Phase 0-2: Schema cleanup, typed relations, event-driven automation
- Phase 0: AGENTS.md cleanup (dedup quotes, renumber sections, merge qmd) - Phase 1: typed relations (manage-relations.py, graph-search.py, check-staleness.py, detect-conflicts.py) - Phase 2: frontmatter validator, weekly lint, knowledge promotion, git hooks - Fix .gitignore to track tools/ and .githooks/ - Fix git remote URL (remove plaintext token) - New wiki pages: 504 pages, 34 raw sources
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import io
|
||||
import re
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
|
||||
if sys.platform == "win32":
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
|
||||
|
||||
|
||||
class InstitutionQualityAnalyzer:
|
||||
def __init__(self, archives_dir: Path):
|
||||
self.archives_dir = archives_dir
|
||||
self.quality_report: List[Dict] = []
|
||||
|
||||
def analyze_institution(self, file_path: Path) -> Dict:
|
||||
try:
|
||||
content = file_path.read_text(encoding="utf-8")
|
||||
filename = file_path.name
|
||||
|
||||
analysis = {
|
||||
"filename": filename,
|
||||
"score": 0,
|
||||
"max_score": 10,
|
||||
"issues": [],
|
||||
"strengths": [],
|
||||
"missing_fields": [],
|
||||
}
|
||||
|
||||
fm_match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
|
||||
if fm_match:
|
||||
fm_text = fm_match.group(1)
|
||||
if "categories:" in fm_text:
|
||||
analysis["score"] += 1
|
||||
analysis["strengths"].append("有frontmatter categories")
|
||||
if "tags:" in fm_text:
|
||||
analysis["score"] += 1
|
||||
if "type: institution" in fm_text:
|
||||
analysis["score"] += 1
|
||||
|
||||
if "官网" in content or "官方网站" in content or "http" in content:
|
||||
analysis["score"] += 1
|
||||
analysis["strengths"].append("有官网信息")
|
||||
else:
|
||||
analysis["missing_fields"].append("官网链接")
|
||||
|
||||
if any(
|
||||
x in content for x in ["研究重点", "研究方向", "核心研究", "重点领域"]
|
||||
):
|
||||
analysis["score"] += 1
|
||||
analysis["strengths"].append("有研究方向")
|
||||
else:
|
||||
analysis["missing_fields"].append("研究重点")
|
||||
|
||||
if any(
|
||||
x in content for x in ["主要成果", "研究成果", "核心产品", "旗舰项目"]
|
||||
):
|
||||
analysis["score"] += 1
|
||||
analysis["strengths"].append("有主要成果")
|
||||
else:
|
||||
analysis["missing_fields"].append("主要成果")
|
||||
|
||||
if (
|
||||
"联系方式" in content
|
||||
or "联系信息" in content
|
||||
or "contact" in content.lower()
|
||||
):
|
||||
analysis["score"] += 1
|
||||
|
||||
if len(content) > 1500:
|
||||
analysis["score"] += 1
|
||||
|
||||
section_count = content.count("## ")
|
||||
if section_count >= 4:
|
||||
analysis["score"] += 1
|
||||
analysis["strengths"].append(f"结构完整({section_count}章节)")
|
||||
|
||||
if content.count("来源") >= 2 or content.count("参考") >= 2:
|
||||
analysis["score"] += 1
|
||||
analysis["strengths"].append("有信息来源标注")
|
||||
|
||||
if "评级" in content or "质量" in content or "可信度" in content:
|
||||
analysis["score"] += 1
|
||||
analysis["strengths"].append("有质量评级")
|
||||
|
||||
quality_percentage = (analysis["score"] / analysis["max_score"]) * 100
|
||||
analysis["quality_percentage"] = quality_percentage
|
||||
|
||||
if quality_percentage >= 90:
|
||||
analysis["grade"] = "A"
|
||||
elif quality_percentage >= 80:
|
||||
analysis["grade"] = "B"
|
||||
elif quality_percentage >= 70:
|
||||
analysis["grade"] = "C"
|
||||
else:
|
||||
analysis["grade"] = "D"
|
||||
|
||||
return analysis
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"filename": file_path.name,
|
||||
"score": 0,
|
||||
"max_score": 10,
|
||||
"error": str(e),
|
||||
"grade": "F",
|
||||
}
|
||||
|
||||
def analyze_all(self) -> List[Dict]:
|
||||
archive_files = [
|
||||
f for f in self.archives_dir.glob("*.md") if "框架" not in f.name
|
||||
]
|
||||
|
||||
print(f"分析 {len(archive_files)} 个机构档案...")
|
||||
|
||||
results = []
|
||||
for archive_file in archive_files:
|
||||
result = self.analyze_institution(archive_file)
|
||||
results.append(result)
|
||||
|
||||
results.sort(key=lambda x: x.get("quality_percentage", 0))
|
||||
|
||||
return results
|
||||
|
||||
def generate_quality_report(self) -> str:
|
||||
results = self.analyze_all()
|
||||
|
||||
avg_score = (
|
||||
sum(r.get("quality_percentage", 0) for r in results) / len(results)
|
||||
if results
|
||||
else 0
|
||||
)
|
||||
grade_a = sum(1 for r in results if r.get("grade") == "A")
|
||||
grade_b = sum(1 for r in results if r.get("grade") == "B")
|
||||
grade_c = sum(1 for r in results if r.get("grade") == "C")
|
||||
grade_d = sum(1 for r in results if r.get("grade") == "D")
|
||||
|
||||
report = f"""# 机构档案质量分析报告
|
||||
|
||||
## 总体统计
|
||||
|
||||
| 指标 | 值 |
|
||||
|------|-----|
|
||||
| 总档案数 | {len(results)} |
|
||||
| 平均质量分 | {avg_score:.1f}% |
|
||||
| A级档案 | {grade_a} 个 |
|
||||
| B级档案 | {grade_b} 个 |
|
||||
| C级档案 | {grade_c} 个 |
|
||||
| D级档案 | {grade_d} 个 |
|
||||
|
||||
## 按质量分级
|
||||
|
||||
### A级档案 (≥90%)
|
||||
|
||||
"""
|
||||
|
||||
for r in results:
|
||||
if r.get("grade") == "A":
|
||||
report += (
|
||||
f"- **{r['filename']}**: {r.get('quality_percentage', 0):.0f}%\n"
|
||||
)
|
||||
|
||||
report += f"""
|
||||
### B级档案 (80-90%)
|
||||
|
||||
"""
|
||||
|
||||
for r in results:
|
||||
if r.get("grade") == "B":
|
||||
report += (
|
||||
f"- **{r['filename']}**: {r.get('quality_percentage', 0):.0f}%\n"
|
||||
)
|
||||
|
||||
report += f"""
|
||||
### C级档案 (70-80%)
|
||||
|
||||
"""
|
||||
|
||||
for r in results:
|
||||
if r.get("grade") == "C":
|
||||
report += f"- **{r['filename']}**: {r.get('quality_percentage', 0):.0f}% - 缺失: {', '.join(r.get('missing_fields', []))}\n"
|
||||
|
||||
report += f"""
|
||||
### D级档案 (<70%)
|
||||
|
||||
"""
|
||||
|
||||
for r in results:
|
||||
if r.get("grade") == "D":
|
||||
report += f"- **{r['filename']}**: {r.get('quality_percentage', 0):.0f}% - 缺失: {', '.join(r.get('missing_fields', []))}\n"
|
||||
|
||||
report += f"""
|
||||
|
||||
## 改进建议
|
||||
|
||||
### 需要优先修复的档案 (C级和D级)
|
||||
|
||||
"""
|
||||
|
||||
for r in results:
|
||||
if r.get("grade") in ["C", "D"]:
|
||||
missing = r.get("missing_fields", [])
|
||||
if missing:
|
||||
report += f"**{r['filename']}**: 补充 {', '.join(missing)}\n"
|
||||
|
||||
report += f"""
|
||||
|
||||
### 通用改进建议
|
||||
|
||||
1. **官网信息**: 确保每个机构都有官方网站链接
|
||||
2. **研究重点**: 添加明确的研究方向/重点领域描述
|
||||
3. **主要成果**: 列出代表性研究成果或产品
|
||||
4. **联系方式**: 添加联系信息(可选)
|
||||
5. **信息来源**: 确保每条数据有明确来源标注
|
||||
6. **结构完整性**: 建议至少4个章节
|
||||
|
||||
---
|
||||
|
||||
*报告生成时间: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}*
|
||||
"""
|
||||
|
||||
return report
|
||||
|
||||
def save_report(self, output_path: Path):
|
||||
report = self.generate_quality_report()
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
f.write(report)
|
||||
print(f"✅ 质量报告已保存: {output_path}")
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("机构档案质量分析工具")
|
||||
print("=" * 60)
|
||||
|
||||
archives_dir = Path(__file__).parent.parent / "机构档案"
|
||||
output_path = (
|
||||
Path(__file__).parent.parent
|
||||
/ "outputs"
|
||||
/ f"institution_quality_analysis_{datetime.date.today()}.md"
|
||||
)
|
||||
|
||||
analyzer = InstitutionQualityAnalyzer(archives_dir)
|
||||
analyzer.save_report(output_path)
|
||||
|
||||
results = analyzer.analyze_all()
|
||||
avg = sum(r.get("quality_percentage", 0) for r in results) / len(results)
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("分析完成")
|
||||
print("=" * 60)
|
||||
print(f"平均质量分: {avg:.1f}%")
|
||||
print(f"A级: {sum(1 for r in results if r.get('grade') == 'A')}个")
|
||||
print(f"B级: {sum(1 for r in results if r.get('grade') == 'B')}个")
|
||||
print(f"C级: {sum(1 for r in results if r.get('grade') == 'C')}个")
|
||||
print(f"D级: {sum(1 for r in results if r.get('grade') == 'D')}个")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user