Browse Source

feat:添加历史人物的润色

zhangwl 1 month ago
parent
commit
1a7e23e567
4 changed files with 173 additions and 2 deletions
  1. 55 0
      app/db/mongo.py
  2. 84 2
      app/routers/chat_tools.py
  3. 9 0
      app/routers/users.py
  4. 25 0
      app/schemas/chat.py

+ 55 - 0
app/db/mongo.py

@@ -1,4 +1,5 @@
 from pymongo import MongoClient
+from bson import ObjectId
 from datetime import datetime
 from dotenv import load_dotenv
 import os
@@ -16,6 +17,8 @@ chat_logs = db["chat_logs"]
 chat_history_col = db["chat_history"]
 # 兴趣圈集合
 circle_prompts = db["circle_prompt"]
+# 历史人物集合
+historical_figures = db["historical_figures"]
 
 def _ensure_index():
     try:
@@ -166,3 +169,55 @@ def upsert_circle_prompt(data: dict) -> None:
         {"$set": data},
         upsert=True,
     )
+
+
+# ===================== 历史人物 =====================
+
+def get_all_figures() -> list:
+    try:
+        docs = historical_figures.find({})
+        return [{"_id": str(doc["_id"]), **{k: v for k, v in doc.items() if k != "_id"}} for doc in docs]
+    except Exception as e:
+        print(f"MongoDB 历史人物列表查询失败: {e}")
+        return []
+
+
+def get_figure_by_id(figure_id: str) -> dict | None:
+    try:
+        doc = historical_figures.find_one({"_id": ObjectId(figure_id)})
+        if doc:
+            doc["_id"] = str(doc["_id"])
+        return doc
+    except Exception as e:
+        print(f"MongoDB 历史人物查询失败: {e}")
+        return None
+
+
+def insert_figure(data: dict) -> str:
+    try:
+        result = historical_figures.insert_one(data)
+        return str(result.inserted_id)
+    except Exception as e:
+        print(f"MongoDB 历史人物新增失败: {e}")
+        return None
+
+
+def update_figure(figure_id: str, data: dict) -> int:
+    try:
+        result = historical_figures.update_one(
+            {"_id": ObjectId(figure_id)},
+            {"$set": data},
+        )
+        return result.matched_count
+    except Exception as e:
+        print(f"MongoDB 历史人物修改失败: {e}")
+        return 0
+
+
+def delete_figure(figure_id: str) -> int:
+    try:
+        result = historical_figures.delete_one({"_id": ObjectId(figure_id)})
+        return result.deleted_count
+    except Exception as e:
+        print(f"MongoDB 历史人物删除失败: {e}")
+        return 0

+ 84 - 2
app/routers/chat_tools.py

@@ -2,9 +2,9 @@ from fastapi import APIRouter, HTTPException
 from datetime import datetime
 
 from ..core.ark_client import config, client
-from ..schemas.chat import ChatMessage, ChatResponse, CircleRequest, CirclePromptConfig
+from ..schemas.chat import ChatMessage, ChatResponse, CircleRequest, CirclePromptConfig, HistoricalFigure, RephraseRequest, FigureUpsert
 from ..db.souyue_mongo import get_mblog_by_id
-from ..db.mongo import get_circle_prompt, upsert_circle_prompt
+from ..db.mongo import get_circle_prompt, upsert_circle_prompt, get_all_figures, get_figure_by_id, insert_figure, update_figure, delete_figure
 
 router = APIRouter()
 
@@ -96,3 +96,85 @@ async def generate_circle_comment(request: CircleRequest):
         model=response.model,
         usage=response.usage.model_dump() if response.usage else None,
     )
