xhs_factory/llm_service.py
zhoujie d27ffe94f4 feat(automation): 新增无人值守自动化运营模块
- 新增完整的自动化运营模块,包含一键评论、一键发布和定时调度功能
- 【一键评论】自动搜索高赞笔记,AI分析内容并生成个性化评论进行引流
- 【一键发布】随机选择主题和风格,AI生成文案,SD生成图片并自动发布到小红书
- 【定时调度】支持随机时间间隔的自动评论和发布,模拟真人操作节奏降低风险
- 新增自动化日志系统,实时记录操作状态和结果
- 在UI中新增“自动运营”标签页,提供完整的配置和操作界面

📝 docs(prompts): 优化SD提示词生成模板

- 更新文案生成提示词,适配JuggernautXL模型并优化质量描述
- 新增详细的质量词、光影、风格、构图和细节要求
- 移除括号权重语法,改为英文逗号分隔的描述方式
- 优化反向提示词,针对SDXL模型进行适配和增强

🔧 chore(config): 更新安全令牌配置

- 更新config.json中的xsec_token为新的安全令牌值

️ perf(sd): 优化Stable Diffusion服务参数

- 增加SD服务超时时间至900秒,适应高质量图片生成
- 优化文生图和图生图的默认参数,适配JuggernautXL模型
- 新增采样器和调度器参数配置,提升图片生成质量
- 优化默认反向提示词,针对SDXL模型进行专门优化
2026-02-08 22:23:25 +08:00

