重构路由架构
This commit is contained in:
@@ -1,68 +1,16 @@
|
||||
from fastapi import APIRouter
|
||||
from ..core.items import ChatRequest
|
||||
from ..tools.get_all_role_and_chat import get_all_role_and_chat
|
||||
from ..core.models.chat_history import ChatHistory # 修改导入语句
|
||||
from .routes import presetsRoute, chatsRoute, worldbooksRoute
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
# 从本地读取所有的data内容
|
||||
# 注册子路由
|
||||
router.include_router(presetsRoute.router)
|
||||
router.include_router(chatsRoute.router)
|
||||
router.include_router(worldbooksRoute.router)
|
||||
|
||||
|
||||
# 保留原有的其他路由
|
||||
@router.get("/tool_bar/get_all_role_and_chat")
|
||||
def get_all_role_and_chat_endpoint():
|
||||
# 正确调用函数并返回结果
|
||||
return get_all_role_and_chat()
|
||||
|
||||
# 根据rolename和chatname读取特定聊天记录
|
||||
@router.get("/chat_box/get_chat_history")
|
||||
async def get_chat_history_endpoint(role_name: str, chat_name: str):
|
||||
# 实例化工具类
|
||||
reader = ChatHistory.load_from_file(role_name, chat_name)
|
||||
|
||||
return reader.to_chatbox_format()
|
||||
|
||||
|
||||
# 从本地读取所有的预设列表内容
|
||||
@router.get("/presets/list")
|
||||
async def get_presets_list():
|
||||
"""
|
||||
获取所有可用的预设列表
|
||||
返回预设名称列表
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# 预设文件存储目录
|
||||
preset_dir = Path("data/preset")
|
||||
|
||||
# 确保目录存在
|
||||
if not preset_dir.exists():
|
||||
return {"presets": []}
|
||||
|
||||
# 获取所有.json文件
|
||||
preset_files = list(preset_dir.glob("*.json"))
|
||||
|
||||
# 提取文件名(不带扩展名)作为预设名称
|
||||
presets = [file.stem for file in preset_files]
|
||||
|
||||
return {"presets": presets}
|
||||
|
||||
|
||||
# 从本地读取特定预设
|
||||
@router.get("/presets/{preset_name}")
|
||||
async def get_preset_content(preset_name: str):
|
||||
"""
|
||||
获取特定预设的完整内容
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
return preset_data
|
||||
|
||||
from ..tools.get_all_role_and_chat import get_all_role_and_chat
|
||||
return get_all_role_and_chat()
|
||||
|
||||
193
backend/api/routes/chatsRoute.py
Normal file
193
backend/api/routes/chatsRoute.py
Normal file
@@ -0,0 +1,193 @@
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pathlib import Path
|
||||
import json
|
||||
from typing import List, Dict
|
||||
from backend.core.models.chat_history import ChatHistory, Message
|
||||
|
||||
router = APIRouter(prefix="/chats", tags=["chats"])
|
||||
|
||||
|
||||
# ========== 聊天历史基础路由 ==========
|
||||
|
||||
@router.get("", response_model=Dict[str, List[Dict]])
|
||||
async def list_all_chats():
|
||||
"""获取所有角色的所有聊天列表"""
|
||||
data_dir = Path("data")
|
||||
if not data_dir.exists():
|
||||
return {"chats": []}
|
||||
|
||||
chats = []
|
||||
for role_dir in data_dir.iterdir():
|
||||
if role_dir.is_dir():
|
||||
for chat_file in role_dir.glob("*.jsonl"):
|
||||
try:
|
||||
with open(chat_file, 'r', encoding='utf-8') as f:
|
||||
# 读取第一行获取元数据
|
||||
first_line = f.readline()
|
||||
metadata = json.loads(first_line)
|
||||
chats.append({
|
||||
"role_name": role_dir.name,
|
||||
"chat_name": chat_file.stem,
|
||||
"user_name": metadata.get("user_name", "User"),
|
||||
"character_name": metadata.get("character_name", "Assistant"),
|
||||
"last_modified": metadata.get("last_modified", ""),
|
||||
"message_count": sum(1 for _ in f) # 统计剩余行数(消息数)
|
||||
})
|
||||
except Exception as e:
|
||||
continue # 跳过损坏的聊天文件
|
||||
return {"chats": chats}
|
||||
|
||||
|
||||
@router.get("/{role_name}/{chat_name}")
|
||||
async def get_chat(role_name: str, chat_name: str):
|
||||
"""获取指定聊天的完整内容"""
|
||||
try:
|
||||
chat_history = ChatHistory.load_from_file(role_name, chat_name)
|
||||
return {
|
||||
"metadata": chat_history.chat_metadata.dict(),
|
||||
"messages": chat_history.to_chatbox_format()
|
||||
}
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
|
||||
|
||||
@router.post("/{role_name}", status_code=status.HTTP_201_CREATED)
|
||||
async def create_chat(role_name: str, chat_name: str, metadata: Dict = None):
|
||||
"""创建新聊天"""
|
||||
role_dir = Path("data") / role_name
|
||||
role_dir.mkdir(parents=True, exist_ok=True)
|
||||
chat_path = role_dir / f"{chat_name}.jsonl"
|
||||
|
||||
if chat_path.exists():
|
||||
raise HTTPException(status_code=400, detail="Chat already exists")
|
||||
|
||||
# 创建聊天历史对象
|
||||
chat_history = ChatHistory(
|
||||
chat_metadata=metadata or {},
|
||||
messages=[]
|
||||
)
|
||||
|
||||
# 保存到文件
|
||||
chat_history.save_to_file(role_name, chat_name)
|
||||
return {"message": "Chat created successfully"}
|
||||
|
||||
|
||||
@router.put("/{role_name}/{chat_name}")
|
||||
async def update_chat(role_name: str, chat_name: str, update_data: Dict):
|
||||
"""更新聊天元数据"""
|
||||
try:
|
||||
chat_history = ChatHistory.load_from_file(role_name, chat_name)
|
||||
|
||||
# 更新元数据
|
||||
if "metadata" in update_data:
|
||||
for key, value in update_data["metadata"].items():
|
||||
if hasattr(chat_history.chat_metadata, key):
|
||||
setattr(chat_history.chat_metadata, key, value)
|
||||
|
||||
# 保存更改
|
||||
chat_history.save_to_file(role_name, chat_name)
|
||||
return {"message": "Chat metadata updated successfully"}
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
|
||||
|
||||
@router.delete("/{role_name}/{chat_name}")
|
||||
async def delete_chat(role_name: str, chat_name: str):
|
||||
"""删除指定聊天"""
|
||||
chat_path = Path("data") / role_name / f"{chat_name}.jsonl"
|
||||
if not chat_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
chat_path.unlink()
|
||||
return {"message": "Chat deleted successfully"}
|
||||
|
||||
|
||||
# ========== 聊天消息路由 ==========
|
||||
|
||||
@router.get("/{role_name}/{chat_name}/messages")
|
||||
async def list_messages(role_name: str, chat_name: str):
|
||||
"""获取聊天的所有消息"""
|
||||
try:
|
||||
chat_history = ChatHistory.load_from_file(role_name, chat_name)
|
||||
return {"messages": chat_history.to_chatbox_format()}
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
|
||||
|
||||
@router.get("/{role_name}/{chat_name}/messages/{floor}")
|
||||
async def get_message(role_name: str, chat_name: str, floor: int):
|
||||
"""获取指定楼层的消息"""
|
||||
try:
|
||||
chat_history = ChatHistory.load_from_file(role_name, chat_name)
|
||||
message = next((msg for msg in chat_history.messages if msg.floor == floor), None)
|
||||
|
||||
if not message:
|
||||
raise HTTPException(status_code=404, detail="Message not found")
|
||||
|
||||
return message.dict()
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
|
||||
|
||||
@router.post("/{role_name}/{chat_name}/messages", status_code=status.HTTP_201_CREATED)
|
||||
async def add_message(role_name: str, chat_name: str, message_data: Dict):
|
||||
"""向聊天添加新消息"""
|
||||
try:
|
||||
chat_history = ChatHistory.load_from_file(role_name, chat_name)
|
||||
|
||||
# 创建消息对象
|
||||
message = Message(**message_data)
|
||||
|
||||
# 检查楼层是否已存在
|
||||
if any(msg.floor == message.floor for msg in chat_history.messages):
|
||||
raise HTTPException(status_code=400, detail="Message floor already exists")
|
||||
|
||||
# 添加消息
|
||||
chat_history.messages.append(message)
|
||||
|
||||
# 保存更改
|
||||
chat_history.save_to_file(role_name, chat_name)
|
||||
return {"message": "Message added successfully", "floor": message.floor}
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
|
||||
|
||||
@router.put("/{role_name}/{chat_name}/messages/{floor}")
|
||||
async def update_message(role_name: str, chat_name: str, floor: int, update_data: Dict):
|
||||
"""更新指定楼层的消息"""
|
||||
try:
|
||||
chat_history = ChatHistory.load_from_file(role_name, chat_name)
|
||||
message = next((msg for msg in chat_history.messages if msg.floor == floor), None)
|
||||
|
||||
if not message:
|
||||
raise HTTPException(status_code=404, detail="Message not found")
|
||||
|
||||
# 更新消息字段
|
||||
for key, value in update_data.items():
|
||||
if hasattr(message, key):
|
||||
setattr(message, key, value)
|
||||
|
||||
# 保存更改
|
||||
chat_history.save_to_file(role_name, chat_name)
|
||||
return {"message": "Message updated successfully"}
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
|
||||
|
||||
@router.delete("/{role_name}/{chat_name}/messages/{floor}")
|
||||
async def delete_message(role_name: str, chat_name: str, floor: int):
|
||||
"""删除指定楼层的消息"""
|
||||
try:
|
||||
chat_history = ChatHistory.load_from_file(role_name, chat_name)
|
||||
|
||||
# 查找并删除消息
|
||||
original_length = len(chat_history.messages)
|
||||
chat_history.messages = [msg for msg in chat_history.messages if msg.floor != floor]
|
||||
|
||||
if len(chat_history.messages) == original_length:
|
||||
raise HTTPException(status_code=404, detail="Message not found")
|
||||
|
||||
# 保存更改
|
||||
chat_history.save_to_file(role_name, chat_name)
|
||||
return {"message": "Message deleted successfully"}
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Chat not found")
|
||||
264
backend/api/routes/presetsRoute.py
Normal file
264
backend/api/routes/presetsRoute.py
Normal file
@@ -0,0 +1,264 @@
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pathlib import Path
|
||||
import json
|
||||
from typing import List, Dict
|
||||
from backend.core.models.PromptList import AIDesignSpec
|
||||
from backend.core.models.PromptComponent import PromptComponent
|
||||
|
||||
router = APIRouter(prefix="/presets", tags=["presets"])
|
||||
|
||||
|
||||
# ========== 预设基础路由 ==========
|
||||
|
||||
@router.get("", response_model=Dict[str, List[Dict]])
|
||||
async def list_presets():
|
||||
"""获取所有预设列表及其基本信息"""
|
||||
preset_dir = Path("data/preset")
|
||||
if not preset_dir.exists():
|
||||
return {"presets": []}
|
||||
|
||||
presets = []
|
||||
for preset_file in preset_dir.glob("*.json"):
|
||||
try:
|
||||
with open(preset_file, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
presets.append({
|
||||
"name": preset_file.stem,
|
||||
"description": preset_data.get("description", ""),
|
||||
"component_count": len(preset_data.get("prompts", [])),
|
||||
"temperature": preset_data.get("temperature", 1.0)
|
||||
})
|
||||
except Exception as e:
|
||||
continue # 跳过损坏的预设文件
|
||||
return {"presets": presets}
|
||||
|
||||
|
||||
@router.get("/{preset_name}")
|
||||
async def get_preset(preset_name: str):
|
||||
"""获取指定预设的完整内容"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
# 转换为AIDesignSpec对象进行验证
|
||||
ai_design_spec = AIDesignSpec(**preset_data)
|
||||
return ai_design_spec.dict()
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to load preset: {str(e)}")
|
||||
|
||||
|
||||
@router.post("", status_code=status.HTTP_201_CREATED)
|
||||
async def create_preset(preset_name: str, preset_data: Dict):
|
||||
"""创建新预设"""
|
||||
preset_dir = Path("data/preset")
|
||||
preset_dir.mkdir(parents=True, exist_ok=True)
|
||||
preset_path = preset_dir / f"{preset_name}.json"
|
||||
|
||||
if preset_path.exists():
|
||||
raise HTTPException(status_code=400, detail="Preset already exists")
|
||||
|
||||
try:
|
||||
# 验证并转换为AIDesignSpec对象
|
||||
ai_design_spec = AIDesignSpec(**preset_data)
|
||||
|
||||
# 保存到文件
|
||||
with open(preset_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(ai_design_spec.dict(), f, ensure_ascii=False, indent=2)
|
||||
|
||||
return {"message": "Preset created successfully", "name": preset_name}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to create preset: {str(e)}")
|
||||
|
||||
|
||||
@router.put("/{preset_name}")
|
||||
async def update_preset(preset_name: str, update_data: Dict):
|
||||
"""更新预设配置"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
# 加载现有预设
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
# 更新字段
|
||||
for key, value in update_data.items():
|
||||
preset_data[key] = value
|
||||
|
||||
# 验证并转换为AIDesignSpec对象
|
||||
ai_design_spec = AIDesignSpec(**preset_data)
|
||||
|
||||
# 保存更新
|
||||
with open(preset_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(ai_design_spec.dict(), f, ensure_ascii=False, indent=2)
|
||||
|
||||
return {"message": "Preset updated successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to update preset: {str(e)}")
|
||||
|
||||
|
||||
@router.delete("/{preset_name}")
|
||||
async def delete_preset(preset_name: str):
|
||||
"""删除指定预设"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
preset_path.unlink()
|
||||
return {"message": "Preset deleted successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to delete preset: {str(e)}")
|
||||
|
||||
|
||||
# ========== 预设组件路由 ==========
|
||||
|
||||
@router.get("/{preset_name}/components")
|
||||
async def list_preset_components(preset_name: str):
|
||||
"""获取预设中的所有组件"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
# 获取组件列表
|
||||
components = preset_data.get("prompts", [])
|
||||
return {"components": components}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to load components: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/{preset_name}/components/{component_id}")
|
||||
async def get_preset_component(preset_name: str, component_id: str):
|
||||
"""获取指定组件的详情"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
# 查找组件
|
||||
components = preset_data.get("prompts", [])
|
||||
component = next((c for c in components if c.get("identifier") == component_id), None)
|
||||
|
||||
if not component:
|
||||
raise HTTPException(status_code=404, detail="Component not found")
|
||||
|
||||
return component
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to load component: {str(e)}")
|
||||
|
||||
|
||||
@router.post("/{preset_name}/components", status_code=status.HTTP_201_CREATED)
|
||||
async def add_preset_component(preset_name: str, component_data: Dict):
|
||||
"""向预设添加新组件"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
# 加载预设数据
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
# 验证组件数据
|
||||
component = PromptComponent(**component_data)
|
||||
|
||||
# 检查组件ID是否已存在
|
||||
components = preset_data.get("prompts", [])
|
||||
if any(c.get("identifier") == component.identifier for c in components):
|
||||
raise HTTPException(status_code=400, detail="Component identifier already exists")
|
||||
|
||||
# 添加组件
|
||||
components.append(component.dict())
|
||||
preset_data["prompts"] = components
|
||||
|
||||
# 保存更新
|
||||
with open(preset_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(preset_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
return {"message": "Component added successfully", "identifier": component.identifier}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to add component: {str(e)}")
|
||||
|
||||
|
||||
@router.put("/{preset_name}/components/{component_id}")
|
||||
async def update_preset_component(preset_name: str, component_id: str, update_data: Dict):
|
||||
"""更新指定组件"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
# 加载预设数据
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
# 查找并更新组件
|
||||
components = preset_data.get("prompts", [])
|
||||
component_index = next((i for i, c in enumerate(components) if c.get("identifier") == component_id), None)
|
||||
|
||||
if component_index is None:
|
||||
raise HTTPException(status_code=404, detail="Component not found")
|
||||
|
||||
# 更新组件字段
|
||||
for key, value in update_data.items():
|
||||
components[component_index][key] = value
|
||||
|
||||
# 保存更新
|
||||
with open(preset_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(preset_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
return {"message": "Component updated successfully"}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to update component: {str(e)}")
|
||||
|
||||
|
||||
@router.delete("/{preset_name}/components/{component_id}")
|
||||
async def delete_preset_component(preset_name: str, component_id: str):
|
||||
"""从预设中删除指定组件"""
|
||||
preset_path = Path("data/preset") / f"{preset_name}.json"
|
||||
if not preset_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
|
||||
try:
|
||||
# 加载预设数据
|
||||
with open(preset_path, 'r', encoding='utf-8') as f:
|
||||
preset_data = json.load(f)
|
||||
|
||||
# 查找并删除组件
|
||||
components = preset_data.get("prompts", [])
|
||||
original_length = len(components)
|
||||
components = [c for c in components if c.get("identifier") != component_id]
|
||||
|
||||
if len(components) == original_length:
|
||||
raise HTTPException(status_code=404, detail="Component not found")
|
||||
|
||||
# 更新预设数据
|
||||
preset_data["prompts"] = components
|
||||
|
||||
# 保存更新
|
||||
with open(preset_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(preset_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
return {"message": "Component deleted successfully"}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to delete component: {str(e)}")
|
||||
170
backend/api/routes/worldbooksRoute.py
Normal file
170
backend/api/routes/worldbooksRoute.py
Normal file
@@ -0,0 +1,170 @@
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
from backend.core.models.WorldBook import WorldBook
|
||||
from backend.core.models.WorldItem import WorldInfoEntry
|
||||
|
||||
router = APIRouter(prefix="/worldbooks", tags=["worldbooks"])
|
||||
|
||||
|
||||
# ========== 世界书基础路由 ==========
|
||||
|
||||
@router.get("", response_model=Dict[str, List[Dict]])
|
||||
async def list_worldbooks():
|
||||
"""获取所有世界书列表"""
|
||||
worldbook_dir = Path("data/worldbooks")
|
||||
if not worldbook_dir.exists():
|
||||
return {"worldbooks": []}
|
||||
|
||||
worldbooks = []
|
||||
for wb_file in worldbook_dir.glob("*.json"):
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(wb_file))
|
||||
worldbooks.append(worldbook.to_summary_dict())
|
||||
except Exception as e:
|
||||
print(f"警告: 跳过文件 {wb_file.name},加载失败: {e}")
|
||||
continue
|
||||
|
||||
return {"worldbooks": worldbooks}
|
||||
|
||||
|
||||
@router.get("/{worldbook_uid}")
|
||||
async def get_worldbook(worldbook_uid: str):
|
||||
"""获取指定世界书完整内容"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(worldbook_path))
|
||||
return worldbook.to_dict()
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to load worldbook: {str(e)}")
|
||||
|
||||
|
||||
@router.post("", status_code=status.HTTP_201_CREATED)
|
||||
async def create_worldbook(worldbook_data: Dict):
|
||||
"""创建新世界书"""
|
||||
worldbook_dir = Path("data/worldbooks")
|
||||
worldbook_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
worldbook = WorldBook.from_dict(worldbook_data)
|
||||
worldbook_path = worldbook_dir / f"{worldbook.uid}.json"
|
||||
|
||||
if worldbook_path.exists():
|
||||
raise HTTPException(status_code=400, detail="WorldBook already exists")
|
||||
|
||||
worldbook.to_sillytavern_json(str(worldbook_path))
|
||||
return {"message": "WorldBook created successfully", "uid": worldbook.uid}
|
||||
|
||||
|
||||
@router.put("/{worldbook_uid}")
|
||||
async def update_worldbook(worldbook_uid: str, update_data: Dict):
|
||||
"""更新世界书基本信息"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(worldbook_path))
|
||||
for key, value in update_data.items():
|
||||
if hasattr(worldbook, key):
|
||||
setattr(worldbook, key, value)
|
||||
worldbook.to_sillytavern_json(str(worldbook_path))
|
||||
return {"message": "WorldBook updated successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to update worldbook: {str(e)}")
|
||||
|
||||
|
||||
@router.delete("/{worldbook_uid}")
|
||||
async def delete_worldbook(worldbook_uid: str):
|
||||
"""删除世界书"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
worldbook_path.unlink()
|
||||
return {"message": "WorldBook deleted successfully"}
|
||||
|
||||
|
||||
# ========== 世界书条目路由 ==========
|
||||
|
||||
@router.get("/{worldbook_uid}/entries")
|
||||
async def list_worldbook_entries(worldbook_uid: str):
|
||||
"""获取世界书所有条目列表"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(worldbook_path))
|
||||
return {"entries": [entry.dict() for entry in worldbook.entries]}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to load entries: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/{worldbook_uid}/entries/{entry_uid}")
|
||||
async def get_worldbook_entry(worldbook_uid: str, entry_uid: str):
|
||||
"""获取指定条目详情"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(worldbook_path))
|
||||
entry = worldbook.get_entry(entry_uid)
|
||||
if not entry:
|
||||
raise HTTPException(status_code=404, detail="Entry not found")
|
||||
return entry.dict()
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to load entry: {str(e)}")
|
||||
|
||||
|
||||
@router.post("/{worldbook_uid}/entries", status_code=status.HTTP_201_CREATED)
|
||||
async def add_worldbook_entry(worldbook_uid: str, entry_data: Dict):
|
||||
"""向世界书添加新条目"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(worldbook_path))
|
||||
entry = WorldInfoEntry(**entry_data)
|
||||
worldbook.add_entry(entry)
|
||||
worldbook.to_sillytavern_json(str(worldbook_path))
|
||||
return {"message": "Entry added successfully", "entry_uid": entry.uid}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to add entry: {str(e)}")
|
||||
|
||||
|
||||
@router.put("/{worldbook_uid}/entries/{entry_uid}")
|
||||
async def update_worldbook_entry(worldbook_uid: str, entry_uid: str, update_data: Dict):
|
||||
"""更新指定条目"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(worldbook_path))
|
||||
if not worldbook.update_entry(entry_uid, **update_data):
|
||||
raise HTTPException(status_code=404, detail="Entry not found")
|
||||
worldbook.to_sillytavern_json(str(worldbook_path))
|
||||
return {"message": "Entry updated successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to update entry: {str(e)}")
|
||||
|
||||
|
||||
@router.delete("/{worldbook_uid}/entries/{entry_uid}")
|
||||
async def delete_worldbook_entry(worldbook_uid: str, entry_uid: str):
|
||||
"""从世界书删除指定条目"""
|
||||
worldbook_path = Path("data/worldbooks") / f"{worldbook_uid}.json"
|
||||
if not worldbook_path.exists():
|
||||
raise HTTPException(status_code=404, detail="WorldBook not found")
|
||||
|
||||
try:
|
||||
worldbook = WorldBook.from_sillytavern_json(str(worldbook_path))
|
||||
if not worldbook.remove_entry(entry_uid):
|
||||
raise HTTPException(status_code=404, detail="Entry not found")
|
||||
worldbook.to_sillytavern_json(str(worldbook_path))
|
||||
return {"message": "Entry deleted successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to delete entry: {str(e)}")
|
||||
Reference in New Issue
Block a user