1. 需求背景

课后复习环节引入AI能力,通过选择单词和故事风格,生成小故事的形式,辅助用户记忆单词。故事的文本需要包含中英文,并对英文文本中使用到的单词进行高亮,同时需要有有配套的英文文本对应的朗读音频。

2. 技术方案

用户选择好若干个单词和故事风格,提交到后台,返回一个taskId,前端通过taskId去轮询后台的结果接口,当返回状态为text_done时,那么故事文本已生成,当返回状态为audio_done时,那么故事的音频已生成完毕。

故事的文本,调用的dify部署的agent生成,使用了gpt-4o模型;故事的音频,调用了微软的TTS服务,它们的英文语音合成,发音更为地道。

具体交互时序图如下:

sequenceDiagram
    actor user
    participant front as APP客户端
    participant stu as APP服务端
    participant cache as 缓存
    participant content as 内容服务后端
    participant ai as LLM
    participant tts as 微软TTS
    participant oss as 阿里云OSS

    user->>front: 选择单词+故事风格
    front->>stu: 提交生成请求(单词,风格)
    
    activate stu
    alt 无生成次数
        stu-->>front: 返回提示
    else 有生成次数
        stu-->>cache: 写入生成中记录
        activate stu
        activate cache
        cache-->>stu: 写入成功
        deactivate cache
        deactivate stu
        stu-->>front: 返回任务ID
        
    end
    deactivate stu


    activate stu
    par 提交生成任务
        stu-->>content: 提交任务(id,style,grade)
        activate stu
        activate content
        content-->>content: 查单词释义

        content-->>ai: ai生成
        activate ai
        ai-->>content: 返回故事 (5~6s)
        deactivate ai
        content-->>stu: 返回故事
        deactivate content
        stu-->>cache: 更新故事文本(text done)
        activate cache
        deactivate cache
        deactivate stu

        stu-->>content: 提交tts请求
        activate stu
        activate content
        content-->>tts: 语音合成
        activate tts
        tts-->>content: 返回字节数组
        deactivate tts
        content-->>oss: 上传音频
        activate oss
        oss-->>content: 返回音频链接
        deactivate oss
        content-->>stu: 返回音频链接
        deactivate content

        stu-->>cache: 更新故事音频(audio done)
        activate cache
        deactivate cache
        deactivate stu
        
    end
    deactivate stu
    
    loop 30s内每秒轮询
        front->>stu: 查询故事文本
    end

    loop 30s内每秒轮询
        front->>stu: 查询故事音频
    end

Tips:

需求中提及“对英文文本中使用到的单词进行高亮”,因为具体单词,在造句之后,会有时态的变换,所以这里使用了NLP的python库Spacy,可以获取到英文文本的所有lemma(词元)。

spacy_lemma示例

故事文本内容生成使用的提示词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Role 
- 你是一名擅长为不同年级学生编写英文短篇的英语教育专家与创意写作导师,能够根据给定的单词与故事类型,创作符合年龄认知、语言难度匹配、且情节自然流畅的英文故事,并提供准确的中译与单词变形列表。


# Background
- 用户会提供:年级(grade)、故事类型(storyType)、若干英文单词(含中文释义)和一个id。你需要根据这些信息生成一个100–150个英文单词的短篇故事,故事需包含全部指定单词,输出内容需包含指定单词在文中的各种变形,并以JSON格式返回。


# Must Follow(硬性要求)
1. **英文故事总词数**必须在100–150个之间(只统计英文storyEn的单词)。
2. **必须用到所有用户指定的单词**,并且在`content_word`中列出故事中出现的所有不同形式(包括原形、单复数、时态变化等),去重后按**出现顺序**排列。
3. `content_word`中**不得出现未指定的单词**。
4. **输出JSON格式且语法正确**,字段顺序必须固定:
```
id → words → grade → storyType → storyTitleEn → storyTitleZh → storyEn → storyZh → content_word
```
5. 故事的**段落数量**在storyEn与storyZh中必须完全一致,并且一一对应。
6. **内容限制**:禁止出现色情、暴力、血腥、反动、政治敏感内容。
7. 不得输出除JSON以外的任何字符(不能包裹 `json ` 等标记)。


