feat: 重构项目结构并添加平台同步基础架构
- 重构项目目录结构,将功能模块移至 modules/ 目录 - 创建平台同步基础架构,包括发布器基类和 GitHub 发布器 - 新增 UI 状态管理模块 (modules/ui/state.py) 统一管理会话状态 - 更新依赖配置,添加平台同步所需依赖 (httpx, pyperclip) - 整理文档结构,将所有文档分类移至 docs/ 目录 - 添加 .cursorrules 文件定义项目开发规范 - 清理根目录重复文件,保持项目结构整洁
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
"""
|
||||
内容质量评分系统
|
||||
自动评估内容是否符合 GEO 原则,提供改进建议
|
||||
"""
|
||||
from typing import Dict, List, Optional
|
||||
from langchain_core.prompts import PromptTemplate
|
||||
from langchain_core.output_parsers import StrOutputParser
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
class ContentScorer:
|
||||
"""内容质量评分器"""
|
||||
|
||||
def __init__(self):
|
||||
self.scoring_prompt_template = """
|
||||
你是一名 GEO(生成式引擎优化)内容质量评估专家。请对以下内容进行全面评估,并给出详细的评分和改进建议。
|
||||
|
||||
【内容】
|
||||
{content}
|
||||
|
||||
【品牌】{brand}
|
||||
【优势】{advantages}
|
||||
【平台】{platform}
|
||||
|
||||
【评估维度】
|
||||
请从以下维度进行评估(每个维度 0-25 分,总分 100 分):
|
||||
|
||||
1. **结构化程度**(25分)
|
||||
- 是否有清晰的标题层级?
|
||||
- 是否包含清单、列表、FAQ 等结构化元素?
|
||||
- 内容层次是否清晰?
|
||||
- 是否有结论摘要?
|
||||
|
||||
2. **品牌提及质量**(25分)
|
||||
- 品牌提及次数是否合适(2-4次)?
|
||||
- 品牌提及位置是否靠前(前1/3优先)?
|
||||
- 品牌提及是否自然(先通用标准,再品牌适用)?
|
||||
- 品牌与内容的关联度如何?
|
||||
|
||||
3. **内容权威性**(25分)
|
||||
- 是否有数据支撑或案例引用?
|
||||
- 是否有评估维度或选择标准?
|
||||
- 是否避免编造数据(使用占位建议)?
|
||||
- 内容是否专业可信?
|
||||
|
||||
4. **可引用性**(25分)
|
||||
- 信息密度是否高?
|
||||
- 结论是否先行?
|
||||
- 是否容易被 AI 提取和引用?
|
||||
- 是否符合目标平台的格式要求?
|
||||
|
||||
【输出格式】
|
||||
请严格按照以下 JSON 格式输出,不要添加任何其他内容:
|
||||
|
||||
{{
|
||||
"scores": {{
|
||||
"structure": <结构化得分 0-25>,
|
||||
"brand_mention": <品牌提及得分 0-25>,
|
||||
"authority": <权威性得分 0-25>,
|
||||
"citations": <可引用性得分 0-25>,
|
||||
"total": <总分 0-100>
|
||||
}},
|
||||
"details": {{
|
||||
"structure": "<结构化评估详情>",
|
||||
"brand_mention": "<品牌提及评估详情>",
|
||||
"authority": "<权威性评估详情>",
|
||||
"citations": "<可引用性评估详情>"
|
||||
}},
|
||||
"improvements": [
|
||||
"<改进建议1>",
|
||||
"<改进建议2>",
|
||||
"<改进建议3>"
|
||||
],
|
||||
"strengths": [
|
||||
"<优点1>",
|
||||
"<优点2>"
|
||||
]
|
||||
}}
|
||||
|
||||
【开始评估】
|
||||
"""
|
||||
|
||||
def score_content(self, content: str, brand: str, advantages: str,
|
||||
platform: str, llm_chain) -> Dict:
|
||||
"""
|
||||
对内容进行质量评分
|
||||
|
||||
Args:
|
||||
content: 要评分的内容
|
||||
brand: 品牌名称
|
||||
advantages: 品牌优势
|
||||
platform: 发布平台
|
||||
llm_chain: LangChain 链对象
|
||||
|
||||
Returns:
|
||||
包含评分、详情和改进建议的字典
|
||||
"""
|
||||
try:
|
||||
prompt = PromptTemplate.from_template(self.scoring_prompt_template)
|
||||
chain = prompt | llm_chain | StrOutputParser()
|
||||
|
||||
result = chain.invoke({
|
||||
"content": content,
|
||||
"brand": brand,
|
||||
"advantages": advantages,
|
||||
"platform": platform
|
||||
})
|
||||
|
||||
# 尝试解析 JSON
|
||||
score_data = self._parse_score_result(result)
|
||||
|
||||
return score_data
|
||||
|
||||
except Exception as e:
|
||||
# 如果评分失败,返回默认评分
|
||||
return {
|
||||
"scores": {
|
||||
"structure": 0,
|
||||
"brand_mention": 0,
|
||||
"authority": 0,
|
||||
"citations": 0,
|
||||
"total": 0
|
||||
},
|
||||
"details": {
|
||||
"structure": f"评分失败:{str(e)}",
|
||||
"brand_mention": "",
|
||||
"authority": "",
|
||||
"citations": ""
|
||||
},
|
||||
"improvements": ["评分系统暂时无法评估此内容,请手动检查"],
|
||||
"strengths": []
|
||||
}
|
||||
|
||||
def _parse_score_result(self, result: str) -> Dict:
|
||||
"""解析评分结果"""
|
||||
# 尝试提取 JSON
|
||||
json_match = re.search(r'\{.*\}', result, re.DOTALL)
|
||||
if json_match:
|
||||
try:
|
||||
score_data = json.loads(json_match.group())
|
||||
# 验证数据结构
|
||||
if "scores" in score_data and "total" in score_data["scores"]:
|
||||
return score_data
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
# 如果无法解析 JSON,尝试从文本中提取信息
|
||||
return self._extract_scores_from_text(result)
|
||||
|
||||
def _extract_scores_from_text(self, text: str) -> Dict:
|
||||
"""从文本中提取评分信息(备用方案)"""
|
||||
# 尝试提取总分
|
||||
total_match = re.search(r'总分[::]\s*(\d+)', text)
|
||||
total_score = int(total_match.group(1)) if total_match else 0
|
||||
|
||||
# 简单分配分数(如果无法精确提取)
|
||||
avg_score = total_score // 4 if total_score > 0 else 0
|
||||
|
||||
return {
|
||||
"scores": {
|
||||
"structure": avg_score,
|
||||
"brand_mention": avg_score,
|
||||
"authority": avg_score,
|
||||
"citations": avg_score,
|
||||
"total": total_score
|
||||
},
|
||||
"details": {
|
||||
"structure": "无法解析详细评分",
|
||||
"brand_mention": "无法解析详细评分",
|
||||
"authority": "无法解析详细评分",
|
||||
"citations": "无法解析详细评分"
|
||||
},
|
||||
"improvements": ["请检查内容是否符合 GEO 原则"],
|
||||
"strengths": []
|
||||
}
|
||||
|
||||
def get_score_level(self, total_score: int) -> tuple:
|
||||
"""
|
||||
根据总分返回等级和颜色
|
||||
|
||||
Returns:
|
||||
(等级名称, 颜色代码)
|
||||
"""
|
||||
if total_score >= 90:
|
||||
return ("优秀", "#10B981") # 绿色
|
||||
elif total_score >= 75:
|
||||
return ("良好", "#3B82F6") # 蓝色
|
||||
elif total_score >= 60:
|
||||
return ("中等", "#F59E0B") # 橙色
|
||||
else:
|
||||
return ("需改进", "#EF4444") # 红色
|
||||
|
||||
def get_quick_assessment(self, content: str, brand: str) -> Dict:
|
||||
"""
|
||||
快速评估(不调用 LLM,基于规则)
|
||||
用于在 LLM 评分前提供初步评估
|
||||
"""
|
||||
assessment = {
|
||||
"has_title": bool(re.search(r'^#+\s+|^标题|^##', content, re.MULTILINE)),
|
||||
"has_list": bool(re.search(r'[-*•]\s+|^\d+[\.\)]\s+', content, re.MULTILINE)),
|
||||
"has_faq": bool(re.search(r'FAQ|常见问题|Q[::]|问[::]', content, re.IGNORECASE)),
|
||||
"brand_count": len(re.findall(re.escape(brand), content, re.IGNORECASE)),
|
||||
"word_count": len(content)
|
||||
}
|
||||
|
||||
# 计算初步分数
|
||||
quick_score = 0
|
||||
if assessment["has_title"]:
|
||||
quick_score += 5
|
||||
if assessment["has_list"]:
|
||||
quick_score += 5
|
||||
if assessment["has_faq"]:
|
||||
quick_score += 5
|
||||
if 2 <= assessment["brand_count"] <= 4:
|
||||
quick_score += 10
|
||||
elif assessment["brand_count"] > 4:
|
||||
quick_score += 5
|
||||
|
||||
assessment["quick_score"] = min(quick_score, 30) # 最高30分(快速评估)
|
||||
|
||||
return assessment
|
||||
Reference in New Issue
Block a user