음성 재생과 운영 배포 정리
This commit is contained in:
parent
8ed185ce6c
commit
ac7db95542
1020 changed files with 46863 additions and 2175 deletions
|
|
@ -173,23 +173,39 @@ export type PersonaSummary = ApiSchema<"PersonaSummary">;
|
|||
export type PersonaReviewStatus = "draft" | "review" | "approved" | "archived";
|
||||
export type PersonaReviewAction = ApiSchema<"PersonaReviewDecisionRequest">["action"];
|
||||
export type PersonaReviewSummary = ApiSchema<"PersonaReviewSummary">;
|
||||
export type PersonaRevisionRequest = ApiSchema<"PersonaRevisionRequest">;
|
||||
|
||||
export type PersonaDraftPayload = ApiSchema<"PersonaDraftPayload">;
|
||||
export type PersonaDraftDetail = ApiSchema<"PersonaDraftDetail">;
|
||||
export type PersonaSourceDocumentRequest = ApiSchema<"PersonaSourceDocumentRequest">;
|
||||
export type PersonaSourceDocumentResponse = ApiSchema<"PersonaSourceDocumentResponse">;
|
||||
export type PersonaGenerationEvidence = ApiSchema<"PersonaGenerationEvidence">;
|
||||
export type PersonaDraftGenerateRequest = ApiSchema<"PersonaDraftGenerateRequest">;
|
||||
export type PersonaDraftGenerateResponse = ApiSchema<"PersonaDraftGenerateResponse">;
|
||||
|
||||
/** POST /sessions — sessions.py SessionStartResponse */
|
||||
export type SessionStartResponse = ApiSchema<"SessionStartResponse">;
|
||||
|
||||
/** POST /sessions/{id}/turn — sessions.py TurnResponse */
|
||||
export type TurnResponse = ApiSchema<"TurnResponse">;
|
||||
export type LiveCoachRequest = ApiSchema<"LiveCoachRequest">;
|
||||
export type LiveCoachEvent = ApiSchema<"LiveCoachEvent">;
|
||||
export type LiveCoachHistoryResponse = ApiSchema<"LiveCoachHistoryResponse">;
|
||||
export type LiveCoachSuggestion = ApiSchema<"LiveCoachSuggestion">;
|
||||
export type LiveCoachSource = ApiSchema<"LiveCoachSource">;
|
||||
|
||||
/** POST /sessions/{id}/end — sessions.py SessionEndResponse */
|
||||
export type SessionEndResponse = ApiSchema<"SessionEndResponse">;
|
||||
|
||||
export type CrisisResource = ApiSchema<"CrisisResourceResponse">;
|
||||
export type LearnerSessionSummary = ApiSchema<"LearnerSessionSummary">;
|
||||
export type SessionArchiveResponse = ApiSchema<"SessionArchiveResponse">;
|
||||
|
||||
export type LearnerSessionsResponse = ApiSchema<"LearnerSessionsResponse">;
|
||||
export type LearnerDashboardResponse = ApiSchema<"LearnerDashboardResponse">;
|
||||
export type LearnerDashboardPersonaProgress = ApiSchema<"LearnerDashboardPersonaProgress">;
|
||||
export type LearnerDashboardAchievement = ApiSchema<"LearnerDashboardAchievement">;
|
||||
export type LearnerDashboardFeedbackItem = ApiSchema<"LearnerDashboardFeedbackItem">;
|
||||
|
||||
export type SessionDetailTurn = ApiSchema<"SessionDetailTurn">;
|
||||
|
||||
|
|
@ -213,6 +229,8 @@ export type ReviewWorksheetSection = ApiSchema<"ReviewWorksheetSection-Output">;
|
|||
export type ReviewCaseWorksheet = ApiSchema<"ReviewCaseWorksheet">;
|
||||
export type ReviewCaseWorksheetSaveRequest = ApiSchema<"ReviewCaseWorksheetSaveRequest">;
|
||||
export type SessionReviewResponse = ApiSchema<"SessionReviewResponse">;
|
||||
export type SessionShareResponse = ApiSchema<"SessionShareResponse">;
|
||||
export type SessionShareDeleteResponse = ApiSchema<"SessionShareDeleteResponse">;
|
||||
|
||||
/* =====================================================================
|
||||
SSE 헬퍼 — POST /sessions/{id}/stream
|
||||
|
|
@ -381,14 +399,23 @@ export const personaReviewApi = {
|
|||
}),
|
||||
createDraft: (payload: PersonaDraftPayload) =>
|
||||
api.post<PersonaReviewSummary>("/personas/drafts", payload),
|
||||
createSource: (payload: PersonaSourceDocumentRequest) =>
|
||||
api.post<PersonaSourceDocumentResponse>("/personas/sources", payload),
|
||||
generateDraft: (payload: PersonaDraftGenerateRequest) =>
|
||||
api.post<PersonaDraftGenerateResponse>("/personas/drafts/generate", payload),
|
||||
getDraft: (personaId: string) =>
|
||||
api.get<PersonaDraftDetail>(`/personas/drafts/${encodeURIComponent(personaId)}`),
|
||||
updateDraft: (personaId: string, payload: PersonaDraftPayload) =>
|
||||
api.put<PersonaReviewSummary>(`/personas/drafts/${encodeURIComponent(personaId)}`, payload),
|
||||
reviseApproved: (personaId: string, payload: PersonaRevisionRequest = { submit_for_review: false }) =>
|
||||
api.post<PersonaDraftDetail>(`/personas/${encodeURIComponent(personaId)}/revisions`, payload),
|
||||
archive: (personaId: string) =>
|
||||
api.del<PersonaReviewSummary>(`/personas/${encodeURIComponent(personaId)}`),
|
||||
};
|
||||
|
||||
export const sessionApi = {
|
||||
list: () => api.get<LearnerSessionsResponse>("/sessions"),
|
||||
dashboard: () => api.get<LearnerDashboardResponse>("/sessions/dashboard"),
|
||||
/**
|
||||
* 음성 캐스케이드 가용성(STT/TTS provider 키 설정 여부). degraded 시 백엔드가 503을
|
||||
* 주므로 상태코드와 무관하게 본문을 읽어 available 만 돌려준다(미설정도 정상 응답으로 취급).
|
||||
|
|
@ -408,8 +435,19 @@ export const sessionApi = {
|
|||
api.post<SessionStartResponse>("/sessions", { persona_code, theory_mode }),
|
||||
turn: (sessionId: string, text: string) =>
|
||||
api.post<TurnResponse>(`/sessions/${encodeURIComponent(sessionId)}/turn`, { text }),
|
||||
liveCoach: (sessionId: string, payload: LiveCoachRequest) =>
|
||||
api.post<LiveCoachSuggestion>(
|
||||
`/sessions/${encodeURIComponent(sessionId)}/live-coach`,
|
||||
payload,
|
||||
),
|
||||
liveCoachHistory: (sessionId: string) =>
|
||||
api.get<LiveCoachHistoryResponse>(`/sessions/${encodeURIComponent(sessionId)}/live-coach`),
|
||||
end: (sessionId: string) =>
|
||||
api.post<SessionEndResponse>(`/sessions/${encodeURIComponent(sessionId)}/end`),
|
||||
archive: (sessionId: string) =>
|
||||
api.post<SessionArchiveResponse>(`/sessions/${encodeURIComponent(sessionId)}/archive`, {}),
|
||||
restore: (sessionId: string) =>
|
||||
api.post<SessionArchiveResponse>(`/sessions/${encodeURIComponent(sessionId)}/restore`, {}),
|
||||
review: (sessionId: string) =>
|
||||
api.get<SessionReviewResponse>(`/sessions/${encodeURIComponent(sessionId)}/review`),
|
||||
saveWorksheet: (sessionId: string, payload: ReviewCaseWorksheetSaveRequest) =>
|
||||
|
|
@ -417,6 +455,10 @@ export const sessionApi = {
|
|||
`/sessions/${encodeURIComponent(sessionId)}/review/worksheet`,
|
||||
payload,
|
||||
),
|
||||
createShare: (sessionId: string) =>
|
||||
api.post<SessionShareResponse>(`/sessions/${encodeURIComponent(sessionId)}/share`, {}),
|
||||
revokeShare: (sessionId: string) =>
|
||||
api.del<SessionShareDeleteResponse>(`/sessions/${encodeURIComponent(sessionId)}/share`),
|
||||
stream: openSessionStream,
|
||||
};
|
||||
|
||||
|
|
@ -426,10 +468,44 @@ export type AdminHealthResponse = ApiSchema<"AdminHealthResponse">;
|
|||
export type AdminUsageBreakdown = ApiSchema<"AdminUsageBreakdown">;
|
||||
export type AdminUsageBudget = ApiSchema<"AdminUsageBudget">;
|
||||
export type AdminUsageResponse = ApiSchema<"AdminUsageResponse">;
|
||||
export type AdminHealthEvent = ApiSchema<"AdminHealthEvent">;
|
||||
export type AdminUptimeServiceSummary = ApiSchema<"AdminUptimeServiceSummary">;
|
||||
export type AdminUptimeResponse = ApiSchema<"AdminUptimeResponse">;
|
||||
export type AdminSupportTicket = ApiSchema<"AdminSupportTicketResponse">;
|
||||
export type AdminTicketsResponse = ApiSchema<"AdminTicketsResponse">;
|
||||
export type AdminTicketPatchRequest = ApiSchema<"AdminTicketPatch">;
|
||||
export type AdminTicketFilters = {
|
||||
status?: AdminSupportTicket["status"] | "";
|
||||
category?: AdminSupportTicket["category"] | "";
|
||||
priority?: AdminSupportTicket["priority"] | "";
|
||||
assignedGroup?: string;
|
||||
sourcePath?: string;
|
||||
staleOnly?: boolean;
|
||||
search?: string;
|
||||
windowDays?: number;
|
||||
};
|
||||
|
||||
export const adminApi = {
|
||||
health: () => api.get<AdminHealthResponse>("/admin/health"),
|
||||
usage: (windowDays = 7) => api.get<AdminUsageResponse>(`/admin/usage?window_days=${windowDays}`),
|
||||
uptime: (windowHours = 24) =>
|
||||
api.get<AdminUptimeResponse>(`/admin/uptime?window_hours=${windowHours}`),
|
||||
tickets: (filters: AdminTicketFilters = {}) => {
|
||||
const params = new URLSearchParams({ window_days: String(filters.windowDays ?? 30) });
|
||||
if (filters.status) params.set("status", filters.status);
|
||||
if (filters.category) params.set("category", filters.category);
|
||||
if (filters.priority) params.set("priority", filters.priority);
|
||||
if (filters.assignedGroup?.trim()) params.set("assigned_group", filters.assignedGroup.trim());
|
||||
if (filters.sourcePath?.trim()) params.set("source_path", filters.sourcePath.trim());
|
||||
if (filters.staleOnly) params.set("stale_only", "true");
|
||||
if (filters.search?.trim()) params.set("search", filters.search.trim());
|
||||
return api.get<AdminTicketsResponse>(`/admin/tickets?${params.toString()}`);
|
||||
},
|
||||
updateTicket: (ticketId: string, body: AdminTicketPatchRequest) =>
|
||||
apiFetch<AdminSupportTicket>(`/admin/tickets/${encodeURIComponent(ticketId)}`, {
|
||||
method: "PATCH",
|
||||
body,
|
||||
}),
|
||||
};
|
||||
|
||||
export type AdminManagedUser = ApiSchema<"AdminUserResponse">;
|
||||
|
|
@ -462,24 +538,52 @@ export type TeacherGrowthPoint = ApiSchema<"TeacherGrowthPoint">;
|
|||
|
||||
export type TeacherLearnerGrowth = ApiSchema<"TeacherLearnerGrowth">;
|
||||
export type TeacherDashboardResponse = ApiSchema<"TeacherDashboardResponse">;
|
||||
export type TeacherSessionReviewStatusRequest = ApiSchema<"TeacherSessionReviewStatusRequest">;
|
||||
export type TeacherSessionReviewStatusResponse = ApiSchema<"TeacherSessionReviewStatusResponse">;
|
||||
|
||||
export const teacherApi = {
|
||||
dashboard: () => api.get<TeacherDashboardResponse>("/teacher/dashboard"),
|
||||
updateSessionReviewStatus: (
|
||||
sessionId: string,
|
||||
body: TeacherSessionReviewStatusRequest,
|
||||
) =>
|
||||
apiFetch<TeacherSessionReviewStatusResponse>(
|
||||
`/teacher/sessions/${encodeURIComponent(sessionId)}/review-status`,
|
||||
{ method: "PUT", body },
|
||||
),
|
||||
};
|
||||
|
||||
export type UserProfileResponse = ApiSchema<"UserProfileResponse">;
|
||||
export type LegalDocumentsResponse = ApiSchema<"LegalDocumentsResponse">;
|
||||
export type NotificationPreferences = ApiSchema<"NotificationPreferences">;
|
||||
export type UserPreferencesResponse = ApiSchema<"UserPreferencesResponse">;
|
||||
export type UserPreferencesPatchRequest = ApiSchema<"UserPreferencesPatch">;
|
||||
export type UserProfilePatchRequest = ApiSchema<"UserProfilePatch">;
|
||||
export type OnboardingRequest = ApiSchema<"OnboardingRequest">;
|
||||
export type AvatarUploadResponse = ApiSchema<"AvatarUploadResponse">;
|
||||
export type VoicePresetResponse = ApiSchema<"VoicePresetResponse">;
|
||||
|
||||
export type RoleString = "learner" | "teacher" | "admin" | string;
|
||||
|
||||
export const userApi = {
|
||||
legalDocs: () => api.get<LegalDocumentsResponse>("/users/legal-docs"),
|
||||
me: () => api.get<UserProfileResponse>("/users/me"),
|
||||
updateMe: (body: UserProfilePatchRequest) =>
|
||||
apiFetch<UserProfileResponse>("/users/me", { method: "PATCH", body }),
|
||||
uploadAvatar: async (file: File) => {
|
||||
const form = new FormData();
|
||||
form.append("file", file);
|
||||
const res = await fetch(joinUrl("/users/me/avatar"), {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { Accept: "application/json" },
|
||||
body: form,
|
||||
});
|
||||
if (!res.ok) throw await parseError(res);
|
||||
return (await res.json()) as AvatarUploadResponse;
|
||||
},
|
||||
completeOnboarding: (body: OnboardingRequest) =>
|
||||
apiFetch<UserProfileResponse>("/users/me/onboarding", { method: "POST", body }),
|
||||
preferences: () => api.get<UserPreferencesResponse>("/users/me/preferences"),
|
||||
updatePreferences: (body: UserPreferencesPatchRequest) =>
|
||||
apiFetch<UserPreferencesResponse>("/users/me/preferences", { method: "PATCH", body }),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue