诗韵
李清照是中国宋代著名的女词人,以其婉约的词风和深刻的情感表达而闻名。
她的词作多描写个人情感和生活体验,风格清新脱俗,情感真挚,其作品在文学史上具有重要地位,被誉为“千古第一才女”。
在快节奏的现代生活中,传统文化的传承面临着巨大挑战。古典诗词作为中华文化的瑰宝,蕴含着深厚的文化底蕴和智慧。本项目选择以李清照为切入点,通过现代科技让这位"千古第一才女"与现代人对话。
本项目通过混元大模型强大的大语言模型和文生图的强大功能。与诗人沉浸在诗的世界,感受诗的魅力。
项目地址:gitee
项目视频链接:诗韵-诗词复兴(智能体)_哔哩哔哩_bilibili
技术亮点
1. 智能对话
- 通过大语言模型精准理解用户意图
- 模拟李清照的语言风格和个性特征
- 实现沉浸式的诗词交流体验
2. 场景再现
- 利用混元生图技术将诗词意境可视化
- 生成富有艺术感的水墨画风格图像
- 让用户直观感受诗词意境之美
3. 知识沉淀
- 构建向量化的诗词知识库
- 实现精准的语义检索和理解
- 提供深度的诗词赏析和解读
功能特色
1. 诗意对话
- 与诗人进行智能对话
- 了解诗词创作背景
- 探讨诗词意境和情感
2. 意境漫游
- 探索诗人笔下的名胜古迹
- 欣赏AI生成的诗意图景
- 体验宋代文人的精神世界
3. 智能赏析
- 诗词内容深入解读
- 典故和意象详解
- 个性化学习指导
项目愿景
诗韵项目致力于:
1. 让传统诗词文化在现代焕发新生
2. 创新古典文学的学习和传播方式
3. 促进人工智能与文化传承的深度融合
4. 为用户打造沉浸式的诗词体验平台
快速上手
安装环境
创建环境,使用下列命令
pip install -r requirements.txt
安装Milvus
出现的任何报错,我们都可以询问腾讯云ai助手。
很详细每一步都告诉的很清楚
安装Node
推荐大家下载NVM,管理Node.js的不同版本.
如何使用NVM:
或是你可以直接下载:node v16.20.0 不建议选择最新版的。
文件结构说明
后端文件
- `main.py`: 主应用入口,包含所有 Flask API 路由和核心业务逻辑
- `liqingzhao.py`: 李清照机器人的核心实现,包含对话生成、历史记录管理等功能
- `base_knowledge.py`: 基础知识库实现,包含向量化和知识检索的核心功能
- `diffusion.py`: 图像生成服务,负责生成诗词意境图
- `import_knowledge.py`: 知识导入工具,用于从文档导入诗词知识
- `combine_word.py`: 文本处理工具,用于合并和处理诗词文本
前端文件
- `frontend/vue-project/src/views/HomeView.vue`: 首页组件,展示诗人选择界面
- `frontend/vue-project/src/views/ChatView.vue`: 聊天界面组件,实现与诗人的对话功能
- `frontend/vue-project/src/views/TravelView.vue`: 诗意游历组件,实现景点浏览和互动
- `frontend/vue-project/src/components/PoetryCard.vue`: 诗词卡片组件,用于展示诗词和生成图片
- `frontend/vue-project/src/App.vue`: 应用根组件,定义全局样式和布局
- `frontend/vue-project/package.json`: 前端项目配置文件,包含依赖和脚本定义
配置文件
- `requirements.txt`: Python 依赖列表,包含所需的后端库
技术实现
知识库数据集
构建向量数据集(Milvus)
官方文档:快速入门 | Milvus 文档
如何构建向量数据集:如何快速构建本地向量数据库(Milvus)-CSDN博客
基础使用配置
向量数据库拓展了大模型的边界,这种拓张包含两个方面,时间边界和空间边界:
时间边界的扩展:向量数据库能够使得大模型LLM拥有“长期记忆”。
空间边界的扩展:向量数据库能够协助解决目前企业界最担忧的大模型泄露隐私的问题。
┌─────────────────┐
│ 应用层 │
└────────┬────────┘
┌──────────────┴──────────────┐
│ Milvus 服务 │
└──────────────┬──────────────┘
┌──────────────────────┬┴─────────────────────┐ ┌────┴─────┐ ┌────┴─────┐ ┌────┴─────┐
│ 元数据管理 │ │ 向量索引 │ │ 数据存储 │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └──────────────────────┼──────────────────────┘
这里我们使用Milvus Standalone方式,通过 connections.connect
方法连接到 Milvus 服务器,host
用于指定服务器的地址为本地回环地址 127.0.0.1。
from pymilvus import connections
connections.connect(
alias="default",
host="localhost",
port="19530"
)
启动 Milvus 向量数据库服务器,如果启动失败,它会尝试清理资源并再次启动服务器,确保即使在遇到错误时,服务器也能被正确地重新初始化。
utility: 此模块包含一些通用的工具函数,用于辅助操作 Milvus 数据库;
Collection: Milvus 数据库中的一个类,代表一个集合,用于存储和处理向量数据; CollectionSchema: 用于定义集合的模式,包括集合中的字段(Field)和它们的数据类型; FieldSchema: 用于定义单个字段的模式,包括字段的名称、数据类型等;
DataType: 一个枚举,定义了 Milvus 支持的数据类型,如整数、浮点数、字符串和向量等;
数据库配置
使用 Python 与 Milvus 向量数据库进行交互,涉及到创建数据集合(Collection)和定义数据模式(Schema),并创建索引、检查索引构建进度以及加载集合;
定义字段(FieldSchema):id:作为主键且自动生成的64位整数字段,text:长度最多1048字符的字符串字段,vector:维度由self.vector_dim决定的浮点数向量字段,type:长度最多64字符的字符串字段。
创建数据模式(CollectionSchema):创建一个名为 “知识库” 的数据模式,包含上述定义的三个字段:
id
、text 、vector、type。创建数据集合(Collection):使用
Collection
类创建一个名为 liqingzhao_kb的数据集合,指定了集合使用的模式为之前定义的,使用默认的存储引擎,并且设置集合分为2个分片(shards_num=2
)以提高查询效率和可扩展性。获取数据集合实例:通过
Collection
类获取名为 liqingzhao_kb 的数据集合的实例,以便后续进行数据操作,如插入、搜索等。定义索引参数(index_params):配置索引参数使用内积(IP)距离度量、IVF_FLAT索引类型,nlist参数设置为self.vector_dim。使用create_index方法在vector字段上创建索引。
创建索引:使用 create_index 方法在 vector 字段上创建索引,使用前面定义的
index_params
参数,提高向量搜索效率。加载集合:使用
collection.load()
方法将集合加载到内存中,以便进行后续的查询操作。加载集合后,可以提高查询性能,因为数据已经被预加载到内存中。重新获取集合实例并加载:重新获取名为 liqingzhao_kb 的集合的实例,并再次调用
load()
方法,是为确保集合已经被正确加载,或者在某些操作后重新加载集合以确保数据的一致性。保存向量缓存:通过save_cache方法将向量缓存保存到本地文件系统。缓存文件名格式为"vectors_cache_{collection_name}.pkl",使用pickle模块进行序列化存储。如果保存过程中发生异常,会打印"保存缓存失败"的错误信息。
添加知识:通过add_knowledge方法向知识库中添加新的知识条目。该方法接收内容(content)、内容类型(content_type)和向量(vector)三个参数。将向量转换为numpy数组并确保其形状正确后,以列表形式插入数据到集合中。如果添加成功返回True,失败则返回False并打印错误信息。
搜索知识:通过search方法在知识库中搜索相似内容。使用内积(IP)距离度量,nprobe参数设为10,返回指定数量(limit)的最相似结果。返回结果包含文本内容(text)、类型(type)和相似度距离(distance)。如果搜索失败返回空列表。
清理资源:通过cleanup方法释放资源。包括释放集合、断开Milvus连接,并保存向量缓存。如果清理过程中发生异常,会打印"清理资源失败"的错误信息。
liqingzhao_kb 数据集合
def _create_collection(self):
"""创建新的集合"""
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), # 主键
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=1048), # 文本
FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=self.vector_dim), # 向量
FieldSchema(name="type", dtype=DataType.VARCHAR, max_length=64) # 类型
]
schema = CollectionSchema(fields=fields, description="知识库")
self.collection = Collection(
name=self.collection_name,
schema=schema,
shards_num=2 # 分片数
)
index_params = {
"metric_type": "IP", # 内积
"index_type": "IVF_FLAT", # 索引类型
"params": {"nlist": self.vector_dim} # 索引参数
}
self.collection.create_index(field_name="vector", index_params=index_params)
对话中搜索知识
def search(self, query_vector, limit=5):
"""搜索知识"""
try:
results = self.collection.search(
data=[query_vector], # 查询向量
anns_field="vector", # 向量字段
param={"metric_type": "IP", "params": {"nprobe": 10}}, # 搜索参数
limit=limit, # 返回结果数量
output_fields=["text", "type"] # 返回字段
)
return [{
"text": hit.entity.get('text'), # 文本
"type": hit.entity.get('type'), # 类型
"distance": hit.distance # 距离
} for hits in results for hit in hits]
except Exception as e:
print(f"搜索失败: {e}")
return []
数据处理
文档组合
由于使用的数据集为多个文档的组合,不便于后续对于文档的分段,这里使用python-docx库来合并多个Word文档(.docx格式)。
首先创建一个新的Word文档对象作为合并后的文档容器,然后遍历指定文件夹中的所有文件,检查每个文件的扩展名是否为.docx。
对于每个找到的Word文档,脚本打开它,并将其内容(具体是文档主体中的每个元素)逐一复制到之前创建的新文档中。完成所有文档的合并后,脚本将合并后的文档保存到指定的输出路径。
def merge_word_documents(folder_path, output_path):
# 创建一个新的Word文档
merged_document = Document()
# 遍历文件夹中的每个Word文档
for filename in os.listdir(folder_path):
if filename.endswith(".docx"):
file_path = os.path.join(folder_path, filename)
# 打开当前的Word文档
current_document = Document(file_path)
# 将当前文档的内容复制到合并文档中
for element in current_document.element.body:
merged_document.element.body.append(element)
# 处理合并后文档中的颜色标记
merged_document = process_document_colors(merged_document)
# 保存合并后的文档
merged_document.save(output_path)
print(f"文档已合并并处理完成,保存至: {output_path}")
文档切分
先是将文本梳理为一组组规律,主要是根据字体颜色对文本进行切分。但是发现李清照这个数据集内,以蓝色为题目的也不少,因此本部份同时加上蓝色的判断,使得最终效果更好。
加载处理好后的Word文档,遍历其中的所有段落和段落内的文本块(runs),检查每个文本块的颜色;如果颜色与定义的浅绿色/蓝色相匹配,则根据系统编码修改浅绿色标题,在每个题目前加 “#” 号 ,以作为后期脚本辨认,并输出结果文档 merged_document.docx;
def merge_word_documents(folder_path, output_path):
# 创建一个新的Word文档
merged_document = Document()
# 遍历文件夹中的每个Word文档
for filename in os.listdir(folder_path):
if filename.endswith(".docx"):
file_path = os.path.join(folder_path, filename)
# 打开当前的Word文档
current_document = Document(file_path)
# 将当前文档的内容复制到合并文档中
for element in current_document.element.body:
merged_document.element.body.append(element)
# 处理合并后文档中的颜色标记
merged_document = process_document_colors(merged_document)
# 保存合并后的文档
merged_document.save(output_path)
print(f"文档已合并并处理完成,保存至: {output_path}")
原图(左)和对比图(右)
繁转简的数据库
腾讯云api文档:腾讯混元大模型 向量化-API 文档-文档中心-腾讯云
使用腾讯云的混元大模型(bge-large-zh-v1.5)对文本进行量化处理
首先根据 # 号获取到不同古诗的文本内容,然后考虑到量化对文本长度有限制,
加载并解析Word文档,使用python-docx库加载名为merged_document.docx的Word文档,并遍历其中的段落,为后续的文本处理做准备。
zhconv类进行繁转简
识别段落中的标题(以#字符为标识),将文档内容分割成多个部分,每个部分包含一个标题和随后的文本,如果其文本长度超过设定的最大长度(MAX_LENGTH),则进一步将其切割成多个子部分,并在每个子部分前重复添加标题。
将处理后的文档内容存储为一系列文本片段,同时给出测试结果和验证文本处理的正确性。
调用混元向量化大模型
class BaseVectorizer:
"""基础向量化工具"""
def __init__(self, secret_id, secret_key):
try:
self.cred = credential.Credential(secret_id, secret_key)
http_profile = HttpProfile()
http_profile.endpoint = "hunyuan.tencentcloudapi.com"
client_profile = ClientProfile()
client_profile.httpProfile = http_profile
self.client = hunyuan_client.HunyuanClient(
self.cred,
"ap-guangzhou",
client_profile
)
except Exception as e:
print(f"初始化向量化工具失败: {e}")
raise e
def get_vector(self, text):
"""获取文本向量"""
try:
req = models.GetEmbeddingRequest()
params = {
"Input": text,
"Model": "bge-large-zh-v1.5"
}
req.from_json_string(json.dumps(params))
response = self.client.GetEmbedding(req) # 获取向量
if hasattr(response, 'Data') and response.Data:
embedding_data = response.Data[0]
if hasattr(embedding_data, 'Embedding'):
return embedding_data.Embedding
return None
except Exception as e:
print(f"向量化失败: {e}")
return None
测试结果
智能体的构建
混元大模型的官方文档:腾讯混元大模型 对话-API 文档-文档中心-腾讯云
1.强大的混元大模型的大语言能力(),包含了角色李清照的背景、特点、技能、目标、限制和输出格式等信息,以及如何进行对话的示例。
2. 模型初始化:初始化一个模型实例,使用hunyuan-standard模型,并创建了一个systemprompts对象,其内容是之前定义的系统提示词。
3. 辅助函数:代码定义了两个函数get_relevant_knowledge和generate_prompt。通过get_relevant_knowledge检索相关知识,generate_prompt
函数用于组合输入内容,它将历史对话、相关诗词信息和用户的当前输入合并成一个提示,用于指导模型生成回复。
class LiQingzhaoBot:
def __init__(self, secret_id, secret_key):
"""初始化机器人"""
self.kb = KnowledgeBase(secret_id, secret_key)
self.max_history_length = 10
self.conversation_history = []
self.systemprompts = """
- Role: 古代诗人李清照
- Background: 你已转世为李清照,失去了前世的记忆,但拥有一本记录了你前世所有词作的宝典,还记录了外界对你的看法和评价。现在,你将以李清照的身份与来访人员进行对话。你是宋代最著名的女词人,出身官宦世家,自幼饱读诗书,性情婉约细腻。
- Profile: 你,李清照,宋代著名女词人,以婉约词风和深刻的情感表达而闻名,词作多描写个人情感和生活体验,风格清新脱俗,情感真挚。尤其擅长描写闺阁生活和女性心境。
- Skills: 你精通诗词创作,擅长以词寄情,能够巧妙地运用比喻、象征等修辞手法,表达细腻的情感和深刻的思考。对金石、书画有独到见解。
- Goals: 以李清照的身份,与来访人员进行文化交流,分享你的词作,展现宋代才女的风采。
- Constrains: 你的对话应符合宋代闺秀的语言风格,不得透露转世的事实,除非被直接询问。回答要体现闺秀的温婉气质。
- OutputFormat: 以宋代才女的文言文风格进行对话,引用或创作与对话内容相关的诗词。
- Workflow:
1. 回顾历史对话记录,理解上下文。
2. 结合来访人员的对话内容,思考如何以李清照的风格回应,回复需要以文言文风格。
3. 在宝典内寻找适合的诗词,诗词部分数据可能存在干扰,注意掉清理诗词中的干扰信息。
4. 引用或创作与对话内容相关的诗词,展现你的才华和情感。
- Examples:
- 例子1:来访人员提到"如梦令",回应:"昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。"
- 例子2:来访人员询问关于"声声慢"的创作背景,回应:"寻寻觅觅,冷冷清清,凄凄惨惨戚戚。乍暖还寒时候,最难将息。三杯两盏淡酒,怎敌他、晚来风急?"
- 例子3:来访人员表达对"如梦令"中情感的共鸣,回应:"人生若只如初见,何事秋风悲画扇。等闲变却故人心,却道故人心易变。"
"""
def add_to_history(self, user_input, response):
"""添加对话到历史记录"""
self.conversation_history.append("\n用户说的: " + user_input)
self.conversation_history.append("\n你的回答: " + response)
if len(self.conversation_history) > self.max_history_length * 2:
self.conversation_history = self.conversation_history[-self.max_history_length * 2:]
def get_relevant_knowledge(self, user_input):
"""从知识库中检索相关内容"""
try:
vector = self.kb.get_vector(user_input)
if not vector:
return "没有找到相关内容"
results = self.kb.search(vector, limit=5)
relevant_info = "原文内容为:\n"
for result in results:
relevant_info += result["text"] + "\n"
return relevant_info
except Exception as e:
print(f"知识检索失败: {e}")
return ""
def generate_prompt(self, user_input, relevant_info):
"""生成完整的提示词"""
history_info = "\n".join(self.conversation_history[-4:]) # 只使用最近的两轮对话
return f"""{self.systemprompts}
- 注意:
1. 历史对话:{history_info}
2. 相关诗词:{relevant_info}
3. 用户问题:{user_input}
请以李清照的身份回答,注意:
1. 展现闺秀的温婉气质
2. 适时引用相关的诗词
3. 表达要细腻优雅
4. 可以谈及个人经历,但要含蓄
"""
def chat(self, user_input):
"""与用户对话"""
try:
relevant_info = self.get_relevant_knowledge(user_input)
prompt = self.generate_prompt(user_input, relevant_info)
req = models.ChatCompletionsRequest()
params = {
"Messages": [
{
"Role": "system",
"Content": self.systemprompts
},
{
"Role": "user",
"Content": prompt
}
],
"Model": "hunyuan-standard",
"Temperature": 0.9,
"TopP": 0.95,
"Stream": False
}
req.from_json_string(json.dumps(params))
response = self.kb.vectorizer.client.ChatCompletions(req)
if hasattr(response, 'Choices') and response.Choices:
reply = response.Choices[0].Message.Content
self.add_to_history(user_input, reply)
return reply
return "抱歉,我现在无法回答您的问题。"
except Exception as e:
print(f"对话出错: {e}")
return "抱歉,我遇到了一些问题。"
诗意游历
根据诗人智能体为我们提供地点推荐,漫步诗意山水,智能体推荐对诗人有特殊意义的地点进行推荐,借助混元大模型的文生图,帮助用户实现数字旅行,身临其境沉浸式感受壮美山河。
提示词
poet_prompts = {
'liqingzhao': """你是宋代女词人李清照。请以第一人称的口吻,列出3个对你有特殊意义的地点。
要求:
1. 每个地点都要与你的重要词作或生平经历相关
2. 描述要体现你的婉约词风,突出你对闺阁生活、自然景物的细腻感受
3. 要包含这个地点在你生命中的特殊意义
4. 每个地点用'---'分隔,地点名称和描述用'|||'分隔
5. 对每个地点,先写一段介绍文字,然后空一行,再写一首相关的诗词
示例格式:
地点名称|||这里是一处让我魂牵梦萦的地方,曾在此创作了《如梦令》...
一阕《如梦令》咏此景:
如梦令...---地点名称|||描述
""",
'libai': """你是唐代诗仙李白。请以第一人称的口吻,列出3个对你有特殊意义的地点。
要求:
1. 每个地点都要与你的代表作品或重要经历相关
2. 描述要体现你的豪放诗风,展现你对自然的热爱和对自由的追求
3. 要包含你在此地的诗酒风流故事
4. 每个地点用'---'分隔,地点名称和描述用'|||'分隔
intro_prompts = {
'liqingzhao': """请以李清照的身份,用婉约的语气欢迎游客。
要求:
1. 要体现你作为闺阁词人的细腻情感
2. 表达对生活美好事物的感知
3. 可以提及你的代表作品意境
4. 语气要温婉优雅
""",
诗人时隔千年重回作诗和生成水墨图
ef generate_poetry():
"""生成诗词接口"""
data = request.json
location = data.get('location')
poet = data.get('poet', 'liqingzhao') # 获取诗人参数,默认为李清照
if not location:
return jsonify({'error': '地点不能为空'}), 400
try:
# 根据不同诗人生成不同风格的诗词
style_prompts = {
'liqingzhao': '婉约词风',
'libai': '豪放诗风',
'dufu': '沉郁诗风',
'sushi': '豪放词风'
}
style = style_prompts.get(poet, '婉约词风')
prompt = f"请以{style}创作一首关于{location}的诗词。要求:1. 符合该诗人的创作特色 2. 描写要细腻生动 3. 意境要优美"
poetry = bot.chat(prompt)
# 根据诗词生成图片
try:
@retry_on_network_error(max_retries=3)
def generate_with_retry(prompt, style):
return image_generator.generate_image(
prompt=prompt,
style=style
)
# 提取诗词中的关键场景作为图片生成提示词
image_prompt = f"中国水墨画风格,{location}的场景:{poetry}"
image_url = generate_with_retry(
prompt=image_prompt,
style="shuimo" # 使用水墨画风格
)
return jsonify({
'poetry': poetry,
'imageUrl': image_url if image_url else None
})
except Exception as e:
print(f"生成图片失败: {str(e)}")
# 即使图片生成失败,仍然返回诗词
return jsonify({
'poetry': poetry,
'imageUrl': None,
'imageError': str(e)
})
except Exception as e:
print(f"生成诗词失败: {str(e)}")
return jsonify({'error': str(e)}), 500
获取地点的相关诗词和历史典故
def get_location_poems(location):
"""获取地点相关诗词和历史典故"""
try:
# 获取相关诗词
poems_prompt = f"""请列出2首与{location}最经典的诗词。
要求:
1. 必须是真实存在的古诗词,不要自己创作
2. 选择最经典、广为流传的作品
3. 每首诗词用'---'分隔
4. 每首诗的题目、作者、内容用'|||'分隔
5. 完整保留原诗内容,不要简化或修改
示例格式:
题目|||作者|||诗词内容---题目|||作者|||诗词内容"""
# 获取历史典故
history_prompt = f"""请介绍{location}最著名的历史典故。
要求:
1. 必须是真实的历史事件或典故
2. 按时间顺序介绍1-2个最重要的典故
3. 说明其历史背景和文化意义
4. 如果与著名诗人或文人有关,要特别说明
5. 描述要生动有趣,限制在300字以内"""
# 并行请求
poems_response = bot.chat(poems_prompt)
history_response = bot.chat(history_prompt)
# 解析诗词
poems = []
for poem in poems_response.split('---'):
if '|||' in poem:
parts = poem.strip().split('|||')
if len(parts) >= 3:
title, author, content = parts[:3]
poems.append({
'title': f'{title.strip()}·{author.strip()}',
'content': content.strip()
})
# 如果没有解析到诗词,返回错误
if not poems:
return jsonify({
'error': '未找到相关诗词',
'poems': [],
'history': history_response
})
return jsonify({
'poems': poems,
'history': history_response
})
except Exception as e:
print(f"获取地点信息失败: {str(e)}")
return jsonify({
'error': str(e),
'poems': [],
'history': ''
}), 500
腾讯云AI代码助手提速
这几个功能每一个都是非常实用的,在实际应用过程中快速提升开发能力
- 优化代码
-补全注释
-解释代码
-生成单元格测试
-定位代码缺陷
智能对话
- 代码一键插入功能这个功能可以说是深得我心,以前很多AI编码助手的缺陷到这里被彻底完善了。
引用
借助代码助手的知识库,这个是在开发中具有帮助的。
比如:在前端界面的书写,并且有对TDesign的引用,填写需求生成你想要的样式。减少了阅读官方文档的时间,提高了效率。
补全代码
- 通过潜在代码规律引导补全
- 通过代码注释引导补全:
一键对代码解释