Merge branch 'staging' into smol-tag-improvements

This commit is contained in:
Cohee 2024-06-17 21:52:36 +03:00
commit 08a0b1e828
18 changed files with 371 additions and 48 deletions

View File

@ -476,7 +476,11 @@
"type": "context"
},
{
"filename": "presets/context/DreamGen Role-Play V1.json",
"filename": "presets/context/DreamGen Role-Play V1 ChatML.json",
"type": "context"
},
{
"filename": "presets/context/DreamGen Role-Play V1 Llama3.json",
"type": "context"
},
{
@ -556,7 +560,11 @@
"type": "instruct"
},
{
"filename": "presets/instruct/DreamGen Role-Play V1.json",
"filename": "presets/instruct/DreamGen Role-Play V1 ChatML.json",
"type": "instruct"
},
{
"filename": "presets/instruct/DreamGen Role-Play V1 Llama3.json",
"type": "instruct"
},
{

View File

@ -8,5 +8,5 @@
"trim_sentences": true,
"include_newline": false,
"single_line": false,
"name": "DreamGen Role-Play V1"
"name": "DreamGen Role-Play V1 ChatML"
}

View File

@ -0,0 +1,12 @@
{
"story_string": "<|start_header_id|>system<|end_header_id|>\n\n{{#if system}}{{system}}\n\n\n{{/if}}## Overall plot description:\n\n{{#if scenario}}{{scenario}}{{else}}Conversation between {{char}} and {{user}}.{{/if}}{{#if wiBefore}}\n\n{{wiBefore}}{{/if}}\n\n\n## Characters:\n\n### {{char}}\n\n{{#if description}}{{description}}\n\n{{/if}}{{#if personality}}{{personality}}\n\n{{/if}}### {{user}}\n\n{{#if persona}}{{persona}}{{else}}{{user}} is the protagonist of the role-play.{{/if}}{{#if wiAfter}}\n\n{{wiAfter}}{{/if}}{{#if mesExamples}}\n\n{{mesExamples}}{{/if}}",
"example_separator": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nWrite an example narrative / conversation that is not part of the main story.",
"chat_start": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nStart the role-play between {{char}} and {{user}}.",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": false,
"trim_sentences": true,
"include_newline": false,
"single_line": false,
"name": "DreamGen Role-Play V1 Llama3"
}

View File

@ -20,5 +20,5 @@
"user_alignment_message": "",
"system_same_as_user": true,
"last_system_sequence": "",
"name": "DreamGen Role-Play V1"
"name": "DreamGen Role-Play V1 ChatML"
}

View File

@ -0,0 +1,18 @@
{
"system_prompt": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below.",
"input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n",
"output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n",
"first_output_sequence": "",
"last_output_sequence": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",
"stop_sequence": "",
"separator_sequence": "",
"wrap": false,
"macro": true,
"names": false,
"names_force_groups": false,
"activation_regex": "",
"skip_examples": false,
"name": "DreamGen Role-Play V1 Llama3"
}

View File

@ -57,7 +57,7 @@
color: var(--SmartThemeBodyColor);
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 7px;
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
padding: 3px 5px;
}
@ -85,7 +85,7 @@
color: var(--SmartThemeBodyColor);
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 7px;
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
padding: 3px 5px;
}
@ -267,4 +267,4 @@ span.select2.select2-container .select2-selection__choice__remove:hover {
.select2_multi_sameline+span.select2-container.select2-container--focus .select2-selection--multiple .select2-search--inline {
height: unset;
}
}

View File

@ -1565,7 +1565,7 @@
"help_macros_10": "the Character's Personality",
"help_macros_11": "the Character's Scenario",
"help_macros_12": "your current Persona Description",
"help_macros_": "the Character's Dialogue Examples",
"help_macros_13": "the Character's Dialogue Examples",
"help_macros_14": "unformatted Dialogue Examples",
"help_macros_15": "your current Persona username",
"help_macros_16": "the Character's name",

View File

