上传文件至 /

This commit is contained in:
2026-02-25 03:02:52 +00:00
commit a7354b1d3c
4 changed files with 4850 additions and 0 deletions

208
NovelConfig.py Normal file
View File

@@ -0,0 +1,208 @@
"""
小说生成器配置文件
包含各种高级配置选项和预设模板
"""
from dataclasses import dataclass
from typing import Dict, List, Any, Optional
@dataclass
class AdvancedNovelConfig:
"""高级小说生成配置"""
# 基础配置
genre: str
target_total_chars: int
model: str = "qwen-turbo"
temperature: float = 0.8
# 质量控制
enable_logic_check: bool = True
max_logic_iterations: int = 3
enable_emotion_enhancement: bool = True
enable_dialogue_optimization: bool = True
# 写作风格
writing_style: str = "balanced" # balanced, literary, commercial, dramatic
narrative_perspective: str = "third" # first, third, mixed
tone: str = "neutral" # light, neutral, serious, humorous
# 内容控制
max_characters: int = 8 # 最大角色数量
min_dialogue_ratio: float = 0.3 # 对话占比最小值
max_description_ratio: float = 0.4 # 描写占比最大值
# 技术参数
segment_size: int = 2000 # 分段处理大小
parallel_workers: int = 3 # 并行处理线程数
retry_attempts: int = 3 # 重试次数
# 预设配置模板
PRESET_CONFIGS = {
"精品长篇": AdvancedNovelConfig(
genre="都市逆袭",
target_total_chars=25000,
model="qwen-max",
temperature=0.9,
enable_logic_check=True,
max_logic_iterations=5,
writing_style="literary",
enable_emotion_enhancement=True,
enable_dialogue_optimization=True,
max_characters=12,
parallel_workers=4
)
}
# 写作风格配置
WRITING_STYLES = {
"balanced": {
"description": "平衡风格,适合大众阅读",
"dialogue_ratio": 0.35,
"description_ratio": 0.30,
"action_ratio": 0.35,
"complexity": "medium"
},
"literary": {
"description": "文学风格,注重深度和内涵",
"dialogue_ratio": 0.25,
"description_ratio": 0.45,
"action_ratio": 0.30,
"complexity": "high"
},
"commercial": {
"description": "商业风格,节奏快,易读",
"dialogue_ratio": 0.45,
"description_ratio": 0.25,
"action_ratio": 0.30,
"complexity": "low"
},
"dramatic": {
"description": "戏剧风格,冲突强烈",
"dialogue_ratio": 0.50,
"description_ratio": 0.20,
"action_ratio": 0.30,
"complexity": "medium"
}
}
# 语调配置
TONE_CONFIGS = {
"light": {
"description": "轻松愉快的语调",
"keywords": ["温馨", "轻松", "幽默", "治愈"],
"avoid_keywords": ["沉重", "压抑", "悲伤"]
},
"neutral": {
"description": "中性平衡的语调",
"keywords": ["自然", "真实", "平衡"],
"avoid_keywords": ["过于夸张", "过于沉重"]
},
"serious": {
"description": "严肃深刻的语调",
"keywords": ["深刻", "思考", "内省", "成长"],
"avoid_keywords": ["轻浮", "肤浅"]
},
"humorous": {
"description": "幽默风趣的语调",
"keywords": ["幽默", "风趣", "机智", "轻松"],
"avoid_keywords": ["严肃", "沉重", "悲伤"]
}
}
# 题材扩展配置
EXTENDED_GENRES = {
"都市逆袭": {
"core": "底层主角通过智慧和机遇逐步崛起,每一步都有合理动机和代价",
"typical_characters": ["奋斗主角", "贵人导师", "竞争对手", "支持朋友", "家人"],
"common_conflicts": ["阶层差距", "能力质疑", "机遇选择", "道德考验"],
"emotional_themes": ["自我证明", "成长蜕变", "责任担当", "情感成熟"]
},
"甜宠先婚后爱": {
"core": "两个有血有肉的人从陌生到相知相爱的心理变化过程",
"typical_characters": ["独立女主", "温柔男主", "闺蜜", "家人", "工作伙伴"],
"common_conflicts": ["误解矛盾", "价值观差异", "外界阻力", "内心恐惧"],
"emotional_themes": ["信任建立", "情感觉醒", "相互理解", "共同成长"]
},
"悬疑推理": {
"core": "通过逻辑推理和线索收集,逐步揭开真相的智力较量过程",
"typical_characters": ["推理主角", "神秘反派", "关键证人", "警方助手", "受害者"],
"common_conflicts": ["线索迷雾", "逻辑陷阱", "时间压力", "真相冲击"],
"emotional_themes": ["真相追求", "正义坚持", "智慧较量", "人性探索"]
},
"末世生存": {
"core": "在绝望环境中求生,展现人性光辉与黑暗的生存史诗",
"typical_characters": ["生存主角", "幸存团队", "资源争夺者", "希望守护者", "堕落者"],
"common_conflicts": ["资源争夺", "环境威胁", "人性考验", "道德选择"],
"emotional_themes": ["生存意志", "人性光辉", "团队协作", "希望重燃"]
},
"玄幻升级": {
"core": "在奇幻世界中通过修炼和历练不断突破自我的成长之路",
"typical_characters": ["修炼主角", "师父导师", "同门师兄", "强敌对手", "红颜知己"],
"common_conflicts": ["境界瓶颈", "强敌挑战", "门派争斗", "天道考验"],
"emotional_themes": ["修炼感悟", "师徒情深", "友情考验", "爱情升华"]
},
"校园青春": {
"core": "青春期的成长、友情、初恋和自我发现的故事",
"typical_characters": ["青涩主角", "初恋对象", "好友团体", "老师", "家长"],
"common_conflicts": ["学业压力", "情感困惑", "友情考验", "家庭期待"],
"emotional_themes": ["青春迷茫", "初恋美好", "友情珍贵", "成长痛苦"]
},
"职场励志": {
"core": "职场新人或转型者在工作中的成长和突破",
"typical_characters": ["职场新人", "严厉上司", "竞争同事", "导师前辈", "客户"],
"common_conflicts": ["工作挑战", "人际关系", "职业选择", "价值冲突"],
"emotional_themes": ["专业成长", "自我价值", "团队合作", "领导力"]
},
"家庭温情": {
"core": "家庭成员之间的情感纠葛和最终和解",
"typical_characters": ["家庭成员", "长辈", "晚辈", "亲戚", "邻居"],
"common_conflicts": ["代沟问题", "价值观差异", "生活压力", "情感隔阂"],
"emotional_themes": ["亲情珍贵", "理解包容", "传承责任", "家庭和谐"]
}
}
def get_preset_config(preset_name: str) -> Optional[AdvancedNovelConfig]:
"""获取预设配置"""
return PRESET_CONFIGS.get(preset_name)
def get_writing_style_info(style: str) -> Dict[str, Any]:
"""获取写作风格信息"""
return WRITING_STYLES.get(style, WRITING_STYLES["balanced"])
def get_tone_info(tone: str) -> Dict[str, Any]:
"""获取语调信息"""
return TONE_CONFIGS.get(tone, TONE_CONFIGS["neutral"])
def get_genre_info(genre: str) -> Dict[str, Any]:
"""获取题材信息"""
return EXTENDED_GENRES.get(genre, EXTENDED_GENRES["都市逆袭"])
def list_available_presets() -> List[str]:
"""列出可用的预设配置"""
return list(PRESET_CONFIGS.keys())
def list_available_genres() -> List[str]:
"""列出可用的题材"""
return list(EXTENDED_GENRES.keys())
def list_available_styles() -> List[str]:
"""列出可用的写作风格"""
return list(WRITING_STYLES.keys())
def list_available_tones() -> List[str]:
"""列出可用的语调"""
return list(TONE_CONFIGS.keys())

