
Book Writer
- 8 installs
- 33 repo stars
- Updated April 26, 2026
- bighardperson/computer-science-skills-collection
book-writer is a skill that generates book outlines and expands chapter content with formulas, figures, tables, and code using AI.
About
This skill uses AI to generate a book outline from a prompt and progressively expand each chapter's content. It supports inserting LaTeX formulas, figures, tables, and code, and adapts structure for academic, technical, fiction, and textbook types. A developer uses it via Python scripts to draft long-form books, with content optimization and web material search as helpers.
- Generates structured book outlines from a prompt and expands chapters level by level
- Supports formulas (LaTeX), figures, tables, and code across academic, technical, and fiction books
- Requires OpenAI and Google CSE API keys for generation and material search
Book Writer by the numbers
- 8 all-time installs (skills.sh)
- Ranked #1,167 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Jul 30, 2026 (Skillselion catalog sync)
book-writer capabilities & compatibility
Requires OPENAI_API_KEY plus GOOGLE_CSE_ID and GOOGLE_API_KEY for material search; usage billed to those keys.
- Capabilities
- copywriting
- Works with
- openai
- Use cases
- copywriting · documentation · research
- Runs
- Runs locally
- Pricing
- Bring your own API key
What book-writer says it does
使用AI辅助写作的OpenClaw技能,可以根据提示词生成书籍大纲并逐级扩写内容,支持添加公式、图表、代码等元素。
export OPENAI_API_KEY="your_openai_api_key"
python scripts/book_writer.py --action outline --prompt "机器学习入门教程"
npx skills add https://github.com/bighardperson/computer-science-skills-collection --skill book-writerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 33 |
| Last updated | April 26, 2026 |
| Repository | bighardperson/computer-science-skills-collection ↗ |
What it does
Generate a book outline from a prompt and expand chapters with formulas, figures, tables, and code.
Who is it for?
Drafting long-form books (academic, technical, fiction, textbook) from a prompt with multimedia elements.
Skip if: Users without OpenAI and Google CSE keys, since generation and material search require them.
When should I use this skill?
the user wants to generate a book outline or expand chapters into long-form written content.
What you get
- Book outline
- Expanded chapter content with formulas, tables, and code
By the numbers
- Default max 10 chapters and 5 sections per chapter
- Three core scripts (book_writer, content_optimizer, material_searcher)
Files
OpenClaw 智能写书技能
这是一个功能完整的AI辅助写作技能,能够根据用户提供的提示词生成书籍大纲,并逐级扩写各章节内容,支持在内容中插入公式、图表、表格和代码等元素。
功能特性
📚 大纲生成能力
- 智能大纲生成: 根据提示词自动生成结构化书籍大纲
- 多层级结构: 支持章节、小节、子小节等多级结构
- 内容规划: 为每个章节提供内容概要和要点
- 风格适配: 根据书籍类型调整大纲结构
✍️ 内容扩写能力
- 逐级扩写: 从章节标题逐步扩展到具体内容
- 内容丰富: 自动添加公式、图表、表格、代码等元素
- 引用管理: 自动生成并管理文献引用
- 格式规范: 遵循学术或出版格式规范
🧩 多媒体支持
- 数学公式: LaTeX格式的数学公式插入
- 图表生成: 根据内容需求生成图表描述
- 代码片段: 支持多种编程语言的代码插入
- 表格设计: 结构化表格的创建和填充
📖 类型适配
- 学术著作: 符合学术写作规范
- 技术书籍: 包含代码示例和技术图表
- 小说创作: 支持情节发展和人物描写
- 教科书: 包含练习题和知识点总结
快速开始
1. 安装技能
# 进入技能目录
cd book-writer
# 安装依赖
python scripts/install_dependencies.py2. 设置API密钥
# 设置环境变量
export OPENAI_API_KEY="your_openai_api_key"
export GOOGLE_CSE_ID="your_google_cse_id" # 用于搜索素材
export GOOGLE_API_KEY="your_google_api_key" # 用于搜索素材3. 生成第一本书
# 生成大纲
python scripts/book_writer.py --action outline --prompt "机器学习入门教程"
# 扩写前三章
python scripts/book_writer.py --action expand --book-path "ml_intro_tutorial" --chapters 1,2,3核心组件
书籍生成器 (scripts/book_writer.py)
主生成模块,负责协调整个书籍生成流程。
主要功能:
- 解析用户提示词
- 生成书籍大纲
- 逐级扩写内容
- 管理多媒体元素
使用方法:
from scripts.book_writer import BookWriter
writer = BookWriter()
# 生成大纲
outline = writer.generate_outline("深度学习理论与实践")
# 扩写内容
book = writer.expand_book(outline, max_chapters=3)
# 保存书籍
writer.save_book(book, "deep_learning_book")内容优化器 (scripts/content_optimizer.py)
优化生成的内容质量。
主要功能:
- 语法和风格优化
- 引用和参考文献管理
- 公式和代码验证
- 图表描述生成
素材搜索器 (scripts/material_searcher.py)
从网络搜索相关素材。
主要功能:
- 根据内容需求搜索图片
- 查找相关数据和统计信息
- 搜索代码示例
- 获取引用文献
配置说明
配置文件 (config.yaml)
# API配置
openai:
api_key: ${OPENAI_API_KEY}
model: gpt-4o
max_tokens: 4000
temperature: 0.7
# 搜索API配置
google:
cse_id: ${GOOGLE_CSE_ID}
api_key: ${GOOGLE_API_KEY}
# 书籍生成默认参数
defaults:
max_chapters: 10
max_sections_per_chapter: 5
content_length: "medium" # short, medium, long
include_formulas: true
include_code: true
include_figures: true
include_tables: true
# 存储设置
storage:
output_dir: "generated_books"
temp_dir: "temp_files"
max_storage_gb: 10使用示例
示例1:生成技术书籍大纲
python scripts/book_writer.py --action outline --prompt "Python Web开发实战指南" --output my_web_dev_book示例2:扩写指定章节
python scripts/book_writer.py --action expand --book-path my_web_dev_book --chapters 1,2,3 --include-code true示例3:生成学术著作
python scripts/book_writer.py --action full --prompt "量子计算基础理论" --chapters 3 --include-formulas true --citation-style "apa"部署到OpenClaw
将整个 book-writer 目录复制到 OpenClaw 的技能目录中即可使用。
许可证
本技能使用MIT许可证。详见项目根目录的LICENSE文件。
{
"ownerId": "kn75r53hf5des4tjzcfc9me29d80k12w",
"slug": "book-writer",
"version": "1.0.0",
"publishedAt": 1771359470076
}{
"slug": "book-writer",
"name": "Book Writer",
"version": "1.0.0",
"installedAt": 1776152391236,
"source": "skillhub"
}# OpenAI API配置
openai:
api_key: ${OPENAI_API_KEY}
model: gpt-4o
max_tokens: 4000
temperature: 0.7
timeout: 300
# Google搜索API配置(用于素材搜索)
google:
cse_id: ${GOOGLE_CSE_ID}
api_key: ${GOOGLE_API_KEY}
# 书籍生成默认参数
defaults:
max_chapters: 10
max_sections_per_chapter: 5
content_length: "medium" # short, medium, long
include_formulas: true
include_code: true
include_figures: true
include_tables: true
citation_style: "apa" # apa, mla, chicago, harvard
# 存储设置
storage:
output_dir: "generated_books"
temp_dir: "temp_files"
max_storage_gb: 10
# 内容设置
content:
academic_mode: false # 是否启用学术写作模式
target_audience: "general" # general, beginner, intermediate, advanced
writing_style: "informative" # informative, narrative, persuasive, descriptive第1章 Python机器学习实战教程基础
第1章 Python机器学习实战教程基础
章节概述
本章将详细介绍第1章 Python机器学习实战教程基础的相关内容。我们将从基本概念入手,逐步深入探讨其核心原理和实际应用。
主要内容
介绍Python机器学习实战教程的基本概念和原理
在这一部分,我们将:
1. 介绍基本定义和概念 2. 探讨核心原理 3. 分析实际应用场景
小节内容
第2章 Python机器学习实战教程基础
第2章 Python机器学习实战教程基础
章节概述
本章将详细介绍第2章 Python机器学习实战教程基础的相关内容。我们将从基本概念入手,逐步深入探讨其核心原理和实际应用。
主要内容
介绍Python机器学习实战教程的基本概念和原理
在这一部分,我们将:
1. 介绍基本定义和概念 2. 探讨核心原理 3. 分析实际应用场景
小节内容
第3章 Python机器学习实战教程基础
第3章 Python机器学习实战教程基础
章节概述
本章将详细介绍第3章 Python机器学习实战教程基础的相关内容。我们将从基本概念入手,逐步深入探讨其核心原理和实际应用。
主要内容
介绍Python机器学习实战教程的基本概念和原理
在这一部分,我们将:
1. 介绍基本定义和概念 2. 探讨核心原理 3. 分析实际应用场景
小节内容
第4章 Python机器学习实战教程基础
第4章 Python机器学习实战教程基础
章节概述
本章将详细介绍第4章 Python机器学习实战教程基础的相关内容。我们将从基本概念入手,逐步深入探讨其核心原理和实际应用。
主要内容
介绍Python机器学习实战教程的基本概念和原理
在这一部分,我们将:
1. 介绍基本定义和概念 2. 探讨核心原理 3. 分析实际应用场景
小节内容
第4章 Python机器学习实战教程基础
第4章 Python机器学习实战教程基础
章节概述
本章将详细介绍第4章 Python机器学习实战教程基础的相关内容。我们将从基本概念入手,逐步深入探讨其核心原理和实际应用。
主要内容
介绍Python机器学习实战教程的基本概念和原理
在这一部分,我们将:
1. 介绍基本定义和概念 2. 探讨核心原理 3. 分析实际应用场景
小节内容
{
"title": "机电电子专业英语 - 完整指南",
"subtitle": "深入理解机电电子专业英语的核心概念与应用",
"chapters": [
{
"chapter_number": 1,
"title": "第1章 机电电子专业英语基础",
"description": "介绍机电电子专业英语的基本概念和原理",
"sections": [
{
"section_number": 1,
"title": "第1章 机电电子专业英语基础的小节1",
"description": "探讨第1章 机电电子专业英语基础的小节1的相关内容"
},
{
"section_number": 2,
"title": "第1章 机电电子专业英语基础的小节2",
"description": "探讨第1章 机电电子专业英语基础的小节2的相关内容"
},
{
"section_number": 3,
"title": "第1章 机电电子专业英语基础的小节3",
"description": "探讨第1章 机电电子专业英语基础的小节3的相关内容"
}
]
},
{
"chapter_number": 2,
"title": "第2章 机电电子专业英语基础",
"description": "介绍机电电子专业英语的基本概念和原理",
"sections": [
{
"section_number": 1,
"title": "第2章 机电电子专业英语基础的小节1",
"description": "探讨第2章 机电电子专业英语基础的小节1的相关内容"
},
{
"section_number": 2,
"title": "第2章 机电电子专业英语基础的小节2",
"description": "探讨第2章 机电电子专业英语基础的小节2的相关内容"
},
{
"section_number": 3,
"title": "第2章 机电电子专业英语基础的小节3",
"description": "探讨第2章 机电电子专业英语基础的小节3的相关内容"
}
]
},
{
"chapter_number": 3,
"title": "第3章 机电电子专业英语基础",
"description": "介绍机电电子专业英语的基本概念和原理",
"sections": [
{
"section_number": 1,
"title": "第3章 机电电子专业英语基础的小节1",
"description": "探讨第3章 机电电子专业英语基础的小节1的相关内容"
},
{
"section_number": 2,
"title": "第3章 机电电子专业英语基础的小节2",
"description": "探讨第3章 机电电子专业英语基础的小节2的相关内容"
},
{
"section_number": 3,
"title": "第3章 机电电子专业英语基础的小节3",
"description": "探讨第3章 机电电子专业英语基础的小节3的相关内容"
}
]
},
{
"chapter_number": 4,
"title": "第4章 机电电子专业英语基础",
"description": "介绍机电电子专业英语的基本概念和原理",
"sections": [
{
"section_number": 1,
"title": "第4章 机电电子专业英语基础的小节1",
"description": "探讨第4章 机电电子专业英语基础的小节1的相关内容"
},
{
"section_number": 2,
"title": "第4章 机电电子专业英语基础的小节2",
"description": "探讨第4章 机电电子专业英语基础的小节2的相关内容"
},
{
"section_number": 3,
"title": "第4章 机电电子专业英语基础的小节3",
"description": "探讨第4章 机电电子专业英语基础的小节3的相关内容"
}
]
},
{
"chapter_number": 5,
"title": "第5章 机电电子专业英语基础",
"description": "介绍机电电子专业英语的基本概念和原理",
"sections": [
{
"section_number": 1,
"title": "第5章 机电电子专业英语基础的小节1",
"description": "探讨第5章 机电电子专业英语基础的小节1的相关内容"
},
{
"section_number": 2,
"title": "第5章 机电电子专业英语基础的小节2",
"description": "探讨第5章 机电电子专业英语基础的小节2的相关内容"
},
{
"section_number": 3,
"title": "第5章 机电电子专业英语基础的小节3",
"description": "探讨第5章 机电电子专业英语基础的小节3的相关内容"
}
]
}
],
"metadata": {
"topic": "机电电子专业英语",
"target_audience": "general",
"writing_style": "informative"
}
}openai>=1.0.0
requests>=2.28.0
pyyaml>=6.0
python-dotenv>=0.19.0
tiktoken>=0.3.0
beautifulsoup4>=4.11.0
lxml>=4.9.0#!/usr/bin/env python3
"""
智能写书主程序 - 根据提示词生成书籍大纲并逐级扩写内容
"""
import os
import sys
import json
import yaml
import re
from pathlib import Path
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
import logging
# 尝试导入依赖,如果失败则提供替代方案
try:
import openai
from openai import OpenAI
HAS_OPENAI = True
except ImportError:
HAS_OPENAI = False
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
# 导入内容优化器
try:
from .content_optimizer import ContentOptimizer
HAS_CONTENT_OPTIMIZER = True
except ImportError:
HAS_CONTENT_OPTIMIZER = False
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/book_writer.log'),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
@dataclass
class BookOutline:
"""书籍大纲数据结构"""
title: str
subtitle: Optional[str]
chapters: List[Dict[str, Any]]
metadata: Dict[str, Any]
@dataclass
class ChapterContent:
"""章节内容数据结构"""
chapter_number: int
title: str
sections: List[Dict[str, Any]]
content: str
formulas: List[str]
figures: List[Dict[str, str]]
tables: List[Dict[str, Any]]
code_snippets: List[Dict[str, str]]
references: List[str]
@dataclass
class Book:
"""整本书的数据结构"""
title: str
outline: BookOutline
chapters: List[ChapterContent]
metadata: Dict[str, Any]
class BookWriter:
"""智能写书主类"""
def __init__(self, config_path: str = "config.yaml"):
"""
初始化写书器
Args:
config_path: 配置文件路径
"""
self.config = self._load_config(config_path)
self.client = None
self.content_optimizer = None
# 初始化OpenAI客户端
self._initialize_openai_client()
# 初始化内容优化器
self._initialize_content_optimizer()
# 创建输出目录
self.output_dir = self.config.get("storage", {}).get("output_dir", "generated_books")
self.temp_dir = self.config.get("storage", {}).get("temp_dir", "temp_files")
Path(self.output_dir).mkdir(parents=True, exist_ok=True)
Path(self.temp_dir).mkdir(parents=True, exist_ok=True)
logger.info(f"写书器初始化完成,输出目录: {self.output_dir}")
def _load_config(self, config_path: str) -> Dict:
"""加载配置文件"""
if not os.path.exists(config_path):
logger.warning(f"配置文件 {config_path} 不存在,使用默认配置")
return {}
try:
with open(config_path, 'r') as f:
config = yaml.safe_load(f)
logger.info(f"配置文件加载成功: {config_path}")
return config or {}
except Exception as e:
logger.error(f"加载配置文件失败: {e}")
return {}
def _initialize_openai_client(self):
"""初始化OpenAI客户端"""
if not HAS_OPENAI:
logger.warning("OpenAI库未安装,将使用模拟模式")
return
openai_config = self.config.get("openai", {})
api_key = os.environ.get("OPENAI_API_KEY") or openai_config.get("api_key")
if not api_key:
logger.warning("OpenAI API密钥未设置,将使用模拟模式")
return
try:
self.client = OpenAI(api_key=api_key)
logger.info("OpenAI客户端初始化成功")
except Exception as e:
logger.error(f"OpenAI客户端初始化失败: {e}")
def _initialize_content_optimizer(self):
"""初始化内容优化器"""
if HAS_CONTENT_OPTIMIZER:
try:
self.content_optimizer = ContentOptimizer()
logger.info("内容优化器初始化成功")
except Exception as e:
logger.error(f"内容优化器初始化失败: {e}")
self.content_optimizer = None
def generate_outline(self, prompt: str, max_chapters: Optional[int] = None) -> BookOutline:
"""
根据提示词生成书籍大纲
Args:
prompt: 书籍主题提示词
max_chapters: 最大章节数
Returns:
BookOutline: 生成的书籍大纲
"""
logger.info(f"开始生成书籍大纲: {prompt}")
# 使用默认值或配置值
if max_chapters is None:
max_chapters = self.config.get("defaults", {}).get("max_chapters", 10)
# 构造请求
outline_prompt = f"""
请为以下主题生成一本结构完整的书籍大纲:
主题: {prompt}
要求:
1. 生成不超过{max_chapters}章的大纲
2. 每章包含3-5个小节
3. 为每章和每节提供简要描述
4. 考虑目标读者为{self.config.get('content', {}).get('target_audience', 'general')}
5. 内容风格应为{self.config.get('content', {}).get('writing_style', 'informative')}
请以JSON格式返回,结构如下:
{{
"title": "书籍标题",
"subtitle": "副标题(可选)",
"chapters": [
{{
"chapter_number": 1,
"title": "第一章标题",
"description": "章节简介",
"sections": [
{{
"section_number": 1,
"title": "第一节标题",
"description": "小节简介"
}}
]
}}
],
"metadata": {{
"topic": "{prompt}",
"target_audience": "{self.config.get('content', {}).get('target_audience', 'general')}",
"writing_style": "{self.config.get('content', {}).get('writing_style', 'informative')}"
}}
}}
"""
if self.client:
# 使用真实的OpenAI API
try:
response = self.client.chat.completions.create(
model=self.config.get("openai", {}).get("model", "gpt-4o"),
messages=[{"role": "user", "content": outline_prompt}],
temperature=self.config.get("openai", {}).get("temperature", 0.7),
max_tokens=self.config.get("openai", {}).get("max_tokens", 2000)
)
response_text = response.choices[0].message.content
logger.info(f"OpenAI响应: {response_text[:200]}...")
except Exception as e:
logger.error(f"OpenAI API调用失败: {e}")
response_text = self._generate_outline_mock(prompt, max_chapters) # 使用模拟数据
else:
# 使用模拟模式
response_text = self._generate_outline_mock(prompt, max_chapters)
# 解析响应
try:
# 尝试提取JSON部分
json_match = re.search(r'\{.*\}', response_text, re.DOTALL)
if json_match:
json_str = json_match.group()
outline_data = json.loads(json_str)
# 创建BookOutline对象
outline = BookOutline(
title=outline_data.get("title", "未命名书籍"),
subtitle=outline_data.get("subtitle"),
chapters=outline_data.get("chapters", []),
metadata=outline_data.get("metadata", {})
)
logger.info(f"大纲生成成功,共{len(outline.chapters)}章")
return outline
else:
logger.error("未能从响应中提取JSON数据")
# 返回一个基本的大纲
return self._create_basic_outline(prompt, max_chapters)
except json.JSONDecodeError as e:
logger.error(f"JSON解析失败: {e}")
logger.error(f"响应内容: {response_text}")
return self._create_basic_outline(prompt, max_chapters)
def _generate_outline_mock(self, prompt: str, max_chapters: int) -> str:
"""模拟生成大纲(用于测试或无API密钥时)"""
logger.info(f"使用模拟模式生成大纲: {prompt}")
# 创建一个模拟的JSON响应
mock_outline = {
"title": f"{prompt} - 完整指南",
"subtitle": f"深入理解{prompt}的核心概念与应用",
"chapters": [],
"metadata": {
"topic": prompt,
"target_audience": self.config.get('content', {}).get('target_audience', 'general'),
"writing_style": self.config.get('content', {}).get('writing_style', 'informative')
}
}
for i in range(1, min(max_chapters, 5) + 1): # 限制为最多5章以保持简洁
chapter = {
"chapter_number": i,
"title": f"第{i}章 {prompt}基础",
"description": f"介绍{prompt}的基本概念和原理",
"sections": []
}
for j in range(1, 4): # 每章3个小节
section_title = f"{chapter['title']}的小节{j}"
chapter["sections"].append({
"section_number": j,
"title": section_title,
"description": f"探讨{section_title}的相关内容"
})
mock_outline["chapters"].append(chapter)
return json.dumps(mock_outline, ensure_ascii=False, indent=2)
def _create_basic_outline(self, prompt: str, max_chapters: int) -> BookOutline:
"""创建基本大纲(当JSON解析失败时)"""
logger.warning("创建基本大纲结构")
chapters = []
for i in range(1, min(max_chapters, 5) + 1):
chapters.append({
"chapter_number": i,
"title": f"第{i}章",
"description": f"关于{prompt}的第{i}部分内容",
"sections": [{
"section_number": 1,
"title": "引言",
"description": "本章引言"
}, {
"section_number": 2,
"title": "主要内容",
"description": "本章主要内容"
}, {
"section_number": 3,
"title": "总结",
"description": "本章总结"
}]
})
return BookOutline(
title=f"{prompt}指南",
subtitle=f"关于{prompt}的全面介绍",
chapters=chapters,
metadata={
"topic": prompt,
"target_audience": self.config.get('content', {}).get('target_audience', 'general'),
"writing_style": self.config.get('content', {}).get('writing_style', 'informative')
}
)
def expand_chapter(self, chapter_data: Dict, chapter_index: int) -> ChapterContent:
"""
扩写单个章节
Args:
chapter_data: 章节数据
chapter_index: 章节索引
Returns:
ChapterContent: 扩写后的章节内容
"""
logger.info(f"开始扩写章节: {chapter_data['title']}")
# 构造扩写提示
expand_prompt = f"""
请详细扩写以下章节内容:
章节标题: {chapter_data['title']}
章节描述: {chapter_data['description']}
该章节包含以下小节:
{chr(10).join([f"- {sec['title']}: {sec['description']}" for sec in chapter_data['sections']])}
要求:
1. 写作长度为{self.config.get('defaults', {}).get('content_length', 'medium')}
2. 包含适当的标题层级结构
3. 如适用,添加相关的数学公式、代码示例、图表描述或表格
4. 保持{self.config.get('content', {}).get('writing_style', 'informative')}的写作风格
5. 如适用,包含相关引用和参考文献
请返回内容,包含:
- 主要内容文本
- 数学公式列表(如果有)
- 代码示例列表(如果有)
- 图表描述列表(如果有)
- 表格数据列表(如果有)
- 参考文献列表(如果有)
"""
if self.client:
# 使用真实的OpenAI API
try:
response = self.client.chat.completions.create(
model=self.config.get("openai", {}).get("model", "gpt-4o"),
messages=[{"role": "user", "content": expand_prompt}],
temperature=self.config.get("openai", {}).get("temperature", 0.7),
max_tokens=self.config.get("openai", {}).get("max_tokens", 3000)
)
content = response.choices[0].message.content
except Exception as e:
logger.error(f"OpenAI API调用失败: {e}")
content = self._expand_chapter_mock(chapter_data, chapter_index) # 使用模拟数据
else:
# 使用模拟模式
content = self._expand_chapter_mock(chapter_data, chapter_index)
# 解析内容,提取各种元素
chapter_content = self._parse_expanded_content(content, chapter_data, chapter_index)
logger.info(f"章节扩写完成: {chapter_data['title']}")
return chapter_content
def _expand_chapter_mock(self, chapter_data: Dict, chapter_index: int) -> str:
"""模拟扩写章节内容"""
logger.info(f"使用模拟模式扩写章节: {chapter_data['title']}")
return f"""
# {chapter_data['title']}
## 章节概述
本章将详细介绍{chapter_data['title']}的相关内容。我们将从基本概念入手,逐步深入探讨其核心原理和实际应用。
## 主要内容
{chapter_data['description']}
在这一部分,我们将:
1. 介绍基本定义和概念
2. 探讨核心原理
3. 分析实际应用场景
## 小节内容
"""
def _parse_expanded_content(self, content: str, chapter_data: Dict, chapter_index: int) -> ChapterContent:
"""解析扩写后的内容,提取各种元素"""
# 提取数学公式(LaTeX格式)
formula_pattern = r'\$\$(.*?)\$\$|\$(.*?)\$'
formulas = re.findall(formula_pattern, content, re.DOTALL)
formulas = [item[0] if item[0] else item[1] for item in formulas if item[0] or item[1]]
# 提取代码块
code_pattern = r'```(\w*)\n(.*?)```'
code_matches = re.findall(code_pattern, content, re.DOTALL)
code_snippets = [{"language": lang, "code": code.strip()} for lang, code in code_matches]
# 提取图表描述(简单模式)
figure_pattern = r'图\d+[::]\s*(.*?)(?:\n|$)'
figures = [{"caption": cap.strip(), "description": cap.strip()} for cap in re.findall(figure_pattern, content)]
# 提取表格(简单模式)
table_pattern = r'表\d+[::]\s*(.*?)(?:\n|$)'
tables = [{"title": tbl.strip(), "description": tbl.strip()} for tbl in re.findall(table_pattern, content)]
# 提取参考文献
ref_patterns = [
r'\[(\d+)\].*?',
r'(?:参考文献|References).*?\n((?:.*?\n)*?)\n\n',
r'\[([^\]]+)\]'
]
references = []
for pat in ref_patterns:
refs = re.findall(pat, content)
references.extend(refs)
return ChapterContent(
chapter_number=chapter_index,
title=chapter_data['title'],
sections=chapter_data['sections'],
content=content,
formulas=formulas,
figures=figures,
tables=tables,
code_snippets=code_snippets,
references=list(set(references)) # 去重
)
def expand_book(self, outline: BookOutline, max_chapters: Optional[int] = None) -> Book:
"""
扩写整本书
Args:
outline: 书籍大纲
max_chapters: 最大扩写章节数
Returns:
Book: 扩写后的书籍
"""
logger.info(f"开始扩写整本书: {outline.title}")
if max_chapters is None:
max_chapters = self.config.get("defaults", {}).get("max_chapters", 3) # 默认只扩写3章
chapters_to_expand = outline.chapters[:max_chapters]
expanded_chapters = []
for i, chapter_data in enumerate(chapters_to_expand):
logger.info(f"正在扩写第{i+1}/{len(chapters_to_expand)}章")
chapter_content = self.expand_chapter(chapter_data, i+1)
expanded_chapters.append(chapter_content)
book = Book(
title=outline.title,
outline=outline,
chapters=expanded_chapters,
metadata=outline.metadata
)
logger.info(f"书籍扩写完成,共{len(expanded_chapters)}章")
return book
def save_book(self, book: Book, output_path: str):
"""
保存书籍到文件
Args:
book: 书籍对象
output_path: 输出路径
"""
output_dir = Path(self.output_dir) / output_path
output_dir.mkdir(parents=True, exist_ok=True)
# 保存完整书籍数据
book_data = {
"title": book.title,
"outline": asdict(book.outline),
"chapters": [asdict(chapter) for chapter in book.chapters],
"metadata": book.metadata
}
with open(output_dir / "book.json", 'w', encoding='utf-8') as f:
json.dump(book_data, f, ensure_ascii=False, indent=2)
# 为每一章创建单独的文件
for chapter in book.chapters:
chapter_file = output_dir / f"chapter_{chapter.chapter_number:02d}.md"
with open(chapter_file, 'w', encoding='utf-8') as f:
f.write(f"# {chapter.title}\n\n")
f.write(chapter.content)
# 添加公式
if chapter.formulas:
f.write("\n## 数学公式\n\n")
for i, formula in enumerate(chapter.formulas):
f.write(f"$$\n{formula}\n$$\n\n")
# 添加代码
if chapter.code_snippets:
f.write("\n## 代码示例\n\n")
for snippet in chapter.code_snippets:
f.write(f"```{snippet['language']}\n{snippet['code']}\n```\n\n")
# 添加图表
if chapter.figures:
f.write("\n## 图表\n\n")
for figure in chapter.figures:
f.write(f"图: {figure['caption']}\n\n")
# 添加表格
if chapter.tables:
f.write("\n## 表格\n\n")
for table in chapter.tables:
f.write(f"表: {table['title']}\n\n")
logger.info(f"书籍已保存到: {output_dir}")
def main():
"""命令行入口点"""
import argparse
parser = argparse.ArgumentParser(description="智能写书工具")
parser.add_argument("--action", choices=["outline", "expand", "full"],
default="outline", help="操作类型: outline(生成大纲), expand(扩写内容), full(全流程)")
parser.add_argument("--prompt", type=str, help="书籍主题提示词")
parser.add_argument("--book-path", type=str, help="书籍路径(扩写时使用)")
parser.add_argument("--chapters", type=str, default="1,2,3", help="要扩写的章节(逗号分隔)")
parser.add_argument("--output", type=str, help="输出目录名称")
parser.add_argument("--max-chapters", type=int, default=3, help="最大章节数")
args = parser.parse_args()
# 创建写书器
writer = BookWriter()
if args.action == "outline":
if not args.prompt:
print("❌ 错误: 生成大纲需要提供 --prompt 参数")
return
print(f"📖 正在为 '{args.prompt}' 生成书籍大纲...")
outline = writer.generate_outline(args.prompt, args.max_chapters)
print(f"✅ 大纲生成完成!共 {len(outline.chapters)} 章")
print(f"📚 书籍标题: {outline.title}")
# 保存大纲
output_name = args.output or outline.title.replace(" ", "_").replace("/", "_")
outline_path = Path(writer.output_dir) / output_name
outline_path.mkdir(parents=True, exist_ok=True)
outline_data = {
"title": outline.title,
"subtitle": outline.subtitle,
"chapters": outline.chapters,
"metadata": outline.metadata
}
with open(outline_path / "outline.json", 'w', encoding='utf-8') as f:
json.dump(outline_data, f, ensure_ascii=False, indent=2)
print(f"💾 大纲已保存到: {outline_path}/outline.json")
elif args.action == "expand":
if not args.book_path:
print("❌ 错误: 扩写内容需要提供 --book-path 参数")
return
if not args.prompt:
print("❌ 错误: 扩写内容需要提供 --prompt 参数(用于重新生成大纲)")
# 我们将从现有的大纲文件加载
outline_path = Path(writer.output_dir) / args.book_path / "outline.json"
if not outline_path.exists():
print(f"❌ 错误: 未找到大纲文件 {outline_path}")
return
with open(outline_path, 'r', encoding='utf-8') as f:
outline_data = json.load(f)
# 重构BookOutline对象
outline = BookOutline(
title=outline_data["title"],
subtitle=outline_data["subtitle"],
chapters=outline_data["chapters"],
metadata=outline_data["metadata"]
)
else:
# 生成新大纲
print(f"📖 正在为 '{args.prompt}' 生成书籍大纲...")
outline = writer.generate_outline(args.prompt, args.max_chapters)
print(f"✍️ 正在扩写书籍内容...")
selected_chapters = [int(x.strip()) for x in args.chapters.split(",")]
max_chap = max(selected_chapters) if selected_chapters else args.max_chapters
book = writer.expand_book(outline, max_chap)
print(f"✅ 内容扩写完成!")
# 保存完整书籍
output_name = args.output or args.book_path
writer.save_book(book, output_name)
print(f"💾 书籍已保存到: {writer.output_dir}/{output_name}")
elif args.action == "full":
if not args.prompt:
print("❌ 错误: 全流程操作需要提供 --prompt 参数")
return
print(f"📖 正在为 '{args.prompt}' 生成书籍大纲...")
outline = writer.generate_outline(args.prompt, args.max_chapters)
print(f"✍️ 正在扩写书籍内容...")
book = writer.expand_book(outline, args.max_chapters)
output_name = args.output or outline.title.replace(" ", "_").replace("/", "_")
writer.save_book(book, output_name)
print(f"🎉 书籍生成完成!")
print(f"📚 书籍标题: {book.title}")
print(f"💾 保存位置: {writer.output_dir}/{output_name}")
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
内容优化器 - 优化生成的书籍内容质量
"""
import re
import json
from typing import Dict, List, Optional
from pathlib import Path
import logging
logger = logging.getLogger(__name__)
class ContentOptimizer:
"""内容优化器"""
def __init__(self):
self.citation_formats = {
"apa": self._format_apa_citation,
"mla": self._format_mla_citation,
"chicago": self._format_chicago_citation,
"harvard": self._format_harvard_citation
}
def optimize_content(self, content: str, content_type: str = "chapter") -> str:
"""
优化内容质量
Args:
content: 原始内容
content_type: 内容类型(chapter, section, paragraph等)
Returns:
str: 优化后的内容
"""
# 1. 语法和风格优化
content = self._optimize_grammar_and_style(content)
# 2. 格式规范化
content = self._normalize_formatting(content)
# 3. 引用格式化
content = self._format_citations(content)
# 4. 公式验证和格式化
content = self._validate_and_format_equations(content)
# 5. 代码块语法高亮标记
content = self._add_code_language_tags(content)
return content
def _optimize_grammar_and_style(self, content: str) -> str:
"""优化语法和风格"""
# 修正常见的语法错误
content = re.sub(r'\s+', ' ', content) # 合并多个空格为单个空格
content = re.sub(r'(\w)\.(\w)', r'\1. \2', content) # 确保句号后有空格
content = re.sub(r'(\w),(\w)', r'\1, \2', content) # 确保逗号后有空格
# 修正标题格式
lines = content.split('\n')
optimized_lines = []
for line in lines:
# 检查是否为标题行
if line.strip().startswith('#'):
# 确保标题后有空行
optimized_lines.append(line)
if len(optimized_lines) > 0 and optimized_lines[-1] != '':
optimized_lines.append('')
else:
optimized_lines.append(line)
return '\n'.join(optimized_lines)
def _normalize_formatting(self, content: str) -> str:
"""规范化格式"""
# 标准化标题层级
content = re.sub(r'^#{6,}', '##', content, flags=re.MULTILINE) # 将过多的标题层级降级
content = re.sub(r'^#{1}', '#', content, flags=re.MULTILINE) # 保留一级标题
# 确保列表格式一致
content = re.sub(r'^\s*[*+-]\s+', '- ', content, flags=re.MULTILINE) # 统一无序列表标记
return content
def _format_citations(self, content: str) -> str:
"""格式化引用"""
# 查找引用标记,如 [1], [Smith et al., 2020], [Author, Year] 等
citation_pattern = r'\[([^]]+)\]'
def replace_citation(match):
citation_text = match.group(1)
# 这里可以实现具体的引用格式化逻辑
# 为简化,暂时返回原文
return f'[{citation_text}]'
return re.sub(citation_pattern, replace_citation, content)
def _validate_and_format_equations(self, content: str) -> str:
"""验证和格式化方程式"""
# 确保LaTeX公式格式正确
# 匹配 $$...$$ 或 $...$ 形式的公式
content = re.sub(r'\$\$(.*?)\$\$', r'\n$$\n\1\n$$\n', content, flags=re.DOTALL)
content = re.sub(r'\$(.*?)\$', r'$\1$', content)
return content
def _add_code_language_tags(self, content: str) -> str:
"""为代码块添加语言标签"""
# 简单的代码语言检测和标记
# 这里使用简单的启发式方法,实际应用中可能需要更复杂的检测逻辑
lines = content.split('\n')
optimized_content = []
in_code_block = False
code_block_start_idx = -1
i = 0
while i < len(lines):
line = lines[i]
if line.strip() == '```':
if not in_code_block:
# 代码块开始
in_code_block = True
code_block_start_idx = i
else:
# 代码块结束
in_code_block = False
# 检查代码块内容并尝试确定语言
if code_block_start_idx + 1 < len(lines) and i > code_block_start_idx + 1:
# 获取代码块内容
code_content = '\n'.join(lines[code_block_start_idx+1:i])
# 简单的语言检测
lang = self._detect_code_language(code_content)
if lang:
# 在代码块开始标记后插入语言标识
lines[code_block_start_idx] = f'```{lang}'
optimized_content.append(lines[i])
i += 1
continue
optimized_content.append(line)
i += 1
return '\n'.join(optimized_content)
def _detect_code_language(self, code_content: str) -> Optional[str]:
"""检测代码语言"""
code_content_lower = code_content.lower()
# 检测常见语言的关键字
language_keywords = {
'python': ['def ', 'import ', 'class ', 'print(', 'lambda '],
'javascript': ['function', 'const ', 'let ', 'var ', 'console.log'],
'java': ['public class', 'private ', 'import ', 'System.out'],
'cpp': ['#include', 'using namespace', 'cout <<', 'cin >>'],
'html': ['<html>', '<body>', '<div', '</'],
'css': ['{', '}', 'margin:', 'padding:'],
'sql': ['SELECT', 'FROM', 'WHERE', 'INSERT INTO'],
'bash': ['#!/bin/bash', 'echo ', 'cd ', 'ls ', 'mkdir '],
'markdown': ['#', '*', '**', '[', '](']
}
scores = {}
for lang, keywords in language_keywords.items():
score = sum(1 for keyword in keywords if keyword.lower() in code_content_lower)
scores[lang] = score
# 返回得分最高的语言
if scores:
best_lang = max(scores, key=scores.get)
if scores[best_lang] > 0: # 只有在找到至少一个关键字时才返回语言
return best_lang
return None
def _format_apa_citation(self, citation: str) -> str:
"""格式化APA引用"""
# APA格式示例: (Author, Year)
return f"({citation})"
def _format_mla_citation(self, citation: str) -> str:
"""格式化MLA引用"""
# MLA格式示例: (Author Page)
return f"({citation})"
def _format_chicago_citation(self, citation: str) -> str:
"""格式化Chicago引用"""
# Chicago格式示例: (Author Year)
return f"({citation})"
def _format_harvard_citation(self, citation: str) -> str:
"""格式化Harvard引用"""
# Harvard格式示例: (Author, Year)
return f"({citation})"
def add_multimedia_elements(self, content: str, multimedia_data: Dict) -> str:
"""
添加多媒体元素(公式、图表、表格、代码等)
Args:
content: 原始内容
multimedia_data: 多媒体数据字典
Returns:
str: 添加多媒体元素后的内容
"""
# 添加数学公式
if 'formulas' in multimedia_data and multimedia_data['formulas']:
content += "\n\n## 数学公式\n\n"
for i, formula in enumerate(multimedia_data['formulas']):
content += f"$$\n{formula}\n$$\n\n"
# 添加代码示例
if 'code_snippets' in multimedia_data and multimedia_data['code_snippets']:
content += "\n\n## 代码示例\n\n"
for snippet in multimedia_data['code_snippets']:
lang = snippet.get('language', 'python')
code = snippet.get('code', '')
content += f"```{lang}\n{code}\n```\n\n"
# 添加表格
if 'tables' in multimedia_data and multimedia_data['tables']:
content += "\n\n## 表格\n\n"
for table in multimedia_data['tables']:
title = table.get('title', '表格')
content += f"**{title}**\n\n"
# 简单的表格表示
if 'rows' in table:
for row in table['rows']:
content += "| " + " | ".join(str(cell) for cell in row) + " |\n"
content += "\n"
# 添加图表描述
if 'figures' in multimedia_data and multimedia_data['figures']:
content += "\n\n## 图表\n\n"
for figure in multimedia_data['figures']:
caption = figure.get('caption', '图表')
description = figure.get('description', '')
content += f"**{caption}**: {description}\n\n"
return content
def validate_content_quality(self, content: str) -> Dict[str, any]:
"""
验证内容质量
Args:
content: 待验证的内容
Returns:
Dict: 验证结果
"""
result = {
'word_count': len(content.split()),
'character_count': len(content),
'sentence_count': len(re.split(r'[.!?]+', content)),
'paragraph_count': len([p for p in content.split('\n\n') if p.strip()]),
'has_headings': bool(re.search(r'^#+\s', content, re.MULTILINE)),
'has_lists': bool(re.search(r'^\s*[-*+]\s|^(\d+\. )', content, re.MULTILINE)),
'has_code_blocks': '```' in content,
'has_equations': '$$' in content or '$' in content,
'readability_score': self._calculate_readability_score(content)
}
return result
def _calculate_readability_score(self, content: str) -> float:
"""计算可读性分数(简化版)"""
words = content.split()
sentences = re.split(r'[.!?]+', content)
sentences = [s for s in sentences if s.strip()] # 移除空句子
if not words or not sentences:
return 0.0
avg_sentence_length = len(words) / len(sentences)
# 简化的可读性计算
score = max(0, min(100, 204.8 - 1.015 * avg_sentence_length))
return round(score, 2)
def main():
"""测试函数"""
import argparse
parser = argparse.ArgumentParser(description="内容优化器测试")
parser.add_argument("content", nargs='?', help="要优化的内容")
parser.add_argument("--file", help="包含内容的文件路径")
args = parser.parse_args()
optimizer = ContentOptimizer()
if args.file:
with open(args.file, 'r', encoding='utf-8') as f:
content = f.read()
elif args.content:
content = args.content
else:
content = """
# 第一章 引言
本章将介绍相关内容.这是第一段内容.这是第二句话。
- 列表项1
- 列表项2
代码块如下:
```
print("Hello, world!")
```
这里有一个公式 $E=mc^2$ 和另一个 $$\\int_0^\\infty e^{-x^2} dx$$
"""
print("原始内容:")
print(content)
print("\n" + "="*50 + "\n")
optimized = optimizer.optimize_content(content)
print("优化后内容:")
print(optimized)
quality = optimizer.validate_content_quality(optimized)
print("\n内容质量评估:")
for key, value in quality.items():
print(f" {key}: {value}")
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
依赖安装脚本 - 自动安装智能写书技能所需的所有依赖
"""
import subprocess
import sys
import os
import platform
def run_command(cmd, description=""):
"""运行命令并显示进度"""
if description:
print(f"🔧 {description}...")
print(f" 💻 执行: {cmd}")
try:
result = subprocess.run(cmd, shell=True, check=True,
capture_output=True, text=True)
if result.returncode == 0:
print(f" ✅ 成功")
if result.stdout.strip():
print(f" 输出: {result.stdout.strip()}")
return True
except subprocess.CalledProcessError as e:
print(f" ❌ 失败")
print(f" 错误: {e.stderr}")
if e.stdout.strip():
print(f" 输出: {e.stdout}")
return False
return True
def check_python_version():
"""检查Python版本"""
print("🐍 检查Python版本...")
version = sys.version_info
print(f" 当前Python版本: {version.major}.{version.minor}.{version.micro}")
if version.major < 3 or (version.major == 3 and version.minor < 8):
print(" ❌ 需要Python 3.8或更高版本")
return False
print(" ✅ Python版本满足要求")
return True
def install_pip_packages():
"""安装必要的Python包"""
packages = [
"openai>=1.0.0",
"requests>=2.28.0",
"pyyaml>=6.0",
"python-dotenv>=0.19.0",
"tiktoken>=0.3.0",
"beautifulsoup4>=4.11.0",
"lxml>=4.9.0"
]
print("📦 安装Python依赖包...")
for package in packages:
package_name = package.split(">=")[0].split("<=")[0]
cmd = f"{sys.executable} -m pip install --upgrade {package}"
run_command(cmd, f"安装 {package_name}")
return True
def setup_environment():
"""设置环境变量和配置"""
print("⚙️ 设置环境...")
# 创建必要的目录
directories = [
"generated_books",
"temp_files",
"logs"
]
for directory in directories:
if not os.path.exists(directory):
os.makedirs(directory)
print(f" 📁 创建目录: {directory}")
# 检查API密钥环境变量
print("🔑 检查API密钥环境变量...")
api_keys = {
"OPENAI_API_KEY": "OpenAI API密钥",
"GOOGLE_CSE_ID": "Google自定义搜索引擎ID",
"GOOGLE_API_KEY": "Google API密钥"
}
missing_keys = []
for key, description in api_keys.items():
if os.environ.get(key):
print(f" ✅ {description}: 已设置")
else:
print(f" ⚠️ {description}: 未设置")
missing_keys.append(key)
if missing_keys:
print(f"\n🔔 需要设置以下环境变量:")
for key in missing_keys:
print(f" export {key}=your_api_key_here")
print("\n💡 提示: 可以将这些设置添加到 ~/.bashrc 或 ~/.zshrc")
return True
def main():
"""主安装函数"""
print("🚀 开始安装智能写书技能依赖...")
print("=" * 60)
# 检查Python版本
if not check_python_version():
sys.exit(1)
# 安装pip包
if not install_pip_packages():
print("❌ Python包安装失败")
sys.exit(1)
# 设置环境
setup_environment()
print("\n" + "=" * 60)
print("🎉 安装完成!")
print("\n📋 后续步骤:")
print("1. 设置API密钥环境变量")
print("2. 开始使用写书技能!")
return 0
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
素材搜索器 - 从网络搜索相关素材(图片、数据、代码等)
"""
import os
import requests
import json
from typing import Dict, List, Optional, Any
from pathlib import Path
import logging
from urllib.parse import urlencode
logger = logging.getLogger(__name__)
class MaterialSearcher:
"""素材搜索器"""
def __init__(self, config_path: str = "config.yaml"):
"""
初始化搜索器
Args:
config_path: 配置文件路径
"""
self.config = self._load_config(config_path)
self.google_api_key = os.environ.get("GOOGLE_API_KEY") or self.config.get("google", {}).get("api_key")
self.google_cse_id = os.environ.get("GOOGLE_CSE_ID") or self.config.get("google", {}).get("cse_id")
if not self.google_api_key or not self.google_cse_id:
logger.warning("Google API密钥或CSE ID未设置,素材搜索功能将受限")
logger.info("素材搜索器初始化完成")
def _load_config(self, config_path: str) -> Dict:
"""加载配置文件"""
if not os.path.exists(config_path):
logger.warning(f"配置文件 {config_path} 不存在,使用默认配置")
return {}
try:
with open(config_path, 'r') as f:
config = json.load(f) if config_path.endswith('.json') else yaml.safe_load(f)
logger.info(f"配置文件加载成功: {config_path}")
return config or {}
except Exception as e:
logger.error(f"加载配置文件失败: {e}")
return {}
def search_images(self, query: str, num_results: int = 5) -> List[Dict[str, str]]:
"""
搜索相关图片
Args:
query: 搜索查询
num_results: 结果数量
Returns:
List[Dict]: 图片信息列表
"""
if not self.google_api_key or not self.google_cse_id:
logger.warning("Google API未配置,返回模拟结果")
return self._mock_image_search(query, num_results)
try:
url = "https://www.googleapis.com/customsearch/v1"
params = {
'key': self.google_api_key,
'cx': self.google_cse_id,
'q': query,
'searchType': 'image',
'num': min(num_results, 10) # Google API限制每次最多10个结果
}
response = requests.get(url, params=params)
response.raise_for_status()
data = response.json()
images = []
if 'items' in data:
for item in data['items']:
images.append({
'title': item.get('title', ''),
'link': item.get('link', ''),
'thumbnail': item.get('thumbnailLink', ''),
'context': item.get('image', {}).get('contextLink', ''),
'description': item.get('snippet', '')
})
logger.info(f"找到 {len(images)} 张相关图片")
return images
except Exception as e:
logger.error(f"图片搜索失败: {e}")
return self._mock_image_search(query, num_results)
def search_code_examples(self, query: str, num_results: int = 3) -> List[Dict[str, str]]:
"""
搜索代码示例
Args:
query: 搜索查询
num_results: 结果数量
Returns:
List[Dict]: 代码示例信息列表
"""
if not self.google_api_key or not self.google_cse_id:
logger.warning("Google API未配置,返回模拟结果")
return self._mock_code_search(query, num_results)
try:
# 在GitHub等代码托管平台搜索
github_query = f"{query} language:python OR language:javascript OR language:java OR language:cpp"
url = "https://www.googleapis.com/customsearch/v1"
params = {
'key': self.google_api_key,
'cx': self.google_cse_id,
'q': github_query,
'num': min(num_results, 10)
}
response = requests.get(url, params=params)
response.raise_for_status()
data = response.json()
codes = []
if 'items' in data:
for item in data['items']:
codes.append({
'title': item.get('title', ''),
'link': item.get('link', ''),
'snippet': item.get('snippet', ''),
'source': 'GitHub' if 'github.com' in item.get('link', '') else 'Other'
})
logger.info(f"找到 {len(codes)} 个相关代码示例")
return codes
except Exception as e:
logger.error(f"代码搜索失败: {e}")
return self._mock_code_search(query, num_results)
def search_data_and_statistics(self, query: str, num_results: int = 3) -> List[Dict[str, str]]:
"""
搜索数据和统计数据
Args:
query: 搜索查询
num_results: 结果数量
Returns:
List[Dict]: 数据信息列表
"""
if not self.google_api_key or not self.google_cse_id:
logger.warning("Google API未配置,返回模拟结果")
return self._mock_data_search(query, num_results)
try:
url = "https://www.googleapis.com/customsearch/v1"
params = {
'key': self.google_api_key,
'cx': self.google_cse_id,
'q': f"{query} statistics data chart graph",
'num': min(num_results, 10)
}
response = requests.get(url, params=params)
response.raise_for_status()
data = response.json()
datasets = []
if 'items' in data:
for item in data['items']:
datasets.append({
'title': item.get('title', ''),
'link': item.get('link', ''),
'snippet': item.get('snippet', ''),
'source': item.get('displayLink', '')
})
logger.info(f"找到 {len(datasets)} 个相关数据源")
return datasets
except Exception as e:
logger.error(f"数据搜索失败: {e}")
return self._mock_data_search(query, num_results)
def _mock_image_search(self, query: str, num_results: int) -> List[Dict[str, str]]:
"""模拟图片搜索"""
logger.info(f"使用模拟模式搜索图片: {query}")
return [
{
'title': f'Sample image for {query}',
'link': f'https://example.com/image_{i}.jpg',
'thumbnail': f'https://example.com/thumb_{i}.jpg',
'context': 'https://example.com/context',
'description': f'This is a sample image related to {query}'
}
for i in range(min(num_results, 3))
]
def _mock_code_search(self, query: str, num_results: int) -> List[Dict[str, str]]:
"""模拟代码搜索"""
logger.info(f"使用模拟模式搜索代码: {query}")
return [
{
'title': f'{query} code example {i}',
'link': f'https://github.com/example/repo{i}',
'snippet': f'// Sample code for {query}\nfunction example() {{\n // TODO: implement {query}\n}}',
'source': 'GitHub'
}
for i in range(min(num_results, 3))
]
def _mock_data_search(self, query: str, num_results: int) -> List[Dict[str, str]]:
"""模拟数据搜索"""
logger.info(f"使用模拟模式搜索数据: {query}")
return [
{
'title': f'{query} statistics and data',
'link': f'https://example.com/data{i}.json',
'snippet': f'Dataset containing information about {query} trends and statistics',
'source': 'DataHub'
}
for i in range(min(num_results, 3))
]
def download_image(self, image_url: str, save_path: str) -> bool:
"""
下载图片
Args:
image_url: 图片URL
save_path: 保存路径
Returns:
bool: 是否成功下载
"""
try:
response = requests.get(image_url, stream=True)
response.raise_for_status()
with open(save_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
logger.info(f"图片已下载: {save_path}")
return True
except Exception as e:
logger.error(f"下载图片失败: {e}")
return False
def generate_figure_description(self, topic: str) -> str:
"""
生成图表描述
Args:
topic: 图表主题
Returns:
str: 图表描述
"""
# 这里可以集成AI模型来生成更精确的图表描述
descriptions = {
"machine learning": f"Figure: Overview of {topic} concepts, showing the relationship between training data, model, and predictions.",
"data science": f"Chart: Distribution of {topic} metrics, illustrating key statistical properties.",
"programming": f"Diagram: Flowchart demonstrating the {topic} algorithm or process.",
"mathematics": f"Graph: Mathematical function related to {topic}, showing key properties and behaviors."
}
default_desc = f"Figure: Visualization of {topic} concepts, showing key relationships and properties."
return descriptions.get(topic.lower(), default_desc)
def generate_table_schema(self, topic: str, columns: List[str]) -> Dict[str, Any]:
"""
生成表格结构
Args:
topic: 表格主题
columns: 列名列表
Returns:
Dict: 表格结构
"""
return {
"title": f"Table: {topic} Data",
"description": f"Structured data table for {topic} information",
"columns": [{"name": col, "type": "string", "description": f"Column for {col}"} for col in columns],
"sample_rows": []
}
def main():
"""测试函数"""
import argparse
parser = argparse.ArgumentParser(description="素材搜索器测试")
parser.add_argument("query", help="搜索查询")
parser.add_argument("--type", choices=["images", "code", "data"], default="images", help="搜索类型")
args = parser.parse_args()
searcher = MaterialSearcher()
if args.type == "images":
results = searcher.search_images(args.query)
print(f"找到 {len(results)} 张图片:")
for img in results:
print(f" - {img['title']}: {img['link']}")
elif args.type == "code":
results = searcher.search_code_examples(args.query)
print(f"找到 {len(results)} 个代码示例:")
for code in results:
print(f" - {code['title']}: {code['link']}")
print(f" {code['snippet'][:100]}...")
elif args.type == "data":
results = searcher.search_data_and_statistics(args.query)
print(f"找到 {len(results)} 个数据源:")
for data in results:
print(f" - {data['title']}: {data['link']}")
print(f" {data['snippet'][:100]}...")
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
安装测试脚本 - 测试智能写书技能的所有组件
"""
import os
import sys
import importlib
import json
from pathlib import Path
def print_header(text):
"""打印标题"""
print("\n" + "=" * 60)
print(f"🔍 {text}")
print("=" * 60)
def print_result(name, status, details=""):
"""打印测试结果"""
emoji = "✅" if status else "❌"
print(f"{emoji} {name}: {'通过' if status else '失败'}")
if details:
print(f" 详情: {details}")
def test_python_version():
"""测试Python版本"""
print_header("测试Python版本")
version = sys.version_info
print(f"Python版本: {version.major}.{version.minor}.{version.micro}")
# 检查是否满足最低要求
min_version = (3, 8)
is_ok = (version.major > min_version[0]) or \
(version.major == min_version[0] and version.minor >= min_version[1])
print_result("Python版本", is_ok,
f"需要Python {min_version[0]}.{min_version[1]}+")
return is_ok
def test_dependencies():
"""测试依赖包"""
print_header("测试依赖包")
dependencies = [
("openai", ">=1.0.0"),
("requests", ">=2.28.0"),
("yaml", ">=6.0"), # PyYAML的模块名是yaml
("tiktoken", ">=0.3.0"),
]
all_ok = True
for package, required_version in dependencies:
try:
module = importlib.import_module(package)
version = getattr(module, "__version__", "未知")
print_result(f"{package}", True, f"版本: {version}")
except ImportError as e:
print_result(f"{package}", False, f"未安装: {e}")
all_ok = False
return all_ok
def test_api_keys():
"""测试API密钥"""
print_header("测试API密钥环境变量")
api_keys = [
("OPENAI_API_KEY", "OpenAI API密钥"),
("GOOGLE_CSE_ID", "Google自定义搜索引擎ID"),
("GOOGLE_API_KEY", "Google API密钥")
]
available_keys = []
for key, description in api_keys:
value = os.environ.get(key)
if value:
masked_value = value[:4] + "..." + value[-4:] if len(value) > 8 else "***"
print_result(description, True, f"已设置 ({masked_value})")
available_keys.append(key)
else:
print_result(description, False, "未设置")
if available_keys:
print(f"\n📋 可用的API服务: {len(available_keys)}/{len(api_keys)}")
return True
else:
print(f"\n⚠️ 警告: 未设置任何API密钥,将使用模拟模式")
return True # 仍然返回True,因为模拟模式可用
def test_skill_modules():
"""测试技能模块"""
print_header("测试技能模块")
# 添加当前目录到Python路径
if os.getcwd() not in sys.path:
sys.path.insert(0, os.getcwd())
modules_to_test = [
"scripts.book_writer",
"scripts.content_optimizer",
"scripts.material_searcher",
"scripts.install_dependencies"
]
all_ok = True
for module_path in modules_to_test:
try:
module = importlib.import_module(module_path)
print_result(module_path, True, "加载成功")
except Exception as e:
print_result(module_path, False, f"加载失败: {e}")
all_ok = False
return all_ok
def test_directory_structure():
"""测试目录结构"""
print_header("测试目录结构")
required_dirs = [
"scripts",
"assets/templates",
"generated_books",
"temp_files",
"logs"
]
required_files = [
"SKILL.md",
"config.yaml",
"scripts/book_writer.py",
"scripts/content_optimizer.py",
"scripts/material_searcher.py",
"scripts/install_dependencies.py"
]
all_ok = True
# 检查目录
for directory in required_dirs:
if Path(directory).exists():
print_result(f"目录: {directory}", True)
else:
print_result(f"目录: {directory}", False, "不存在")
all_ok = False
# 检查文件
for file_path in required_files:
if Path(file_path).exists():
print_result(f"文件: {file_path}", True)
else:
print_result(f"文件: {file_path}", False, "不存在")
all_ok = False
return all_ok
def test_book_writer():
"""测试书籍生成器"""
print_header("测试书籍生成器(模拟模式)")
try:
from scripts.book_writer import BookWriter
# 创建生成器
writer = BookWriter()
# 测试大纲生成(模拟模式)
print(" 正在测试大纲生成...")
outline = writer.generate_outline("人工智能导论", max_chapters=3)
print(f" 书籍标题: {outline.title}")
print(f" 章节数量: {len(outline.chapters)}")
if len(outline.chapters) > 0:
print(f" 第一章: {outline.chapters[0]['title']}")
print_result("大纲生成", True, f"成功生成{len(outline.chapters)}章")
else:
print_result("大纲生成", False, "未生成任何章节")
return False
# 测试章节扩写(模拟模式)
print(" 正在测试章节扩写...")
if len(outline.chapters) > 0:
chapter = writer.expand_chapter(outline.chapters[0], 1)
print(f" 章节标题: {chapter.title}")
print(f" 内容长度: {len(chapter.content)} 字符")
print_result("章节扩写", True, "成功扩写章节内容")
else:
print_result("章节扩写", False, "没有章节可供扩写")
return False
return True
except Exception as e:
print_result("书籍生成器", False, f"错误: {e}")
return False
def test_content_optimizer():
"""测试内容优化器"""
print_header("测试内容优化器")
try:
from scripts.content_optimizer import ContentOptimizer
optimizer = ContentOptimizer()
test_content = """
# 第一章 引言
本章将介绍相关内容.这是第一段内容.这是第二句话。
- 列表项1
- 列表项2
代码块如下:
```
print("Hello, world!")
```
这里有一个公式 $E=mc^2$ 和另一个 $$\\int_0^\\infty e^{-x^2} dx$$
"""
optimized = optimizer.optimize_content(test_content)
quality = optimizer.validate_content_quality(optimized)
print(f" 原始字符数: {len(test_content)}")
print(f" 优化后字符数: {len(optimized)}")
print(f" 句子数: {quality['sentence_count']}")
print(f" 段落数: {quality['paragraph_count']}")
print(f" 可读性分数: {quality['readability_score']}")
print_result("内容优化器", True, "功能正常")
return True
except Exception as e:
print_result("内容优化器", False, f"错误: {e}")
return False
def generate_test_report():
"""生成测试报告"""
print_header("生成测试报告")
tests = [
("Python版本", test_python_version()),
("依赖包", test_dependencies()),
("API密钥", test_api_keys()),
("技能模块", test_skill_modules()),
("目录结构", test_directory_structure()),
("内容优化器", test_content_optimizer()),
("书籍生成器", test_book_writer()),
]
# 统计结果
passed = sum(1 for _, result in tests if result)
total = len(tests)
print_header("测试总结")
print(f"📊 总计测试: {total} 项")
print(f"✅ 通过: {passed} 项")
print(f"❌ 失败: {total - passed} 项")
print(f"📈 通过率: {(passed/total)*100:.1f}%")
if passed == total:
print("\n🎉 所有测试通过!技能已准备好使用。")
print("\n💡 使用示例:")
print(" 1. python scripts/book_writer.py --action outline --prompt \"机器学习基础\"")
print(" 2. python scripts/book_writer.py --action expand --book-path ml_fundamentals --chapters 1,2,3")
print(" 3. 查看generated_books/目录中的输出")
else:
print("\n⚠️ 部分测试失败,请检查并修复问题。")
print("💡 建议:")
print(" 1. 运行: python scripts/install_dependencies.py")
print(" 2. 设置必要的API密钥环境变量")
print(" 3. 确保所有脚本文件存在")
return passed == total
def main():
"""主函数"""
print("🚀 智能写书技能安装测试")
print("=" * 60)
try:
success = generate_test_report()
return 0 if success else 1
except Exception as e:
print(f"❌ 测试过程中出现错误: {e}")
return 1
if __name__ == "__main__":
sys.exit(main())