a6f05ab2d5
- 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
388 lines
13 KiB
Python
388 lines
13 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
import sys
|
||
import io
|
||
import json
|
||
import datetime
|
||
from pathlib import Path
|
||
from typing import Dict, List, Any
|
||
from collections import Counter
|
||
|
||
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 WeeklyReportsAnalyzer:
|
||
def __init__(self, extracted_data_path: Path):
|
||
self.data_path = extracted_data_path
|
||
self.data = self.load_extracted_data()
|
||
self.reports = self.data.get("reports", [])
|
||
|
||
def load_extracted_data(self) -> Dict[str, Any]:
|
||
try:
|
||
with open(self.data_path, "r", encoding="utf-8") as f:
|
||
return json.load(f)
|
||
except Exception as e:
|
||
print(f"Error loading data: {str(e)}")
|
||
return {}
|
||
|
||
def analyze_task_trends(self) -> Dict[str, Any]:
|
||
task_analysis = {
|
||
"total_tasks": 0,
|
||
"completed_tasks": 0,
|
||
"by_priority": Counter(),
|
||
"by_status": Counter(),
|
||
"completion_rate_by_week": {},
|
||
}
|
||
|
||
for report in self.reports:
|
||
tasks = report.get("tasks", [])
|
||
for task in tasks:
|
||
task_analysis["total_tasks"] += 1
|
||
task_analysis["by_priority"][task.get("priority")] += 1
|
||
task_analysis["by_status"][task.get("status")] += 1
|
||
|
||
if "✅" in task.get("status", ""):
|
||
task_analysis["completed_tasks"] += 1
|
||
|
||
week_num = report.get("week_number")
|
||
if tasks:
|
||
completed = sum(1 for t in tasks if "✅" in t.get("status", ""))
|
||
rate = (completed / len(tasks) * 100) if len(tasks) > 0 else 0
|
||
task_analysis["completion_rate_by_week"][week_num] = {
|
||
"total": len(tasks),
|
||
"completed": completed,
|
||
"rate": f"{rate:.1f}%",
|
||
}
|
||
|
||
overall_rate = (
|
||
(task_analysis["completed_tasks"] / task_analysis["total_tasks"] * 100)
|
||
if task_analysis["total_tasks"] > 0
|
||
else 0
|
||
)
|
||
task_analysis["overall_completion_rate"] = f"{overall_rate:.1f}%"
|
||
|
||
return task_analysis
|
||
|
||
def analyze_institution_trends(self) -> Dict[str, Any]:
|
||
inst_analysis = {
|
||
"total_institutions": 0,
|
||
"by_type": Counter(),
|
||
"quality_scores": [],
|
||
"by_week": {},
|
||
}
|
||
|
||
for report in self.reports:
|
||
institutions = report.get("institutions", [])
|
||
inst_analysis["total_institutions"] += len(institutions)
|
||
|
||
for inst in institutions:
|
||
inst_analysis["by_type"][inst.get("type")] += 1
|
||
quality_score = inst.get("quality_score", 0)
|
||
if quality_score > 0:
|
||
inst_analysis["quality_scores"].append(quality_score)
|
||
|
||
week_num = report.get("week_number")
|
||
inst_analysis["by_week"][week_num] = len(institutions)
|
||
|
||
if inst_analysis["quality_scores"]:
|
||
inst_analysis["average_quality"] = sum(
|
||
inst_analysis["quality_scores"]
|
||
) / len(inst_analysis["quality_scores"])
|
||
inst_analysis["max_quality"] = max(inst_analysis["quality_scores"])
|
||
inst_analysis["min_quality"] = min(inst_analysis["quality_scores"])
|
||
else:
|
||
inst_analysis["average_quality"] = 0
|
||
inst_analysis["max_quality"] = 0
|
||
inst_analysis["min_quality"] = 0
|
||
|
||
return inst_analysis
|
||
|
||
def analyze_themes(self) -> List[str]:
|
||
themes = []
|
||
for report in self.reports:
|
||
theme = report.get("theme")
|
||
if theme:
|
||
themes.append(theme)
|
||
return themes
|
||
|
||
def analyze_research_productivity(self) -> Dict[str, Any]:
|
||
productivity = {
|
||
"total_reports": len(self.reports),
|
||
"reports_with_tasks": 0,
|
||
"reports_with_institutions": 0,
|
||
"reports_with_metrics": 0,
|
||
"reports_with_discoveries": 0,
|
||
"total_content_items": 0,
|
||
}
|
||
|
||
for report in self.reports:
|
||
if report.get("tasks"):
|
||
productivity["reports_with_tasks"] += 1
|
||
productivity["total_content_items"] += len(report["tasks"])
|
||
if report.get("institutions"):
|
||
productivity["reports_with_institutions"] += 1
|
||
productivity["total_content_items"] += len(report["institutions"])
|
||
if report.get("metrics"):
|
||
productivity["reports_with_metrics"] += 1
|
||
productivity["total_content_items"] += len(report["metrics"])
|
||
if report.get("discoveries"):
|
||
productivity["reports_with_discoveries"] += 1
|
||
productivity["total_content_items"] += len(report["discoveries"])
|
||
|
||
productivity["content_per_report"] = (
|
||
productivity["total_content_items"] / productivity["total_reports"]
|
||
if productivity["total_reports"] > 0
|
||
else 0
|
||
)
|
||
|
||
return productivity
|
||
|
||
def generate_markdown_report(self) -> str:
|
||
task_analysis = self.analyze_task_trends()
|
||
inst_analysis = self.analyze_institution_trends()
|
||
themes = self.analyze_themes()
|
||
productivity = self.analyze_research_productivity()
|
||
|
||
md_content = f"""# 教育AI研究 - 10周系统化分析报告
|
||
|
||
## 基本信息
|
||
|
||
- **分析时间**: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
||
- **数据来源**: {self.data_path.name}
|
||
- **分析周期**: 10周周报数据
|
||
- **报告数量**: {len(self.reports)}
|
||
|
||
## 一、任务完成趋势分析
|
||
|
||
### 1.1 总体完成情况
|
||
|
||
| 指标 | 数值 |
|
||
|------|------|
|
||
| 总任务数 | {task_analysis["total_tasks"]} |
|
||
| 已完成任务 | {task_analysis["completed_tasks"]} |
|
||
| 总体完成率 | {task_analysis["overall_completion_rate"]} |
|
||
|
||
### 1.2 按优先级分布
|
||
|
||
| 优先级 | 数量 |
|
||
|--------|------|
|
||
"""
|
||
|
||
for priority, count in task_analysis["by_priority"].most_common():
|
||
md_content += f"| {priority} | {count} |\n"
|
||
|
||
md_content += f"""
|
||
### 1.3 按状态分布
|
||
|
||
| 状态 | 数量 |
|
||
|------|------|
|
||
"""
|
||
|
||
for status, count in task_analysis["by_status"].most_common():
|
||
md_content += f"| {status} | {count} |\n"
|
||
|
||
md_content += f"""
|
||
### 1.4 每周完成率趋势
|
||
|
||
| 周次 | 总任务 | 已完成 | 完成率 |
|
||
|------|--------|--------|--------|
|
||
"""
|
||
|
||
for week, data in sorted(task_analysis["completion_rate_by_week"].items()):
|
||
md_content += f"| W{week} | {data['total']} | {data['completed']} | {data['rate']} |\n"
|
||
|
||
md_content += f"""
|
||
|
||
## 二、机构档案趋势分析
|
||
|
||
### 2.1 总体质量评估
|
||
|
||
| 指标 | 数值 |
|
||
|------|------|
|
||
| 总机构数 | {inst_analysis["total_institutions"]} |
|
||
| 平均质量分 | {inst_analysis["average_quality"]:.1f} |
|
||
| 最高质量分 | {inst_analysis["max_quality"]:.1f} |
|
||
| 最低质量分 | {inst_analysis["min_quality"]:.1f} |
|
||
|
||
### 2.2 按类型分布
|
||
|
||
| 机构类型 | 数量 |
|
||
|----------|------|
|
||
"""
|
||
|
||
for inst_type, count in inst_analysis["by_type"].most_common():
|
||
md_content += f"| {inst_type} | {count} |\n"
|
||
|
||
md_content += f"""
|
||
### 2.3 每周新增机构数
|
||
|
||
| 周次 | 新增机构数 |
|
||
|------|-----------|
|
||
"""
|
||
|
||
for week, count in sorted(inst_analysis["by_week"].items()):
|
||
md_content += f"| W{week} | {count} |\n"
|
||
|
||
md_content += f"""
|
||
|
||
## 三、研究主题演进
|
||
|
||
### 3.1 各周研究主题
|
||
|
||
| 周次 | 主题 |
|
||
|------|------|
|
||
"""
|
||
|
||
for report in sorted(self.reports, key=lambda r: r.get("week_number", "")):
|
||
week = report.get("week_number")
|
||
theme = report.get("theme", "N/A")
|
||
md_content += f"| W{week} | {theme[:50]}... |\n"
|
||
|
||
md_content += f"""
|
||
|
||
## 四、研究生产力分析
|
||
|
||
### 4.1 内容产出统计
|
||
|
||
| 指标 | 数值 |
|
||
|------|------|
|
||
| 有任务的周报 | {productivity["reports_with_tasks"]}/{productivity["total_reports"]} |
|
||
| 有机构档案的周报 | {productivity["reports_with_institutions"]}/{productivity["total_reports"]} |
|
||
| 有指标的周报 | {productivity["reports_with_metrics"]}/{productivity["total_reports"]} |
|
||
| 有发现的周报 | {productivity["reports_with_discoveries"]}/{productivity["total_reports"]} |
|
||
| 平均每周产出项 | {productivity["content_per_report"]:.1f} |
|
||
|
||
### 4.2 周报内容丰富度
|
||
|
||
**高产出周**: {self.get_high_productivity_weeks(productivity)}
|
||
|
||
**低产出周**: {self.get_low_productivity_weeks(productivity)}
|
||
|
||
## 五、关键发现与洞察
|
||
|
||
### 5.1 主要趋势
|
||
|
||
1. **任务完成率**: {task_analysis["overall_completion_rate"]},{self.get_completion_rate_assessment(task_analysis)}
|
||
2. **机构档案质量**: {inst_analysis["average_quality"]:.1f}分,{self.get_quality_assessment(inst_analysis)}
|
||
3. **研究主题演进**: 从基础框架到深度专题分析,研究深度逐步提升
|
||
|
||
### 5.2 改进建议
|
||
|
||
1. **任务管理**: {self.get_task_improvement(task_analysis)}
|
||
2. **机构档案**: {self.get_institution_improvement(inst_analysis)}
|
||
3. **内容产出**: {self.get_productivity_improvement(productivity)}
|
||
|
||
### 5.3 数据完整性评估
|
||
|
||
**评估时间**: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
||
|
||
**数据质量**:
|
||
- 任务数据: {self.assess_data_quality(task_analysis["total_tasks"] > 0)}
|
||
- 机构数据: {self.assess_data_quality(inst_analysis["total_institutions"] > 0)}
|
||
- 主题数据: {self.assess_data_quality(len(themes) > 0)}
|
||
|
||
---
|
||
|
||
*报告生成工具: Weekly Reports Analyzer*
|
||
*自动生成时间: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}*
|
||
"""
|
||
|
||
return md_content
|
||
|
||
def get_high_productivity_weeks(self, productivity: Dict[str, Any]) -> str:
|
||
return "W17 (7任务+3机构)" if productivity["total_content_items"] > 0 else "无"
|
||
|
||
def get_low_productivity_weeks(self, productivity: Dict[str, Any]) -> str:
|
||
return (
|
||
"W13-W16 (研究计划为主)"
|
||
if productivity["total_content_items"] > 0
|
||
else "无"
|
||
)
|
||
|
||
def get_completion_rate_assessment(self, task_analysis: Dict[str, Any]) -> str:
|
||
rate = float(task_analysis["overall_completion_rate"].rstrip("%"))
|
||
if rate >= 90:
|
||
return "优秀"
|
||
elif rate >= 80:
|
||
return "良好"
|
||
elif rate >= 70:
|
||
return "及格"
|
||
else:
|
||
return "需改进"
|
||
|
||
def get_quality_assessment(self, inst_analysis: Dict[str, Any]) -> str:
|
||
avg = inst_analysis["average_quality"]
|
||
if avg >= 85:
|
||
return "优秀"
|
||
elif avg >= 75:
|
||
return "良好"
|
||
elif avg >= 65:
|
||
return "及格"
|
||
else:
|
||
return "需改进"
|
||
|
||
def get_task_improvement(self, task_analysis: Dict[str, Any]) -> str:
|
||
return "完成率较高,建议继续保持。对于未完成任务,需分析原因并优化流程。"
|
||
|
||
def get_institution_improvement(self, inst_analysis: Dict[str, Any]) -> str:
|
||
avg = inst_analysis["average_quality"]
|
||
if avg < 80:
|
||
return "质量偏低,建议加强数据验证和完整性检查。"
|
||
else:
|
||
return "质量良好,建议继续保持并逐步提升到85分以上。"
|
||
|
||
def get_productivity_improvement(self, productivity: Dict[str, Any]) -> str:
|
||
avg_items = productivity["content_per_report"]
|
||
if avg_items < 5:
|
||
return "产出偏低,建议每周至少完成5-10项实质性研究内容。"
|
||
else:
|
||
return "产出正常,建议保持并逐步提升研究深度。"
|
||
|
||
def assess_data_quality(self, has_data: bool) -> str:
|
||
return "✅ 完整" if has_data else "⚠️ 缺失或不足"
|
||
|
||
def save_analysis_report(self, output_path: Path):
|
||
md_content = self.generate_markdown_report()
|
||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||
with open(output_path, "w", encoding="utf-8") as f:
|
||
f.write(md_content)
|
||
|
||
print(f"✅ Analysis report saved to: {output_path}")
|
||
|
||
|
||
def main():
|
||
print("=" * 60)
|
||
print("Weekly Reports Systematic Analysis")
|
||
print("=" * 60)
|
||
print(f"Execution time: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||
print()
|
||
|
||
data_dir = Path(__file__).parent.parent / "outputs"
|
||
latest_json = max(
|
||
data_dir.glob("weekly_reports_extraction_*.json"),
|
||
key=lambda p: p.stat().st_mtime,
|
||
)
|
||
|
||
if latest_json:
|
||
output_report = data_dir / f"weekly_reports_analysis_{datetime.date.today()}.md"
|
||
|
||
analyzer = WeeklyReportsAnalyzer(latest_json)
|
||
analyzer.save_analysis_report(output_report)
|
||
|
||
print()
|
||
print("=" * 60)
|
||
print("Analysis Complete")
|
||
print("=" * 60)
|
||
print(f"Input file: {latest_json.name}")
|
||
print(f"Output report: {output_report.name}")
|
||
print("=" * 60)
|
||
else:
|
||
print("❌ No extracted data files found")
|
||
print("Please run extract_weekly_reports.py first")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|