Developer Guide
SeaVoice UI Tabs Implementation Guide
Hướng dẫn chi tiết thiết kế và triển khai giao diện 4 Tab chức năng trong SeaVoice Studio (TTS, Clone, Design, Registry)
Hướng Dẫn Triển Khai Các Tab Trong SeaVoice Studio
Tài liệu kỹ thuật chi tiết dành cho kỹ sư Frontend và Fullstack để xây dựng và tích hợp giao diện Studio quản trị âm thanh SeaVoice Studio (bao gồm 4 Tabs: Sinh giọng TTS, Nhân bản giọng, Thiết kế giọng và Quản lý danh mục giọng) vào bất kỳ dự án React / Next.js / TanStack Start nào.
1. Kiến Trúc Tổng Thể Studio (AudioGeneratePanel)
Giao diện Studio được đóng gói trong component container AudioGeneratePanel, điều phối trạng thái và luồng dữ liệu giữa 4 tabs độc lập thông qua hệ thống State trung tâm:
1.1. Luồng Trải Nghiệm Người Dùng (UX Flow)
- Khởi tạo: Mặc định mở Tab 1 (Sinh giọng) với một giọng mặc định trong danh mục hoặc giọng được truyền qua props (
selectedVoice). - Tạo giọng mới: Khi người dùng vào Tab 2 (Nhân bản) hoặc Tab 3 (Thiết kế) để tạo một giọng mới thành công, hệ thống tự động:
- Ghi nhận
VoiceRegistryRowmới tạo vào stateselectedVoice. - Tự động chuyển active tab quay lại Tab 1 (Sinh giọng).
- Nạp ngay giọng vừa tạo vào bộ chọn để người dùng có thể gõ nội dung đọc thử tức thì.
- Ghi nhận
- Chọn từ thư viện: Khi người dùng duyệt Tab 4 (Danh mục giọng) và ấn "Sử dụng giọng này", hệ thống chuyển ngay về Tab 1 với giọng đã chọn.
2. Chi Tiết Triển Khai Tab 1: Sinh Giọng (TTS Generation)
Component: TtsForm
Mục đích: Cho phép người dùng nhập văn bản, chèn các biểu cảm tự nhiên, tinh chỉnh thông số âm thanh và sinh file đọc tức thì.
2.1. Cấu Trúc Giao Diện & Điều Khiển
+-----------------------------------------------------------------------------+
| [Chọn giọng đọc ▾] (Giọng của tôi / Giọng công đồng / Preset) |
| [Đoạn văn bản cần đọc ...................................................] |
| [Thẻ cảm xúc: [cười] [thở dài] [thì thầm] [vỗ tay] [ngáp] [khóc] ...] |
| |
| [Tốc độ đọc: 1.0x (0.5x - 2.0x)] [Số bước Denoising: 32 (10 - 64)] |
| [Ngôn ngữ: Tiếng Việt ▾] [Ước tính phí: 120 ký tự = 120 VNĐ] |
| |
| [ ▶ Nút Sinh Giọng Nói (TTS) ] |
| |
| [ Audio Player Bar: Sóng âm thanh | Play/Pause | Tải về .wav | Gắn vào shot ]|
+-----------------------------------------------------------------------------+2.2. Các Tính Năng Kỹ Thuật Trọng Tâm
A. Bộ Chèn Thẻ Cảm Xúc Phi Ngôn Ngữ (EmotionBadgeSelector)
Cho phép người dùng click vào các thẻ cảm xúc để chèn mã tag vào đúng vị trí con trỏ (cursor caret) trong ô textarea:
const handleInsertEmotion = (emotion: string) => {
const textarea = textareaRef.current;
if (!textarea) {
setText((prev) => `${prev} ${emotion} `);
return;
}
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const currentText = text;
// Chèn thẻ cảm xúc vào giữa vị trí con trỏ đang đứng
const newText =
currentText.substring(0, start) +
` ${emotion} ` +
currentText.substring(end);
setText(newText);
// Phục hồi vị trí con trỏ ngay sau thẻ vừa chèn
setTimeout(() => {
textarea.focus();
const newCursorPos = start + emotion.length + 2;
textarea.setSelectionRange(newCursorPos, newCursorPos);
}, 10);
};B. Bộ Tính Phí Trực Quan (Realtime Billing Counter)
- Tính toán trực tiếp số ký tự văn bản (
text.trim().length). - Hiển thị ước tính số VNĐ hoặc credits bị trừ:
1 ký tự = 1 VNĐ.
C. Tham Số Điều Khiển Suy Luận GPU
speed(0.5 - 2.0): Thanh trượt tốc độ phát thanh.numStep(10 - 64, mặc định 32): Tùy chỉnh chất lượng âm thanh khử nhiễu.duration(tùy chọn): Khống chế thời lượng file audio (giây) nếu cần khớp timeline video.
3. Chi Tiết Triển Khai Tab 2: Nhân Bản Giọng (Voice Cloning)
Component: VoiceCloneForm
Mục đích: Cho phép người dùng tải lên mẫu giọng thật (ref_audio) để tạo ra một Voice ID độc quyền.
3.1. Luồng Xử Lý Dữ Liệu Tải Lên (Audio Upload Pipeline)
3.2. Form Fields & Validation Rules
- File âm thanh mẫu (
ref_audio):- Dung lượng: Tối đa
10MB. - Định dạng:
.wav,.mp3,.m4a,.ogg. - Khuyến nghị: 5 - 15 giây, một người nói, không nhạc nền, không tạp âm.
- Dung lượng: Tối đa
- Tên giọng đọc (
name): Tự động trích xuất từ tên file tải lên (loại bỏ ký tự gạch dưới/đuôi mở rộng) nếu người dùng chưa nhập. - Giới tính (
gender):male|female|unspecified. - Văn bản đối soát (
refText) (Không bắt buộc nhưng khuyến khích): Chép lại chính xác nội dung câu nói trong đoạn file mẫu giúp mô hình nhận diện âm vị và phát âm chuẩn hơn 40%. - Câu đọc thử nghiệm (
testText): Văn bản để sinh ngay một đoạn đọc thử kiểm tra chất lượng bản sao.
4. Chi Tiết Triển Khai Tab 3: Thiết Kế Giọng (Voice Design)
Component: VoiceDesignForm
Mục đích: Tạo ra giọng nói hoàn toàn mới bằng cách miêu tả các đặc tính âm học tự nhiên thông qua bộ chọn Tag Chips và Presets có sẵn.
4.1. Hệ Thống Thuộc Tính Âm Học Chuẩn (Taxonomy Chips)
Giao diện chia các thuộc tính thành 5 nhóm thẻ để người dùng click chọn:
| Nhóm Thuộc Tính | Các Giá Trị Hỗ Trợ | Cơ Chế Chọn |
|---|---|---|
| Giới tính (Gender) | female (Nữ), male (Nam) | Đơn chọn (Single select) |
| Độ tuổi (Age) | child, teenager, young adult, middle-aged, elderly | Đơn chọn trong nhóm |
| Cao độ (Pitch) | very low pitch, low pitch, moderate pitch, high pitch, very high pitch | Đơn chọn trong nhóm |
| Phong cách (Style) | whisper (Thì thầm / ASMR) | Bật / Tắt (Toggle) |
| Ngữ điệu (Accent) | american accent, british accent, japanese accent, chinese accent, v.v. | Đơn chọn trong nhóm |
4.2. Logic Đảm Bảo Tính Nhất Quán (Tag Mutual Exclusivity)
Khi người dùng click một thẻ thuộc tính, hệ thống tự động loại bỏ các thẻ cũ cùng nhóm trong chuỗi instruct:
const handleToggleTag = (tagId: string, category: string) => {
let currentTokens = instruct.split(/[,]+/).map(t => t.trim().toLowerCase());
if (currentTokens.includes(tagId)) {
// Nếu đã chọn thì gỡ bỏ
currentTokens = currentTokens.filter(t => t !== tagId);
} else {
// Lấy danh sách toàn bộ tag cùng danh mục (ví dụ cùng là độ tuổi)
const sameCategoryTagIds = SEAVOICE_TAXONOMY
.filter(t => t.category === category)
.map(t => t.id.toLowerCase());
// Loại bỏ các tag cùng danh mục trước khi thêm tag mới
currentTokens = currentTokens.filter(t => !sameCategoryTagIds.includes(t));
currentTokens.push(tagId);
}
setInstruct(currentTokens.join(', '));
};4.3. Whitelist Sanitization (Kiểm Tra Từ Khóa Hợp Lệ)
Để tránh lỗi HTTP 400 Bad Request từ SeaVoice API, component tích hợp hook useMemo chạy hàm sanitizeVoiceDesignInstruct để cảnh báo ngay trên UI nếu người dùng nhập các từ khóa lạ không nằm trong danh mục hỗ trợ.
5. Chi Tiết Triển Khai Tab 4: Quản Lý Danh Mục Giọng (Voice Registry)
Component: VoiceRegistryManager
Mục đích: Cung cấp trung tâm quản lý tất cả các giọng nói của Team và khám phá các giọng nói dùng chung từ cộng đồng.
5.1. Phân Loại Bộ Lọc (Filter Categories)
- Tất cả (
all): Hiển thị toàn bộ giọng của team hiện tại + các giọng công cộng đã được duyệt trên toàn nền tảng. - Của tôi / Team (
mine): Chỉ hiển thị các giọng do chính team tạo ra (có quyền sửa tên, xóa, yêu cầu chia sẻ công khai). - Cộng đồng (
public): Danh sách các giọng nói do cộng đồng chia sẻ đã qua kiểm duyệt (publicStatus === 'approved').
5.2. Thẻ Hiển Thị Giọng (VoiceCard)
Mỗi giọng đọc được hiển thị dưới dạng Card trực quan bao gồm:
- Thông tin nhận diện: Tên giọng, Avatar giới tính, Voice ID 22 ký tự, ngày tạo.
- Trình nghe thử tích hợp: Nút Play/Pause mini phát đoạn âm thanh mẫu (
sample_url). - Huy hiệu kiểm duyệt (Moderation Badge):
Riêng tư(Màu xám): Giọng chỉ trong nội bộ team.Đang chờ duyệt(Màu vàng): Đã gửi yêu cầu chia sẻ công khai.Đã duyệt công khai(Màu xanh lá): Mọi người dùng trên hệ thống đều có thể sử dụng.
- Các thao tác nghiệp vụ:
Sử dụng: Kích hoạtonSelectVoice(voice)và chuyển ngay về Tab 1.Chia sẻ công khai/Thu hồi chia sẻ: Gửi hoặc hủy yêu cầu kiểm duyệt.Xóa giọng: Xóa vĩnh viễn khỏi Database và giải phóng tài nguyên trên remote SeaVoice engine (DELETE /v1/tts/voices/{id}).
6. Danh Mục React Query Hooks Phục Vụ 4 Tabs (use-seavoice.ts)
Bảng tổng hợp các Hooks dùng chung trong toàn bộ các Tab:
| Hook Name | Loại | Mục Đích | Cache Invalidation |
|---|---|---|---|
useAvailableVoices() | Query | Lấy danh sách giọng khả dụng (Team + Approved Public) | seavoiceKeys.availableVoices() |
useMyVoices() | Query | Lấy danh sách giọng do chính team sở hữu | seavoiceKeys.myVoices() |
useEmotions() | Query | Lấy danh sách nhãn cảm xúc phi ngôn ngữ | seavoiceKeys.emotions() |
useLanguages() | Query | Lấy danh sách ngôn ngữ hỗ trợ (vi, en) | seavoiceKeys.languages() |
useGenerateTts() | Mutation | Gửi yêu cầu sinh giọng đọc văn bản | Không đổi DB giọng |
useCloneVoice() | Mutation | Đăng ký & sinh giọng nhân bản từ file mẫu | Invalidate seavoiceKeys.all |
useDesignVoice() | Mutation | Đăng ký & sinh giọng mới từ câu mô tả instruct | Invalidate seavoiceKeys.all |
useDeleteVoice() | Mutation | Xóa một giọng khỏi kho lưu trữ | Invalidate seavoiceKeys.all |
useRequestPublicVoice() | Mutation | Gửi yêu cầu duyệt giọng ra thư viện chung | Invalidate seavoiceKeys.all |
useRevokePublicVoice() | Mutation | Hủy chia sẻ giọng công cộng | Invalidate seavoiceKeys.all |
7. Checklist Kiểm Thử Giao Diện 4 Tabs (QA / Acceptance Criteria)
- Tab 1 (TTS):
- Hiển thị chính xác tên giọng được truyền từ Tab 2, 3, 4.
- Chèn thẻ cảm xúc tại đúng vị trí trỏ chuột và duy trì focus của textarea.
- Bộ đếm ký tự và tiền VNĐ cập nhật realtime theo từng phím gõ.
- Phát thanh mượt mà sau khi render xong qua
AudioPlayerBar.
- Tab 2 (Clone):
- Báo lỗi ngay nếu file tải lên vượt quá 10MB hoặc sai định dạng âm thanh.
- Hiển thị trình phát nghe thử file mẫu trước khi bấm Submit.
- Tự động chuyển về Tab 1 và điền sẵn giọng mới khi clone thành công.
- Tab 3 (Design):
- Chọn preset tự động cập nhật text instruct, tên và giới tính tương ứng.
- Chọn thẻ mới cùng danh mục tự động ghi đè thẻ cũ.
- Hiển thị cảnh báo màu cam nếu có từ khóa ngoài Whitelist.
- Tab 4 (Registry):
- Chuyển tab lọc "Tất cả", "Của tôi", "Công đồng" hoạt động chính xác.
- Tìm kiếm realtime theo tên và VoiceID không phân biệt hoa thường.
- Quyền xóa và chia sẻ chỉ xuất hiện trên các giọng thuộc quyền sở hữu của Team.