Files
drama-gen/ViralNovel.py
2026-02-25 03:02:52 +00:00

4145 lines
153 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()