180 lines
7.0 KiB
Python
180 lines
7.0 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
|
|||
|
|
"""
|
|||
|
|
文字内容服务层
|
|||
|
|
封装现有功能,提供API调用
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
import uuid
|
|||
|
|
from typing import List, Dict, Any, Optional, Tuple
|
|||
|
|
from datetime import datetime
|
|||
|
|
|
|||
|
|
from core.config import ConfigManager, GenerateTopicConfig, GenerateContentConfig
|
|||
|
|
from core.ai import AIAgent
|
|||
|
|
from utils.file_io import OutputManager
|
|||
|
|
from tweet.topic_generator import TopicGenerator
|
|||
|
|
from tweet.content_generator import ContentGenerator
|
|||
|
|
from tweet.content_judger import ContentJudger
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TweetService:
|
|||
|
|
"""文字内容服务类"""
|
|||
|
|
|
|||
|
|
def __init__(self, ai_agent: AIAgent, config_manager: ConfigManager, output_manager: OutputManager):
|
|||
|
|
"""
|
|||
|
|
初始化文字内容服务
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
ai_agent: AI代理
|
|||
|
|
config_manager: 配置管理器
|
|||
|
|
output_manager: 输出管理器
|
|||
|
|
"""
|
|||
|
|
self.ai_agent = ai_agent
|
|||
|
|
self.config_manager = config_manager
|
|||
|
|
self.output_manager = output_manager
|
|||
|
|
|
|||
|
|
# 初始化各个组件
|
|||
|
|
self.topic_generator = TopicGenerator(ai_agent, config_manager, output_manager)
|
|||
|
|
self.content_generator = ContentGenerator(ai_agent, config_manager, output_manager)
|
|||
|
|
self.content_judger = ContentJudger(ai_agent, config_manager, output_manager)
|
|||
|
|
|
|||
|
|
async def generate_topics(self, date: str, num_topics: int = 5,
|
|||
|
|
style: Optional[str] = None,
|
|||
|
|
target_audience: Optional[str] = None) -> Tuple[str, List[Dict[str, Any]]]:
|
|||
|
|
"""
|
|||
|
|
生成选题
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
date: 选题日期,格式为YYYY-MM-DD
|
|||
|
|
num_topics: 要生成的选题数量
|
|||
|
|
style: 内容风格
|
|||
|
|
target_audience: 目标受众
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
请求ID和生成的选题列表
|
|||
|
|
"""
|
|||
|
|
logger.info(f"开始生成选题,日期: {date}, 数量: {num_topics}")
|
|||
|
|
|
|||
|
|
# 获取并更新配置
|
|||
|
|
topic_config = self.config_manager.get_config('topic_gen', GenerateTopicConfig)
|
|||
|
|
topic_config.topic.date = date
|
|||
|
|
topic_config.topic.num = num_topics
|
|||
|
|
|
|||
|
|
# 生成选题
|
|||
|
|
topics = await self.topic_generator.generate_topics()
|
|||
|
|
if not topics:
|
|||
|
|
logger.error("未能生成任何选题")
|
|||
|
|
return str(uuid.uuid4()), []
|
|||
|
|
|
|||
|
|
# 生成请求ID
|
|||
|
|
request_id = f"topic_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{str(uuid.uuid4())[:8]}"
|
|||
|
|
|
|||
|
|
logger.info(f"选题生成完成,请求ID: {request_id}, 数量: {len(topics)}")
|
|||
|
|
return request_id, topics
|
|||
|
|
|
|||
|
|
async def generate_content(self, topic: Dict[str, Any]) -> Tuple[str, str, Dict[str, Any]]:
|
|||
|
|
"""
|
|||
|
|
为选题生成内容
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
topic: 选题信息
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
请求ID、选题索引和生成的内容
|
|||
|
|
"""
|
|||
|
|
topic_index = topic.get('index', 'unknown')
|
|||
|
|
logger.info(f"开始为选题 {topic_index} 生成内容")
|
|||
|
|
|
|||
|
|
# 生成内容
|
|||
|
|
content = await self.content_generator.generate_content_for_topic(topic)
|
|||
|
|
|
|||
|
|
# 生成请求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]:
|
|||
|
|
"""
|
|||
|
|
审核内容
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
topic: 选题信息
|
|||
|
|
content: 要审核的内容
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
请求ID、选题索引、审核后的内容和审核是否成功
|
|||
|
|
"""
|
|||
|
|
topic_index = topic.get('index', 'unknown')
|
|||
|
|
logger.info(f"开始审核选题 {topic_index} 的内容")
|
|||
|
|
|
|||
|
|
# 审核内容
|
|||
|
|
judged_data = await self.content_judger.judge_content(content, topic)
|
|||
|
|
judge_success = judged_data.get('judge_success', False)
|
|||
|
|
|
|||
|
|
# 生成请求ID
|
|||
|
|
request_id = f"judge_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{str(uuid.uuid4())[:8]}"
|
|||
|
|
|
|||
|
|
logger.info(f"内容审核完成,请求ID: {request_id}, 选题索引: {topic_index}, 审核结果: {judge_success}")
|
|||
|
|
return request_id, topic_index, judged_data, judge_success
|
|||
|
|
|
|||
|
|
async def run_pipeline(self, date: str, num_topics: int = 5,
|
|||
|
|
style: Optional[str] = None,
|
|||
|
|
target_audience: Optional[str] = None,
|
|||
|
|
skip_judge: bool = False) -> Tuple[str, List[Dict[str, Any]], Dict[str, Dict[str, Any]], Dict[str, Dict[str, Any]]]:
|
|||
|
|
"""
|
|||
|
|
运行完整流水线
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
date: 选题日期,格式为YYYY-MM-DD
|
|||
|
|
num_topics: 要生成的选题数量
|
|||
|
|
style: 内容风格
|
|||
|
|
target_audience: 目标受众
|
|||
|
|
skip_judge: 是否跳过内容审核步骤
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
请求ID、生成的选题列表、生成的内容和审核后的内容
|
|||
|
|
"""
|
|||
|
|
logger.info(f"开始运行完整流水线,日期: {date}, 数量: {num_topics}")
|
|||
|
|
|
|||
|
|
# 生成请求ID
|
|||
|
|
request_id = f"pipeline_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{str(uuid.uuid4())[:8]}"
|
|||
|
|
|
|||
|
|
# 步骤1: 生成选题
|
|||
|
|
_, topics = await self.generate_topics(date, num_topics, style, target_audience)
|
|||
|
|
if not topics:
|
|||
|
|
logger.error("未能生成任何选题,流程终止")
|
|||
|
|
return request_id, [], {}, {}
|
|||
|
|
|
|||
|
|
# 步骤2: 为每个选题生成内容
|
|||
|
|
contents = {}
|
|||
|
|
for topic in topics:
|
|||
|
|
topic_index = topic.get('index', 'unknown')
|
|||
|
|
content = await self.content_generator.generate_content_for_topic(topic)
|
|||
|
|
contents[topic_index] = content
|
|||
|
|
|
|||
|
|
# 如果跳过审核,直接返回结果
|
|||
|
|
if skip_judge:
|
|||
|
|
logger.info(f"跳过内容审核步骤,流水线完成,请求ID: {request_id}")
|
|||
|
|
return request_id, topics, contents, contents
|
|||
|
|
|
|||
|
|
# 步骤3: 审核内容
|
|||
|
|
judged_contents = {}
|
|||
|
|
for topic_index, content in contents.items():
|
|||
|
|
topic = next((t for t in topics if t.get('index') == topic_index), None)
|
|||
|
|
if not topic:
|
|||
|
|
logger.warning(f"找不到选题 {topic_index} 的原始数据,跳过审核")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
judged_data = await self.content_judger.judge_content(content, topic)
|
|||
|
|
judged_contents[topic_index] = judged_data
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.critical(f"为选题 {topic_index} 处理内容审核时发生意外错误: {e}", exc_info=True)
|
|||
|
|
|
|||
|
|
logger.info(f"流水线完成,请求ID: {request_id}")
|
|||
|
|
return request_id, topics, contents, judged_contents
|