📄

PDF AI智能分析

使用DeepSeek R1一键生成文献笔记

自动提取PDF内容,调用DeepSeek R1进行深度分析,生成结构化Markdown笔记。 支持并发处理、自动重试、错误恢复等企业级特性。

✨ 核心特性

🤖

AI深度分析

DeepSeek R1模型,支持争议点提炼、机制解析、批判性分析等多维度总结

并发处理

多任务并发执行,API Key轮询使用,充分利用网络带宽

🔄

自动重试

智能重试机制,网络波动或API限流时自动恢复,确保任务完成

📋 前置准备

⚠️ 开始前请确认
  • 已安装Python 3.8+(推荐使用Miniconda)
  • 已申请硅基流动API Key(用于调用DeepSeek R1)
  • 已安装必要的Python包:pypdf, openai

Step 1: 安装依赖包

# 使用pip安装依赖
pip install pypdf openai

Step 2: 获取API Key

访问 硅基流动官网, 注册账号并获取API Key。建议准备多个Key以实现轮询并发。

💡 API Key使用建议
  • 准备3-5个API Key可以实现更高的并发稳定性
  • DeepSeek R1思考时间较长,建议设置timeout≥300秒
  • 硅基流动新用户通常有免费额度,足够日常使用

🔧 Automator工作流设置

创建快速操作

  1. 打开 Automator.app
  2. 选择 "快速操作" (Quick Action)
  3. 设置工作流:
    • 工作流程收到当前:PDF文件
    • 位于:访达.app (Finder)
    • 传递输入:作为自变量
  4. 添加 "运行Shell脚本" 动作
  5. Shell选择:/bin/bash
  6. 传递输入:作为自变量

Shell脚本内容

复制以下代码到Automator的Shell脚本框中,记得修改第14行的Python路径

# 1. 替换为你自己的Python路径
PYTHON_EXEC="/Users/你的用户名/miniconda3/bin/python"

# 2. 调用Python脚本
"$PYTHON_EXEC" - "$@" <<'EOF'

import sys
import os
import re
import time
import random
from pathlib import Path
from pypdf import PdfReader
from openai import OpenAI

# ================= 配置区域 =================
# ⚠️ 请替换为你自己的API Key
API_KEYS = [
    "sk-your-api-key-1",
    "sk-your-api-key-2",
    "sk-your-api-key-3",
]

BASE_URL = "https://api.siliconflow.cn/v1"
MODEL_NAME = "deepseek-ai/DeepSeek-R1"
MAX_WORKERS = 4  # 并发数,建议不超过API Key数量

# --- 提示词配置 ---
PROMPT_1 = """
请作为一名资深的生物医学领域审稿人及科研专家读取文献。
严格按照下列框架总结文献:

✅关键词1✅关键词2✅关键词3✅关键词4……

🟫争议/切入点🟫:

🟪结论与机制解析🟪:

🟥数据来源与研究设计🟥:

⬛研究结果⬛:

🟧文章亮点🟧:

🟨文章局限性🟨:

📰双语摘要📰:
"""

PROMPT_2 = """帮我详细总结文章用到的数据,包括GWAS、临床数据等。"""

PROMPT_3 = """
从批判性角度分析文献,包括创新性、方法学、逻辑链条、数据解读等维度。
"""

TASK_LIST = [
    ("Task_01", PROMPT_1),
    ("Task_02", PROMPT_2),
    ("Task_03", PROMPT_3),
]

# ===========================================

def notify(title, message):
    clean_msg = message.replace('"', '\\"')
    os.system(f'osascript -e \'display notification "{clean_msg}" with title "{title}"\'')

def extract_text_from_pdf(pdf_path):
    """提取PDF文本(前50页)"""
    try:
        reader = PdfReader(pdf_path)
        text = ""
        for i, page in enumerate(reader.pages):
            if i >= 50:  # 读取前50页
                break
            page_text = page.extract_text()
            if page_text:
                text += page_text + "\n"
        return text
    except Exception as e:
        return f"Error reading PDF: {str(e)}"

