汉字谜盒-核心功能开发

汉字谜盒-核心功能开发

2026年9月20日·#编程学习/python学习笔记Python/Web开发·1577 字 8 分钟
浏览量加载中...
AI 摘要

五个接口的开发:新建会话、与 AI 交互(Pydantic 数据模型 + 调用大模型七步)、会话列表、加载与删除会话

五个接口总览#

接口方式参数说明
/api/sessionsPOST新建会话,返回会话标识
/api/chatPOST{session_id, message}与 AI 交互,返回 AI 的回复
/api/sessionsGET获取会话列表(按时间倒序)
/api/sessions/{session_id}GET会话 ID(路径参数)加载指定会话
/api/sessions/{session_id}DELETE会话 ID(路径参数)删除指定会话

统一响应格式(三个字段):

{ "code": 200, "message": "创建会话成功", "data": "2026-04-12_16-16-13" }

用 Pydantic 定义数据模型#

from typing import Any
from pydantic import BaseModel
# 统一响应模型
class ApiResponse(BaseModel):
code: int
message: str
data: Any # 任意类型的数据
# 与 AI 交互的请求模型
class ChatRequest(BaseModel):
session_id: str
message: str
Important

BaseModel 是 Pydantic 库提供的父类(FastAPI 深度集成了 Pydantic),用于定义数据模型和数据验证规则。 定义好 ChatRequest 后,接口函数写成 def chat(request: ChatRequest),FastAPI 就会自动把请求体里的 JSON 解析成这个对象,并校验字段类型——不用自己 json.loads。 (前端传的就是 {"session_id": "...", "message": "你好"}。)

接口一:新建会话#

打开页面时如果没有会话,就自动创建一个,会话标识形如 2026-04-15_12-00-05

def generate_session_id():
return datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
@app.post("/api/sessions")
def create_session() -> ApiResponse:
session_id = generate_session_id()
session_data = {"current_session": session_id, "messages": []}
with open(f"sessions/{session_id}.json", "w", encoding="utf-8") as f:
json.dump(session_data, f, ensure_ascii=False, indent=2)
return ApiResponse(code=200, message="创建会话成功", data=session_id)

接口二:与 AI 交互(核心)#

请求体:{"session_id": "2026-04-15_12-00-05", "message": "你好"}

处理流程七步

@app.post("/api/chat")
def chat(request: ChatRequest) -> ApiResponse:
# 1. 加载 json 文件中的会话数据
session_path = f"sessions/{request.session_id}.json"
with open(session_path, "r", encoding="utf-8") as f:
session_data = json.load(f)
# 2. 构建给大模型的消息列表(system + 历史 + 本轮提问)
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
for message in session_data["messages"]:
messages.append(message)
messages.append({"role": "user", "content": request.message})
# 3. 调用 AI 大模型
response = client.chat.completions.create(
model="deepseek-v4-flash",
messages=messages,
stream=False,
temperature=1.0,
)
# 4. 获取响应的数据
ai_response = response.choices[0].message.content
# 5. 更新消息列表(把 system 摘掉,把 AI 回复追加进去)
messages.pop(0)
messages.append({"role": "assistant", "content": ai_response})
session_data["messages"] = messages
# 6. 保存会话信息到 json 文件
with open(session_path, "w", encoding="utf-8") as f:
json.dump(session_data, f, ensure_ascii=False, indent=2)
# 7. 返回数据
return ApiResponse(code=200, message="请求成功", data=ai_response)
Note

第 5 步为什么要 messages.pop(0) 因为落盘保存的是”会话历史”,只需要 user 和 assistant 的往来内容;system 是每次请求时临时加上去的(第 2 步),不该混进历史里,否则下次加载会重复叠加。

Warning

课程的代码里 model 写的是 "deepseek-v4-flash"。按 DeepSeek 官方文档(2026-09 查证),当前可用的是 deepseek-flash(对应 DeepSeek-V4.1-Flash)和 deepseek-v4-prodeepseek-v4-flash 属于已被兼容的旧 id,仍能调用但会被路由到新模型;而更早的 deepseek-chat / deepseek-reasoner 已经不在文档的模型列表里。写新代码时建议用文档上的当前 id,具体以官方文档为准。

接口三~五:会话列表 / 加载 / 删除#

# 会话列表:取出 sessions 目录下所有文件名,去掉后缀,倒序
@app.get("/api/sessions")
def get_sessions() -> ApiResponse:
session_files = os.listdir("sessions")
session_ids = [file.split(".")[0] for file in session_files]
session_ids.sort(reverse=True)
return ApiResponse(code=200, message="获取会话列表成功", data=session_ids)
# 加载指定会话:路径参数 session_id
@app.get("/api/sessions/{session_id}")
def get_session(session_id: str) -> ApiResponse:
with open(f"sessions/{session_id}.json", "r", encoding="utf-8") as f:
session_data = json.load(f)
return ApiResponse(code=200, message="获取会话信息成功", data=session_data)
# 删除指定会话
@app.delete("/api/sessions/{session_id}")
def delete_session(session_id: str) -> ApiResponse:
session_file = f"sessions/{session_id}.json"
if os.path.exists(session_file):
os.remove(session_file)
return ApiResponse(code=200, message="删除会话成功", data=None)
Tip

路径参数/api/sessions/{session_id} 里的花括号部分是变量,要原样写进函数形参def get_session(session_id: str)),FastAPI 会自动把 URL 里那一段取出来传给你。这也是 REST 风格”URL 定位资源”的落地:同一个路径,靠不同的请求方式(GET/DELETE)做不同的事。

相关#

练习题#

一、回忆填空(写完再展开对答案)#

  1. 统一响应格式的三个字段:code________
  2. 定义数据模型需要继承 Pydantic 的 ____ 类;FastAPI 会据此自动解析请求体 JSON 并做 ____ 校验
  3. 与 AI 交互的请求模型 ChatRequest 有两个字段:________
  4. 与 AI 交互七步:加载会话 json → 构建 ____ → 调用 ____ → 获取响应 → 更新消息列表 → 保存 json → 返回数据
  5. 第 5 步用 messages.____(0)system 消息摘掉,因为它只是本次请求临时加上去的
  6. 路径参数写在 URL 的 ____ 里,并且要写进函数 ____
  7. 会话列表接口用 os.____("sessions") 列出文件,再用 sort(reverse=____) 按时间倒序
  8. 删除会话前先判断文件是否存在:os.path.____(path),存在才 os.____(path)
填空答案(做完再点开)
  1. message / data 2. BaseModel / 类型(数据验证) 3. session_id / message 4. 消息列表 / 大模型 5. pop 6. 花括号 {} / 形参 7. listdir / True 8. exists / remove

二、裸写题#

  • 2-1 新建会话接口POST /api/sessions:生成以秒为单位的会话标识,创建 sessions/{id}.json(内含 current_session 与空 messages),返回统一格式。

    提示(先自己想,实在想不出再点开)

    一级 · 思路:生成标识 → 写文件 → 返回 二级 · 方法datetime.now().strftime("%Y-%m-%d_%H-%M-%S") / json.dump(..., ensure_ascii=False, indent=2) 三级 · 骨架return ApiResponse(code=200, message="创建会话成功", data=session_id)

  • 2-2 会话列表接口GET /api/sessions:列出 sessions 目录下所有会话标识(去掉 .json 后缀),按时间倒序返回。

    提示

    一级 · 思路:列目录 → 去后缀 → 排序 二级 · 方法os.listdir / file.split(".")[0] / sort(reverse=True) 三级 · 骨架:因为会话标识本身就是时间戳格式,字符串倒序就等于时间倒序

  • 2-3 用一个测试请求走通流程TestClient:先 POST 新建会话拿到 id,再用这个 id 调 GET 列表(确认列表里有它),最后 DELETE 掉。

    提示

    一级 · 思路:三个接口串成一条链路,不启动服务器也能测 二级 · 方法client.post("/api/sessions") / client.get("/api/sessions") / client.delete(...) 三级 · 骨架session_id = resp.json()["data"],再拼进 URL

