Skill: lhy123456lhy/homework-grader (version 2.0.0)

--- name: homework-grader description: 老师作业批改助手，用于自动批改数学作业、统计错题、生成Excel统计表和PDF报告。当老师需要：(1) 上传正确答案并让AI识别 (2) 批量上传学生作业照片进行批改 (3) 统计全班错误率并生成错题分析报告 (4) 生成重点错题PDF供讲解使用时，触发此skill。 --- # Homework Grader - 作业批改助手 ## Overview 帮助老师自动批改数学作业，统计错题信息，生成 Excel 统计表和 PDF 分析报告。 ## 依赖安装 运行此 skill 前需要安装以下依赖： ### Python 包 ```bash pip install -r scripts/requirements.txt ``` ### 系统依赖（必须安装） ```bash # Ubuntu/Debian sudo apt install tesseract-ocr # macOS brew install tesseract # Windows # 下载安装：https://github.com/UB-Mannheim/tesseract/wiki ``` ## Workflow ### 完整工作流程 ``` Step 1: 上传正确答案 → AI OCR 识别 ↓ Step 2: 循环上传学生作业 → AI 批改 → 记录结果 ↓ Step 3: 统计错误率 → 生成 Excel 统计表 ↓ Step 4: 生成 PDF 报告（含重点标记） ``` --- ## Step 1: 上传正确答案 老师上传包含正确答案的图片（可以是纸质答案照片或电子版截图）。 **AI 行为：** 1. 使用 OCR 识别图片中的答案 2. 解析答案内容，按题目编号存储 3. 向老师确认识别结果是否正确 4. 如需修改，允许老师手动调整 --- ## Step 2: 上传学生作业 循环上传学生作业照片。 **交互流程：** 1. 询问老师"请上传学生作业照片" 2. 提供学生姓名输入框（可选填写） 3. 如果不填姓名，使用序号标识（如：学生1、学生2） 4. 重复步骤1-3，直到老师说"上传完成" **AI 行为：** 1. OCR 识别学生作业内容 2. 与正确答案比对 3. 标记正确/错误 4. 记录错误类型 --- ## Step 3: 生成 Excel 统计表 当老师说"生成统计表"或"上传完成"时： **输出 Excel 包含：** - 学生姓名/序号 - 各题对错情况 - 正确题数、错误题数 - 错误率百分比 --- ## Step 4: 生成 PDF 报告 当老师说"生成 PDF"或"生成报告"时： **PDF 内容：** 1. 班级概况 - 总人数、提交人数、平均正确率 2. 错题统计表 - 每道题的错题人数、错误率 3. 重点错题 - 错误率 ≥ 配置阈值的题目（默认40%） 4. 讲解建议 - AI 针对重点错题提供的解题思路和讲解要点 --- ## 配置说明 | 配置项 | 说明 | 默认值 | |--------|------|--------| | threshold | 重点错题错误率阈值 | 40% | **修改阈值：** 老师可以说"设置阈值为 30%"来调整 --- ## Resources ### scripts/requirements.txt Python 依赖包列表 ### scripts/ - `ocr_helper.py` - OCR 识别辅助工具 - `generate_excel.py` - 生成 Excel 统计表 - `generate_pdf.py` - 生成 PDF 分析报告 ### references/ - `answer_format.md` - 答案格式规范 - `output_format.md` - 输出格式说明 ### assets/ - `report_template.html` - PDF 报告 HTML 模板

path: scripts/generate_excel.py
content: #!/usr/bin/env python3
"""
Excel Generator - 生成作业统计Excel表格
"""

import os
import json
from typing import List, Dict
from datetime import datetime

try:
    import openpyxl
    from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
except ImportError:
    print("请安装依赖: pip install openpyxl")
    exit(1)


