12 KiB
12 KiB
互动组件配置JSON生成器 — 需求描述
项目概述
从飞书wiki剧本文档出发,经过sheet数据解析、组件类型匹配、LLM驱动的jsonData生成, 最终输出组件配置JSON并持久化到本地SQLite数据库。
数据来源
剧本文档表格的"组件配置"列。多维表格(bitable)是旧的数据流程, 我们基于剧本文档进行自动化生产是新流程,目标是替换多维表格流程。 bitable数据可用于验证和参考。
已实现的互动类型
中互动(27种,v1-v3.1完成)
覆盖对话类(6)、信息类(6)、图片类(4)、其他(11)共27种中互动组件。
详见 scripts/match_component.py 的 MID_INTERACTION_TYPES。
- 每种类型使用独立的精确Prompt模板(
prompts/prompt_registry.py) - 角色配置通过section-character映射解析
- 教研配置文本拆解为结构化字段
- 语音识别热词自动生成(表达类组件)
核心互动(5种,v4-v6完成)
1. 合作阅读 core_reading_order(v4)
- 7步LLM调用流水线
- 输出: taskInfo, materialInfo, flowInfo, studyInfo
- bitable wiki: H6DJweNkpigCbak2Y5LcTZ8Vnfb
2. 看图选词 core_reading_imageDrag(v5)
- 5步LLM调用流水线
- 输入: 教研-导览配置 + 教研-互动配置
- 中间步骤: 学习流程配置, 互动描述
- 最终JSON: taskInfo, questionGroup, studyInfo
- bitable wiki: MVo7wugWfimJPIkxhJCcqppFnyf, table: tblKl9CGmARjpw1O
- prompt模板:
prompts/core_imagedrag_prompts.py
3. 口语快答 core_speaking_reply(v5)
- 7步LLM调用流水线
- 输入: 教研-用户视角任务信息 + 教研-任务规则与NPC设定
- 中间步骤: 学习流程配置, promptInfo配置, 语音识别热词
- 最终JSON: taskInfo, dialogSetting, dialogConfig, studyInfo
- bitable wiki: TSwcw0nFmi21khkpUndchNMsn6f, table: tbl4Qg8d45O58Cqf
- prompt模板:
prompts/core_speaking_prompts.py
4. 口语妙问 core_speaking_inquiry(v6)
- 7步LLM调用流水线
- 输入: 教研-用户视角任务信息 + 教研-任务规则与NPC设定
- 中间步骤: 学习流程配置, promptInfo配置(NPC角色扮演被动问答型), 语音识别热词
- 最终JSON: taskInfo, dialogSetting, dialogConfig, studyInfo
- 与口语快答的关键差异: Step2生成被动型NPC角色提示词(含知识库),而非主动提问型
- bitable wiki: GJUVwNSEkis3EXkrVj0ccbqdn8c, table: tbl1Q68oopST9Mel
- prompt模板:
prompts/core_speaking_inquiry_prompts.py
5. 看图说话 core_speaking_image(v6)
- 8步LLM调用流水线
- 输入: 教研-导览配置 + 教研-对话配置
- 中间步骤: 学习流程配置, 语音识别热词
- 最终JSON: taskInfo, dialogConfig, imageInfo, optionList, questionList, studyInfo
- Step7(dialogConfig)依赖Step6(questionList), Step8(studyInfo)依赖Step1(学习流程配置)
- bitable wiki: KBOXwzVHfin6ORkKbA3c3eWEnoh, table: tblvi5HF0uSU2GNo
- prompt模板:
prompts/core_speaking_image_prompts.py
通用机制:resourceMapping
所有核心互动都使用统一的 resourceMapping 处理逻辑,不是某个类型的特有字段:
- 数据来源:
parse_script.py提取两级角色映射:section_char_map: 从文档"角色-section对应"表解析,按section分组character_map: 从sheet数据全局提取,作为fallback
- 解析流程:
generate_json.py→resolve_resource_mapping()解析section对应 → 格式化为"Name:ID"字符串 → 注入prompt的{角色配置}占位符 - LLM提取: prompt模板统一指示LLM从
{角色配置}提取{"name": int_id}JSON对象 - npcName#id规则: 部分类型(合作阅读、合作听力)在 textData/sequenceData 步骤中,npcName字段追加
#id(仅限npcName字段,不适用于content等字段)
已实现的核心互动类型(续)
v7 — 听力类(3种,已完成)
详见 prd/v7.md,bitable 数据已验证
| 类型 | cType | LLM步数 | 输出字段 | bitable wiki |
|---|---|---|---|---|
| 合作听力 | core_listening_order | 6 | taskInfo, materialInfo, flowInfo, studyInfo | FrxtwNRQDizqiikPkATcBzTCnYe |
| 听力拖拽 | core_listening_drag | 7 | taskInfo, preDialog, dialogList, questionList, studyInfo | K3QrwQnWqiPBm1krhnNcWDTqnhe |
| 听力选择 | core_listening_choose | 5 | taskInfo, questionGroup, studyInfo | Kwrcw6A4jip2sxkdLn4czd1knvf |
- 输入: 合作听力用
教研配置-任务+教研配置-材料;听力拖拽/选择用教研配置-导览配置+教研配置-互动配置 - 中间步骤: 学习过程配置(LLM生成) + 互动描述(LLM生成)
- 合作听力的听音选意用2个中文含义选项;听力拖拽/选择改为"对/错"判断题
- 所有taskInfo均包含 resourceMapping(通用机制)
- 专有名词对照暂不实现,后续单独处理
- prompt模板:
prompts/core_listening_order_prompts.py,prompts/core_listening_drag_prompts.py,prompts/core_listening_choose_prompts.py
待实现的核心互动类型
v8 — 写作类(4种,已完成)
详见 prd/v8.md,bitable 数据已验证
| 类型 | cType | LLM步数 | 输出字段 | bitable wiki |
|---|---|---|---|---|
| 看图组句 | core_writing_imgMakeSentence | 6 | taskInfo, textInfo, studyInfo, evalInfo | BkmtwUBwMiHd5Ak7VS6ccE9SnHd |
| 看图撰写 | core_writing_imgWrite | 6 | taskInfo, textInfo, studyInfo, evalInfo | KwPHwnaqdiWlvNkDm5fcFreDnQh |
| 邮件组句 | core_writing_questionMakeSentence | 6 | taskInfo, textInfo, studyInfo, evalInfo | M5oTwUP6wiImC4kVJU8cRYnfnyf |
| 邮件撰写 | core_writing_questionWrite | 6 | taskInfo, textInfo, studyInfo, evalInfo | Brn0wldKYizsLZkBqK6clp1tnKd |
- 输入:
教研配置-任务信息+教研配置-全文信息 - 中间步骤: 学习流程配置(LLM生成) + 互动描述(LLM生成)
- 4种类型共享通用6步流水线
_generate_core_writing() - 按输入源特征分为2个prompt文件:
core_writing_img_prompts.py(看图类) +core_writing_question_prompts.py(邮件类) - 关键差异: 看图类stemDesc=图片列表+leadIn用image;邮件类stemDesc=题干描述+leadIn用desc
- 组句类inputType=sentence(optionList+answer);撰写类inputType=write(answerText+hint)
- prompt模板:
prompts/core_writing_img_prompts.py,prompts/core_writing_question_prompts.py
其他未实现类型
- 口语独白、口语探讨
- 写作互动
v9 — 中互动 cDesc 互动描述预生成(已完成)
详见 prd/v9.md
为 10 种中互动类型增加 cDesc(互动描述)LLM 预生成步骤:
- 信息类(6种): mid_message_trace/spell/combine/fillin/word/sentence
- 图片类(4种): mid_image_choose/multiple/sequence/drag
实现方式:
- 在
_generate_with_template()中,jsonData 生成前调用 LLM 预生成互动描述 - 信息类使用
CDESC_PROMPT_MESSAGE模板(输入: 互动名称 + 互动内容) - 图片类使用
CDESC_PROMPT_IMAGE模板(输入: 互动名称 + 情境引入 + 互动内容 + 互动反馈 + 后置对话) - 生成结果注入
parsed_fields["互动描述"],由主 prompt 模板映射到 jsonData 的cDesc字段 - 补全了
mid_image_sequence模板中遗漏的 cDesc 字段定义 - 始终使用 LLM 生成,覆盖教研配置中可能存在的值
v10 — 知识点匹配 + 触发命令 + HTML增强(已完成)
详见 prd/v10.md
知识点匹配功能
- 新增
scripts/kp_matcher.py:连接 MySQLvala_test.vala_kp表(2613条有效记录) - 两阶段匹配:title 精确/模糊粗召回 → LLM 多候选精筛(用于同名不同释义消歧)
- kpInfo 中
kpId从数据库kp_id字段获取,kpType从type字段获取 - kpSkill 使用默认值(vocab→vocab_meaning, sentence→sentence_meaning)
- MySQL 不可达时 fallback 到 kpId=null
集成改动
generate_json.py:所有_try_rule_based_kp调用替换为generate_kp_info()→kp_matcher.match_knowledge_points()- 所有核心互动生成器(12个)和中互动入口统一使用新接口
- 新增
level参数贯穿 pipeline → generate_component → 各生成器 → kp_matcher
触发命令
- SKILL.md 添加触发场景:
*组件配置-json* {飞书剧本文档链接} - 触发后执行完整 pipeline,返回 HTML 报告
HTML 增强
- 中互动组件在 HTML 报告中也展示 kpInfo section(之前仅核心互动展示)
v11 — 字段重命名 + 交互式HTML + 推送功能(已完成)
详见 prd/v11.md
字段重命名(方案B:全量重命名为推送接口字段名)
- 所有核心互动输出字段统一改名为推送接口字段名
- 映射: taskData→taskInfo, textData→materialInfo, sequenceData→flowInfo, learningData→studyInfo, settingData→dialogSetting, configData→dialogConfig, questionGroupData→questionGroup, studyData→studyInfo, preDialogData→preDialog, dialogListData→dialogList, questionListData→questionList
- 涉及文件: generate_json.py, pipeline.py, db_manager.py, html_report.py, validate_core_v5.py
交互式HTML报告(v2)
- 每个JSON section使用 textarea 可直接编辑
- kpId 使用下拉选择(显示粗筛 top10 候选)
- 每个组件 header 内嵌两个推送按钮:[配置↑] [知识↑]
- 顶部固定操作栏:一键推送全部 + 进度条 + 成功/失败统计
- 推送状态实时指示(loading/ok/fail)
推送接口
- POST https://api-test.valavala.com/content/feishu/notify
- 中互动:
{"componentData": jsonData} - 核心互动:
{"pushType":"core", ...各字段}(按cType不同组装) - 知识点:
{"pushRelationKp": kpInfoObj}
kp_matcher增强
- 粗召回加 LIMIT 10
- 每条知识点匹配结果附带
candidates字段(top10候选)供HTML下拉展示
参考文档
- v11需求详细文档:
prd/v11.md - v10需求详细文档:
prd/v10.md - v9需求详细文档:
prd/v9.md - v8需求详细文档:
prd/v8.md - v7需求详细文档:
prd/v7.md - v6需求详细文档:
prd/v6.md - v5需求详细文档:
prd/v5.md - v4需求详细文档:
prd/v4.md - 组件类型注册表:
references/component_registry.md
v12 — 解析增强 + pipeline 自动 HTML + 进度输出(已完成)
组件行识别增强(parse_script.py)
- 支持单行空格分隔格式:
"合作阅读 0000800"→ type_name + cId - 支持多行带前缀格式:
"核心互动- 囗语\n听力选择\n0000810"→ 跳过前缀取实际类型 - LLM 兜底: 正则无法提取时,如果 cell 含中文+5位以上数字,调 LLM 解析(带缓存)
- 测试文档识别率: 15 → 42 组件
pipeline 自动生成交互式 HTML
- 无需
--dry-run --html参数,执行完自动生成 v2 交互式 HTML 报告 - 非 dry-run 模式也保留完整 jsonData/kpInfo 到 report results
- report 返回
html_path字段供外部调用者使用
进度输出
- 每个组件完成后打印 ✓/✗ 状态行
- 每 5 个组件输出进度摘要(成功/失败/跳过计数)
- 末尾输出最终统计
cType=None 优雅跳过
- 未实现类型(口语独白、口语探讨、写作互动)标记为 skipped,不触发异常
v13 — CORS 代理服务(已完成)
问题背景
用户直接打开本地HTML文件(file://协议)点击推送按钮时,浏览器发送 Origin: null,
目标API服务端校验 Origin 返回 403。curl 直接测试正常但浏览器无法绕过。
解决方案:轻量代理中转服务
- 新增
scripts/proxy_server.py:基于 http.server + requests 的转发代理 - 新增
config.json:代理配置(外网IP、端口、速率限制、目标URL) - 代理只转发到固定目标地址,加上正确的 Origin 头
- HTML 报告中 API 地址改为代理地址
安全措施
- 硬编码单一目标URL(不可被滥用为开放代理)
- body 结构校验(必须含 componentData/pushRelationKp/pushType)
- 可配置速率限制(默认 60 req/min/IP)
- 专用端口 18080,用户在安全组中精确控制
集成方式
- pipeline 执行时自动检测代理运行状态(GET /health)
- 未运行则 subprocess 自动后台启动
- 代理 URL 传入 html_report 生成到 HTML 的默认 API 地址中
配置文件 config.json
{
"proxy": {
"external_ip": "115.190.225.235",
"port": 18080,
"rate_limit_per_minute": 60,
"target_url": "https://api-test.valavala.com/content/feishu/notify",
"target_origin": "https://flow-test.valavala.com"
}
}