@ -238,6 +238,9 @@
"Squash system messages": "压缩系统消息",
"Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "将连续的系统消息合并为一条(不包括示例对话),可能会提高一些模型的连贯性。",
"Enable function calling": "启用函数调用",
"enable_functions_desc_1": "允许使用",
"enable_functions_desc_2": "功能工具",
"enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。",
"Send inline images": "发送内联图像",
"image_inlining_hint_1": "如果模型支持,则在提示词中发送图像(例如 GPT-4V、Claude 3 或 Llava 13B。\n对任何消息使用",
"image_inlining_hint_2": "或",
@ -266,8 +269,10 @@
"Delete preset": "删除预设",
"View / Edit bias preset": "查看/编辑偏置预设",
"Add bias entry": "添加偏置条目",
"openai_logit_bias_no_items": "没有相关产品",
"Most tokens have a leading space.": "大多数词符都有一个前导空格。",
"API Connections": "API连接",
"api_no_connection": "无连接...",
"Text Completion": "文本补全",
"Chat Completion": "聊天补全",
"NovelAI": "NovelAI",
@ -344,6 +349,7 @@
"Legacy API (pre-OAI, no streaming)": "旧版APIOAI之前无流式传输",
"Bypass status check": "绕过状态检查",
"Chat Completion Source": "聊天补全来源",
"Custom (OpenAI-compatible)": "自定义(兼容 OpenAI",
"Reverse Proxy": "反向代理",
"Proxy Presets": "代理预设",
"Saved addresses and passwords.": "保存的地址和密码。",
@ -402,10 +408,17 @@
"Cohere API Key": "Cohere API 密钥",
"Cohere Model": "Cohere 模型",
"Custom Endpoint (Base URL)": "自定义端点(基本 URL",
"Example: http://localhost:1234/v1": "例如http://localhost:1234/v1",
"at the end of the URL!": "在 URL 的末尾!",
"Custom API Key": "自定义 API 密钥",
"(Optional)": "(可选的)",
"Enter a Model ID": "输入模型名",
"Example: gpt-3.5-turbo": "例如gpt-3.5-turbo",
"Available Models": "可用模型",
"Prompt Post-Processing": "提示词后处理",
"Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。",
"prompt_post_processing_none": "未选择",
"Additional Parameters": "附加参数",
"Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "通过发送简短的测试消息验证您的API连接。请注意您将因此而消耗额度",
"Test Message": "发送测试消息",
"Auto-connect to Last Server": "自动连接到上次的服务器",
@ -1086,7 +1099,9 @@
"Add to group": "添加到群组中",
"Alternate Greetings": "额外问候语",
"Alternate_Greetings_desc": "开始新聊天时,这些按钮将显示为第一条消息的滑动选项。\n群组成员可以选择其中之一来发起对话。",
"Alternate Greetings Hint": "单击按钮即可开始!",
"alternate_greetings_hint_1": "点击",
"alternate_greetings_hint_2": "按钮即可开始!",
"Alternate Greeting #": "额外问候语 #",
"(This will be the first message from the character that starts every chat)": "(这将是角色在每次聊天开始时发送的第一条消息)",
"Forbid Media Override explanation": "当前角色/群组在聊天中使用外部媒体的能力。",
"Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。",
@ -1203,7 +1218,6 @@
"Extras": "更多",
"Horde": "Horde",
"API": "API",
"Custom (OpenAI-compatible)": "自定义(兼容 OpenAI",
"Text Generation WebUI (oobabooga)": "文本生成 WebUI (oobabooga)",
"Model": "模型",
"currently_selected": "[当前选定]",
@ -1322,12 +1336,15 @@
"(if disabled, use ": "(如果禁用,使用",
"macro for manual injection)": "宏用于手动注入)",
"ext_regex_title": "正则",
"ext_regex_new_global_script_desc": "新的全局正则表达式脚本",
"ext_regex_new_global_script": "新建全局正则",
"ext_regex_new_scoped_script_desc": "新的作用域正则表达式脚本",
"ext_regex_new_scoped_script": "新建局部正则",
"ext_regex_import_script": "导入正则",
"ext_regex_global_scripts": "全局正则脚本",
"ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中",
"ext_regex_scoped_scripts": "局部正则脚本",
"ext_regex_allow_scoped": "允许使用范围正则表达式",
"ext_regex_scoped_scripts_desc": "只影响当前角色,保存在角色卡片中",
"Regex Editor": "正则表达式编辑器",
"Test Mode": "测试模式",
@ -1452,6 +1469,19 @@
"Slash Command": "快捷命令",
"Interactive Mode": "交互模式",
"Image Prompt Templates": "图像提示模板",
"ext_translate_btn_chat": "翻译聊天",
"ext_translate_btn_input": "翻译输入",
"ext_translate_delete_confirm_1": "你确定吗?",
"ext_translate_delete_confirm_2": "这将从当前聊天中的所有消息中删除翻译文本。此操作无法撤消。",
"ext_translate_title": "聊天翻译",
"ext_translate_auto_mode": "自动模式",
"ext_translate_mode_none": "没有任何",
"ext_translate_mode_responses": "翻译回复",
"ext_translate_mode_inputs": "翻译输入",
"ext_translate_mode_both": "翻译两者",
"ext_translate_mode_provider": "提供者",
"ext_translate_target_lang": "目标语言",
"ext_translate_clear": "清空设置",
"Vector Storage": "向量存储",
"Vectorization Source": "向量化源",
"Local (Transformers)": "本地Transformers",
@ -1510,6 +1540,12 @@
"Current Password:": "当前密码:",
"New Password:": "新密码:",
"Confirm New Password:": "确认新密码:",
"Include Body Parameters": "包括主体参数",
"custom_include_body_desc": "聊天完成请求主体中要包含的参数YAML 对象)\n\n示例\n- top_k20\n- repetition_penalty1.1",
"Exclude Body Parameters": "排除主体参数",
"custom_exclude_body_desc": "要从聊天完成请求主体中排除的参数YAML 数组)\n\n示例\n- frequency_penalty\n- presence_penalty",
"Include Request Headers": "包含请求标头",
"custom_include_headers_desc": "聊天完成请求的附加标头YAML 对象)\n\n示例\n- CustomHeader自定义值\n- AnotherHeader自定义值",
"Debug Warning": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。",
"Are you sure you want to delete this user?": "您确定要删除该用户吗?",
"Deleting:": "删除:",
@ -1517,6 +1553,76 @@
"Warning:": "警告:",
"This action is irreversible.": "此操作不可逆。",
"Type the user's handle below to confirm:": "在下面输入用户的名称以确认:",
"help_format_1": "文本格式化命令:",
"help_format_2": "*文本*",
"help_format_3": "显示为",
"help_format_4": "斜体",
"help_format_5": "**文本**",
"help_format_6": "显示为",
"help_format_7": "大胆的",
"help_format_8": "***文本***",
"help_format_9": "显示为",
"help_format_10": "粗斜体",
"help_format_11": "__文本__",
"help_format_12": "显示为",
"help_format_13": "强调",
"help_format_14": "~~文本~~",
"help_format_15": "显示为",
"help_format_16": "删除线",
"help_format_17": "[文本](网址)",
"help_format_18": "显示为",
"help_format_19": "超级链接",
"help_format_20": "![文本](网址)",
"help_format_21": "显示为图像",
"help_format_22": "```文本```",
"help_format_23": "显示为代码块(反引号之间允许换行)",
"help_format_like_this": "像这样",
"help_format_24": "`文本`",
"help_format_25": "显示为",
"help_format_26": "内联代码",
"help_format_27": "> 文本",
"help_format_28": "显示为块引用(请注意 > 后面的空格)",
"help_format_29": " 文本",
"help_format_30": "显示为大标题(注意空格)",
"help_format_32": " 文本",
"help_format_33": "显示为中等标题(注意空格)",
"help_format_35": " 文本",
"help_format_36": "显示为小标题(注意空格)",
"help_format_38": "$$ 文本 $$",
"help_format_39": "呈现 LaTeX 公式(如果启用)",
"help_format_40": "$文本$",
"help_format_41": "呈现 AsciiMath 公式(如果启用)",
"help_1": "您好!请选择您想要详细了解的帮助主题:",
"help_2": "斜线命令",
"help_or": "或者",
"help_3": "格式化",
"help_4": "热键",
"help_5": "{{宏}}",
"help_6": "还有其他问题吗?",
"help_7": "SillyTavern 官方文档网站",
"help_8": "有更多信息!",
"help_hotkeys_0": "热键/按键绑定",
"help_hotkeys_1": "向上",
"help_hotkeys_2": "编辑聊天中的最后一条消息",
"help_hotkeys_3": "Ctrl+向上",
"help_hotkeys_4": "编辑聊天中的最后一条用户消息",
"help_hotkeys_5": "左边",
"help_hotkeys_6": "向左滑动",
"help_hotkeys_7": "正确的",
"help_hotkeys_8": "向右滑动(注意:当聊天栏中输入内容时,滑动热键将被禁用)",
"help_hotkeys_9": "进入",
"help_hotkeys_10": "(选中聊天栏)",
"help_hotkeys_10_1": "向 AI 发送消息",
"help_hotkeys_11": "Ctrl+Enter",
"help_hotkeys_12": "重新生成最后的 AI 响应",
"help_hotkeys_13": "Alt+Enter",
"help_hotkeys_14": "继续上一次AI响应",
"help_hotkeys_15": "逃脱",
"help_hotkeys_16": "停止 AI 响应生成、关闭 UI 面板、取消消息编辑",
"help_hotkeys_17": "Ctrl+Shift+向上",
"help_hotkeys_18": "滚动到上下文行",
"help_hotkeys_19": "Ctrl+Shift+向下",
"help_hotkeys_20": "滚动聊天到底部",
"Import Characters": "导入角色",
"Enter the URL of the content to import": "输入要导入的内容的URL",
"Supported sources:": "支持的来源:",
@ -1531,6 +1637,87 @@
"char_import_8": "RisuRealm 角色(直链)",
"Supports importing multiple characters.": "支持导入多个角色。",
"Write each URL or ID into a new line.": "将每个 URL 或 ID 写入新行。",
"System-wide Replacement Macros (in order of evaluation):": "系统范围的替换宏(按评估顺序):",
"help_macros_1": "仅适用于斜线命令批处理。替换为上一个命令的返回结果。",
"help_macros_2": "仅插入一个换行符。",
"help_macros_3": "修剪此宏周围的换行符。",
"help_macros_4": "没有操作,只是一个空字符串。",
"help_macros_5": "API 设置中定义的全局提示。仅在高级定义提示覆盖中有效。",
"help_macros_6": "用户输入",
"help_macros_7": "角色的主提示覆盖",
"help_macros_8": "角色越狱提示覆盖",
"help_macros_9": "角色描述",
"help_macros_10": "人物性格",
"help_macros_11": "角色场景",
"help_macros_12": "您当前的角色描述",
"help_macros_13": "角色对话示例",
"help_macros_14": "未格式化的对话示例",
"(only for Story String)": "(仅适用于故事字符串)",
"help_macros_15": "您当前的 Persona 用户名",
"help_macros_16": "角色的名字",
"help_macros_17": "角色的版本号",
"help_macros_18": "以逗号分隔的群组成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}",
"help_macros_19": "当前选定的 API 的文本生成模型名称。",
"Can be inaccurate!": "可能不准确!",
"help_macros_20": "最新聊天消息的文本。",
"help_macros_21": "最新聊天消息的索引号。对于斜线命令批处理很有用。",
"help_macros_22": "上下文中包含的第一条消息的 ID。要求在当前会话中至少运行一次生成。",
"help_macros_23": "最后一条聊天消息中当前滑动的 ID以 1 为基数)。如果最后一条消息是用户或提示隐藏的,则为空字符串。",
"help_macros_24": "最后一条聊天消息中的滑动次数。如果最后一条消息是用户隐藏或提示隐藏的,则为空字符串。",
"help_macros_25": "您可以在此处留言宏将被替换为空白内容。AI 看不到。",
"help_macros_26": "当前时间",
"help_macros_27": "当前日期",
"help_macros_28": "当前工作日",
"help_macros_29": "当前 ISO 时间24 小时制)",
"help_macros_30": "当前 ISO 日期 (YYYY-MM-DD)",
"help_macros_31": "指定格式的当前日期/时间,例如德国日期/时间:",
"help_macros_32": "指定 UTC 时区偏移量的当前时间,例如 UTC-4 或 UTC+2",
"help_macros_33": "time1 和 time2 之间的时间差。接受时间和日期宏。(例如:{{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}}",
"help_macros_34": "距离上次用户消息发送的时间",
"help_macros_35": "为 AI 设置行为偏差,直到下一个用户输入。文本周围的引号很重要。",
"help_macros_36": "掷骰子。(例如:",
"space_ will roll a 6-sided dice and return a number between 1 and 6)": "将掷一个 6 面骰子并返回 1 到 6 之间的数字)",
"help_macros_37": "从列表中返回一个随机项目。(例如:",
"space_ will return 1 of the 4 numbers at random. Works with text lists too.": "将随机返回 4 个数字中的 1 个。也适用于文本列表。",
"help_macros_38": "随机的替代语法允许在列表项中使用逗号。",
"help_macros_39": "从列表中随机挑选一项。工作原理与 {{random}} 相同,具有相同的语法选项,但一旦挑选,挑选将一直持续到本次聊天,不会在连续消息和提示处理中重新滚动。",
"help_macros_40": "如果使用文本生成 WebUI 后端则动态地将引号中的文本添加到禁用单词序列中。对其他后端不执行任何操作。可以在任何地方使用角色描述、WI、AN 等)。文本周围的引号很重要。",
"Instruct Mode and Context Template Macros:": "指导模式和上下文模板宏:",
"(enabled in the Advanced Formatting settings)": "(在高级格式设置中启用)",
"help_macros_41": "令牌中允许的最大提示长度 = (上下文大小 - 响应长度)",
"help_macros_42": "上下文模板示例对话分隔符",
"help_macros_43": "上下文模板聊天开始行",
"help_macros_44": "主系统提示(如果选择,则覆盖字符提示,或 instructSystemPrompt",
"help_macros_45": "指示系统提示",
"help_macros_46": "指示系统提示前缀序列",
"help_macros_47": "指示系统提示后缀序列",
"help_macros_48": "指示用户前缀序列",
"help_macros_49": "指示用户后缀序列",
"help_macros_50": "指导助理前缀序列",
"help_macros_51": "指导助理后缀序列",
"help_macros_52": "指导助理第一个输出序列",
"help_macros_53": "指导助手最后输出序列",
"help_macros_54": "指示系统消息前缀序列",
"help_macros_55": "指示系统消息后缀序列",
"help_macros_56": "指示系统指令前缀",
"help_macros_57": "指示第一个用户消息填充器",
"help_macros_58": "指示停止顺序",
"Chat variables Macros:": "聊天变量宏:",
"Local variables = unique to the current chat": "局部变量 = 当前聊天所独有",
"Global variables = works in any chat for any character": "全局变量 = 适用于任何角色的任何聊天",
"Scoped variables = works in STscript": "范围变量 = 在 STscript 中有效",
"help_macros_59": "替换为局部变量“name”的值",
"help_macros_60": "替换为空字符串将局部变量“name”设置为“value”",
"help_macros_61": "替换为空字符串将“increment”的数值添加到局部变量“name”",
"help_macros_62": "替换为变量“name”的值增加 1 的结果",
"help_macros_63": "替换为变量“name”的值减 1 的结果",
"help_macros_64": "替换为全局变量“name”的值",
"help_macros_65": "替换为空字符串将全局变量“name”设置为“value”",
"help_macros_66": "替换为空字符串将“increment”的数值添加到全局变量“name”",
"help_macros_67": "替换为全局变量“name”的值增加 1 的结果",
"help_macros_68": "替换为全局变量“name”的值减 1 的结果",
"help_macros_69": "替换为范围变量“name”的值",
"help_macros_70": "用范围变量“name”的索引处的项目值对于数组/列表或对象/字典)替换",
"Export for character": "导出角色",
"Export prompts for this character, including their order.": "导出此角色的提示词,包括其顺序。",
"Export all": "全部导出",
@ -1550,17 +1737,6 @@
"Record a snapshot of your current settings.": "记录当前设置的快照。",
"Make a Snapshot": "制作快照",
"Restore this snapshot": "恢复此快照",
"ext_translate_btn_chat": "翻译聊天",
"ext_translate_btn_input": "翻译输入",
"Chat Translation": "聊天翻译",
"ext_translate_auto_mode": "自动模式",
"ext_translate_mode_none": "没有任何",
"ext_translate_mode_responses": "翻译回复",
"ext_translate_mode_inputs": "翻译输入",
"ext_translate_mode_both": "翻译两者",
"ext_translate_mode_provider": "提供者",
"ext_translate_target_lang": "目标语言",
"ext_translate_clear": "清空设置",
"Hi,": "嘿,",
"To enable multi-account features, restart the SillyTavern server with": "要启用多帐户功能,请使用以下命令重新启动 SillyTavern 服务器",
"set to true in the config.yaml file.": "在 config.yaml 文件中设置为 true。",

