基于semantic_kernel的ChatMD系统

问答系统需求文档

一、项目概述

本项目旨在开发一个能够上传 MD 文件,并基于 MD内容进行问答互动的系统。用户可以上传 MD文件,系统将解析 MD内容,并允许用户通过对话框进行问答互动,获取有关 MD文件内容的信息。

二、功能需求

2.1 用户上传 MD
  • 功能描述:用户可以通过文件选择框上传一个 MD文件。
  • 前端需求
    • 提供文件选择框。
    • 显示文件上传进度。
    • 上传成功后显示文件名和上传成功提示。
  • 后端需求
    • 接收并保存用户上传的 MD文件。
    • 确保上传的文件格式正确(仅支持 PDF,MD)。
    • 限制文件大小(如最大 50 MB)。
2.2 PDF 内容解析
  • 功能描述:系统解析上传的 MD文件内容,将其转换为可处理的文本格式。
  • 前端需求
    • 显示解析进度。
    • 提示用户解析成功或失败。
  • 后端需求
    • 使用 PDF 解析库(如 PyMuPDF、pdfminer)提取 PDF 文本内容。
    • 处理解析错误并返回相应提示。
2.3 用户问答交互
  • 功能描述:用户可以在对话框中输入问题,系统基于解析的 PDF 内容回答问题。
  • 前端需求
    • 提供输入框供用户输入问题。
    • 显示用户问题和系统回答。
  • 后端需求
    • 基于解析的 PDF 内容构建问答模型(如使用 NLP 模型)。
    • 处理用户问题并生成答案。
    • 返回答案给前端显示。

三、非功能需求

3.1 性能要求
  • 系统应能在合理时间内(如 10 秒内)解析 50 页以内的 PDF 文件。
  • 系统应能在 2 秒内返回用户问题的答案。
3.2 安全性要求
  • 上传的 PDF 文件应仅限于当前用户访问。
  • 系统应防止恶意文件上传,如执行文件等。
3.3 可用性要求
  • 系统界面应简单易用,交互流畅。
  • 提供详细的错误提示,如文件格式错误、解析失败等。

四、技术栈

前端
  • HTML/CSS/JavaScript
  • 前端框架:React 或 Vue
后端
  • 编程语言:Python
  • Web 框架:Flask 或 Django
  • PDF 解析库:PyMuPDF、pdfminer
  • NLP 模型:使用 Hugging Face 提供的预训练模型(如 BERT、GPT 系列)
数据库
  • SQLite 或 PostgreSQL(存储用户上传文件信息及解析结果)

五、接口设计

5.1 上传 PDF 文件接口
  • URL/upload
  • 方法:POST
  • 请求参数
    • file:用户上传的 PDF 文件
  • 响应参数
    • 成功:{ "status": "success", "message": "File uploaded successfully.", "file_id": "unique_file_id" }
    • 失败:{ "status": "error", "message": "File upload failed." }
5.2 提取 PDF 内容接口
  • URL/parse
  • 方法:POST
  • 请求参数
    • file_id:已上传文件的唯一标识符
  • 响应参数
    • 成功:{ "status": "success", "message": "File parsed successfully.", "content": "parsed_content" }
    • 失败:{ "status": "error", "message": "File parsing failed." }
5.3 问答接口
  • URL/ask
  • 方法:POST
  • 请求参数
    • file_id:已上传文件的唯一标识符
    • question:用户输入的问题
  • 响应参数
    • 成功:{ "status": "success", "answer": "answer_to_question" }
    • 失败:{ "status": "error", "message": "Unable to retrieve answer." }

六、开发计划

6.1 阶段划分
  1. 需求分析与设计:1 周
  2. 前端开发:2 周
  3. 后端开发:3 周
  4. 整合与测试:2 周
  5. 部署与上线:1 周
