kiku-agent 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -12
- package/package.json +5 -12
- package/server/agent/agentCore.js +319 -46
- package/server/agent/appPaths.js +31 -0
- package/server/agent/audioPlayer.js +339 -12
- package/server/agent/autoContext.js +193 -0
- package/server/agent/catalogEntityResolver.js +170 -28
- package/server/agent/clarifyingQuestions.js +137 -35
- package/server/agent/cli.js +177 -48
- package/server/agent/cloudAdapters.js +116 -0
- package/server/agent/commandRegistry.js +409 -80
- package/server/agent/commands.js +1056 -125
- package/server/agent/config.js +1088 -690
- package/server/agent/contextCompactor.js +213 -21
- package/server/agent/cpuMetrics.js +199 -0
- package/server/agent/engineService.js +591 -0
- package/server/agent/eval/AGENTS.md +228 -0
- package/server/agent/eval/analyze.py +684 -0
- package/server/agent/eval/gates.json +15 -0
- package/server/agent/eval/modules/analysis/compare.js +198 -0
- package/server/agent/eval/modules/analysis/gates.js +72 -0
- package/server/agent/eval/modules/analysis/judge.js +70 -0
- package/server/agent/eval/modules/core/cli.js +453 -0
- package/server/agent/eval/modules/core/config.js +60 -0
- package/server/agent/eval/modules/core/store.js +236 -0
- package/server/agent/eval/modules/evaluation/cases.js +689 -0
- package/server/agent/eval/modules/evaluation/runner.js +288 -0
- package/server/agent/eval/modules/evaluation/scoring.js +363 -0
- package/server/agent/eval/modules/evaluation/worker.js +122 -0
- package/server/agent/eval/modules/reporting/benchmark.js +265 -0
- package/server/agent/eval/modules/reporting/benchmarkPng.js +487 -0
- package/server/agent/eval/modules/reporting/dashboard.js +1406 -0
- package/server/agent/eval/modules/server/evalApi.js +1099 -0
- package/server/agent/eval/modules/ui/evalUi.js +4799 -0
- package/server/agent/eval/modules/utils/smokes.js +119 -0
- package/server/agent/eventBus.js +1 -0
- package/server/agent/ink/main.jsx +196 -191
- package/server/agent/jobManager.js +11 -1
- package/server/agent/lanDiscovery.js +721 -23
- package/server/agent/llmClient.js +317 -71
- package/server/agent/lmStudioWakeup.js +517 -65
- package/server/agent/locationService.js +797 -0
- package/server/agent/mcpQuizData.js +509 -0
- package/server/agent/memory/contextAllocator.js +19 -7
- package/server/agent/memory.js +3 -1
- package/server/agent/modelCompatibility.js +352 -0
- package/server/agent/modelDefaults.js +1 -0
- package/server/agent/modelManager.js +46 -2
- package/server/agent/newsWatch.js +9 -3
- package/server/agent/processManager.js +229 -0
- package/server/agent/prompts.js +174 -8
- package/server/agent/routingInterceptor.js +9 -1
- package/server/agent/sanitizer.js +41 -6
- package/server/agent/searchQueryPlanner.js +202 -0
- package/server/agent/session.js +59 -4
- package/server/agent/tests/agentBubbleSystem.test.js +65 -0
- package/server/agent/tests/agentFollowUps.test.js +253 -0
- package/server/agent/tests/agentMusicControl.test.js +245 -0
- package/server/agent/tests/apiRouter.test.js +108 -0
- package/server/agent/tests/architectureFixes.test.js +81 -0
- package/server/agent/tests/architectureRefactoring.test.js +194 -0
- package/server/agent/tests/autoContext.test.js +176 -0
- package/server/agent/tests/autoResearch.test.js +64 -0
- package/server/agent/tests/bilibiliEmbed.test.js +296 -0
- package/server/agent/tests/catalogSync.test.js +130 -0
- package/server/agent/tests/chatHardening.test.js +121 -0
- package/server/agent/tests/chineseWebSearchEscalation.test.js +62 -0
- package/server/agent/tests/citations.test.js +180 -0
- package/server/agent/tests/clarificationAnalytics.test.js +219 -0
- package/server/agent/tests/clarifyingQuestions.test.js +627 -0
- package/server/agent/tests/cliAutomation.test.js +158 -0
- package/server/agent/tests/cloudProviders.test.js +322 -0
- package/server/agent/tests/commandInput.test.js +24 -0
- package/server/agent/tests/commands.test.js +506 -0
- package/server/agent/tests/contextIntelligence.test.js +209 -0
- package/server/agent/tests/conversationSafety.test.js +53 -0
- package/server/agent/tests/cpuMetrics.test.js +101 -0
- package/server/agent/tests/decisionAndSearchEnhancements.test.js +167 -0
- package/server/agent/tests/dramaAnswerQuality.test.js +73 -0
- package/server/agent/tests/dynamicCatalogIngestion.test.js +285 -0
- package/server/agent/tests/dynamicRoutingAndSearch.test.js +92 -0
- package/server/agent/tests/edgeCasesScenarios.test.js +131 -0
- package/server/agent/tests/engineService.test.js +436 -0
- package/server/agent/tests/engineUnload.test.js +94 -0
- package/server/agent/tests/entertainmentMetrics.test.js +126 -0
- package/server/agent/tests/envBootstrap.test.js +87 -0
- package/server/agent/tests/envCommand.test.js +284 -0
- package/server/agent/tests/errorHandling.test.js +80 -0
- package/server/agent/tests/errors.test.js +13 -0
- package/server/agent/tests/evalAnalyze.test.js +54 -0
- package/server/agent/tests/evalCommand.test.js +54 -0
- package/server/agent/tests/evalCorpus.test.js +126 -0
- package/server/agent/tests/evalHarness.test.js +62 -0
- package/server/agent/tests/evalJudgeContext.test.js +38 -0
- package/server/agent/tests/evalMetrics.test.js +320 -0
- package/server/agent/tests/evalStore.test.js +190 -0
- package/server/agent/tests/evalStudio.test.js +179 -0
- package/server/agent/tests/feedbackLearning.test.js +186 -0
- package/server/agent/tests/fetchApi.test.js +99 -0
- package/server/agent/tests/firstRun.test.js +44 -0
- package/server/agent/tests/gemma4eOptimization.test.js +95 -0
- package/server/agent/tests/hardwareTiers.test.js +206 -0
- package/server/agent/tests/hybridWebSearch.test.js +194 -0
- package/server/agent/tests/judgeService.test.js +251 -0
- package/server/agent/tests/lanDiscovery.test.js +324 -0
- package/server/agent/tests/lanInterfaces.test.js +510 -0
- package/server/agent/tests/lmStudioWakeup.test.js +278 -0
- package/server/agent/tests/locationTool.test.js +278 -0
- package/server/agent/tests/mcpClient.test.js +201 -0
- package/server/agent/tests/memoryRoute.test.js +173 -0
- package/server/agent/tests/memoryUiNormalization.test.js +75 -0
- package/server/agent/tests/modelCompatibility.test.js +148 -0
- package/server/agent/tests/modelManager.test.js +141 -0
- package/server/agent/tests/multilingualScenarios.test.js +69 -0
- package/server/agent/tests/musicControlUiBridge.test.js +113 -0
- package/server/agent/tests/newCommands.test.js +347 -0
- package/server/agent/tests/newCommandsTui.test.js +141 -0
- package/server/agent/tests/newTools.test.js +113 -0
- package/server/agent/tests/newsIntelligence.test.js +178 -0
- package/server/agent/tests/nextGenArchitecture.test.js +101 -0
- package/server/agent/tests/offlineInput.test.js +217 -0
- package/server/agent/tests/openDomainPrompt.test.js +197 -0
- package/server/agent/tests/openDomainSearch.test.js +121 -0
- package/server/agent/tests/packagingGuard.test.js +57 -0
- package/server/agent/tests/presentation.test.js +61 -0
- package/server/agent/tests/processManager.test.js +144 -0
- package/server/agent/tests/providerPersistence.test.js +44 -0
- package/server/agent/tests/queryBenchmarks.test.js +83 -0
- package/server/agent/tests/queryDetails.test.js +126 -0
- package/server/agent/tests/quickActionsAndModals.test.js +180 -0
- package/server/agent/tests/realWorldValidation.test.js +391 -0
- package/server/agent/tests/resilienceAndConcurrency.test.js +117 -0
- package/server/agent/tests/runtimeWatchdog.test.js +32 -0
- package/server/agent/tests/sanitizer.test.js +37 -0
- package/server/agent/tests/scenariosData.js +378 -0
- package/server/agent/tests/schemaRouting.test.js +54 -0
- package/server/agent/tests/searchQueryPlanner.test.js +108 -0
- package/server/agent/tests/securityAuditRemediation.test.js +221 -0
- package/server/agent/tests/securityAuditRemediations2.test.js +154 -0
- package/server/agent/tests/securityHardening.test.js +146 -0
- package/server/agent/tests/securitySanitizer.test.js +38 -0
- package/server/agent/tests/sessionAndCopy.test.js +267 -0
- package/server/agent/tests/sidebarControls.test.js +135 -0
- package/server/agent/tests/statefulMemory.test.js +277 -0
- package/server/agent/tests/subagent.test.js +216 -0
- package/server/agent/tests/subagentProgress.test.js +109 -0
- package/server/agent/tests/subagentTextFallback.test.js +115 -0
- package/server/agent/tests/suggestions.test.js +199 -0
- package/server/agent/tests/suggestionsTui.test.js +251 -0
- package/server/agent/tests/telemetryAndProfiles.test.js +179 -0
- package/server/agent/tests/terminalImage.test.js +80 -0
- package/server/agent/tests/terminalMarkdown.test.js +166 -0
- package/server/agent/tests/terminalText.test.js +133 -0
- package/server/agent/tests/textProtocolLoop.test.js +197 -0
- package/server/agent/tests/textToolParsing.test.js +187 -0
- package/server/agent/tests/theme.test.js +26 -0
- package/server/agent/tests/toolRegistryParity.test.js +53 -0
- package/server/agent/tests/toolRoutingRegressions.test.js +160 -0
- package/server/agent/tests/tools.test.js +259 -0
- package/server/agent/tests/unifiedEndpoints.test.js +159 -0
- package/server/agent/tests/v110Features.test.js +262 -0
- package/server/agent/tests/versionBump.test.js +69 -0
- package/server/agent/tests/vramEstimator.test.js +595 -0
- package/server/agent/tests/webChatDocs.test.js +199 -0
- package/server/agent/tests/webChatInferenceControl.test.js +298 -0
- package/server/agent/tests/webChatInspection.test.js +551 -0
- package/server/agent/tests/webChatMcp.test.js +94 -0
- package/server/agent/tests/webChatMemory.test.js +112 -0
- package/server/agent/tests/webChatSecurity.test.js +169 -0
- package/server/agent/tests/webExtract.test.js +284 -0
- package/server/agent/tests/webSources.test.js +281 -0
- package/server/agent/textToolProtocol.js +173 -46
- package/server/agent/toolRouter.js +318 -44
- package/server/agent/tools.js +877 -96
- package/server/agent/ui.js +39 -34
- package/server/agent/vramService.js +35 -54
- package/server/agent/webSearch.js +441 -162
- package/server/agent/websearch/orchestrator.js +15 -5
- package/server/agent/websearch/resilience/cache.js +9 -2
- package/server/agent/websearch/security/ssrf.js +41 -10
- package/server/agent/youtubeAuth.js +5 -20
- package/server/apiRouter.js +5558 -4422
- package/server/eval/judgeRubrics.js +110 -0
- package/server/eval/judgeService.js +290 -0
- package/server/eval/runBenchmark.js +182 -0
- package/server/mcp/data/discography.js +2 -2
- package/server/mcp/examples/antigravity.example.json +17 -0
- package/server/mcp/examples/librechat.example.yaml +16 -0
- package/server/mcp/handler.js +8 -4
- package/server/mcp/security.js +220 -21
- package/server/mcp/server.js +2 -1
- package/server/mcp/tests/connection.test.js +162 -0
- package/server/mcp/tests/mcpKeyAuth.test.js +156 -0
- package/server/mcp/tools.js +7 -1
- package/server/supabase_migration_prefix.sql +102 -0
- package/server/supabase_schema.sql +63 -0
- package/server/web-chat/core/connection.js +179 -218
- package/server/web-chat/core/conversationContext.js +9 -2
- package/server/web-chat/core/directCatalogEngine.js +52 -28
- package/server/web-chat/core/dramaKnowledge.js +33 -22
- package/server/web-chat/core/followUpEngine.js +735 -81
- package/server/web-chat/core/futureEventGuard.js +5 -1
- package/server/web-chat/core/musicControlAction.js +70 -0
- package/server/web-chat/core/security.js +32 -21
- package/server/web-chat/core/toolInspector.js +6 -6
- package/server/web-chat/core/urlGuard.js +45 -0
- package/server/web-chat/router.js +204 -157
- package/server/web-chat/routes/chatRoute.js +885 -488
- package/server/web-chat/routes/engineRoute.js +270 -0
- package/server/web-chat/routes/exportRoute.js +1 -1
- package/server/web-chat/routes/lanDiscoveryRoute.js +17 -2
- package/server/web-chat/routes/lmStudioLoadRoute.js +172 -0
- package/server/web-chat/routes/mcpRoute.js +386 -0
- package/server/web-chat/routes/memoryRoute.js +253 -0
- package/server/web-chat/routes/providerRoute.js +49 -16
- package/server/web-chat/routes/staticRoute.js +306 -17
- package/server/web-chat/routes/statusRoute.js +194 -73
- package/server/web-chat/routes/suggestRoute.js +11 -3
- package/server/web-chat/routes/verifyRoute.js +26 -4
- package/server/web-chat/server.js +7 -6
- package/server/web-chat/ui/docsBuilder.js +3558 -0
- package/server/web-chat/ui/htmlBuilder.js +12 -0
- package/server/web-chat/ui/scripts/client.js +3401 -1302
- package/server/web-chat/ui/scripts/webchatI18n.js +155 -153
- package/server/web-chat/ui/settingsBuilder.js +7870 -0
- package/server/web-chat/ui/styles/lan-card.css +165 -0
- package/server/web-chat/ui/styles/main.css +4289 -447
- package/server/web-chat/ui/sw.js +64 -0
- package/server/web-chat/ui/templates/body.html +407 -281
- package/src/data/awardsData.js +146 -146
- package/src/data/musicVideoData.js +6 -4
- package/src/lib/vram/estimator.js +195 -19
|
@@ -2,7 +2,8 @@ import { executeTool } from '../../agent/tools.js';
|
|
|
2
2
|
import { makeInspectableToolPayload } from './toolInspector.js';
|
|
3
3
|
import { generateDynamicFollowUps } from './followUpEngine.js';
|
|
4
4
|
import { buildDramaSpecialistAnswer } from './dramaKnowledge.js';
|
|
5
|
-
import { resolveQueryEntities
|
|
5
|
+
import { resolveQueryEntities } from '../../agent/catalogEntityResolver.js';
|
|
6
|
+
import { evaluateMusicControlIntent } from '../../agent/audioPlayer.js';
|
|
6
7
|
|
|
7
8
|
export async function executeDirectCatalogKnowledge(query, _persona = 'default', options = {}) {
|
|
8
9
|
const toolsUsed = [];
|
|
@@ -30,6 +31,35 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
30
31
|
}
|
|
31
32
|
};
|
|
32
33
|
|
|
34
|
+
const musicIntent = evaluateMusicControlIntent(query);
|
|
35
|
+
if (musicIntent && musicIntent.score >= 3) {
|
|
36
|
+
let args = {};
|
|
37
|
+
if (musicIntent.action === 'set_volume') {
|
|
38
|
+
args = { volume: musicIntent.volume !== undefined ? musicIntent.volume : 80 };
|
|
39
|
+
} else if (musicIntent.action === 'seek') {
|
|
40
|
+
args = { seconds: musicIntent.seconds || 0 };
|
|
41
|
+
} else if (musicIntent.action === 'set_repeat') {
|
|
42
|
+
args = { mode: 'all' };
|
|
43
|
+
} else if (musicIntent.action === 'set_shuffle') {
|
|
44
|
+
args = { enabled: true };
|
|
45
|
+
} else if (musicIntent.action === 'play') {
|
|
46
|
+
const cleanSongQuery = query.replace(/(?:เล่นเพลง|เปิดเพลง|ฟังเพลง|play\s*song|放歌|听歌)/gi, '').trim();
|
|
47
|
+
args = cleanSongQuery ? { query: cleanSongQuery } : {};
|
|
48
|
+
}
|
|
49
|
+
const toolRes = await addToolExec(musicIntent.tool, args);
|
|
50
|
+
const msg = toolRes?.message || 'ดำเนินการควบคุมเครื่องเล่นเพลงเรียบร้อยแล้ว';
|
|
51
|
+
return {
|
|
52
|
+
answer: `> [OK] **Music Player Control**\n> ${msg}`,
|
|
53
|
+
thinking: 'ตรวจพบคำสั่งควบคุมเพลง -> ดำเนินการผ่าน Music Tool ทันที',
|
|
54
|
+
tools: toolsUsed,
|
|
55
|
+
suggestions: [
|
|
56
|
+
{ label: '❚❚ พักการเล่นเพลง', action: 'send_query', query: 'พักเพลง' },
|
|
57
|
+
{ label: '▶ เล่นเพลงต่อ', action: 'send_query', query: 'เล่นต่อ' },
|
|
58
|
+
{ label: '■ ปิดเพลง', action: 'send_query', query: 'ปิดเพลง' }
|
|
59
|
+
]
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
33
63
|
const specialistAnswer = await buildDramaSpecialistAnswer(query, addToolExec);
|
|
34
64
|
if (specialistAnswer) answerParts.push(specialistAnswer);
|
|
35
65
|
|
|
@@ -38,7 +68,7 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
38
68
|
if (!specialistAnswer && (q.includes('ประวัติ') || q.includes('who is') || q.includes('profile') || q.includes('slogan') || q.includes('ฉายา'))) {
|
|
39
69
|
const profile = await addToolExec('get_profile_and_fandom', {});
|
|
40
70
|
if (profile) {
|
|
41
|
-
answerParts.push(`###
|
|
71
|
+
answerParts.push(`### [Profile] ประวัติและข้อมูลส่วนตัว: จวีจิ้งอี (Ju Jingyi / 鞠婧祎)\n\n` +
|
|
42
72
|
`- **ชื่อภาษาจีน:** ${profile.profile?.nameCn || '鞠婧祎'} (${profile.profile?.pinyin || 'Jū Jìngyī'})\n` +
|
|
43
73
|
`- **ชื่อสากล/ฉายา:** Kiku / เสี่ยวจวี (小鞠) / สาวงาม 4,000 ปี\n` +
|
|
44
74
|
`- **วันเกิด:** ${profile.profile?.birthDate || '18 มิถุนายน 1994'}\n` +
|
|
@@ -49,7 +79,6 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
49
79
|
}
|
|
50
80
|
}
|
|
51
81
|
|
|
52
|
-
|
|
53
82
|
if (!specialistAnswer && (entityRes.hasBrand || q.includes('แบรนด์') || q.includes('พรีเซนเตอร์') || q.includes('ambassador') || q.includes('โฆษณา') || q.includes('โปรโมท') || q.includes('โปรโมต') || entityRes.isPromotion)) {
|
|
54
83
|
const brandQuery = entityRes.primaryBrand ? (entityRes.primaryBrand.nameEn || entityRes.primaryBrand.id) : undefined;
|
|
55
84
|
const brandsRes = await addToolExec('get_brand_endorsements', brandQuery ? { query: brandQuery } : {});
|
|
@@ -57,51 +86,50 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
57
86
|
if (brands.length > 0) {
|
|
58
87
|
if (entityRes.primaryBrand) {
|
|
59
88
|
const b = brands[0];
|
|
60
|
-
let md = `###
|
|
89
|
+
let md = `### [Brand] ข้อมูลแบรนด์: ${b.brand} (${b.year || 'ปัจจุบัน'})\n\n` +
|
|
61
90
|
`- **ตำแหน่ง:** ${b.title || 'Brand Ambassador'}\n` +
|
|
62
91
|
`- **หมวดหมู่:** ${b.category || 'Luxury'}\n` +
|
|
63
92
|
`- **ไฮไลต์สำคัญ:** ${b.highlight || 'พรีเซนเตอร์ระดับโลกของจวีจิ้งอี'}\n`;
|
|
64
|
-
if (b.bilibiliSearchUrl) md += `-
|
|
65
|
-
if (b.youtubeCommercialSearch) md += `-
|
|
93
|
+
if (b.bilibiliSearchUrl) md += `- [Link] [ค้นหาคลิปโปรโมทบน Bilibili](${b.bilibiliSearchUrl})\n`;
|
|
94
|
+
if (b.youtubeCommercialSearch) md += `- [Link] [ค้นหาโฆษณาบน YouTube](${b.youtubeCommercialSearch})\n`;
|
|
66
95
|
answerParts.push(md);
|
|
67
96
|
} else {
|
|
68
|
-
let md = `###
|
|
97
|
+
let md = `### [Brand] บทบาท Brand Ambassador และพรีเซนเตอร์ระดับโลก (${brands.length} แบรนด์)\n\n`;
|
|
69
98
|
brands.slice(0, 15).forEach(b => {
|
|
70
99
|
md += `- **${b.brand}** — ตำแหน่ง: **${b.title}** (${b.category || 'Luxury'}) [ปี ${b.year || 'ปัจจุบัน'}]\n`;
|
|
71
|
-
if (b.bilibiliSearchUrl) md += ` -
|
|
100
|
+
if (b.bilibiliSearchUrl) md += ` - [Link] [คลิปบน Bilibili](${b.bilibiliSearchUrl})\n`;
|
|
72
101
|
});
|
|
73
102
|
answerParts.push(md);
|
|
74
103
|
}
|
|
75
104
|
}
|
|
76
105
|
}
|
|
77
106
|
|
|
78
|
-
|
|
79
107
|
if (!specialistAnswer && (entityRes.hasWork || q.includes('ซีรีส์') || q.includes('ละคร') || q.includes('หนัง') || q.includes('ผลงาน') || q.includes('บทบาท'))) {
|
|
80
108
|
const workQuery = entityRes.primaryWork ? (entityRes.primaryWork.nameCn || entityRes.primaryWork.nameEn) : q.replace(/(ซีรีส์|ละคร|หนัง|ผลงาน|เรื่อง|เด่น|ของ|จวีจิ้งอี)/g, '').trim();
|
|
81
109
|
const worksRes = await addToolExec('search_works', { query: workQuery });
|
|
82
110
|
if (worksRes?.status === 'rumored_project_info' && worksRes?.rumoredProject) {
|
|
83
111
|
const r = worksRes.rumoredProject;
|
|
84
|
-
answerParts.push(`###
|
|
112
|
+
answerParts.push(`### [Series] ข้อมูลซีรีส์ 《${r.titleCn}》 (${r.titleEn})\n\n` +
|
|
85
113
|
`**《${r.titleCn}》** เป็นโปรเจกต์ซีรีส์ที่มีกระแสข่าวลือแคสติ้ง (${r.status}):\n\n` +
|
|
86
|
-
`####
|
|
114
|
+
`#### [Details] รายละเอียดโปรเจกต์:\n` +
|
|
87
115
|
`- **ผู้ผลิต:** ${r.producer || 'Youku x Stellar Media'}\n` +
|
|
88
116
|
`- **ต้นฉบับ:** ${r.originalNovel || 'นวนิยายจีน'}\n` +
|
|
89
117
|
`- **เนื้อหา:** ${r.details || ''}\n\n` +
|
|
90
|
-
`####
|
|
118
|
+
`#### [Highlight] เหตุผลที่เป็นกระแส:\n` +
|
|
91
119
|
`${r.buzzReason || ''}\n\n` +
|
|
92
|
-
`>
|
|
120
|
+
`> [Notice] **ข้อควรระวัง (Disambiguation):** ${r.disambiguation || ''}`);
|
|
93
121
|
} else {
|
|
94
122
|
const works = worksRes?.works || [];
|
|
95
123
|
if (works.length > 0) {
|
|
96
|
-
let md = `###
|
|
124
|
+
let md = `### [Works] ผลงานซีรีส์และภาพยนตร์ที่โดดเด่น (${works.length} เรื่อง)\n\n`;
|
|
97
125
|
works.slice(0, 15).forEach(w => {
|
|
98
|
-
md += `####
|
|
126
|
+
md += `#### [Featured] **${w.titleTh || w.titleCn}** (${w.titleCn || ''})\n` +
|
|
99
127
|
`- **บทบาทที่ได้รับ:** ${w.role || w.character || 'นักแสดงนำ'}\n` +
|
|
100
128
|
`- **ปีที่ฉาย:** ${w.year || 'N/A'} • **ประเภท:** ${w.category || 'ซีรีส์โบราณ/โรแมนติก'}\n` +
|
|
101
129
|
`- **เรื่องย่อ:** ${w.synopsis || w.description || 'ผลงานซีรีส์ชื่อดังของจวีจิ้งอี'}\n` +
|
|
102
130
|
`- **ช่องทางรับชม:** ${w.streamingPlatform || w.platform || 'ไม่ระบุในแคตตาล็อก'}\n`;
|
|
103
131
|
if (w.youtubeSearchUrl) {
|
|
104
|
-
md += `-
|
|
132
|
+
md += `- [Link] [ดูตัวอย่างบน YouTube](${w.youtubeSearchUrl})\n\n`;
|
|
105
133
|
} else {
|
|
106
134
|
md += `\n`;
|
|
107
135
|
}
|
|
@@ -111,27 +139,25 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
111
139
|
}
|
|
112
140
|
}
|
|
113
141
|
|
|
114
|
-
|
|
115
142
|
if (!specialistAnswer && (entityRes.hasSong || q.includes('เพลง') || q.includes('อัลบั้ม') || q.includes('ost') || q.includes('ร้อง'))) {
|
|
116
143
|
const songQuery = entityRes.primarySong ? (entityRes.primarySong.nameCn || entityRes.primarySong.nameEn) : q.replace(/(เพลง|อัลบั้ม|ost|ของ|จวีจิ้งอี)/g, '').trim();
|
|
117
144
|
const discoRes = await addToolExec('search_discography', { query: songQuery });
|
|
118
145
|
const songs = discoRes?.songs || [];
|
|
119
146
|
if (songs.length > 0) {
|
|
120
|
-
let md = `###
|
|
147
|
+
let md = `### [Discography] ผลงานเพลงและเพลงประกอบซีรีส์ (${songs.length} เพลง)\n\n`;
|
|
121
148
|
songs.slice(0, 20).forEach(s => {
|
|
122
149
|
md += `- **${s.titleTh || s.titleCn}** (${s.titleCn || ''}) — *ปี ${s.year || ''}* [ประเภท: ${s.work || 'Single'}]\n`;
|
|
123
|
-
if (s.youtubeUrl) md += ` -
|
|
150
|
+
if (s.youtubeUrl) md += ` - [Link] [ฟังบน YouTube](${s.youtubeUrl})\n`;
|
|
124
151
|
});
|
|
125
152
|
answerParts.push(md);
|
|
126
153
|
}
|
|
127
154
|
}
|
|
128
155
|
|
|
129
|
-
|
|
130
156
|
if (!specialistAnswer && (entityRes.hasAward || q.includes('รางวัล') || q.includes('award') || q.includes('เกียรติยศ'))) {
|
|
131
157
|
const awardsRes = await addToolExec('get_awards', {});
|
|
132
158
|
const awards = awardsRes?.awards || [];
|
|
133
159
|
if (awards.length > 0) {
|
|
134
|
-
let md = `###
|
|
160
|
+
let md = `### [Awards] รางวัลและความสำเร็จสำคัญ (${awards.length} รางวัล)\n\n`;
|
|
135
161
|
awards.slice(0, 20).forEach(a => {
|
|
136
162
|
md += `- **${a.year || ''}**: ${a.award || a.title} (${a.ceremony || 'งานประกาศรางวัล'}) — *${a.category || ''}*\n`;
|
|
137
163
|
});
|
|
@@ -139,12 +165,11 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
139
165
|
}
|
|
140
166
|
}
|
|
141
167
|
|
|
142
|
-
|
|
143
168
|
if (!specialistAnswer && (entityRes.hasTimeline || q.includes('ไทม์ไลน์') || q.includes('timeline') || q.includes('snh48') || q.includes('เส้นทาง') || q.includes('อดีต'))) {
|
|
144
169
|
const timelineRes = await addToolExec('get_career_timeline', {});
|
|
145
170
|
const events = timelineRes?.timeline || [];
|
|
146
171
|
if (events.length > 0) {
|
|
147
|
-
let md = `###
|
|
172
|
+
let md = `### [Timeline] ไทม์ไลน์เส้นทางอาชีพสำคัญ (${events.length} เหตุการณ์)\n\n`;
|
|
148
173
|
events.slice(0, 20).forEach(e => {
|
|
149
174
|
md += `- **ปี ${e.year}**: ${e.title} — ${e.description || ''}\n`;
|
|
150
175
|
});
|
|
@@ -152,12 +177,11 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
152
177
|
}
|
|
153
178
|
}
|
|
154
179
|
|
|
155
|
-
|
|
156
180
|
if (!specialistAnswer && (q.includes('บทบาท') || q.includes('ตัวละคร') || q.includes('character') || q.includes('role'))) {
|
|
157
181
|
const rolesRes = await addToolExec('get_character_roles', {});
|
|
158
182
|
const roles = rolesRes?.roles || [];
|
|
159
183
|
if (roles.length > 0) {
|
|
160
|
-
let md = `###
|
|
184
|
+
let md = `### [Roles] โครงสร้างบทบาทและตัวละครเด่น (${roles.length} บทบาท)\n\n`;
|
|
161
185
|
roles.slice(0, 15).forEach(r => {
|
|
162
186
|
md += `- **${r.nameTh || r.nameCn}** (${r.nameCn || ''}) จากเรื่อง *${r.drama || ''}* — บุคลิก: ${r.personality || r.archetype || 'ตัวเอก'}\n`;
|
|
163
187
|
});
|
|
@@ -177,9 +201,9 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
177
201
|
const worksRes = await addToolExec('search_works', { featuredOnly: true });
|
|
178
202
|
const brandRes = await addToolExec('get_brand_endorsements', { isGlobal: true });
|
|
179
203
|
const topBrand = brandRes?.brands?.[0]?.brand || 'Global Brand Ambassador';
|
|
180
|
-
let md = `###
|
|
204
|
+
let md = `### [Profile] ข้อมูลสรุป จวีจิ้งอี (Ju Jingyi / 鞠婧祎)\n\n`;
|
|
181
205
|
md += `จวีจิ้งอี เป็นศิลปิน นักร้อง และนักแสดงหญิงชั้นนำของประเทศจีน เจ้าของฉายา "สาวงาม 4,000 ปี" และตัวแทนภาพลักษณ์แบรนด์ระดับสากล (${topBrand})\n\n`;
|
|
182
|
-
md += `####
|
|
206
|
+
md += `#### [Works] ผลงานซีรีส์เด่น:\n`;
|
|
183
207
|
(worksRes?.works || []).slice(0, 4).forEach(w => {
|
|
184
208
|
md += `- **${w.titleTh || w.titleCn}** รับบทเป็น *${w.role || w.character}* (ปี ${w.year})\n`;
|
|
185
209
|
});
|
|
@@ -187,7 +211,7 @@ export async function executeDirectCatalogKnowledge(query, _persona = 'default',
|
|
|
187
211
|
}
|
|
188
212
|
}
|
|
189
213
|
|
|
190
|
-
const headerNotice = `>
|
|
214
|
+
const headerNotice = `> [Direct Catalog] **โหมดฐานข้อมูลอัจฉริยะ (Direct Catalog Knowledge Mode)**\n` +
|
|
191
215
|
`> *ระบบสืบค้นข้อมูลจาก Local Database ให้โดยตรงทันทีอย่างแม่นยำ (เปิด LM Studio เพื่อเปิดใช้งาน Generative AI)*\n\n`;
|
|
192
216
|
|
|
193
217
|
const finalMarkdown = headerNotice + answerParts.join('\n\n');
|
|
@@ -12,42 +12,53 @@ export function detectDramaKnowledgeIntent(query) {
|
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function
|
|
15
|
+
export function evaluateDramaCoverageScore(query, answer) {
|
|
16
16
|
const intent = detectDramaKnowledgeIntent(query);
|
|
17
|
-
if (!intent) return { applicable: false, valid: true, issues: [] };
|
|
17
|
+
if (!intent) return { applicable: false, coverageScore: 1.0, qualityScore: 1.0, valid: true, issues: [] };
|
|
18
18
|
|
|
19
19
|
const text = String(answer || '');
|
|
20
20
|
const issues = [];
|
|
21
|
+
let factHits = 0;
|
|
22
|
+
let expectedFacts = 3;
|
|
23
|
+
|
|
21
24
|
const unsupported = /(?:ระดับแนวหน้า|ไม่มีใครเทียบได้|ก้าวข้ามจากไอดอล(?:ได้)?อย่างสมบูรณ์|ได้รับรางวัลมากมาย)/i;
|
|
22
25
|
if (unsupported.test(text)) issues.push('unsupported-career-claim');
|
|
23
26
|
if (/★\s*\d+(?:\.\d+)?\s*\/\s*10/.test(text)) issues.push('unattributed-rating');
|
|
24
27
|
|
|
25
28
|
if (intent === 'white-snake-story') {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
}
|
|
29
|
+
expectedFacts = 3;
|
|
30
|
+
const mentionsBai = /(?:ไป๋ซู่เจิน|bai\s+suzhen).{0,100}(?:งูขาว|white[- ]snake spirit)/is.test(text);
|
|
31
|
+
const mentionsXu = /(?:สวี่เซียน|xu\s+xian).{0,80}(?:มนุษย์ชาย|human man|human scholar|mortal)/is.test(text);
|
|
32
|
+
const reversed = /(?:ตัวละครเอก|นางเอก|protagonist).{0,80}(?:มนุษย์สาว|human woman).{0,200}(?:พญางูขาว|white snake)/is.test(text);
|
|
33
|
+
|
|
34
|
+
if (mentionsBai) factHits++; else issues.push('missing-bai-suzhen-identity');
|
|
35
|
+
if (mentionsXu) factHits++; else issues.push('missing-xu-xian-identity');
|
|
36
|
+
if (!reversed) factHits++; else issues.push('reversed-species-or-gender');
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
if (intent === 'acting-era-comparison') {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
expectedFacts = 4;
|
|
41
|
+
const has2024 = /In\s+Blossom/i.test(text) && /Sword\s+and\s+Fairy\s+4/i.test(text);
|
|
42
|
+
const hasPast = /(?:2016|2017|2018|2019)/.test(text);
|
|
43
|
+
const hasRoleNuance = /(?:ตัวตน|identity).{0,100}(?:หยางไฉ่เวย|yang\s+caiwei).{0,160}(?:รูปลักษณ์|ร่าง|appearance).{0,100}(?:ซ่างกวนจื่อ|shangguan\s+zhi)/is.test(text);
|
|
44
|
+
const hasFalseDual = /(?:สลับเล่น\s*2|เล่น\s*2\s*(?:บทบาท|คาแรคเตอร์)|dual-role performance)/i.test(text);
|
|
45
|
+
|
|
46
|
+
if (has2024) factHits++; else issues.push('incomplete-2024-comparison');
|
|
47
|
+
if (hasPast) factHits++; else issues.push('missing-past-work-evidence');
|
|
48
|
+
if (hasRoleNuance) factHits++; else issues.push('imprecise-in-blossom-role');
|
|
49
|
+
if (!hasFalseDual) factHits++; else issues.push('false-dual-role-framing');
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
const coverageScore = Number((factHits / expectedFacts).toFixed(2));
|
|
53
|
+
const penalty = issues.length * 0.25;
|
|
54
|
+
const qualityScore = Number(Math.max(0, 1.0 - penalty).toFixed(2));
|
|
55
|
+
const valid = issues.length === 0;
|
|
56
|
+
|
|
57
|
+
return { applicable: true, coverageScore, qualityScore, valid, issues };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function assessDramaAnswerQuality(query, answer) {
|
|
61
|
+
return evaluateDramaCoverageScore(query, answer);
|
|
51
62
|
}
|
|
52
63
|
|
|
53
64
|
function bulletList(items = []) {
|