first commit
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
from fastapi import APIRouter, File, Form, HTTPException, UploadFile
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
from services.character_card import list_characters, get_character, import_card_file, update_character, update_appearance_tags
|
||||
|
||||
router = APIRouter(prefix="/characters", tags=["characters"])
|
||||
|
||||
|
||||
class CardPatch(BaseModel):
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
personality: Optional[str] = None
|
||||
scenario: Optional[str] = None
|
||||
first_mes: Optional[str] = None
|
||||
mes_example: Optional[str] = None
|
||||
appearance_tags: Optional[str] = None
|
||||
lora_name: Optional[str] = None
|
||||
lora_weight: Optional[float] = None
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def list_all():
|
||||
return await list_characters()
|
||||
|
||||
|
||||
@router.get("/{card_id}")
|
||||
async def get_one(card_id: str):
|
||||
card = await get_character(card_id)
|
||||
if not card:
|
||||
raise HTTPException(status_code=404, detail="Карточка не найдена")
|
||||
return card
|
||||
|
||||
|
||||
@router.patch("/{card_id}")
|
||||
async def patch_card(card_id: str, body: CardPatch):
|
||||
card = await get_character(card_id)
|
||||
if not card:
|
||||
raise HTTPException(status_code=404, detail="Карточка не найдена")
|
||||
fields = {k: v for k, v in body.model_dump().items() if v is not None}
|
||||
await update_character(card_id, fields)
|
||||
# sync appearance_tags and lora to persona
|
||||
from services.personas import update_persona_appearance
|
||||
if "appearance_tags" in fields:
|
||||
await update_persona_appearance(f"card_{card_id}", fields["appearance_tags"])
|
||||
if {"lora_name", "lora_weight"} & fields.keys():
|
||||
from services.personas import update_persona_lora
|
||||
await update_persona_lora(f"card_{card_id}", fields.get("lora_name"), fields.get("lora_weight"))
|
||||
# rebuild system prompt if character fields changed
|
||||
char_fields = {"name", "description", "personality", "scenario", "first_mes", "mes_example"}
|
||||
if char_fields & fields.keys():
|
||||
updated = await get_character(card_id)
|
||||
from services.character_card import build_system_prompt
|
||||
from services.personas import update_persona_prompt
|
||||
await update_persona_prompt(f"card_{card_id}", build_system_prompt(updated))
|
||||
return await get_character(card_id)
|
||||
|
||||
|
||||
@router.post("/import")
|
||||
async def import_card(
|
||||
file: UploadFile = File(...),
|
||||
lora_name: str = Form(""),
|
||||
lora_weight: float = Form(0.8),
|
||||
):
|
||||
content = await file.read()
|
||||
try:
|
||||
card = await import_card_file(
|
||||
content,
|
||||
file.filename or "card.json",
|
||||
lora_name=lora_name,
|
||||
lora_weight=lora_weight,
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
return {
|
||||
"status": "imported",
|
||||
"card_id": card["card_id"],
|
||||
"persona_id": f"card_{card['card_id']}",
|
||||
"name": card["name"],
|
||||
}
|
||||
|
||||
|
||||
@router.delete("/{card_id}")
|
||||
async def remove_card(card_id: str):
|
||||
from services.personas import delete_persona
|
||||
|
||||
if not await delete_persona(f"card_{card_id}"):
|
||||
raise HTTPException(status_code=404, detail="Карточка не найдена")
|
||||
return {"status": "deleted", "card_id": card_id}
|
||||
|
||||
Reference in New Issue
Block a user