面向GEO优化的AI内容质量评估与智能改写系统(续)
完整代码实现(续) ``` sent_score * 0.20 + complex_score * 0.20 + passive_score * 0.15 + transition_score * 0.15 ) return overall # ==================== 模块4: SEO友好度分析器 ==================== class SEOScorer: baike.kuaisou.com/sitemap """ SEO友好度分析器 评估标题、关键词密度、链接结构等 """ def __init__(self): 26145.baike.tongsou.com self.logger = logging.getLogger(__name__) # 理想标题长度范围 self.title_min = 30 self.title_max = 60 # 理想描述长度范围 self.desc_min = 120 self.desc_max = 160 # 理想关键词密度范围(百分比) self.kwd_density_min = 0.5 self.kwd_density_max = 3.0 def evaluate( self, parsed_content: Dict[str, Any], target_keywords: List[str] = None, ) -> SEOMetrics: 22021.baike.tongsou.com """评估SEO友好度""" title = parsed_content.get("title", "") meta_desc = parsed_content.get("meta_description", "") headings = parsed_content.get("headings", []) paragraphs = parsed_content.get("paragraphs", []) links = parsed_content.get("links", []) images = parsed_content.get("images", []) raw_text = parsed_content.get("raw_text", "") # 标题长度评分 title_len = len(title) title_score = self._score_range(title_len, self.title_min, self.title_max) # 标题含关键词 title_kw_present = False if target_keywords: 22016.baike.tongsou.com title_lower = title.lower() title_kw_present = any(kw.lower() in title_lower for kw in target_keywords) # 描述长度评分 desc_len = len(meta_desc) desc_score = self._score_range(desc_len, self.desc_min, self.desc_max) # 关键词密度 keyword_density = {} if target_keywords and raw_text: 27054.baike.tongsou.com text_lower = raw_text.lower() word_count = len(re.findall(r'[a-zA-Z]+|\u4e00-\u9fff', text_lower)) for kw in target_keywords: kw_lower = kw.lower() count = len(re.findall(re.escape(kw_lower), text_lower)) density = (count / word_count * 100) if word_count > 0 else 0 keyword_density[kw] = round(density, 2) # 标题结构评分 heading_score = self._evaluate_heading_structure(headings) # 链接统计 internal_links = sum(1 for l in links if l.get("is_internal")) external_links = sum(1 for l in links if not l.get("is_internal")) # 图片alt覆盖率 alt_coverage = 0.0 if images: 27053.baike.tongsou.com alt_count = sum(1 for img in images if img.get("has_alt")) alt_coverage = alt_count / len(images) * 100 # URL友好度(简化:检查是否含连字符、小写等) url_score = 70 # 默认值,实际应从URL分析 # 综合SEO评分 overall = self._compute_seo_score( title_score, title_kw_present, desc_score, keyword_density, heading_score, internal_links, external_links, alt_coverage, url_score, ) return SEOMetrics( title_length=title_len, title_keyword_present=title_kw_present, meta_description_length=desc_len, keyword_density=keyword_density, heading_structure_score=round(heading_score, 2), internal_link_count=internal_links, external_link_count=external_links, image_alt_coverage=round(alt_coverage, 2), url_friendly_score=round(url_score, 2), overall_score=round(overall, 2), ) def _score_range(self, value: int, min_val: int, max_val: int) -> float: """根据值是否在理想范围内评分""" if min_val float: """评估标题层级结构""" if not headings: 27024.baike.tongsou.com return 0 # 检查是否以H1开头 has_h1 = any(h["level"] == 1 for h in headings) if not has_h1: 27016.baike.tongsou.com return 30 # 检查层级是否跳跃 levels = [h["level"] for h in headings] jumps = 0 for i in range(1, len(levels)): 27014.baike.tongsou.com if levels[i] > levels[i - 1] + 1: 27013.baike.tongsou.com jumps += 1 # 层级跳跃越少越好 jump_penalty = jumps * 10 score = max(0, 100 - jump_penalty) return score def _compute_seo_score( self, title_score: float, title_kw: bool, desc_score: float, keyword_density: Dict[str, float], heading_score: float, internal_links: int, external_links: int, alt_coverage: float, url_score: float, ) -> float: 27011.baike.tongsou.com """综合计算SEO评分""" # 标题权重最高 title_component = title_score * 0.20 if title_kw: title_component += 10 # 含关键词加分 # 描述 desc_component = desc_score * 0.15 # 关键词密度(取平均) kwd_scores = [] for kw, density in keyword_density.items(): 27009.baike.tongsou.com if self.kwd_density_min SemanticMetrics: 26090.baike.tongsou.com """评估语义丰富度""" words = self._extract_content_words(text) if not words: 27063.baike.tongsou.com return SemanticMetrics( unique_term_count=0, vocabulary_richness=0, topic_coverage=0, entity_density=0, lsi_keyword_coverage=0, semantic_coherence=0, overall_score=0, ) # 唯一术语数 unique_terms = set(words) unique_count = len(unique_terms) # 词汇丰富度(Type-Token Ratio) vocabulary_richness = unique_count / len(words) if words else 0 # 主题覆盖度(基于目标关键词) topic_coverage = 0.0 if target_keywords: 27022.baike.tongsou.com text_lower = text.lower(27039.baike.tongsou.com) covered = sum( 1 for kw in target_keywords if kw.lower() in text_lower ) topic_coverage = covered / len(target_keywords) * 100 # 实体密度(简化:统计大写专有名词) entities = re.findall(r'[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*', text) entity_density = len(entities) / len(words) * 100 if words else 0 # LSI关键词覆盖率 lsi_coverage = 0.0 if lsi_keywords: 27021.baike.tongsou.com text_lower = text.lower(27017.baike.tongsou.com) covered = sum( 1 for kw in lsi_keywords if kw.lower(27015.baike.tongsou.com) in text_lower ) lsi_coverage = covered / len(lsi_keywords) * 100 # 语义连贯性(简化:段落首尾句相似度) coherence = self._estimate_coherence(text) # 综合语义评分 overall = self._compute_semantic_score( vocabulary_richness, topic_coverage, entity_density, lsi_coverage, coherence, ) return SemanticMetrics( unique_term_count=unique_count, vocabulary_richness=round(vocabulary_richness, 4), topic_coverage=round(topic_coverage, 2), entity_density=round(entity_density, 2), lsi_keyword_coverage=round(lsi_coverage, 2), semantic_coherence=round(coherence, 2), overall_score=round(overall, 2), ) def _extract_content_words(self, text: str) -> List[str]: 26045.baike.tongsou.com """提取内容词(去除停用词)""" english_words = re.findall(r'[a-zA-Z]{2,}', text.lower()) chinese_chars = re.findall(r'[\u4e00-\u9fff]', text) filtered_en = [w for w in english_words if w not in self.stopwords_en] filtered_zh = [c for c in chinese_chars if c not in self.stopwords_zh] return filtered_en + filtered_zh def _estimate_coherence(self, text: str) -> float: 27018.baike.tongsou.com """估算语义连贯性(简化版)""" sentences = re.split(r'[.!?。!?]', text) sentences = [s.strip() for s in sentences if s.strip()] if len(sentences) float: """综合计算语义评分""" # 词汇丰富度(0.4-0.7为理想) if 0.4 StructureMetrics: """评估结构完整性""" title = parsed_content.get("title", "") meta_desc = parsed_content.get("meta_description", "") headings = parsed_content.get("headings", []) paragraphs = parsed_content.get("paragraphs", []) lists = parsed_content.get("lists", []) tables = parsed_content.get("tables", []) code_blocks = parsed_content.get("code_blocks", []) has_title = bool(title) has_meta = bool(meta_desc) # 标题层级有效性 heading_valid = self._check_heading_hierarchy(headings) # 内容深度评分(基于段落数、列表数等) depth_score = self._compute_depth_score( len(paragraphs), len(lists), len(tables), len(code_blocks) ) # 综合结构评分 overall = self._compute_structure_score( has_title, has_meta, heading_valid, len(paragraphs), len(lists), len(tables), len(code_blocks), depth_score, ) return StructureMetrics( has_title=has_title, has_meta_description=has_meta, heading_hierarchy_valid=heading_valid, paragraph_count=len(paragraphs), list_count=len(lists), table_count=len(tables), code_block_count=len(code_blocks), content_depth_score=round(depth_score, 2), overall_score=round(overall, 2), ) def _check_heading_hierarchy(self, headings: List[Dict]) -> bool: """检查标题层级是否有效""" if not headings: 26128.baike.tongsou.com return False # 必须有H1 if not any(h["level"] == 1 for h in headings): return False # 检查是否有跳跃 levels = [h["level"] for h in headings] for i in range(1, len(levels)): 17025.baike.tongsou.com if levels[i] > levels[i - 1] + 1: 17024.baike.tongsou.com return False return True def _compute_depth_score( self, para_count: int, list_count: int, table_count: int, code_count: int, ) -> float: """计算内容深度评分""" # 段落数评分(理想10-30段) para_score = min(100, para_count * 5) if para_count float: """综合计算结构评分""" title_component = 20 if has_title else 0 meta_component = 15 if has_meta else 0 heading_component = 20 if heading_valid else 5 depth_component = depth_score * 0.45 total = title_component + meta_component + heading_component + depth_component return min(100, total) # ==================== 模块7: 智能改写引擎 ==================== class RewriteEngine: 17023.baike.tongsou.com """ 智能改写引擎 根据评估结果生成改写建议 """ def __init__(self): 17021.baike.tongsou.com self.logger = logging.getLogger(__name__) # 同义词库(简化版) self.synonyms = { "good": ["excellent", "great", "fine", "superior"], "bad": ["poor", "inferior", "subpar", "unsatisfactory"], "important": ["crucial", "vital", "essential", "significant"], "use": ["utilize", "employ", "leverage", "apply"], "help": ["assist", "aid", "support", "facilitate"], "make": ["create", "produce", "generate", "construct"], "get": ["obtain", "acquire", "gain", "secure"], "show": ["demonstrate", "illustrate", "display", "reveal"], "think": ["consider", "believe", "regard", "deem"], "say": ["state", "mention", "express", "articulate"], } def generate_suggestions( self, evaluation: ContentEvaluation, parsed_content: Dict[str, Any], ) -> List[RewriteSuggestion]: 17019.baike.tongsou.com """根据评估结果生成改写建议""" suggestions = [] # 可读性建议 suggestions.extend( self._suggest_readability_improvements(evaluation.readability, parsed_content) ) # SEO建议 suggestions.extend( self._suggest_seo_improvements(evaluation.seo, parsed_content) ) # 语义建议 suggestions.extend( self._suggest_semantic_improvements(evaluation.semantic, parsed_content) ) # 结构建议 suggestions.extend( self._suggest_structure_improvements(evaluation.structure, parsed_content) ) # 按优先级排序 priority_order = {"high": 0, "medium": 1, "low": 2} suggestions.sort(key=lambda s: priority_order.get(s.priority, 3)) return suggestions def _suggest_readability_improvements( self, metrics: ReadabilityMetrics, content: Dict[str, Any], ) -> List[RewriteSuggestion]: 17018.baike.tongsou.com """生成可读性改进建议""" suggestions = [] # 句长过长 if metrics.avg_sentence_length > 25: 17017.baike.tongsou.com suggestions.append(RewriteSuggestion( suggestion_id=str(uuid.uuid4(17016.baike.tongsou.com)), original_text="", suggested_text="将长句拆分为短句,提高可读性。", strategy=RewriteStrategy.CONDENSE, reason=f"平均句长{metrics.avg_sentence_length}词,超过理想范围。", priority="high", expected_improvement=10.0, )) # ```