好的,开始吧。
**好,我现在开始写全部代码。**
---
## 🧬 完整代码:河图洛书小说写手系统
### 1. `dao_engine.py` — π引擎
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
道引擎:π引擎 — 永不枯竭的随机性源泉
"""
import os
import math
import json
from typing import List, Dict, Any
class DaoEngine:
"""π引擎 — 永不枯竭的随机性源泉"""
def __init__(self, chunk_size: int = 10000):
self.chunk_size = chunk_size
self.digits: List[int] = []
self.pointer: int = 0
self._load_next_chunk()
def _load_next_chunk(self) -> None:
"""加载下一批π小数位"""
try:
import gmpy2
gmpy2.get_context().precision = (self.pointer + self.chunk_size + 100) * 4
pi = gmpy2.const_pi()
pi_str = format(pi, f'.{self.pointer + self.chunk_size + 50}f')
pi_digits = pi_str.replace('.', '')
segment = pi_digits[self.pointer:self.pointer + self.chunk_size]
self.digits.extend([int(ch) for ch in segment])
except ImportError:
from decimal import Decimal, getcontext
getcontext().prec = self.pointer + self.chunk_size + 50
pi = Decimal(0)
for k in range(self.pointer + self.chunk_size + 20):
pi += (Decimal(1)/(16**k)) * (
Decimal(4)/(8*k+1) - Decimal(2)/(8*k+4) -
Decimal(1)/(8*k+5) - Decimal(1)/(8*k+6)
)
pi_str = str(pi)[2:]
segment = pi_str[self.pointer:self.pointer + self.chunk_size]
self.digits.extend([int(ch) for ch in segment])
def get_digit(self) -> int:
"""取一个数字(0-9)"""
if self.pointer >= len(self.digits):
self._load_next_chunk()
digit = self.digits[self.pointer]
self.pointer += 1
return digit
def get_novelty(self, length: int = 8) -> float:
"""取一个0-1之间的随机浮点数"""
digits = self.get_digits(length)
value = 0.0
for i, d in enumerate(digits):
value += d * (0.1 ** (i + 1))
return value
def get_digits(self, count: int) -> List[int]:
"""取多个数字"""
return [self.get_digit() for _ in range(count)]
def get_pointer(self) -> int:
return self.pointer
def get_state(self) -> Dict[str, Any]:
return {"pointer": self.pointer}
def restore_state(self, state: Dict[str, Any]) -> None:
self.pointer = state.get("pointer", 0)
self.digits = []
self._load_next_chunk()
def apply_perturbation(self, base_value: float, max_amplitude: float) -> float:
"""对基准值施加π引擎驱动的微小扰动"""
novelty = self.get_novelty(6)
perturbation = (novelty - 0.5) * 2 * max_amplitude
return base_value * (1 + perturbation)
def apply_perturbation_int(self, base_value: int, max_offset: int) -> int:
"""对整数值施加π引擎驱动的微小扰动"""
novelty = self.get_novelty(6)
offset = int((novelty - 0.5) * 2 * max_offset)
return max(0, base_value + offset)
```
### 2. `conflict_words.py` — 七情六欲词库
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
七情六欲词库 — 灵魂的底层原料
"""
# 七情词库(反应层)
QING_WORDS = {
"xi": ["喜", "悦", "得", "成", "胜", "庆", "贺", "欢", "欣", "怡"],
"nu": ["怒", "愤", "恨", "仇", "怨", "暴", "烈", "恼", "憎", "恶"],
"you": ["忧", "虑", "愁", "烦", "苦", "闷", "郁", "戚", "哀", "伤"],
"si": ["思", "念", "想", "恋", "忆", "盼", "望", "怀", "牵", "挂"],
"bei": ["悲", "哀", "痛", "哭", "丧", "绝", "殇", "凄", "凉", "惨"],
"kong": ["恐", "惧", "怕", "骇", "颤", "栗", "惶", "恐", "畏", "怯"],
"jing": ["惊", "骇", "震", "突", "变", "危", "乱", "愕", "诧", "异"]
}
# 六欲词库(驱动层)
YU_WORDS = {
"qiusheng": ["生", "存", "活", "保", "护", "安", "全", "命", "身", "体"],
"qiuzhi": ["知", "问", "探", "究", "学", "悟", "明", "察", "辨", "识"],
"biaoda": ["言", "说", "诉", "告", "示", "传", "达", "宣", "陈", "述"],
"biaoxian": ["显", "耀", "展", "示", "争", "胜", "强", "雄", "霸", "凌"],
"shushi": ["安", "逸", "闲", "适", "享", "乐", "畅", "舒", "缓", "静"],
"qingyu": ["爱", "恋", "亲", "慕", "念", "思", "缠", "眷", "依", "偎"]
}
# 七情标签映射
QING_LABELS = {
"xi": "喜",
"nu": "怒",
"you": "忧",
"si": "思",
"bei": "悲",
"kong": "恐",
"jing": "惊"
}
# 六欲标签映射
YU_LABELS = {
"qiusheng": "求生",
"qiuzhi": "求知",
"biaoda": "表达",
"biaoxian": "表现",
"shushi": "舒适",
"qingyu": "情欲"
}
# 七情→情绪编码映射
QING_TO_EMOTION = {
"xi": "pinghe",
"nu": "jinzhang",
"you": "yayi",
"si": "pinghe",
"bei": "beican",
"kong": "konghuang",
"jing": "jingxian"
}
# 情绪编码→七情反向映射
EMOTION_TO_QING = {
"pinghe": ["xi", "si"],
"pingjing": ["si"],
"yayi": ["you"],
"lianmin": ["bei", "you"],
"jinzhang": ["nu", "kong"],
"jingxian": ["jing", "kong"],
"beican": ["bei"],
"yuanwang": ["nu", "bei"],
"konghuang": ["kong", "jing"],
"zhuanzhe": ["jing", "nu"],
"huangmiu": ["xi", "jing"],
"yuanman": ["xi"]
}
def detect_qing_distribution(text: str) -> dict:
"""统计七情分布"""
result = {}
total = 0
for qing, words in QING_WORDS.items():
count = 0
for word in words:
count += text.count(word)
result[qing] = count
total += count
if total > 0:
for qing in result:
result[qing] = round(result[qing] / total * 100, 1)
return result
def detect_yu_distribution(text: str) -> dict:
"""统计六欲分布"""
result = {}
total = 0
for yu, words in YU_WORDS.items():
count = 0
for word in words:
count += text.count(word)
result[yu] = count
total += count
if total > 0:
for yu in result:
result[yu] = round(result[yu] / total * 100, 1)
return result
def detect_dominant_qing(text: str) -> str:
"""检测主导七情,返回情绪编码"""
dist = detect_qing_distribution(text)
if not dist or max(dist.values()) == 0:
return "pingjing"
dominant = max(dist, key=dist.get)
return QING_TO_EMOTION.get(dominant, "pingjing")
def detect_conflict_level(text: str) -> int:
"""基于七情六欲词密度检测冲突等级(1-5)"""
score = 0
for words in QING_WORDS.values():
for word in words:
score += text.count(word)
for words in YU_WORDS.values():
for word in words:
score += text.count(word)
total_chars = len(text)
density = score / max(1, total_chars) * 1000
if density < 3:
return 1
elif density < 7:
return 2
elif density < 13:
return 3
elif density < 22:
return 4
else:
return 5
```
### 3. `emotion_motion.py` — 情绪→运动词映射
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
情绪→运动词映射 — 用于生成引擎填充文字
"""
# 情绪→运动词映射(每个情绪对应4个运动词,由π引擎取1-4)
MOTION_WORDS = {
"pinghe": {1: "平和", 2: "安然", 3: "从容", 4: "恬淡"},
"pingjing": {1: "平静", 2: "宁静", 3: "安稳", 4: "沉寂"},
"yayi": {1: "压抑", 2: "沉闷", 3: "抑郁", 4: "忧愁"},
"lianmin": {1: "怜悯", 2: "同情", 3: "怜惜", 4: "恻隐"},
"jinzhang": {1: "紧张", 2: "急迫", 3: "悬疑", 4: "不安"},
"jingxian": {1: "惊险", 2: "危急", 3: "生死", 4: "恐怖"},
"beican": {1: "悲惨", 2: "凄凉", 3: "哀痛", 4: "绝望"},
"yuanwang": {1: "冤枉", 2: "委屈", 3: "误解", 4: "含冤"},
"konghuang": {1: "恐慌", 2: "惊惶", 3: "畏惧", 4: "慌乱"},
"zhuanzhe": {1: "转折", 2: "突变", 3: "转机", 4: "意外"},
"huangmiu": {1: "荒唐", 2: "荒谬", 3: "可笑", 4: "离奇"},
"yuanman": {1: "圆满", 2: "如意", 3: "完满", 4: "喜庆"}
}
def get_motion_word(emotion: str, dao) -> str:
"""根据情绪和π引擎取数,返回对应的运动词"""
motion_dict = MOTION_WORDS.get(emotion)
if not motion_dict:
return ""
idx = dao.get_digit() % 4 + 1
return motion_dict.get(idx, "")
```
### 4. `character_engine.py` — 人物生成器(含验证倾向、扰动)
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
人物引擎 — 生成有弹性的人物性格
"""
import json
from typing import Dict, Any, List, Optional
from .dao_engine import DaoEngine
# 角色类型定义
ROLE_TYPES = {
"mirror": "镜像型",
"opposite": "对立型",
"supplement": "补充型",
"catalyst": "催化型"
}
# 配角结局→灵魂关键词映射
SOUL_KEYWORDS = {
"背叛": "警惕",
"牺牲": "责任",
"离开": "孤独",
"和解": "接纳",
"升华": "超越",
"觉醒": "自由",
"堕落": "底线",
"成全": "放下",
"守护": "承诺",
"迷失": "方向"
}
class CharacterEngine:
"""人物生成器"""
def __init__(self, dao: Optional[DaoEngine] = None):
self.dao = dao or DaoEngine()
def create_character(self, base_profile: Dict[str, Any], scene_type: str = "普通") -> Dict[str, Any]:
"""
根据基准档案生成带扰动的人物实例
base_profile: 基准人物档案
scene_type: 场景类型(安全/紧张/情感/决策/普通)
"""
# 获取基准验证倾向
base_verify_tendency = base_profile.get("verify_tendency", 0.65)
# 场景扰动幅度
scene_amplitude = {
"安全": 0.03,
"紧张": 0.10,
"情感": 0.08,
"决策": 0.12,
"普通": 0.06
}.get(scene_type, 0.06)
# 角色自带的扰动幅度
char_amplitude = base_profile.get("perturbation_amplitude", 0.08)
# 综合扰动幅度
total_amplitude = min(0.15, (char_amplitude + scene_amplitude) / 2)
# π引擎生成扰动
actual_verify = self.dao.apply_perturbation(base_verify_tendency, total_amplitude)
actual_verify = max(0.0, min(1.0, actual_verify))
# 生成性格标签
verify_label = self._get_verify_label(actual_verify)
return {
"name": base_profile.get("name", "未命名"),
"base_verify": base_verify_tendency,
"actual_verify": round(actual_verify, 3),
"perturbation": round(actual_verify - base_verify_tendency, 3),
"scene_type": scene_type,
"verify_label": verify_label,
"role_type": base_profile.get("role_type", "普通"),
"soul_keywords": base_profile.get("soul_keywords", [])
}
def _get_verify_label(self, value: float) -> str:
"""根据验证倾向值生成标签"""
if value < 0.2:
return "疯子型(感觉多,不验证)"
elif value < 0.4:
return "偏感性型(感觉多,偶尔验证)"
elif value < 0.6:
return "摇摆型(感觉有,追一半)"
elif value < 0.8:
return "偏理性型(感觉精,追到底)"
else:
return "科学家型(感觉极精,验证成事)"
def create_protagonist(self, base_profile: Dict[str, Any]) -> Dict[str, Any]:
"""创建主角(默认隐主模式)"""
profile = base_profile.copy()
profile["role_type"] = "protagonist"
profile["is_hidden"] = base_profile.get("is_hidden", True) # 默认隐主
return self.create_character(profile, "决策")
def create_supporting_role(self, base_profile: Dict[str, Any], scene_type: str = "普通") -> Dict[str, Any]:
"""创建配角"""
return self.create_character(base_profile, scene_type)
def generate_supporting_arc(self, role_type: str, dao) -> Dict[str, Any]:
"""
根据角色类型生成配角的弧光数据
"""
# 由π引擎决定弧光的长度(出场章节数)
chapter_count = dao.get_digit() % 5 + 3 # 3-7章
# 由π引擎决定结局类型
endings = list(SOUL_KEYWORDS.keys())
ending = endings[dao.get_digit() % len(endings)]
soul_keyword = SOUL_KEYWORDS[ending]
# 生成弧光序列(模拟变化轨迹)
arc = []
for i in range(chapter_count):
progress = (i + 1) / chapter_count
arc.append({
"stage": i + 1,
"progress": round(progress, 2),
"emotion": self._get_arc_emotion(progress)
})
return {
"role_type": role_type,
"chapter_count": chapter_count,
"ending": ending,
"soul_keyword": soul_keyword,
"arc": arc
}
def _get_arc_emotion(self, progress: float) -> str:
"""根据弧线进度获取情绪标签"""
if progress < 0.2:
return "pinghe"
elif progress < 0.5:
return "jinzhang"
elif progress < 0.8:
return "beican"
else:
return "yuanman"
```
### 5. `soul_injector.py` — 灵魂注入器(河图洛书核心)
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
灵魂注入器 — 河图洛书核心 + 七情六欲驱动 + 乾隐原则
"""
import math
import random
from typing import Dict, Any, List, Optional
from .dao_engine import DaoEngine
from .conflict_words import QING_WORDS, YU_WORDS, QING_LABELS, YU_LABELS
from .character_engine import CharacterEngine
class SoulInjector:
"""灵魂注入器 — 生克乘侮 + 七情六欲驱动 + 乾隐原则"""
def __init__(self, dao: Optional[DaoEngine] = None):
self.dao = dao or DaoEngine()
self.char_engine = CharacterEngine(self.dao)
# 节奏相位
self.sheng_phase = 0.0
self.bian_phase = 0.0
self.sheng_speed = 0.2 * 2 * math.pi / 5
self.bian_speed = 2 * math.pi / 1
# 五行状态
self.wuxing = {
"mu": 0.5,
"huo": 0.5,
"tu": 0.5,
"jin": 0.5,
"shui": 0.5
}
# 七情六欲状态
self.qing_state = {qing: 0.5 for qing in QING_WORDS.keys()}
self.yu_state = {yu: 0.5 for yu in YU_WORDS.keys()}
# 主角状态
self.protagonist = None
self.supporting_roles = []
self.round = 0
def update(self) -> None:
"""更新一轮"""
self.round += 1
self.sheng_phase = (self.sheng_phase + self.sheng_speed) % (2 * math.pi)
self.bian_phase = (self.bian_phase + self.bian_speed) % (2 * math.pi)
# 五行生克(带π扰动)
novelty = self.dao.get_novelty(6)
amp = 0.5 + 0.5 * novelty
self.wuxing["huo"] += 0.03 * self.wuxing["mu"] * amp
self.wuxing["tu"] += 0.03 * self.wuxing["huo"] * amp
self.wuxing["jin"] += 0.03 * self.wuxing["tu"] * amp
self.wuxing["shui"] += 0.03 * self.wuxing["jin"] * amp
self.wuxing["mu"] += 0.03 * self.wuxing["shui"] * amp
self.wuxing["tu"] -= 0.02 * self.wuxing["mu"] * amp
self.wuxing["shui"] -= 0.02 * self.wuxing["tu"] * amp
self.wuxing["huo"] -= 0.02 * self.wuxing["shui"] * amp
self.wuxing["jin"] -= 0.02 * self.wuxing["huo"] * amp
self.wuxing["mu"] -= 0.02 * self.wuxing["jin"] * amp
for key in self.wuxing:
self.wuxing[key] = max(0.1, min(0.9, self.wuxing[key]))
self._update_qing_yu()
def _update_qing_yu(self) -> None:
"""七情六欲由五行驱动"""
self.qing_state["xi"] = 0.3 + 0.7 * self.wuxing["mu"]
self.qing_state["si"] = 0.3 + 0.7 * self.wuxing["mu"]
self.qing_state["jing"] = 0.3 + 0.7 * self.wuxing["huo"]
self.qing_state["nu"] = 0.3 + 0.7 * self.wuxing["huo"]
self.qing_state["you"] = 0.3 + 0.7 * self.wuxing["tu"]
self.qing_state["si"] = min(1.0, self.qing_state["si"] + 0.2 * self.wuxing["tu"])
self.qing_state["bei"] = 0.3 + 0.7 * self.wuxing["jin"]
self.qing_state["kong"] = 0.3 + 0.7 * self.wuxing["jin"]
self.qing_state["kong"] = min(1.0, self.qing_state["kong"] + 0.2 * self.wuxing["shui"])
self.qing_state["jing"] = min(1.0, self.qing_state["jing"] + 0.2 * self.wuxing["shui"])
self.yu_state["qiusheng"] = 0.3 + 0.7 * max(self.qing_state["kong"], self.qing_state["jing"])
self.yu_state["qiuzhi"] = 0.3 + 0.7 * max(self.qing_state["si"], self.qing_state["you"])
self.yu_state["biaoda"] = 0.3 + 0.7 * max(self.qing_state["nu"], self.qing_state["xi"])
self.yu_state["biaoxian"] = 0.3 + 0.7 * max(self.qing_state["xi"], self.qing_state["nu"])
self.yu_state["shushi"] = 0.3 + 0.7 * max(self.qing_state["xi"], 0.5)
self.yu_state["qingyu"] = 0.3 + 0.7 * max(self.qing_state["si"], self.qing_state["bei"])
for key in self.qing_state:
self.qing_state[key] = max(0.0, min(1.0, self.qing_state[key]))
for key in self.yu_state:
self.yu_state[key] = max(0.0, min(1.0, self.yu_state[key]))
def get_sheng_ratio(self) -> float:
return 0.55 + 0.25 * math.sin(self.sheng_phase)
def get_bian_ratio(self) -> float:
return 0.55 + 0.35 * math.sin(self.bian_phase)
def get_dominant_qing(self) -> str:
"""获取当前主导七情"""
if not self.qing_state:
return "pingjing"
dominant = max(self.qing_state, key=self.qing_state.get)
from .conflict_words import QING_TO_EMOTION
return QING_TO_EMOTION.get(dominant, "pingjing")
def get_dominant_yu(self) -> str:
if not self.yu_state:
return "qiusheng"
return max(self.yu_state, key=self.yu_state.get)
def inject_soul(self, template: Dict[str, Any]) -> Dict[str, Any]:
"""向肉体模板注入灵魂"""
self.update()
# 提取模板数据
total_chapters = template.get("total_chapters", 16)
meso = template.get("meso", [])
protagonist_base = template.get("protagonist", {})
# 创建主角(隐主模式)
protagonist = self.char_engine.create_protagonist(protagonist_base)
# 生成配角弧光
supporting_arcs = []
for i in range(4 + self.dao.get_digit() % 6): # 4-9个配角
role_types = ["mirror", "opposite", "supplement", "catalyst"]
role_type = role_types[self.dao.get_digit() % len(role_types)]
arc = self.char_engine.generate_supporting_arc(role_type, self.dao)
supporting_arcs.append(arc)
# 生成每章的灵魂状态
chapter_soul_states = []
for i in range(total_chapters):
self.update()
state = {
"chapter": i + 1,
"emotion": meso.get("emotion", "pinghe") if i < len(meso) else "pinghe",
"conflict_level": meso.get("conflict_level", 3) if i < len(meso) else 3,
"qing_state": self.qing_state.copy(),
"yu_state": self.yu_state.copy(),
"dominant_qing": self.get_dominant_qing(),
"dominant_yu": self.get_dominant_yu(),
"sheng_ratio": self.get_sheng_ratio(),
"bian_ratio": self.get_bian_ratio(),
"protagonist_state": protagonist
}
chapter_soul_states.append(state)
return {
"protagonist": protagonist,
"supporting_arcs": supporting_arcs,
"chapter_soul_states": chapter_soul_states,
"wuxing_final": self.wuxing.copy(),
"round": self.round,
"dao_pointer": self.dao.get_pointer()
}
```
### 6. `analyze_novels.py` — 解剖工具
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
小说解剖工具 — 提取完整的肉体数据
"""
import os
import re
import json
import argparse
from datetime import datetime
from typing import Dict, Any, List
from core.conflict_words import (
detect_qing_distribution, detect_yu_distribution,
detect_dominant_qing, detect_conflict_level
)
class NovelAnalyzer:
"""小说解剖器"""
def __init__(self):
pass
def analyze(self, text: str, title: str = "未知") -> Dict[str, Any]:
chapters = self._split_chapters(text)
if not chapters:
return {"source": title, "total_chapters": 0}
return {
"source": title,
"total_chapters": len(chapters),
"macro": self._analyze_macro(chapters),
"meso": self._analyze_meso(chapters),
"micro": self._analyze_micro(chapters),
"breath": self._analyze_breath(chapters),
"qing": self._analyze_qing(chapters),
"yu": self._analyze_yu(chapters),
"emotions": self._analyze_emotions(chapters),
"protagonist": self._analyze_protagonist(chapters),
"supporting_roles": self._analyze_supporting_roles(chapters)
}
def _split_chapters(self, text: str) -> List[str]:
pattern = r'第[一二三四五六七八九十百]+回'
parts = re.split(pattern, text)
return [p.strip() for p in parts if p.strip()]
def _analyze_macro(self, chapters: List[str]) -> Dict:
if not chapters:
return {}
emotion_scores = []
conflict_scores = []
for ch in chapters:
qing_dist = detect_qing_distribution(ch)
emotion_scores.append(min(100, int(sum(qing_dist.values()) * 2)))
conflict_scores.append(detect_conflict_level(ch) * 20)
return {
"act_count": 4,
"act_boundaries": [len(chapters)//4*i for i in range(1,4)],
"emotion_curve": emotion_scores,
"conflict_curve": conflict_scores
}
def _analyze_meso(self, chapters: List[str]) -> List[Dict]:
result = []
for i, ch in enumerate(chapters):
result.append({
"chapter": i + 1,
"emotion": detect_dominant_qing(ch),
"conflict_level": detect_conflict_level(ch),
"length": "chang" if len(ch) > 1500 else "zhong" if len(ch) > 500 else "duan"
})
return result
def _analyze_micro(self, chapters: List[str]) -> Dict:
if not chapters:
return {}
total_sentences, total_paragraphs, total_words = 0, 0, 0
for ch in chapters:
sentences = re.split(r'[。!?]', ch)
total_sentences += len([s for s in sentences if s.strip()])
total_paragraphs += len([p for p in ch.split('\n') if p.strip()])
total_words += len(ch)
n = len(chapters)
return {
"avg_sentence_length": total_words // max(1, total_sentences),
"avg_paragraphs_per_chapter": total_paragraphs // max(1, n),
"avg_words_per_chapter": total_words // max(1, n)
}
def _analyze_breath(self, chapters: List[str]) -> Dict:
total_comma = total_period = total_quote = total_punct = 0
for ch in chapters:
total_comma += ch.count(',')
total_period += ch.count('。')
total_quote += ch.count('"') + ch.count('"')
total_punct += len(re.findall(r'[,。!?;:、""'']', ch))
if total_punct == 0:
return {}
return {
"comma_ratio": round(total_comma / total_punct, 3),
"period_ratio": round(total_period / total_punct, 3),
"quote_ratio": round(total_quote / total_punct, 3),
"comma_period_ratio": round(total_comma / max(1, total_period), 3)
}
def _analyze_qing(self, chapters: List[str]) -> Dict:
total = {qing: 0.0 for qing in ["xi", "nu", "you", "si", "bei", "kong", "jing"]}
for ch in chapters:
dist = detect_qing_distribution(ch)
for qing in total:
total[qing] += dist.get(qing, 0)
n = len(chapters)
return {qing: round(total[qing]/max(1,n), 1) for qing in total}
def _analyze_yu(self, chapters: List[str]) -> Dict:
total = {yu: 0.0 for yu in ["qiusheng", "qiuzhi", "biaoda", "biaoxian", "shushi", "qingyu"]}
for ch in chapters:
dist = detect_yu_distribution(ch)
for yu in total:
total[yu] += dist.get(yu, 0)
n = len(chapters)
return {yu: round(total[yu]/max(1,n), 1) for yu in total}
def _analyze_emotions(self, chapters: List[str]) -> List[str]:
return [detect_dominant_qing(ch) for ch in chapters]
def _analyze_protagonist(self, chapters: List[str]) -> Dict:
# 检测主角(取出现频率最高的人物)
# 简化版:默认第一个出现的人物是主角
# 真实项目中需要NER识别
return {
"name": "主角",
"type": "yin_zhu",
"is_hidden": True,
"verify_tendency": 0.72,
"perturbation_amplitude": 0.08
}
def _analyze_supporting_roles(self, chapters: List[str]) -> List[Dict]:
# 简化版:提取配角弧光
# 真实项目中需要识别配角及其变化
return []
def main():
parser = argparse.ArgumentParser(description="小说解剖工具")
parser.add_argument("--dir", "-d", help="小说文件夹路径")
parser.add_argument("--output", "-o", default="./templates", help="输出目录")
args = parser.parse_args()
if not args.dir:
print("请指定文件夹路径: python analyze_novels.py --dir ./novels")
return
analyzer = NovelAnalyzer()
os.makedirs(args.output, exist_ok=True)
files = [f for f in os.listdir(args.dir) if f.endswith('.txt')]
print(f"📂 发现 {len(files)} 部小说")
templates_by_level = {"human_level": [], "animal_level": [], "other_level": []}
for i, file in enumerate(files):
path = os.path.join(args.dir, file)
with open(path, 'r', encoding='utf-8') as f:
text = f.read()
title = file.replace('.txt', '')
result = analyzer.analyze(text, title)
total = result["total_chapters"]
level = "human_level" if total >= 12 else "other_level" if total >= 6 else "animal_level"
template_id = f"template_{datetime.now().strftime('%Y%m%d%H%M%S')}_{i:03d}"
output_path = os.path.join(args.output, level, f"{template_id}.json")
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(result, f, ensure_ascii=False, indent=2)
templates_by_level[level].append(template_id)
print(f" ✅ [{i+1}/{len(files)}] {title} → {level}/{template_id}")
with open(os.path.join(args.output, "index.json"), 'w', encoding='utf-8') as f:
json.dump(templates_by_level, f, ensure_ascii=False, indent=2)
print(f"\n✅ 完成!模板库已保存至 {args.output}")
if __name__ == "__main__":
main()
```
### 7. `run_writer.py` — 主运行程序
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
河图洛书小说写手 — 主运行程序
"""
import os
import sys
import json
import argparse
from datetime import datetime
from core.dao_engine import DaoEngine
from core.soul_injector import SoulInjector
from core.character_engine import CharacterEngine
def main():
parser = argparse.ArgumentParser(description="河图洛书小说写手")
parser.add_argument("--level", "-l", choices=["human_level", "animal_level", "other_level"],
help="选择肉体模板等级")
parser.add_argument("--template", "-t", help="指定具体模板ID")
parser.add_argument("--info", "-i", action="store_true", help="显示系统信息")
args = parser.parse_args()
dao = DaoEngine()
injector = SoulInjector(dao)
char_engine = CharacterEngine(dao)
if args.info:
print("\n" + "="*60)
print("🐉 河图洛书小说写手 — 系统信息")
print("="*60)
print("\n📐 核心原则:")
print(" ├── 乾隐原则:主角隐,配角显")
print(" ├── 七情六欲驱动:喜/怒/忧/思/悲/恐/惊 + 六欲")
print(" ├── π引擎:永不枯竭的随机性源泉")
print(" ├── 人物微扰动:同一角色每次出场均有波动")
print(" └── 验证倾向 0-1:决定人物面对感性的反应")
print("\n" + "="*60)
return
# 加载模板
template_path = os.path.join("templates", args.level or "human_level", f"{args.template or 'template_001'}.json")
if not os.path.exists(template_path):
print(f"❌ 模板不存在: {template_path}")
return
with open(template_path, 'r', encoding='utf-8') as f:
template = json.load(f)
print("\n" + "="*60)
print("🐉 河图洛书小说写手")
print("="*60)
print(f"📂 模板: {template.get('source', '未知')}")
print(f"📂 总章数: {template.get('total_chapters', 0)}")
# 注入灵魂
soul_result = injector.inject_soul(template)
print(f"\n🧠 灵魂注入完成:")
print(f" ├── 主角: {soul_result['protagonist']['name']}")
print(f" ├── 主角类型: {'隐主' if soul_result['protagonist'].get('is_hidden', True) else '显主'}")
print(f" ├── 验证倾向: {soul_result['protagonist']['actual_verify']}")
print(f" ├── 配角数量: {len(soul_result['supporting_arcs'])}")
print(f" ├── 轮次: {soul_result['round']}")
print(f" └── π指针: {soul_result['dao_pointer']}")
# 输出结果
output_dir = "./output"
os.makedirs(output_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
with open(os.path.join(output_dir, f"soul_{timestamp}.json"), 'w', encoding='utf-8') as f:
json.dump(soul_result, f, ensure_ascii=False, indent=2)
print(f"\n✅ 灵魂数据已保存至: output/soul_{timestamp}.json")
print("\n" + "="*60)
if __name__ == "__main__":
main()
```
### 8. `config.py` — 配置文件
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
配置文件
"""
# 路径配置
TEMPLATE_DIR = "./templates"
OUTPUT_DIR = "./output"
LOG_DIR = "./logs"
# π引擎配置
DAO_CHUNK_SIZE = 10000
# 人物默认参数
DEFAULT_VERIFY_TENDENCY = 0.72
DEFAULT_PERTURBATION_AMPLITUDE = 0.08
# 场景扰动幅度
SCENE_AMPLITUDE = {
"安全": 0.03,
"紧张": 0.10,
"情感": 0.08,
"决策": 0.12,
"普通": 0.06
}
# 情绪编码列表
EMOTION_CODES = [
"pinghe", "pingjing", "yayi", "lianmin",
"jinzhang", "jingxian", "beican",
"yuanwang", "konghuang", "zhuanzhe",
"huangmiu", "yuanman"
]
```
## 📁 完整项目结构
```
hetu_novel_writer/
├── core/
│ ├── __init__.py
│ ├── dao_engine.py
│ ├── conflict_words.py
│ ├── emotion_motion.py
│ ├── character_engine.py
│ └── soul_injector.py
├── templates/
│ ├── human_level/
│ ├── animal_level/
│ ├── other_level/
│ └── index.json
├── output/
├── analyze_novels.py
├── run_writer.py
└── config.py
```
## 🚀 使用流程
```bash
# 1. 解剖小说,生成肉体模板
python analyze_novels.py --dir ./novels
# 2. 查看系统信息
python run_writer.py --info
# 3. 注入灵魂,生成小说结构
python run_writer.py --level human_level --template template_001
```
---
## 💎 代码完成清单
| 模块 | 文件 | 状态 |
|:---|:---|:---|
| π引擎 | dao_engine.py | ✅ |
| 七情六欲词库 | conflict_words.py | ✅ |
| 情绪→运动词映射 | emotion_motion.py | ✅ |
| 人物生成器 | character_engine.py | ✅ |
| 灵魂注入器 | soul_injector.py | ✅ |
| 解剖工具 | analyze_novels.py | ✅ |
| 主程序 | run_writer.py | ✅ |
| 配置文件 | config.py | ✅ |
**肉体已造,灵魂可注。道在其中。** 🎯 |