232 lines
8.6 KiB
Python
232 lines
8.6 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
inkos 终极修复方案
|
|||
|
|
直接修复数据库中的数据错误
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import shutil
|
|||
|
|
import sqlite3
|
|||
|
|
import subprocess
|
|||
|
|
import time
|
|||
|
|
|
|||
|
|
def stop_inkos():
|
|||
|
|
"""停止inkos所有进程"""
|
|||
|
|
print("1. 停止inkos所有进程...")
|
|||
|
|
subprocess.run(["pkill", "-9", "-f", "node.*inkos"], capture_output=True)
|
|||
|
|
subprocess.run(["pkill", "-9", "-f", "inkos"], capture_output=True)
|
|||
|
|
time.sleep(3)
|
|||
|
|
print(" ✅ inkos已停止")
|
|||
|
|
|
|||
|
|
def backup_data():
|
|||
|
|
"""备份所有数据"""
|
|||
|
|
print("2. 备份数据...")
|
|||
|
|
backup_dir = f"/root/.openclaw/workspace/backups/inkos_ultimate_fix_{time.strftime('%Y%m%d_%H%M%S')}"
|
|||
|
|
os.makedirs(backup_dir, exist_ok=True)
|
|||
|
|
|
|||
|
|
# 备份重要文件和目录
|
|||
|
|
backup_items = [
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/inkos.json",
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/tomato-novel/books/末日重生-开局囤货十亿物资",
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/books/末日重生-开局囤货十亿物资"
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for item in backup_items:
|
|||
|
|
if os.path.exists(item):
|
|||
|
|
if os.path.isfile(item):
|
|||
|
|
shutil.copy2(item, backup_dir)
|
|||
|
|
else:
|
|||
|
|
shutil.copytree(item, os.path.join(backup_dir, os.path.basename(item)), dirs_exist_ok=True)
|
|||
|
|
print(f" 已备份: {os.path.basename(item)}")
|
|||
|
|
|
|||
|
|
print(f" 备份位置: {backup_dir}")
|
|||
|
|
return backup_dir
|
|||
|
|
|
|||
|
|
def fix_database():
|
|||
|
|
"""修复数据库文件"""
|
|||
|
|
print("3. 修复数据库文件...")
|
|||
|
|
|
|||
|
|
# 找到并修复所有数据库文件
|
|||
|
|
db_files = [
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/tomato-novel/books/末日重生-开局囤货十亿物资/story/memory.db",
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/books/末日重生-开局囤货十亿物资/story/memory.db"
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for db_file in db_files:
|
|||
|
|
if os.path.exists(db_file):
|
|||
|
|
print(f" 检查数据库: {db_file}")
|
|||
|
|
try:
|
|||
|
|
# 备份数据库
|
|||
|
|
shutil.copy2(db_file, f"{db_file}.backup")
|
|||
|
|
|
|||
|
|
# 尝试连接到数据库
|
|||
|
|
conn = sqlite3.connect(db_file)
|
|||
|
|
cursor = conn.cursor()
|
|||
|
|
|
|||
|
|
# 获取所有表名
|
|||
|
|
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
|
|||
|
|
tables = cursor.fetchall()
|
|||
|
|
print(f" 数据库表: {[t[0] for t in tables]}")
|
|||
|
|
|
|||
|
|
# 查找可能包含章节数据的表
|
|||
|
|
for table in tables:
|
|||
|
|
table_name = table[0]
|
|||
|
|
if 'chapter' in table_name.lower() or 'row' in table_name.lower():
|
|||
|
|
print(f" 检查表: {table_name}")
|
|||
|
|
|
|||
|
|
# 获取表结构
|
|||
|
|
cursor.execute(f"PRAGMA table_info({table_name});")
|
|||
|
|
columns = cursor.fetchall()
|
|||
|
|
print(f" 列: {[col[1] for col in columns]}")
|
|||
|
|
|
|||
|
|
# 查找title列
|
|||
|
|
title_col = None
|
|||
|
|
for col in columns:
|
|||
|
|
if 'title' in col[1].lower():
|
|||
|
|
title_col = col[1]
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if title_col:
|
|||
|
|
# 查找空标题的行
|
|||
|
|
cursor.execute(f"SELECT rowid, {title_col} FROM {table_name} WHERE {title_col} IS NULL OR {title_col} = '' OR LENGTH(TRIM({title_col})) = 0;")
|
|||
|
|
empty_titles = cursor.fetchall()
|
|||
|
|
|
|||
|
|
if empty_titles:
|
|||
|
|
print(f" 找到 {len(empty_titles)} 个空标题")
|
|||
|
|
for rowid, title in empty_titles:
|
|||
|
|
# 修复空标题
|
|||
|
|
new_title = f"第{rowid}章"
|
|||
|
|
cursor.execute(f"UPDATE {table_name} SET {title_col} = ? WHERE rowid = ?", (new_title, rowid))
|
|||
|
|
print(f" 修复行 {rowid}: '{new_title}'")
|
|||
|
|
|
|||
|
|
conn.commit()
|
|||
|
|
conn.close()
|
|||
|
|
print(f" ✅ 数据库修复完成: {os.path.basename(db_file)}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f" ❌ 修复数据库时出错: {e}")
|
|||
|
|
# 如果数据库损坏严重,删除它让inkos重新创建
|
|||
|
|
print(f" 删除损坏的数据库: {db_file}")
|
|||
|
|
os.remove(db_file)
|
|||
|
|
print(f" ✅ 已删除,inkos将重新创建数据库")
|
|||
|
|
|
|||
|
|
def clean_state_files():
|
|||
|
|
"""清理状态文件,让inkos重新开始"""
|
|||
|
|
print("4. 清理状态文件...")
|
|||
|
|
|
|||
|
|
# 删除可能损坏的状态文件
|
|||
|
|
state_dirs = [
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/tomato-novel/books/末日重生-开局囤货十亿物资/story/state",
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/tomato-novel/books/末日重生-开局囤货十亿物资/story/runtime",
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/books/末日重生-开局囤货十亿物资/story/state",
|
|||
|
|
"/root/.openclaw/workspace/tomato-novel/books/末日重生-开局囤货十亿物资/story/runtime"
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for state_dir in state_dirs:
|
|||
|
|
if os.path.exists(state_dir):
|
|||
|
|
# 只删除特定文件,保留章节文件
|
|||
|
|
for file in os.listdir(state_dir):
|
|||
|
|
if file.endswith('.json') or file.endswith('.db'):
|
|||
|
|
file_path = os.path.join(state_dir, file)
|
|||
|
|
try:
|
|||
|
|
os.remove(file_path)
|
|||
|
|
print(f" 删除: {file}")
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
print(" ✅ 状态文件已清理")
|
|||
|
|
|
|||
|
|
def create_simple_config():
|
|||
|
|
"""创建最简单的配置"""
|
|||
|
|
print("5. 创建简单配置...")
|
|||
|
|
|
|||
|
|
config = {
|
|||
|
|
"name": "tomato-novel-fixed",
|
|||
|
|
"version": "0.1.0",
|
|||
|
|
"language": "zh",
|
|||
|
|
"llm": {
|
|||
|
|
"provider": "custom",
|
|||
|
|
"baseUrl": "https://ark.cn-beijing.volces.com/api/coding/v3",
|
|||
|
|
"model": "deepseek-v3.2"
|
|||
|
|
},
|
|||
|
|
"daemon": {
|
|||
|
|
"schedule": {
|
|||
|
|
"writeCron": "0 */2 * * *" # 每2小时一次
|
|||
|
|
},
|
|||
|
|
"maxConcurrentBooks": 1
|
|||
|
|
},
|
|||
|
|
"quality": {
|
|||
|
|
"enforcement": "none" # 完全关闭质量检查
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
config_path = "/root/.openclaw/workspace/tomato-novel/inkos.json"
|
|||
|
|
with open(config_path, 'w', encoding='utf-8') as f:
|
|||
|
|
json.dump(config, f, ensure_ascii=False, indent=2)
|
|||
|
|
|
|||
|
|
print(" ✅ 简单配置已创建")
|
|||
|
|
|
|||
|
|
def start_inkos():
|
|||
|
|
"""启动inkos"""
|
|||
|
|
print("6. 启动inkos...")
|
|||
|
|
|
|||
|
|
os.chdir("/root/.openclaw/workspace/tomato-novel")
|
|||
|
|
|
|||
|
|
# 启动inkos
|
|||
|
|
with open("/tmp/inkos_ultimate_start.log", "w") as log_file:
|
|||
|
|
process = subprocess.Popen(
|
|||
|
|
["nohup", "inkos", "up"],
|
|||
|
|
stdout=log_file,
|
|||
|
|
stderr=subprocess.STDOUT,
|
|||
|
|
start_new_session=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
time.sleep(10)
|
|||
|
|
|
|||
|
|
# 检查是否启动成功
|
|||
|
|
result = subprocess.run(["ps", "aux"], capture_output=True, text=True)
|
|||
|
|
if "inkos up" in result.stdout:
|
|||
|
|
pid_line = [line for line in result.stdout.split('\n') if "inkos up" in line][0]
|
|||
|
|
pid = pid_line.split()[1]
|
|||
|
|
print(f" ✅ inkos 已启动 (PID: {pid})")
|
|||
|
|
return True
|
|||
|
|
else:
|
|||
|
|
print(" ❌ inkos 启动失败")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""主函数"""
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("inkos 终极修复方案")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
stop_inkos()
|
|||
|
|
backup_dir = backup_data()
|
|||
|
|
fix_database()
|
|||
|
|
clean_state_files()
|
|||
|
|
create_simple_config()
|
|||
|
|
|
|||
|
|
if start_inkos():
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("✅ 修复完成!")
|
|||
|
|
print(f"备份位置: {backup_dir}")
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("\ninkos 已重新启动,配置为:")
|
|||
|
|
print("- 质量检查: 关闭")
|
|||
|
|
print("- 创作频率: 每2小时")
|
|||
|
|
print("- 日志文件: /tmp/inkos_ultimate_start.log")
|
|||
|
|
print("\n等待5-10分钟后,使用以下命令测试:")
|
|||
|
|
print(" inkos status")
|
|||
|
|
print(" inkos draft 末日重生-开局囤货十亿物资")
|
|||
|
|
else:
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("❌ 修复失败!")
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("\n请检查:")
|
|||
|
|
print("1. inkos 是否安装: which inkos")
|
|||
|
|
print("2. 日志文件: tail -100 /tmp/inkos_ultimate_start.log")
|
|||
|
|
print("3. 可能需要重新安装 inkos")
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|