2025-07-10 17:51:37 +08:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
文字内容API路由
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import logging
|
2025-07-11 16:07:55 +08:00
|
|
|
|
from typing import List, Dict, Any, Optional
|
2025-07-10 17:51:37 +08:00
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
|
|
|
|
|
|
|
|
|
|
from api.models.tweet import (
|
|
|
|
|
|
TopicRequest, TopicResponse,
|
2025-07-11 16:07:55 +08:00
|
|
|
|
ContentRequest, ContentResponse,
|
|
|
|
|
|
JudgeRequest, JudgeResponse,
|
2025-07-10 17:51:37 +08:00
|
|
|
|
PipelineRequest, PipelineResponse
|
|
|
|
|
|
)
|
2025-07-11 16:07:55 +08:00
|
|
|
|
from api.services.tweet import TweetService
|
2025-07-14 17:46:20 +08:00
|
|
|
|
from api.services.database_service import DatabaseService
|
|
|
|
|
|
from api.dependencies import get_tweet_service, get_database_service
|
2025-07-10 17:51:37 +08:00
|
|
|
|
|
2025-07-11 16:07:55 +08:00
|
|
|
|
# 创建一个新的模型用于接收预构建提示词的请求
|
|
|
|
|
|
from pydantic import BaseModel, Field
|
2025-07-10 17:51:37 +08:00
|
|
|
|
|
2025-07-11 16:07:55 +08:00
|
|
|
|
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": "旅游攻略",
|
2025-07-15 15:47:47 +08:00
|
|
|
|
"targetAudience": "年轻人",
|
2025-07-11 16:07:55 +08:00
|
|
|
|
"logic": "暑期旅游热门景点推荐"
|
|
|
|
|
|
},
|
|
|
|
|
|
"system_prompt": "你是一位专业的旅游内容创作者...",
|
|
|
|
|
|
"user_prompt": "请为以下景点创作一篇旅游文章..."
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-10 17:51:37 +08:00
|
|
|
|
|
2025-07-11 16:07:55 +08:00
|
|
|
|
logger = logging.getLogger(__name__)
|
2025-07-10 17:51:37 +08:00
|
|
|
|
|
2025-07-11 16:07:55 +08:00
|
|
|
|
router = APIRouter(
|
|
|
|
|
|
tags=["tweet"],
|
|
|
|
|
|
responses={404: {"description": "Not found"}},
|
|
|
|
|
|
)
|
2025-07-10 17:51:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-16 16:38:38 +08:00
|
|
|
|
def _resolve_ids_to_names_with_mapping(db_service: DatabaseService,
|
|
|
|
|
|
styleIds: Optional[List[int]] = None,
|
|
|
|
|
|
audienceIds: Optional[List[int]] = None,
|
|
|
|
|
|
scenicSpotIds: Optional[List[int]] = None,
|
|
|
|
|
|
productIds: Optional[List[int]] = None) -> tuple:
|
2025-07-14 17:46:20 +08:00
|
|
|
|
"""
|
2025-07-16 16:38:38 +08:00
|
|
|
|
将ID列表转换为名称列表,并返回ID到名称的映射关系
|
2025-07-14 17:46:20 +08:00
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
db_service: 数据库服务
|
2025-07-15 10:59:36 +08:00
|
|
|
|
styleIds: 风格ID列表
|
|
|
|
|
|
audienceIds: 受众ID列表
|
|
|
|
|
|
scenicSpotIds: 景区ID列表
|
|
|
|
|
|
productIds: 产品ID列表
|
2025-07-14 17:46:20 +08:00
|
|
|
|
|
|
|
|
|
|
Returns:
|
2025-07-16 16:38:38 +08:00
|
|
|
|
(styles, audiences, scenic_spots, products, id_name_mappings) 名称列表和映射关系元组
|
2025-07-14 17:46:20 +08:00
|
|
|
|
"""
|
|
|
|
|
|
styles = []
|
|
|
|
|
|
audiences = []
|
|
|
|
|
|
scenic_spots = []
|
|
|
|
|
|
products = []
|
|
|
|
|
|
|
2025-07-16 16:38:38 +08:00
|
|
|
|
# 建立ID到名称的映射字典
|
|
|
|
|
|
id_name_mappings = {
|
|
|
|
|
|
'style_mapping': {}, # {name: id}
|
|
|
|
|
|
'audience_mapping': {}, # {name: id}
|
|
|
|
|
|
'scenic_spot_mapping': {}, # {name: id}
|
|
|
|
|
|
'product_mapping': {} # {name: id}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 17:46:20 +08:00
|
|
|
|
# 如果数据库服务不可用,返回空列表
|
|
|
|
|
|
if not db_service or not db_service.is_available():
|
|
|
|
|
|
logger.warning("数据库服务不可用,无法解析ID")
|
2025-07-16 16:38:38 +08:00
|
|
|
|
return styles, audiences, scenic_spots, products, id_name_mappings
|
2025-07-14 17:46:20 +08:00
|
|
|
|
|
|
|
|
|
|
# 解析风格ID
|
2025-07-15 10:59:36 +08:00
|
|
|
|
if styleIds:
|
|
|
|
|
|
style_records = db_service.get_styles_by_ids(styleIds)
|
2025-07-16 16:38:38 +08:00
|
|
|
|
for record in style_records:
|
|
|
|
|
|
style_name = record['styleName']
|
|
|
|
|
|
styles.append(style_name)
|
|
|
|
|
|
id_name_mappings['style_mapping'][style_name] = record['id']
|
2025-07-14 17:46:20 +08:00
|
|
|
|
|
|
|
|
|
|
# 解析受众ID
|
2025-07-15 10:59:36 +08:00
|
|
|
|
if audienceIds:
|
|
|
|
|
|
audience_records = db_service.get_audiences_by_ids(audienceIds)
|
2025-07-16 16:38:38 +08:00
|
|
|
|
for record in audience_records:
|
|
|
|
|
|
audience_name = record['audienceName']
|
|
|
|
|
|
audiences.append(audience_name)
|
|
|
|
|
|
id_name_mappings['audience_mapping'][audience_name] = record['id']
|
2025-07-14 17:46:20 +08:00
|
|
|
|
|
|
|
|
|
|
# 解析景区ID
|
2025-07-15 10:59:36 +08:00
|
|
|
|
if scenicSpotIds:
|
|
|
|
|
|
spot_records = db_service.get_scenic_spots_by_ids(scenicSpotIds)
|
2025-07-16 16:38:38 +08:00
|
|
|
|
for record in spot_records:
|
|
|
|
|
|
spot_name = record['name']
|
|
|
|
|
|
scenic_spots.append(spot_name)
|
|
|
|
|
|
id_name_mappings['scenic_spot_mapping'][spot_name] = record['id']
|
2025-07-14 17:46:20 +08:00
|
|
|
|
|
|
|
|
|
|
# 解析产品ID
|
2025-07-15 10:59:36 +08:00
|
|
|
|
if productIds:
|
|
|
|
|
|
product_records = db_service.get_products_by_ids(productIds)
|
2025-07-16 16:38:38 +08:00
|
|
|
|
for record in product_records:
|
2025-07-18 19:32:55 +08:00
|
|
|
|
product_name = record['productName'] # 修改这里,从name改为productName
|
2025-07-16 16:38:38 +08:00
|
|
|
|
products.append(product_name)
|
|
|
|
|
|
id_name_mappings['product_mapping'][product_name] = record['id']
|
2025-07-14 17:46:20 +08:00
|
|
|
|
|
2025-07-16 16:38:38 +08:00
|
|
|
|
return styles, audiences, scenic_spots, products, id_name_mappings
|
|
|
|
|
|
|
|
|
|
|
|
def _resolve_ids_to_names(db_service: DatabaseService,
|
|
|
|
|
|
styleIds: Optional[List[int]] = None,
|
|
|
|
|
|
audienceIds: Optional[List[int]] = None,
|
|
|
|
|
|
scenicSpotIds: Optional[List[int]] = None,
|
|
|
|
|
|
productIds: Optional[List[int]] = None) -> tuple:
|
|
|
|
|
|
"""
|
|
|
|
|
|
将ID列表转换为名称列表(保持向后兼容)
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
db_service: 数据库服务
|
|
|
|
|
|
styleIds: 风格ID列表
|
|
|
|
|
|
audienceIds: 受众ID列表
|
|
|
|
|
|
scenicSpotIds: 景区ID列表
|
|
|
|
|
|
productIds: 产品ID列表
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
(styles, audiences, scenic_spots, products) 名称列表元组
|
|
|
|
|
|
"""
|
|
|
|
|
|
styles, audiences, scenic_spots, products, _ = _resolve_ids_to_names_with_mapping(
|
|
|
|
|
|
db_service, styleIds, audienceIds, scenicSpotIds, productIds
|
|
|
|
|
|
)
|
2025-07-14 17:46:20 +08:00
|
|
|
|
return styles, audiences, scenic_spots, products
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-16 16:38:38 +08:00
|
|
|
|
def _add_ids_to_topics(topics: List[Dict[str, Any]], id_name_mappings: Dict[str, Dict[str, int]]) -> List[Dict[str, Any]]:
|
|
|
|
|
|
"""
|
|
|
|
|
|
为每个topic添加对应的ID字段
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
topics: 生成的选题列表
|
|
|
|
|
|
id_name_mappings: 名称到ID的映射字典
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
包含ID字段的选题列表
|
|
|
|
|
|
"""
|
|
|
|
|
|
enriched_topics = []
|
|
|
|
|
|
|
|
|
|
|
|
for topic in topics:
|
|
|
|
|
|
# 复制原topic
|
|
|
|
|
|
enriched_topic = topic.copy()
|
|
|
|
|
|
|
|
|
|
|
|
# 添加ID字段
|
|
|
|
|
|
enriched_topic['styleIds'] = []
|
|
|
|
|
|
enriched_topic['audienceIds'] = []
|
|
|
|
|
|
enriched_topic['scenicSpotIds'] = []
|
|
|
|
|
|
enriched_topic['productIds'] = []
|
|
|
|
|
|
|
|
|
|
|
|
# 根据topic中的name查找对应的ID
|
|
|
|
|
|
if 'style' in topic and topic['style']:
|
|
|
|
|
|
style_name = topic['style']
|
|
|
|
|
|
if style_name in id_name_mappings['style_mapping']:
|
|
|
|
|
|
enriched_topic['styleIds'] = [id_name_mappings['style_mapping'][style_name]]
|
|
|
|
|
|
|
|
|
|
|
|
if 'targetAudience' in topic and topic['targetAudience']:
|
|
|
|
|
|
audience_name = topic['targetAudience']
|
|
|
|
|
|
if audience_name in id_name_mappings['audience_mapping']:
|
|
|
|
|
|
enriched_topic['audienceIds'] = [id_name_mappings['audience_mapping'][audience_name]]
|
|
|
|
|
|
|
|
|
|
|
|
if 'object' in topic and topic['object']:
|
|
|
|
|
|
spot_name = topic['object']
|
|
|
|
|
|
if spot_name in id_name_mappings['scenic_spot_mapping']:
|
|
|
|
|
|
enriched_topic['scenicSpotIds'] = [id_name_mappings['scenic_spot_mapping'][spot_name]]
|
|
|
|
|
|
|
|
|
|
|
|
if 'product' in topic and topic['product']:
|
|
|
|
|
|
product_name = topic['product']
|
|
|
|
|
|
if product_name in id_name_mappings['product_mapping']:
|
|
|
|
|
|
enriched_topic['productIds'] = [id_name_mappings['product_mapping'][product_name]]
|
|
|
|
|
|
|
|
|
|
|
|
enriched_topics.append(enriched_topic)
|
|
|
|
|
|
|
|
|
|
|
|
return enriched_topics
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
@router.post("/topics", response_model=TopicResponse, summary="生成选题")
|
|
|
|
|
|
async def generate_topics(
|
|
|
|
|
|
request: TopicRequest,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
tweet_service: TweetService = Depends(get_tweet_service),
|
|
|
|
|
|
db_service: DatabaseService = Depends(get_database_service)
|
2025-07-10 17:51:37 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
生成选题
|
|
|
|
|
|
|
2025-07-11 17:39:51 +08:00
|
|
|
|
- **dates**: 日期字符串,可能为单个日期、多个日期用逗号分隔或范围
|
2025-07-15 10:59:36 +08:00
|
|
|
|
- **numTopics**: 要生成的选题数量
|
|
|
|
|
|
- **styleIds**: 风格ID列表
|
|
|
|
|
|
- **audienceIds**: 受众ID列表
|
|
|
|
|
|
- **scenicSpotIds**: 景区ID列表
|
|
|
|
|
|
- **productIds**: 产品ID列表
|
2025-07-10 17:51:37 +08:00
|
|
|
|
"""
|
|
|
|
|
|
try:
|
2025-07-16 16:38:38 +08:00
|
|
|
|
# 将ID转换为名称,并获取映射关系
|
|
|
|
|
|
styles, audiences, scenic_spots, products, id_name_mappings = _resolve_ids_to_names_with_mapping(
|
2025-07-14 17:46:20 +08:00
|
|
|
|
db_service,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
request.styleIds,
|
|
|
|
|
|
request.audienceIds,
|
|
|
|
|
|
request.scenicSpotIds,
|
|
|
|
|
|
request.productIds
|
2025-07-14 17:46:20 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
request_id, topics = await tweet_service.generate_topics(
|
2025-07-11 17:39:51 +08:00
|
|
|
|
dates=request.dates,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
numTopics=request.numTopics,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
styles=styles,
|
|
|
|
|
|
audiences=audiences,
|
|
|
|
|
|
scenic_spots=scenic_spots,
|
|
|
|
|
|
products=products
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-16 16:38:38 +08:00
|
|
|
|
# 为topics添加ID字段
|
|
|
|
|
|
enriched_topics = _add_ids_to_topics(topics, id_name_mappings)
|
|
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
return TopicResponse(
|
2025-07-15 10:59:36 +08:00
|
|
|
|
requestId=request_id,
|
2025-07-16 16:38:38 +08:00
|
|
|
|
topics=enriched_topics
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"生成选题失败: {e}", exc_info=True)
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"生成选题失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/content", response_model=ContentResponse, summary="生成内容")
|
|
|
|
|
|
async def generate_content(
|
|
|
|
|
|
request: ContentRequest,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
tweet_service: TweetService = Depends(get_tweet_service),
|
|
|
|
|
|
db_service: DatabaseService = Depends(get_database_service)
|
2025-07-10 17:51:37 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""
|
2025-07-11 17:55:29 +08:00
|
|
|
|
生成内容
|
2025-07-10 17:51:37 +08:00
|
|
|
|
|
|
|
|
|
|
- **topic**: 选题信息
|
2025-07-15 10:59:36 +08:00
|
|
|
|
- **styleIds**: 风格ID列表
|
|
|
|
|
|
- **audienceIds**: 受众ID列表
|
|
|
|
|
|
- **scenicSpotIds**: 景区ID列表
|
|
|
|
|
|
- **productIds**: 产品ID列表
|
2025-07-15 11:03:24 +08:00
|
|
|
|
- **autoJudge**: 是否自动进行内容审核
|
2025-07-10 17:51:37 +08:00
|
|
|
|
"""
|
|
|
|
|
|
try:
|
2025-07-14 17:46:20 +08:00
|
|
|
|
# 将ID转换为名称
|
|
|
|
|
|
styles, audiences, scenic_spots, products = _resolve_ids_to_names(
|
|
|
|
|
|
db_service,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
request.styleIds,
|
|
|
|
|
|
request.audienceIds,
|
|
|
|
|
|
request.scenicSpotIds,
|
|
|
|
|
|
request.productIds
|
2025-07-14 17:46:20 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
request_id, topic_index, content = await tweet_service.generate_content(
|
2025-07-11 17:55:29 +08:00
|
|
|
|
topic=request.topic,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
styles=styles,
|
|
|
|
|
|
audiences=audiences,
|
|
|
|
|
|
scenic_spots=scenic_spots,
|
|
|
|
|
|
products=products,
|
2025-07-15 11:03:24 +08:00
|
|
|
|
autoJudge=request.autoJudge
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-16 18:24:17 +08:00
|
|
|
|
# 提取judgeSuccess字段,从content中移除以避免重复
|
|
|
|
|
|
judge_success = None
|
|
|
|
|
|
if isinstance(content, dict) and 'judgeSuccess' in content:
|
|
|
|
|
|
judge_success = content.pop('judgeSuccess')
|
2025-07-14 13:41:43 +08:00
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
return ContentResponse(
|
2025-07-15 10:59:36 +08:00
|
|
|
|
requestId=request_id,
|
|
|
|
|
|
topicIndex=topic_index,
|
2025-07-14 13:41:43 +08:00
|
|
|
|
content=content,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
judgeSuccess=judge_success
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"生成内容失败: {e}", exc_info=True)
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"生成内容失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-11 16:07:55 +08:00
|
|
|
|
@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(
|
2025-07-15 10:59:36 +08:00
|
|
|
|
requestId=request_id,
|
|
|
|
|
|
topicIndex=topic_index,
|
2025-07-14 13:41:43 +08:00
|
|
|
|
content=content,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
judgeSuccess=None
|
2025-07-11 16:07:55 +08:00
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"使用预构建提示词生成内容失败: {e}", exc_info=True)
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"使用预构建提示词生成内容失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
@router.post("/judge", response_model=JudgeResponse, summary="审核内容")
|
|
|
|
|
|
async def judge_content(
|
|
|
|
|
|
request: JudgeRequest,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
tweet_service: TweetService = Depends(get_tweet_service),
|
|
|
|
|
|
db_service: DatabaseService = Depends(get_database_service)
|
2025-07-10 17:51:37 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
审核内容
|
|
|
|
|
|
|
|
|
|
|
|
- **topic**: 选题信息
|
|
|
|
|
|
- **content**: 要审核的内容
|
2025-07-15 10:59:36 +08:00
|
|
|
|
- **styleIds**: 风格ID列表
|
|
|
|
|
|
- **audienceIds**: 受众ID列表
|
|
|
|
|
|
- **scenicSpotIds**: 景区ID列表
|
|
|
|
|
|
- **productIds**: 产品ID列表
|
2025-07-10 17:51:37 +08:00
|
|
|
|
"""
|
|
|
|
|
|
try:
|
2025-07-14 17:46:20 +08:00
|
|
|
|
# 将ID转换为名称
|
|
|
|
|
|
styles, audiences, scenic_spots, products = _resolve_ids_to_names(
|
|
|
|
|
|
db_service,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
request.styleIds,
|
|
|
|
|
|
request.audienceIds,
|
|
|
|
|
|
request.scenicSpotIds,
|
|
|
|
|
|
request.productIds
|
2025-07-14 17:46:20 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
request_id, topic_index, judged_content, judge_success = await tweet_service.judge_content(
|
|
|
|
|
|
topic=request.topic,
|
2025-07-11 17:55:29 +08:00
|
|
|
|
content=request.content,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
styles=styles,
|
|
|
|
|
|
audiences=audiences,
|
|
|
|
|
|
scenic_spots=scenic_spots,
|
|
|
|
|
|
products=products
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return JudgeResponse(
|
2025-07-15 10:59:36 +08:00
|
|
|
|
requestId=request_id,
|
|
|
|
|
|
topicIndex=topic_index,
|
2025-07-14 13:41:43 +08:00
|
|
|
|
content=judged_content,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
judgeSuccess=judge_success
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"审核内容失败: {e}", exc_info=True)
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"审核内容失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/pipeline", response_model=PipelineResponse, summary="运行完整流水线")
|
|
|
|
|
|
async def run_pipeline(
|
|
|
|
|
|
request: PipelineRequest,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
tweet_service: TweetService = Depends(get_tweet_service),
|
|
|
|
|
|
db_service: DatabaseService = Depends(get_database_service)
|
2025-07-10 17:51:37 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""
|
2025-07-11 17:55:29 +08:00
|
|
|
|
运行完整流水线:生成选题 → 生成内容 → 审核内容
|
2025-07-10 17:51:37 +08:00
|
|
|
|
|
2025-07-11 17:55:29 +08:00
|
|
|
|
- **dates**: 日期范围
|
2025-07-15 10:59:36 +08:00
|
|
|
|
- **numTopics**: 要生成的选题数量
|
|
|
|
|
|
- **styleIds**: 风格ID列表
|
|
|
|
|
|
- **audienceIds**: 受众ID列表
|
|
|
|
|
|
- **scenicSpotIds**: 景区ID列表
|
|
|
|
|
|
- **productIds**: 产品ID列表
|
2025-07-10 17:51:37 +08:00
|
|
|
|
- **skip_judge**: 是否跳过内容审核步骤
|
2025-07-15 11:03:24 +08:00
|
|
|
|
- **autoJudge**: 是否在内容生成时进行内嵌审核
|
2025-07-10 17:51:37 +08:00
|
|
|
|
"""
|
|
|
|
|
|
try:
|
2025-07-14 17:46:20 +08:00
|
|
|
|
# 将ID转换为名称
|
|
|
|
|
|
styles, audiences, scenic_spots, products = _resolve_ids_to_names(
|
|
|
|
|
|
db_service,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
request.styleIds,
|
|
|
|
|
|
request.audienceIds,
|
|
|
|
|
|
request.scenicSpotIds,
|
|
|
|
|
|
request.productIds
|
2025-07-14 17:46:20 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-10 17:51:37 +08:00
|
|
|
|
request_id, topics, contents, judged_contents = await tweet_service.run_pipeline(
|
2025-07-11 17:39:51 +08:00
|
|
|
|
dates=request.dates,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
numTopics=request.numTopics,
|
2025-07-14 17:46:20 +08:00
|
|
|
|
styles=styles,
|
|
|
|
|
|
audiences=audiences,
|
|
|
|
|
|
scenic_spots=scenic_spots,
|
|
|
|
|
|
products=products,
|
2025-07-15 17:18:46 +08:00
|
|
|
|
skipJudge=request.skipJudge,
|
2025-07-15 11:03:24 +08:00
|
|
|
|
autoJudge=request.autoJudge
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return PipelineResponse(
|
2025-07-15 10:59:36 +08:00
|
|
|
|
requestId=request_id,
|
2025-07-10 17:51:37 +08:00
|
|
|
|
topics=topics,
|
|
|
|
|
|
contents=contents,
|
2025-07-15 10:59:36 +08:00
|
|
|
|
judgedContents=judged_contents
|
2025-07-10 17:51:37 +08:00
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"运行流水线失败: {e}", exc_info=True)
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"运行流水线失败: {str(e)}")
|