M2b:导入改造产出可审阅灵胚(启镜物化世谱)与组装管线(符文展开/火候进入 IR),Kernel 打通采样参数链路
This commit is contained in:
1 parent
e6a3b7121f
commit
5f36e3785c
86 files changed
+424
-14455
No files matched your search
@@ -1,29 +1,49 @@
|
||||
"""角色卡导入 / 导出 API。"""
|
||||
"""角色卡导入 / 导出 API。
|
||||
|
||||
rewrite/1.0 M2b:导入产出**可审阅灵胚**(含 character_book 暂存),不再直接建人物;
|
||||
经照心编辑与启镜(POST /embryo-drafts/{id}/activate)后才物化人物与世谱。
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Response, UploadFile
|
||||
|
||||
from app.api.v1.deps import get_current_user
|
||||
from app.domains import jingsheng
|
||||
from app.schemas.auth import CurrentUser
|
||||
from app.schemas.character import ImportCardResponse
|
||||
from app.services.card_import import export_character_card, import_character_card_response
|
||||
from app.services.card_import import card_to_embryo_payload, export_character_card
|
||||
|
||||
router = APIRouter(prefix="/characters", tags=["characters"])
|
||||
|
||||
|
||||
@router.post("/import-card", response_model=ImportCardResponse)
|
||||
@router.post("/import-card", status_code=201)
|
||||
async def import_character_card_api(
|
||||
file: UploadFile = File(..., description="角色卡文件,支持 .png / .json / .charx。"),
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> ImportCardResponse:
|
||||
"""导入酒馆角色卡(V1/V2/V3),建立人物 + 世谱(character_book)。
|
||||
) -> dict:
|
||||
"""导入酒馆角色卡(V1/V2/V3)→ 生成可审阅灵胚。
|
||||
|
||||
``personality`` 写入道体 ``personality_summary`` 作初始值;
|
||||
``character_book`` 转为该角色的世谱书 + 条目。
|
||||
卡内容整体进入灵胚道体草稿(identity_baseline.import_card),
|
||||
``character_book`` 在启镜时物化为该人物的世谱书与条目。
|
||||
"""
|
||||
raw = await file.read()
|
||||
return await import_character_card_response(raw, owner_scope=current_user.owner_scope)
|
||||
payload = card_to_embryo_payload(raw)
|
||||
book_entry_count = payload.pop("book_entry_count")
|
||||
embryo = await jingsheng.create_embryo(
|
||||
owner_scope=current_user.owner_scope,
|
||||
source="imported",
|
||||
name=payload["name"],
|
||||
description=payload["description"],
|
||||
identity_baseline=payload["identity_baseline"],
|
||||
)
|
||||
return {
|
||||
"embryo_id": embryo.id,
|
||||
"status": embryo.status,
|
||||
"name": embryo.name,
|
||||
"source": embryo.source,
|
||||
"book_entry_count": book_entry_count,
|
||||
"next": "照心编辑 PATCH /embryo-drafts/{id},启镜 POST /embryo-drafts/{id}/activate",
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{character_id}/export-card")
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
"""聊天 API。"""
|
||||
|
||||
from fastapi import APIRouter, Depends, Header, Query, Request, Response, status
|
||||
|
||||
from app.api.v1.deps import get_current_user
|
||||
from app.schemas.auth import CurrentUser
|
||||
from app.schemas.chat import (
|
||||
ChatMessageListResponse,
|
||||
ChatMessageResponse,
|
||||
ChatSessionListResponse,
|
||||
ChatSessionResponse,
|
||||
CreateSessionRequest,
|
||||
SelectVersionRequest,
|
||||
SendMessageRequest,
|
||||
SendMessageResponse,
|
||||
UpdateSessionRequest,
|
||||
)
|
||||
from app.services.chat import (
|
||||
create_session,
|
||||
delete_session,
|
||||
get_session_response,
|
||||
list_message_responses,
|
||||
list_session_responses,
|
||||
select_message_version,
|
||||
send_message,
|
||||
update_session_response,
|
||||
)
|
||||
from app.services.idempotency import run_idempotent
|
||||
|
||||
router = APIRouter(prefix="/chat", tags=["chat"])
|
||||
|
||||
|
||||
@router.post("/sessions", response_model=ChatSessionResponse)
|
||||
async def create_chat_session(
|
||||
payload: CreateSessionRequest,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> ChatSessionResponse:
|
||||
return await create_session(payload, owner_scope=current_user.owner_scope)
|
||||
|
||||
|
||||
@router.get("/sessions", response_model=ChatSessionListResponse)
|
||||
async def list_chat_sessions(
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
status: str | None = Query(default=None, description="按状态过滤:active / archived"),
|
||||
limit: int = Query(default=50, ge=1, le=100),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
) -> ChatSessionListResponse:
|
||||
return await list_session_responses(
|
||||
owner_scope=current_user.owner_scope, status=status, limit=limit, offset=offset
|
||||
)
|
||||
|
||||
|
||||
@router.get("/sessions/{session_id}", response_model=ChatSessionResponse)
|
||||
async def get_chat_session(
|
||||
session_id: str,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> ChatSessionResponse:
|
||||
return await get_session_response(session_id, owner_scope=current_user.owner_scope)
|
||||
|
||||
|
||||
@router.patch("/sessions/{session_id}", response_model=ChatSessionResponse)
|
||||
async def update_chat_session(
|
||||
session_id: str,
|
||||
payload: UpdateSessionRequest,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> ChatSessionResponse:
|
||||
return await update_session_response(session_id, payload, owner_scope=current_user.owner_scope)
|
||||
|
||||
|
||||
@router.delete("/sessions/{session_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_chat_session(
|
||||
session_id: str,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> Response:
|
||||
await delete_session(session_id, owner_scope=current_user.owner_scope)
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
@router.post("/sessions/{session_id}/messages", response_model=SendMessageResponse)
|
||||
async def send_chat_message(
|
||||
session_id: str,
|
||||
payload: SendMessageRequest,
|
||||
request: Request,
|
||||
idempotency_key: str | None = Header(default=None, alias="Idempotency-Key"),
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> SendMessageResponse:
|
||||
return await run_idempotent(
|
||||
key=idempotency_key,
|
||||
method="POST",
|
||||
path=str(request.url.path),
|
||||
payload=payload,
|
||||
response_type=SendMessageResponse,
|
||||
resource_type="run",
|
||||
handler=lambda session: send_message(
|
||||
session,
|
||||
session_id,
|
||||
payload,
|
||||
owner_scope=current_user.owner_scope,
|
||||
tool_runtime=getattr(request.app.state, "tool_runtime", None),
|
||||
confirmation_registry=getattr(request.app.state, "confirmation_registry", None),
|
||||
confirmation_store=getattr(request.app.state, "confirmation_store", None),
|
||||
event_store=getattr(request.app.state, "event_store", None),
|
||||
agent_run_registry=getattr(request.app.state, "agent_run_registry", None),
|
||||
python_skill_catalog=getattr(request.app.state, "python_skill_catalog", None),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/sessions/{session_id}/messages", response_model=ChatMessageListResponse)
|
||||
async def list_chat_messages(
|
||||
session_id: str,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
limit: int = Query(default=100, ge=1, le=200),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
) -> ChatMessageListResponse:
|
||||
return await list_message_responses(
|
||||
session_id, owner_scope=current_user.owner_scope, limit=limit, offset=offset
|
||||
)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/sessions/{session_id}/messages/{message_id}/version",
|
||||
response_model=ChatMessageResponse,
|
||||
)
|
||||
async def select_message_version_endpoint(
|
||||
session_id: str,
|
||||
message_id: str,
|
||||
payload: SelectVersionRequest,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> ChatMessageResponse:
|
||||
"""选择/激活消息的某个历史版本。"""
|
||||
return await select_message_version(
|
||||
session_id,
|
||||
message_id,
|
||||
payload,
|
||||
owner_scope=current_user.owner_scope,
|
||||
)
|
||||
@@ -1,113 +0,0 @@
|
||||
"""辰正时态 API(设计 §10)。
|
||||
|
||||
挂载于 /api/v1/time。事件不走 REST(走 EventStore 订阅)。路由薄层:参数校验 → 调
|
||||
service → 转响应;session 由 service 自管(deps.py 惯例)。
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
|
||||
from app.api.v1.deps import get_current_user, get_event_store
|
||||
from app.core.config import settings
|
||||
from app.schemas.auth import CurrentUser
|
||||
from app.schemas.time import (
|
||||
AcquaintanceResponse,
|
||||
AnniversaryCreateRequest,
|
||||
AnniversaryResponse,
|
||||
AnniversaryUpdateRequest,
|
||||
SnapshotResponse,
|
||||
TimeConfigResponse,
|
||||
)
|
||||
from app.services.time_sense import (
|
||||
create_anniversary_for_active,
|
||||
delete_anniversary_or_404,
|
||||
get_acquaintance_for_active,
|
||||
get_anniversary_or_404,
|
||||
get_live_snapshot,
|
||||
list_anniversaries_for_active,
|
||||
update_anniversary_or_404,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/time", tags=["time"])
|
||||
|
||||
|
||||
@router.get("/snapshot", response_model=SnapshotResponse)
|
||||
async def get_snapshot(
|
||||
request: Request, current_user: CurrentUser = Depends(get_current_user)
|
||||
) -> SnapshotResponse:
|
||||
"""当前 TemporalSnapshot + ModulationFactors + context_text。"""
|
||||
result = await get_live_snapshot(get_event_store(request), owner_scope=current_user.owner_scope)
|
||||
return SnapshotResponse(
|
||||
snapshot=result.snapshot,
|
||||
factors=result.factors,
|
||||
context_text=result.context_text,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/anniversaries", response_model=list[AnniversaryResponse])
|
||||
async def list_anniversaries_api(
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> list[AnniversaryResponse]:
|
||||
items = await list_anniversaries_for_active(owner_scope=current_user.owner_scope)
|
||||
return [AnniversaryResponse.model_validate(a) for a in items]
|
||||
|
||||
|
||||
@router.post("/anniversaries", response_model=AnniversaryResponse, status_code=201)
|
||||
async def create_anniversary_api(
|
||||
payload: AnniversaryCreateRequest, current_user: CurrentUser = Depends(get_current_user)
|
||||
) -> AnniversaryResponse:
|
||||
created = await create_anniversary_for_active(payload, owner_scope=current_user.owner_scope)
|
||||
return AnniversaryResponse.model_validate(created)
|
||||
|
||||
|
||||
@router.get("/anniversaries/{anniv_id}", response_model=AnniversaryResponse)
|
||||
async def get_anniversary_api(
|
||||
anniv_id: str, current_user: CurrentUser = Depends(get_current_user)
|
||||
) -> AnniversaryResponse:
|
||||
return AnniversaryResponse.model_validate(
|
||||
await get_anniversary_or_404(anniv_id, owner_scope=current_user.owner_scope)
|
||||
)
|
||||
|
||||
|
||||
@router.patch("/anniversaries/{anniv_id}", response_model=AnniversaryResponse)
|
||||
async def update_anniversary_api(
|
||||
anniv_id: str,
|
||||
payload: AnniversaryUpdateRequest,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
) -> AnniversaryResponse:
|
||||
return AnniversaryResponse.model_validate(
|
||||
await update_anniversary_or_404(anniv_id, payload, owner_scope=current_user.owner_scope)
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/anniversaries/{anniv_id}", status_code=204)
|
||||
async def delete_anniversary_api(
|
||||
anniv_id: str, current_user: CurrentUser = Depends(get_current_user)
|
||||
) -> None:
|
||||
await delete_anniversary_or_404(anniv_id, owner_scope=current_user.owner_scope)
|
||||
|
||||
|
||||
@router.get("/acquaintance", response_model=AcquaintanceResponse)
|
||||
async def get_acquaintance_api(
|
||||
request: Request, current_user: CurrentUser = Depends(get_current_user)
|
||||
) -> AcquaintanceResponse:
|
||||
acq = await get_acquaintance_for_active(
|
||||
get_event_store(request), owner_scope=current_user.owner_scope
|
||||
)
|
||||
return AcquaintanceResponse(total_days=acq.total_days, natural_language=acq.natural_language)
|
||||
|
||||
|
||||
@router.get("/config", response_model=TimeConfigResponse)
|
||||
async def get_time_config_api(
|
||||
current_user: CurrentUser = Depends(get_current_user), # noqa: ARG001
|
||||
) -> TimeConfigResponse:
|
||||
return TimeConfigResponse(
|
||||
user_timezone=settings.user_timezone,
|
||||
home_timezone=settings.home_timezone,
|
||||
default_city=settings.default_city,
|
||||
offline_active_minutes=settings.offline_active_minutes,
|
||||
offline_short_absence_minutes=settings.offline_short_absence_minutes,
|
||||
offline_long_absence_minutes=settings.offline_long_absence_minutes,
|
||||
offline_reunion_impact_minutes=settings.offline_reunion_impact_minutes,
|
||||
care_enabled=settings.care_enabled,
|
||||
jetlag_threshold_minutes=settings.jetlag_threshold_minutes,
|
||||
)
|
||||
Reference in new issue
Block a user