diff --git a/modules/novel-draw/llm-service.js b/modules/novel-draw/llm-service.js index 280b160..46131e7 100644 --- a/modules/novel-draw/llm-service.js +++ b/modules/novel-draw/llm-service.js @@ -41,6 +41,10 @@ Output: userTemplate: ` 这是你要配图的场景的背景知识设定(世界观/人设/场景设定),用于你理解背景: +用户设定: +{{persona}} +--- +世界/场景: {{description}} --- {$worldInfo} @@ -206,92 +210,75 @@ export async function generateScenePlan(options) { presentCharacters = [], llmApi = {}, useStream = false, - useWorldInfo = false, // 新增:默认不使用世界书 + useWorldInfo = false, timeout = 120000 } = options; - + if (!messageText?.trim()) { throw new LLMServiceError('消息内容为空', 'EMPTY_MESSAGE'); } - + const charInfo = buildCharacterInfoForLLM(presentCharacters); - - // msg1: systemPrompt (硬编码) + + // msg1: systemPrompt const msg1 = LLM_PROMPT_CONFIG.systemPrompt; - - // msg2: assistantAck + TAG编写指南注入 + + // msg2: assistantAck + TAG编写指南 let msg2 = LLM_PROMPT_CONFIG.assistantAck; if (tagGuideContent) { msg2 = msg2.replace('{$tagGuide}', tagGuideContent); } else { msg2 = msg2.replace(/我已查阅以下.*?\n\s*\{\$tagGuide\}\s*\n/g, ''); } - + // msg3: userTemplate let msg3 = LLM_PROMPT_CONFIG.userTemplate .replace('{{lastMessage}}', messageText) .replace('{{characterInfo}}', charInfo); - - // 根据 useWorldInfo 决定是否保留 {$worldInfo} 占位符 + + // 不用世界书时:只清空占位符 if (!useWorldInfo) { - // 不使用世界书时,清空占位符 msg3 = msg3.replace(/\{\$worldInfo\}/gi, ''); - // 清理多余的空行和分隔线 - msg3 = msg3.replace(/---\s*\n\s*(?=<\/worldInfo>)/g, ''); } - + // msg4: assistantPrefix const msg4 = LLM_PROMPT_CONFIG.assistantPrefix; - - const messages = [ + + // 只把 msg1+msg2 放到 top + const topMessages = [ { role: 'user', content: msg1 }, { role: 'assistant', content: msg2 }, - { role: 'user', content: msg3 }, - { role: 'assistant', content: msg4 } ]; - + const streamingMod = getStreamingModule(); if (!streamingMod) { throw new LLMServiceError('xbgenraw 模块不可用', 'MODULE_UNAVAILABLE'); } - + const args = { as: 'user', nonstream: useStream ? 'false' : 'true', - top64: b64UrlEncode(JSON.stringify(messages)), + top64: b64UrlEncode(JSON.stringify(topMessages)), + bottomassistant: msg4, id: 'xb_nd_scene_plan' }; - - if (useWorldInfo) { - args.addon = 'worldInfo'; - } - - // 渠道配置 - const provider = String(llmApi.provider || '').toLowerCase(); - const mappedApi = PROVIDER_MAP[provider]; - if (mappedApi && provider !== 'st') { - args.api = mappedApi; - if (llmApi.url) args.apiurl = llmApi.url; - if (llmApi.key) args.apipassword = llmApi.key; - if (llmApi.model) args.model = llmApi.model; - } - + let rawOutput; try { if (useStream) { - const sessionId = await streamingMod.xbgenrawCommand(args, ''); + const sessionId = await streamingMod.xbgenrawCommand(args, msg3); rawOutput = await waitForStreamingComplete(sessionId, streamingMod, timeout); } else { - rawOutput = await streamingMod.xbgenrawCommand(args, ''); + rawOutput = await streamingMod.xbgenrawCommand(args, msg3); } } catch (e) { throw new LLMServiceError(`LLM 调用失败: ${e.message}`, 'CALL_FAILED'); } - + console.group('%c[LLM-Service] 场景分析输出', 'color: #d4a574; font-weight: bold'); console.log(rawOutput); console.groupEnd(); - + return rawOutput; }