View File

@ -21,7 +21,7 @@
<div class="expression_api_block m-b-1 m-t-1">
<label for="expression_api" data-i18n="Classifier API">Classifier API</label>
<small data-i18n="Select the API for classifying expressions.">Select the API for classifying expressions.</small>
<select id="expression_api" class="flex1 margin0" data-i18n="Expression API" placeholder="Expression API">
<select id="expression_api" class="flex1 margin0">
<option value="0" data-i18n="Local">Local</option>
<option value="1" data-i18n="Extras">Extras</option>
<option value="2" data-i18n="LLM">LLM</option>

View File

@ -402,6 +402,10 @@ async function translate(text, lang) {
return '';
}
if (!lang) {
lang = extension_settings.translate.target_language;
}
switch (extension_settings.translate.provider) {
case 'libre':
return await translateProviderLibre(text, lang);

View File

@ -175,7 +175,7 @@ class AzureTtsProvider {
const url = URL.createObjectURL(audio);
this.audioElement.src = url;
this.audioElement.play();
URL.revokeObjectURL(url);
this.audioElement.onended = () => URL.revokeObjectURL(url);
}
async fetchTtsGeneration(text, voiceId) {

View File

@ -155,7 +155,7 @@ class EdgeTtsProvider {
const url = URL.createObjectURL(audio);
this.audioElement.src = url;
this.audioElement.play();
URL.revokeObjectURL(url);
this.audioElement.onended = () => URL.revokeObjectURL(url);
}
/**

View File

@ -1,4 +1,4 @@
import { callPopup, cancelTtsPlay, eventSource, event_types, name2, saveSettingsDebounced, substituteParams } from '../../../script.js';
import { callPopup, cancelTtsPlay, eventSource, event_types, isStreamingEnabled, name2, saveSettingsDebounced, substituteParams } from '../../../script.js';
import { ModuleWorkerWrapper, doExtrasFetch, extension_settings, getApiUrl, getContext, modules } from '../../extensions.js';
import { delay, escapeRegex, getBase64Async, getStringHash, onlyUnique } from '../../utils.js';
import { EdgeTtsProvider } from './edge.js';
@ -18,6 +18,7 @@ import { AzureTtsProvider } from './azure.js';
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
import { debounce_timeout } from '../../constants.js';
export { talkingAnimation };
const UPDATE_INTERVAL = 1000;
@ -28,6 +29,8 @@ let talkingHeadState = false;
let lastChatId = null;
let lastMessage = null;
let lastMessageHash = null;
let periodicMessageGenerationTimer = null;
let lastPositionOfParagraphEnd = -1;
const DEFAULT_VOICE_MARKER = '[Default Voice]';
const DISABLED_VOICE_MARKER = 'disabled';
@ -109,7 +112,7 @@ async function onNarrateOneMessage() {
async function onNarrateText(args, text) {
if (!text) {
return;
return '';
}
audioElement.src = '/sounds/silence.mp3';
@ -135,6 +138,7 @@ async function onNarrateText(args, text) {
// Return back to the chat voices
await initVoiceMap(false);
return '';
}
async function moduleWorker() {
@ -531,6 +535,7 @@ function loadSettings() {
$('#tts_narrate_dialogues').prop('checked', extension_settings.tts.narrate_dialogues_only);
$('#tts_narrate_quoted').prop('checked', extension_settings.tts.narrate_quoted_only);
$('#tts_auto_generation').prop('checked', extension_settings.tts.auto_generation);
$('#tts_periodic_auto_generation').prop('checked', extension_settings.tts.periodic_auto_generation);
$('#tts_narrate_translated_only').prop('checked', extension_settings.tts.narrate_translated_only);
$('#tts_narrate_user').prop('checked', extension_settings.tts.narrate_user);
$('#tts_pass_asterisks').prop('checked', extension_settings.tts.pass_asterisks);
@ -594,6 +599,12 @@ function onAutoGenerationClick() {
}
function onPeriodicAutoGenerationClick() {
extension_settings.tts.periodic_auto_generation = !!$('#tts_periodic_auto_generation').prop('checked');
saveSettingsDebounced();
}
function onNarrateDialoguesClick() {
extension_settings.tts.narrate_dialogues_only = !!$('#tts_narrate_dialogues').prop('checked');
saveSettingsDebounced();
@ -679,13 +690,14 @@ export function saveTtsProviderSettings() {
//###################//
async function onChatChanged() {
await resetTtsPlayback();
await onGenerationEnded();
resetTtsPlayback();
const voiceMapInit = initVoiceMap();
await Promise.race([voiceMapInit, delay(1000)]);
await Promise.race([voiceMapInit, delay(debounce_timeout.relaxed)]);
lastMessage = null;
}
async function onMessageEvent(messageId) {
async function onMessageEvent(messageId, lastCharIndex) {
// If TTS is disabled, do nothing
if (!extension_settings.tts.enabled) {
return;
@ -723,12 +735,17 @@ async function onMessageEvent(messageId) {
return;
}
// if we only want to process part of the message
if (lastCharIndex) {
message.mes = message.mes.substring(0, lastCharIndex);
}
const isLastMessageInCurrent = () =>
lastMessage &&
typeof lastMessage === 'object' &&
message.swipe_id === lastMessage.swipe_id &&
message.name === lastMessage.name &&
message.is_user === lastMessage.is_user &&
message.name === lastMessage.name &&
message.is_user === lastMessage.is_user &&
message.mes.indexOf(lastMessage.mes) !== -1;
// if last message within current message, message got extended. only send diff to TTS.
@ -781,6 +798,83 @@ async function onMessageDeleted() {
resetTtsPlayback();
}
async function onGenerationStarted(generationType, _args, isDryRun) {
// If dry running or quiet mode, do nothing
if (isDryRun || ['quiet', 'impersonate'].includes(generationType)) {
return;
}
// If TTS is disabled, do nothing
if (!extension_settings.tts.enabled) {
return;
}
// Auto generation is disabled
if (!extension_settings.tts.auto_generation) {
return;
}
// Periodic auto generation is disabled
if (!extension_settings.tts.periodic_auto_generation) {
return;
}
// If the reply is not being streamed
if (!isStreamingEnabled()) {
return;
}
// start the timer
if (!periodicMessageGenerationTimer) {
periodicMessageGenerationTimer = setInterval(onPeriodicMessageGenerationTick, UPDATE_INTERVAL);
}
}
async function onGenerationEnded() {
if (periodicMessageGenerationTimer) {
clearInterval(periodicMessageGenerationTimer);
periodicMessageGenerationTimer = null;
}
lastPositionOfParagraphEnd = -1;
}
async function onPeriodicMessageGenerationTick() {
const context = getContext();
// no characters or group selected
if (!context.groupId && context.characterId === undefined) {
return;
}
const lastMessageId = context.chat.length - 1;
// the last message was from the user
if (context.chat[lastMessageId].is_user) {
return;
}
const lastMessage = structuredClone(context.chat[lastMessageId]);
const lastMessageText = lastMessage?.mes ?? '';
// look for double ending lines which should indicate the end of a paragraph
let newLastPositionOfParagraphEnd = lastMessageText
.indexOf('\n\n', lastPositionOfParagraphEnd + 1);
// if not found, look for a single ending line which should indicate the end of a paragraph
if (newLastPositionOfParagraphEnd === -1) {
newLastPositionOfParagraphEnd = lastMessageText
.indexOf('\n', lastPositionOfParagraphEnd + 1);
}
// send the message to the tts module if we found the new end of a paragraph
if (newLastPositionOfParagraphEnd > -1) {
onMessageEvent(lastMessageId, newLastPositionOfParagraphEnd);
if (periodicMessageGenerationTimer) {
lastPositionOfParagraphEnd = newLastPositionOfParagraphEnd;
}
}
}
/**
* Get characters in current chat
* @param {boolean} unrestricted - If true, will include all characters in voiceMapEntries, even if they are not in the current chat.
@ -1010,6 +1104,10 @@ $(document).ready(function () {
<input type="checkbox" id="tts_auto_generation">
<small>Auto Generation</small>
</label>
<label class="checkbox_label" for="tts_periodic_auto_generation" title="Requires auto generation to be enabled.">
<input type="checkbox" id="tts_periodic_auto_generation">
<small>Narrate by paragraphs (when streaming)</small>
</label>
<label class="checkbox_label" for="tts_narrate_quoted">
<input type="checkbox" id="tts_narrate_quoted">
<small>Only narrate "quotes"</small>
@ -1072,6 +1170,7 @@ $(document).ready(function () {
$('#tts_skip_tags').on('click', onSkipTagsClick);
$('#tts_pass_asterisks').on('click', onPassAsterisksClick);
$('#tts_auto_generation').on('click', onAutoGenerationClick);
$('#tts_periodic_auto_generation').on('click', onPeriodicAutoGenerationClick);
$('#tts_narrate_user').on('click', onNarrateUserClick);
$('#playback_rate').on('input', function () {
@ -1099,9 +1198,12 @@ $(document).ready(function () {
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
eventSource.on(event_types.MESSAGE_DELETED, onMessageDeleted);
eventSource.on(event_types.GROUP_UPDATED, onChatChanged);
eventSource.on(event_types.GENERATION_STARTED, onGenerationStarted);
eventSource.on(event_types.GENERATION_ENDED, onGenerationEnded);
eventSource.makeLast(event_types.CHARACTER_MESSAGE_RENDERED, onMessageEvent);
eventSource.makeLast(event_types.USER_MESSAGE_RENDERED, onMessageEvent);
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'speak',
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'speak',
callback: onNarrateText,
aliases: ['narrate', 'tts'],
namedArgumentList: [

View File

@ -180,7 +180,7 @@ class NovelTtsProvider {
const url = URL.createObjectURL(audio);
this.audioElement.src = url;
this.audioElement.play();
URL.revokeObjectURL(url);
this.audioElement.onended = () => URL.revokeObjectURL(url);
}
async* fetchTtsGeneration(inputText, voiceId) {

View File

@ -60,7 +60,7 @@ class SpeechT5TtsProvider {
const url = URL.createObjectURL(audio);
this.audioElement.src = url;
this.audioElement.play();
URL.revokeObjectURL(url);
this.audioElement.onended = () => URL.revokeObjectURL(url);
}
async loadSettings(settings) {

View File

@ -3700,8 +3700,8 @@ function onSettingsPresetChange() {
preset.assistant_impersonation = preset.assistant_prefill;
}
const updateInput = (selector, value) => $(selector).val(value).trigger('input');
const updateCheckbox = (selector, value) => $(selector).prop('checked', value).trigger('input');
const updateInput = (selector, value) => $(selector).val(value).trigger('input', { source: 'preset' });
const updateCheckbox = (selector, value) => $(selector).prop('checked', value).trigger('input', { source: 'preset' });
// Allow subscribers to alter the preset before applying deltas
eventSource.emit(event_types.OAI_PRESET_CHANGED_BEFORE, {
@ -4857,9 +4857,11 @@ $(document).ready(async function () {
eventSource.emit(event_types.CHATCOMPLETION_SOURCE_CHANGED, oai_settings.chat_completion_source);
});
$('#oai_max_context_unlocked').on('input', function () {
$('#oai_max_context_unlocked').on('input', function (_e, data) {
oai_settings.max_context_unlocked = !!$(this).prop('checked');
$('#chat_completion_source').trigger('change');
if (data?.source !== 'preset') {
$('#chat_completion_source').trigger('change');
}
saveSettingsDebounced();
});

View File

@ -14,13 +14,13 @@
<li><tt>&lcub;&lcub;personality&rcub;&rcub;</tt> <span data-i18n="help_macros_10">the Character's Personality</span></li>
<li><tt>&lcub;&lcub;scenario&rcub;&rcub;</tt> <span data-i18n="help_macros_11">the Character's Scenario</span></li>
<li><tt>&lcub;&lcub;persona&rcub;&rcub;</tt> <span data-i18n="help_macros_12">your current Persona Description</span></li>
<li><tt>&lcub;&lcub;mesExamples&rcub;&rcub;</tt> <span data-i18n="help_macros_"13>the Character's Dialogue Examples</span></li>
<li><tt>&lcub;&lcub;mesExamplesRaw&rcub;&rcub;</tt> <span data-i18n="help_macros_14">unformatted Dialogue Examples </span><b>(only for Story String)</b></li>
<li><tt>&lcub;&lcub;mesExamples&rcub;&rcub;</tt> <span data-i18n="help_macros_13">the Character's Dialogue Examples</span></li>
<li><tt>&lcub;&lcub;mesExamplesRaw&rcub;&rcub;</tt> <span data-i18n="help_macros_14">unformatted Dialogue Examples </span><b data-i18n="(only for Story String)">(only for Story String)</b></li>
<li><tt>&lcub;&lcub;user&rcub;&rcub;</tt> <span data-i18n="help_macros_15">your current Persona username</span></li>
<li><tt>&lcub;&lcub;char&rcub;&rcub;</tt> <span data-i18n="help_macros_16">the Character's name</span></li>
<li><tt>&lcub;&lcub;char_version&rcub;&rcub;</tt> <span data-i18n="help_macros_17">the Character's version number</span></li>
<li><tt>&lcub;&lcub;group&rcub;&rcub;</tt> <span data-i18n="help_macros_18">a comma-separated list of group member names or the character name in solo chats. Alias: &lcub;&lcub;charIfNotGroup&rcub;&rcub;</span></li>
<li><tt>&lcub;&lcub;model&rcub;&rcub;</tt> <span data-i18n="help_macros_19">a text generation model name for the currently selected API. </span><b>Can be inaccurate!</b></li>
<li><tt>&lcub;&lcub;model&rcub;&rcub;</tt> <span data-i18n="help_macros_19">a text generation model name for the currently selected API. </span><b data-i18n="Can be inaccurate!">Can be inaccurate!</b></li>
<li><tt>&lcub;&lcub;lastMessage&rcub;&rcub;</tt> - <span data-i18n="help_macros_20">the text of the latest chat message.</span></li>
<li><tt>&lcub;&lcub;lastMessageId&rcub;&rcub;</tt> <span data-i18n="help_macros_21">index # of the latest chat message. Useful for slash command batching.</span></li>
<li><tt>&lcub;&lcub;firstIncludedMessageId&rcub;&rcub;</tt> - <span data-i18n="help_macros_22">the ID of the first message included in the context. Requires generation to be ran at least once in the current session.</span></li>
@ -37,8 +37,8 @@
<li><tt>&lcub;&lcub;timeDiff::(time1)::(time2)&rcub;&rcub;</tt> <span data-i18n="help_macros_33">the time difference between time1 and time2. Accepts time and date macros. (Ex: &lcub;&lcub;timeDiff::&lcub;&lcub;isodate&rcub;&rcub; &lcub;&lcub;time&rcub;&rcub;::2024/5/11 12:30:00&rcub;&rcub;)</span></li>
<li><tt>&lcub;&lcub;idle_duration&rcub;&rcub;</tt> <span data-i18n="help_macros_34">the time since the last user message was sent</span></li>
<li><tt>&lcub;&lcub;bias "text here"&rcub;&rcub;</tt> <span data-i18n="help_macros_35">sets a behavioral bias for the AI until the next user input. Quotes around the text are important.</span></li>
<li><tt>&lcub;&lcub;roll:(formula)&rcub;&rcub;</tt> <span data-i18n="help_macros_36">rolls a dice. (ex: </span><tt>>&lcub;&lcub;roll:1d6&rcub;&rcub;</tt> will roll a 6-sided dice and return a number between 1 and 6)</li>
<li><tt>&lcub;&lcub;random:(args)&rcub;&rcub;</tt> <span data-i18n="help_macros_37">returns a random item from the list. (ex: </span><tt>&lcub;&lcub;random:1,2,3,4&rcub;&rcub;</tt> will return 1 of the 4 numbers at random. Works with text lists too.</li>
<li><tt>&lcub;&lcub;roll:(formula)&rcub;&rcub;</tt> <span data-i18n="help_macros_36">rolls a dice. (ex: </span><tt>&lcub;&lcub;roll:1d6&rcub;&rcub;</tt><span data-i18n="space_ will roll a 6-sided dice and return a number between 1 and 6)"> will roll a 6-sided dice and return a number between 1 and 6)</span></li>
<li><tt>&lcub;&lcub;random:(args)&rcub;&rcub;</tt> <span data-i18n="help_macros_37">returns a random item from the list. (ex: </span><tt>&lcub;&lcub;random:1,2,3,4&rcub;&rcub;</tt><span data-i18n="space_ will return 1 of the 4 numbers at random. Works with text lists too."> will return 1 of the 4 numbers at random. Works with text lists too.</span></li>
<li><tt>&lcub;&lcub;random::(arg1)::(arg2)&rcub;&rcub;</tt> <span data-i18n="help_macros_38">alternative syntax for random that allows to use commas in the list items.</span></li>
<li><tt>&lcub;&lcub;pick::(args)&rcub;&rcub;</tt> <span data-i18n="help_macros_39">picks a random item from the list. Works the same as &lcub;&lcub;random&rcub;&rcub;, with the same possible syntax options, but the pick will stay consistent for this chat once picked and won't be re-rolled on consecutive messages and prompt processing.</span></li>
<li><tt>&lcub;&lcub;banned "text here"&rcub;&rcub;</tt> <span data-i18n="help_macros_40">dynamically add text in the quotes to banned words sequences, if Text Generation WebUI backend used. Do nothing for others backends. Can be used anywhere (Character description, WI, AN, etc.) Quotes around the text are important.</span></li>

View File

@ -838,7 +838,7 @@ body .panelControlBar {
}
.font-family-reset {
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
font-size: var(--mainFontSize);
font-weight: 400;
}
@ -988,7 +988,7 @@ body .panelControlBar {
color: var(--SmartThemeBodyColor);
font-size: 12px;
padding: 0;
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
font-weight: 400;
}
@ -1168,7 +1168,7 @@ textarea {
border-radius: 5px;
color: var(--SmartThemeBodyColor);
font-size: var(--mainFontSize);
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
padding: 5px 10px;
max-height: 90vh;
max-height: 90svh;
@ -1181,6 +1181,7 @@ textarea.autoSetHeight {
input,
select {
font-family: var(--mainFontFamily);
font-size: var(--mainFontSize);
color: var(--SmartThemeBodyColor);
}
@ -1197,7 +1198,7 @@ select {
border: 0;
box-shadow: none;
padding: 6px;
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
margin: 0;
text-shadow: 0px 0px calc(var(--shadowWidth) * 1px) var(--SmartThemeShadowColor);
flex: 1;
@ -2132,7 +2133,7 @@ textarea::placeholder {
color: var(--SmartThemeBodyColor);
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 5px;
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
padding: 3px 5px;
width: 100%;
margin: 5px 0;