147 lines
4.2 KiB
Python
147 lines
4.2 KiB
Python
"""
|
||
GLM AI 服务
|
||
使用智谱 GLM 生成标题和标签
|
||
"""
|
||
|
||
import json
|
||
import re
|
||
from loguru import logger
|
||
from zai import ZhipuAiClient
|
||
|
||
from app.core.config import settings
|
||
|
||
|
||
class GLMService:
|
||
"""GLM AI 服务"""
|
||
|
||
def __init__(self):
|
||
self.client = None
|
||
|
||
def _get_client(self):
|
||
"""获取或创建 ZhipuAI 客户端"""
|
||
if self.client is None:
|
||
if not settings.GLM_API_KEY:
|
||
raise Exception("GLM_API_KEY 未配置")
|
||
self.client = ZhipuAiClient(api_key=settings.GLM_API_KEY)
|
||
return self.client
|
||
|
||
async def generate_title_tags(self, text: str) -> dict:
|
||
"""
|
||
根据口播文案生成标题和标签
|
||
|
||
Args:
|
||
text: 口播文案
|
||
|
||
Returns:
|
||
{"title": "标题", "tags": ["标签1", "标签2", ...]}
|
||
"""
|
||
prompt = f"""根据以下口播文案,生成一个吸引人的短视频标题和3个相关标签。
|
||
|
||
口播文案:
|
||
{text}
|
||
|
||
要求:
|
||
1. 标题要简洁有力,能吸引观众点击,不超过10个字
|
||
2. 标签要与内容相关,便于搜索和推荐,只要3个
|
||
|
||
请严格按以下JSON格式返回(不要包含其他内容):
|
||
{{"title": "标题", "tags": ["标签1", "标签2", "标签3"]}}"""
|
||
|
||
try:
|
||
client = self._get_client()
|
||
logger.info(f"Calling GLM API with model: {settings.GLM_MODEL}")
|
||
|
||
response = client.chat.completions.create(
|
||
model=settings.GLM_MODEL,
|
||
messages=[{"role": "user", "content": prompt}],
|
||
thinking={"type": "disabled"}, # 禁用思考模式,加快响应
|
||
max_tokens=500,
|
||
temperature=0.7
|
||
)
|
||
|
||
# 提取生成的内容
|
||
content = response.choices[0].message.content
|
||
logger.info(f"GLM response (model: {settings.GLM_MODEL}): {content}")
|
||
|
||
# 解析 JSON
|
||
result = self._parse_json_response(content)
|
||
return result
|
||
|
||
except Exception as e:
|
||
logger.error(f"GLM service error: {e}")
|
||
raise Exception(f"AI 生成失败: {str(e)}")
|
||
|
||
async def rewrite_script(self, text: str) -> str:
|
||
"""
|
||
AI 洗稿(文案改写)
|
||
|
||
Args:
|
||
text: 原始文案
|
||
|
||
Returns:
|
||
改写后的文案
|
||
"""
|
||
prompt = f"""请将以下视频文案进行改写。
|
||
|
||
原始文案:
|
||
{text}
|
||
|
||
要求:
|
||
1. 保持原意,但语气更加自然流畅
|
||
2. 适合口播,读起来朗朗上口
|
||
3. 字数与原文相当或略微精简
|
||
4. 不要返回多余的解释,只返回改写后的正文"""
|
||
|
||
try:
|
||
client = self._get_client()
|
||
logger.info(f"Using GLM to rewrite script")
|
||
|
||
response = client.chat.completions.create(
|
||
model=settings.GLM_MODEL,
|
||
messages=[{"role": "user", "content": prompt}],
|
||
thinking={"type": "disabled"},
|
||
max_tokens=2000,
|
||
temperature=0.8
|
||
)
|
||
|
||
content = response.choices[0].message.content
|
||
logger.info("GLM rewrite completed")
|
||
return content.strip()
|
||
|
||
except Exception as e:
|
||
logger.error(f"GLM rewrite error: {e}")
|
||
raise Exception(f"AI 改写失败: {str(e)}")
|
||
|
||
|
||
|
||
def _parse_json_response(self, content: str) -> dict:
|
||
"""解析 GLM 返回的 JSON 内容"""
|
||
# 尝试直接解析
|
||
try:
|
||
return json.loads(content)
|
||
except json.JSONDecodeError:
|
||
pass
|
||
|
||
# 尝试提取 JSON 块
|
||
json_match = re.search(r'\{[^{}]*"title"[^{}]*"tags"[^{}]*\}', content, re.DOTALL)
|
||
if json_match:
|
||
try:
|
||
return json.loads(json_match.group())
|
||
except json.JSONDecodeError:
|
||
pass
|
||
|
||
# 尝试提取 ```json 代码块
|
||
code_match = re.search(r'```(?:json)?\s*(\{.*?\})\s*```', content, re.DOTALL)
|
||
if code_match:
|
||
try:
|
||
return json.loads(code_match.group(1))
|
||
except json.JSONDecodeError:
|
||
pass
|
||
|
||
logger.error(f"Failed to parse GLM response: {content}")
|
||
raise Exception("AI 返回格式解析失败")
|
||
|
||
|
||
# 全局服务实例
|
||
glm_service = GLMService()
|