def create_statistics(students_data: List[Dict], correct_answers: List[Dict]) -> Dict:
    """统计数据"""
    total_questions = len(correct_answers)
    
    # 统计每道题的错题人数
    question_stats = {}
    for i in range(1, total_questions + 1):
        question_stats[i] = {'incorrect_count': 0, 'total': len(students_data)}
    
    # 统计每个学生的正确情况
    student_stats = []
    for student in students_data:
        correct_count = 0
        incorrect_questions = []
        
        for answer in student.get('answers', []):
            q_num = answer['question']
            is_correct = answer.get('correct', False)
            
            if is_correct:
                correct_count += 1
            else:
                incorrect_questions.append(q_num)
                if q_num in question_stats:
                    question_stats[q_num]['incorrect_count'] += 1
        
        # 计算错误率
        error_rate = ((total_questions - correct_count) / total_questions * 100) if total_questions > 0 else 0
        
        student_stats.append({
            'name': student.get('name', student.get('index', '未知')),
            'correct_count': correct_count,
            'incorrect_count': total_questions - correct_count,
            'error_rate': round(error_rate, 1),
            'incorrect_questions': incorrect_questions
        })
    
    # 计算每道题的错误率
    for q_num in question_stats:
        stats = question_stats[q_num]
        stats['error_rate'] = round(stats['incorrect_count'] / stats['total'] * 100, 1) if stats['total'] > 0 else 0
    
    return {
        'students': student_stats,
        'questions': question_stats,
        'total_questions': total_questions,
        'total_students': len(students_data)
    }