386
QualityAssessment.py Normal file
View File

@@ -0,0 +1,386 @@
"""
小说质量评估模块
提供多维度的质量评估和改进建议
"""
import re
import json
import logging
from typing import Dict, List, Tuple, Any
from dataclasses import dataclass
from collections import Counter
logger = logging.getLogger(__name__)
@dataclass
class QualityMetrics:
"""质量指标"""
# 基础指标
total_chars: int
effective_chars: int
paragraph_count: int
sentence_count: int
dialogue_count: int
# 比例指标
dialogue_ratio: float
description_ratio: float
action_ratio: float
# 复杂度指标
avg_sentence_length: float
vocabulary_richness: float
repetition_rate: float
# 结构指标
scene_transitions: int
character_mentions: Dict[str, int]
emotion_words: int
# 质量评分
overall_score: float
dimension_scores: Dict[str, float]
class NovelQualityAssessor:
"""小说质量评估器"""
def __init__(self):
# 情感词汇库
self.emotion_words = {
"positive": ["开心", "快乐", "兴奋", "满足", "温暖", "感动", "幸福", "甜蜜", "欣慰", "骄傲"],
"negative": ["难过", "痛苦", "愤怒", "失望", "恐惧", "焦虑", "绝望", "孤独", "委屈", "后悔"],
"complex": ["复杂", "矛盾", "纠结", "挣扎", "无奈", "感慨", "思考", "反思", "领悟", "成长"]
}
# 动作词汇
self.action_words = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
# 描写词汇
self.description_words = ["美丽", "漂亮", "高大", "宽敞", "明亮", "温暖", "寒冷", "炎热", "安静", "嘈杂"]
# 对话标记
self.dialogue_patterns = [
r'[【「"]([^【「"]+)[】」"]', # 【】「」""标记的对话
r'"([^"]+)"', # 英文引号
r"'([^']+)'", # 中文引号
]
def assess_novel_quality(self, text: str, title: str = "") -> QualityMetrics:
"""评估小说质量"""
logger.info("开始质量评估...")
# 基础统计
basic_stats = self._calculate_basic_stats(text)
# 内容分析
content_analysis = self._analyze_content(text)
# 结构分析
structure_analysis = self._analyze_structure(text)
# 语言质量分析
language_analysis = self._analyze_language_quality(text)
# 计算综合评分
dimension_scores = {
"内容丰富度": content_analysis["richness_score"],
"结构合理性": structure_analysis["structure_score"],
"语言质量": language_analysis["language_score"],
"情感表达": content_analysis["emotion_score"],
"对话质量": content_analysis["dialogue_score"]
}
overall_score = sum(dimension_scores.values()) / len(dimension_scores)
# 构建质量指标对象
metrics = QualityMetrics(
total_chars=basic_stats["total_chars"],
effective_chars=basic_stats["effective_chars"],
paragraph_count=basic_stats["paragraph_count"],
sentence_count=basic_stats["sentence_count"],
dialogue_count=basic_stats["dialogue_count"],
dialogue_ratio=content_analysis["dialogue_ratio"],
description_ratio=content_analysis["description_ratio"],
action_ratio=content_analysis["action_ratio"],
avg_sentence_length=language_analysis["avg_sentence_length"],
vocabulary_richness=language_analysis["vocabulary_richness"],
repetition_rate=language_analysis["repetition_rate"],
scene_transitions=structure_analysis["scene_transitions"],
character_mentions=structure_analysis["character_mentions"],
emotion_words=content_analysis["emotion_words"],
overall_score=overall_score,
dimension_scores=dimension_scores
)
logger.info(f"质量评估完成,综合评分: {overall_score:.1f}")
return metrics
def _calculate_basic_stats(self, text: str) -> Dict[str, Any]:
"""计算基础统计信息"""
# 总字符数
total_chars = len(text)
# 有效字符数(中文字符+标点+数字)
lines = [line.strip() for line in text.split('\n') if line.strip()]
combined = ''.join(lines)
chinese_chars = re.findall(r'[\u4e00-\u9fa5]', combined)
punctuation = re.findall(r'[,。!?;:、""''()【】《》]', combined)
numbers = re.findall(r'\d', combined)
effective_chars = len(chinese_chars) + len(punctuation) + len(numbers)
# 段落数
paragraphs = [p.strip() for p in text.split('\n\n') if p.strip()]
paragraph_count = len(paragraphs)
# 句子数
sentences = re.split(r'[。!?]', text)
sentence_count = len([s for s in sentences if s.strip()])
# 对话数
dialogue_count = 0
for pattern in self.dialogue_patterns:
dialogue_count += len(re.findall(pattern, text))
return {
"total_chars": total_chars,
"effective_chars": effective_chars,
"paragraph_count": paragraph_count,
"sentence_count": sentence_count,
"dialogue_count": dialogue_count
}
def _analyze_content(self, text: str) -> Dict[str, Any]:
"""分析内容质量"""
# 对话比例
dialogue_chars = 0
for pattern in self.dialogue_patterns:
matches = re.findall(pattern, text)
dialogue_chars += sum(len(match) for match in matches)
dialogue_ratio = dialogue_chars / len(text) if text else 0
# 描写比例(通过描写词汇估算)
description_count = 0
for word in self.description_words:
description_count += text.count(word)
description_ratio = min(description_count / 100, 0.5) # 归一化
# 动作比例
action_count = 0
for word in self.action_words:
action_count += text.count(word)
action_ratio = min(action_count / 100, 0.5) # 归一化
# 情感词汇统计
emotion_words = 0
for category, words in self.emotion_words.items():
for word in words:
emotion_words += text.count(word)
# 评分计算
richness_score = min(100, (dialogue_ratio * 30 + description_ratio * 40 + action_ratio * 30) * 100)
emotion_score = min(100, emotion_words * 2) # 每个情感词2分
dialogue_score = min(100, dialogue_ratio * 200) # 对话比例评分
return {
"dialogue_ratio": dialogue_ratio,
"description_ratio": description_ratio,
"action_ratio": action_ratio,
"emotion_words": emotion_words,
"richness_score": richness_score,
"emotion_score": emotion_score,
"dialogue_score": dialogue_score
}
def _analyze_structure(self, text: str) -> Dict[str, Any]:
"""分析结构质量"""
# 场景转换(通过时间、地点词汇估算)
scene_markers = ["突然", "接着", "然后", "后来", "此时", "这时", "同时", "与此同时", "第二天", "几天后"]
scene_transitions = 0
for marker in scene_markers:
scene_transitions += text.count(marker)
# 角色提及统计(简单的人名识别)
# 这里使用简单的启发式方法实际应用中可以使用NER
potential_names = re.findall(r'[\u4e00-\u9fa5]{2,3}(?=[,。!?:;]|说|想|看|听)', text)
character_mentions = Counter(potential_names)
# 只保留出现频率较高的(可能是角色名)
character_mentions = {name: count for name, count in character_mentions.items() if count >= 3}
# 结构评分
structure_score = min(100, scene_transitions * 5 + len(character_mentions) * 10)
return {
"scene_transitions": scene_transitions,
"character_mentions": character_mentions,
"structure_score": structure_score
}
def _analyze_language_quality(self, text: str) -> Dict[str, Any]:
"""分析语言质量"""
# 句子平均长度
sentences = re.split(r'[。!?]', text)
valid_sentences = [s.strip() for s in sentences if s.strip()]
avg_sentence_length = sum(len(s) for s in valid_sentences) / len(valid_sentences) if valid_sentences else 0
# 词汇丰富度(简单估算)
words = re.findall(r'[\u4e00-\u9fa5]+', text)
unique_words = set(words)
vocabulary_richness = len(unique_words) / len(words) if words else 0
# 重复率(检查重复的短语)
phrases = []
for i in range(len(text) - 10):
phrase = text[i:i+10]
if re.match(r'^[\u4e00-\u9fa5""''()【】《》]+$', phrase):
phrases.append(phrase)
phrase_counts = Counter(phrases)
repeated_phrases = sum(1 for count in phrase_counts.values() if count > 1)
repetition_rate = repeated_phrases / len(phrases) if phrases else 0
# 语言质量评分
length_score = min(100, max(0, 100 - abs(avg_sentence_length - 20) * 2)) # 理想句长20字
richness_score = vocabulary_richness * 100
repetition_score = max(0, 100 - repetition_rate * 200)
language_score = (length_score + richness_score + repetition_score) / 3
return {
"avg_sentence_length": avg_sentence_length,
"vocabulary_richness": vocabulary_richness,
"repetition_rate": repetition_rate,
"language_score": language_score
}
def generate_improvement_suggestions(self, metrics: QualityMetrics) -> List[str]:
"""生成改进建议"""
suggestions = []
# 基于各维度评分给出建议
if metrics.dimension_scores["内容丰富度"] < 70:
suggestions.append("建议增加更多的场景描写和人物内心活动,提升内容丰富度")
if metrics.dimension_scores["结构合理性"] < 70:
suggestions.append("建议优化故事结构,增加场景转换和情节推进")
if metrics.dimension_scores["语言质量"] < 70:
suggestions.append("建议提升语言表达质量,避免重复用词,丰富词汇")
if metrics.dimension_scores["情感表达"] < 70:
suggestions.append("建议增强情感表达,多使用情感词汇和内心独白")
if metrics.dimension_scores["对话质量"] < 70:
suggestions.append("建议增加对话内容,让角色通过对话展现性格")
# 基于具体指标给出建议
if metrics.dialogue_ratio < 0.2:
suggestions.append("对话比例偏低,建议增加角色对话来推进情节")
if metrics.avg_sentence_length > 30:
suggestions.append("句子平均长度偏长,建议适当使用短句增加节奏感")
if metrics.repetition_rate > 0.1:
suggestions.append("存在较多重复表达,建议使用同义词替换增加表达多样性")
if len(metrics.character_mentions) < 3:
suggestions.append("角色数量偏少,建议增加配角丰富故事内容")
return suggestions
def export_quality_report(self, metrics: QualityMetrics, title: str = "", output_file: str = None) -> str:
"""导出质量报告"""
report = f"""
# 小说质量评估报告
## 基本信息
- 标题: {title or "未命名"}
- 总字符数: {metrics.total_chars:,}
- 有效字符数: {metrics.effective_chars:,}
- 段落数: {metrics.paragraph_count}
- 句子数: {metrics.sentence_count}
- 对话数: {metrics.dialogue_count}
## 综合评分: {metrics.overall_score:.1f}/100
## 各维度评分
- 内容丰富度: {metrics.dimension_scores['内容丰富度']:.1f}/100
- 结构合理性: {metrics.dimension_scores['结构合理性']:.1f}/100
- 语言质量: {metrics.dimension_scores['语言质量']:.1f}/100
- 情感表达: {metrics.dimension_scores['情感表达']:.1f}/100
- 对话质量: {metrics.dimension_scores['对话质量']:.1f}/100
## 详细指标
- 对话比例: {metrics.dialogue_ratio:.1%}
- 描写比例: {metrics.description_ratio:.1%}
- 动作比例: {metrics.action_ratio:.1%}
- 平均句长: {metrics.avg_sentence_length:.1f}
- 词汇丰富度: {metrics.vocabulary_richness:.1%}
- 重复率: {metrics.repetition_rate:.1%}
- 场景转换: {metrics.scene_transitions}
- 情感词汇: {metrics.emotion_words}
## 角色提及统计
"""
for character, count in metrics.character_mentions.items():
report += f"- {character}: {count}\n"
# 添加改进建议
suggestions = self.generate_improvement_suggestions(metrics)
if suggestions:
report += "\n## 改进建议\n"
for i, suggestion in enumerate(suggestions, 1):
report += f"{i}. {suggestion}\n"
# 保存到文件
if output_file:
try:
with open(output_file, 'w', encoding='utf-8') as f:
f.write(report)
logger.info(f"质量报告已保存到: {output_file}")
except Exception as e:
logger.error(f"保存质量报告失败: {str(e)}")
return report
def assess_novel_quality(text: str, title: str = "") -> QualityMetrics:
"""便捷函数:评估小说质量"""
assessor = NovelQualityAssessor()
return assessor.assess_novel_quality(text, title)
def generate_quality_report(text: str, title: str = "", output_file: str = None) -> str:
"""便捷函数:生成质量报告"""
assessor = NovelQualityAssessor()
metrics = assessor.assess_novel_quality(text, title)
return assessor.export_quality_report(metrics, title, output_file)
if __name__ == "__main__":
# 测试代码
sample_text = """
《测试小说》
李明走进办公室,心情复杂。今天是他入职的第一天,既兴奋又紧张。
【你好,我是新来的李明。】他对前台小姐说道。
【欢迎!我是小王,有什么需要帮助的尽管说。】小王热情地回答。
李明感到一阵温暖,看来这里的同事都很友善。他想起了母亲昨天的话:【要好好工作,不要让我们失望。】
突然,一个严肃的声音响起:【你就是新来的?跟我来。】
"""
metrics = assess_novel_quality(sample_text, "测试小说")
print(f"综合评分: {metrics.overall_score:.1f}")
print(f"对话比例: {metrics.dialogue_ratio:.1%}")
print(f"平均句长: {metrics.avg_sentence_length:.1f}")