+
+
+# ===================== 历史人物管理 =====================
+# 获取历史人物列表
+@router.get("/figures", response_model=list[HistoricalFigure])
+async def list_figures():
+    return get_all_figures()
+
+# 获取单个历史人物
+@router.get("/figures/{id}", response_model=HistoricalFigure)
+async def get_figure(id: str):
+    doc = get_figure_by_id(id)
+    if not doc:
+        raise HTTPException(status_code=404, detail="历史人物不存在")
+    return doc
+
+# 新增历史人物
+@router.post("/figures", response_model=HistoricalFigure)
+async def create_figure(figure: FigureUpsert):
+    inserted_id = insert_figure(figure.model_dump())
+    if not inserted_id:
+        raise HTTPException(status_code=500, detail="新增失败")
+    return {**figure.model_dump(), "_id": inserted_id}
+
+# 修改历史人物
+@router.put("/figures/{id}", response_model=HistoricalFigure)
+async def modify_figure(id: str, figure: FigureUpsert):
+    matched = update_figure(id, figure.model_dump())
+    if not matched:
+        raise HTTPException(status_code=404, detail="历史人物不存在")
+    return {**figure.model_dump(), "_id": id}
+
+# 删除历史人物
+@router.delete("/figures/{id}")
+async def remove_figure(id: str):
+    deleted = delete_figure(id)
+    if not deleted:
+        raise HTTPException(status_code=404, detail="历史人物不存在")
+    return {"message": "删除成功", "id": id}
+
+
+# ===================== 润色接口 =====================
+# 润色接口
+@router.post("/rephrase")
+async def rephrase_as_figure(request: RephraseRequest):
+    figure = get_figure_by_id(request.figureId)
+    if not figure:
+        raise HTTPException(status_code=404, detail="历史人物不存在")
+
+    prompt = (
+        f"你是{figure['name']},{figure['description']},生活在{figure['era']}。\n"
+        f"请将以下话语改写成{figure['name']}的说话风格,保留原意,体现其性格特点({figure['prompt']})。\n"
+        f"只输出改写后的内容,不要解释、不要加引号。\n"
+        f"原文:{request.text}"
+    )
+
+    response = client.responses.create(
+        model=config.MODEL_NAME,
+        input=[{"role": "user", "content": prompt}],
+        stream=False,
+        store=False,
+        # thinking={"type":"auto"},
+    )
+
+    rephrased = ""
+    for item in response.output:
+        if hasattr(item, 'type') and item.type == 'message' and hasattr(item, 'content'):
+            if isinstance(item.content, list):
+                for content_item in item.content:
+                    if hasattr(content_item, 'text'):
+                        rephrased += content_item.text
+            else:
+                rephrased += str(item.content)
+
+    if not rephrased:
+        raise HTTPException(status_code=500, detail="AI未能生成润色结果")
+
+    return {
+        "original": request.text,
+        "rephrased": rephrased,
+        "figure": figure["name"],
+    }

+ 9 - 0
app/routers/users.py

@@ -111,6 +111,15 @@ fake_users_db = {
     "root": {
         "userId":"1",
         "username": "root",
+        "full_name": "root",
+        "email": "root@example.com",
+        # 这是"admin"的bcrypt哈希值
+        "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$AnPKKWadE68rd3n9CSM7vQ$p0LA3GqVSYxGRopB0B1yzzlO7W1LRCWagShF+Sbre9I",
+        "disabled": False,
+    },
+    "admin": {
+        "userId":"2",
+        "username": "admin",
         "full_name": "Administrator",
         "email": "admin@example.com",
         # 这是"admin"的bcrypt哈希值

+ 25 - 0
app/schemas/chat.py

@@ -53,3 +53,28 @@ class StreamResponse(BaseModel):
     model: str
     timestamp: datetime
     type: str = "answer"  # "thinking"=AI思考开过车delta | "searching"=搜索状态/关键词 | "answer" = 正式回答 delta(现有逻辑)
+
+
+# 历史人物
+class HistoricalFigure(BaseModel):
+    id: str = Field(alias="_id")  # MongoDB _id
+    name: str           # 姓名,如 "孔子"
+    era: str            # 朝代/时期,如 "春秋时期"
+    description: str    # 简介,如 "儒家创始人"
+    prompt: str         # 说话风格提示词,用于 AI 润色
+
+    model_config = ConfigDict(populate_by_name=True)
+
+
+# 历史人物新增/修改(不含 id,由 MongoDB 生成)
+class FigureUpsert(BaseModel):
+    name: str
+    era: str
+    description: str
+    prompt: str
+
+
+# 润色请求
+class RephraseRequest(BaseModel):
+    figureId: str   # 历史人物 _id
+    text: str       # 用户原文