def generate_excel(students_data: List[Dict], correct_answers: List[Dict], output_path: str, threshold: float = 40):
    """生成Excel统计表"""
    stats = create_statistics(students_data, correct_answers)
    
    wb = openpyxl.Workbook()
    
    # ===== Sheet 1: 学生统计 =====
    ws_students = wb.active
    ws_students.title = "学生统计"
    
    # 标题行
    headers = ["姓名/序号", "正确题数", "错误题数", "正确率", "错题列表"]
    
    # 设置样式
    header_font = Font(bold=True, color="FFFFFF")
    header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid")
    header_alignment = Alignment(horizontal="center", vertical="center")
    
    for col, header in enumerate(headers, 1):
        cell = ws_students.cell(row=1, column=col, value=header)
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = header_alignment
    
    # 填充数据
    for row, student in enumerate(stats['students'], 2):
        ws_students.cell(row=row, column=1, value=student['name'])
        ws_students.cell(row=row, column=2, value=student['correct_count'])
        ws_students.cell(row=row, column=3, value=student['incorrect_count'])
        ws_students.cell(row=row, column=4, value=f"{student['error_rate']}%")
        ws_students.cell(row=row, column=5, value=str(student['incorrect_questions']))
    
    # 设置列宽
    ws_students.column_dimensions['A'].width = 15
    ws_students.column_dimensions['B'].width = 12
    ws_students.column_dimensions['C'].width = 12
    ws_students.column_dimensions['D'].width = 10
    ws_students.column_dimensions['E'].width = 30
    
    # ===== Sheet 2: 错题统计 =====
    ws_questions = wb.create_sheet("错题统计")
    
    q_headers = ["题号", "错题人数", "错误率", "是否重点"]
    for col, header in enumerate(q_headers, 1):
        cell = ws_questions.cell(row=1, column=col, value=header)
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = header_alignment
    
    # 重点标记样式
    highlight_fill = PatternFill(start_color="FF6B6B", end_color="FF6B6B", fill_type="solid")
    
    for row, (q_num, q_stat) in enumerate(stats['questions'].items(), 2):
        ws_questions.cell(row=row, column=1, value=f"第{q_num}题")
        ws_questions.cell(row=row, column=2, value=q_stat['incorrect_count'])
        ws_questions.cell(row=row, column=3, value=f"{q_stat['error_rate']}%")
        
        is重点 = q_stat['error_rate'] >= threshold
        cell = ws_questions.cell(row=row, column=4, value="⭐ 重点" if is重点 else "")
        if is重点:
            cell.fill = highlight_fill
            cell.font = Font(bold=True, color="FFFFFF")
    
    ws_questions.column_dimensions['A'].width = 10
    ws_questions.column_dimensions['B'].width = 12
    ws_questions.column_dimensions['C'].width = 10
    ws_questions.column_dimensions['D'].width = 12
    
    # ===== Sheet 3: 班级概况 =====
    ws_summary = wb.create_sheet("班级概况")
    
    # 计算班级整体数据
    total_correct = sum(s['correct_count'] for s in stats['students'])
    total_possible = stats['total_questions'] * stats['total_students']
    avg_correct_rate = round(total_correct / total_possible * 100, 1) if total_possible > 0 else 0
    
    # 重点错题数量
    key_questions = [q for q, s in stats['questions'].items() if s['error_rate'] >= threshold]
    
    summary_data = [
        ("统计时间", datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
        ("班级人数", stats['total_students']),
        ("题目总数", stats['total_questions']),
        ("班级平均正确率", f"{avg_correct_rate}%"),
        ("重点错题数量", len(key_questions)),
        ("重点错题题号", ", ".join([f"第{q}题" for q in key_questions]) if key_questions else "无"),
    ]
    
    for row, (label, value) in enumerate(summary_data, 1):
        ws_summary.cell(row=row, column=1, value=label).font = Font(bold=True)
        ws_summary.cell(row=row, column=2, value=value)
    
    ws_summary.column_dimensions['A'].width = 18
    ws_summary.column_dimensions['B'].width = 30
    
    # 保存文件
    wb.save(output_path)
    print(f"Excel 统计表已生成: {output_path}")
    
    return stats


if __name__ == '__main__':
    import sys
    
    if len(sys.argv) < 3:
        print("用法: python generate_excel.py <学生数据json> <正确答案json> [输出路径] [阈值]")
        sys.exit(1)
    
    student_file = sys.argv[1]
    correct_file = sys.argv[2]
    output_path = sys.argv[3] if len(sys.argv) > 3 else "作业统计表.xlsx"
    threshold = float(sys.argv[4]) if len(sys.argv) > 4 else 40
    
    with open(student_file, 'r', encoding='utf-8') as f:
        students_data = json.load(f)
    
    with open(correct_file, 'r', encoding='utf-8') as f:
        correct_answers = json.load(f)
    
    generate_excel(students_data, correct_answers, output_path, threshold)

path: scripts/generate_pdf.py
content: #!/usr/bin/env python3
"""
PDF Generator - 生成作业分析PDF报告
"""

import os
import json
from datetime import datetime
from typing import List, Dict

try:
    from weasyprint import HTML
except ImportError:
    print("请安装依赖: pip install weasyprint")
    exit(1)


def generate_pdf_report(
    students_data: List[Dict],
    correct_answers: List[Dict],
    stats: Dict,
    output_path: str,
    threshold: float = 40
) -> str:
    """生成PDF分析报告"""
    
    # 准备数据
    total_students = stats['total_students']
    total_questions = stats['total_questions']
    question_stats = stats['questions']
    student_stats = stats['students']
    
    # 计算班级整体数据
    total_correct = sum(s['correct_count'] for s in student_stats)
    total_possible = total_questions * total_students
    avg_correct_rate = round(total_correct / total_possible * 100, 1) if total_possible > 0 else 0
    
    # 获取重点错题
    key_questions = []
    for q_num, q_stat in question_stats.items():
        if q_stat['error_rate'] >= threshold:
            key_questions.append({
                'question': q_num,
                'error_rate': q_stat['error_rate'],
                'incorrect_count': q_stat['incorrect_count'],
                'correct_answer': correct_answers[q_num - 1]['answer'] if q_num <= len(correct_answers) else ''
            })
    
    # 按错误率排序
    key_questions.sort(key=lambda x: x['error_rate'], reverse=True)
    
    # 生成HTML内容
    html_content = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>作业分析报告</title>
    <style>
        body {{ font-family: "Microsoft YaHei", "SimHei", sans-serif; margin: 40px; }}
        h1 {{ color: #2c3e50; text-align: center; border-bottom: 3px solid #3498db; padding-bottom: 10px; }}
        h2 {{ color: #34495e; border-left: 4px solid #3498db; padding-left: 10px; margin-top: 30px; }}
        .summary {{ background: #ecf0f1; padding: 20px; border-radius: 10px; margin: 20px 0; }}
        .summary-item {{ display: inline-block; margin: 10px 20px; }}
        .summary-label {{ font-weight: bold; color: #7f8c8d; }}
        .summary-value {{ font-size: 1.5em; color: #2c3e50; font-weight: bold; }}
        
        table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
        th, td {{ border: 1px solid #bdc3c7; padding: 12px; text-align: center; }}
        th {{ background: #3498db; color: white; }}
        tr:nth-child(even) {{ background: #f8f9fa; }}
        
        .key-question {{ background: #fff3cd; }}
        .key-badge {{ background: #dc3545; color: white; padding: 3px 8px; border-radius: 3px; font-size: 0.8em; }}
        
        .suggestion {{ background: #d4edda; padding: 15px; border-radius: 5px; margin: 10px 0; }}
        .suggestion-title {{ font-weight: bold; color: #155724; }}
        
        .footer {{ text-align: center; color: #95a5a6; margin-top: 40px; font-size: 0.9em; }}
    </style>
</head>
<body>
    <h1>📊 作业分析报告</h1>
    
    <div class="summary">
        <div class="summary-item">
            <div class="summary-label">班级人数</div>
            <div class="summary-value">{total_students}</div>
        </div>
        <div class="summary-item">
            <div class="summary-label">题目总数</div>
            <div class="summary-value">{total_questions}</div>
        </div>
        <div class="summary-item">
            <div class="summary-label">平均正确率</div>
            <div class="summary-value">{avg_correct_rate}%</div>
        </div>
        <div class="summary-item">
            <div class="summary-label">重点错题</div>
            <div class="summary-value">{len(key_questions)}</div>
        </div>
    </div>
    
    <h2>📈 错题统计</h2>
    <table>
        <tr>
            <th>题号</th>
            <th>错题人数</th>
            <th>错误率</th>
            <th>标记</th>
        </tr>
"""
    
    # 添加错题统计行
    for q_num in sorted(question_stats.keys()):
        q_stat = question_stats[q_num]
        is_key = q_stat['error_rate'] >= threshold
        row_class = 'class="key-question"' if is_key else ''
        badge = '<span class="key-badge">⭐ 重点</span>' if is_key else ''
        
        html_content += f"""
        <tr {row_class}>
            <td>第{q_num}题</td>
            <td>{q_stat['incorrect_count']}</td>
            <td>{q_stat['error_rate']}%</td>
            <td>{badge}</td>
        </tr>
"""
    
    html_content += """
    </table>
"""
    
    # 添加重点错题讲解建议
    if key_questions:
        html_content += """
    <h2>⭐ 重点错题讲解建议</h2>
"""
        for kq in key_questions:
            html_content += f"""
    <div class="suggestion">
        <div class="suggestion-title">第{kq['question']}题 (错误率: {kq['error_rate']}%)</div>
        <p><strong>正确答案:</strong> {kq['correct_answer']}</p>
        <p><strong>讲解建议:</strong> 该题错误人数较多，建议老师在课堂上详细讲解此题目。</p>
    </div>
"""
    
    # 添加学生详情（可选）
    html_content += f"""
    <h2>👥 学生得分明细</h2>
    <table>
        <tr>
            <th>学生</th>
            <th>正确题数</th>
            <th>错误题数</th>
            <th>正确率</th>
        </tr>
"""
    
    for student in student_stats:
        html_content += f"""
        <tr>
            <td>{student['name']}</td>
            <td>{student['correct_count']}</td>
            <td>{student['incorrect_count']}</td>
            <td>{100 - student['error_rate']}%</td>
        </tr>
"""
    
    html_content += """
    </table>
    
    <div class="footer">
        <p>生成时间: """ + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + """</p>
        <p>作业批改助手 | Homework Grader</p>
    </div>
</body>
</html>
"""
    
    # 生成PDF
    HTML(string=html_content).write_pdf(output_path)
    print(f"PDF 报告已生成: {output_path}")
    
    return output_path


if __name__ == '__main__':
    import sys
    
    if len(sys.argv) < 4:
        print("用法: python generate_pdf.py <学生数据json> <正确答案json> <统计结果json> [输出路径] [阈值]")
        sys.exit(1)
    
    student_file = sys.argv[1]
    correct_file = sys.argv[2]
    stats_file = sys.argv[3]
    output_path = sys.argv[4] if len(sys.argv) > 4 else "作业分析报告.pdf"
    threshold = float(sys.argv[5]) if len(sys.argv) > 5 else 40
    
    with open(student_file, 'r', encoding='utf-8') as f:
        students_data = json.load(f)
    
    with open(correct_file, 'r', encoding='utf-8') as f:
        correct_answers = json.load(f)
    
    with open(stats_file, 'r', encoding='utf-8') as f:
        stats = json.load(f)
    
    generate_pdf_report(students_data, correct_answers, stats, output_path, threshold)

path: scripts/ocr_helper.py
content: #!/usr/bin/env python3
"""
OCR Helper - 作业答案识别辅助工具
使用 pytesseract 进行 OCR 识别
"""

import os
import json
import re
from typing import List, Dict, Optional

# 尝试导入所需库
try:
    from PIL import Image
    import pytesseract
except ImportError:
    print("请安装依赖: pip install pillow pytesseract")
    print("同时需要安装 tesseract-ocr")
    exit(1)


def extract_text_from_image(image_path: str) -> str:
    """从图片中提取文字"""
    try:
        image = Image.open(image_path)
        text = pytesseract.image_to_string(image, lang='chi_sim+eng')
        return text
    except Exception as e:
        return f"[OCR识别失败: {str(e)}]"


def parse_answers(text: str) -> List[Dict]:
    """
    解析答案文本，返回题目列表
    格式支持：
    1. 答案
    2. 答案
    或者：
    1) 答案
    2) 答案
    """
    answers = []
    lines = text.strip().split('\n')
    
    # 匹配题号的正则表达式
    pattern = r'^\s*(\d+)[.)、]\s*(.+)$'
    
    for line in lines:
        match = re.match(pattern, line.strip())
        if match:
            question_num = int(match.group(1))
            answer = match.group(2).strip()
            answers.append({
                'question': question_num,
                'answer': answer
            })
    
    return answers


def save_answers(answers: List[Dict], output_path: str):
    """保存答案到 JSON 文件"""
    with open(output_path, 'w', encoding='utf-8') as f:
        json.dump(answers, f, ensure_ascii=False, indent=2)
    print(f"答案已保存到: {output_path}")


def load_answers(input_path: str) -> List[Dict]:
    """从 JSON 文件加载答案"""
    with open(input_path, 'r', encoding='utf-8') as f:
        return json.load(f)


def grade_homework(student_answers: List[Dict], correct_answers: List[Dict]) -> Dict:
    """
    批改作业
    返回批改结果
    """
    result = {
        'correct': [],
        'incorrect': [],
        'total': len(correct_answers),
        'correct_count': 0,
        'incorrect_count': 0
    }
    
    # 建立正确答案字典
    answer_dict = {a['question']: a['answer'] for a in correct_answers}
    
    for student_answer in student_answers:
        q_num = student_answer['question']
        if q_num in answer_dict:
            is_correct = student_answer['answer'].strip() == answer_dict[q_num].strip()
            question_result = {
                'question': q_num,
                'student_answer': student_answer['answer'],
                'correct_answer': answer_dict[q_num],
                'correct': is_correct
            }
            if is_correct:
                result['correct'].append(question_result)
                result['correct_count'] += 1
            else:
                result['incorrect'].append(question_result)
                result['incorrect_count'] += 1
    
    return result


if __name__ == '__main__':
    import sys
    
    if len(sys.argv) < 3:
        print("用法:")
        print("  python ocr_helper.py recognize <图片路径>")
        print("  python ocr_helper.py grade <学生答案json> <正确答案json>")
        sys.exit(1)
    
    command = sys.argv[1]
    
    if command == 'recognize':
        image_path = sys.argv[2]
        text = extract_text_from_image(image_path)
        print("识别结果:")
        print(text)
        
        # 尝试解析答案
        answers = parse_answers(text)
        if answers:
            print("\n解析出的答案:")
            for a in answers:
                print(f"  第{a['question']}题: {a['answer']}")
            
            # 保存到文件
            output_path = os.path.splitext(image_path)[0] + '_answers.json'
            save_answers(answers, output_path)
    
    elif command == 'grade':
        student_file = sys.argv[2]
        correct_file = sys.argv[3]
        
        student_answers = load_answers(student_file)
        correct_answers = load_answers(correct_file)
        
        result = grade_homework(student_answers, correct_answers)
        
        print(f"批改结果: {result['correct_count']}/{result['total']} 正确")
        print(f"错误题目: {[i['question'] for i in result['incorrect']]}")

path: scripts/requirements.txt
content: pillow
pytesseract
openpyxl

path: references/answer_format.md
content: # 答案格式规范

## 图片要求

### 推荐格式
- PNG 或 JPEG
- 分辨率不低于 1024x768
- 文字清晰可读

### 拍摄建议
- 光线均匀，避免阴影
- 保持水平，不要倾斜
- 包含题号和答案

## 答案识别格式

### 支持的格式

**格式 1：编号 + 答案**
```
1. 答案内容
2. 答案内容
3. 答案内容
```

**格式 2：括号格式**
```
1) 答案内容
2) 答案内容
3) 答案内容
```

**格式 3：顿号分隔**
```
1、答案内容
2、答案内容
3、答案内容
```

### 答案内容示例

数学答案示例：
```
1. 125
2. x = 3
3. 36平方厘米
4. 2/3
5. 180度
```

## 注意事项

1. **每题一行**：一个答案占一行
2. **题号连续**：题号应该是连续的（1, 2, 3...）
3. **避免复杂格式**：OCR 对复杂格式识别可能不准确
4. **检查识别结果**：AI 识别后请老师确认答案是否正确

path: references/output_format.md
content: # 输出格式说明

## Excel 统计表格式

### Sheet 1: 学生统计

| 列名 | 说明 | 示例 |
|------|------|------|
| 姓名/序号 | 学生姓名或序号 | 张三 / 学生1 |
| 正确题数 | 做对的题目数量 | 8 |
| 错误题数 | 做错的题目数量 | 2 |
| 正确率 | 正确率百分比 | 80% |
| 错题列表 | 错误的题号列表 | [1, 5] |

### Sheet 2: 错题统计

| 列名 | 说明 | 示例 |
|------|------|------|
| 题号 | 题目编号 | 第1题 |
| 错题人数 | 错误该题的人数 | 15 |
| 错误率 | 错误率百分比 | 75% |
| 是否重点 | 是否为重点错题 | ⭐ 重点 |

### Sheet 3: 班级概况

| 项目 | 说明 | 示例 |
|------|------|------|
| 统计时间 | 生成报表的时间 | 2024-01-15 14:30 |
| 班级人数 | 总学生数 | 20 |
| 题目总数 | 总题目数 | 10 |
| 班级平均正确率 | 班级整体正确率 | 75% |
| 重点错题数量 | 错误率≥阈值的题目数 | 3 |
| 重点错题题号 | 重点错题列表 | 第1题, 第5题, 第8题 |

## PDF 报告格式

### 页面结构

1. **标题区**：报告标题 + 生成时间
2. **班级概况**：人数、题目数、平均正确率、重点错题数
3. **错题统计表**：所有题目的错误率统计
4. **重点错题讲解建议**：错误率≥阈值的题目 + 讲解建议
5. **学生得分明细**：每个学生的得分情况

### 重点标记

- 错误率 ≥ 配置阈值（默认40%）的题目
- 在表格中用红色/高亮标记
- 题目后显示 "⭐ 重点" 标签

## JSON 数据格式

### 学生数据 (students_data.json)

```json
[
  {
    "name": "张三",
    "index": "学生1",
    "answers": [
      {"question": 1, "answer": "125", "correct": true},
      {"question": 2, "answer": "x=3", "correct": false}
    ]
  }
]
```

### 正确答案 (correct_answers.json)

```json
[
  {"question": 1, "answer": "125"},
  {"question": 2, "answer": "x=3"}
]
```

### 统计数据 (stats.json)

```json
{
  "students": [...],
  "questions": {
    "1": {"incorrect_count": 5, "total": 20, "error_rate": 25.0}
  },
  "total_questions": 10,
  "total_students": 20
}
```

path: assets/report_template.html
content: <!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>作业分析报告</title>
    <style>
        body {
            font-family: "Microsoft YaHei", "SimHei", sans-serif;
            margin: 40px;
            color: #2c3e50;
        }
        h1 {
            color: #2c3e50;
            text-align: center;
            border-bottom: 3px solid #3498db;
            padding-bottom: 10px;
        }
        h2 {
            color: #34495e;
            border-left: 4px solid #3498db;
            padding-left: 10px;
            margin-top: 30px;
        }
        .summary {
            background: #ecf0f1;
            padding: 20px;
            border-radius: 10px;
            margin: 20px 0;
        }
        .summary-item {
            display: inline-block;
            margin: 10px 20px;
        }
        .summary-label {
            font-weight: bold;
            color: #7f8c8d;
        }
        .summary-value {
            font-size: 1.5em;
            color: #2c3e50;
            font-weight: bold;
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }
        th, td {
            border: 1px solid #bdc3c7;
            padding: 12px;
            text-align: center;
        }
        th {
            background: #3498db;
            color: white;
        }
        tr:nth-child(even) {
            background: #f8f9fa;
        }
        
        .key-question {
            background: #fff3cd;
        }
        .key-badge {
            background: #dc3545;
            color: white;
            padding: 3px 8px;
            border-radius: 3px;
            font-size: 0.8em;
        }
        
        .suggestion {
            background: #d4edda;
            padding: 15px;
            border-radius: 5px;
            margin: 10px 0;
        }
        .suggestion-title {
            font-weight: bold;
            color: #155724;
        }
        
        .footer {
            text-align: center;
            color: #95a5a6;
            margin-top: 40px;
            font-size: 0.9em;
        }
    </style>
</head>
<body>
    <h1>📊 作业分析报告</h1>
    
    <div class="summary">
        <div class="summary-item">
            <div class="summary-label">班级人数</div>
            <div class="summary-value">{{total_students}}</div>
        </div>
        <div class="summary-item">
            <div class="summary-label">题目总数</div>
            <div class="summary-value">{{total_questions}}</div>
        </div>
        <div class="summary-item">
            <div class="summary-label">平均正确率</div>
            <div class="summary-value">{{avg_correct_rate}}%</div>
        </div>
        <div class="summary-item">
            <div class="summary-label">重点错题</div>
            <div class="summary-value">{{key_question_count}}</div>
        </div>
    </div>
    
    <h2>📈 错题统计</h2>
    <table>
        <tr>
            <th>题号</th>
            <th>错题人数</th>
            <th>错误率</th>
            <th>标记</th>
        </tr>
        {{question_rows}}
    </table>
    
    {{key_questions_section}}
    
    <h2>👥 学生得分明细</h2>
    <table>
        <tr>
            <th>学生</th>
            <th>正确题数</th>
            <th>错误题数</th>
            <th>正确率</th>
        </tr>
        {{student_rows}}
    </table>
    
    <div class="footer">
        <p>生成时间: {{generate_time}}</p>
        <p>作业批改助手 | Homework Grader</p>
    </div>
</body>
</html>

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)