From a7354b1d3c0a4e2401a9398954d8863de39a84a3 Mon Sep 17 00:00:00 2001 From: 18997223426 <12175283714@qq.com> Date: Wed, 25 Feb 2026 03:02:52 +0000 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NovelConfig.py | 208 +++ QualityAssessment.py | 386 ++++ ViralNovel.py | 4145 ++++++++++++++++++++++++++++++++++++++++++ resume_generation.py | 111 ++ 4 files changed, 4850 insertions(+) create mode 100644 NovelConfig.py create mode 100644 QualityAssessment.py create mode 100644 ViralNovel.py create mode 100644 resume_generation.py diff --git a/NovelConfig.py b/NovelConfig.py new file mode 100644 index 0000000..1b334b9 --- /dev/null +++ b/NovelConfig.py @@ -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()) \ No newline at end of file diff --git a/QualityAssessment.py b/QualityAssessment.py new file mode 100644 index 0000000..1961ebb --- /dev/null +++ b/QualityAssessment.py @@ -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}") \ No newline at end of file diff --git a/ViralNovel.py b/ViralNovel.py new file mode 100644 index 0000000..540f4fd --- /dev/null +++ b/ViralNovel.py @@ -0,0 +1,4145 @@ +import os +import re +import json +import time +import random +import logging +import signal +import threading +from dataclasses import dataclass, asdict +from typing import Optional, Dict, Any, List, Tuple +from datetime import datetime +from pathlib import Path + +import dashscope +from dashscope import Generation + +# 导入新模块 +try: + from NovelConfig import AdvancedNovelConfig, get_preset_config, list_available_presets, list_available_genres + ENHANCED_FEATURES = True +except ImportError: + ENHANCED_FEATURES = False + # logger还没有定义,先不记录日志 + +try: + from dotenv import load_dotenv + load_dotenv() +except ImportError: + pass + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +# 现在可以记录增强功能的状态 +if not ENHANCED_FEATURES: + logger.warning("增强功能模块未找到,使用基础功能") + +API_KEY = os.getenv('DASHSCOPE_API_KEY', '') or os.getenv('QWEN_API_KEY', '') +if API_KEY: + dashscope.api_key = API_KEY + + +# 反同质化系统 +ANTI_REPETITION_SYSTEM = { + "plot_patterns": { + "conflict_types": [ + "内心挣扎型", "道德选择型", "能力极限型", "关系背叛型", + "身份揭秘型", "时间压力型", "资源争夺型", "信念冲突型" + ], + "resolution_methods": [ + "智慧解决", "牺牲换取", "意外转折", "合作共赢", + "代价妥协", "创新突破", "情感感化", "力量压制" + ], + "story_structures": [ + "线性推进", "双线并行", "倒叙揭秘", "多视角切换", + "时间跳跃", "梦境现实", "回忆穿插", "悬念设置" + ] + }, + "dialogue_variety": { + "emotional_expressions": { + "愤怒": ["怒火中烧", "咬牙切齿", "拳头紧握", "眼中喷火", "暴跳如雷"], + "喜悦": ["眉开眼笑", "心花怒放", "手舞足蹈", "笑逐颜开", "欣喜若狂"], + "悲伤": ["泪如雨下", "心如刀割", "黯然神伤", "痛不欲生", "肝肠寸断"], + "紧张": ["心跳加速", "手心出汗", "屏息凝神", "如坐针毡", "忐忑不安"], + "惊讶": ["目瞪口呆", "大吃一惊", "瞠目结舌", "惊愕不已", "震惊莫名"] + }, + "speech_patterns": { + "直接型": ["直截了当", "开门见山", "毫不掩饰", "坦率表达"], + "委婉型": ["拐弯抹角", "欲言又止", "暗示暗喻", "含蓄表达"], + "幽默型": ["调侃玩笑", "自嘲解围", "机智应对", "轻松化解"], + "严肃型": ["郑重其事", "一本正经", "严厉警告", "庄重宣告"] + } + }, + "scene_diversity": { + "settings": [ + "古朴庭院", "繁华街市", "幽深洞穴", "高耸山峰", "神秘遗迹", + "宁静湖泊", "茂密森林", "荒芜沙漠", "冰雪世界", "云海仙境" + ], + "atmospheres": [ + "紧张刺激", "温馨和谐", "神秘诡异", "壮丽磅礴", "凄美哀伤", + "热血沸腾", "宁静致远", "危机四伏", "希望满怀", "绝望深渊" + ], + "weather_moods": [ + "阳光明媚", "细雨绵绵", "狂风暴雨", "雪花纷飞", "雾气朦胧", + "星光璀璨", "月色如水", "乌云密布", "彩虹初现", "晨曦微露" + ] + }, + "character_development": { + "growth_triggers": [ + "重大失败", "意外发现", "他人牺牲", "价值冲突", "能力觉醒", + "关系变化", "环境压力", "内心顿悟", "外界刺激", "责任觉醒" + ], + "personality_shifts": [ + "从冲动到冷静", "从自私到无私", "从怯懦到勇敢", "从固执到灵活", + "从孤僻到开朗", "从悲观到乐观", "从依赖到独立", "从骄傲到谦逊" + ] + }, + "forbidden_repetitions": [ + # 从n4发现的高频重复短语 + "手牵手,迎着朝阳", "相视一笑", "心中充满了", "只要彼此相伴", + "没有什么是克服不了的", "新的征程", "书写属于他们的传奇", + "太棒了,你们干得真漂亮", "我们一起加油", "放心,我们", + "### 尾声:梦想与希望", "尾声:梦想与希望", "梦想与希望", + "时光荏苒", "他们的名字成为了", "无人不知、无人不晓", + "在修炼道路上不断前行", "得到了升华", "真正的力量", + "不仅仅来自于", "更来自于", "内心的坚韧和勇气", + + # n4中严重重复的内容 + "心中涌动着复杂的情绪", "眼神中闪烁着坚定", "深吸一口气", + "点了点头", "轻声说道", "坚定地说道", "沉默片刻", + "摸了摸下巴", "紧握长剑", "走上前来", "转过身", + "他想起父亲临终前的话语", "真正的能力,不是来自武力,而是内心的平和与坚定", + "这句话一直萦绕在他心头", "但如何找到这种力量,他却始终迷茫", + "真正的力量不仅仅是外在的能力,更是心灵的韧性与胆识", + "只有内心强大,才能面对一切困难", "心中仿佛有了一丝明悟", + "他决定,要找到属于自己的力量", "无论前方有多少困难", + "他都不会再感到迷茫", "因为他已经找到了属于自己的力量", + + # 重复的对话模式 + "邓华,你在想什么?", "我认为,真正的力量", "现在不是思考的时候", + "我们必须尽快解决眼前的问题", "好,我们上!", "你没事吧?", + "没事,我们必须坚持下去", "这股能量似乎有一个核心", + "我们必须找到并摧毁它", "在那里!", "成功了!", + + # 重复的场景描写 + "洞穴内潮湿阴冷", "石壁上布满了青苔", "空气中弥漫着一股霉味", + "这里太安静了", "我总感觉有什么东西在暗处窥视我们", + "这个洞穴似乎有些奇怪", "好像有一种无形的力量在引导我们", + "看,这些符号", "它们好像是某种古老的文字", + "这些符号我不认识,但它们似乎指向某个方向", + "我们跟着这些符号走吧", "也许它们能带我们找到", + + # 重复的战斗描写 + "大家小心,准备战斗!", "黑暗能量异常强大", "每一击都被反弹回来", + "邓华感到一阵剧痛", "身体不由自主地后退", "咬紧牙关,勉强站稳", + "努力集中精神", "闭上眼睛,感受着周围的气流和能量波动", + "脑海中闪过一道灵光", "挥舞长剑,全力一击", "发出一声震耳欲聋的咆哮", + + # 重复的情感表达 + "心中充满了平静与满足", "这场旅程不仅让他找到了力量", + "更让他找到了真正的自我", "未来还有更多的挑战等着他", + "但他已经准备好迎接这一切", "望向远方,嘴角露出一抹微笑", + "无论发生什么,我们都会一起面对", "是的,我们会一直并肩作战", + "交换眼神,默契一笑", "心中充满了坚定", + + # 重复的章节标题 + "### 幽深洞穴", "### 内心挣扎", "### 牺牲换取", "### 多视角切换", + "### 情感描写", "### 细节描写", "### 结尾", "### 时间跳跃", + "### 冲突与信念", "### 智慧的考验", "### 能力觉醒", "### 回到现实", + "### 未来的征程", "### 终章", "### 月色下的沙漠", "### 意外的发现", + + # 角色重名问题 + "另一个邓华", "这个邓华", "同名的角色", "两个邓华" + ] +} + + +def _extract_high_frequency_phrases(text: str) -> List[str]: + """提取文本中的高频短语,用于反重复检查""" + import re + from collections import Counter + + # 提取2-6字的短语 + phrases = [] + + # 使用正则表达式提取中文短语 + chinese_text = re.sub(r'[^\u4e00-\u9fa5,。!?;:、""''()【】《》]', '', text) + + # 提取2-6字的连续中文短语 + for length in range(2, 7): + for i in range(len(chinese_text) - length + 1): + phrase = chinese_text[i:i+length] + if len(phrase) == length and not re.search(r'[,。!?;:、""''()【】《》]', phrase): + phrases.append(phrase) + + # 统计频率并返回高频短语 + phrase_counts = Counter(phrases) + high_freq_phrases = [phrase for phrase, count in phrase_counts.most_common(50) if count >= 2] + + return high_freq_phrases + + +def detect_and_replace_repetitions(text: str) -> str: + """超强化版重复检测和替换系统 - 彻底解决重复问题""" + import re + import random + + logger.info("开始执行强化版反重复处理...") + + # 严格的重复短语检测和替换 + strict_replacements = { + # 最高频重复短语 - 必须替换 + "轻轻颔首": ["微微点头", "表示赞同", "示意同意", "轻点头颅", "颔首示意"], + "心头泛起": ["内心涌现", "胸中升起", "心中浮现", "情感涌动", "心境变化"], + "胸中涌起": ["内心升腾", "心头浮现", "情感翻涌", "心中激荡", "胸怀激荡"], + "凝视着": ["注视着", "望向", "看向", "眺望", "凝望"], + "情感汹涌": ["内心激荡", "情绪翻腾", "心潮澎湃", "感情起伏", "心境波动"], + "眼神中闪烁着": ["目光中透出", "眼中流露出", "眸子里显现", "眼底浮现", "眼中显露"], + "深吸一口气": ["缓缓吸气", "长长吐息", "调整呼吸", "平复心情", "稳定情绪"], + "点了点头": ["轻轻颔首", "微微点头", "表示赞同", "示意同意", "颔首回应"], + "整理衣襟": ["拂拭衣袖", "理了理衣服", "整理着装", "抚平衣物", "拉直衣角"], + "站起身": ["起身", "站了起来", "从座位上起来", "离开座位", "起立"], + "走上前": ["迈步向前", "上前几步", "走近过来", "靠近过来", "向前走去"], + "转过身": ["回过身", "转身", "掉转身子", "回身", "转向"], + "抬起头": ["仰起头", "抬头", "昂首", "举目", "抬眸"], + "低下头": ["垂下头", "低头", "俯首", "低眉", "垂眸"], + "握紧拳头": ["攥紧双拳", "紧握双手", "拳头紧握", "手握成拳", "双拳紧攥"], + + # 情感表达重复 + "心中充满了": ["内心满怀", "胸中涌起", "心头泛起", "情感汹涌", "心境充盈"], + "眼中充满了": ["目光中满含", "眼底尽是", "眸中盛满", "眼神里透着", "眼中蕴含"], + "脸上露出": ["面上显现", "神情中带着", "表情流露出", "面容上浮现", "脸上显现"], + + # 对话引导重复 + "轻声说道": ["低声道", "柔声说", "细声道", "温和地说", "轻柔地说"], + "坚定地说道": ["断然道", "毅然说", "决然道", "斩钉截铁地说", "坚决地说"], + "沉默片刻": ["静默良久", "默然不语", "陷入沉思", "思索片刻", "短暂沉默"], + + # 场景描写重复 + "空气中弥漫着": ["空中飘散着", "四周充斥着", "周围弥散着", "气息中带着", "空间里充满"], + "阳光透过": ["光线穿过", "日光从", "阳光从", "光芒透过", "光线透射"], + "微风轻拂": ["清风徐来", "风儿轻抚", "微风拂过", "清风吹过", "风轻轻吹"], + + # 心理活动重复 + "心中暗想": ["暗自思忖", "心里琢磨", "默默思考", "内心盘算", "私下思量"], + "陷入沉思": ["深入思考", "沉浸思索", "专心思虑", "认真思考", "仔细思量"], + "若有所思": ["若有所悟", "似有所感", "若有所得", "似有领悟", "若有感触"], + + # 动作描写重复 + "缓缓走来": ["慢慢走近", "徐徐而来", "缓步走来", "慢步走来", "从容走来"], + "快步走向": ["急步走向", "匆忙走向", "快速走向", "疾步走向", "迅速走向"], + "紧紧握住": ["牢牢抓住", "紧紧抓着", "死死握着", "用力握住", "紧握不放"], + + # 时间转换重复 + "与此同时": ["同一时间", "就在此时", "此时此刻", "正在这时", "恰在此时"], + "就在这时": ["正在此刻", "恰在这时", "此时", "这一刻", "当时"], + "不久之后": ["过了一会", "片刻之后", "稍后", "随后", "接着"], + + # 结尾表达重复 + "望向远方": ["眺望远处", "看向远方", "凝望远处", "遥望远方", "目视远方"], + "嘴角露出一抹微笑": ["脸上浮现笑意", "嘴角上扬", "露出淡淡笑容", "面带微笑", "笑容浮现"], + "心中充满了坚定": ["内心无比坚定", "心志坚如磐石", "意志坚定不移", "决心无比坚定", "信念坚定不摇"] + } + + # 统计替换次数 + total_replacements = 0 + + # 执行严格替换 + for original, alternatives in strict_replacements.items(): + count = text.count(original) + if count > 1: + # 保留1个原文,其余全部替换 + replace_times = count - 1 + for i in range(replace_times): + replacement = alternatives[i % len(alternatives)] # 循环使用替换词 + text = text.replace(original, replacement, 1) + total_replacements += 1 + + # 检测并删除重复的段落 + paragraphs = [p.strip() for p in text.split('\n\n') if p.strip() and len(p.strip()) > 30] + paragraphs_to_remove = set() + + for i in range(len(paragraphs)): + for j in range(i + 1, len(paragraphs)): + similarity = _calculate_similarity(paragraphs[i], paragraphs[j]) + if similarity > 0.7: # 降低阈值,更严格检测 + paragraphs_to_remove.add(j) + + if paragraphs_to_remove: + filtered_paragraphs = [p for i, p in enumerate(paragraphs) if i not in paragraphs_to_remove] + text = '\n\n'.join(filtered_paragraphs) + logger.info(f"删除了 {len(paragraphs_to_remove)} 个重复段落") + + # 检测重复的句子模式 + sentences = re.split(r'[。!?]', text) + sentence_counts = {} + for sentence in sentences: + sentence = sentence.strip() + if len(sentence) > 10: # 只检查较长的句子 + if sentence in sentence_counts: + sentence_counts[sentence] += 1 + else: + sentence_counts[sentence] = 1 + + # 删除重复超过2次的句子 + for sentence, count in sentence_counts.items(): + if count > 2: + # 保留2个,删除其余的 + for _ in range(count - 2): + text = text.replace(sentence, '', 1) + + logger.info(f"反重复处理完成,共执行 {total_replacements} 次替换") + return text + + +def _calculate_similarity(text1: str, text2: str) -> float: + """计算两个文本的相似度""" + if not text1 or not text2: + return 0.0 + + # 简单的字符级相似度计算 + words1 = set(text1) + words2 = set(text2) + + intersection = len(words1.intersection(words2)) + union = len(words1.union(words2)) + + return intersection / union if union > 0 else 0.0 + + +def generate_anti_repetition_guidance(genre: str, chapter_count: int) -> str: + """生成强化版反同质化指导""" + import random + + # 根据章节数选择不同的冲突类型和解决方式 + conflict_type = random.choice(ANTI_REPETITION_SYSTEM["plot_patterns"]["conflict_types"]) + resolution_method = random.choice(ANTI_REPETITION_SYSTEM["plot_patterns"]["resolution_methods"]) + story_structure = random.choice(ANTI_REPETITION_SYSTEM["plot_patterns"]["story_structures"]) + + # 选择场景和氛围 + setting = random.choice(ANTI_REPETITION_SYSTEM["scene_diversity"]["settings"]) + atmosphere = random.choice(ANTI_REPETITION_SYSTEM["scene_diversity"]["atmospheres"]) + weather = random.choice(ANTI_REPETITION_SYSTEM["scene_diversity"]["weather_moods"]) + + # 选择角色发展触发器 + growth_trigger = random.choice(ANTI_REPETITION_SYSTEM["character_development"]["growth_triggers"]) + + forbidden_phrases = "、".join(ANTI_REPETITION_SYSTEM["forbidden_repetitions"]) + + return f""" +【强化版反同质化创作指导 - 第{chapter_count}轮】 + +## 🚫 严格禁止的重复内容(违反将重新生成): + +### 禁用短语列表: +{forbidden_phrases} + +### 禁用句式模式: +- "他想起父亲临终前的话语"(已出现多次) +- "真正的力量不仅仅是外在的能力,更是心灵的韧性与胆识"(完全重复) +- "只有内心强大,才能面对一切困难"(高频重复) +- "心中涌动着复杂的情绪"(过度使用) +- "眼神中闪烁着坚定"(重复表达) +- "深吸一口气"(动作重复) +- "点了点头"(动作重复) +- "摸了摸下巴"(动作重复) + +### 禁用对话模式: +- "邓华,你在想什么?"(重复询问) +- "我认为,真正的力量..."(重复说教) +- "现在不是思考的时候"(重复催促) +- "我们必须..."(重复表态) + +### 禁用情节模式: +- 反复进入洞穴探险 +- 反复遇到黑暗能量 +- 反复的内心挣扎独白 +- 反复的哲理对话 +- 反复的战斗→受伤→坚持模式 + +## ✅ 本轮创作要求: + +### 1. 情节创新要求: +- **冲突类型**:{conflict_type} - 必须是全新的冲突,不能重复之前的模式 +- **解决方式**:{resolution_method} - 避免总是用战斗或说教解决问题 +- **叙事结构**:{story_structure} - 打破线性推进,尝试新的叙事方式 +- **场景设定**:{setting},营造{atmosphere}的氛围,天气:{weather} +- **角色成长触发**:通过{growth_trigger}推动角色发展 + +### 2. 对话创新要求: +- 每个角色必须有独特的说话方式,不能千篇一律 +- 对话要推进情节,不能是无意义的哲理讨论 +- 避免重复的对话开头:"邓华,你..." +- 增加角色间的分歧和冲突,不要总是和谐一致 +- 用对话展现角色性格差异,而非重复相同观点 + +### 3. 动作描写创新: +- 禁止使用:摸下巴、深吸气、点头、转身、走上前等重复动作 +- 用新的动作:整理衣襟、凝视远方、轻抚剑柄、踱步思考等 +- 每个角色要有专属的习惯动作 +- 动作要符合当时的情绪和情境 + +### 4. 情感表达创新: +- 禁止"心中充满了"、"眼神中闪烁着"等空泛表达 +- 用具体的生理反应:心跳加速、手心出汗、喉咙发紧等 +- 用环境细节反映内心:注意到平时忽略的细节等 +- 用行为变化体现情感:说话速度、音调变化等 + +### 5. 场景转换要求: +- 不能再进入洞穴、山峰等重复场景 +- 尝试新环境:城镇街道、学院内部、商铺、客栈等 +- 每个场景要有独特的氛围和细节 +- 场景转换要自然,有明确的时间和空间逻辑 + +### 6. 角色互动创新: +- 增加角色间的真实冲突,不要总是和谐 +- 让配角有自己的想法和立场,不要只是附和主角 +- 增加误解、分歧、争论等真实的人际关系 +- 让角色关系有发展和变化 + +## 🎯 质量控制要求: + +### 内容完整性: +- 每1000字必须推进主线情节 +- 不能原地打转或重复之前的内容 +- 每个章节都要有新的信息或发展 +- 避免为了凑字数而重复描写 + +### 逻辑一致性: +- 角色行为要符合已建立的性格 +- 时间线要清晰,不能前后矛盾 +- 世界观设定要保持一致 +- 因果关系要合理 + +### 创新性要求: +- 每轮续写都要有新的元素 +- 不能重复使用相同的情节模式 +- 角色要有新的发现或成长 +- 故事要向前推进,不能停滞 + +## ⚠️ 特别警告: + +1. **绝对禁止重复结尾**:不能出现多个"尾声"、"终章"、"结语" +2. **严禁角色重名**:不能再出现"另一个邓华"这种混乱设定 +3. **禁止重复哲理**:不要反复讨论"真正的力量是什么" +4. **避免套话对话**:每句对话都要有具体目的,不能是空洞的鼓励 +5. **杜绝场景重复**:不能再写洞穴探险、山峰沉思等重复场景 + +## 📝 写作检查清单: + +续写前必须确认: +- [ ] 本段内容是否与之前重复? +- [ ] 角色对话是否有新意? +- [ ] 情节是否向前推进? +- [ ] 是否避免了禁用短语? +- [ ] 场景是否有新鲜感? +- [ ] 角色行为是否符合逻辑? + +**记住:宁可写得少一些,也不要重复之前的内容!** +""" + + +# 人物随机种子系统 +CHARACTER_SEED_POOLS = { + "names": { + "male": [ + # 传统名字 + "林浩", "张明", "王强", "李伟", "陈杰", "刘涛", "赵磊", "孙宇", "周峰", "吴斌", + "马超", "朱辉", "胡军", "郭亮", "何东", "高飞", "梁凯", "宋阳", "邓华", "冯毅", + # 文艺名字 + "苏墨", "顾言", "萧然", "慕容", "司徒", "欧阳", "上官", "诸葛", "轩辕", "夏侯", + "白羽", "墨轩", "云天", "风华", "星辰", "月影", "寒冰", "烈火", "雷霆", "山河", + # 现代名字 + "陈逸飞", "林子轩", "张浩宇", "王梓豪", "李俊杰", "赵子涵", "孙嘉诚", "周志强", + "吴天宇", "马俊熙", "朱子墨", "胡浩然", "郭子轩", "何志远", "高梓轩", "梁浩宇", + # 古风名字 + "慕容白", "司马青", "欧阳墨", "上官寒", "诸葛风", "轩辕天", "夏侯雪", "独孤求", + "令狐冲", "东方不败", "西门吹雪", "南宫飞", "北冥有鱼", "叶孤城", "花满楼", "陆小凤", + # 霸气名字 + "龙傲天", "叶天帝", "萧炎", "林动", "石昊", "牧尘", "萧晨", "秦尘", "叶辰", "林凡", + "王腾", "姬昊", "帝天", "古青", "萧叶", "楚风", "洛尘", "凌霄", "战天", "破军", + # 温和名字 + "温如玉", "君莫笑", "顾清欢", "沈清秋", "谢怜", "花城", "魏无羡", "蓝忘机", "江澄", "聂怀桑" + ], + "female": [ + # 传统名字 + "李薇", "王雪", "张丽", "陈美", "刘芳", "赵敏", "孙娜", "周静", "吴琳", "马欣", + "朱莉", "胡蓉", "郭婷", "何洁", "高雅", "梁慧", "宋颖", "邓萍", "冯娟", "田甜", + # 古典美名 + "苏若汐", "顾倾城", "萧雨涵", "慕容雪", "司徒月", "欧阳晴", "上官婉儿", "诸葛青青", + "轩辕紫", "夏侯霜", "白素贞", "墨兰", "云裳", "风铃", "星月", "影儿", "寒梅", "烈焰", + # 现代名字 + "陈诗涵", "林雨萱", "张梓涵", "王欣怡", "李思雨", "赵雨桐", "孙梦琪", "周诗雅", + "吴雨欣", "马梓萱", "朱雨涵", "胡诗涵", "郭梦瑶", "何雨桐", "高梓涵", "梁诗雨", + # 仙气名字 + "慕容仙", "司马灵", "欧阳雪", "上官月", "诸葛云", "轩辕霜", "夏侯冰", "独孤雁", + "令狐蓉", "东方玉", "西门雪", "南宫舞", "北冥雪", "叶轻舞", "花无缺", "陆雪琪", + # 霸气女名 + "龙女帝", "叶青帝", "萧薰儿", "林青檀", "石紫嫣", "牧锦", "萧潇", "秦瑶", "叶倾仙", "林仙儿", + "王语嫣", "姬如雪", "帝女花", "古薰儿", "萧雪", "楚倾歌", "洛神", "凌雪", "战姬", "破晓", + # 温婉名字 + "温柔", "君如意", "顾盼兮", "沈佳期", "谢安然", "花解语", "魏璎珞", "蓝湛", "江雪", "聂小倩" + ] + }, + "personalities": [ + # 基础性格 + "内向谨慎", "外向开朗", "理性冷静", "感性温暖", "倔强坚持", "灵活变通", + "完美主义", "随性自由", "责任感强", "创新冒险", "传统保守", "叛逆独立", + "乐观积极", "悲观现实", "敏感细腻", "粗犷豪爽", "温和包容", "激进直接", + # 复合性格 + "外冷内热", "表面温和内心坚定", "看似散漫实则专注", "外表柔弱内心强大", + "表面冷漠实则关怀", "看似冲动实则深思", "外表严肃内心温柔", "表面随和内有原则", + "看似懒散实则敏锐", "外表高冷内心火热", "表面谦逊实则自信", "看似天真实则睿智", + # 特殊性格 + "神秘莫测", "古灵精怪", "腹黑毒舌", "天然呆萌", "高冷禁欲", "温润如玉", + "霸道强势", "温柔体贴", "机智狡黠", "单纯善良", "成熟稳重", "活泼可爱", + "孤傲不群", "平易近人", "心机深沉", "直率真诚", "优雅高贵", "接地气亲民" + ], + "backgrounds": [ + # 家庭背景 + "贫困家庭出身", "中产阶级家庭", "富裕家庭背景", "单亲家庭成长", "留守儿童经历", + "城市精英家庭", "农村朴实家庭", "书香门第", "商人家庭", "军人家庭", + "艺术家庭", "学者家庭", "普通工人家庭", "创业家庭", "移民家庭", + # 特殊背景 + "孤儿院长大", "被收养的孩子", "家族企业继承人", "没落贵族后裔", "新兴富豪之子", + "外交官家庭", "医生世家", "教师家庭", "警察家庭", "消防员家庭", + "农民工家庭", "个体户家庭", "公务员家庭", "科研工作者家庭", "文艺工作者家庭", + # 复杂背景 + "父母离异重组家庭", "隔代抚养", "寄养家庭", "国际化家庭", "军政世家", + "商政联姻家庭", "学术世家", "医学世家", "法律世家", "金融世家" + ], + "occupations": { + "都市逆袭": [ + # 基础职业 + "程序员", "设计师", "销售", "会计", "文员", "服务员", "快递员", "保安", "清洁工", "司机", + # 新兴职业 + "网络主播", "自媒体博主", "电商运营", "游戏策划", "UI设计师", "产品经理", "数据分析师", + "新媒体运营", "短视频制作", "网络作家", "独立开发者", "自由摄影师", "健身教练", "营养师", + # 传统职业 + "厨师", "理发师", "修理工", "装修工", "外卖员", "网约车司机", "便利店员工", "超市收银员" + ], + "甜宠先婚后爱": [ + # 高端职业 + "律师", "医生", "教师", "设计师", "编辑", "心理咨询师", "金融分析师", "市场营销", "人力资源", "建筑师", + # 创意职业 + "服装设计师", "珠宝设计师", "室内设计师", "广告创意", "品牌策划", "公关经理", "活动策划", + "艺术策展人", "画廊经理", "时尚编辑", "美食评论家", "旅游博主", "生活方式博主", + # 商业职业 + "投资顾问", "企业顾问", "管理培训师", "商业分析师", "风险评估师", "项目经理" + ], + "悬疑推理": [ + # 调查类 + "侦探", "警察", "法医", "记者", "律师", "心理学家", "私家侦探", "档案管理员", "图书管理员", "研究员", + # 专业类 + "犯罪心理学家", "司法鉴定师", "网络安全专家", "数据恢复专家", "监控分析师", "情报分析员", + "保险调查员", "企业内审", "反欺诈专家", "密码学专家", "行为分析师", "痕迹检验师" + ], + "末世生存": [ + # 军事类 + "军人", "特种兵", "雇佣兵", "保镖", "安保人员", "武器专家", "战术专家", "军事顾问", + # 技能类 + "医生", "工程师", "农民", "猎人", "厨师", "机械师", "电工", "护士", "教师", "建筑师", + # 生存类 + "野外生存专家", "应急救援员", "消防员", "搜救队员", "登山向导", "户外教练", "求生专家" + ], + "玄幻升级": [ + # 修炼类 + "修炼者", "炼药师", "阵法师", "剑修", "体修", "术法师", "驯兽师", "符箓师", "器修", "丹师", + # 特殊类 + "占卜师", "风水师", "驱魔师", "召唤师", "元素法师", "幻术师", "毒师", "医师", "乐师", "棋师", + # 门派类 + "宗门弟子", "散修", "魔修", "佛修", "道修", "儒修", "武修", "法修", "鬼修", "妖修" + ] + }, + "flaws": [ + # 性格缺陷 + "过度自尊", "缺乏自信", "控制欲强", "优柔寡断", "情绪化", "固执己见", + "完美主义", "拖延症", "社交恐惧", "信任困难", "冲动鲁莽", "过度敏感", + "逃避现实", "依赖他人", "嫉妒心强", "报复心理", "自我中心", "悲观消极", + # 行为缺陷 + "说话不经大脑", "容易被激怒", "记仇", "小心眼", "爱面子", "死要面子活受罪", + "三分钟热度", "半途而废", "眼高手低", "好高骛远", "自以为是", "刚愎自用", + "多疑猜忌", "患得患失", "犹豫不决", "瞻前顾后", "畏首畏尾", "胆小怕事", + # 深层缺陷 + "童年阴影", "被抛弃恐惧", "失败恐惧", "成功恐惧", "亲密关系恐惧", "承诺恐惧", + "被评判恐惧", "不完美恐惧", "被拒绝恐惧", "孤独恐惧", "死亡恐惧", "未知恐惧" + ], + "desires": [ + # 基本需求 + "获得认可", "追求自由", "寻找真爱", "实现梦想", "保护家人", "证明自己", + "获得财富", "追求权力", "寻求安全", "渴望冒险", "追求知识", "获得尊重", + "寻找归属", "实现价值", "获得救赎", "追求完美", "寻求刺激", "获得平静", + # 深层渴望 + "被无条件爱着", "找到人生意义", "超越父母期待", "打破家族诅咒", "改变世界", + "留下传奇", "获得永生", "掌控命运", "拯救他人", "复仇雪恨", "弥补遗憾", + "重新开始", "找回初心", "守护信念", "追求真理", "探索未知", "创造奇迹", + # 情感需求 + "被理解", "被信任", "被需要", "被依赖", "被崇拜", "被原谅", "被接纳", + "被保护", "被珍惜", "被记住", "被感激", "被尊敬", "被欣赏", "被支持" + ], + "genre_specific": { + "悬疑推理": { + "special_traits": [ + "观察敏锐", "逻辑严密", "记忆超群", "直觉准确", "心理洞察", "细节控", + "推理天才", "破案如神", "洞察人心", "记忆宫殿", "逻辑怪物", "真相猎手", + "证据收集狂", "线索敏感", "疑点发现者", "谎言识别器", "动机分析师", "时间线专家" + ], + "investigation_skills": [ + "现场勘查", "证据分析", "心理分析", "逻辑推理", "信息整合", "人际交往", + "审讯技巧", "跟踪监视", "伪装潜入", "密码破译", "痕迹还原", "时间推算", + "动机分析", "关系梳理", "数据挖掘", "网络追踪", "心理画像", "行为预测" + ] + }, + "末世生存": { + "survival_skills": [ + "野外求生", "医疗急救", "机械维修", "食物获取", "武器制作", "团队领导", + "资源搜集", "陷阱制作", "庇护所建造", "水源净化", "食物保存", "伤口处理", + "药物调配", "工具制作", "火种保存", "方向辨识", "天气预测", "危险预警" + ], + "mental_traits": [ + "意志坚强", "适应力强", "危机意识", "团队合作", "资源管理", "道德坚持", + "冷静理智", "果断决策", "牺牲精神", "保护欲强", "生存本能", "危机应对", + "压力承受", "情绪控制", "希望维持", "信念坚定", "责任担当", "人性坚守" + ] + }, + "玄幻升级": { + "cultivation_types": [ + "剑道天才", "体质特殊", "悟性超群", "意志坚定", "机缘深厚", "血脉觉醒", + "天生道体", "先天灵根", "混沌体质", "不灭金身", "万法不侵", "天眼通", + "神识强大", "元神特异", "灵魂变异", "天赋异禀", "根骨奇佳", "慧根深厚" + ], + "spiritual_roots": [ + "金系", "木系", "水系", "火系", "土系", "雷系", "风系", "冰系", "暗系", "光系", + "混沌", "阴阳", "五行", "时间", "空间", "生命", "死亡", "毁灭", "创造", "轮回", + "因果", "命运", "虚无", "真实", "梦幻", "永恒", "瞬息", "无限", "有限", "超脱" + ], + "special_abilities": [ + "过目不忘", "举一反三", "触类旁通", "融会贯通", "无师自通", "天人合一", + "心有灵犀", "预知未来", "回溯过去", "洞察本质", "看破虚妄", "参透天机" + ] + } + } +} + + +def generate_random_character_seed(character_type: str = "main", genre: str = "都市逆袭") -> Dict[str, Any]: + """生成随机角色种子 - 增强版""" + seed = random.randint(1000, 9999) + random.seed(seed) + + gender = random.choice(["male", "female"]) + name = random.choice(CHARACTER_SEED_POOLS["names"][gender]) + personality = random.choice(CHARACTER_SEED_POOLS["personalities"]) + background = random.choice(CHARACTER_SEED_POOLS["backgrounds"]) + + # 根据题材选择职业 + if genre in CHARACTER_SEED_POOLS["occupations"]: + occupation = random.choice(CHARACTER_SEED_POOLS["occupations"][genre]) + else: + occupation = random.choice(CHARACTER_SEED_POOLS["occupations"]["都市逆袭"]) + + flaw = random.choice(CHARACTER_SEED_POOLS["flaws"]) + desire = random.choice(CHARACTER_SEED_POOLS["desires"]) + + # 添加题材特定属性 + special_attrs = {} + if genre in CHARACTER_SEED_POOLS["genre_specific"]: + genre_data = CHARACTER_SEED_POOLS["genre_specific"][genre] + for attr_type, attr_list in genre_data.items(): + special_attrs[attr_type] = random.choice(attr_list) + + # 生成角色关系倾向 + relationship_style = random.choice([ + "独来独往型", "团队合作型", "领导者型", "追随者型", "调解者型", "挑战者型", + "保护者型", "被保护型", "导师型", "学生型", "竞争者型", "支持者型" + ]) + + # 生成说话风格 + speech_patterns = [ + "简洁直接", "温和委婉", "幽默风趣", "严肃正经", "文雅书面", "口语化", + "逻辑性强", "感性表达", "反问较多", "喜欢举例", "爱用比喻", "习惯沉默" + ] + speech_style = random.choice(speech_patterns) + + # 生成习惯动作 + habit_actions = [ + "思考时摸下巴", "紧张时咬唇", "兴奋时搓手", "生气时皱眉", "无聊时转笔", + "专注时眯眼", "困惑时挠头", "开心时笑眼", "担心时踱步", "放松时伸懒腰", + "思考时凝视远方", "紧张时整理衣襟", "习惯性轻抚剑柄", "喜欢双手抱胸" + ] + habit_action = random.choice(habit_actions) + + # 重置随机种子以避免影响其他随机生成 + random.seed() + + result = { + "seed": seed, + "name": name, + "gender": gender, + "personality": personality, + "background": background, + "occupation": occupation, + "flaw": flaw, + "desire": desire, + "character_type": character_type, + "genre": genre, + "relationship_style": relationship_style, + "speech_style": speech_style, + "habit_action": habit_action + } + + # 添加特殊属性 + result.update(special_attrs) + + return result + + +def generate_character_team(genre: str, team_size: int = 4) -> List[Dict[str, Any]]: + """生成一个角色团队,确保角色间有互补性和冲突性""" + team = [] + used_names = set() + used_personalities = set() + + # 生成主角 + main_char = generate_random_character_seed("main", genre) + while main_char["name"] in used_names: + main_char = generate_random_character_seed("main", genre) + + team.append(main_char) + used_names.add(main_char["name"]) + used_personalities.add(main_char["personality"]) + + # 生成配角,确保多样性 + for i in range(team_size - 1): + attempts = 0 + while attempts < 20: # 最多尝试20次 + char = generate_random_character_seed("supporting", genre) + + # 确保名字不重复 + if char["name"] in used_names: + attempts += 1 + continue + + # 尽量确保性格不重复(但不强制) + if len(used_personalities) < 10 and char["personality"] in used_personalities: + attempts += 1 + continue + + team.append(char) + used_names.add(char["name"]) + used_personalities.add(char["personality"]) + break + else: + # 如果20次都没找到合适的,就用最后一个生成的 + team.append(char) + + return team + + +@dataclass +class ViralNovelConfig: + 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_progress_save: bool = True + enable_content_filter: bool = True + max_retry_attempts: int = 5 + # 新增:故事完整性控制 + min_chars_before_ending: int = 15000 # 最少15000字才允许结尾 + max_chars_limit: int = 50000 # 最大字数限制,防止无限生成 + story_completeness_check: bool = True # 启用故事完整性检查 + + +@dataclass +class GenerationProgress: + """生成进度数据""" + project_dir: str + stage: str # "bible", "title", "story", "refine", "complete" + progress_percent: float + bible: Optional[Dict[str, Any]] = None + title: Optional[str] = None + story: Optional[str] = None + start_time: Optional[str] = None + last_update: Optional[str] = None + error_count: int = 0 + + +GENRE_TEMPLATES: Dict[str, Dict[str, Any]] = { + "都市逆袭": { + "core": "底层主角通过智慧和机遇逐步崛起,每一步都有合理动机和代价", + "character_depth": { + "主角": "有明确过往创伤、性格缺陷、成长动机,不是完美人设", + "反派": "有自己的逻辑和立场,不是纯粹的恶人", + "配角": "各有独特性格和说话方式,不是工具人" + }, + "plot_structure": { + "铺垫比例": "30%用于人物背景和世界观建立", + "冲突升级": "每个冲突都有前因后果,不突兀", + "情感线": "与主线紧密结合,不是装饰品" + }, + "writing_focus": "重点描写人物内心活动、动机变化、情感冲突" + }, + "甜宠先婚后爱": { + "core": "两个有血有肉的人从陌生到相知相爱的心理变化过程", + "character_depth": { + "女主": "有自己的事业追求、性格弱点、成长历程", + "男主": "不是霸总模板,有温柔也有脆弱的一面", + "配角": "闺蜜、同事、家人都有独特个性" + }, + "plot_structure": { + "情感递进": "从排斥→好奇→心动→深爱,每一步都有具体事件触发", + "误会设置": "基于性格差异的合理误会,不是狗血剧情", + "甜蜜时刻": "细节描写,不是空洞的'很甜'" + }, + "writing_focus": "重点描写微表情、小动作、内心独白、情感变化" + }, + "悬疑推理": { + "core": "通过逻辑推理和线索收集,逐步揭开真相的智力较量过程", + "character_depth": { + "主角": "敏锐观察力、理性思维、有推理天赋但也有盲点", + "反派": "智商在线、动机复杂、手法精巧的对手", + "配角": "各有隐秘、可能是证人也可能是嫌疑人" + }, + "plot_structure": { + "线索布局": "40%用于线索埋设和氛围营造", + "推理过程": "逻辑严密、步步深入、有误导也有突破", + "真相揭示": "意外但合理,所有线索都能串联" + }, + "writing_focus": "重点描写细节观察、逻辑推理、心理博弈、氛围营造" + }, + "末世生存": { + "core": "在绝望环境中求生,展现人性光辉与黑暗的生存史诗", + "character_depth": { + "主角": "有生存技能、道德底线、但也会面临艰难选择", + "幸存者": "各有背景、技能、价值观,形成复杂的生存群体", + "反派": "为生存不择手段、或被环境扭曲的人" + }, + "plot_structure": { + "世界构建": "30%用于末世环境和生存规则建立", + "生存挑战": "资源争夺、环境威胁、人性考验层层递进", + "希望主线": "在绝望中寻找重建文明的可能" + }, + "writing_focus": "重点描写生存技巧、环境威胁、人性冲突、团队协作" + }, + "玄幻升级": { + "core": "在奇幻世界中通过修炼和历练不断突破自我的成长之路", + "character_depth": { + "主角": "有修炼天赋、坚定意志、但也有成长瓶颈和内心挣扎", + "师父": "智慧深邃、有自己的过往和秘密", + "同门": "各有特长、性格、竞争与友谊并存" + }, + "plot_structure": { + "世界观建设": "35%用于修炼体系和世界规则建立", + "升级历程": "境界突破有合理过程,不是简单的数值增长", + "试炼考验": "每次升级都伴随着心性和实力的双重考验" + }, + "writing_focus": "重点描写修炼感悟、战斗技巧、师徒情谊、境界突破" + } +} + + +def _get_advanced_writing_system() -> str: + """获取高级写作系统 - 解决流水账、突兀、重复、矛盾、角色符号化问题""" + return """ +【高级写作系统 - 解决常见AI写作问题】 + +## 一、反流水账写作法 + +### 1. 情感驱动叙事 +❌ 流水账:他走进办公室,坐下来,打开电脑,开始工作。 +✅ 情感驱动:李明推开办公室的门,熟悉的咖啡香味扑面而来。他深吸一口气,试图平复刚才在电梯里遇到前女友时的心跳。桌上那份离职申请书静静躺着,像是在嘲笑他的犹豫不决。 + +### 2. 冲突张力写法 +- 每个场景都要有内在冲突(内心挣扎、两难选择、情感冲突) +- 每个对话都要有潜台词(表面说A,实际想B) +- 每个动作都要有情感色彩(不是机械动作,是情感表达) + +### 3. 细节质感提升 +- 用具体细节替代抽象描述 +- 用感官体验替代概念表达 +- 用对比反差制造印象深刻的画面 + +## 二、铺垫与因果系统 + +### 1. 三层铺垫法 +**远程铺垫**(开篇埋下)→ **中程铺垫**(中段呼应)→ **近程铺垫**(爆发前预兆) + +示例: +- 远程:开篇提到主角怕黑(童年创伤) +- 中程:几次在黑暗中的不适反应 +- 近程:关键时刻必须进入黑暗空间,内心挣扎 +- 爆发:克服恐惧,完成蜕变 + +### 2. 因果链条设计 +每个重要情节都要有: +- **动机**:为什么这样做? +- **阻碍**:遇到什么困难? +- **选择**:如何决定? +- **后果**:产生什么影响? +- **反思**:角色如何成长? + +### 3. 情节预告系统 +- 用细节暗示即将发生的事 +- 用角色的不安情绪预告危机 +- 用环境描写烘托气氛变化 + +## 三、防重复系统(严格执行) + +### 1. 词汇变化库(必须使用) +- **情感词汇轮换**: + - 愤怒:恼火→暴躁→怒不可遏→勃然大怒→怒火中烧 + - 高兴:开心→欣喜→狂欢→兴奋不已→心花怒放 + - 紧张:不安→焦虑→惶恐→心惊胆战→忐忑不安 + - 悲伤:难过→沮丧→痛苦→心如刀割→悲痛欲绝 + +- **动作词汇轮换**: + - 走:踱步→疾行→拖着脚步→大步流星→蹑手蹑脚 + - 看:凝视→瞥见→注视→扫视→凝望→窥视 + - 说:低语→呢喃→高声→轻声→大声→细声 + +- **表情词汇轮换**: + - 笑:微笑→轻笑→大笑→苦笑→冷笑→狞笑 + - 皱眉:蹙眉→紧锁眉头→眉头紧皱→愁眉不展 + +### 2. 句式变化法(强制要求) +- **禁止重复的句式**: + - 避免连续使用"他知道"、"他想"、"他觉得" + - 避免重复"...的时候"、"就在这时"、"与此同时" + - 避免重复"心中一沉"、"深吸一口气"、"点了点头" + +- **句式轮换策略**: + - 长短句交替:长句描写,短句冲击 + - 语气变化:陈述→疑问→感叹→反问 + - 视角切换:第三人称→内心独白→环境描写 + +### 3. 情节螺旋上升(避免重复情节) +- 相似情况下角色反应的变化 +- 同类冲突的不同层次处理 +- 重复中的递进和深化 + +## 四、逻辑一致性系统 + +### 1. 角色行为逻辑 +- 每个角色都有核心性格特征(3-5个关键词) +- 所有行为都要符合性格逻辑 +- 性格改变必须有充分的事件触发 + +### 2. 世界观一致性 +- 建立明确的世界规则 +- 所有情节都在规则内发生 +- 规则改变必须有合理解释 + +### 3. 时间线管理 +- 明确每个事件的时间点 +- 确保前后事件的逻辑顺序 +- 避免时间矛盾 + +## 五、角色立体化系统 + +### 1. 角色三维构建法 +**外在层**:外貌、职业、社会身份 +**行为层**:说话方式、行为习惯、反应模式 +**内核层**:价值观、恐惧、渴望、创伤 + +### 2. 角色差异化标签 +每个角色必须有: +- **独特口头禅**:体现性格的说话习惯 +- **专属动作**:紧张时的小动作、思考时的习惯 +- **情感触发点**:什么最容易让他们情绪波动 +- **核心矛盾**:内心最大的冲突是什么 + +### 3. 角色关系网络 +- 每个角色与主角的关系都不同 +- 角色之间也要有独立的关系线 +- 通过关系冲突推动情节发展 + +## 六、情感共鸣写作法 + +### 1. 共同体验挖掘 +- 找到读者都有过的情感体验 +- 用具体场景唤起共鸣 +- 避免过于特殊的经历 + +### 2. 情感层次递进 +- 表面情感→深层情感→核心情感 +- 从个人情感→关系情感→社会情感 +- 从当下情感→过往情感→未来期待 + +### 3. 情感冲突设计 +- 理智与情感的冲突 +- 不同价值观的冲突 +- 现实与理想的冲突 + +## 七、节奏控制系统 + +### 1. 张弛有度 +- 高潮后必须有缓冲 +- 平静中埋下不安因子 +- 用小冲突串联大冲突 + +### 2. 信息投放节奏 +- 关键信息分批透露 +- 用悬念控制阅读节奏 +- 在读者期待最高时给予满足 + +### 3. 情感波动曲线 +- 设计情感的起伏变化 +- 避免情感平线或过山车 +- 让读者的心情跟着角色走 + +## 八、具体写作指令 + +### 开篇500字要求: +1. 建立主角的核心冲突(内心挣扎) +2. 展示独特的世界观细节 +3. 埋下至少2个伏笔 +4. 让读者对主角产生情感连接 +5. 制造悬念或期待 + +### 每1000字检查点: +1. 是否推进了主线情节? +2. 是否深化了角色关系? +3. 是否有新的情感层次? +4. 是否避免了重复表达? +5. 是否保持了逻辑一致? + +### 对话写作要求(必须严格遵守): +1. **对话占比要求**:对话内容必须占总文本的30%以上 +2. **对话格式要求**:所有对话必须使用中文引号标记,格式如下: + - 直接对话:"角色说的话" + - 带说话人:"角色说的话,"他说道。 + - 示例:"林浩,你在这儿干嘛呢?"李薇的声音中带着一丝调侃。 +3. **角色语言差异化**:每个角色说话方式必须不同 + - 主角:内敛、谨慎、有礼貌 + - 导师型角色:睿智、引导性、温和 + - 对手型角色:强势、直接、带攻击性 + - 朋友型角色:轻松、支持性、亲近 +4. **对话功能性**: + - 推进情节发展(不是闲聊) + - 展现角色性格和关系 + - 传递重要信息 + - 制造冲突和张力 +5. **对话真实性**: + - 符合角色身份和教育背景 + - 体现当时的情绪状态 + - 有潜台词和言外之意 + - 自然流畅,不生硬 + +### 强制对话场景: +- 每个重要情节转折都必须有对话 +- 角色初次见面必须有对话 +- 冲突场面必须有对话交锋 +- 情感变化时必须有内心或外在对话 +- 每1000字至少要有3-5段对话 + +### 场景转换要求: +1. 用情感状态连接场景 +2. 通过环境变化体现内心变化 +3. 避免突兀的跳跃 +4. 保持叙事的连贯性 +5. 用细节暗示时间流逝 +""" + + +def _get_logic_consistency_system() -> str: + """逻辑一致性检查和修复系统""" + return """ +【逻辑一致性检查系统 - 确保故事逻辑严密】 + +## 一、角色行为一致性检查 + +### 1. 核心性格特征追踪 +- 每个角色必须有3-5个核心性格关键词 +- 所有行为、对话、反应都必须符合这些特征 +- 性格改变必须有充分的事件触发和心理过程 + +### 2. 角色能力边界检查 +- 角色的知识水平、技能范围要保持一致 +- 不能突然掌握之前没有的能力 +- 角色的社会地位、经济条件要前后一致 + +### 3. 角色关系动态追踪 +- 角色之间的关系变化要有合理过程 +- 情感变化要有具体的触发事件 +- 对话语气要符合当前关系状态 + +## 二、时间线逻辑检查 + +### 1. 事件时序验证 +- 所有事件按时间顺序排列 +- 检查是否有时间倒流或跳跃 +- 确保事件持续时间合理 + +### 2. 因果关系验证 +- 每个结果都有明确的原因 +- 原因发生在结果之前 +- 因果链条完整无断裂 + +### 3. 角色行程合理性 +- 角色移动时间要符合实际 +- 不能同时出现在不同地点 +- 角色的精力和时间分配要合理 + +## 三、世界观规则检查 + +### 1. 物理规则一致性 +- 世界的基本物理法则要统一 +- 特殊设定要前后呼应 +- 不能违反已建立的世界规则 + +### 2. 社会规则一致性 +- 社会制度、法律、习俗要统一 +- 角色的社会行为要符合设定 +- 经济、政治背景要保持一致 + +### 3. 技术水平一致性 +- 科技发展水平要统一 +- 不能出现超越时代的技术 +- 信息传播方式要符合设定 + +## 四、情节逻辑检查 + +### 1. 动机合理性检查 +- 每个角色的行为都有明确动机 +- 动机要符合角色性格和处境 +- 动机强度要与行为程度匹配 + +### 2. 冲突升级合理性 +- 冲突升级要有合理的触发点 +- 冲突强度要逐步递进 +- 解决方案要符合角色能力 + +### 3. 转折点合理性 +- 重大转折要有充分铺垫 +- 转折的触发因素要合理 +- 转折后的发展要符合逻辑 + +## 五、对话逻辑检查 + +### 1. 信息传递一致性 +- 角色知道的信息要前后一致 +- 不能突然知道不该知道的事 +- 信息获取渠道要合理 + +### 2. 语言风格一致性 +- 每个角色的说话方式要固定 +- 教育背景影响语言水平 +- 情绪状态影响说话方式 + +### 3. 对话内容合理性 +- 对话要推进情节或展现性格 +- 避免无意义的闲聊 +- 对话长度要符合情境 + +## 六、逻辑检查执行流程 + +### 1. 分段检查(每1000字) +- 提取关键信息点 +- 与前文进行对比验证 +- 标记潜在的逻辑问题 + +### 2. 全文检查(完成后) +- 构建完整的角色档案 +- 绘制时间线图谱 +- 验证世界观一致性 + +### 3. 问题修复流程 +- 识别逻辑矛盾点 +- 分析矛盾原因 +- 提供修复方案 +- 重新生成问题段落 + +## 七、逻辑检查标准 + +### 严重逻辑错误(必须修复): +- 角色性格严重OOC +- 时间线明显错误 +- 世界观规则冲突 +- 因果关系断裂 + +### 轻微逻辑问题(建议修复): +- 细节前后不一致 +- 角色反应略显突兀 +- 信息传递不够清晰 +- 动机解释不够充分 + +### 检查通过标准: +- 无严重逻辑错误 +- 轻微问题少于3个 +- 角色行为符合设定 +- 情节发展合理自然 +""" + + +def _get_enhanced_character_system() -> str: + """增强版角色发展系统""" + return """ +【增强版角色发展系统 - 打造真正立体的角色】 + +## 一、角色核心档案建立 + +### 1. 基础信息档案 +``` +角色姓名:[具体姓名] +年龄:[具体年龄] +职业:[具体职业及工作内容] +外貌特征:[3-5个显著特征] +家庭背景:[家庭结构、经济状况、教育背景] +``` + +### 2. 性格核心标签(必须具体化) +``` +核心性格:[3个核心特征,如:敏感、倔强、善良] +性格缺陷:[1-2个明显缺陷,如:过度自尊、不信任他人] +隐藏特质:[1个不易察觉的特质,如:内心脆弱、渴望被理解] +价值观:[核心价值观,如:公平正义、家庭至上] +恐惧点:[最害怕的事物,如:被抛弃、失去控制] +``` + +### 3. 行为模式档案 +``` +说话习惯:[口头禅、语气特点、用词偏好] +思考方式:[理性型/感性型、决策模式] +压力反应:[遇到困难时的第一反应] +情感表达:[如何表达喜怒哀乐] +人际模式:[与不同类型人的相处方式] +``` + +## 二、角色成长轨迹设计 + +### 1. 过往经历塑造 +``` +童年关键事件:[影响性格形成的重要事件] +青少年转折:[价值观形成的关键时期] +成年重要经历:[影响现在行为的重要经历] +创伤事件:[造成心理阴影的事件] +成功经验:[建立自信的成功经历] +``` + +### 2. 当前状态分析 +``` +现在的困境:[面临的主要问题] +内心冲突:[价值观冲突、情感冲突] +未实现的愿望:[内心深处的渴望] +人际关系状况:[与重要他人的关系] +自我认知:[对自己的看法] +``` + +### 3. 成长路径规划 +``` +成长起点:[故事开始时的状态] +成长触发:[促使改变的关键事件] +成长阻碍:[阻止改变的内外因素] +成长转折:[突破的关键时刻] +成长结果:[最终达到的状态] +``` + +## 三、角色差异化系统 + +### 1. 语言个性化标签 +``` +知识分子型: +- 用词:准确、书面化 +- 句式:复杂、逻辑性强 +- 特点:喜欢引用、分析 + +平民百姓型: +- 用词:口语化、直接 +- 句式:简单、生活化 +- 特点:用比喻、俗语 + +年轻活泼型: +- 用词:网络用语、新潮 +- 句式:短句、语气词多 +- 特点:表达活泼、情绪化 + +商务精英型: +- 用词:专业、效率导向 +- 句式:简洁、目标明确 +- 特点:数字化、结果导向 +``` + +### 2. 情绪表达差异化 +``` +内向型角色: +- 情绪内敛,通过细节表达 +- 多用内心独白 +- 行为含蓄,眼神、微表情丰富 + +外向型角色: +- 情绪外放,直接表达 +- 多用肢体语言 +- 行为夸张,声音、动作明显 + +理性型角色: +- 用逻辑分析情感 +- 控制情绪表达 +- 通过行为体现理性思考 + +感性型角色: +- 情感丰富,表达直接 +- 容易情绪波动 +- 通过感受描述事物 +``` + +## 四、角色关系动态系统 + +### 1. 关系发展阶段 +``` +初识阶段: +- 第一印象形成 +- 基于外在判断 +- 保持距离和礼貌 + +了解阶段: +- 发现共同点和差异 +- 开始深入交流 +- 建立初步信任 + +深入阶段: +- 分享内心想法 +- 产生情感连接 +- 关系质量提升 + +冲突阶段: +- 价值观差异显现 +- 利益冲突出现 +- 关系面临考验 + +和解/决裂阶段: +- 选择妥协或坚持 +- 关系重新定义 +- 达到新的平衡 +``` + +### 2. 关系影响因素 +``` +性格匹配度: +- 互补型:性格互补,相互吸引 +- 相似型:价值观相近,容易理解 +- 冲突型:差异过大,容易摩擦 + +利益关系: +- 合作关系:共同目标,互相支持 +- 竞争关系:利益冲突,相互制约 +- 依赖关系:一方需要另一方 + +情感基础: +- 亲情:血缘关系,天然纽带 +- 友情:选择关系,基于认同 +- 爱情:情感关系,基于吸引 +``` + +## 五、角色一致性维护 + +### 1. 行为一致性检查清单 +- [ ] 角色反应符合性格设定 +- [ ] 对话风格保持一致 +- [ ] 价值观体现在行为中 +- [ ] 能力水平前后一致 +- [ ] 知识背景没有矛盾 + +### 2. 成长合理性检查清单 +- [ ] 性格改变有充分触发 +- [ ] 改变过程符合心理规律 +- [ ] 保留核心性格特征 +- [ ] 成长速度合理 +- [ ] 新行为有学习过程 + +### 3. 关系发展检查清单 +- [ ] 关系变化有具体事件 +- [ ] 情感发展符合逻辑 +- [ ] 对话体现关系状态 +- [ ] 行为符合关系定位 +- [ ] 冲突和和解都有原因 +""" + + +def _get_enhanced_plot_system() -> str: + """增强版情节发展系统""" + return """ +【增强版情节发展系统 - 构建引人入胜的故事】 + +## 一、情节结构优化 + +### 1. 开篇吸引力公式 +``` +开篇必备要素(前500字): +1. 冲突预告:暗示即将到来的主要冲突 +2. 角色困境:展示主角面临的具体问题 +3. 情感钩子:让读者对角色产生情感连接 +4. 悬念设置:提出让读者好奇的问题 +5. 世界观展示:通过细节展现故事背景 +``` + +### 2. 中段推进策略 +``` +每章节必备: +- 新信息:推进主线或揭示背景 +- 新冲突:增加故事张力 +- 角色发展:展现角色成长或变化 +- 关系变化:推进人物关系发展 +- 悬念延续:保持读者阅读兴趣 +``` + +### 3. 高潮设计原则 +``` +高潮构成要素: +- 所有矛盾集中爆发 +- 主角面临最大考验 +- 情感达到最高点 +- 价值观接受终极检验 +- 为结局做好铺垫 +``` + +## 二、冲突层次设计 + +### 1. 外在冲突(表层) +``` +人与人的冲突: +- 利益冲突:资源争夺、地位竞争 +- 价值观冲突:理念差异、立场对立 +- 情感冲突:爱恨情仇、背叛伤害 + +人与环境的冲突: +- 自然环境:天灾、恶劣条件 +- 社会环境:制度限制、社会压力 +- 时代背景:历史变迁、技术冲击 +``` + +### 2. 内在冲突(深层) +``` +价值观冲突: +- 理想与现实的冲突 +- 个人利益与集体利益 +- 传统观念与新思想 + +情感冲突: +- 爱与恨的纠缠 +- 理智与情感的对立 +- 责任与欲望的冲突 + +身份冲突: +- 真实自我与社会期待 +- 过去身份与现在角色 +- 多重身份的矛盾 +``` + +### 3. 冲突升级路径 +``` +第一层:日常摩擦 +- 小误会、小分歧 +- 轻微的不满情绪 +- 可以轻易化解 + +第二层:明显对立 +- 立场分歧明确 +- 情绪开始激化 +- 需要努力才能和解 + +第三层:激烈冲突 +- 矛盾公开化 +- 情绪失控 +- 关系面临破裂 + +第四层:不可调和 +- 价值观根本对立 +- 伤害已经造成 +- 只能选择一方 +``` + +## 三、铺垫技巧升级 + +### 1. 多层次铺垫系统 +``` +远程铺垫(开篇-中段): +- 在日常对话中埋下关键信息 +- 通过角色回忆暗示过往 +- 用环境描写预示未来 + +中程铺垫(中段-高潮前): +- 通过配角行为暗示变化 +- 用角色情绪变化预告转折 +- 通过细节描写营造氛围 + +近程铺垫(高潮前): +- 角色内心不安加剧 +- 环境细节变化明显 +- 对话中透露关键信息 +``` + +### 2. 伏笔回收技巧 +``` +信息伏笔: +- 开篇提到的细节在关键时刻发挥作用 +- 看似无关的对话包含重要信息 +- 角色的无意行为暗示真相 + +情感伏笔: +- 角色的情感变化有迹可循 +- 关系发展的转折有预兆 +- 内心冲突的爆发有征兆 + +物品伏笔: +- 重要物品多次出现 +- 看似普通的物品有特殊意义 +- 物品的出现推动情节发展 +``` + +## 四、节奏控制系统 + +### 1. 张弛有度原则 +``` +紧张节奏段落: +- 冲突激化时刻 +- 悬念揭晓前夕 +- 角色面临选择 +- 危机处理过程 + +缓和节奏段落: +- 冲突后的反思 +- 角色情感交流 +- 日常生活描写 +- 背景信息补充 +``` + +### 2. 信息投放节奏 +``` +信息投放策略: +- 关键信息分批透露 +- 在读者好奇心最强时给出答案 +- 用新信息引发新疑问 +- 保持信息的新鲜感 +``` + +## 五、情节逻辑检查 + +### 1. 因果关系验证 +``` +每个重要情节点检查: +- 这个结果的原因是什么? +- 原因是否充分? +- 时间顺序是否正确? +- 是否有其他可能的结果? +- 角色的反应是否合理? +``` + +### 2. 动机合理性检查 +``` +角色行为动机检查: +- 动机是否明确? +- 动机是否符合角色性格? +- 动机强度是否匹配行为? +- 是否有更简单的解决方案? +- 其他角色的反应是否合理? +``` + +### 3. 转折点合理性 +``` +重大转折检查: +- 转折是否有充分铺垫? +- 触发因素是否合理? +- 角色反应是否符合性格? +- 转折后的发展是否自然? +- 是否推进了主线发展? +``` +""" + """角色发展系统""" + return """ +【角色发展系统 - 让每个角色都活起来】 + +## 主角塑造公式 + +### 1. 核心设定 +- **致命弱点**:性格上的最大缺陷(如:过度自尊、不信任他人、逃避责任) +- **内心渴望**:最深层的需求(如:被认可、找到归属、证明自己) +- **外在目标**:表面上想要达成的事(如:升职、复仇、找到真爱) +- **成长弧线**:从缺陷到成长的完整路径 + +### 2. 背景故事模板 +- **童年创伤**:塑造性格的关键事件 +- **重要关系**:影响人生观的重要人物 +- **转折时刻**:改变人生轨迹的事件 +- **未完成的事**:内心的遗憾或执念 + +### 3. 行为模式设计 +- **压力反应**:遇到困难时的第一反应 +- **情感表达**:如何表达喜怒哀乐 +- **决策方式**:理性型还是感性型 +- **人际模式**:如何与不同类型的人相处 + +## 配角立体化方案 + +### 1. 功能性角色的人格化 +**导师型角色**: +- 不是完美的智者,有自己的局限性 +- 有过失败的经历,所以更珍惜成功 +- 对主角的指导带有个人色彩 + +**对手型角色**: +- 有合理的动机和立场 +- 在某些方面比主角更优秀 +- 有自己的成长和变化 + +**朋友型角色**: +- 有独立的人生目标 +- 与主角的友谊有起伏 +- 有自己的性格特点和说话方式 + +### 2. 角色关系动态化 +- 关系会随着情节发展而变化 +- 每个角色都有自己的成长线 +- 角色之间的冲突和和解都有原因 + +## 对话个性化系统 + +### 1. 语言习惯设计 +**知识分子型**:用词准确,逻辑清晰,偶尔引用典故 +**平民型**:口语化,直接,用比喻和俗语 +**年轻人型**:网络用语,语气词多,表达活泼 +**商人型**:实用主义,喜欢用数字和比较 + +### 2. 情绪表达差异 +**内向型**:情绪内敛,通过细节表达 +**外向型**:情绪外放,直接表达感受 +**理性型**:用逻辑分析情感 +**感性型**:用感受描述事物 + +### 3. 潜台词设计 +- 表面说的话 vs 内心想的话 +- 通过语气、停顿、用词暗示真实想法 +- 让读者能读出言外之意 +""" + + +def _get_emotional_resonance_system() -> str: + """情感共鸣系统 - 让读者产生强烈代入感""" + return """ +【情感共鸣系统 - 触动人心的写作技巧】 + +## 一、普遍情感体验挖掘 + +### 1. 核心人性情感 +``` +恐惧类情感: +- 被抛弃的恐惧:害怕失去重要的人 +- 失败的恐惧:担心达不到期望 +- 未知的恐惧:对不确定未来的焦虑 +- 被误解的恐惧:担心他人不理解自己 + +渴望类情感: +- 被认可的渴望:希望得到他人肯定 +- 归属感的渴望:想要找到自己的位置 +- 成长的渴望:希望变得更好 +- 爱与被爱的渴望:情感连接的需求 + +挫折类情感: +- 努力无果的挫败:付出得不到回报 +- 选择困难的痛苦:两难境地的煎熬 +- 时间流逝的无奈:错过机会的遗憾 +- 能力不足的焦虑:想做却做不到的痛苦 +``` + +### 2. 生活场景共鸣点 +``` +职场共鸣: +- 第一天上班的紧张 +- 被领导批评的委屈 +- 同事关系的复杂 +- 升职加薪的期待 + +情感共鸣: +- 暗恋时的小心翼翼 +- 分手时的痛苦挣扎 +- 友情背叛的失望 +- 家人关爱的温暖 + +成长共鸣: +- 离开家乡的不舍 +- 独自面对困难的勇气 +- 犯错后的自责 +- 突破自我的成就感 +``` + +## 二、细节化情感表达 + +### 1. 微表情描写 +``` +紧张时: +- 不自觉地咬下唇 +- 手指轻敲桌面 +- 眼神闪躲不敢直视 +- 声音微微颤抖 + +开心时: +- 眼角不自觉上扬 +- 步伐轻快有力 +- 忍不住哼小曲 +- 整个人都在发光 + +难过时: +- 肩膀微微下垂 +- 眼中蒙上一层雾气 +- 声音变得很轻很轻 +- 习惯性地抱住自己 +``` + +### 2. 内心独白技巧 +``` +真实的内心声音: +- "为什么我总是这样?"(自我质疑) +- "如果当时我..."(后悔反思) +- "也许他是对的"(动摇犹豫) +- "我一定要证明给他们看"(决心坚定) + +情感层次递进: +表面想法 → 深层担忧 → 核心恐惧 +"我不在乎" → "其实我很在意" → "我害怕被拒绝" +``` + +### 3. 感官细节运用 +``` +视觉细节: +- 阳光透过窗帘洒在地板上的斑驳光影 +- 她眼中闪烁的泪光像星星一样 +- 他紧握的拳头上青筋暴起 + +听觉细节: +- 心跳声在安静的房间里格外清晰 +- 远处传来的音乐声若有若无 +- 她轻柔的呼吸声让人安心 + +触觉细节: +- 冰冷的门把手让人瞬间清醒 +- 温暖的拥抱驱散了所有寒意 +- 粗糙的手掌传递着坚定的力量 +``` + +## 三、情感冲突设计 + +### 1. 内心矛盾冲突 +``` +理智与情感: +- 知道应该放手,但舍不得 +- 明白这样不对,但控制不住 +- 理性分析很清楚,感情上接受不了 + +责任与欲望: +- 想要追求梦想,但不能抛下家庭 +- 渴望自由,但承担着责任 +- 个人幸福与他人期待的冲突 + +过去与现在: +- 想要忘记过去,但阴影挥之不去 +- 怀念过去,但必须面对现实 +- 过去的选择影响现在的生活 +``` + +### 2. 关系情感冲突 +``` +爱恨交织: +- 爱一个人,但被他伤害 +- 恨一个人,但又离不开他 +- 想要报复,但又心软 + +期待与失望: +- 对某人抱有期待,但总是失望 +- 想要被理解,但总是被误解 +- 努力付出,但得不到回应 + +依赖与独立: +- 想要独立,但习惯了依赖 +- 需要帮助,但不愿意承认 +- 保护与被保护的角色转换 +``` + +## 四、共鸣触发技巧 + +### 1. 对比反差法 +``` +强烈对比: +- 表面坚强 vs 内心脆弱 +- 外表光鲜 vs 内心孤独 +- 众人羡慕 vs 自己痛苦 + +时间对比: +- 过去的天真 vs 现在的成熟 +- 曾经的梦想 vs 现实的妥协 +- 当初的承诺 vs 如今的改变 +``` + +### 2. 细节共鸣法 +``` +生活化细节: +- 深夜一个人吃泡面的孤独 +- 收到工资时的小确幸 +- 被人理解时的感动 +- 犯错时的羞愧难当 + +情感化细节: +- 想哭却哭不出来的憋屈 +- 突然想起某个人的瞬间 +- 听到熟悉歌曲时的回忆涌现 +- 一个人走夜路时的恐惧 +``` + +### 3. 成长共鸣法 +``` +成长痛点: +- 第一次离开父母的不安 +- 意识到自己长大的瞬间 +- 发现父母也会老的震撼 +- 承担责任时的重量感 + +蜕变时刻: +- 从依赖到独立的转变 +- 从天真到成熟的过程 +- 从逃避到面对的勇气 +- 从自卑到自信的建立 +``` + +## 五、情感表达层次 + +### 1. 表层情感(直接表达) +- 直接的情绪词汇:开心、难过、愤怒 +- 明显的行为表现:哭泣、大笑、发怒 +- 清晰的态度表达:喜欢、讨厌、支持 + +### 2. 深层情感(间接暗示) +- 通过行为暗示:不自觉的小动作 +- 通过对话暗示:言不由衷的话语 +- 通过环境暗示:周围事物的变化 + +### 3. 核心情感(深层挖掘) +- 童年创伤的影响:深层恐惧的根源 +- 价值观冲突:内心最深的矛盾 +- 存在意义:对人生的终极思考 + +## 六、读者代入感营造 + +### 1. 第一人称视角运用 +``` +内心独白: +- "我告诉自己要坚强,但眼泪还是不争气地掉下来" +- "那一刻,我突然明白了什么叫做心痛" +- "我想我永远不会忘记那个下午" + +感官体验: +- "我感到胸口一阵闷痛" +- "我听到自己心跳的声音" +- "我闻到了熟悉的香水味" +``` + +### 2. 情感节奏控制 +``` +情感起伏: +平静 → 波动 → 高潮 → 回落 → 新的波动 + +情感层次: +表面平静 → 内心波澜 → 情感爆发 → 深层反思 +``` + +### 3. 共同记忆唤起 +``` +集体记忆: +- 学生时代的青涩回忆 +- 第一次工作的紧张兴奋 +- 恋爱时的甜蜜痛苦 +- 成年后的责任重担 + +时代记忆: +- 特定年代的流行歌曲 +- 共同经历的社会事件 +- 集体的文化符号 +- 时代特色的生活方式 +``` +""" + + +def _get_advanced_dialogue_system() -> str: + """高级对话系统 - 让每句话都有深意""" + return """ +【高级对话系统 - 让对话活起来】 + +## 一、潜台词设计技巧 + +### 1. 表里不一型对话 +``` +表面说法 → 真实想法: +"我很好" → 其实我很痛苦 +"随便你" → 我很在意你的选择 +"没关系" → 我很受伤 +"我不在乎" → 我非常在乎 +"你去吧" → 我希望你留下来 +``` + +### 2. 情感层次对话 +``` +第一层(表面):礼貌客套 +"谢谢你的关心" + +第二层(暗示):有所保留 +"我会处理好的"(不想让你担心) + +第三层(深层):真实情感 +"其实我很害怕"(内心独白) +``` + +### 3. 关系状态对话 +``` +亲密关系: +- 可以有停顿、省略 +- 一个眼神就能理解 +- 用昵称、专属词汇 + +疏远关系: +- 客套、正式用词 +- 避免深入话题 +- 保持安全距离 + +紧张关系: +- 话中有话 +- 试探性发言 +- 防御性回应 +``` + +## 二、角色语言个性化 + +### 1. 教育背景影响语言 +``` +高学历角色: +- 用词准确、书面化 +- 逻辑性强、条理清晰 +- 偶尔引用典故、专业术语 +- 例:"从逻辑上分析,这个方案确实存在漏洞" + +普通教育角色: +- 口语化、生活化 +- 直接表达、简单明了 +- 用比喻、俗语 +- 例:"这事儿就像烂泥扶不上墙" + +低学历角色: +- 方言、口语重 +- 表达直接、情绪化 +- 语法不够规范 +- 例:"这咋整啊,我心里没底" +``` + +### 2. 年龄特征语言 +``` +青少年: +- 网络用语、流行词汇 +- 语气词多:"超级"、"特别" +- 情绪化表达 +- 例:"这也太离谱了吧!" + +中年人: +- 稳重、考虑周全 +- 责任感强的表达 +- 经验性判断 +- 例:"年轻人,这事得从长计议" + +老年人: +- 人生感悟、经验之谈 +- 怀旧、对比过去 +- 语速较慢、用词谨慎 +- 例:"我这把年纪了,什么没见过" +``` + +### 3. 职业特色语言 +``` +医生: +- 专业术语自然运用 +- 理性分析、客观判断 +- 关注健康、风险 +- 例:"从症状来看,需要进一步检查" + +教师: +- 习惯性解释、引导 +- 用词规范、逻辑清晰 +- 关注成长、教育 +- 例:"这个问题很好,我们来分析一下" + +商人: +- 效率导向、结果导向 +- 成本效益思维 +- 人际关系敏感 +- 例:"这个项目的投入产出比如何?" +``` + +## 三、对话推进技巧 + +### 1. 信息递进式对话 +``` +第一轮:试探 +A:"你最近怎么样?" +B:"还行吧。" + +第二轮:深入 +A:"看你好像有心事?" +B:"也没什么大不了的。" + +第三轮:突破 +A:"是不是工作上的事?" +B:"你怎么知道的?"(开始敞开心扉) +``` + +### 2. 冲突升级式对话 +``` +第一阶段:分歧出现 +A:"我觉得这样不对。" +B:"为什么不对?" + +第二阶段:立场明确 +A:"这违背了我们的原则。" +B:"原则?什么时候你这么在意原则了?" + +第三阶段:情绪爆发 +A:"我一直都很在意!" +B:"那你之前为什么不说?" + +第四阶段:深层矛盾 +A:"因为我以为你会理解!" +B:"理解?我怎么理解一个从不跟我沟通的人?" +``` + +### 3. 情感递进式对话 +``` +疏远 → 试探 → 接近 → 亲密 + +疏远阶段: +"你好。"(客套) + +试探阶段: +"你还记得我们以前..."(回忆) + +接近阶段: +"其实我一直想跟你说..."(敞开) + +亲密阶段: +"我知道你懂我的意思。"(默契) +``` + +## 四、对话节奏控制 + +### 1. 快节奏对话(紧张、激烈) +``` +特点: +- 短句、断句多 +- 语气急促 +- 互相打断 +- 情绪激动 + +示例: +A:"你怎么能这样?" +B:"我怎么了?" +A:"你明知道——" +B:"我明知道什么?" +A:"别装了!" +``` + +### 2. 慢节奏对话(深沉、思考) +``` +特点: +- 长句、停顿多 +- 语气平缓 +- 深思熟虑 +- 情感深沉 + +示例: +A:"你知道吗...有时候我会想,如果当初我们选择了不同的路,现在会是什么样子。" +B:"(沉默片刻)也许...也许我们都会更快乐一些。" +``` + +### 3. 变化节奏对话(情感转折) +``` +从慢到快: +A:"我一直在想一个问题..."(慢) +B:"什么问题?" +A:"为什么你要骗我?!"(快,情绪爆发) + +从快到慢: +A:"你必须告诉我真相!"(快) +B:"好吧...其实..."(慢,开始坦白) +``` + +## 五、对话功能设计 + +### 1. 推进情节的对话 +``` +信息揭示: +- 通过对话透露关键信息 +- 推动故事发展 +- 解答读者疑问 + +冲突制造: +- 通过对话引发矛盾 +- 加剧紧张关系 +- 制造戏剧冲突 + +转折触发: +- 关键对话改变局势 +- 重要决定的宣布 +- 意外信息的披露 +``` + +### 2. 展现性格的对话 +``` +直接展现: +- 通过说话方式展现性格 +- 通过观点表达展现价值观 +- 通过反应方式展现特质 + +间接展现: +- 通过对话选择展现优先级 +- 通过语气变化展现情绪 +- 通过沉默展现内心状态 +``` + +### 3. 营造氛围的对话 +``` +紧张氛围: +- 短促、急迫的对话 +- 充满质疑和怀疑 +- 话中有话的试探 + +温馨氛围: +- 温和、关怀的语调 +- 分享和倾听 +- 理解和支持的表达 + +悬疑氛围: +- 模糊、暗示性的话语 +- 欲言又止的表达 +- 意味深长的沉默 +``` + +## 六、对话真实感营造 + +### 1. 生活化表达 +``` +口语化特征: +- 语气词:"嗯"、"啊"、"呢" +- 重复:"真的真的"、"好好好" +- 省略:"知道了"(省略主语) +- 感叹:"天哪!"、"我的妈呀!" + +情境化表达: +- 根据场合调整语言 +- 考虑说话环境 +- 符合当时情绪状态 +``` + +### 2. 个性化标签 +``` +每个角色的专属特征: +- 口头禅:"说实话"、"你懂的" +- 语言习惯:爱用反问、喜欢举例 +- 表达方式:直接/委婉、理性/感性 +- 词汇偏好:书面语/口语、正式/随意 +``` + +### 3. 情感真实性 +``` +情感与语言的匹配: +- 开心时:语调上扬、语速加快 +- 难过时:语调低沉、语速缓慢 +- 愤怒时:语调激烈、用词强硬 +- 紧张时:语调不稳、结结巴巴 +``` +""" + """情节发展系统""" + return """ +【情节发展系统 - 告别突兀和流水账】 + +## 情节推进三原则 + +### 1. 因果链原则 +每个情节点都要回答: +- **为什么发生**:有什么原因导致? +- **如何发生**:具体过程是什么? +- **产生什么后果**:对角色和故事有什么影响? + +### 2. 情感驱动原则 +- 情节的推进来自角色的情感需求 +- 外在事件触发内在情感变化 +- 情感变化推动行为选择 + +### 3. 冲突升级原则 +- 小冲突→中冲突→大冲突 +- 外在冲突→内在冲突→价值观冲突 +- 个人冲突→关系冲突→社会冲突 + +## 铺垫技巧系统 + +### 1. 细节铺垫法 +- 在日常对话中透露关键信息 +- 通过环境描写暗示即将发生的事 +- 用角色的小动作预示内心变化 + +### 2. 情绪铺垫法 +- 用气氛烘托即将到来的转折 +- 通过角色的不安情绪制造悬念 +- 用对比手法突出变化 + +### 3. 伏笔回收法 +- 开篇埋下的线索在中后段回收 +- 看似无关的细节在关键时刻发挥作用 +- 角色的过往经历影响现在的选择 + +## 冲突设计模板 + +### 1. 内心冲突类型 +- **价值观冲突**:正义 vs 利益 +- **情感冲突**:爱情 vs 友情 +- **选择冲突**:安全 vs 冒险 +- **身份冲突**:真实自我 vs 社会期待 + +### 2. 关系冲突类型 +- **误解型**:基于信息不对称的冲突 +- **立场型**:基于不同立场的冲突 +- **竞争型**:基于资源争夺的冲突 +- **成长型**:基于成长差异的冲突 + +### 3. 外在冲突类型 +- **环境阻碍**:客观条件的限制 +- **时间压力**:deadline带来的紧迫感 +- **资源稀缺**:有限资源的争夺 +- **规则限制**:制度或法律的约束 + +## 情节转折技巧 + +### 1. 反转设计 +- **信息反转**:之前的认知被颠覆 +- **身份反转**:角色身份的意外揭示 +- **立场反转**:敌友关系的转换 +- **结果反转**:预期结果的意外改变 + +### 2. 高潮设计 +- 所有矛盾在此刻集中爆发 +- 主角面临最大的选择和考验 +- 情感达到最高点 +- 为结局做好铺垫 + +### 3. 结局设计 +- 回应开篇提出的问题 +- 展示角色的成长和变化 +- 给读者满足感和思考空间 +- 为可能的续集留下空间 +""" + + +def list_genres() -> List[str]: + return list(GENRE_TEMPLATES.keys()) + + +def _force_story_expansion(config: ViralNovelConfig, bible: Dict[str, Any], existing_story: str, target_chars: int) -> str: + """强制扩展故事到目标字数,降低完整性检查标准""" + + current_length = _count_effective_characters(existing_story) + needed_chars = target_chars - current_length + + if needed_chars <= 0: + return existing_story + + logger.info(f"强制扩展模式:需要增加约{needed_chars}字") + + # 获取写作系统 + writing_system = _get_advanced_writing_system() + character_system = _get_enhanced_character_system() + plot_system = _get_enhanced_plot_system() + + # 分析已有内容 + story_summary = existing_story[-3000:] if len(existing_story) > 3000 else existing_story + bible_text = json.dumps(bible, ensure_ascii=False, indent=2) + + prompt = f"""你需要为以下小说进行扩展,确保达到目标字数。当前故事可能看起来接近完整,但需要进一步丰富内容。 + +{writing_system} + +{character_system} + +{plot_system} + +【原始设定】 +{bible_text} + +【已有故事内容(最后部分)】 +...{story_summary} + +【扩展要求】 +1. 目标增加字数:约{needed_chars}字 +2. 可以通过以下方式扩展: + - 增加角色间的深度对话和互动 + - 丰富场景描写和环境细节 + - 添加角色的内心独白和情感变化 + - 增加支线情节或回忆片段 + - 扩展现有情节的细节描写 +3. 保持与现有内容的连贯性 +4. 即使故事看似完整,也要找到合理的扩展点 +5. 可以添加新的小冲突或情节转折来丰富内容 + +请直接输出扩展内容,不要任何说明或标记:""" + + max_tokens = min(int(needed_chars * 3), 8192) + + try: + response = _call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是世界顶级的小说家,擅长在保持故事完整性的同时丰富内容细节。"}, + {"role": "user", "content": prompt} + ], + temperature=getattr(config, 'temperature', 0.9), # 稍微提高创造性 + max_tokens=max_tokens + ) + + expansion = _clean_extra_lines(_safe_get_content(response)) + + # 检查扩展内容质量 + if len(expansion.strip()) < 200: + logger.warning("强制扩展内容过短,返回原故事") + return existing_story + + # 合并内容 + combined_story = existing_story + "\n\n" + expansion + + # 应用反重复处理 + final_story = detect_and_replace_repetitions(combined_story) + + final_length = _count_effective_characters(final_story) + logger.info(f"强制扩展完成,最终字数: {final_length}") + + return final_story + + except Exception as e: + logger.error(f"强制扩展过程中出错: {e}") + return existing_story + + +def _continue_story_generation(config: ViralNovelConfig, bible: Dict[str, Any], existing_story: str) -> str: + """智能续写故事,基于故事完整性而非固定字数""" + + current_length = _count_effective_characters(existing_story) + logger.info(f"开始智能续写,当前字数: {current_length}") + + # 检查当前故事阶段 + story_stage = _analyze_story_stage(existing_story, bible) + logger.info(f"故事阶段分析: {story_stage}") + + # 检查是否已经完整 - 但如果字数不足,优先续写 + is_complete, completeness_reason = _check_story_completeness(existing_story, bible, config.min_chars_before_ending) + + # 如果字数严重不足,即使看起来完整也要继续写 + if current_length < config.min_chars_before_ending * 0.8: # 如果少于最小要求的80% + logger.info(f"字数不足最小要求的80%({current_length} < {config.min_chars_before_ending * 0.8}),强制续写") + is_complete = False + completeness_reason = f"字数不足,需要继续扩展(当前{current_length}字)" + + if is_complete and current_length >= config.min_chars_before_ending: + logger.info(f"故事已完整且字数充足: {completeness_reason}") + return existing_story + + # 如果字数已经很多但故事不完整,优先完善结构而非增加字数 + if current_length > config.max_chars_limit: + logger.info("字数已达上限,专注于完善故事结构") + target_addition = min(2000, config.max_chars_limit - current_length) + else: + # 根据故事阶段决定续写长度 + if "开端" in story_stage or "发展" in story_stage: + target_addition = min(5000, config.max_chars_limit - current_length) + elif "高潮" in story_stage: + target_addition = min(3000, config.max_chars_limit - current_length) + else: # 收尾阶段 + target_addition = min(2000, config.max_chars_limit - current_length) + + if target_addition <= 0: + logger.info("已达字数上限,不再续写") + return existing_story + + # 获取写作系统 + writing_system = _get_advanced_writing_system() + character_system = _get_enhanced_character_system() + plot_system = _get_enhanced_plot_system() + + # 分析已有内容,提取关键信息 + story_summary = existing_story[-2000:] if len(existing_story) > 2000 else existing_story + + bible_text = json.dumps(bible, ensure_ascii=False, indent=2) + + prompt = f"""你需要为以下小说续写内容,确保故事的连贯性和完整性。 + +{writing_system} + +{character_system} + +{plot_system} + +【原始设定】 +{bible_text} + +【当前故事发展阶段】 +{story_stage} + +【已有故事内容(最后部分)】 +...{story_summary} + +【续写要求】 +1. 无缝衔接已有内容,保持人物性格和情节逻辑一致 +2. 根据当前阶段推进故事发展,不要重复已有情节 +3. 目标续写长度:约{target_addition}字 +4. 如果故事接近完整,应该开始收尾而不是无限扩展 +5. 确保情节有意义的推进,避免无意义的重复描写 + +请直接输出续写内容,不要任何说明或标记:""" + + max_tokens = min(int(target_addition * 2.5), 4096) + + try: + response = _call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是世界顶级的小说家,精通故事续写和情节发展。"}, + {"role": "user", "content": prompt} + ], + temperature=getattr(config, 'temperature', 0.8), + max_tokens=max_tokens + ) + + continuation = _clean_extra_lines(_safe_get_content(response)) + + # 检查续写内容质量 + if len(continuation.strip()) < 100: + logger.warning("续写内容过短,可能生成失败") + return existing_story + + # 合并内容 + combined_story = existing_story + "\n\n" + continuation + + # 应用反重复处理 + final_story = detect_and_replace_repetitions(combined_story) + + final_length = _count_effective_characters(final_story) + logger.info(f"续写完成,最终字数: {final_length}") + + return final_story + + except Exception as e: + logger.error(f"续写过程中出错: {e}") + return existing_story + + +def generate_viral_novel_with_progress(genre: str, + target_total_chars: int, + model: str = "qwen-turbo", + temperature: float = 0.8, + enable_logic_check: bool = True, + project_dir: str = None, + resume: bool = False) -> Dict[str, str]: + """带进度保存的小说生成""" + global _current_progress + + config = ViralNovelConfig( + genre=genre, + target_total_chars=int(target_total_chars), + model=model, + temperature=temperature, + enable_logic_check=enable_logic_check, + min_chars_before_ending=max(15000, int(target_total_chars * 0.6)), # 至少60%的目标字数 + max_chars_limit=int(target_total_chars * 2.5), # 最大不超过目标的2.5倍 + story_completeness_check=True + ) + + # 确定项目目录 + if not project_dir: + base_dir = os.path.dirname(os.path.abspath(__file__)) + project_dir = _next_project_dir(base_dir) + + # 尝试恢复进度 + progress = None + if resume: + progress = _load_generation_progress(project_dir) + + if not progress: + progress = GenerationProgress( + project_dir=project_dir, + stage="start", + progress_percent=0.0, + start_time=datetime.now().isoformat() + ) + + _current_progress = progress + + try: + # 阶段1: 构建故事圣经 + if progress.stage in ["start", "bible"]: + progress.stage = "bible" + progress.progress_percent = 10.0 + _save_generation_progress(progress) + + if not progress.bible: + progress.bible = _build_detailed_bible(config) + progress.progress_percent = 25.0 + _save_generation_progress(progress) + print("✓ 角色设定完成") + + # 阶段2: 生成标题 + if progress.stage in ["bible", "title"]: + progress.stage = "title" + progress.progress_percent = 30.0 + _save_generation_progress(progress) + + if not progress.title: + progress.title = _generate_title(config, progress.bible) + + progress.progress_percent = 35.0 + _save_generation_progress(progress) + print(f"✓ 标题生成: 《{progress.title}》") + + # 阶段3: 生成故事主体 + if progress.stage in ["title", "story"]: + progress.stage = "story" + progress.progress_percent = 40.0 + _save_generation_progress(progress) + + if not progress.story: + if ENHANCED_FEATURES and config.enable_logic_check: + progress.story = _enhanced_story_generation_with_logic_check(config, progress.bible) + print("✓ 故事主体完成(已通过逻辑检查)") + else: + progress.story = _generate_story_with_depth_fallback(config, progress.bible) + print("✓ 故事主体完成") + + progress.progress_percent = 75.0 + _save_generation_progress(progress) + + # 阶段4: 智能扩展(基于故事完整性) + if progress.stage in ["story", "refine"]: + progress.stage = "refine" + progress.progress_percent = 80.0 + _save_generation_progress(progress) + + # 检查故事完整性而非固定字数 + current_length = _count_effective_characters(progress.story) + logger.info(f"开始智能扩展阶段,当前字数: {current_length}") + + # 循环续写直到达到最小要求 + max_iterations = 5 # 最多尝试5次续写 + iteration = 0 + + while iteration < max_iterations: + iteration += 1 + logger.info(f"第{iteration}次续写尝试...") + + # 使用新的智能续写函数 + new_story = _continue_story_generation(config, progress.bible, progress.story) + + # 检查是否有实际的内容增加 + new_length = _count_effective_characters(new_story) + if new_length <= current_length + 100: # 如果增加的内容少于100字,说明续写失败 + logger.warning(f"第{iteration}次续写增加内容过少,停止续写") + break + + progress.story = new_story + current_length = new_length + logger.info(f"第{iteration}次续写完成,当前字数: {current_length}") + + # 检查是否达到最小要求 + if current_length >= config.min_chars_before_ending: + logger.info(f"已达到最小字数要求: {current_length} >= {config.min_chars_before_ending}") + break + + # 更新进度 + progress.progress_percent = 80.0 + (iteration / max_iterations) * 10.0 + _save_generation_progress(progress) + + # 最终检查 + final_length = _count_effective_characters(progress.story) + is_complete, completeness_reason = _check_story_completeness( + progress.story, progress.bible, config.min_chars_before_ending + ) + + if is_complete: + logger.info(f"故事完整:{completeness_reason},最终字数: {final_length}") + else: + logger.warning(f"故事可能不够完整:{completeness_reason},最终字数: {final_length}") + + # 如果仍然不足最小要求,强制再次扩展 + if final_length < config.min_chars_before_ending: + logger.info("字数仍不足最小要求,进行强制扩展...") + # 降低完整性检查标准,强制续写 + forced_story = _force_story_expansion(config, progress.bible, progress.story, config.min_chars_before_ending) + if forced_story != progress.story: + progress.story = forced_story + final_length = _count_effective_characters(progress.story) + logger.info(f"强制扩展完成,最终字数: {final_length}") + + progress.progress_percent = 95.0 + _save_generation_progress(progress) + print("✓ 内容优化完成") + + # 内容安全检查 + if config.enable_content_filter: + is_safe, issues = _content_safety_check(progress.story) + if not is_safe: + logger.warning(f"内容安全检查发现问题: {issues}") + # 可以选择是否继续或进行内容过滤 + + # 完成 + progress.stage = "complete" + progress.progress_percent = 100.0 + _save_generation_progress(progress) + + # 保存最终结果 + _write_outputs(project_dir, progress.title, progress.story) + + # 清理进度文件 + _cleanup_progress_file(project_dir) + + full_text = f"《{progress.title}》\n\n{progress.story}" + return { + "title": progress.title, + "text": full_text, + "project_dir": project_dir + } + + except Exception as e: + logger.error(f"生成过程出错: {str(e)}") + # 保存当前进度 + if progress: + progress.error_count += 1 + _save_generation_progress(progress) + raise e + + +def _save_generation_progress(progress: GenerationProgress): + """保存生成进度""" + if not progress.project_dir: + return + + try: + os.makedirs(progress.project_dir, exist_ok=True) + progress_file = os.path.join(progress.project_dir, ".generation_progress.json") + + progress.last_update = datetime.now().isoformat() + + with open(progress_file, 'w', encoding='utf-8') as f: + json.dump(asdict(progress), f, ensure_ascii=False, indent=2) + + logger.info(f"进度已保存: {progress.stage} ({progress.progress_percent:.1f}%)") + except Exception as e: + logger.warning(f"保存进度失败: {str(e)}") + + +def _load_generation_progress(project_dir: str) -> Optional[GenerationProgress]: + """加载生成进度""" + try: + progress_file = os.path.join(project_dir, ".generation_progress.json") + if not os.path.exists(progress_file): + return None + + with open(progress_file, 'r', encoding='utf-8') as f: + data = json.load(f) + + progress = GenerationProgress(**data) + logger.info(f"已加载进度: {progress.stage} ({progress.progress_percent:.1f}%)") + return progress + except Exception as e: + logger.warning(f"加载进度失败: {str(e)}") + return None + + +def _cleanup_progress_file(project_dir: str): + """清理进度文件""" + try: + progress_file = os.path.join(project_dir, ".generation_progress.json") + if os.path.exists(progress_file): + os.remove(progress_file) + except Exception as e: + logger.warning(f"清理进度文件失败: {str(e)}") + + +def _content_safety_check(text: str) -> Tuple[bool, List[str]]: + """内容安全检查,包括对话质量检查""" + issues = [] + + # 敏感词检查(简单示例,实际应用中需要更完善的词库) + sensitive_words = [ + "暴力", "血腥", "恐怖", "政治敏感", "违法", "犯罪", + # 可以根据需要扩展 + ] + + for word in sensitive_words: + if word in text: + issues.append(f"包含敏感词汇: {word}") + + # 长度检查 + if len(text) < 100: + issues.append("内容过短,可能生成失败") + + # 字数达标检查 + effective_chars = _count_effective_characters(text) + if effective_chars < 20000: # 低于20000字认为不达标 + issues.append(f"字数不足: 当前{effective_chars}字,建议至少20000字") + + # 对话比例检查 + dialogue_count = text.count('"') + text.count('"') + text.count('"') + text.count('「') + text.count('『') + total_chars = len(text) + if total_chars > 0: + dialogue_ratio = (dialogue_count / total_chars) * 100 + if dialogue_ratio < 5: # 对话比例低于5% + issues.append(f"对话比例过低: {dialogue_ratio:.1f}%,建议增加角色对话") + + # 重复内容检查(加强版) + lines = text.split('\n') + line_counts = {} + for line in lines: + line = line.strip() + if len(line) > 10: # 只检查较长的行 + line_counts[line] = line_counts.get(line, 0) + 1 + + repeated_lines = [line for line, count in line_counts.items() if count > 3] + if repeated_lines: + issues.append(f"发现重复内容: {len(repeated_lines)}行") + + # 重复词汇检查 + common_phrases = ["他知道", "心中一沉", "深吸一口气", "点了点头", "说道", "与此同时"] + for phrase in common_phrases: + count = text.count(phrase) + if count > 10: # 超过10次认为过度重复 + issues.append(f"词汇重复过多: '{phrase}' 出现{count}次") + + # 结构完整性检查 + if "第一章" not in text and "第1章" not in text and "章" not in text: + issues.append("缺少章节结构,建议添加章节划分") + + is_safe = len(issues) == 0 + return is_safe, issues + + +def _handle_api_error(error: Exception, attempt: int, max_attempts: int) -> bool: + """处理API错误 - 增强版""" + error_msg = str(error).lower() + + # 检查是否是超时错误 + if "timeout" in error_msg or "timed out" in error_msg: + wait_time = min(30 * (2 ** attempt), 180) # 超时错误等待更久,最多3分钟 + logger.warning(f"API超时,等待 {wait_time} 秒后重试...") + time.sleep(wait_time) + return True + + # 检查是否是限流错误 + if "rate limit" in error_msg or "too many requests" in error_msg: + wait_time = min(60 * (2 ** attempt), 300) # 最多等待5分钟 + logger.warning(f"API限流,等待 {wait_time} 秒后重试...") + time.sleep(wait_time) + return True + + # 检查是否是网络错误 + if "network" in error_msg or "connection" in error_msg: + wait_time = min(15 * (2 ** attempt), 90) # 网络错误等待时间适中 + logger.warning(f"网络错误,等待 {wait_time} 秒后重试...") + time.sleep(wait_time) + return True + + # 检查是否是服务器错误 + if "server error" in error_msg or "internal error" in error_msg or "500" in error_msg: + wait_time = min(45 * (2 ** attempt), 240) # 服务器错误等待较久 + logger.warning(f"服务器错误,等待 {wait_time} 秒后重试...") + time.sleep(wait_time) + return True + + # 检查是否是服务不可用 + if "service unavailable" in error_msg or "503" in error_msg: + wait_time = min(60 * (2 ** attempt), 300) + logger.warning(f"服务不可用,等待 {wait_time} 秒后重试...") + time.sleep(wait_time) + return True + + # 其他错误不重试 + return False + + +def _enhanced_call_generation(model: str, messages: list, temperature: float, + max_tokens: Optional[int] = None, max_attempts: int = 8): + """增强版API调用,包含更强的超时和错误处理""" + last_error: Optional[Exception] = None + + for attempt in range(max_attempts): + try: + logger.info(f"API调用尝试 {attempt + 1}/{max_attempts}") + + # 设置更长的超时时间 + import dashscope + + response = Generation.call( + model=model, + messages=messages, + temperature=temperature, + max_tokens=max_tokens, + result_format='message' + ) + + if response.status_code == 200: + logger.info(f"API调用成功 (尝试 {attempt + 1})") + return response + else: + error_msg = f"API调用失败: {response.message}" + last_error = Exception(error_msg) + logger.warning(f"API返回错误: {error_msg}") + + # 尝试处理特定错误 + if not _handle_api_error(last_error, attempt, max_attempts): + logger.error(f"无法处理的API错误,停止重试: {error_msg}") + break + + except Exception as e: + last_error = e + error_str = str(e) + logger.warning(f"第 {attempt + 1} 次尝试失败: {error_str}") + + # 尝试处理错误 + if attempt < max_attempts - 1: + if _handle_api_error(e, attempt, max_attempts): + continue + else: + # 简单的指数退避重试 + wait_time = min((2 ** attempt) + random.uniform(0, 1), 30) + logger.info(f"等待 {wait_time:.1f} 秒后重试...") + time.sleep(wait_time) + else: + logger.error(f"已达到最大重试次数 {max_attempts},停止尝试") + + # 如果所有尝试都失败了 + error_msg = f"API调用失败: {str(last_error) if last_error else '未知错误'}" + logger.error(error_msg) + raise last_error if last_error else Exception("API调用失败") + + +def _safe_api_call_with_fallback(model: str, messages: list, temperature: float, + max_tokens: Optional[int] = None) -> str: + """安全的API调用,带降级处理""" + try: + response = _enhanced_call_generation(model, messages, temperature, max_tokens) + return _safe_get_content(response) + except Exception as e: + error_str = str(e) + logger.error(f"API调用完全失败: {error_str}") + + # 如果是超时或网络问题,建议用户稍后重试 + if any(keyword in error_str.lower() for keyword in ['timeout', 'network', 'connection']): + raise Exception(f"网络连接问题,请检查网络后重试: {error_str}") + + # 如果是限流问题 + if 'rate limit' in error_str.lower(): + raise Exception(f"API调用频率过高,请稍后重试: {error_str}") + + # 其他错误 + raise Exception(f"API服务异常,请稍后重试: {error_str}") + + +# 全局变量用于处理中断信号 +_generation_interrupted = False +_current_progress: Optional[GenerationProgress] = None + +def _signal_handler(signum, frame): + """处理中断信号""" + global _generation_interrupted, _current_progress + _generation_interrupted = True + + print("\n\n收到中断信号,正在保存进度...") + if _current_progress: + _save_generation_progress(_current_progress) + print("进度已保存,可以稍后继续生成") + exit(0) + +# 注册信号处理器 +signal.signal(signal.SIGINT, _signal_handler) +if hasattr(signal, 'SIGTERM'): + signal.signal(signal.SIGTERM, _signal_handler) + + +def _call_generation(model: str, messages: list, temperature: float, max_tokens: Optional[int] = None): + """兼容性包装函数""" + return _enhanced_call_generation(model, messages, temperature, max_tokens) + + +def _safe_get_content(response) -> str: + try: + return response.output.choices[0].message.content.strip() + except Exception: + return "" + + +def _count_effective_characters(text: str) -> int: + 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) + return len(chinese_chars) + len(punctuation) + len(numbers) + + +def _clean_extra_lines(text: str) -> str: + text = re.sub(r'\n{3,}', '\n\n', text) + return text.strip() + + +def _next_project_dir(base_dir: str) -> str: + existing = [] + for name in os.listdir(base_dir): + if re.fullmatch(r'n\d+', name) and os.path.isdir(os.path.join(base_dir, name)): + existing.append(int(name[1:])) + idx = (max(existing) + 1) if existing else 1 + return os.path.join(base_dir, f"n{idx}") + + +def _choose_genre_enhanced() -> str: + """增强版题材选择""" + if ENHANCED_FEATURES: + genres = list_available_genres() + else: + genres = list(GENRE_TEMPLATES.keys()) + + print("\n可选题材:") + for i, g in enumerate(genres, 1): + print(f"{i}. {g}") + + while True: + s = input(f"\n请选择题材 (1-{len(genres)}): ").strip() + if not s.isdigit(): + print("请输入数字") + continue + idx = int(s) + if 1 <= idx <= len(genres): + return genres[idx - 1] + print("无效选择") + + +def _build_detailed_bible(config: ViralNovelConfig) -> Dict[str, Any]: + """构建详细的故事圣经,重点解决角色符号化问题""" + t = GENRE_TEMPLATES[config.genre] + + # 生成随机角色种子 + main_char_seed = generate_random_character_seed("main", config.genre) + supporting_seeds = [ + generate_random_character_seed("supporting", config.genre) for _ in range(3) + ] + + print(f"🎲 角色随机种子已生成:") + print(f" 主角种子: {main_char_seed['seed']} - {main_char_seed['name']} ({main_char_seed['personality']}, {main_char_seed['occupation']})") + print(f" 主角特征: {main_char_seed.get('speech_style', '未知')}说话风格, {main_char_seed.get('habit_action', '无特殊习惯')}") + for i, seed in enumerate(supporting_seeds, 1): + print(f" 配角{i}种子: {seed['seed']} - {seed['name']} ({seed['personality']}, {seed['occupation']})") + print(f" 配角{i}特征: {seed.get('speech_style', '未知')}说话风格, {seed.get('relationship_style', '未知')}人际关系") + + prompt = f"""你是顶级编剧,专门创作有深度、有灵魂的故事。请为以下题材创建一个详细的故事设定。 + +题材:{config.genre} +核心理念:{t['core']} + +【角色随机种子 - 必须严格使用】: +主角种子: +- 姓名:{main_char_seed['name']} +- 性格:{main_char_seed['personality']} +- 背景:{main_char_seed['background']} +- 职业:{main_char_seed['occupation']} +- 性格缺陷:{main_char_seed['flaw']} +- 内心渴望:{main_char_seed['desire']} + +配角种子: +{chr(10).join([f"- {seed['name']}:{seed['personality']},{seed['background']},{seed['occupation']}" for seed in supporting_seeds])} + +【重要】你必须基于上述随机种子创造真正立体的角色,不是符号化的工具人: + +1. **主角设定要求**: + - 严格使用提供的姓名、性格、背景等种子信息 + - 有明确的童年创伤或成长经历 + - 有性格缺陷和内心恐惧 + - 有具体的说话习惯和行为模式 + - 有内心的矛盾和挣扎 + +2. **配角设定要求**: + - 严格使用提供的配角种子信息 + - 每个配角都有独立的人生目标 + - 有不同的价值观和行为逻辑 + - 有独特的说话方式和性格特征 + - 与主角的关系有深度和变化 + +3. **情节设定要求**: + - 每个重要情节都有充分的铺垫 + - 冲突来自角色的内心需求 + - 有明确的因果关系链条 + - 避免突兀的剧情转折 + +请输出JSON格式,包含以下字段: +{{ + "character_seeds": {{ + "main_seed": {main_char_seed['seed']}, + "supporting_seeds": {[seed['seed'] for seed in supporting_seeds]} + }}, + "title_concept": "故事核心概念(一句话)", + "theme": "深层主题(人性、成长、价值观等)", + "main_character": {{ + "name": "{main_char_seed['name']}", + "age": 年龄, + "background": "详细背景故事(至少100字,基于种子背景:{main_char_seed['background']})", + "personality_core": "{main_char_seed['personality']}相关的核心性格特征", + "fatal_flaw": "{main_char_seed['flaw']}的具体表现", + "inner_desire": "{main_char_seed['desire']}的深层含义", + "speech_pattern": "说话习惯和口头禅", + "behavior_habits": "行为习惯和小动作", + "growth_arc": "成长轨迹(从什么到什么)" + }}, + "supporting_characters": [ + {{ + "name": "{supporting_seeds[0]['name']}", + "role": "在故事中的作用", + "personality": "{supporting_seeds[0]['personality']}", + "motivation": "行为动机", + "speech_style": "说话风格", + "relationship_with_mc": "与主角的关系动态" + }}, + {{ + "name": "{supporting_seeds[1]['name']}", + "role": "在故事中的作用", + "personality": "{supporting_seeds[1]['personality']}", + "motivation": "行为动机", + "speech_style": "说话风格", + "relationship_with_mc": "与主角的关系动态" + }}, + {{ + "name": "{supporting_seeds[2]['name']}", + "role": "在故事中的作用", + "personality": "{supporting_seeds[2]['personality']}", + "motivation": "行为动机", + "speech_style": "说话风格", + "relationship_with_mc": "与主角的关系动态" + }} + ], + "world_setting": {{ + "environment": "故事发生的具体环境", + "social_context": "社会背景和氛围", + "rules": "这个世界的运行规则", + "conflicts": "环境中存在的矛盾" + }}, + "plot_structure": {{ + "opening_hook": "开篇钩子(具体事件)", + "inciting_incident": "引发事件(改变主角生活的事件)", + "first_plot_point": "第一个转折点", + "midpoint": "中点危机", + "climax": "高潮冲突", + "resolution": "解决方案" + }}, + "emotional_journey": {{ + "opening_emotion": "开篇主角的情感状态", + "emotional_turns": ["情感转折点1", "情感转折点2", "情感转折点3"], + "final_emotion": "结尾主角的情感状态" + }}, + "key_relationships": [ + {{ + "characters": "角色A与角色B", + "relationship_type": "关系类型", + "conflict_source": "冲突来源", + "development": "关系发展轨迹" + }} + ] +}} +""" + + try: + response = _enhanced_call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是世界顶级的故事创作大师,擅长创造深刻、立体、有灵魂的角色和故事。你创作的每个角色都有血有肉,每个情节都有深层逻辑,每个冲突都来自人性的真实需求。"}, + {"role": "user", "content": prompt} + ], + temperature=0.6, + max_tokens=4000 + ) + except Exception as e: + logger.error(f"故事圣经生成失败: {str(e)}") + raise Exception(f"角色设定生成失败,请检查网络连接后重试: {str(e)}") + + text = _safe_get_content(response) + m = re.search(r'\{[\s\S]*\}', text) + json_text = m.group(0) if m else text + try: + data = json.loads(json_text) + except Exception: + # 如果JSON解析失败,返回基础结构 + data = { + "title_concept": "一个关于成长的故事", + "theme": "人性与成长", + "main_character": { + "name": "主角", + "background": "普通人的不普通经历", + "personality_core": "坚韧不拔", + "fatal_flaw": "过度自尊", + "inner_desire": "被认可", + "speech_pattern": "简洁直接", + "behavior_habits": "紧张时握拳", + "growth_arc": "从自卑到自信" + }, + "supporting_characters": [], + "world_setting": {}, + "plot_structure": {}, + "emotional_journey": {}, + "key_relationships": [] + } + return data + + +def _generate_title(config: ViralNovelConfig, bible: Dict[str, Any]) -> str: + """生成标题""" + concept = bible.get("title_concept", "") + theme = bible.get("theme", "") + + prompt = f"""请为以下故事创作一个吸引人的中文标题。 + +故事概念:{concept} +深层主题:{theme} +题材:{config.genre} + +要求: +1. 4-8个中文字 +2. 体现故事的核心冲突或情感 +3. 朗朗上口,有记忆点 +4. 不要使用书名号 +5. 原创,不模仿现有作品 + +只输出标题本身: +""" + + try: + response = _enhanced_call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是专业的文学编辑,擅长为深度故事创作有内涵的标题。"}, + {"role": "user", "content": prompt} + ], + temperature=0.7, + max_tokens=50 + ) + except Exception as e: + logger.error(f"标题生成失败: {str(e)}") + # 标题生成失败时使用默认标题 + logger.warning("使用默认标题") + return "未命名作品" + + title = _safe_get_content(response) + title = title.replace('《', '').replace('》', '').replace('"', '').replace('"', '').replace(''', '').replace(''', '').strip() + title = re.sub(r'\s+', '', title) + return title[:15] if title else "未命名" + + +def _check_logic_consistency(text: str, bible: Dict[str, Any], config: ViralNovelConfig) -> Tuple[bool, List[str], str]: + """ + 检查文本的逻辑一致性 + 返回: (是否通过检查, 问题列表, 修复建议) + """ + if not config.enable_logic_check: + return True, [], "" + + logger.info("开始逻辑一致性检查...") + + # 构建检查提示词 + prompt = f"""请对以下小说文本进行逻辑一致性检查,重点检查: + +【检查维度】 +1. 角色行为一致性: + - 角色行为是否符合已设定的性格特征 + - 角色能力是否前后一致 + - 角色知识水平是否合理 + +2. 时间线逻辑: + - 事件发生顺序是否合理 + - 时间跨度是否现实 + - 因果关系是否正确 + +3. 世界观一致性: + - 是否违反已建立的世界规则 + - 社会背景是否前后统一 + - 技术水平是否一致 + +4. 情节逻辑: + - 角色动机是否充分 + - 冲突升级是否合理 + - 转折点是否有铺垫 + +5. 对话逻辑: + - 角色是否知道不该知道的信息 + - 说话方式是否符合角色设定 + - 对话内容是否推进情节 + +【角色设定参考】 +{json.dumps(bible.get('main_character', {}), ensure_ascii=False, indent=2)} + +【配角设定参考】 +{json.dumps(bible.get('supporting_characters', []), ensure_ascii=False, indent=2)} + +【世界观设定参考】 +{json.dumps(bible.get('world_setting', {}), ensure_ascii=False, indent=2)} + +【待检查文本】 +{text} + +请以JSON格式回复: +{{ + "overall_pass": true/false, + "critical_issues": ["严重逻辑错误1", "严重逻辑错误2"], + "minor_issues": ["轻微问题1", "轻微问题2"], + "suggestions": ["修复建议1", "修复建议2"], + "score": 评分(0-100), + "details": {{ + "character_consistency": 评分(0-100), + "timeline_logic": 评分(0-100), + "world_consistency": 评分(0-100), + "plot_logic": 评分(0-100), + "dialogue_logic": 评分(0-100) + }} +}}""" + + try: + response = _call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是一位专业的逻辑分析师,擅长发现故事中的逻辑漏洞和不一致之处。你的分析必须客观、准确、有建设性。"}, + {"role": "user", "content": prompt} + ], + temperature=0.3, + max_tokens=2000 + ) + + result_text = _safe_get_content(response) + + # 尝试解析JSON + try: + # 提取JSON部分 + json_match = re.search(r'\{[\s\S]*\}', result_text) + if json_match: + result_data = json.loads(json_match.group(0)) + + overall_pass = result_data.get("overall_pass", True) + critical_issues = result_data.get("critical_issues", []) + minor_issues = result_data.get("minor_issues", []) + suggestions = result_data.get("suggestions", []) + + # 如果有严重问题,检查不通过 + if critical_issues: + overall_pass = False + + all_issues = critical_issues + minor_issues + fix_suggestions = "\n".join(suggestions) if suggestions else "" + + logger.info(f"逻辑检查完成,发现 {len(critical_issues)} 个严重问题,{len(minor_issues)} 个轻微问题") + return overall_pass, all_issues, fix_suggestions + else: + logger.warning("无法解析逻辑检查结果,跳过检查") + return True, [], "" + + except json.JSONDecodeError: + logger.warning("逻辑检查结果JSON解析失败,跳过检查") + return True, [], "" + + except Exception as e: + logger.error(f"逻辑检查过程出错: {str(e)}") + return True, [], "" + + +def _fix_logic_issues(text: str, issues: List[str], suggestions: str, bible: Dict[str, Any], config: ViralNovelConfig) -> str: + """ + 根据逻辑检查结果修复问题 + """ + if not issues or not suggestions: + return text + + logger.info(f"开始修复 {len(issues)} 个逻辑问题...") + + # 构建修复提示词 + issues_text = "\n".join(f"- {issue}" for issue in issues) + + prompt = f"""请修复以下文本中的逻辑问题,要求: + +【发现的逻辑问题】 +{issues_text} + +【修复建议】 +{suggestions} + +【修复要求】 +1. 保持原文的核心情节和主要内容不变 +2. 只修复逻辑问题,不要大幅改动 +3. 确保修复后的内容符合角色设定和世界观 +4. 保持文本的流畅性和可读性 +5. 修复后的内容要逻辑自洽 + +【角色设定参考】 +{json.dumps(bible.get('main_character', {}), ensure_ascii=False, indent=2)} + +【需要修复的文本】 +{text} + +请直接输出修复后的完整文本,不要添加任何说明:""" + + try: + response = _call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是一位专业的文本编辑,擅长修复逻辑问题而不改变故事的核心内容。你的修复必须精准、合理、保持原文风格。"}, + {"role": "user", "content": prompt} + ], + temperature=0.5, + max_tokens=min(len(text) * 2, 8192) + ) + + fixed_text = _safe_get_content(response) + if fixed_text and len(fixed_text) > len(text) * 0.5: # 确保修复后的文本不会太短 + logger.info("逻辑问题修复完成") + return _clean_extra_lines(fixed_text) + else: + logger.warning("修复结果异常,返回原文") + return text + + except Exception as e: + logger.error(f"逻辑修复过程出错: {str(e)}") + return text + + +def _enhanced_story_generation_with_logic_check(config: ViralNovelConfig, bible: Dict[str, Any]) -> str: + """ + 增强版故事生成,包含逻辑检查和修复 + """ + # 获取增强的写作系统 + writing_system = _get_advanced_writing_system() + character_system = _get_enhanced_character_system() + plot_system = _get_enhanced_plot_system() + logic_system = _get_logic_consistency_system() + + # 生成反同质化指导 + anti_repetition_guide = generate_anti_repetition_guidance(config.genre, 1) + + bible_text = json.dumps(bible, ensure_ascii=False, indent=2) + + prompt = f"""你将创作一篇高质量的原创小说,必须解决AI写作的常见问题并确保逻辑严密。 + +{anti_repetition_guide} + +{writing_system} + +{character_system} + +{plot_system} + +{logic_system} + +【故事设定】 +{bible_text} + +【创作要求 - 必须严格遵守】 + +1. **逻辑严密要求**: + - 角色行为必须符合性格设定,不能OOC + - 时间线必须清晰合理,不能前后矛盾 + - 世界观规则必须统一,不能自相矛盾 + - 因果关系必须明确,每个结果都有充分原因 + - 角色知识和能力必须前后一致 + +2. **反流水账要求**: + - 每个场景都要有情感张力和内心冲突 + - 用内心独白展现角色思考过程 + - 通过具体细节暗示而非直接说明 + - 让每个动作都有情感色彩和深层含义 + +3. **铺垫与因果要求**: + - 重要情节前必须有多层次铺垫 + - 每个转折都要有合理原因和充分动机 + - 用细节和情绪变化暗示即将发生的事 + - 角色的选择要有内心挣扎和思考过程 + +4. **防重复要求**: + - 同一情感用不同方式表达(愤怒→恼火→暴躁→怒不可遏) + - 同一场景从不同角度描写(视觉→听觉→心理感受) + - 词汇和句式要有变化,避免重复表达 + - 情节要螺旋上升,在重复中递进和深化 + +5. **角色立体化要求**: + - 每个角色都有独特的说话方式和行为模式 + - 通过行为展现性格,不要直接说明 + - 角色要有内心冲突和成长轨迹 + - 配角也要有自己的目标和动机,不是工具人 + +6. **情感共鸣要求**: + - 挖掘普遍的人性体验和情感共鸣点 + - 用具体细节唤起读者情感 + - 展现角色的脆弱和坚强,让人物有血有肉 + - 让读者能感同身受,产生代入感 + +【具体写作指令】 + +**开篇500字必须包含**: +1. 主角的核心冲突和内心困境 +2. 独特的环境细节和世界观展示 +3. 至少2个伏笔为后续情节埋线 +4. 让读者对主角产生情感连接的细节 +5. 制造悬念或期待,吸引读者继续阅读 + +**每1000字自检要求**: +1. 是否推进了情感发展和角色关系? +2. 是否深化了角色的内心层次? +3. 是否有新的冲突或转折? +4. 是否避免了重复表达? +5. 是否保持了逻辑一致性? + +**对话写作要求**: +1. 每个角色说话方式不同(用词、语气、句式) +2. 对话要有潜台词(表面说A,实际想B) +3. 通过对话推进情节和展现角色性格 +4. 符合角色的情感状态和人际关系 +5. 自然口语化,不要书面语 + +**场景转换要求**: +1. 用角色的情感状态连接不同场景 +2. 通过环境变化体现角色内心变化 +3. 用过渡句避免突兀跳跃 +4. 保持时间和空间的连贯性 +5. 每个场景都要有存在的必要性 + +目标字数:至少 {config.target_total_chars} 字 + +请直接输出小说正文,不要任何说明或标记:""" + + max_tokens = min(int(config.target_total_chars * 2.5), 8192) + + # 生成初始故事 + response = _call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是世界顶级的小说家,精通人性洞察和情感描写。你的作品逻辑严密,从不流水账,每个角色都活灵活现,每个情节都有深层逻辑,每个细节都服务于情感表达。你擅长通过细腻的心理描写和生动的细节描写创造强烈的代入感。"}, + {"role": "user", "content": prompt} + ], + temperature=config.temperature, + max_tokens=max_tokens + ) + + story = _clean_extra_lines(_safe_get_content(response)) + + # 应用反重复处理 + story = detect_and_replace_repetitions(story) + + # 进行逻辑检查和修复 + if config.enable_logic_check: + for iteration in range(config.max_logic_iterations): + logger.info(f"进行第 {iteration + 1} 轮逻辑检查...") + + # 检查逻辑一致性 + is_consistent, issues, suggestions = _check_logic_consistency(story, bible, config) + + if is_consistent: + logger.info("逻辑检查通过") + break + else: + logger.info(f"发现 {len(issues)} 个逻辑问题,开始修复...") + story = _fix_logic_issues(story, issues, suggestions, bible, config) + + # 如果是最后一轮,即使有问题也不再修复 + if iteration == config.max_logic_iterations - 1: + logger.warning("已达到最大修复轮数,停止逻辑修复") + + return story + """生成有深度的故事,解决所有常见问题""" + + writing_system = _get_advanced_writing_system() + character_system = _get_character_development_system() + plot_system = _get_plot_development_system() + + bible_text = json.dumps(bible, ensure_ascii=False, indent=2) + + prompt = f"""你将创作一篇高质量的原创小说,必须解决AI写作的常见问题。 + +{writing_system} + +{character_system} + +{plot_system} + +【故事设定】 +{bible_text} + +【创作要求 - 必须严格遵守】 + +1. **字数要求**: + - 必须生成至少8000字的内容 + - 内容要丰富充实,不能敷衍了事 + - 每个章节都要有足够的篇幅展开 + +2. **对话要求(重要)**: + - 对话内容必须占总文本的30%以上 + - 每个角色说话方式必须不同 + - 通过对话推进情节,展现性格 + - 每1000字至少要有5-8段对话 + +3. **反流水账要求**: + - 每个场景都要有情感张力和内心冲突 + - 用内心独白展现角色思考过程 + - 通过具体细节暗示而非直接说明 + - 让每个动作都有情感色彩和深层含义 + +4. **铺垫与因果要求**: + - 重要情节前必须有多层次铺垫 + - 每个转折都要有合理原因和充分动机 + - 用细节和情绪变化暗示即将发生的事 + - 角色的选择要有内心挣扎和思考过程 + +5. **防重复要求(严格执行)**: + - 禁止重复使用"他知道"、"心中一沉"、"深吸一口气"等词汇 + - 同一情感用不同方式表达(愤怒→恼火→暴躁→怒不可遏) + - 同一场景从不同角度描写(视觉→听觉→心理感受) + - 词汇和句式要有变化,避免重复表达 + - 词汇和句式要有变化 + - 情节要螺旋上升,不原地打转 + +4. **逻辑一致性要求**: + - 角色行为符合性格设定 + - 前后情节不能矛盾 + - 时间线要清晰合理 + - 世界观规则要统一 + +5. **角色立体化要求**: + - 每个角色都有独特的说话方式 + - 通过行为展现性格,不要直接说明 + - 角色要有内心冲突和成长 + - 配角也要有自己的目标和动机 + +6. **情感共鸣要求**: + - 挖掘普遍的人性体验 + - 用具体细节唤起情感 + - 展现角色的脆弱和坚强 + - 让读者能感同身受 + +【具体写作指令】 + +**开篇500字必须包含**: +1. 主角的核心冲突(内心挣扎) +2. 独特的环境细节(不是泛泛描述) +3. 至少2个伏笔(为后续情节埋线) +4. 让读者对主角产生情感连接的细节 +5. 制造悬念或期待 + +**每1000字检查**: +1. 是否推进了情感发展? +2. 是否深化了角色关系? +3. 是否有新的内心层次? +4. 是否避免了重复? +5. 是否保持了逻辑? + +**对话要求**: +1. 每个角色说话方式不同(用词、语气、句式) +2. 对话要有潜台词(表面说A,实际想B) +3. 通过对话推进情节和展现性格 +4. 符合角色的情感状态和关系 +5. 自然口语化,不要书面语 + +**场景转换要求**: +1. 用角色的情感状态连接场景 +2. 通过环境变化体现内心变化 +3. 用过渡句避免突兀跳跃 +4. 保持时间和空间的连贯性 + +目标字数:至少 {config.target_total_chars} 字 + +请直接输出小说正文,不要任何说明或标记: +""" + + max_tokens = min(int(config.target_total_chars * 2.5), 8192) + response = _call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是世界顶级的小说家,精通人性洞察和情感描写。你的作品从不流水账,每个角色都活灵活现,每个情节都有深层逻辑,每个细节都服务于情感表达。你擅长通过细腻的心理描写和生动的细节描写创造强烈的代入感。"}, + {"role": "user", "content": prompt} + ], + temperature=config.temperature, + max_tokens=max_tokens + ) + + story = _clean_extra_lines(_safe_get_content(response)) + return story + + +def _refine_and_expand(config: ViralNovelConfig, bible: Dict[str, Any], story: str) -> str: + """精炼和扩展故事,确保质量和字数 - 优化版""" + current_length = _count_effective_characters(story) + + if current_length >= config.target_total_chars: + return story + + # 需要补充的字数 + shortage = config.target_total_chars - current_length + logger.info(f"开始续写,当前字数: {current_length}, 目标字数: {config.target_total_chars}, 需要补充: {shortage}") + + writing_system = _get_advanced_writing_system() + bible_text = json.dumps(bible, ensure_ascii=False, indent=2) + + # 减少续写轮数,提高每轮质量 + max_attempts = 6 # 从10次减少到6次 + min_words_per_round = 2000 # 每轮最少2000字 + + for attempt in range(max_attempts): + if current_length >= config.target_total_chars: + logger.info(f"已达到目标字数: {current_length}") + break + + # 计算本轮需要写的字数 + remaining_rounds = max_attempts - attempt + words_this_round = max(min_words_per_round, shortage // remaining_rounds) + words_this_round = min(words_this_round, 8000) # 单轮最多8000字 + + # 获取故事结尾部分作为上下文 + context = _get_smart_context(story, bible, shortage) + + # 生成强化版反同质化指导 + anti_repetition_guide = generate_anti_repetition_guidance(config.genre, attempt + 2) + + # 检查当前故事是否已经有结尾 + has_ending = _check_story_ending(story) + + # 提取当前故事中的高频短语,用于生成时避免 + existing_phrases = _extract_high_frequency_phrases(story) + forbidden_phrases_text = "、".join(existing_phrases[:15]) if existing_phrases else "无" + + prompt = f"""请继续这个故事,必须补充至少 {words_this_round} 字的高质量内容。 + +⚠️ 【严格禁止重复以下已出现的高频短语】: +{forbidden_phrases_text} + +⚠️ 【绝对禁止的表达方式】: +- 心头泛起、胸中涌起、情感汹涌、心中充满了 +- 轻轻颔首、点了点头、深吸一口气、整理衣襟 +- 凝视着、注视着、眼神中闪烁着、目光中透出 +- 站起身、走上前、转过身、抬起头、低下头 +- 与此同时、就在这时、不久之后、片刻之后 + +{anti_repetition_guide} + +{writing_system} + +【故事设定】 +{bible_text} + +【当前状态分析】 +- 故事是否已有结尾:{'是' if has_ending else '否'} +- 本轮续写目标:{words_this_round} 字 +- 剩余续写轮数:{remaining_rounds} + +【续写要求 - 严格执行】 + +1. **字数要求**: + - 必须写够 {words_this_round} 字,不能敷衍了事 + - 内容要丰富充实,有实质性推进 + +2. **内容质量要求**: + - 必须推进主线情节,不能原地打转 + - 增加新的冲突、发现或角色发展 + - 每个场景都要有存在的必要性 + - 避免为了凑字数而重复描写 + +3. **对话要求**: + - 对话占比必须达到30%以上 + - 每个角色说话方式必须不同 + - 对话要推进情节,不能是空洞的哲理讨论 + - 格式:所有对话使用中文引号 "角色说的话" + +4. **反重复要求**: + - 绝对禁止重复之前出现过的情节 + - 不能重复使用相同的场景(洞穴、山峰等) + - 避免重复的对话模式和动作描写 + - 每个段落都要有新意 + +5. **结尾控制**: + {'- 故事已有结尾,不要再写结尾内容' if has_ending else '- 如果是最后一轮续写,可以适当收尾'} + - 不要出现"尾声"、"终章"等标题 + - 让故事自然发展,不要强行煽情 + +6. **场景创新**: + - 尝试新的场景:城镇、学院、商铺、客栈等 + - 每个场景要有独特的氛围和细节 + - 通过环境变化体现角色内心变化 + +7. **角色互动**: + - 增加角色间的真实冲突和分歧 + - 让配角有自己的想法,不只是附和主角 + - 展现角色关系的发展和变化 + +【上文结尾】 +{context} + +【写作提示】 +- 从上文自然衔接,不要突兀跳跃 +- 用具体的事件推进情节 +- 通过角色行为展现性格 +- 用细节描写增加真实感 +- 让每个对话都有目的性 + +请直接输出续写内容,确保质量和字数: +""" + + # 根据需要补充的字数动态调整max_tokens + max_tokens = min(words_this_round * 3, 8192) # 给足够空间 + + logger.info(f"第 {attempt + 1} 轮续写,目标: {words_this_round} 字,max_tokens: {max_tokens}") + + try: + response = _enhanced_call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是世界顶级的小说家,擅长写长篇小说。你必须严格按照字数要求进行创作,确保内容丰富、对话充分、情节精彩。\n\n【核心原则】:绝不能重复之前的内容,每一段都要有新的价值。\n\n【严格禁止】:\n- 任何形式的重复短语和表达\n- 套路化的动作描写(如:轻轻颔首、心头泛起、凝视着等)\n- 空洞的情感表达(如:心中充满了、眼神中闪烁着等)\n- 重复的对话模式和场景设置\n\n【必须做到】:\n- 每个动作、表情、心理活动都用全新的表达方式\n- 对话要有个性化,推进情节\n- 场景描写要具体生动,避免抽象概念\n- 情节必须向前推进,不能原地打转"}, + {"role": "user", "content": prompt} + ], + temperature=config.temperature, + max_tokens=max_tokens + ) + + additional_text = _clean_extra_lines(_safe_get_content(response)) + + # 严格检查生成内容是否包含禁用短语 + forbidden_check_phrases = [ + "轻轻颔首", "心头泛起", "胸中涌起", "情感汹涌", "凝视着", + "眼神中闪烁着", "深吸一口气", "点了点头", "整理衣襟", + "心中充满了", "眼中充满了", "站起身", "走上前", "转过身" + ] + + violation_count = 0 + for phrase in forbidden_check_phrases: + if phrase in additional_text: + violation_count += 1 + logger.warning(f"检测到禁用短语: {phrase}") + + # 如果违规短语过多,重新生成 + if violation_count >= 3: + logger.warning(f"生成内容包含 {violation_count} 个禁用短语,重新生成...") + if attempt < max_attempts - 1: # 不是最后一次尝试 + continue # 重新生成 + else: + logger.warning("已达最大重试次数,强制应用反重复处理") + + except Exception as e: + error_str = str(e) + logger.error(f"第 {attempt + 1} 轮续写API调用失败: {error_str}") + + # 如果是网络或超时问题,给用户明确提示 + if any(keyword in error_str.lower() for keyword in ['timeout', 'network', 'connection']): + logger.error("网络连接问题,建议:") + logger.error("1. 检查网络连接") + logger.error("2. 稍后重试") + logger.error("3. 进度已保存,可以继续生成") + raise Exception(f"网络连接超时,进度已保存至 {config.target_total_chars*0.8:.0f}%,请稍后继续") + + # 如果是限流问题 + if 'rate limit' in error_str.lower(): + logger.error("API调用频率过高,建议等待几分钟后重试") + raise Exception("API调用频率限制,请等待几分钟后重试") + + # 其他错误,尝试继续下一轮 + if attempt < max_attempts - 2: # 还有至少2轮机会 + logger.warning(f"第 {attempt + 1} 轮续写失败,尝试下一轮") + continue + else: + raise Exception(f"续写过程中遇到问题: {error_str}") + + if not additional_text or len(additional_text) < 500: # 如果续写内容太少 + logger.warning(f"第 {attempt + 1} 轮续写内容不足,跳过") + continue + + # 应用强化版反重复处理 + additional_text = detect_and_replace_repetitions(additional_text) + + # 检查是否有重复内容 + if _check_content_repetition(story, additional_text): + logger.warning(f"第 {attempt + 1} 轮续写发现重复内容,跳过") + continue + + story = _clean_extra_lines(story + "\n\n" + additional_text) + new_length = _count_effective_characters(story) + added_length = new_length - current_length + current_length = new_length + shortage = config.target_total_chars - current_length + + logger.info(f"第 {attempt + 1} 轮续写完成,新增字数: {added_length}, 当前总字数: {current_length}, 剩余: {shortage}") + + # 如果单次续写字数太少且还有很多轮次,继续 + if added_length < min_words_per_round and attempt < max_attempts - 2: + logger.info("单次续写字数不足,继续下一轮") + continue + + final_length = _count_effective_characters(story) + completion_rate = (final_length / config.target_total_chars) * 100 + + if completion_rate < 80: + logger.warning(f"续写完成,但字数不足。最终字数: {final_length}, 完成度: {completion_rate:.1f}%") + else: + logger.info(f"续写成功完成。最终字数: {final_length}, 完成度: {completion_rate:.1f}%") + + return detect_and_replace_repetitions(story) + + +def _analyze_story_stage(story: str, bible: Dict[str, Any]) -> str: + """分析当前故事发展到哪个阶段""" + + current_length = _count_effective_characters(story) + + # 基于字数的粗略阶段判断 + if current_length < 5000: + stage = "开端阶段" + description = "故事刚刚开始,需要建立世界观、介绍主要角色、设置初始冲突" + elif current_length < 12000: + stage = "发展阶段" + description = "情节逐步展开,角色关系发展,冲突逐渐升级" + elif current_length < 20000: + stage = "深化阶段" + description = "主要冲突全面展开,角色面临重大挑战,情节复杂化" + elif current_length < 30000: + stage = "高潮阶段" + description = "故事达到高潮,主要冲突激化,角色做出关键决定" + else: + stage = "收尾阶段" + description = "冲突解决,角色成长完成,可以考虑适当收尾" + + # 检查故事中的关键词来判断更精确的阶段 + story_lower = story.lower() + + # 检查是否有结尾迹象 + ending_signs = ["解决", "战胜", "成功", "完成", "实现", "胜利", "和解", "团聚"] + has_resolution = any(sign in story[-1000:] for sign in ending_signs) + + if has_resolution and current_length > 15000: + stage = "自然结尾阶段" + description = "主要冲突已解决,故事可以自然结束,但需要适当的情感升华和收尾" + + return f"{stage}:{description}(当前字数:{current_length})" + + +def _check_story_completeness(story: str, bible: Dict[str, Any], min_chars: int) -> Tuple[bool, str]: + """检查故事是否真正完整,而不仅仅是字数达标""" + + current_length = _count_effective_characters(story) + + # 1. 字数检查:至少要达到最小字数要求 + if current_length < min_chars: + return False, f"字数不足,当前{current_length}字,最少需要{min_chars}字" + + # 2. 检查是否有明显的结尾标志(但不是重复的套路结尾) + ending_indicators = [ + "### 尾声", "### 终章", "### 结语", "### 完结", "### 结局", + "故事到此结束", "全文完", "(完)", "【完】" + ] + + has_ending_marker = any(indicator in story for indicator in ending_indicators) + + # 3. 检查故事结构完整性 + plot_elements = { + "开端": ["开始", "起初", "最初", "一开始", "故事开始"], + "发展": ["接着", "然后", "随后", "后来", "接下来", "与此同时"], + "高潮": ["关键时刻", "决定性", "最终", "终于", "关键", "决战", "最后的"], + "结局": ["最终", "终于", "最后", "结束", "完成", "实现", "成功"] + } + + structure_score = 0 + for element, keywords in plot_elements.items(): + if any(keyword in story for keyword in keywords): + structure_score += 1 + + # 4. 检查主要情节线是否解决 + main_conflicts = bible.get("plot_structure", {}) + if main_conflicts: + climax_keywords = ["解决", "战胜", "克服", "成功", "胜利", "完成", "实现"] + has_resolution = any(keyword in story[-2000:] for keyword in climax_keywords) # 检查最后2000字 + else: + has_resolution = True # 如果没有明确的冲突设定,默认为已解决 + + # 5. 综合判断 + if structure_score >= 3 and has_resolution: + if has_ending_marker: + return True, "故事结构完整,有明确结尾" + elif current_length > min_chars * 1.5: # 如果字数超过最小要求的1.5倍 + return True, "故事内容充实,可以自然结束" + else: + return False, "故事发展充分但缺少明确结尾" + else: + return False, f"故事结构不完整(结构得分:{structure_score}/4,冲突解决:{has_resolution})" + + +def _check_story_ending(story: str) -> bool: + """检查故事是否已经有结尾""" + ending_indicators = [ + "### 尾声", "### 终章", "### 结语", "### 完结", + "这就是", "的故事", "传奇故事", "未来还有更多的挑战", + "他已经找到了属于自己的力量", "准备好迎接这一切" + ] + + # 检查最后2000字符 + ending_part = story[-2000:] if len(story) > 2000 else story + + for indicator in ending_indicators: + if indicator in ending_part: + return True + + return False + + +def _check_content_repetition(existing_story: str, new_content: str) -> bool: + """检查新内容是否与现有故事重复""" + # 简单的重复检查 + new_sentences = [s.strip() for s in new_content.split('。') if len(s.strip()) > 10] + existing_sentences = [s.strip() for s in existing_story.split('。') if len(s.strip()) > 10] + + repetition_count = 0 + for new_sentence in new_sentences: + for existing_sentence in existing_sentences: + similarity = _calculate_similarity(new_sentence, existing_sentence) + if similarity > 0.7: # 相似度超过70% + repetition_count += 1 + break + + # 如果超过30%的句子重复,认为是重复内容 + repetition_rate = repetition_count / len(new_sentences) if new_sentences else 0 + return repetition_rate > 0.3 + + +def _get_smart_context(story: str, bible: Dict[str, Any], shortage: int) -> str: + """智能获取上下文,简化版本""" + # 基础上下文长度 + base_context_length = min(2000, len(story)) + + # 根据需要补充的字数调整上下文长度 + if shortage > 3000: + context_length = min(3000, len(story)) + elif shortage > 1500: + context_length = min(2500, len(story)) + else: + context_length = base_context_length + + # 获取结尾部分 + context = story[-context_length:] if len(story) > context_length else story + + # 添加关键角色信息 + if bible and "main_character" in bible: + main_char = bible["main_character"] + char_info = f"\n【主角设定】\n姓名: {main_char.get('name', '主角')}\n性格: {main_char.get('personality_core', '')}\n动机: {main_char.get('inner_desire', '')}\n" + context = char_info + "\n" + context + + return context + + +def _write_outputs(project_dir: str, title: str, story: str): + os.makedirs(project_dir, exist_ok=True) + story_path = os.path.join(project_dir, f"novel{os.path.basename(project_dir)[1:]}.txt") + + with open(story_path, "w", encoding="utf-8") as f: + f.write(f"《{title}》\n\n{story}") + + +def main(): + + api_key = os.getenv('DASHSCOPE_API_KEY', '') or os.getenv('QWEN_API_KEY', '') + if not api_key: + print("\n❌ 未检测到 API Key。请设置环境变量 DASHSCOPE_API_KEY 或 QWEN_API_KEY") + return + + # 检查是否有未完成的生成任务 + base_dir = os.path.dirname(os.path.abspath(__file__)) + resume_option = False + resume_dir = None + + # 查找未完成的任务 + for i in range(1, 100): + check_dir = os.path.join(base_dir, f"n{i}") + if os.path.exists(os.path.join(check_dir, ".generation_progress.json")): + progress = _load_generation_progress(check_dir) + if progress and progress.stage != "complete": + print(f"\n发现未完成的生成任务:") + print(f" 目录: {check_dir}") + print(f" 阶段: {progress.stage}") + print(f" 进度: {progress.progress_percent:.1f}%") + + resume_choice = input("是否继续未完成的任务?(y/n,默认n): ").strip().lower() + if resume_choice == 'y': + resume_option = True + resume_dir = check_dir + break + + if resume_option and resume_dir: + # 继续未完成的任务 + try: + print(f"\n继续生成任务...") + result = generate_viral_novel_with_progress( + genre="", # 从进度中恢复 + target_total_chars=0, # 从进度中恢复 + project_dir=resume_dir, + resume=True + ) + + print("\n" + "=" * 70) + print("🎉 续写完成!") + print("=" * 70) + print(f"📖 标题: 《{result['title']}》") + print(f"📁 输出目录: {result['project_dir']}") + + except Exception as e: + print(f"\n❌ 续写过程出错: {str(e)}") + logger.error(f"续写过程出错: {str(e)}", exc_info=True) + + return + + # 新的生成任务 + # 直接使用精品长篇配置 + if ENHANCED_FEATURES: + config = get_preset_config("精品长篇") + + # 允许用户选择题材 + config.genre = _choose_genre_enhanced() + else: + # 基础配置 + genre = _choose_genre_enhanced() + target = input("\n请输入目标有效字数(建议8000-20000):").strip() + if not target.isdigit() or int(target) <= 0: + print("无效字数") + return + + config = ViralNovelConfig( + genre=genre, + target_total_chars=int(target) + ) + + project_dir = _next_project_dir(os.path.dirname(os.path.abspath(__file__))) + + print(f"\n开始生成高质量小说...") + print(f"题材: {config.genre}") + print(f"最小字数: {config.target_total_chars}(故事完整性优先,不设上限)") + print(f"使用模型: {config.model}") + if hasattr(config, 'temperature'): + print(f"创作温度: {config.temperature}") + if hasattr(config, 'enable_logic_check'): + print(f"逻辑检查: {'启用' if config.enable_logic_check else '禁用'}") + print(f"输出目录: {os.path.basename(project_dir)}/") + print(f"进度保存: 启用(支持中断恢复)") + print("\n正在创建立体角色和深度情节...") + print("提示: 可以随时按 Ctrl+C 中断,进度会自动保存") + + try: + start_time = time.time() + + # 使用新的带进度保存的生成函数 + result = generate_viral_novel_with_progress( + genre=config.genre, + target_total_chars=config.target_total_chars, + model=config.model, + temperature=getattr(config, 'temperature', 0.8), + enable_logic_check=getattr(config, 'enable_logic_check', True), + project_dir=project_dir + ) + + generation_time = time.time() - start_time + final_len = _count_effective_characters(result['text']) + completion_rate = (final_len / config.target_total_chars) * 100 + + print("\n" + "=" * 70) + if completion_rate >= 80: + print("🎉 高质量小说生成完成!") + else: + print("⚠️ 小说生成完成(字数不足)") + print("=" * 70) + print(f"📖 标题: 《{result['title']}》") + print(f"📊 有效字数: {final_len}") + + # 根据完成度显示不同的信息 + if completion_rate >= 100: + print(f"📈 完成度: {completion_rate:.1f}% ✅ 超额完成") + elif completion_rate >= 80: + print(f"📈 完成度: {completion_rate:.1f}% ✅ 达标") + elif completion_rate >= 60: + print(f"📈 完成度: {completion_rate:.1f}% ⚠️ 基本达标") + else: + print(f"📈 完成度: {completion_rate:.1f}% ❌ 严重不足") + + print(f"📁 输出目录: {result['project_dir']}") + print(f"🤖 使用模型: {config.model}") + print(f"⏱️ 生成耗时: {generation_time:.1f}秒") + + print("=" * 70) + + except KeyboardInterrupt: + print("\n\n⚠️ 用户中断生成") + print("📁 进度已自动保存,可以稍后继续") + + except Exception as e: + error_str = str(e) + print(f"\n❌ 生成过程出错: {error_str}") + + if "网络连接" in error_str or "超时" in error_str or "timeout" in error_str.lower(): + print("\n🔧 网络问题解决建议:") + print("1. 检查网络连接是否稳定") + print("2. 等待几分钟后重试") + print("3. 如果问题持续,可能是API服务繁忙") + print("4. 进度已保存,下次运行时选择继续未完成的任务") + + elif "rate limit" in error_str.lower(): + print("\n⏰ API调用频率限制:") + print("1. 请等待几分钟后重试") + print("2. 避免频繁调用API") + print("3. 进度已保存,可以稍后继续") + + else: + print(f"\n🔧 其他错误,请检查:") + print("1. API密钥是否正确") + print("2. 网络连接是否正常") + print("3. 是否有足够的磁盘空间") + + logger.error(f"生成过程出错: {error_str}", exc_info=True) + print("📁 进度已保存,可以稍后继续生成") + + +def _generate_story_with_depth_fallback(config, bible: Dict[str, Any]) -> str: + """备用的故事生成方法(兼容旧版本)""" + writing_system = _get_advanced_writing_system() + character_system = _get_enhanced_character_system() + plot_system = _get_enhanced_plot_system() + + bible_text = json.dumps(bible, ensure_ascii=False, indent=2) + + prompt = f"""你将创作一篇高质量的原创小说,必须解决AI写作的常见问题。 + +{writing_system} + +{character_system} + +{plot_system} + +【故事设定】 +{bible_text} + +目标字数:至少 {config.target_total_chars} 字 + +请直接输出小说正文,不要任何说明或标记:""" + + max_tokens = min(int(config.target_total_chars * 2.5), 8192) + + response = _call_generation( + model=config.model, + messages=[ + {"role": "system", "content": "你是世界顶级的小说家,精通人性洞察和情感描写。"}, + {"role": "user", "content": prompt} + ], + temperature=getattr(config, 'temperature', 0.8), + max_tokens=max_tokens + ) + + return _clean_extra_lines(_safe_get_content(response)) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/resume_generation.py b/resume_generation.py new file mode 100644 index 0000000..2098db7 --- /dev/null +++ b/resume_generation.py @@ -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() \ No newline at end of file