def call_ai_task(args):
    """调用AI,带重试机制"""
    task_id, prompt, content, assigned_key = args
    client = OpenAI(api_key=assigned_key, base_url=BASE_URL)
    max_retries = 3  # 最多重试3次

    for attempt in range(max_retries):
        try:
            response = client.chat.completions.create(
                model=MODEL_NAME,
                messages=[
                    {"role": "system", "content": "你是一个严谨的科研助手。必须强制使用中文回答。直接输出内容。"},
                    {"role": "user", "content": f"{prompt}\n\n论文内容:\n{content}"}
                ],
                temperature=0.6,
                timeout=300  # 5分钟超时
            )
            return task_id, response.choices[0].message.content
        except Exception as e:
            if attempt == max_retries - 1:
                return task_id, f"Error: {str(e)}"
            else:
                wait_time = (attempt + 1) * 3  # 3s, 6s, 9s
                time.sleep(wait_time)

def sanitize_filename(text):
    """清洗文件名"""
    if not text: return "Untitled"
    text = re.sub(r'[#*`]', '', text)
    text = " ".join(text.split())
    text = re.sub(r'[\\/*?:"<>|]', "_", text)
    return text[:60].strip()

def main():
    if len(sys.argv) < 2:
        notify("错误", "未检测到输入文件")
        return

    pdf_path = Path(sys.argv[1])
    notify("PDF AI分析", f"正在分析: {pdf_path.name}")

    pdf_text = extract_text_from_pdf(str(pdf_path))
    if "Error" in pdf_text:
        notify("PDF读取失败", "文件可能已损坏")
        return

    # 准备任务
    tasks = []
    for i, (task_id, prompt_content) in enumerate(TASK_LIST):
        assigned_key = API_KEYS[i % len(API_KEYS)]
        tasks.append((task_id, prompt_content, pdf_text, assigned_key))

    results = []
    notify("AI思考中", f"正在执行{len(tasks)}个分析任务...")

    # 并发执行
    import concurrent.futures
    with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        future_to_task = {executor.submit(call_ai_task, t): t[0] for t in tasks}
        for future in concurrent.futures.as_completed(future_to_task):
            try:
                t_id, content = future.result()
                results.append((t_id, content))
            except Exception as e:
                notify("任务失败", str(e))

    # 保存结果
    parent_dir = pdf_path.parent
    for task_id, raw_content in results:
        clean_content = re.sub(r'^```[a-zA-Z]*\n?', "", raw_content.strip())
        clean_content = re.sub(r'\n?```$', "", clean_content.strip())
        filename = sanitize_filename(clean_content) + ".md"
        output_path = parent_dir / filename
        with open(output_path, "w", encoding="utf-8") as f:
            f.write(clean_content)

    notify("分析完成", f"已生成{len(results)}个笔记文件")

if __name__ == "__main__":
    main()

EOF

📖 使用方法

  1. 在Finder中找到需要分析的PDF文件
  2. 右键点击PDF文件,选择"快速操作""PDF AI分析"
  3. 等待系统通知提示"分析完成"
  4. 在PDF文件所在目录查看生成的Markdown笔记文件
💡 使用技巧
  • 可以同时选中多个PDF文件进行批量分析
  • 生成的笔记文件会自动以论文关键词命名
  • 分析过程中请保持网络连接稳定

🔧 常见问题

Q: Automator没有反应怎么办?

这通常是"静默失败"问题。请检查Python路径是否正确,依赖包是否已安装。 可以在终端手动运行脚本测试:which python3

Q: API调用超时怎么办?

DeepSeek R1思考时间较长,建议将timeout设置为300秒以上。 如果持续超时,可能是网络问题,可以尝试降低MAX_WORKERS并发数。

Q: 如何查看详细错误信息?

可以在脚本中添加日志输出功能,将错误信息写入桌面日志文件。 参考本教程的"Automator调试指南"部分。