mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-15 12:50:42 -07:00
Add generated API client files to git for CI builds
This commit is contained in:
@@ -50,7 +50,6 @@ logs/
|
||||
.env.local
|
||||
|
||||
# Generated files
|
||||
app/src/lib/api/
|
||||
app/openapi.json
|
||||
tauri/src-tauri/binaries/*
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# Generated OpenAPI client will be placed here
|
||||
@@ -0,0 +1,201 @@
|
||||
import { useServerStore } from '@/stores/serverStore';
|
||||
import type {
|
||||
VoiceProfileCreate,
|
||||
VoiceProfileResponse,
|
||||
ProfileSampleResponse,
|
||||
GenerationRequest,
|
||||
GenerationResponse,
|
||||
HistoryQuery,
|
||||
HistoryListResponse,
|
||||
HistoryResponse,
|
||||
TranscriptionResponse,
|
||||
HealthResponse,
|
||||
ModelStatusListResponse,
|
||||
ModelDownloadRequest,
|
||||
} from './types';
|
||||
|
||||
class ApiClient {
|
||||
private getBaseUrl(): string {
|
||||
const serverUrl = useServerStore.getState().serverUrl;
|
||||
return serverUrl;
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
endpoint: string,
|
||||
options?: RequestInit,
|
||||
): Promise<T> {
|
||||
const url = `${this.getBaseUrl()}${endpoint}`;
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
detail: response.statusText,
|
||||
}));
|
||||
throw new Error(error.detail || `HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Health
|
||||
async getHealth(): Promise<HealthResponse> {
|
||||
return this.request<HealthResponse>('/health');
|
||||
}
|
||||
|
||||
// Profiles
|
||||
async createProfile(data: VoiceProfileCreate): Promise<VoiceProfileResponse> {
|
||||
return this.request<VoiceProfileResponse>('/profiles', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
async listProfiles(): Promise<VoiceProfileResponse[]> {
|
||||
return this.request<VoiceProfileResponse[]>('/profiles');
|
||||
}
|
||||
|
||||
async getProfile(profileId: string): Promise<VoiceProfileResponse> {
|
||||
return this.request<VoiceProfileResponse>(`/profiles/${profileId}`);
|
||||
}
|
||||
|
||||
async updateProfile(
|
||||
profileId: string,
|
||||
data: VoiceProfileCreate,
|
||||
): Promise<VoiceProfileResponse> {
|
||||
return this.request<VoiceProfileResponse>(`/profiles/${profileId}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
async deleteProfile(profileId: string): Promise<void> {
|
||||
await this.request<void>(`/profiles/${profileId}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
async addProfileSample(
|
||||
profileId: string,
|
||||
file: File,
|
||||
referenceText: string,
|
||||
): Promise<ProfileSampleResponse> {
|
||||
const url = `${this.getBaseUrl()}/profiles/${profileId}/samples`;
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('reference_text', referenceText);
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
detail: response.statusText,
|
||||
}));
|
||||
throw new Error(error.detail || `HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async listProfileSamples(
|
||||
profileId: string,
|
||||
): Promise<ProfileSampleResponse[]> {
|
||||
return this.request<ProfileSampleResponse[]>(
|
||||
`/profiles/${profileId}/samples`,
|
||||
);
|
||||
}
|
||||
|
||||
async deleteProfileSample(sampleId: string): Promise<void> {
|
||||
await this.request<void>(`/profiles/samples/${sampleId}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
// Generation
|
||||
async generateSpeech(
|
||||
data: GenerationRequest,
|
||||
): Promise<GenerationResponse> {
|
||||
return this.request<GenerationResponse>('/generate', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
// History
|
||||
async listHistory(query?: HistoryQuery): Promise<HistoryListResponse> {
|
||||
const params = new URLSearchParams();
|
||||
if (query?.profile_id) params.append('profile_id', query.profile_id);
|
||||
if (query?.search) params.append('search', query.search);
|
||||
if (query?.limit) params.append('limit', query.limit.toString());
|
||||
if (query?.offset) params.append('offset', query.offset.toString());
|
||||
|
||||
const queryString = params.toString();
|
||||
const endpoint = queryString ? `/history?${queryString}` : '/history';
|
||||
|
||||
return this.request<HistoryListResponse>(endpoint);
|
||||
}
|
||||
|
||||
async getGeneration(generationId: string): Promise<HistoryResponse> {
|
||||
return this.request<HistoryResponse>(`/history/${generationId}`);
|
||||
}
|
||||
|
||||
async deleteGeneration(generationId: string): Promise<void> {
|
||||
await this.request<void>(`/history/${generationId}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
// Audio
|
||||
getAudioUrl(audioId: string): string {
|
||||
return `${this.getBaseUrl()}/audio/${audioId}`;
|
||||
}
|
||||
|
||||
// Transcription
|
||||
async transcribeAudio(
|
||||
file: File,
|
||||
language?: 'en' | 'zh',
|
||||
): Promise<TranscriptionResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
if (language) {
|
||||
formData.append('language', language);
|
||||
}
|
||||
|
||||
const url = `${this.getBaseUrl()}/transcribe`;
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
detail: response.statusText,
|
||||
}));
|
||||
throw new Error(error.detail || `HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Model Management
|
||||
async getModelStatus(): Promise<ModelStatusListResponse> {
|
||||
return this.request<ModelStatusListResponse>('/models/status');
|
||||
}
|
||||
|
||||
async triggerModelDownload(modelName: string): Promise<{ message: string }> {
|
||||
return this.request<{ message: string }>('/models/download', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ model_name: modelName } as ModelDownloadRequest),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const apiClient = new ApiClient();
|
||||
@@ -0,0 +1,107 @@
|
||||
// API Types matching backend Pydantic models
|
||||
|
||||
export interface VoiceProfileCreate {
|
||||
name: string;
|
||||
description?: string;
|
||||
language: 'en' | 'zh';
|
||||
}
|
||||
|
||||
export interface VoiceProfileResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
language: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface ProfileSampleCreate {
|
||||
reference_text: string;
|
||||
}
|
||||
|
||||
export interface ProfileSampleResponse {
|
||||
id: string;
|
||||
profile_id: string;
|
||||
audio_path: string;
|
||||
reference_text: string;
|
||||
}
|
||||
|
||||
export interface GenerationRequest {
|
||||
profile_id: string;
|
||||
text: string;
|
||||
language: 'en' | 'zh';
|
||||
seed?: number;
|
||||
model_size?: '1.7B' | '0.6B';
|
||||
}
|
||||
|
||||
export interface GenerationResponse {
|
||||
id: string;
|
||||
profile_id: string;
|
||||
text: string;
|
||||
language: string;
|
||||
audio_path: string;
|
||||
duration: number;
|
||||
seed?: number;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface HistoryQuery {
|
||||
profile_id?: string;
|
||||
search?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export interface HistoryResponse extends GenerationResponse {
|
||||
profile_name: string;
|
||||
}
|
||||
|
||||
export interface HistoryListResponse {
|
||||
items: HistoryResponse[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface TranscriptionRequest {
|
||||
language?: 'en' | 'zh';
|
||||
}
|
||||
|
||||
export interface TranscriptionResponse {
|
||||
text: string;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
export interface HealthResponse {
|
||||
status: string;
|
||||
model_loaded: boolean;
|
||||
model_downloaded?: boolean;
|
||||
model_size?: string;
|
||||
gpu_available: boolean;
|
||||
vram_used_mb?: number;
|
||||
}
|
||||
|
||||
export interface ModelProgress {
|
||||
model_name: string;
|
||||
current: number;
|
||||
total: number;
|
||||
progress: number;
|
||||
filename?: string;
|
||||
status: 'downloading' | 'extracting' | 'complete' | 'error';
|
||||
timestamp: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface ModelStatus {
|
||||
model_name: string;
|
||||
display_name: string;
|
||||
downloaded: boolean;
|
||||
size_mb?: number;
|
||||
loaded: boolean;
|
||||
}
|
||||
|
||||
export interface ModelStatusListResponse {
|
||||
models: ModelStatus[];
|
||||
}
|
||||
|
||||
export interface ModelDownloadRequest {
|
||||
model_name: string;
|
||||
}
|
||||
Reference in New Issue
Block a user