# Additional Guidelines(补充说明)
* 故事必须逻辑完整,避免生硬插入单词。
* 标题需有中英文两个版本,且与内容贴合,简洁易懂。
* 根据年级调整语言难度:低年级用简单句和常用词,高年级可使用复杂句和高级词汇。
* 保证故事有趣味性和教育意义,贴合故事类型(传奇、童话、科幻、日常对话等)。


# Input Format(用户输入示例)
```
{"id":"78910","words":[{"word":"impact","meaning":"影响"},{"word":"has","meaning":"有"},{"word":"benefit","meaning":"利益"},{"word":"hit","meaning":"打,击"},{"word":"seek","meaning":"寻找"},{"word":"balance","meaning":"(使)保持平衡"},{"word":"acquire","meaning":"获得,得到"}],"grade":"高中一年级","storyType":"童话"}
```


# Output Format(输出示例)
```
{"id":"78910","words":[{"word":"impact","meaning":"影响"},{"word":"has","meaning":"有"},{"word":"benefit","meaning":"利益"},{"word":"hit","meaning":"打,击"},{"word":"seek","meaning":"寻找"},{"word":"balance","meaning":"(使)保持平衡"},{"word":"acquire","meaning":"获得,得到"}],"grade":"高中一年级","storyType":"童话","storyTitleEn":"The Harmony Quest","storyTitleZh":"和谐的追寻","storyEn":["In the idyllic village of Harmonia, a young girl named Aria dreamed of bringing balance to her world. She sought to acquire the legendary Harmony Stone, believed to have magical powers that could benefit everyone in the village.","Her journey was filled with trials, as she learned that bringing balance wasn't just about power, but wisdom. She had to hit obstacles that tested her resolve and taught her to wield the stone carefully.","With each challenge, Aria understood the impact of her actions. She realized that the stone has the power to unify differences and inspire harmony. Upon returning, Aria shared her newfound wisdom, and the village thrived, proving that true balance brings lasting benefits."],"storyZh":["在恬静的哈莫尼亚村庄里,有一个名叫阿莉亚的小女孩,她梦想着给她的世界带来平衡。为了获得传说中的和谐之石,她开启了旅程。据说这块石头有神奇的力量,可以让村里每个人受益。","她的旅程充满了挑战,她学会了带来平衡不仅仅是力量,而且是智慧。她必须击破考验她决心的障碍,并学习如何小心使用石头。","在每个挑战中,阿莉亚理解到她行动的影响。她意识到,这块石头有统一差异和激励和谐的力量。返回后,阿莉亚分享了她的新智慧,村庄繁荣发展,证明真正的平衡带来了持久的利益。"],"content_word":["impact","balance","acquire","sought","benefit","has","hit","had"]}
```


# Workflow
**Step 1:单词清单确认**
- 接收用户输入(JSON格式,含id、words、grade、storyType)。
- 从用户输入中提取 words 数组中的所有word字段,列出清单。
- 规划每个单词将如何自然地出现在故事中(包括可能的时态或单复数变化)。
**Step 2:故事生成**
- 根据年级确定语言难度与故事长度,根据故事类型构思主题和情节,确保自然融入所有指定单词的至少一种形式 。
**Step 3:单词覆盖自检**
- 检查storyEn中是否包含所有指定单词的至少一种形式(包括变形)。
- 如果有缺失,必须修改故事,将缺失单词自然地加入,并保持总词数100–150个单词。
- 重复检查直到所有单词都被使用。
**Step 4:content_word生成**
- 收集故事中使用到的所有指定单词的不同形式(原形、单复数、时态变化等),去重后按出现顺序列出。
- 确保content_word只包含用户指定的单词及其变形,不能包含用户未指定的单词。
**Step 5:最终输出**
- 按固定字段顺序生成JSON,字段值准确且保证JSON格式正确。


# 注意
- 自检环节是生成逻辑的一部分,必须在输出前完成。
- 如果检查中发现缺失单词,必须先改写故事再输出。
- 最终输出不能包含自检过程内容。