6.2 任务分配
  • 需求分析与设计:产品经理、技术负责人
  • 前端开发:前端开发工程师
  • 后端开发:后端开发工程师
  • 整合与测试:全体开发人员
  • 部署与上线:运维工程师

七、风险与应对

  • 文件解析失败:提供详细错误日志,便于调试。
  • 问答模型不准确:迭代优化模型,并根据用户反馈调整。
  • 性能问题:优化解析和问答算法,使用缓存技术。

八、验收标准

  • 用户能顺利上传并解析 PDF 文件。
  • 用户能通过问答接口获取准确答案。
  • 系统运行稳定,无重大安全漏洞。

这份需求文档涵盖了 PDF 内容问答系统的主要功能需求、非功能需求、技术栈、接口设计、开发计划等内容,以确保项目开发顺利进行。

技术实现

系统架构

  1. 前端
    • 文件上传界面
    • 问答交互界面
  2. 后端
    • 文件接收与存储模块
    • PDF 内容解析模块
    • 问答处理模块(基于 Semantic Kernel)
  3. 数据库
    • 存储上传文件信息和解析内容

技术栈

  1. 前端
    • HTML/CSS/JavaScript
    • Vue.js
  2. 后端
    • 编程语言:Python
    • 框架:Flask
    • PDF 解析库:PyMuPDF、pdfminer
    • 问答引擎:Semantic Kernel
  3. 数据库
    • SQLite

前端实现

安装 Vue CLI

npm install -g @vue/cli
vue create pdf-qa-frontend
cd pdf-qa-frontend

创建组件

src/components 目录下创建 FileUpload.vueQuestionAnswer.vue

FileUpload.vue

<template><div class="upload-container"><input type="file" @change="onFileChange" class="file-input" accept=".pdf,.md"/><button @click="uploadFile" class="upload-button">Upload</button><p v-if="message" class="upload-message">{{ message }}</p><div v-if="uploadProgress > 0" class="progress-container"><div class="progress-bar" :style="{ width: uploadProgress + '%' }"></div><p>{{ uploadProgress }}%</p></div></div>
</template><script>
export default {name: 'FileUpload',data() {return {file: null,message: '',uploadProgress: 0};},methods: {onFileChange(event) {this.file = event.target.files[0];},uploadFile() {if (!this.file) {this.message = 'Please select a file first.';return;}let formData = new FormData();formData.append('file', this.file);let xhr = new XMLHttpRequest();xhr.open('POST', 'http://localhost:5000/upload', true);xhr.upload.onprogress = (event) => {if (event.lengthComputable) {this.uploadProgress = Math.round((event.loaded / event.total) * 100);}};xhr.onload = () => {if (xhr.status === 200) {let response = JSON.parse(xhr.responseText);this.message = response.message;this.uploadProgress = 0;} else {this.message = 'Error uploading file.';this.uploadProgress = 0;}};xhr.onerror = () => {this.message = 'Error uploading file.';this.uploadProgress = 0;};xhr.send(formData);}}
};
</script><style scoped>
.upload-container {display: flex;flex-direction: column;align-items: center;margin-bottom: 20px;
}.file-input {margin-bottom: 10px;
}.upload-button {padding: 8px 16px;background-color: #007bff;color: white;border: none;border-radius: 4px;cursor: pointer;
}.upload-button:hover {background-color: #0056b3;
}.upload-message {margin-top: 10px;color: #28a745;
}.progress-container {width: 100%;max-width: 600px;border: 1px solid #ccc;border-radius: 4px;overflow: hidden;margin-top: 10px;position: relative;
}.progress-bar {height: 20px;background-color: #28a745;transition: width 0.4s ease;
}.progress-container p {position: absolute;width: 100%;text-align: center;margin: 0;line-height: 20px;color: white;font-weight: bold;
}
</style>

QuestionAnswer.vue