参考答案(做完再点开)
import os
import json
from datetime import datetime
from typing import Any
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
app = FastAPI(title="会话接口练习")
if not os.path.exists("sessions"):
os.mkdir("sessions")
class ApiResponse(BaseModel):
code: int
message: str
data: Any
def generate_session_id():
return datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
# 2-1
@app.post("/api/sessions")
def create_session() -> ApiResponse:
session_id = generate_session_id()
session_data = {"current_session": session_id, "messages": []}
with open(f"sessions/{session_id}.json", "w", encoding="utf-8") as f:
json.dump(session_data, f, ensure_ascii=False, indent=2)
return ApiResponse(code=200, message="创建会话成功", data=session_id)
# 2-2
@app.get("/api/sessions")
def get_sessions() -> ApiResponse:
session_ids = [f.split(".")[0] for f in os.listdir("sessions")]
session_ids.sort(reverse=True)
return ApiResponse(code=200, message="获取会话列表成功", data=session_ids)
@app.delete("/api/sessions/{session_id}")
def delete_session(session_id: str) -> ApiResponse:
path = f"sessions/{session_id}.json"
if os.path.exists(path):
os.remove(path)
return ApiResponse(code=200, message="删除会话成功", data=None)
# 2-3 链路测试
if __name__ == "__main__":
client = TestClient(app)
resp = client.post("/api/sessions")
session_id = resp.json()["data"]
print("新建:", resp.json())
print("列表:", client.get("/api/sessions").json())
print("删除:", client.delete(f"/api/sessions/{session_id}").json())
print("删除后列表:", client.get("/api/sessions").json())

评论区

[ 标签 ]
# AI37# AI 编程2# AI工具1# Ajax2# Apifox1# AstrBot3# Astro2# CC Switch1# CDN2# Claude Code1# claudecode2# ClaudeCode1# Cloudflare2# CloudFlare2# CloudFlare-ImgBed3# coc3# CSS6# DeepSeek6# deepseek2# DELETE1# Docker1# EdgeOne3# Gist1# git1# GitHub1# hexo-circle-of-friends1# HTML6# HTTP5# ImageManager1# Java23# java13# JavaScript5# JDBC3# JSON2# JUnit1# LangChain25# Logback1# Maven6# Muse Spark1# Mybatis1# MyBatis4# MySQL28# MySql1# NapCat1# Node.js1# obsidian2# Obsidian5# OpenCode4# ORM1# PathVariable1# PicGo1# PyCharm1# Python65# RequestBody1# RequestMapping1# RESTful风格1# skills1# Slf4j1# SpringBoot11# SQL2# Streamlit5# Svelte2# TailwindCSS1# Telegram3# Tlias2# Vercel1# vscode2# Vue7# Waline3# WebDAV1# Web基础6# Web开发6# WinSCP1# YAML1# 三层架构1# 中二宣言1# 书籍1# 使用文档10# 写作1# 函数2# 刷步数1# 前端32# 动态1# 动漫1# 包1# 单词2# 博客7# 博客工作流1# 博客开发2# 参数接收1# 友链1# 反思2# 图床6# 地图1# 备份2# 大模型1# 奇思妙想1# 存储1# 学习方法6# 学校1# 宝塔面板3# 宝宝10# 对象1# 导航栏1# 工具2# 开发1# 开发工具1# 开发规范1# 开心1# 异常处理1# 影视2# 微信1# 性能优化2# 总结1# 想法15# 感受1# 感悟11# 指南1# 提示词工程1# 插件5# 故障排除1# 效率工具2# 教程10# 数据分析9# 数据库27# 数据结构1# 文件操作2# 斩神1# 日常92# 日志框架1# 朋友圈1# 朱元璋1# 模块1# 模板1# 正则表达式2# 测试1# 游戏2# 爬虫7# 生活迁移1# 电影2# 电脑1# 碎碎念1# 视觉识别1# 类1# 类型注解1# 网络基础2# 网络教室1# 羊毛2# 脚本2# 脚本工具1# 自动化2# 蓝奏云1# 订阅推荐2# 记录2# 评论系统1# 词根1# 词缀1# 说说1# 足迹1# 跑步2# 路径参数1# 转载2# 运动1# 部落冲突1# 配置1# 随机图1# 面向对象5# 音乐3# 音标1# 饮食1# 驼峰命名1# 高德地图1
[ 公告 ]

如果你喜欢,那么欢迎来到我的世界!

了解更多
[ 音乐 ]
封面

音乐

暂未播放

0:000:00
暂无歌词
找不到相关结果。
[ contents ]
[ 全部文章 ]