4145
ViralNovel.py Normal file

File diff suppressed because it is too large Load Diff

111
resume_generation.py Normal file
View File

@@ -0,0 +1,111 @@
#!/usr/bin/env python3
"""
恢复中断的小说生成任务
"""
import os
import sys
import json
from pathlib import Path
def find_unfinished_projects():
"""查找未完成的项目"""
base_dir = Path(__file__).parent
unfinished = []
for item in base_dir.iterdir():
if item.is_dir() and item.name.startswith('n') and item.name[1:].isdigit():
progress_file = item / ".generation_progress.json"
if progress_file.exists():
try:
with open(progress_file, 'r', encoding='utf-8') as f:
progress = json.load(f)
if progress.get('stage') != 'complete':
unfinished.append({
'dir': item.name,
'stage': progress.get('stage', 'unknown'),
'progress': progress.get('progress_percent', 0),
'last_update': progress.get('last_update', 'unknown')
})
except:
continue
return sorted(unfinished, key=lambda x: x['last_update'], reverse=True)
def main():
print("🔍 查找未完成的小说生成任务...")
unfinished = find_unfinished_projects()
if not unfinished:
print("✅ 没有找到未完成的任务")
print("💡 运行 python ViralNovel.py 开始新的生成")
return
print(f"\n📋 找到 {len(unfinished)} 个未完成的任务:")
print("-" * 60)
for i, proj in enumerate(unfinished, 1):
print(f"{i}. 项目: {proj['dir']}")
print(f" 阶段: {proj['stage']}")
print(f" 进度: {proj['progress']:.1f}%")
print(f" 更新: {proj['last_update']}")
print()
if len(unfinished) == 1:
choice = input("是否继续这个任务?(y/n): ").strip().lower()
if choice == 'y':
selected = unfinished[0]
else:
print("❌ 已取消")
return
else:
try:
choice = input(f"选择要继续的任务 (1-{len(unfinished)}): ").strip()
idx = int(choice) - 1
if 0 <= idx < len(unfinished):
selected = unfinished[idx]
else:
print("❌ 无效选择")
return
except ValueError:
print("❌ 请输入数字")
return
print(f"\n🚀 继续生成任务: {selected['dir']}")
print(f"📊 当前进度: {selected['stage']} ({selected['progress']:.1f}%)")
print("⏳ 正在恢复...")
try:
# 导入并运行恢复函数
sys.path.append(str(Path(__file__).parent))
from ViralNovel import resume_generation_from_progress
result = resume_generation_from_progress(selected['dir'])
print(f"\n✅ 生成完成!")
print(f"📖 标题: {result['title']}")
print(f"📁 保存位置: {result['project_dir']}")
except ImportError:
print("❌ 无法导入 ViralNovel 模块")
print("💡 请确保 ViralNovel.py 文件存在")
except Exception as e:
error_str = str(e)
print(f"\n❌ 恢复失败: {error_str}")
if "网络连接" in error_str or "超时" in error_str:
print("\n🔧 网络问题解决建议:")
print("1. 检查网络连接")
print("2. 等待几分钟后重试")
print("3. 运行: python resume_generation.py")
elif "rate limit" in error_str.lower():
print("\n⏰ API调用频率限制:")
print("1. 等待几分钟后重试")
print("2. 运行: python resume_generation.py")
if __name__ == "__main__":
main()