geo/backend/app/services/content/seo_optimizer.py

118 lines
3.6 KiB
Python

"""SEO优化服务"""
from dataclasses import dataclass
from typing import Optional
from app.services.distribution.platform_rules import PLATFORM_RULES
@dataclass
class OptimizationResult:
"""SEO优化结果"""
optimized_content: str
density: float
suggestions: list
tips: list
class SEOOptimizer:
"""SEO优化器"""
def get_keyword_density(self, content: str, keyword: str) -> float:
"""计算关键词密度
Args:
content: 内容文本
keyword: 关键词
Returns:
关键词密度百分比
"""
if not keyword or not content:
return 0.0
content_len = len(content)
keyword_count = content.count(keyword)
# 密度 = (关键词字符数 * 出现次数) / 总字符数 * 100
density = (len(keyword) * keyword_count) / content_len * 100
return round(density, 2)
def optimize(
self,
content: str,
title: str,
platform: str,
keyword: str = ""
) -> OptimizationResult:
"""优化内容SEO
Args:
content: 内容文本
title: 标题
platform: 平台标识
keyword: 关键词
Returns:
OptimizationResult: 优化结果
"""
rules = PLATFORM_RULES.get(platform, {})
seo_rules = rules.get("seo_rules", {})
suggestions = []
tips = []
optimized = content
# 获取推荐密度配置
density_config = seo_rules.get("keyword_density", {"min": 1, "max": 3, "recommended": 2})
min_density = density_config["min"]
max_density = density_config["max"]
recommended = density_config["recommended"]
# 关键词位置
keyword_positions = seo_rules.get("keyword_position", ["title", "first_para"])
# 计算当前密度
if keyword:
current_density = self.get_keyword_density(content, keyword)
# 密度调整建议
if current_density < min_density:
suggestions.append(
f"关键词密度 {current_density}% 低于最低要求 {min_density}%,建议增加关键词出现次数"
)
elif current_density > max_density:
suggestions.append(
f"关键词密度 {current_density}% 超过最高限制 {max_density}%,建议减少关键词堆砌"
)
else:
suggestions.append(f"关键词密度 {current_density}% 在推荐范围内")
# 关键词位置检查
keyword_in_title = keyword in title if title else False
keyword_in_first = keyword in content[:100] if content else False
if "title" in keyword_positions and not keyword_in_title:
suggestions.append(f"建议在标题中包含关键词「{keyword}")
if "first_para" in keyword_positions and not keyword_in_first:
suggestions.append(f"建议在前100字中包含关键词「{keyword}")
tips.extend(rules.get("seo_tips", []))
return OptimizationResult(
optimized_content=optimized,
density=current_density,
suggestions=suggestions,
tips=tips
)
else:
# 无关键词时返回SEO建议
tips.extend(rules.get("seo_tips", []))
return OptimizationResult(
optimized_content=optimized,
density=0.0,
suggestions=["请指定要优化的关键词"],
tips=tips
)