import type { EmotionTag, RelationshipStage } from "@kokorone/shared"; const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:3001"; export interface ChatResponseStyle { tone: string; sentenceLength: "short" | "medium" | "long"; initiative: "low" | "medium" | "high"; } export interface ChatContext { emotion: { dominant: EmotionTag; style: ChatResponseStyle }; relationship: { intimacy: number; trust: number; stage: RelationshipStage }; } export type ChatAvailability = "NORMAL" | "BRIEF" | "DELAYED" | "NO_REPLY"; export interface ChatResult { text: string; actions: string[]; isFastChannel: boolean; availability: ChatAvailability; exceptionType: string | null; // I-2:作息為睡眠且未破例時不會組裝上下文,此時為 null。 context: ChatContext | null; } export async function sendChatMessage( characterId: string, userId: string, sessionId: string, text: string, ): Promise { const res = await fetch(`${API_BASE_URL}/chat/${characterId}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ userId, sessionId, text }), }); if (!res.ok) { throw new Error(`對話請求失敗(${res.status})`); } return res.json(); } export async function endChatSession(sessionId: string, characterId: string): Promise { await fetch(`${API_BASE_URL}/session/${sessionId}/end`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ characterId }), }); } export interface TachieExpressionResponse { emotionTag: EmotionTag; rawEmotionTag: EmotionTag; eyebrow: string; eye: string; mouth: string; effect: string | null; pose: string; magnitude: number; gaze: "UP" | "AWAY" | "DIRECT" | "NEUTRAL"; availableCostumes: string[]; lockedFallbackApplied: boolean; usedCryingVariant: boolean; } // O-2 表情演出:情緒引擎已經在對話文字生成之前更新完畢,這裡獨立查詢目前的表情狀態, // 讓前端可以在文字訊息出現前先套用新的表情差分。 export async function fetchExpression(characterId: string, userId: string): Promise { const res = await fetch(`${API_BASE_URL}/tachie/${characterId}/${userId}/expression`); if (!res.ok) { throw new Error(`表情查詢失敗(${res.status})`); } return res.json(); }