Files
ketle-manandClaude Sonnet 5.5 5d3b4d0a21 docs/ui: call the judge a decision model everywhere user-facing
Only display strings change: the "VLA" row label becomes "Decision", the tooltip,
node DESCRIPTION, locales descriptions and README wording follow. Identifiers,
the saved-settings key and the /models response keys are unchanged, so saved
selections and behavior are unaffected. pyproject.toml is left as is on purpose
(pushing it triggers the Registry publish workflow).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 15:59:33 +09:00

398 lines
22 KiB
JavaScript

// UI文字列の多言語化(英語 / 日本語 / 中国語)。ComfyUIの言語設定(Comfy.Locale)に従う。
// ノード名・入出力名の翻訳は locales/<lang>/nodeDefs.json(ComfyUI標準の仕組み)で行う。
// 言語を切り替えた場合、このUI(ノード内のDOM)はページの再読み込み後に反映される。
import { app } from "../../../scripts/app.js";
const DICT = {
en: {
reloadModels: "Reload models",
llmTitle: "LLM (text chat)",
vlmTitle: "VLM (used when an image is attached)",
vlaTitle: "Decision model (judges the generated image; needs image input, e.g. clef)",
modeTitle: "When to queue image generation",
modeClose: "Generate when </prompt> closes",
modeLive: "Live while streaming",
modeManual: "Manual (no auto)",
srcTitle: "What becomes the image prompt",
srcTag: "Prompt = <prompt> block",
srcResponse: "Prompt = whole response",
srcBTitle: "chat_p / chat_n: visualize the model's own thinking / reply as-is",
srcBOff: "chat_p: off",
srcBThinking: "chat_p = thinking",
srcBReply: "chat_p = reply",
srcBBoth: "chat_p = thinking + reply",
srcBMind: "chat_p = <mind> block",
maxBTitle: "chat_p: max characters used as the prompt",
negBTitle: "chat_n: negative prompt",
mindEn: "mind EN",
mindEnTitle: "Write the <mind> block in English (image models understand English best)",
vramTitle: "Unload Ollama models before image generation starts",
vramOff: "VRAM: off",
vramAuto: "VRAM: auto-free",
vramAll: "VRAM: unload all",
vramGbTitle: "auto-free: target free VRAM (GB). Largest models are unloaded first, only as many as needed",
gbFree: "GB free (auto)",
judge: "judge",
think: "think",
genTitle: "ON: every reply is turned into an image. OFF: plain chat (no image prompt, no generation)",
genLabel: "🖼 Image",
presetTitle: "System prompt / character preset",
presetsBtn: "Presets…",
presetsBtnTitle: "Manage system prompts / characters",
clear: "Clear",
clearTitle: "Clear chat",
inputPlaceholder: "Message (Ctrl+Enter to send / images can be pasted)",
attachTitle: "Attach image (→ VLM)",
send: "Send",
stop: "Stop",
ready: "ready",
dropIdle: "🖼 Drop an image / click to select / paste (→ VLM / I2I)",
dropLocked: "🔌 Image input connected — it takes priority (drop / click disabled)",
dropTitle: "Drop images here (VLM input / I2I source)",
unload: "⏏ Unload",
unloadTitle: "Unload all Ollama models from VRAM",
settings: "⚙ Settings",
promptSec: "🎨 Prompt",
sectionToggle: "Click to expand / collapse",
empty: "(empty)",
i2iSource: "I2I source",
i2iClear: "Clear I2I source",
freeingVram: "freeing VRAM…",
generating: "generating…",
queueFailed: "queue failed: {msg}",
judging: "judging…",
judgeBusy: "judge model busy — retrying…",
vramFailed: "VRAM prepare failed: {msg}",
vramUnloaded: "🧹 Unloaded {names} — free {a} → {b} GB",
vramShort: "⚠ Free VRAM {a} GB < target {t} GB",
vramShortInUse: "⚠ Free VRAM {a} GB < target {t} GB (in use: {names})",
judgeFailed: "judge failed: {msg}",
judgeResult: "🧪 {model}: match {match} / quality {quality}",
genOn: "Image generation ON",
genOff: "Image generation OFF — plain chat",
presetsSaved: "Presets saved ({n})",
presetsError: "Presets: {msg}",
lockedDrop: "Image input is connected — it takes priority. Disconnect it to use dropped images.",
lockedPick: "Image input is connected — it takes priority. Disconnect it to use selected images.",
onlyImages: "Only image files can be dropped",
streamingBusy: "Streaming in progress — stop it first",
unloading: "unloading Ollama models…",
unloaded: "Unloaded: {names}",
unloadedFailed: "Unloaded: {names} / failed: {failed}",
noneLoaded: "No Ollama models were loaded",
unloadFailed: "unload failed: {msg}",
errorPrefix: "error: {msg}",
noVlm: "No VLM selected",
noLlm: "No LLM selected",
socketPriority: "Image input is connected — it takes priority over the attached images",
socketUnavailable: "Image input is connected but not available yet (use a Load Image node, or run the graph once) — using attached images if any",
charSwitched: "Character presets use the <prompt> block — Prompt source switched",
streamingModel: "streaming ({model})…",
thinkingStatus: "thinking…",
noThinkRetry: "⚠ This model has no thinking support — retrying without it (chat_p falls back to the reply)",
noPromptWarn: "⚠ No image prompt in the reply, so no image was generated (the model skipped <prompt> — check the preset / system prompt, or try a larger model)",
loadingModels: "loading models…",
ollamaStatus: "Ollama {version} · {n} models",
ollamaUnreachable: "Ollama unreachable: {msg}",
ollamaServerSetting: "server setting",
ollamaServerSettingTitle: "The Ollama address is set on the server (environment variable LIVE_CHAT_STREAM_OLLAMA_URL or config.json), not in the browser.",
noLlmOpt: "(no LLM)",
noVlmOpt: "(no VLM)",
noDecisionOpt: "(no decision model)",
i2iSourceErr: "I2I source: {msg}",
mdTitle: "System prompt presets",
mdAddChar: "+ Character",
mdAddPlain: "+ Plain",
mdDup: "Duplicate",
mdDel: "Delete",
mdImport: "Import",
mdExport: "Export",
mdCancel: "Cancel",
mdSave: "Save",
mdSaveUse: "Save & Use",
mdNone: "No presets",
mdTypeChar: "character",
mdTypePlain: "plain",
mdCharName: "Character name (also used in the prompts)",
mdPresetName: "Preset name",
mdFieldSystem: "System prompt (empty = built-in default)",
mdFieldPersona: "Personality, tone, background",
mdFieldAppearance: "Fixed appearance tags (English, always placed first in <prompt>)",
mdFieldEmotion: "Emotion expression rules (optional)",
mdPreview: "System prompt that is actually sent (preview)",
mdDefaultNoDelete: "Default cannot be deleted",
mdImported: "{n} imported (press Save to confirm)",
mdImportFailed: "Import failed: {msg}",
mdNoPresetsKey: "No \"presets\" in the file",
sampleName: "Lumi (sample)",
samplePersona: "Lumi, a curious and slightly shy 16-year-old girl. She speaks casually and cheerfully, and her feelings show on her face right away. She honestly expresses how she feels about the conversation.",
},
ja: {
reloadModels: "モデル一覧を再取得",
llmTitle: "LLM(テキストチャット)",
vlmTitle: "VLM(画像を添付したときに使用)",
vlaTitle: "意思決定モデル(生成画像を判定。画像入力に対応したモデルが必要。例: clef)",
modeTitle: "画像生成を開始するタイミング",
modeClose: "</prompt> が閉じたら生成",
modeLive: "ストリーミング中に連続生成",
modeManual: "手動(自動生成しない)",
srcTitle: "画像プロンプトに使う部分",
srcTag: "プロンプト = <prompt> ブロック",
srcResponse: "プロンプト = 応答全体",
srcBTitle: "chat_p / chat_n: モデル自身の思考・返信をそのまま画像化",
srcBOff: "chat_p: オフ",
srcBThinking: "chat_p = 思考",
srcBReply: "chat_p = 返信",
srcBBoth: "chat_p = 思考 + 返信",
srcBMind: "chat_p = <mind> ブロック",
maxBTitle: "chat_p: プロンプトに使う最大文字数",
negBTitle: "chat_n: ネガティブプロンプト",
mindEn: "mind 英語",
mindEnTitle: "<mind> ブロックを英語で書かせる(画像モデルは英語が得意)",
vramTitle: "画像生成を始める前に Ollama のモデルをアンロード",
vramOff: "VRAM: オフ",
vramAuto: "VRAM: 自動解放",
vramAll: "VRAM: すべてアンロード",
vramGbTitle: "自動解放: 目標の空きVRAM(GB)。大きいモデルから、必要な分だけアンロード",
gbFree: "GB 空き(自動)",
judge: "判定",
think: "思考",
genTitle: "ON: 毎回の返信を画像にする / OFF: 通常のチャット(画像プロンプトの指示・生成なし)",
genLabel: "🖼 画像",
presetTitle: "システムプロンプト / キャラクターのプリセット",
presetsBtn: "プリセット…",
presetsBtnTitle: "システムプロンプト / キャラクターを管理",
clear: "クリア",
clearTitle: "チャットをクリア",
inputPlaceholder: "メッセージ(Ctrl+Enterで送信 / 画像は貼り付け可)",
attachTitle: "画像を添付(→ VLM)",
send: "送信",
stop: "停止",
ready: "待機中",
dropIdle: "🖼 画像をドロップ / クリックで選択 / 貼り付け(→ VLM / I2I)",
dropLocked: "🔌 画像入力が接続中です — そちらを優先します(ドロップ・選択は無効)",
dropTitle: "ここに画像をドロップ(VLMの入力 / I2Iのソース)",
unload: "⏏ アンロード",
unloadTitle: "Ollama のモデルをすべてVRAMからアンロード",
settings: "⚙ 設定",
promptSec: "🎨 プロンプト",
sectionToggle: "クリックで展開 / 折りたたみ",
empty: "(空)",
i2iSource: "I2Iソース",
i2iClear: "I2Iソースを解除",
freeingVram: "VRAMを解放中…",
generating: "生成中…",
queueFailed: "キュー投入に失敗: {msg}",
judging: "判定中…",
judgeBusy: "判定モデルが混み合っています — 再試行中…",
vramFailed: "VRAMの解放に失敗: {msg}",
vramUnloaded: "🧹 {names} をアンロード — 空き {a} → {b} GB",
vramShort: "⚠ 空きVRAM {a} GB < 目標 {t} GB",
vramShortInUse: "⚠ 空きVRAM {a} GB < 目標 {t} GB(使用中: {names})",
judgeFailed: "判定に失敗: {msg}",
judgeResult: "🧪 {model}: 一致 {match} / 品質 {quality}",
genOn: "画像生成 ON",
genOff: "画像生成 OFF — 通常のチャット",
presetsSaved: "プリセットを保存しました({n}件)",
presetsError: "プリセット: {msg}",
lockedDrop: "画像入力が接続されているため、そちらが優先されます。ドロップした画像を使うには接続を外してください。",
lockedPick: "画像入力が接続されているため、そちらが優先されます。選択した画像を使うには接続を外してください。",
onlyImages: "ドロップできるのは画像ファイルのみです",
streamingBusy: "ストリーミング中です — 先に停止してください",
unloading: "Ollama のモデルをアンロード中…",
unloaded: "アンロード: {names}",
unloadedFailed: "アンロード: {names} / 失敗: {failed}",
noneLoaded: "ロード中の Ollama モデルはありません",
unloadFailed: "アンロードに失敗: {msg}",
errorPrefix: "エラー: {msg}",
noVlm: "VLMが選択されていません",
noLlm: "LLMが選択されていません",
socketPriority: "画像入力が接続されているため、添付画像より優先します",
socketUnavailable: "画像入力は接続されていますが、まだ取得できません(Load Image ノードを使うか、グラフを一度実行してください)— 添付画像があればそれを使います",
charSwitched: "キャラクターのプリセットは <prompt> ブロックを使うため、プロンプトの取得方法を切り替えました",
streamingModel: "ストリーミング中({model})…",
thinkingStatus: "思考中…",
noThinkRetry: "⚠ このモデルは思考に対応していません — 思考なしで再試行します(chat_p は返信にフォールバック)",
noPromptWarn: "⚠ 応答に画像プロンプトが無いため、画像は生成されませんでした(モデルが <prompt> を省略 — プリセット/システムプロンプトを確認するか、大きいモデルを試してください)",
loadingModels: "モデル一覧を取得中…",
ollamaStatus: "Ollama {version} · {n} モデル",
ollamaUnreachable: "Ollama に接続できません: {msg}",
ollamaServerSetting: "サーバー設定",
ollamaServerSettingTitle: "Ollama のアドレスはブラウザではなくサーバー側で設定します(環境変数 LIVE_CHAT_STREAM_OLLAMA_URL または config.json)。",
noLlmOpt: "(LLMなし)",
noVlmOpt: "(VLMなし)",
noDecisionOpt: "(意思決定モデルなし)",
i2iSourceErr: "I2Iソース: {msg}",
mdTitle: "システムプロンプトのプリセット",
mdAddChar: "+ キャラクター",
mdAddPlain: "+ 通常",
mdDup: "複製",
mdDel: "削除",
mdImport: "インポート",
mdExport: "エクスポート",
mdCancel: "キャンセル",
mdSave: "保存",
mdSaveUse: "保存して使用",
mdNone: "プリセットがありません",
mdTypeChar: "キャラクター",
mdTypePlain: "通常",
mdCharName: "キャラクター名(プロンプトにも使われます)",
mdPresetName: "プリセット名",
mdFieldSystem: "システムプロンプト(空欄 = 組み込みの既定)",
mdFieldPersona: "性格・口調・背景",
mdFieldAppearance: "固定の外見タグ(英語、毎回 <prompt> の先頭に入ります)",
mdFieldEmotion: "感情表現のルール(任意)",
mdPreview: "実際に送られるシステムプロンプト(プレビュー)",
mdDefaultNoDelete: "Default は削除できません",
mdImported: "{n} 件インポートしました(保存で確定)",
mdImportFailed: "インポートに失敗: {msg}",
mdNoPresetsKey: "ファイルに \"presets\" がありません",
sampleName: "Lumi(サンプル)",
samplePersona: "ルミ。好奇心旺盛で少し照れ屋な16歳の少女。明るくくだけた口調で話し、嬉しいとすぐ顔に出る。ユーザーとの会話で感じたことを素直に表現する。",
},
zh: {
reloadModels: "重新获取模型列表",
llmTitle: "LLM(文本聊天)",
vlmTitle: "VLM(附带图片时使用)",
vlaTitle: "决策模型(评判生成的图片;需支持图片输入,如 clef)",
modeTitle: "何时开始生成图片",
modeClose: "</prompt> 结束时生成",
modeLive: "流式输出时持续生成",
modeManual: "手动(不自动生成)",
srcTitle: "用作图片提示词的部分",
srcTag: "提示词 = <prompt> 块",
srcResponse: "提示词 = 整个回复",
srcBTitle: "chat_p / chat_n: 将模型自身的思考 / 回复直接转为图片",
srcBOff: "chat_p: 关闭",
srcBThinking: "chat_p = 思考",
srcBReply: "chat_p = 回复",
srcBBoth: "chat_p = 思考 + 回复",
srcBMind: "chat_p = <mind> 块",
maxBTitle: "chat_p: 用作提示词的最大字符数",
negBTitle: "chat_n: 负面提示词",
mindEn: "mind 英文",
mindEnTitle: "用英文编写 <mind> 块(图像模型更擅长英文)",
vramTitle: "开始生成图片前卸载 Ollama 模型",
vramOff: "VRAM: 关闭",
vramAuto: "VRAM: 自动释放",
vramAll: "VRAM: 全部卸载",
vramGbTitle: "自动释放: 目标空闲 VRAM(GB)。从最大的模型开始,仅卸载所需数量",
gbFree: "GB 空闲(自动)",
judge: "评判",
think: "思考",
genTitle: "开启: 每次回复都生成图片 / 关闭: 普通聊天(不含图片提示词指令,不生成)",
genLabel: "🖼 图片",
presetTitle: "系统提示词 / 角色预设",
presetsBtn: "预设…",
presetsBtnTitle: "管理系统提示词 / 角色",
clear: "清除",
clearTitle: "清除聊天",
inputPlaceholder: "消息(Ctrl+Enter 发送 / 可粘贴图片)",
attachTitle: "附加图片(→ VLM)",
send: "发送",
stop: "停止",
ready: "就绪",
dropIdle: "🖼 拖放图片 / 点击选择 / 粘贴(→ VLM / I2I)",
dropLocked: "🔌 已连接图片输入 — 优先使用(拖放 / 选择已禁用)",
dropTitle: "将图片拖放到此处(VLM 输入 / I2I 来源)",
unload: "⏏ 卸载",
unloadTitle: "从 VRAM 卸载所有 Ollama 模型",
settings: "⚙ 设置",
promptSec: "🎨 提示词",
sectionToggle: "点击展开 / 折叠",
empty: "(空)",
i2iSource: "I2I 来源",
i2iClear: "清除 I2I 来源",
freeingVram: "正在释放 VRAM…",
generating: "生成中…",
queueFailed: "加入队列失败: {msg}",
judging: "评判中…",
judgeBusy: "评判模型繁忙 — 正在重试…",
vramFailed: "释放 VRAM 失败: {msg}",
vramUnloaded: "🧹 已卸载 {names} — 空闲 {a} → {b} GB",
vramShort: "⚠ 空闲 VRAM {a} GB < 目标 {t} GB",
vramShortInUse: "⚠ 空闲 VRAM {a} GB < 目标 {t} GB(使用中: {names})",
judgeFailed: "评判失败: {msg}",
judgeResult: "🧪 {model}: 匹配 {match} / 质量 {quality}",
genOn: "图片生成 已开启",
genOff: "图片生成 已关闭 — 普通聊天",
presetsSaved: "预设已保存({n} 个)",
presetsError: "预设: {msg}",
lockedDrop: "已连接图片输入,将优先使用。要使用拖放的图片,请先断开连接。",
lockedPick: "已连接图片输入,将优先使用。要使用选择的图片,请先断开连接。",
onlyImages: "只能拖放图片文件",
streamingBusy: "正在流式输出 — 请先停止",
unloading: "正在卸载 Ollama 模型…",
unloaded: "已卸载: {names}",
unloadedFailed: "已卸载: {names} / 失败: {failed}",
noneLoaded: "没有已加载的 Ollama 模型",
unloadFailed: "卸载失败: {msg}",
errorPrefix: "错误: {msg}",
noVlm: "未选择 VLM",
noLlm: "未选择 LLM",
socketPriority: "已连接图片输入,优先于附加的图片",
socketUnavailable: "已连接图片输入,但暂时无法获取(请使用 Load Image 节点,或先运行一次工作流)— 如有附加图片则使用它",
charSwitched: "角色预设使用 <prompt> 块,已切换提示词的获取方式",
streamingModel: "流式输出中({model})…",
thinkingStatus: "思考中…",
noThinkRetry: "⚠ 该模型不支持思考 — 不使用思考重试(chat_p 回退为回复)",
noPromptWarn: "⚠ 回复中没有图片提示词,因此未生成图片(模型省略了 <prompt> — 请检查预设 / 系统提示词,或尝试更大的模型)",
loadingModels: "正在获取模型列表…",
ollamaStatus: "Ollama {version} · {n} 个模型",
ollamaUnreachable: "无法连接 Ollama: {msg}",
ollamaServerSetting: "服务器设置",
ollamaServerSettingTitle: "Ollama 地址在服务器端设置(环境变量 LIVE_CHAT_STREAM_OLLAMA_URL 或 config.json),而不是在浏览器中。",
noLlmOpt: "(无 LLM)",
noVlmOpt: "(无 VLM)",
noDecisionOpt: "(无决策模型)",
i2iSourceErr: "I2I 来源: {msg}",
mdTitle: "系统提示词预设",
mdAddChar: "+ 角色",
mdAddPlain: "+ 普通",
mdDup: "复制",
mdDel: "删除",
mdImport: "导入",
mdExport: "导出",
mdCancel: "取消",
mdSave: "保存",
mdSaveUse: "保存并使用",
mdNone: "没有预设",
mdTypeChar: "角色",
mdTypePlain: "普通",
mdCharName: "角色名称(也会用于提示词)",
mdPresetName: "预设名称",
mdFieldSystem: "系统提示词(留空 = 内置默认)",
mdFieldPersona: "性格、语气、背景",
mdFieldAppearance: "固定外观标签(英文,始终放在 <prompt> 开头)",
mdFieldEmotion: "情感表达规则(可选)",
mdPreview: "实际发送的系统提示词(预览)",
mdDefaultNoDelete: "无法删除 Default",
mdImported: "已导入 {n} 个(按保存确认)",
mdImportFailed: "导入失败: {msg}",
mdNoPresetsKey: "文件中没有 \"presets\"",
sampleName: "Lumi(示例)",
samplePersona: "露米,一个好奇心旺盛、有点害羞的16岁少女。说话轻松开朗,开心时会立刻表现在脸上。会坦率地表达自己对对话的感受。",
},
};
// 英語を基準に、未定義のキーは英語へフォールバックする
function currentLang() {
let locale = "en";
try {
locale = app.extensionManager?.setting?.get?.("Comfy.Locale") || "en";
} catch {
locale = "en";
}
const short = String(locale).split("-")[0].toLowerCase();
return DICT[short] ? short : "en";
}
export function t(key, params) {
const dict = DICT[currentLang()] || DICT.en;
let str = dict[key] ?? DICT.en[key] ?? key;
if (params) {
for (const [k, v] of Object.entries(params)) str = str.split(`{${k}}`).join(String(v));
}
return str;
}