a39e06ff07
Deliver P5.2 writing day logs, cockpit heatmap, streak tracking, and chapter knowledge auto-extraction with merge review. Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.6 KiB
TypeScript
46 lines
1.6 KiB
TypeScript
import type { ExtractedKnowledgeItem } from '../../shared/types'
|
||
|
||
export function buildExtractionPrompt(
|
||
chapterTitle: string,
|
||
plainText: string,
|
||
approvedTitles: Array<{ id: string; title: string }>
|
||
): string {
|
||
const catalog =
|
||
approvedTitles.length > 0
|
||
? approvedTitles.map((e) => `- ${e.id}: ${e.title}`).join('\n')
|
||
: '(无)'
|
||
return `你是小说知识库助手。请从以下章节正文中抽取知识条目,输出 JSON 数组。
|
||
|
||
章节标题:${chapterTitle}
|
||
|
||
已有 approved 知识(id: 标题):
|
||
${catalog}
|
||
|
||
若某条抽取内容是对已有知识的更新,请设置 suggestedMergeId 为对应 id,并在 proposedPatch 中给出建议更新的字段。
|
||
|
||
每条必须包含:type(character|foreshadow|relationship|location|fact)、title、content、importance(1-5)、confidence(0-1)、foreshadowStatus(仅 foreshadow 类型:buried|partial|resolved)。
|
||
|
||
正文:
|
||
${plainText}
|
||
|
||
仅返回 JSON 数组,不要 markdown。`
|
||
}
|
||
|
||
export function parseExtractionJson(raw: string): ExtractedKnowledgeItem[] {
|
||
const cleaned = raw.replace(/```json\n?|\n?```/g, '').trim()
|
||
const arr = JSON.parse(cleaned) as ExtractedKnowledgeItem[]
|
||
if (!Array.isArray(arr)) throw new Error('expected array')
|
||
return arr
|
||
.map((item) => ({
|
||
type: item.type,
|
||
title: String(item.title).trim(),
|
||
content: String(item.content ?? '').trim(),
|
||
importance: item.importance ?? 3,
|
||
confidence: Number(item.confidence) || 0.5,
|
||
foreshadowStatus: item.foreshadowStatus,
|
||
suggestedMergeId: item.suggestedMergeId ?? undefined,
|
||
proposedPatch: item.proposedPatch
|
||
}))
|
||
.filter((x) => x.title.length > 0)
|
||
}
|