Langchain从零开始到应用落地案例[AI智能助手]【5】---实现基于FastAPI+Langchain+ocr实现上下文对话大模型对话接口

目录

前言

环境安装

前提代码编写准备

端口代码编写

示例代码

运行效果演示

错误问题


前言

在之前的篇章已经实现langchain大模型对话,然后ocr文件识别,不过都只能在控制台实现效果操作。

接下来,咱们一起学习如何在FastAPI编写请求接口,为之后部署服务和页面上做好准备。

在这里,我的代码不一定适合所有人运行,只作为参考,不同的环境和版本框架内容不一定能运行,这里先说明了一下,如有需要后续代码会上传到github上提供下载和参考,这里谢谢大家了

环境安装

Fastapi环境

pip install fastapi

uvicorn一个ASGI服务器,用来运行fatapi端口

pip install uvicorn

前提代码编写准备

首先就是fastapi的实例化和服务器设置(在保证端口的不冲突下)

实例化和中间建设置

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware


app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

然后uvicorn服务器设置

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

端口代码编写

首先创建请求路径和传递参数

@app.post("/chat_llm")
async def chat_llm(
        question: str = Form(...),
        session_id: Optional[str] = Form(None),
        file_path: Optional[UploadFile] = None,
):

然后会话session_id定义

# 1. 确保 session_id 存在
if not session_id:
    session_id = str(uuid.uuid4())

# 2. 初始化会话历史(如果不存在)
if session_id not in memory_store:
    memory_store[session_id] = ChatMessageHistory()

对接ocr进行文件内容识别输出

# 3. 处理文件上传(OCR)
    ocr_content = ""
    temp_file_path = None
    try:
        if file_path is not None and hasattr(file_path, 'filename') and file_path.filename:
            # 创建临时文件
            suffix = f".{file_path.filename.split('.')[-1]}" if '.' in file_path.filename else ""
            with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as temp_file:
                content = await file_path.read()
                temp_file.write(content)
                temp_file_path = temp_file.name

            # 执行 OCR
            file_text = ocr_file(temp_file_path)
            if file_text and file_text.strip():
                ocr_content = f"【文件内容】\n{file_text}\n\n"
            else:
                ocr_content = "【文件内容】\n(未识别到有效文本)\n\n"
    finally:
        # 清理临时文件
        if temp_file_path and os.path.exists(temp_file_path):
            os.unlink(temp_file_path)

然后最后面的大模型拼接输出

默认提示词

SYSTEM_PROMPT = (
    "你是一个问答助手。请根据用户的提问和可能提供的文件内容进行回答。"
    "如果用户上传了文件,请结合文件内容回答问题;否则仅根据问题回答。"
)

函数内部

 # 4. 构建完整消息列表
    messages = [("system", SYSTEM_PROMPT)]
    messages.extend(memory_store[session_id].messages)

    # 将 OCR 内容拼接到用户问题前(作为当前轮次的上下文)
    current_user_message = ocr_content + question
    messages.append(("human", current_user_message))

    # 5. 调用模型
    prompt = ChatPromptTemplate.from_messages(messages)
    response = (prompt | Setting_llm).invoke({})

    # 6. 保存原始问题(不含 OCR)到历史,避免重复污染
    memory_store[session_id].add_user_message(question)
    memory_store[session_id].add_ai_message(response.content)

示例代码

@app.post("/chat_llm")
async def chat_llm(
        question: str = Form(...),
        session_id: Optional[str] = Form(None),
        file_path: Optional[UploadFile] = None,
):
    # 1. 确保 session_id 存在
    if not session_id:
        session_id = str(uuid.uuid4())

    # 2. 初始化会话历史(如果不存在)
    if session_id not in memory_store:
        memory_store[session_id] = ChatMessageHistory()

    # 3. 处理文件上传(OCR)
    ocr_content = ""
    temp_file_path = None
    try:
        if file_path is not None and hasattr(file_path, 'filename') and file_path.filename:
            # 创建临时文件
            suffix = f".{file_path.filename.split('.')[-1]}" if '.' in file_path.filename else ""
            with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as temp_file:
                content = await file_path.read()
                temp_file.write(content)
                temp_file_path = temp_file.name

            # 执行 OCR
            file_text = ocr_file(temp_file_path)
            if file_text and file_text.strip():
                ocr_content = f"【文件内容】\n{file_text}\n\n"
            else:
                ocr_content = "【文件内容】\n(未识别到有效文本)\n\n"
    finally:
        # 清理临时文件
        if temp_file_path and os.path.exists(temp_file_path):
            os.unlink(temp_file_path)

    # 4. 构建完整消息列表
    messages = [("system", SYSTEM_PROMPT)]
    messages.extend(memory_store[session_id].messages)

    # 将 OCR 内容拼接到用户问题前(作为当前轮次的上下文)
    current_user_message = ocr_content + question
    messages.append(("human", current_user_message))

    # 5. 调用模型
    prompt = ChatPromptTemplate.from_messages(messages)
    response = (prompt | Setting_llm).invoke({})

    # 6. 保存原始问题(不含 OCR)到历史,避免重复污染
    memory_store[session_id].add_user_message(question)
    memory_store[session_id].add_ai_message(response.content)

    return {
        "session_id": session_id,
        "response": response.content
    }

运行效果演示

错误问题

关于这个接口会出现一个文件上传422错误,这个我目前不知道怎么解决

出现的原因就是当我不上传文件的时候,他会默认传递一个空值,即空字符串,fatapi处理不了,然后就导致错误,不过可以采取把这个参数删除掉,通过前端传递就Ok了,但是测试的时候没法处理,不过目前是够用的。

到时候创建一个普通接口即删除ocr识别,通过前端传递判断使用哪个接口进行传递参数就ok了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值