ai_member_xiaoyan/skills/interactive-component-json/project.md

248 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 互动组件配置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_orderv4
- 7步LLM调用流水线
- 输出: taskInfo, materialInfo, flowInfo, studyInfo
- bitable wiki: H6DJweNkpigCbak2Y5LcTZ8Vnfb
#### 2. 看图选词 core_reading_imageDragv5
- 5步LLM调用流水线
- 输入: 教研-导览配置 + 教研-互动配置
- 中间步骤: 学习流程配置, 互动描述
- 最终JSON: taskInfo, questionGroup, studyInfo
- bitable wiki: MVo7wugWfimJPIkxhJCcqppFnyf, table: tblKl9CGmARjpw1O
- prompt模板: `prompts/core_imagedrag_prompts.py`
#### 3. 口语快答 core_speaking_replyv5
- 7步LLM调用流水线
- 输入: 教研-用户视角任务信息 + 教研-任务规则与NPC设定
- 中间步骤: 学习流程配置, promptInfo配置, 语音识别热词
- 最终JSON: taskInfo, dialogSetting, dialogConfig, studyInfo
- bitable wiki: TSwcw0nFmi21khkpUndchNMsn6f, table: tbl4Qg8d45O58Cqf
- prompt模板: `prompts/core_speaking_prompts.py`
#### 4. 口语妙问 core_speaking_inquiryv6
- 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_imagev6
- 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 处理逻辑**,不是某个类型的特有字段:
1. **数据来源**: `parse_script.py` 提取两级角色映射:
- `section_char_map`: 从文档"角色-section对应"表解析按section分组
- `character_map`: 从sheet数据全局提取作为fallback
2. **解析流程**: `generate_json.py``resolve_resource_mapping()` 解析section对应 → 格式化为 `"NameID"` 字符串 → 注入prompt的 `{角色配置}` 占位符
3. **LLM提取**: prompt模板统一指示LLM从 `{角色配置}` 提取 `{"name": int_id}` JSON对象
4. **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`:连接 MySQL `vala_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
```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"
}
}
```