完成大量美化,zustand迁移,动态表格修复
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from backend.services.chat_service import ChatService
|
||||
from backend.core.config import settings
|
||||
from backend.services.chat_service import ChatService
|
||||
from backend.core.config import settings
|
||||
except ImportError:
|
||||
# Docker环境:直接从当前目录导入
|
||||
from services.chat_service import ChatService
|
||||
from core.config import settings
|
||||
# Docker环境:直接从当前目录导入
|
||||
from services.chat_service import ChatService
|
||||
from core.config import settings
|
||||
|
||||
router = APIRouter(prefix="/chat", tags=["chat"])
|
||||
|
||||
@@ -14,11 +15,23 @@ router = APIRouter(prefix="/chat", tags=["chat"])
|
||||
data_path = Path(settings.DATA_PATH) if hasattr(settings, 'DATA_PATH') else Path("data")
|
||||
chat_service = ChatService(data_path)
|
||||
|
||||
|
||||
@router.get("", response_model=dict)
|
||||
async def list_all_chats():
|
||||
"""获取所有角色的所有聊天列表"""
|
||||
return chat_service.list_all_chats()
|
||||
|
||||
|
||||
# 注意:路由定义顺序很重要!更具体的路由(更多参数)必须放在前面
|
||||
@router.get("/{role_name}/{chat_name}")
|
||||
async def get_chat(role_name: str, chat_name: str):
|
||||
"""获取指定聊天的完整内容"""
|
||||
try:
|
||||
return chat_service.get_chat(role_name, chat_name)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{role_name}")
|
||||
async def list_role_chats(role_name: str):
|
||||
"""获取指定角色的所有聊天列表"""
|
||||
@@ -30,13 +43,6 @@ async def list_role_chats(role_name: str):
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/{role_name}/{chat_name}")
|
||||
async def get_chat(role_name: str, chat_name: str):
|
||||
"""获取指定聊天的完整内容"""
|
||||
try:
|
||||
return chat_service.get_chat(role_name, chat_name)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
|
||||
@router.post("/{role_name}", status_code=status.HTTP_201_CREATED)
|
||||
async def create_chat(role_name: str, chat_data: dict):
|
||||
@@ -48,18 +54,21 @@ async def create_chat(role_name: str, chat_data: dict):
|
||||
except FileExistsError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
@router.put("/{role_name}/{chat_name}")
|
||||
async def update_chat(role_name: str, chat_name: str, update_data: dict):
|
||||
"""更新聊天元数据"""
|
||||
# TODO: 实现更新聊天元数据功能
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
|
||||
|
||||
@router.delete("/{role_name}/{chat_name}")
|
||||
async def delete_chat(role_name: str, chat_name: str):
|
||||
"""删除指定聊天"""
|
||||
# TODO: 实现删除聊天功能
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
|
||||
|
||||
@router.get("/{role_name}/{chat_name}/messages")
|
||||
async def list_messages(role_name: str, chat_name: str):
|
||||
"""获取聊天的所有消息"""
|
||||
@@ -69,6 +78,7 @@ async def list_messages(role_name: str, chat_name: str):
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{role_name}/{chat_name}/messages/{floor}")
|
||||
async def get_message(role_name: str, chat_name: str, floor: int):
|
||||
"""获取指定楼层的消息"""
|
||||
@@ -81,6 +91,7 @@ async def get_message(role_name: str, chat_name: str, floor: int):
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
|
||||
|
||||
@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):
|
||||
"""向聊天添加新消息"""
|
||||
@@ -91,6 +102,7 @@ async def add_message(role_name: str, chat_name: str, message_data: dict):
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
@router.put("/{role_name}/{chat_name}/messages/{floor}")
|
||||
async def update_message(role_name: str, chat_name: str, floor: int, update_data: dict):
|
||||
"""更新指定楼层的消息"""
|
||||
@@ -101,6 +113,7 @@ async def update_message(role_name: str, chat_name: str, floor: int, update_data
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
|
||||
|
||||
@router.delete("/{role_name}/{chat_name}/messages/{floor}")
|
||||
async def delete_message(role_name: str, chat_name: str, floor: int):
|
||||
"""删除指定楼层的消息"""
|
||||
@@ -110,3 +123,14 @@ async def delete_message(role_name: str, chat_name: str, floor: int):
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
|
||||
|
||||
@router.put("/{role_name}/{chat_name}/table")
|
||||
async def update_table_data(role_name: str, chat_name: str, table_update: dict):
|
||||
"""更新表格数据(带时间戳冲突解决)"""
|
||||
try:
|
||||
return chat_service.update_table_data(role_name, chat_name, table_update)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@@ -1,23 +1,43 @@
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
# TODO: 实现 PresetService 来替代旧的 AIDesignSpec 逻辑
|
||||
# from services.preset_service import PresetService
|
||||
from services.preset_service import PresetService
|
||||
|
||||
router = APIRouter(prefix="/presets", tags=["presets"])
|
||||
|
||||
@router.get("", response_model=dict)
|
||||
async def list_presets():
|
||||
"""获取所有预设列表及其基本信息"""
|
||||
# return await PresetService.list_all_presets()
|
||||
return {"presets": []}
|
||||
try:
|
||||
presets = PresetService.list_presets()
|
||||
response_data = {"presets": presets}
|
||||
print(f"[API] GET /api/presets - 返回数据: {response_data}")
|
||||
return response_data
|
||||
except Exception as e:
|
||||
print(f"[API] GET /api/presets - 错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
# 注意:路由定义顺序很重要!更具体的路由(更多参数)必须放在前面
|
||||
@router.get("/{preset_name}/components/{component_id}")
|
||||
async def get_preset_component(preset_name: str, component_id: str):
|
||||
"""获取指定组件的详情"""
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
|
||||
@router.get("/{preset_name}/components")
|
||||
async def list_preset_components(preset_name: str):
|
||||
"""获取预设中的所有组件"""
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
|
||||
@router.get("/{preset_name}")
|
||||
async def get_preset(preset_name: str):
|
||||
"""获取指定预设的完整内容"""
|
||||
# try:
|
||||
# return await PresetService.get_preset(preset_name)
|
||||
# except FileNotFoundError:
|
||||
# raise HTTPException(status_code=404, detail="Preset not found")
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
try:
|
||||
preset_data = PresetService.get_preset(preset_name)
|
||||
return preset_data
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(status_code=404, detail="Preset not found")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.post("", status_code=status.HTTP_201_CREATED)
|
||||
async def create_preset(preset_name: str, preset_data: dict):
|
||||
@@ -34,16 +54,6 @@ async def delete_preset(preset_name: str):
|
||||
"""删除指定预设"""
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
|
||||
@router.get("/{preset_name}/components")
|
||||
async def list_preset_components(preset_name: str):
|
||||
"""获取预设中的所有组件"""
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
|
||||
@router.get("/{preset_name}/components/{component_id}")
|
||||
async def get_preset_component(preset_name: str, component_id: str):
|
||||
"""获取指定组件的详情"""
|
||||
raise HTTPException(status_code=501, detail="Not Implemented")
|
||||
|
||||
@router.post("/{preset_name}/components", status_code=status.HTTP_201_CREATED)
|
||||
async def add_preset_component(preset_name: str, component_data: dict):
|
||||
"""向预设添加新组件"""
|
||||
|
||||
@@ -38,6 +38,80 @@ async def list_worldbooks():
|
||||
logger.error(f"Failed to list worldbooks: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
# 注意:路由定义顺序很重要!更具体的路由(更多参数)必须放在前面
|
||||
@router.get("/{name}/entries/{uid}", response_model=Dict[str, Any])
|
||||
async def get_worldbook_entry(name: str, uid: str):
|
||||
"""
|
||||
获取世界书的指定条目
|
||||
"""
|
||||
try:
|
||||
return worldbook_service.get_entry(name, uid)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get entry '{uid}' from worldbook '{name}': {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/{name}/entries", response_model=Dict[str, Any])
|
||||
async def list_worldbook_entries(
|
||||
name: str,
|
||||
page: int = 1,
|
||||
page_size: int = 20
|
||||
):
|
||||
"""
|
||||
获取世界书的条目列表(支持分页)
|
||||
|
||||
Args:
|
||||
name: 世界书名称
|
||||
page: 页码,从1开始
|
||||
page_size: 每页数量,默认20
|
||||
"""
|
||||
try:
|
||||
return worldbook_service.list_entries(name, page, page_size)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to list entries for worldbook '{name}': {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/{name}/export")
|
||||
async def export_worldbook(name: str, format: str = "internal"):
|
||||
"""
|
||||
导出世界书(支持 internal 和 sillytavern 两种格式)
|
||||
|
||||
Args:
|
||||
name: 世界书名称
|
||||
format: 导出格式 ('internal' 或 'sillytavern'),默认 internal
|
||||
"""
|
||||
try:
|
||||
if format.lower() == "sillytavern":
|
||||
# 导出为 SillyTavern 格式(可能丢失特殊设置)
|
||||
logger.info(f"导出世界书 '{name}' 为 SillyTavern 格式")
|
||||
st_data = worldbook_service.export_to_sillytavern(name)
|
||||
|
||||
return JSONResponse(
|
||||
content=st_data,
|
||||
headers={
|
||||
"Content-Disposition": f"attachment; filename={name}_sillytavern.json"
|
||||
}
|
||||
)
|
||||
else:
|
||||
# 导出为内部格式(保留所有设置)
|
||||
logger.info(f"导出世界书 '{name}' 为内部格式")
|
||||
internal_data = worldbook_service.get_worldbook(name)
|
||||
|
||||
return JSONResponse(
|
||||
content=internal_data,
|
||||
headers={
|
||||
"Content-Disposition": f"attachment; filename={name}.json"
|
||||
}
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to export worldbook '{name}': {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/{name}", response_model=Dict[str, Any])
|
||||
async def get_worldbook(name: str):
|
||||
"""
|
||||
@@ -213,41 +287,3 @@ async def import_worldbook(name: str, file: UploadFile = File(...)):
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to import worldbook '{name}': {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/{name}/export")
|
||||
async def export_worldbook(name: str, format: str = "internal"):
|
||||
"""
|
||||
导出世界书(支持 internal 和 sillytavern 两种格式)
|
||||
|
||||
Args:
|
||||
name: 世界书名称
|
||||
format: 导出格式 ('internal' 或 'sillytavern'),默认 internal
|
||||
"""
|
||||
try:
|
||||
if format.lower() == "sillytavern":
|
||||
# 导出为 SillyTavern 格式(可能丢失特殊设置)
|
||||
logger.info(f"导出世界书 '{name}' 为 SillyTavern 格式")
|
||||
st_data = worldbook_service.export_to_sillytavern(name)
|
||||
|
||||
return JSONResponse(
|
||||
content=st_data,
|
||||
headers={
|
||||
"Content-Disposition": f"attachment; filename={name}_sillytavern.json"
|
||||
}
|
||||
)
|
||||
else:
|
||||
# 导出为内部格式(保留所有设置)
|
||||
logger.info(f"导出世界书 '{name}' 为内部格式")
|
||||
internal_data = worldbook_service.get_worldbook(name)
|
||||
|
||||
return JSONResponse(
|
||||
content=internal_data,
|
||||
headers={
|
||||
"Content-Disposition": f"attachment; filename={name}.json"
|
||||
}
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to export worldbook '{name}': {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
Reference in New Issue
Block a user