<template><div class="qa-container"><div class="input-container"><inputtype="text"v-model="question"placeholder="Ask a question..."@keyup.enter="askQuestion"class="question-input"/><button @click="askQuestion" class="ask-button">Ask</button></div><div class="history-container" v-if="dialogHistory.length"><div class="dialog" v-for="(dialog, index) in dialogHistory" :key="index"><p><strong>You:</strong> {{ dialog.question }}</p><p><strong>Bot:</strong> {{ dialog.answer }}</p></div></div></div>
</template><script>
export default {name: 'QuestionAnswer',data() {return {question: '',answer: '',dialogHistory: [],fileId: 'your-file-id'  // Replace with actual file ID after upload};},methods: {async askQuestion() {if (!this.question) {return;}try {let response = await fetch('http://localhost:5000/ask', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({question: this.question,file_id: this.fileId})});let result = await response.json();this.answer = result.answer;this.dialogHistory.push({question: this.question,answer: this.answer});this.question = '';} catch (error) {console.error('Error asking question:', error);}}}
};
</script><style scoped>
.qa-container {display: flex;flex-direction: column;align-items: center;
}.input-container {display: flex;width: 100%;max-width: 600px;margin-bottom: 20px;
}.question-input {flex: 1;padding: 10px;border: 1px solid #ccc;border-radius: 4px 0 0 4px;font-size: 16px;
}.ask-button {padding: 10px 20px;background-color: #28a745;color: white;border: none;border-radius: 0 4px 4px 0;cursor: pointer;
}.ask-button:hover {background-color: #218838;
}.history-container {width: 100%;max-width: 600px;border: 1px solid #ccc;border-radius: 4px;padding: 10px;background-color: #f9f9f9;
}.dialog {margin-bottom: 10px;
}.dialog p {margin: 5px 0;
}
</style>

App.vue

<template><div id="app" class="app-container"><FileUpload /><QuestionAnswer /></div>
</template><script>
import FileUpload from './components/FileUpload.vue';
import QuestionAnswer from './components/QuestionAnswer.vue';export default {name: 'App',components: {FileUpload,QuestionAnswer}
};
</script><style>
.app-container {display: flex;flex-direction: column;align-items: center;padding: 20px;
}
</style>

后端实现

安装 Flask 及相关依赖

pip install Flask flask-cors PyMuPDF pdfminer.six semantic-kernel

创建 Flask 应用

在项目根目录下创建 app.py。确保后端 Flask 代码可以正确处理并解析 MD 文件:

import timeimport markdown
from flask import Flask, request, jsonify
from flask_cors import CORS
import os
import fitz  # PyMuPDF
import sqlite3
from semantic_kernel import Kernel
import semantic_kernel as sk
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAITextEmbedding
import os
import asyncio# 加载 .env 到环境变量
from dotenv import load_dotenv, find_dotenv
from semantic_kernel.functions import KernelArguments
from semantic_kernel.prompt_template import PromptTemplateConfig, InputVariable
from semantic_kernel.text import split_markdown_lines
import asyncio_ = load_dotenv(find_dotenv())app = Flask(__name__)
CORS(app)
UPLOAD_FOLDER = 'uploads/'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER# Initialize Semantic Kernel
kernel = sk.Kernel()# 配置 OpenAI 服务。OPENAI_BASE_URL 会被自动加载生效
api_key = os.getenv('OPENAI_API_KEY')
service_id = "default"llm_service = OpenAIChatCompletion(service_id=service_id,ai_model_id="gpt-3.5-turbo-1106",api_key=api_key
)# 将 LLM 服务添加到 kernel 中
kernel.add_service(llm_service)embedding_gen = OpenAITextEmbedding(ai_model_id="text-embedding-ada-002",api_key=api_key
)
# 将 Embedding 服务添加到 kernel 中
kernel.add_service(embedding_gen)from semantic_kernel.core_plugins.text_memory_plugin import TextMemoryPlugin
from semantic_kernel.memory.semantic_text_memory import SemanticTextMemory
from semantic_kernel.memory.volatile_memory_store import VolatileMemoryStore
import asyncio# 创建一个(内存)向量数据库
memory = SemanticTextMemory(storage=VolatileMemoryStore(), embeddings_generator=embedding_gen)# 添加一个连接向量数据库的 Plugin
kernel.add_plugin(TextMemoryPlugin(memory), "TextMemoryPlugin")
print("kernel.plugins:", kernel.plugins)@app.route('/upload', methods=['POST'])
def upload_file():if 'file' not in request.files:return jsonify({'status': 'error', 'message': 'No file  part'})file = request.files['file']if file.filename == '':return jsonify({'status': 'error', 'message': 'No selected file'})if file:filename = file.filenamefile_id = filename  # In a real app, use a unique identifierfile_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)file.save(file_path)if filename.endswith('.pdf'):content = parse_pdf(file_path)elif filename.endswith('.md'):content = parse_md(file_path)else:return jsonify({'status': 'error', 'message': 'Unsupported file type'})save_file_to_db(file_id, filename, content)return jsonify({'status': 'success', 'message': 'File uploaded and parsed successfully', 'file_id': file_id})def parse_pdf(file_path):doc = fitz.open(file_path)text = ""for page_num in range(len(doc)):page = doc.load_page(page_num)text += page.get_text()return textdef parse_md(file_path):with open(file_path, 'r', encoding='utf-8') as file:text = file.read()return markdown.markdown(text)async def run_function(*args):return await kernel.invoke(*args)def save_file_to_db(file_id, filename, content):print(f'content:', content)lines = split_markdown_lines(content, 100)print("lines:", lines)collection_id = "generic"asyncio.run(process_lines(memory, collection_id, lines))async def save_information_async(memory, collection_id, index, line):await memory.save_information(collection=collection_id, id=index, text=line)# 在某个函数中调用
async def process_lines(memory, collection_id, lines):tasks = []for index, line in enumerate(lines):task = save_information_async(memory, collection_id, index, line)tasks.append(task)await asyncio.gather(*tasks)@app.route('/ask', methods=['POST'])
def ask_question():data = request.jsonfile_id = data.get('file_id')question = data.get('question')print("file_id:", file_id, "question:", question)content = get_file_content_from_db(file_id, question)print("content:", str(content))return jsonify({'status': 'success', 'answer': str(content)})prompt = """基于下面的背景信息回答问题。如果背景信息为空,或者和问题不相关,请回答"我不知道"。[背景信息开始]{{recall $input}}[背景信息结束]问题:{{$input}}回答:"""
req_settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
prompt_template_config = PromptTemplateConfig(template=prompt,description="RAG问答",execution_settings={service_id: req_settings},input_variables=[InputVariable(name="input", description="The user query", is_required=True),],)
rag_function = kernel.add_function(function_name="search_and_answer",plugin_name="MyDemoPlugin",prompt_template_config=prompt_template_config,)def get_file_content_from_db(file_id, question):result = asyncio.run(run_function(rag_function,KernelArguments(input=question)))return resultif __name__ == '__main__':app.run(debug=True)

运行项目

部署与运行

  1. 前端

    • 运行开发服务器

      npm run serve
      
  2. 后端

    • 运行 Flask 应用

      python app.py
      

实现效果

选择md文件

在这里插入图片描述

上传md文件

在这里插入图片描述

上传成功

在这里插入图片描述

问答

  1. chatall怎么下载?
  2. chatall是一个代理吗?
  3. chatall的下载地址?

在这里插入图片描述

回答基于上传的ChatAll.MD文档。

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/22693.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FreeRTOS学习笔记-基于stm32(8)信号量总结(二值信号量、计数型信号量、互斥信号量、优先级翻转、优先级继承)

一、什么是信号量 信号量是一种队列&#xff0c;用于任务间同步和资源管理的机制&#xff0c;主要用来传递状态。就像是一种特殊的“旗子”或“钥匙”&#xff0c;用来在不同的任务之间进行沟通和协调&#xff0c;确保它们能够正确地配合工作&#xff0c;不会互相干扰。 二、二…

保研面试408复习 8——计算机网络(浏览器http)、离散数学(平面图)、操作系统、数据结构

文章目录 一、计算机网络1、从在浏览器输入网址到页面显示的过程1. 输入网址2. DNS 解析3. 建立TCP连接4. 发送HTTP请求5. 服务器处理请求并响应6. 浏览器处理响应7. 页面渲染 二、离散数学一、平面图1、平面图性质2、Kuratowski定理 三、操作系统四、数据结构 一、计算机网络 …

IDCF五周年专场—【研发效能·创享大会】圆满落幕!

2024 年5 月25 日&#xff0c;【研发效能创享大会】—IDCF五周年专场在北京希尔顿欢朋酒店&#xff08;大红门&#xff09;成功举办&#xff01;本次大会旨在为社区成员提供一个学习与交流的平台&#xff0c;分享技术经验&#xff0c;交流行业见解&#xff0c;促进技术合作与创…

Java模板模式及代码

意图 在父类中定义了算法的骨架&#xff0c;而将一些步骤延迟到子类中&#xff0c;使得子类可以不改变一个算法的结构&#xff0c;就可以重定义该算法的某些特定步骤&#xff0c;这种类型的设计模式属于行为型模式。 主要解决的问题 解决在多个子类中重复实现相同的方法的问…

北京海淀区永丰产业基地地块出让,海开控股79.17亿元竞得

据悉&#xff0c;位于北京海淀区西北旺镇的永丰产业基地地块正式出让&#xff0c;引起了业界的广泛关注。经过激烈的竞争&#xff0c;最终由海开控股以79.17亿元的价格成功竞得该地块&#xff0c;成交楼面价达到35588元/平方米&#xff0c;溢价率为1.5%。此次出让的地块不仅吸引…

【Java基础】线程的五大状态

新建状态 使用 new 关键字和 Thread 类或其子类建立一个线程对象后&#xff0c;该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。 就绪状态 当线程对象调用了start()方法之后&#xff0c;该线程就进入就绪状态。就绪状态的线程处于就绪队列中&#xff…

景深技术在AI绘画中的魔法:为数字艺术注入新维度

引言&#xff1a; 在人工智能&#xff08;AI&#xff09;的浪潮中&#xff0c;绘画艺术领域迎来了革命性的变革。AI绘画不仅改变了创作过程&#xff0c;还为艺术家和设计师提供了前所未有的工具。其中&#xff0c;景深技术作为一种重要的视觉处理手段&#xff0c;在AI绘画中的应…

error:nullptr was not declared in this scope

nullptr是c11的内容,在Qt5.5.0中使用时需要在.pro添加 QMAKE_CXXFLAGS -stdc11

告别繁琐,Xinstall一键解决App代理结算难题!

在移动互联网的浪潮中&#xff0c;App的推广和运营成为了众多企业和开发者关注的焦点。然而&#xff0c;随着App市场的日益竞争&#xff0c;代理结算的复杂性和繁琐性成为了许多推广者头疼的问题。为了解决这个问题&#xff0c;Xinstall凭借其专业的技术和丰富的服务经验&#…

在ros中获取话题的发布节点名称(C++)

文章目录 概要CMakeLists.txt主要代码效果概要 在ROS中,直接从订阅回调函数中获取发布该话题的节点信息并不直接支持。ROS设计的发布-订阅机制并没有直接提供在回调函数中获取发布节点的接口。发布节点的信息主要通过rosgraph等工具来获取。 不过,可以通过以下几种方式间接…

Modebus通信协议 温控器示例

目录 1 指令解释 2 获取动态的CRC 3 crc在线验证 4 16进制正负温度互转 4.2 16进制转温度 4.2 温度转16进制 5 完整工具类 最近安卓工作接了很多硬件&#xff0c;其他的都是发个固定指令&#xff0c;比较有代表性就是温控器和打印机自定义内容所以这个记录接入示例&…

为什么没有输出九九乘法表?

下面的程序本来想输出九九乘法表到屏幕上&#xff0c;为什么没有输出呢&#xff1f;怎样修改&#xff1f; <!DOCTYPE html> <html> <head> <meta charset"utf-8" /> <title>我的HTML练习</title> …

从零开始教你RuoYi-Cloud项目阿里云部署

这里写自定义目录标题 准备需要的文件文件下载运程工具(按需下载)文件上传一、安装Docker环境二、应用部署2.1、Nacos2.2、Nginx2.3、Mysql2.4、Redis2.5、JDK2.6、Docker Compose三、项目部署四、ERROR无法访问云服务器上部署的Docker容器端口冲突或端口占用Linux修改jar包中…

qemu虚拟机安装麒麟v10 arm版系统

截止目前&#xff0c;安装v10 sp1版本系统&#xff0c;&#xff0c;v10 sp3系统无法安装。 1.// 创建虚拟机 最好大于65G qemu-img create -f qcow2 D:\Kylin\Kylindisk.qcow2 70G2.// 使用qemu-system-aarch64.exe命令安装麒麟操作系统&#xff1a; qemu-system-aarch64.exe …

go语言进阶 包

package 包&#xff1a; go 语言使用包&#xff08;package&#xff09;这种语法元素来组织管理源码&#xff0c;所有语法可见性均定义在 package 这个级别 与 Java python 相似 1. main 包&#xff1a; go 语言的程序入口 main() 函数所在的包 (package) 叫做 main包 , mian…

linux内核下rapidio(TSI721)相关笔记汇总

1 驱动的安装 和 主要功能(doorbell, DMA, rionet)的简单测试 linux5.4 下使用rapidio(tsi721)的笔记记录_kernel-rapidio-CSDN博客 2 机理分析 linux内核下&#xff0c;rapidio网络系统建立的过程(枚举 和 发现)_linux rapidio-CSDN博客 linux内核下&#xff0c;(rapidio)T…

新火种AI|倒反天罡!美国名校斯坦福AI团队抄袭中国大模型

作者&#xff1a;一号 编辑&#xff1a;美美 中国大模型被抄袭&#xff0c;怎么不算是某种层面上的国际认可呢&#xff1f; 5月29日&#xff0c;斯坦福大学的一个AI研究团队发布了一个名为「Llama3V」的模型&#xff0c;号称只要 500 美元就能训练出一个 SOTA 多模态模型&am…

Python库之pandas的简介、安装、使用方法详细攻略

Python库之pandas的简介、安装、使用方法详细攻略 简介 pandas 是 Python 中用于数据分析和操作的一个强大库&#xff0c;它提供了快速、灵活和表达力强的数据结构&#xff0c;旨在使数据清洗和分析工作变得更加简单易行。pandas 适用于处理表格数据&#xff08;例如CSV文件、…

元宇宙概念及关键技术

“元宇宙”这个概念最早出自上世纪90年代出版的一部美国人写的科幻小说《雪崩》&#xff08;Snow Crash&#xff09;&#xff0c;作家Neal Stephenson这样定义元宇宙&#xff1a;“元宇宙是指一个脱胎于现实世界&#xff0c;又与现实世界平行、相互影响&#xff0c;并且始终在线…

知识库系统:从认识到搭建

在这个信息过载的时代&#xff0c;企业越来越需要一个集中的知识库系统来促进员工协作和解决问题。本文跟着LookLook同学一起来探讨搭建高效知识库系统的所有注意事项和知识库系统的最佳推荐。 | 什么是知识库系统 知识库系统是一种软件或工具&#xff0c;旨在填补组织内的知识…