from fastapi import APIRouter, HTTPException from datetime import datetime from ..core.ark_client import config, client 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, get_all_figures, get_figure_by_id, insert_figure, update_figure, delete_figure router = APIRouter() def _build_prompt(product_text: str, prompt_config: dict) -> str: name = prompt_config.get("name", "兴趣圈") role = prompt_config.get("role", "活跃用户") style = prompt_config.get("style", "自然亲切,有活人感") keywords: list = prompt_config.get("keywords") or [] forbidden: list = prompt_config.get("forbidden") or [] extraInstruction = prompt_config.get("extra_instruction") lines = [ f"你是{role},活跃在{name}兴趣圈。", "请根据以下帖子信息,生成一条10-30字的评论,要求:", "1. 内容指向性强,结合帖子具体内容", f"2. 风格:{style}", ] seq = 3 if keywords: lines.append(f"{seq}. 适当融入关键词(自然使用):{', '.join(keywords)}") seq += 1 if forbidden: lines.append(f"{seq}. 禁止使用以下词语:{', '.join(forbidden)}") seq += 1 lines.append(f"{seq}. 语言自然,不要暴露你是AI") # 额外要求 if extraInstruction: lines.append(f"【额外要求】{','.join(extraInstruction)}") lines.append(f"\n帖子内容:{product_text}") return "\n".join(lines) # 存储/更新兴趣圈提示词模版(appName 已存在则覆盖) @router.post("/prompt") async def save_circle_prompt(promptcfg: CirclePromptConfig): try: upsert_circle_prompt(promptcfg.model_dump()) return {"message": "保存成功", "appName": promptcfg.appName} except Exception as e: raise HTTPException(status_code=500, detail=f"保存失败: {str(e)}") # 评论帖子的马甲机器人,无状态,支持批量对多个帖子智能回复 @router.post("/airesp", response_model=ChatResponse) async def generate_circle_comment(request: CircleRequest): doc = get_mblog_by_id(request.id) if not doc: raise HTTPException(status_code=404, detail="帖子不存在") title = doc.get("title", "") brief = doc.get("brief", "") nickname = doc.get("nickname", "") app_name = doc.get("appName", "") images: list = doc.get("images") or [] product_text = f"主题:{title}\n摘要:{brief}\n发布者:{nickname}" if images: product_text += "\n图片:\n" + "\n".join(images) prompt_config = get_circle_prompt(app_name) prompt = _build_prompt(product_text, prompt_config) response = client.responses.create( model=config.MODEL_NAME, input=[{"role": "user", "content": prompt}], stream=False, store=False, ) message_content = "" 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'): message_content += content_item.text else: message_content += str(item.content) if not message_content: raise HTTPException(status_code=500, detail="AI未能生成评论") return ChatResponse( message=ChatMessage(role="assistant", content=message_content, timestamp=datetime.now()), 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"], }