245 lines
9.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
LLM 服务模块
封装对 OpenAI 兼容 API 的调用,包含文案生成、热点分析、评论回复等 Prompt
"""
import requests
import json
import re
import logging
logger = logging.getLogger(__name__)
# ================= Prompt 模板 =================
PROMPT_COPYWRITING = """
你是一个小红书爆款内容专家。请根据用户主题生成内容。
【标题规则】(严格执行)
1. 长度限制:必须控制在 18 字以内含Emoji绝对不能超过 20 字!
2. 格式要求Emoji + 爆点关键词 + 核心痛点。
3. 禁忌:禁止使用"第一""""顶级"等绝对化广告法违禁词。
4. 风格:二极管标题(震惊/后悔/必看/避雷/哭了),具有强烈的点击欲望。
【正文规则】:
1. 口语化多用Emoji分段清晰不堆砌长句。
2. 正文控制在 600 字以内(小红书限制 1000 字)。
3. 结尾必须有 5 个以上相关话题标签(#)。
【绘图 Prompt】
生成对应的 Stable Diffusion 英文提示词,适配 JuggernautXL 模型,强调:
- 质量词masterpiece, best quality, ultra detailed, 8k uhd, high resolution
- 光影natural lighting, soft shadows, studio lighting, golden hour 等(根据场景选择)
- 风格photorealistic, cinematic, editorial photography, ins style
- 构图dynamic angle, depth of field, bokeh 等
- 细节detailed skin texture, sharp focus, vivid colors
注意:不要使用括号权重语法,直接用英文逗号分隔描述。
返回 JSON 格式:
{"title": "...", "content": "...", "sd_prompt": "...", "tags": ["标签1", "标签2", ...]}
"""
PROMPT_HOTSPOT_ANALYSIS = """
你是一个小红书运营数据分析专家。下面是搜索到的热门笔记信息:
{feed_data}
请分析这些热门笔记,总结以下内容:
1. **热门选题方向**:提炼 3-5 个最火的细分选题
2. **标题套路**:总结高赞标题的共同特征和写作模板
3. **内容结构**:分析爆款笔记的内容组织方式
4. **推荐模仿方案**:基于分析结果,给出 3 个具体的模仿选题建议
返回 JSON 格式:
{{"hot_topics": ["...", "..."], "title_patterns": ["...", "..."], "content_structure": "...", "suggestions": [{{"topic": "...", "reason": "..."}}]}}
"""
PROMPT_COMMENT_REPLY = """
你是一个小红书博主,人设为:{persona}
有人在你的笔记下评论了,请你用符合人设的口吻回复。
【规则】:
1. 回复简洁,控制在 50 字以内
2. 语气亲切自然,像和朋友聊天
3. 适当加入 1-2 个 Emoji
4. 如果是质疑,礼貌回应;如果是夸奖,真诚感谢
笔记标题:{post_title}
用户评论:{comment}
直接返回回复内容,不需要 JSON 格式。
"""
PROMPT_PROACTIVE_COMMENT = """
你是一个小红书活跃用户,人设为:{persona}
你正在浏览一篇笔记,想要留下一条真诚、有价值的评论,以提升互动和曝光。
【笔记信息】:
标题:{post_title}
正文摘要:{post_content}
【已有评论参考(可能为空)】:
{existing_comments}
【评论规则】:
1. 评论简洁自然,控制在 30-80 字,不要像机器人
2. 体现你对笔记内容的真实感受或个人经验
3. 可以提问、分享类似经历、或表达共鸣
4. 适当加入 1-2 个 Emoji不要过多
5. 不要重复已有评论的观点,找新角度
6. 不要生硬带货或自我推广
7. 语气因内容而异:教程类→请教/补充;种草类→分享体验;生活类→表达共鸣
直接返回评论内容,不需要 JSON 格式。
"""
PROMPT_COPY_WITH_REFERENCE = """
你是一个小红书爆款内容专家。参考以下热门笔记的风格和结构,创作全新原创内容。
【参考笔记】:
{reference_notes}
【创作主题】:{topic}
【风格要求】:{style}
【标题规则】:
1. 长度限制:必须控制在 18 字以内含Emoji绝对不能超过 20 字!
2. 借鉴参考笔记的标题套路但内容必须原创。
【正文规则】:
1. 口语化多用Emoji分段清晰。
2. 正文控制在 600 字以内。
3. 结尾有 5 个以上话题标签(#)。
【绘图 Prompt】
生成 Stable Diffusion 英文提示词,适配 JuggernautXL 模型:
- 必含质量词masterpiece, best quality, ultra detailed, 8k uhd
- 风格photorealistic, cinematic, editorial photography
- 光影和细节natural lighting, sharp focus, vivid colors, detailed skin texture
- 用英文逗号分隔,不用括号权重语法。
返回 JSON 格式:
{{"title": "...", "content": "...", "sd_prompt": "...", "tags": ["标签1", "标签2", ...]}}
"""
class LLMService:
"""LLM API 服务封装"""
def __init__(self, api_key: str, base_url: str, model: str = "gpt-3.5-turbo"):
self.api_key = api_key
self.base_url = base_url.rstrip("/")
self.model = model
def _chat(self, system_prompt: str, user_message: str,
json_mode: bool = True, temperature: float = 0.8) -> str:
"""底层聊天接口"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
}
if json_mode:
user_message = user_message + "\n请以json格式返回。"
payload = {
"model": self.model,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_message},
],
"temperature": temperature,
}
if json_mode:
payload["response_format"] = {"type": "json_object"}
try:
resp = requests.post(
f"{self.base_url}/chat/completions",
headers=headers, json=payload, timeout=90
)
resp.raise_for_status()
content = resp.json()["choices"][0]["message"]["content"]
return content
except requests.exceptions.Timeout:
raise TimeoutError("LLM 请求超时,请检查网络或换一个模型")
except requests.exceptions.HTTPError as e:
raise ConnectionError(f"LLM API 错误 ({resp.status_code}): {resp.text[:200]}")
except Exception as e:
raise RuntimeError(f"LLM 调用异常: {e}")
def _parse_json(self, text: str) -> dict:
"""从 LLM 返回文本中解析 JSON"""
cleaned = re.sub(r"```json\s*|```", "", text).strip()
return json.loads(cleaned)
# ---------- 业务方法 ----------
def get_models(self) -> list[str]:
"""获取可用模型列表"""
url = f"{self.base_url}/models"
headers = {"Authorization": f"Bearer {self.api_key}"}
try:
resp = requests.get(url, headers=headers, timeout=10)
resp.raise_for_status()
text = resp.text.strip()
if not text:
logger.warning("GET %s 返回空响应", url)
return []
data = resp.json()
return [item["id"] for item in data.get("data", [])]
except Exception as e:
logger.warning("获取模型列表失败 (%s): %s", url, e)
return []
def generate_copy(self, topic: str, style: str) -> dict:
"""生成小红书文案"""
content = self._chat(
PROMPT_COPYWRITING,
f"主题:{topic}\n风格:{style}"
)
data = self._parse_json(content)
# 强制标题长度限制
title = data.get("title", "")
if len(title) > 20:
title = title[:20]
data["title"] = title
return data
def generate_copy_with_reference(self, topic: str, style: str,
reference_notes: str) -> dict:
"""参考热门笔记生成文案"""
prompt = PROMPT_COPY_WITH_REFERENCE.format(
reference_notes=reference_notes, topic=topic, style=style
)
content = self._chat(prompt, f"请创作关于「{topic}」的小红书笔记")
data = self._parse_json(content)
title = data.get("title", "")
if len(title) > 20:
data["title"] = title[:20]
return data
def analyze_hotspots(self, feed_data: str) -> dict:
"""分析热门内容趋势"""
prompt = PROMPT_HOTSPOT_ANALYSIS.format(feed_data=feed_data)
content = self._chat(prompt, "请分析以上热门笔记数据")
return self._parse_json(content)
def generate_reply(self, persona: str, post_title: str, comment: str) -> str:
"""AI 生成评论回复"""
prompt = PROMPT_COMMENT_REPLY.format(
persona=persona, post_title=post_title, comment=comment
)
return self._chat(prompt, "请生成回复", json_mode=False, temperature=0.9).strip()
def generate_proactive_comment(self, persona: str, post_title: str,
post_content: str, existing_comments: str = "") -> str:
"""AI 生成主动评论"""
prompt = PROMPT_PROACTIVE_COMMENT.format(
persona=persona, post_title=post_title,
post_content=post_content,
existing_comments=existing_comments or "暂无评论",
)
return self._chat(prompt, "请生成评论", json_mode=False, temperature=0.9).strip()