本地部署开源小模型 Qwen2.5-0.5B,完全离线、零成本、隐私不出本机——"本地 Qwen 论文主题提取与可视化系统"撬动厚重学术积累。它汇集 1981–2026 年共 392 篇英文论文,横跨 45 年,聚焦音频描述 Audio Description 这一面向盲人与低视力群体的无障碍领域;后端以 Python 构建 TF-IDF、jieba 与 KMeans 聚类,由本地 Qwen 凝练准确的中英文主题名、描述与关键词,严格去停用词、剔噪声,确保命名精准。前端用原生 HTML/CSS/JS 与 ECharts 打造 9 视图可交互大屏,含词云、关系网络、桑基流向、热力图、趋势图与论文库。系统提炼 10 个典型主题,贯穿教育、视障服务、博物馆无障碍、翻译本地化、描述理论、效果评估、自动生成、影视描述、儿童绘本与博物馆管理,为无障碍研究提供零门槛、可复现的知识地图。


视频讲解:

系统演示:

核心代码:

# -*- coding: utf-8 -*-
"""
运行入口:抽取 PDF -> 主题提取 -> 输出前端数据
用法:
    python run.py            # 完整流程(默认启用 Qwen)
    python run.py --no-llm   # 仅统计聚类(不加载模型,速度最快)
    python run.py --themes 10
"""

import os
import sys
import json
import argparse
import shutil

BASE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(BASE)
PDF_DIR = r"D:/项目-文件夹/2026年7月/whb-洋娃娃/8-1主题提取/1981-2026"
PAPERS_JSON = os.path.join(BASE, "data", "papers.json")
THEMES_JSON = os.path.join(BASE, "output", "themes.json")
FE_DATA_DIR = os.path.join(ROOT, "frontend", "assets", "data")
FE_THEMES = os.path.join(FE_DATA_DIR, "themes.json")
FE_DATA_JS = os.path.join(FE_DATA_DIR, "theme-data.js")


def step_extract():
    from extract_pdf import extract_all
    print("\n========== STEP 1/3  抽取 PDF 文本 ==========")
    recs = extract_all(PDF_DIR, PAPERS_JSON)
    ok = sum(1 for r in recs if not r.get("error"))
    print(f"  成功抽取 {ok}/{len(recs)} 篇")
    return recs


def step_themes(recs, n_themes, use_llm):
    from theme_extract import load_qwen, extract_themes
    print("\n========== STEP 2/3  主题提取 ==========")
    if use_llm:
        load_qwen()
    data = extract_themes(recs, n_themes=n_themes, use_llm=use_llm)
    os.makedirs(os.path.dirname(THEMES_JSON), exist_ok=True)
    json.dump(data, open(THEMES_JSON, "w", encoding="utf-8"), ensure_ascii=False, indent=1)
    print("  主题:", [t["name_zh"] for t in data["themes"]])
    return data


def step_export(data):
    print("\n========== STEP 3/3  导出前端数据 ==========")
    os.makedirs(FE_DATA_DIR, exist_ok=True)
    json.dump(data, open(FE_THEMES, "w", encoding="utf-8"), ensure_ascii=False, indent=1)
    with open(FE_DATA_JS, "w", encoding="utf-8") as f:
        f.write("// 由后端自动生成,请勿手动修改。前端离线双击打开时使用。\n")
        f.write("window.__THEME_DATA__ = ")
        json.dump(data, f, ensure_ascii=False, separators=(",", ":"))
        f.write(";\n")
    print(f"  已写出:\n   - {FE_THEMES}\n   - {FE_DATA_JS}")


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--no-llm", action="store_true", help="不使用大模型,纯统计聚类")
    ap.add_argument("--themes", type=int, default=10, help="主题数量")
    ap.add_argument("--skip-extract", action="store_true", help="跳过 PDF 抽取(已有 papers.json)")
    args = ap.parse_args()

    if args.skip_extract and os.path.exists(PAPERS_JSON):
        recs = json.load(open(PAPERS_JSON, encoding="utf-8"))
        print(f"[skip] 直接读取已有 papers.json({len(recs)} 篇)")
    else:
        recs = step_extract()
    data = step_themes(recs, args.themes, use_llm=not args.no_llm)
    step_export(data)
    print("\n✅ 完成!运行 `python serve.py` 后浏览器打开 http://localhost:8000")


if __name__ == "__main__":
    main()

完整数据代码分享:

更多推荐