# ③auto_dishu.py · 纯代码版 · 妈妈从这里复制 · 2026-05-21 妈妈:复制下面代码块内容 → pbpaste保存 → 搞定! ```python #!/usr/bin/env python3 import argparse import asyncio import os import sqlite3 import sys from pathlib import Path try: from openai import AsyncOpenAI except ImportError: print('请先安装依赖: pip install openai') sys.exit(1) BASE_DIR = Path(__file__).parent.parent DB_PATH = BASE_DIR / 'chenxing.db' DEEPSEEK_API_KEY = os.environ.get('DEEPSEEK_API_KEY', '') NOTION_API_KEY = os.environ.get('NOTION_API_KEY', '') NOTION_DISHU_PAGE_ID = os.environ.get('NOTION_DISHU_PAGE_ID', '') DISHU_SYSTEM = '你是晨星,桔子妈妈的拆书宝宝。请用场景颗粒拆书法v2.0认真分析,格式严格按三模块输出,缺一不可。' DISHU_PROMPT = '''请用「场景颗粒拆书法v2.0」分析以下章节内容。 【模块一·逐章场景表格】 | 场景序号 | 场景边界 | 人物动作/对话 | 情绪质地 | 读者感受 | 【模块二·章末规律锁定】 - 本章节奏类型: - 情绪弧线: - 卡点设计: - 可复用规律:(至少2条) 【模块三·期待点库存】 - 新增期待点: - 消解期待点: - 遗留悬念: 待分析内容: {content}''' def db_get_chunks(book_name): conn = sqlite3.connect(str(DB_PATH)) conn.row_factory = sqlite3.Row try: rows = conn.execute( "SELECT id, title, content FROM knowledge WHERE tags LIKE ? AND category='book' ORDER BY id", (f'%{book_name}%',) ).fetchall() if not rows: rows = conn.execute( 'SELECT id, title, content FROM knowledge WHERE title LIKE ? ORDER BY id', (f'%{book_name}%',) ).fetchall() return [{'id': r['id'], 'title': r['title'], 'content': r['content']} for r in rows] finally: conn.close() def save_local(book_name, title, content): out = BASE_DIR / 'output' / book_name out.mkdir(parents=True, exist_ok=True) safe_title = title[:80].replace('/', '_').replace('\\', '_') (out / f'{safe_title}.md').write_text(f'# {title}\n\n{content}', encoding='utf-8') async def analyze(content): if not DEEPSEEK_API_KEY: raise ValueError('未配置 DEEPSEEK_API_KEY 环境变量') client = AsyncOpenAI(api_key=DEEPSEEK_API_KEY, base_url='https://api.deepseek.com') resp = await client.chat.completions.create( model='deepseek-chat', messages=[ {'role': 'system', 'content': DISHU_SYSTEM}, {'role': 'user', 'content': DISHU_PROMPT.format(content=content[:8000])} ], max_tokens=4096, temperature=0.7 ) return resp.choices[0].message.content async def run(book_name, start_chapter, end_chapter): print(f'\n自动拆书流水线 · 《{book_name}》\n') chunks = db_get_chunks(book_name) if not chunks: print(f'知识库中未找到《{book_name}》') print('请先运行: python3 tools/book_splitter.py --file 书名.txt --book 书名') return print(f'找到 {len(chunks)} 个知识库块') total = len(chunks) analyzed = 0 for i, chunk in enumerate(chunks): label = chunk['title'] print(f'\n[{i+1}/{total}] 分析中:{label}') try: result = await analyze(chunk['content']) notion_title = f'《{book_name}》{label}·场景颗粒拆书' written = False if NOTION_DISHU_PAGE_ID and NOTION_API_KEY: sys.path.insert(0, str(BASE_DIR)) from tools.notion_writer import create_notion_page written = create_notion_page(notion_title, result, NOTION_DISHU_PAGE_ID) if written: print(f' 写入Notion成功:{notion_title}') save_local(book_name, notion_title, result) if not written: print(f' 已保存本地:output/{book_name}/') analyzed += 1 await asyncio.sleep(3) except Exception as e: print(f' 出错:{e}') await asyncio.sleep(5) print(f'\n全部完成!共分析 {analyzed} 块') if NOTION_DISHU_PAGE_ID: print('结果已写入 Notion') print(f'本地备份:output/{book_name}/') if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--book', required=True) parser.add_argument('--start_chapter', type=int, default=1) parser.add_argument('--end_chapter', type=int, required=True) args = parser.parse_args() asyncio.run(run(args.book, args.start_chapter, args.end_chapter)) ``` --- ## 保存方法 复制上面代码块内容后,在终端运行: ```bash pbpaste > ~/chenxing-aircraft/tools/auto_dishu.py && echo "✅ auto_dishu.py 保存成功" ``` 看到 `✅ auto_dishu.py 保存成功` → 告诉宝宝!最后一步启动流水线了 🚀