From db1319eb11c59ad2c53d8f97ee6727682bd8a0f2 Mon Sep 17 00:00:00 2001 From: jinye_huang Date: Fri, 11 Jul 2025 16:07:55 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E4=BA=86=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E8=8E=B7=E5=BE=97=E7=9A=84=E6=8F=90=E7=A4=BA=E8=AF=8D=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E5=86=85=E5=AE=B9=E7=94=9F=E6=88=90=E7=9A=84=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/__pycache__/dependencies.cpython-312.pyc | Bin 2022 -> 2363 bytes api/dependencies.py | 8 +- .../__pycache__/prompt.cpython-312.pyc | Bin 10282 -> 8865 bytes api/routers/__pycache__/tweet.cpython-312.pyc | Bin 6210 -> 8117 bytes api/routers/prompt.py | 288 +++++++++--------- api/routers/tweet.py | 84 +++-- .../__pycache__/tweet.cpython-312.pyc | Bin 9563 -> 10947 bytes api/services/tweet.py | 24 ++ 8 files changed, 237 insertions(+), 167 deletions(-) diff --git a/api/__pycache__/dependencies.cpython-312.pyc b/api/__pycache__/dependencies.cpython-312.pyc index bd44757265d07ee7b70c2a3b5e563ff9522abcab..3a619957c3c646bed8d8505e90523f1b37a978cb 100644 GIT binary patch delta 1020 zcmZuvO=#3W6rR~6o83*)?QYdtTcNGLOJ&6#>ZN#65UZC~C@h5#HnTO5pJkG@6qN0u zRS;B4pgq`&$5ItUQN*h^4;Jdhh`QCf;-n{vCiyzCzXTvBE zSZ_Zy?Nm#ylgG&sWnyX6*uSQYk6U3-GZmpG_X}mXBnmrz!}W2 zbCd7~t_Qe$%H>n82%MI31;J^{q}FTeOl@RrV_B}1z|Mm`*aMp~Y&6&u!S1trA@sei9EFL^yr`XX27_N=8R)%D3VbrFsD?@nM7!gu|pn$DW{? zHP8Hrp9bex{8Je{$exYovg2*M&wsPam>smDW-Bs1%ZEcaKMTQ^Fkut{E7jpUTv@Or z`1Yp()=>@_mw5C(p(I1@kqBol)>itD)OKo-LkcG$)&aAHN5YyR6{&@T*n9H6^K@-@ z?P2HTdgsAP=hcVZjmMow&v^!%n>5jHFEAF(Fn-smvx<_Gt)^2AyW6lDp_5l26h~sF zv&Eb7^8g_Q7#34cN;m=$Z>H&d47`^y4Bu{vbmWWQwEhkKStkrVi#X$pl2Idbf!D-nET@k*l6R1o7xqKuNhklU3cuAe>-6t|Vv9C+?CKb2&2YY4e$p8QV delta 648 zcmZ8dJ&V*(6wOQWl9$Y6W_QGo{eX2{MMfp~0~R}b(LxByBg}gl14-U+CxcA2&6YMp zS}PI6#%4?(c7qvcW{zelUEkZ5WXhElir&cmh zJTqCAP)xkv%U1j!_~L=Y>(OYiHkEpAheeXlPZ~kDW%FmPig~8 z7*NEi%*$5HYsl)n)ZkMInQMC!13I3VD$A#^O-eY`wcH3EMJ02!&J5BV z6Pwr0Q@)2eqq9Fw#Kzqw{l|-nCOrf&@ZN%bYP3sm^&D4$s?-N3AcVG7~9V zuU^jbY6=bouMl)+9soofq>s%L^@Yvp$_@q`3T~+nBBhWPk09)&m-S r(S OutputManager: """获取输出管理器""" if output_manager is None: raise RuntimeError("输出管理器未初始化") - return output_manager \ No newline at end of file + return output_manager + +def get_tweet_service(): + """获取文字内容服务""" + from api.services.tweet import TweetService + return TweetService(get_ai_agent(), get_config(), get_output_manager()) \ No newline at end of file diff --git a/api/routers/__pycache__/prompt.cpython-312.pyc b/api/routers/__pycache__/prompt.cpython-312.pyc index c344530155407e99e8a08afca2f1d6e7950a3a22..81afe5249010db7e27ba8824a0ae61039ce695eb 100644 GIT binary patch literal 8865 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 S3Sov7WVVT(&|sZxJO3BumrhIo literal 10282 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 diff --git a/api/routers/__pycache__/tweet.cpython-312.pyc b/api/routers/__pycache__/tweet.cpython-312.pyc index 43b84973edba7626481bd95b09a65b151b35363e..6c1922d0fd5c94dba4d089015e3f513f77278066 100644 GIT binary patch delta 3742 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 R+fhf$o^hTYo)dG7_`kWT*LeT{ diff --git a/api/routers/prompt.py b/api/routers/prompt.py index 5a83eac..5618937 100644 --- a/api/routers/prompt.py +++ b/api/routers/prompt.py @@ -6,171 +6,138 @@ """ import logging +from typing import Dict, Any, Optional from fastapi import APIRouter, Depends, HTTPException -from typing import List, Dict, Any +from pydantic import BaseModel, Field -from core.config import ConfigManager from api.services.prompt_service import PromptService from api.services.prompt_builder import PromptBuilderService -from api.models.prompt import ( - StyleRequest, StyleResponse, StyleListResponse, - AudienceRequest, AudienceResponse, AudienceListResponse, - ScenicSpotRequest, ScenicSpotResponse, ScenicSpotListResponse, - PromptBuilderRequest, PromptBuilderResponse -) - -# 从依赖注入模块导入依赖 -from api.dependencies import get_config +from api.dependencies import get_config, get_tweet_service logger = logging.getLogger(__name__) # 创建路由 -router = APIRouter() +router = APIRouter( + tags=["prompt"], + responses={404: {"description": "Not found"}}, +) # 依赖注入函数 -def get_prompt_service( - config_manager: ConfigManager = Depends(get_config) -) -> PromptService: +def get_prompt_service(): """获取提示词服务""" - return PromptService(config_manager) + from core.config import get_config_manager + return PromptService(get_config_manager()) -def get_prompt_builder( - config_manager: ConfigManager = Depends(get_config), - prompt_service: PromptService = Depends(get_prompt_service) -) -> PromptBuilderService: - """获取提示词构建服务""" +def get_prompt_builder(): + """获取提示词构建器服务""" + from core.config import get_config_manager + config_manager = get_config_manager() + prompt_service = PromptService(config_manager) return PromptBuilderService(config_manager, prompt_service) -@router.get("/styles", response_model=StyleListResponse) -async def get_all_styles( +# 请求和响应模型 +class PromptRequest(BaseModel): + """提示词请求模型""" + style: str = Field(..., description="内容风格") + audience: str = Field(..., description="目标受众") + + class Config: + schema_extra = { + "example": { + "style": "攻略风", + "audience": "亲子向" + } + } + + +class PromptResponse(BaseModel): + """提示词响应模型""" + style_content: str = Field(..., description="风格提示词") + audience_content: str = Field(..., description="受众提示词") + + class Config: + schema_extra = { + "example": { + "style_content": "以实用信息为主,包含详细的游玩路线...", + "audience_content": "家庭出游,有小孩同行,关注安全性..." + } + } + + +class PromptBuilderRequest(BaseModel): + """提示词构建器请求模型""" + topic: Dict[str, Any] = Field(..., description="选题信息") + step: Optional[str] = Field(None, description="步骤,如topic、content、judge等") + + class Config: + schema_extra = { + "example": { + "topic": { + "index": "1", + "date": "2023-07-15", + "object": "北京故宫", + "product": "故宫门票", + "style": "攻略风", + "target_audience": "亲子向", + "logic": "暑期旅游热门景点推荐" + }, + "step": "content" + } + } + + +class PromptBuilderResponse(BaseModel): + """提示词构建器响应模型""" + system_prompt: str = Field(..., description="系统提示词") + user_prompt: str = Field(..., description="用户提示词") + + class Config: + schema_extra = { + "example": { + "system_prompt": "你是一位专业的旅游内容创作者...", + "user_prompt": "请为北京故宫创作一篇旅游攻略..." + } + } + + +class GenerateContentResponse(BaseModel): + """生成内容响应模型""" + request_id: str = Field(..., description="请求ID") + topic_index: str = Field(..., description="选题索引") + content: Dict[str, Any] = Field(..., description="生成的内容") + + class Config: + schema_extra = { + "example": { + "request_id": "content_20230715_123456", + "topic_index": "1", + "content": { + "title": "【北京故宫】避开人潮的秘密路线,90%的人都不知道!", + "content": "故宫,作为中国最著名的文化遗产之一...", + "tag": ["北京旅游", "故宫", "旅游攻略", "避暑胜地"] + } + } + } + + +@router.post("/get-style-audience", response_model=PromptResponse) +async def get_style_audience( + request: PromptRequest, prompt_service: PromptService = Depends(get_prompt_service) ): - """获取所有内容风格""" + """获取风格和受众提示词""" try: - styles_dict = prompt_service.get_all_styles() - # 将字典列表转换为StyleResponse对象列表 - styles = [StyleResponse(name=style["name"], description=style["description"]) for style in styles_dict] - return StyleListResponse(styles=styles) - except Exception as e: - logger.error(f"获取所有风格失败: {e}") - raise HTTPException(status_code=500, detail=f"获取风格列表失败: {str(e)}") - - -@router.get("/styles/{style_name}", response_model=StyleResponse) -async def get_style( - style_name: str, - prompt_service: PromptService = Depends(get_prompt_service) -): - """获取指定内容风格""" - try: - content = prompt_service.get_style_content(style_name) - return StyleResponse(name=style_name, description=content) - except Exception as e: - logger.error(f"获取风格 '{style_name}' 失败: {e}") - raise HTTPException(status_code=404, detail=f"未找到风格: {style_name}") - - -@router.post("/styles", response_model=StyleResponse) -async def create_or_update_style( - style: StyleRequest, - prompt_service: PromptService = Depends(get_prompt_service) -): - """创建或更新内容风格""" - try: - if not style.description: - # 如果没有提供描述,则获取现有的 - content = prompt_service.get_style_content(style.name) - return StyleResponse(name=style.name, description=content) + style_content = prompt_service.get_style_content(request.style) + audience_content = prompt_service.get_audience_content(request.audience) - success = prompt_service.save_style(style.name, style.description) - if not success: - raise HTTPException(status_code=500, detail=f"保存风格 '{style.name}' 失败") - - return StyleResponse(name=style.name, description=style.description) + return PromptResponse( + style_content=style_content, + audience_content=audience_content + ) except Exception as e: - logger.error(f"保存风格 '{style.name}' 失败: {e}") - raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}") - - -@router.get("/audiences", response_model=AudienceListResponse) -async def get_all_audiences( - prompt_service: PromptService = Depends(get_prompt_service) -): - """获取所有目标受众""" - try: - audiences_dict = prompt_service.get_all_audiences() - # 将字典列表转换为AudienceResponse对象列表 - audiences = [AudienceResponse(name=audience["name"], description=audience["description"]) for audience in audiences_dict] - return AudienceListResponse(audiences=audiences) - except Exception as e: - logger.error(f"获取所有受众失败: {e}") - raise HTTPException(status_code=500, detail=f"获取受众列表失败: {str(e)}") - - -@router.get("/audiences/{audience_name}", response_model=AudienceResponse) -async def get_audience( - audience_name: str, - prompt_service: PromptService = Depends(get_prompt_service) -): - """获取指定目标受众""" - try: - content = prompt_service.get_audience_content(audience_name) - return AudienceResponse(name=audience_name, description=content) - except Exception as e: - logger.error(f"获取受众 '{audience_name}' 失败: {e}") - raise HTTPException(status_code=404, detail=f"未找到受众: {audience_name}") - - -@router.post("/audiences", response_model=AudienceResponse) -async def create_or_update_audience( - audience: AudienceRequest, - prompt_service: PromptService = Depends(get_prompt_service) -): - """创建或更新目标受众""" - try: - if not audience.description: - # 如果没有提供描述,则获取现有的 - content = prompt_service.get_audience_content(audience.name) - return AudienceResponse(name=audience.name, description=content) - - success = prompt_service.save_audience(audience.name, audience.description) - if not success: - raise HTTPException(status_code=500, detail=f"保存受众 '{audience.name}' 失败") - - return AudienceResponse(name=audience.name, description=audience.description) - except Exception as e: - logger.error(f"保存受众 '{audience.name}' 失败: {e}") - raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}") - - -@router.get("/scenic-spots", response_model=ScenicSpotListResponse) -async def get_all_scenic_spots( - prompt_service: PromptService = Depends(get_prompt_service) -): - """获取所有景区""" - try: - spots_dict = prompt_service.get_all_scenic_spots() - # 将字典列表转换为ScenicSpotResponse对象列表 - spots = [ScenicSpotResponse(name=spot["name"], description=spot["description"]) for spot in spots_dict] - return ScenicSpotListResponse(spots=spots) - except Exception as e: - logger.error(f"获取所有景区失败: {e}") - raise HTTPException(status_code=500, detail=f"获取景区列表失败: {str(e)}") - - -@router.get("/scenic-spots/{spot_name}", response_model=ScenicSpotResponse) -async def get_scenic_spot( - spot_name: str, - prompt_service: PromptService = Depends(get_prompt_service) -): - """获取指定景区信息""" - try: - content = prompt_service.get_scenic_spot_info(spot_name) - return ScenicSpotResponse(name=spot_name, description=content) - except Exception as e: - logger.error(f"获取景区 '{spot_name}' 失败: {e}") - raise HTTPException(status_code=404, detail=f"未找到景区: {spot_name}") + logger.error(f"获取提示词失败: {e}") + raise HTTPException(status_code=500, detail=f"获取提示词失败: {str(e)}") @router.post("/build-prompt", response_model=PromptBuilderResponse) @@ -204,4 +171,33 @@ async def build_prompt( ) except Exception as e: logger.error(f"构建提示词失败: {e}") - raise HTTPException(status_code=500, detail=f"构建提示词失败: {str(e)}") \ No newline at end of file + raise HTTPException(status_code=500, detail=f"构建提示词失败: {str(e)}") + + +@router.post("/generate-content", response_model=GenerateContentResponse) +async def generate_content( + request: PromptBuilderRequest, + prompt_builder: PromptBuilderService = Depends(get_prompt_builder), + tweet_service = Depends(get_tweet_service) +): + """使用构建的提示词生成内容""" + try: + # 构建提示词 + step = request.step or "content" + system_prompt, user_prompt = prompt_builder.build_content_prompt(request.topic, step) + + # 使用提示词生成内容 + request_id, topic_index, content = await tweet_service.generate_content_with_prompt( + topic=request.topic, + system_prompt=system_prompt, + user_prompt=user_prompt + ) + + return GenerateContentResponse( + request_id=request_id, + topic_index=topic_index, + content=content + ) + except Exception as e: + logger.error(f"生成内容失败: {e}") + raise HTTPException(status_code=500, detail=f"生成内容失败: {str(e)}") \ No newline at end of file diff --git a/api/routers/tweet.py b/api/routers/tweet.py index 2ef0b88..958f8e0 100644 --- a/api/routers/tweet.py +++ b/api/routers/tweet.py @@ -6,36 +6,51 @@ """ import logging +from typing import List, Dict, Any, Optional from fastapi import APIRouter, Depends, HTTPException -from typing import List, Dict, Any -from core.config import ConfigManager -from core.ai import AIAgent -from utils.file_io import OutputManager -from api.services.tweet import TweetService from api.models.tweet import ( TopicRequest, TopicResponse, - ContentRequest, ContentResponse, - JudgeRequest, JudgeResponse, + ContentRequest, ContentResponse, + JudgeRequest, JudgeResponse, PipelineRequest, PipelineResponse ) +from api.services.tweet import TweetService +from api.dependencies import get_tweet_service -# 从依赖注入模块导入依赖 -from api.dependencies import get_config, get_ai_agent, get_output_manager +# 创建一个新的模型用于接收预构建提示词的请求 +from pydantic import BaseModel, Field + +class ContentWithPromptRequest(BaseModel): + """带有预构建提示词的内容生成请求模型""" + topic: Dict[str, Any] = Field(..., description="选题信息") + system_prompt: str = Field(..., description="系统提示词") + user_prompt: str = Field(..., description="用户提示词") + + class Config: + schema_extra = { + "example": { + "topic": { + "index": "1", + "date": "2023-07-15", + "object": "北京故宫", + "product": "故宫门票", + "style": "旅游攻略", + "target_audience": "年轻人", + "logic": "暑期旅游热门景点推荐" + }, + "system_prompt": "你是一位专业的旅游内容创作者...", + "user_prompt": "请为以下景点创作一篇旅游文章..." + } + } logger = logging.getLogger(__name__) -# 创建路由 -router = APIRouter() - -# 依赖注入函数 -def get_tweet_service( - config_manager: ConfigManager = Depends(get_config), - ai_agent: AIAgent = Depends(get_ai_agent), - output_manager: OutputManager = Depends(get_output_manager) -) -> TweetService: - """获取文字内容服务""" - return TweetService(ai_agent, config_manager, output_manager) +router = APIRouter( + prefix="/tweet", + tags=["tweet"], + responses={404: {"description": "Not found"}}, +) @router.post("/topics", response_model=TopicResponse, summary="生成选题") @@ -93,6 +108,35 @@ async def generate_content( raise HTTPException(status_code=500, detail=f"生成内容失败: {str(e)}") +@router.post("/content-with-prompt", response_model=ContentResponse, summary="使用预构建提示词生成内容") +async def generate_content_with_prompt( + request: ContentWithPromptRequest, + tweet_service: TweetService = Depends(get_tweet_service) +): + """ + 使用预构建的提示词为选题生成内容 + + - **topic**: 选题信息 + - **system_prompt**: 系统提示词 + - **user_prompt**: 用户提示词 + """ + try: + request_id, topic_index, content = await tweet_service.generate_content_with_prompt( + topic=request.topic, + system_prompt=request.system_prompt, + user_prompt=request.user_prompt + ) + + return ContentResponse( + request_id=request_id, + topic_index=topic_index, + content=content + ) + except Exception as e: + logger.error(f"使用预构建提示词生成内容失败: {e}", exc_info=True) + raise HTTPException(status_code=500, detail=f"使用预构建提示词生成内容失败: {str(e)}") + + @router.post("/judge", response_model=JudgeResponse, summary="审核内容") async def judge_content( request: JudgeRequest, diff --git a/api/services/__pycache__/tweet.cpython-312.pyc b/api/services/__pycache__/tweet.cpython-312.pyc index c2007073250d7e23b89b1e38305a32073251749d..1529e19ce99d941fc05d5734a0ead487b796556e 100644 GIT binary patch delta 1124 zcmZ{ie{54#6vywq@3nO6`g85*()H&|pwcWg8h?!aU<0W?9G15a(K*WXXu5 z7RewRWSwjrC(S%dva)&NYqpMy;EijgMjq2xhiZ?sme+6zHrdLY!eE^}qZzdw)&?Be zY2jBre!|8~8}O6tDboUWtA^y^q$0;6Q#28qQdE5^Dbp2apU56J*l?OnT7p<)pICgH z1ER- z+};1LR@=ShY@uBEY&B%H3{-n+3?6vydg;B}tAWhte33Pp)*YuCd1JJLBekAm>D$?* zFHiobiPfx!x%~3%`^(oZcxfjO4%043UI&0=8US>vyp?;$UHWbFeFSG#9(mS+wnbpc}1dQL}5&(RSa_w&)nR?-;nVwKy_X+#CDR z5nr^%*1pWg!1G4j+b+(VdV<`cTe3SX&k3$g{5WOi2zr;k`n+^C zS1z#9l}qhjn4MjpRhK6J{ro2xskcn z+#BB*E2v2mD!x8ivj-+?cKWU2%#mXHcm<(e(nq-IC)>g7AVW28h&+a~VesC@!{AZ; zD)}ACRYKX4zX@ZB{oVRgAPU!4{~s&7O#oZ~`1-1@BbJa-lX4fGW`8|1Y*GmB{0#xC GLH__Q1yoP~ delta 430 zcmX>cdfSWdG%qg~0}%XZ$6M*3!g36@qG8>XY=M*DQI#R*-u^|=_BC;lq_-t61TXs zN>kEPQ{qz+OA?D*C+mnxF}hEdmy%~p-E1$_&CYKRRHVs#i%HMm7Gp_~ Tuple[str, str, Dict[str, Any]]: + """ + 使用预构建的提示词为选题生成内容 + + Args: + topic: 选题信息 + system_prompt: 系统提示词 + user_prompt: 用户提示词 + + Returns: + 请求ID、选题索引和生成的内容 + """ + topic_index = topic.get('index', 'unknown') + logger.info(f"开始使用预构建提示词为选题 {topic_index} 生成内容") + + # 使用预构建的提示词生成内容 + content = await self.content_generator.generate_content_with_prompt(topic, system_prompt, user_prompt) + + # 生成请求ID + request_id = f"content_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{str(uuid.uuid4())[:8]}" + + logger.info(f"内容生成完成,请求ID: {request_id}, 选题索引: {topic_index}") + return request_id, topic_index, content + async def judge_content(self, topic: Dict[str, Any], content: Dict[str, Any]) -> Tuple[str, str, Dict[str, Any], bool]: """ 审核内容