Loading history...
;
}
return (
Generation History
Text
Profile
Language
Duration
Created
Actions
{history?.map((gen) => (
{gen.text}
{gen.profile_name}
{gen.language}
{gen.duration.toFixed(2)}s
{formatDistance(new Date(gen.created_at), new Date(), {
addSuffix: true,
})}
))}
);
}
```
---
## Implementation Phases
### Phase 1: Foundation (Week 1)
**Goal:** Setup, OpenAPI client, basic UI
1. **Day 1-2: Setup**
- ✅ Install shadcn/ui and dependencies
- ✅ Generate OpenAPI client
- ✅ Setup providers (React Query, Toaster)
- ✅ Create Zustand stores
- ✅ Setup routing (if needed)
2. **Day 3-4: Voice Profiles**
- ProfileList component
- ProfileCard component
- ProfileForm (create/edit)
- Profile deletion
- Sample upload UI
3. **Day 5-7: Testing & Polish**
- Test all CRUD operations
- Error handling
- Loading states
- Empty states
### Phase 2: Generation & History (Week 2)
**Goal:** Core voice generation functionality
1. **Day 1-3: Generation**
- GenerationForm component
- Real-time generation
- Progress indication
- Audio preview player
- Download functionality
2. **Day 4-7: History**
- HistoryTable component
- Filtering and search
- Pagination
- Audio playback
- Export functionality
### Phase 3: Audio Studio (Week 3-4)
**Goal:** Timeline editing and advanced features
1. **Week 3: Basic Studio**
- Waveform visualization (WaveSurfer.js)
- Timeline component
- Playback controls
- Multiple tracks
2. **Week 4: Advanced Features**
- Word-level timestamps
- Editing (trim, split)
- Audio effects
- Project save/load
### Phase 4: Polish & Features (Week 5+)
**Goal:** Production polish
1. **Server Settings**
- Connection management
- Local server toggle
- Health monitoring
2. **UX Improvements**
- Keyboard shortcuts
- Drag and drop
- Batch operations
- Export options
---
## Type Safety Best Practices
### 1. OpenAPI Generated Types
```typescript
// Use generated types from @/lib/api/models
import type {
VoiceProfileResponse,
GenerationRequest,
HistoryQuery,
} from '@/lib/api/models';
// Never use `any`
function handleProfile(profile: VoiceProfileResponse) {
// Fully typed
}
```
### 2. Zod Schemas Match Backend
```typescript
// app/src/lib/schemas/profile.ts
import { z } from 'zod';
// Match backend Pydantic model
export const profileCreateSchema = z.object({
name: z.string().min(1).max(100),
description: z.string().optional(),
language: z.enum(['en', 'zh']),
tags: z.array(z.string()).optional(),
});
export type ProfileCreate = z.infer