#!/usr/bin/env python # -*- coding: utf-8 -*- """ Gemini 地下室方案 #1 替代版: 用 GitHub Models (免费) 替代 Google Cloud NLP 做实体显著性检测 GitHub Models 免费模型: gpt-4o-mini, Phi-4, Llama-3.3-70B 等 用法: python nlp_content_audit.py article.html --targets "Gold" "XAUUSD" "position sizing" """ import sys, io, os, re, json, urllib.request sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') # GitHub Models free endpoint (via GitHub Marketplace) # 优先读环境变量,再读项目 .env config sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')) from config import GITHUB_TOKEN as _CFG_TOKEN GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN') or _CFG_TOKEN or '' if not GITHUB_TOKEN: print("❌ 未找到 GITHUB_TOKEN。请在 .env 中设置或设置环境变量") sys.exit(1) MODEL = 'gpt-4o-mini' # Free tier on GitHub Models ENDPOINT = 'https://models.inference.ai.azure.com/chat/completions' def analyze_entities_with_llm(text, target_entities=None): """用 LLM 做实体显著性分析 — 替代 Google Cloud NLP""" prompt = f"""You are a search engine content quality auditor. Analyze this trading/finance article and: 1. Extract the TOP 10 entities (people, concepts, instruments, strategies) mentioned. 2. Rate each entity's SALIENCE (prominence) from 0.0 to 1.0 based on: - 1.0 = THE main topic, appears in title and first sentence, discussed throughout - 0.5 = Mentioned several times but not central - 0.1 = Passing mention only 3. If the first paragraph doesn't directly state the main topic within 15 words, flag it. 4. Score overall content focus: A (laser-focused), B (mostly focused), C (scattered), D (all over the place). Text to analyze: --- {text[:3000]} --- Respond in JSON format: {{"entities": [{{"name": "...", "salience": 0.X, "type": "..."}}], "focus_grade": "A/B/C/D", "first_paragraph_issue": true/false, "issues": ["..."]}}""" payload = json.dumps({ "model": MODEL, "messages": [{"role": "user", "content": prompt}], "temperature": 0.1, "max_tokens": 1000 }) req = urllib.request.Request(ENDPOINT, data=payload.encode(), headers={ 'Content-Type': 'application/json', 'Authorization': f'Bearer {GITHUB_TOKEN}', 'User-Agent': 'GFIL-NLP-Audit/1.0' }) try: with urllib.request.urlopen(req, timeout=30) as resp: result = json.loads(resp.read().decode()) content = result['choices'][0]['message']['content'] # Extract JSON from response json_match = re.search(r'\{[\s\S]*\}', content) if json_match: return json.loads(json_match.group()) return {"error": "Could not parse LLM response", "raw": content[:500]} except Exception as e: return {"error": str(e)} def audit_html_file(filepath, target_entities=None): """分析 HTML 文件文本""" with open(filepath, 'r', encoding='utf-8') as f: html = f.read() title = re.search(r'(.*?)', html) h1 = re.search(r'

(.*?)

', html) body = re.sub(r'<[^>]+>', ' ', html) body = re.sub(r'\s+', ' ', body).strip() title_text = title.group(1) if title else '' h1_text = h1.group(1) if h1 else '' print(f"文件: {os.path.basename(filepath)}") print(f"标题: {title_text[:100]}") print(f"H1: {h1_text[:100]}") print(f"分析中...") text = f"{title_text}\n{h1_text}\n{body[:2500]}" result = analyze_entities_with_llm(text, target_entities) if 'error' in result: print(f"\n❌ 分析失败: {result['error']}") return print(f"\n=== 内容质量审计 ===") print(f"集中度评分: {result.get('focus_grade', 'N/A')}") if result.get('first_paragraph_issue'): print(f"⚠️ 第一段问题: 主题不够突出(前15字未点题)") print(f"\n=== 实体显著性 Top 10 ===") print(f"{'实体':<30} {'显著性':>8} {'类型':<15}") print("-" * 60) for e in result.get('entities', [])[:10]: bar = '█' * int(e['salience'] * 50) print(f"{e['name']:<30} {e['salience']:.3f} {e.get('type', ''):<15}") if target_entities: print(f"\n=== 目标实体检测 ===") entity_names = {e['name'].lower(): e for e in result.get('entities', [])} for t in target_entities: found = None for name, e in entity_names.items(): if t.lower() in name: found = e break if found: ok = '✅ 达标' if found['salience'] >= 0.8 else '❌ 不够(需≥0.8)' print(f" {t}: 显著度 {found['salience']:.3f} {ok}") else: print(f" {t}: ❌ 未找到! 需在标题或第一段加入") if result.get('issues'): print(f"\n=== 发现的问题 ===") for issue in result['issues']: print(f" - {issue}") if __name__ == '__main__': import argparse p = argparse.ArgumentParser(description='GitHub Models 免费实体审计 (替代Google NLP)') p.add_argument('file', help='HTML 文件路径') p.add_argument('--targets', nargs='+', help='目标实体: --targets Gold XAUUSD "position sizing"') args = p.parse_args() if '1234567890' in GITHUB_TOKEN: print("❌ 请设置 GITHUB_TOKEN 环境变量 (你的 GitHub Personal Access Token)") print(" $env:GITHUB_TOKEN='github_pat_xxxx' # PowerShell") sys.exit(1) audit_html_file(args.file, args.targets)