From b395cb0b98c04da25e4f284ad6005a4bcb39ca93 Mon Sep 17 00:00:00 2001 From: bdim404 Date: Tue, 7 Apr 2026 11:37:47 +0800 Subject: [PATCH] Refactor localization files and remove Aliyun references --- qwen3-tts-backend/api/audiobook.py | 14 +- qwen3-tts-backend/api/auth.py | 44 +-- qwen3-tts-backend/api/tts.py | 120 ++----- qwen3-tts-backend/api/users.py | 60 +--- qwen3-tts-backend/api/voice_designs.py | 11 - qwen3-tts-backend/config.py | 6 - qwen3-tts-backend/core/audiobook_service.py | 99 ++---- qwen3-tts-backend/core/tts_service.py | 294 +----------------- qwen3-tts-backend/db/crud.py | 40 +-- qwen3-tts-backend/db/models.py | 8 +- qwen3-tts-backend/main.py | 6 - qwen3-tts-backend/schemas/audiobook.py | 2 - qwen3-tts-backend/schemas/tts.py | 2 +- qwen3-tts-backend/schemas/user.py | 13 +- qwen3-tts-backend/schemas/voice_design.py | 4 - qwen3-tts-backend/utils/validation.py | 38 +-- .../src/components/users/UserDialog.tsx | 25 -- .../src/components/users/UserTable.tsx | 8 +- .../src/contexts/UserPreferencesContext.tsx | 16 +- qwen3-tts-frontend/src/lib/api.ts | 30 -- qwen3-tts-frontend/src/lib/api/audiobook.ts | 3 +- qwen3-tts-frontend/src/lib/constants.ts | 4 - .../src/locales/en-US/onboarding.json | 15 +- .../src/locales/en-US/settings.json | 49 +-- qwen3-tts-frontend/src/locales/en-US/tts.json | 1 - .../src/locales/en-US/voice.json | 1 - .../src/locales/ja-JP/onboarding.json | 15 +- .../src/locales/ja-JP/settings.json | 49 +-- qwen3-tts-frontend/src/locales/ja-JP/tts.json | 1 - .../src/locales/ja-JP/voice.json | 1 - .../src/locales/ko-KR/onboarding.json | 15 +- .../src/locales/ko-KR/settings.json | 49 +-- qwen3-tts-frontend/src/locales/ko-KR/tts.json | 1 - .../src/locales/ko-KR/voice.json | 1 - .../src/locales/zh-CN/onboarding.json | 15 +- .../src/locales/zh-CN/settings.json | 49 +-- qwen3-tts-frontend/src/locales/zh-CN/tts.json | 1 - .../src/locales/zh-CN/voice.json | 1 - .../src/locales/zh-TW/onboarding.json | 15 +- .../src/locales/zh-TW/settings.json | 49 +-- qwen3-tts-frontend/src/locales/zh-TW/tts.json | 1 - .../src/locales/zh-TW/voice.json | 1 - qwen3-tts-frontend/src/pages/Audiobook.tsx | 52 ++-- qwen3-tts-frontend/src/pages/Settings.tsx | 210 +------------ qwen3-tts-frontend/src/types/auth.ts | 2 +- qwen3-tts-frontend/src/types/tts.ts | 2 +- qwen3-tts-frontend/src/types/voice-design.ts | 4 - 47 files changed, 136 insertions(+), 1311 deletions(-) diff --git a/qwen3-tts-backend/api/audiobook.py b/qwen3-tts-backend/api/audiobook.py index 18e01f4..80e1162 100644 --- a/qwen3-tts-backend/api/audiobook.py +++ b/qwen3-tts-backend/api/audiobook.py @@ -69,7 +69,7 @@ def _char_to_response(c, db: Session) -> AudiobookCharacterResponse: if vd: vd_name = vd.name meta = vd.meta_data or {} - vd_speaker = meta.get('speaker') or vd.aliyun_voice_id or vd.instruct or None + vd_speaker = meta.get('speaker') or vd.instruct or None return AudiobookCharacterResponse( id=c.id, project_id=c.project_id, @@ -80,7 +80,7 @@ def _char_to_response(c, db: Session) -> AudiobookCharacterResponse: voice_design_id=c.voice_design_id, voice_design_name=vd_name, voice_design_speaker=vd_speaker, - use_indextts2=c.use_indextts2 or False, + ) @@ -561,7 +561,7 @@ async def regenerate_character_preview_endpoint( from core.audiobook_service import generate_character_preview try: - await generate_character_preview(project_id, char_id, current_user, db) + await generate_character_preview(project_id, char_id, current_user, db, force_recreate=True) return {"message": "Preview generated successfully"} except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) @@ -740,13 +740,15 @@ async def update_character( description=data.description, instruct=data.instruct, voice_design_id=data.voice_design_id, - use_indextts2=data.use_indextts2, + ) - if data.instruct is not None and char.voice_design_id: + if (data.instruct is not None or data.gender is not None) and char.voice_design_id: voice_design = crud.get_voice_design(db, char.voice_design_id, current_user.id) if voice_design: - voice_design.instruct = data.instruct + if data.instruct is not None: + voice_design.instruct = data.instruct + voice_design.voice_cache_id = None db.commit() return _char_to_response(char, db) diff --git a/qwen3-tts-backend/api/auth.py b/qwen3-tts-backend/api/auth.py index 063f8e8..c7b5d8c 100644 --- a/qwen3-tts-backend/api/auth.py +++ b/qwen3-tts-backend/api/auth.py @@ -14,8 +14,8 @@ from core.security import ( decode_access_token ) from db.database import get_db -from db.crud import get_user_by_username, get_user_by_email, create_user, change_user_password, get_user_preferences, update_user_preferences, can_user_use_local_model, can_user_use_nsfw, get_system_setting -from schemas.user import User, UserCreate, Token, PasswordChange, AliyunKeyVerifyResponse, UserPreferences, UserPreferencesResponse +from db.crud import get_user_by_username, get_user_by_email, create_user, change_user_password, get_user_preferences, update_user_preferences, can_user_use_nsfw, get_system_setting +from schemas.user import User, UserCreate, Token, PasswordChange, UserPreferences, UserPreferencesResponse from schemas.audiobook import LLMConfigResponse router = APIRouter(prefix="/auth", tags=["authentication"]) @@ -155,31 +155,6 @@ async def change_password( return user -@router.get("/aliyun-key/verify", response_model=AliyunKeyVerifyResponse) -@limiter.limit("10/minute") -async def verify_aliyun_key( - request: Request, - current_user: Annotated[User, Depends(get_current_user)], - db: Session = Depends(get_db) -): - from core.security import decrypt_api_key - from core.tts_service import AliyunTTSBackend - - encrypted = get_system_setting(db, "aliyun_api_key") - if not encrypted: - return AliyunKeyVerifyResponse(valid=False, message="No Aliyun API key configured") - - api_key = decrypt_api_key(encrypted) - if not api_key: - return AliyunKeyVerifyResponse(valid=False, message="Failed to decrypt API key") - - aliyun_backend = AliyunTTSBackend(api_key=api_key, region=settings.ALIYUN_REGION) - health = await aliyun_backend.health_check() - - if health.get("available", False): - return AliyunKeyVerifyResponse(valid=True, message="Aliyun API key is valid and working") - return AliyunKeyVerifyResponse(valid=False, message="Aliyun API key is not working.") - @router.get("/preferences", response_model=UserPreferencesResponse) @limiter.limit("30/minute") async def get_preferences( @@ -189,14 +164,10 @@ async def get_preferences( ): prefs = get_user_preferences(db, current_user.id) - available_backends = ["aliyun"] - if can_user_use_local_model(current_user): - available_backends.append("local") - return { - "default_backend": prefs.get("default_backend", "aliyun"), + "default_backend": "local", "onboarding_completed": prefs.get("onboarding_completed", False), - "available_backends": available_backends + "available_backends": ["local"] } @router.put("/preferences") @@ -207,13 +178,6 @@ async def update_preferences( current_user: Annotated[User, Depends(get_current_user)], db: Session = Depends(get_db) ): - if preferences.default_backend == "local": - if not can_user_use_local_model(current_user): - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Local model is not available. Please contact administrator." - ) - updated_user = update_user_preferences( db, current_user.id, diff --git a/qwen3-tts-backend/api/tts.py b/qwen3-tts-backend/api/tts.py index ec853e7..583bb33 100644 --- a/qwen3-tts-backend/api/tts.py +++ b/qwen3-tts-backend/api/tts.py @@ -70,14 +70,7 @@ async def process_custom_voice_job( logger.info(f"Processing custom-voice job {job_id} with backend {backend_type}") - user_api_key = None - if backend_type == "aliyun": - from db.crud import get_system_setting - encrypted = get_system_setting(db, "aliyun_api_key") - if encrypted: - user_api_key = decrypt_api_key(encrypted) - - backend = await TTSServiceFactory.get_backend(backend_type, user_api_key) + backend = await TTSServiceFactory.get_backend() audio_bytes, sample_rate = await backend.generate_custom_voice(request_data) @@ -133,19 +126,9 @@ async def process_voice_design_job( logger.info(f"Processing voice-design job {job_id} with backend {backend_type}") - user_api_key = None - if backend_type == "aliyun": - from db.crud import get_system_setting - encrypted = get_system_setting(db, "aliyun_api_key") - if encrypted: - user_api_key = decrypt_api_key(encrypted) + backend = await TTSServiceFactory.get_backend() - backend = await TTSServiceFactory.get_backend(backend_type, user_api_key) - - if backend_type == "aliyun" and saved_voice_id: - audio_bytes, sample_rate = await backend.generate_voice_design(request_data, saved_voice_id) - else: - audio_bytes, sample_rate = await backend.generate_voice_design(request_data) + audio_bytes, sample_rate = await backend.generate_voice_design(request_data) timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S") filename = f"{user_id}_{job_id}_{timestamp}.wav" @@ -200,14 +183,6 @@ async def process_voice_clone_job( logger.info(f"Processing voice-clone job {job_id} with backend {backend_type}") - from core.security import decrypt_api_key - user_api_key = None - if backend_type == "aliyun": - from db.crud import get_system_setting - encrypted = get_system_setting(db, "aliyun_api_key") - if encrypted: - user_api_key = decrypt_api_key(encrypted) - with open(ref_audio_path, 'rb') as f: ref_audio_data = f.read() @@ -233,7 +208,7 @@ async def process_voice_clone_job( ref_audio_data = f.read() ref_audio_hash = cache_manager.get_audio_hash(ref_audio_data) - if request_data.get('x_vector_only_mode', False) and backend_type == "local": + if request_data.get('x_vector_only_mode', False): x_vector = None cache_id = None @@ -287,9 +262,9 @@ async def process_voice_clone_job( logger.info(f"Job {job_id} completed (x_vector_only_mode)") return - backend = await TTSServiceFactory.get_backend(backend_type, user_api_key) + backend = await TTSServiceFactory.get_backend() - if voice_design_id and backend_type == "local": + if voice_design_id: from db.crud import get_voice_design design = get_voice_design(db, voice_design_id, user_id) cached = await cache_manager.get_cache_by_id(design.voice_cache_id, db) @@ -339,34 +314,20 @@ async def create_custom_voice_job( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): - from core.security import decrypt_api_key - from db.crud import get_user_preferences, can_user_use_local_model + from db.crud import can_user_use_local_model - user_prefs = get_user_preferences(db, current_user.id) - preferred_backend = user_prefs.get("default_backend", "aliyun") - - can_use_local = can_user_use_local_model(current_user) - - backend_type = req_data.backend if hasattr(req_data, 'backend') and req_data.backend else preferred_backend - - if backend_type == "local" and not can_use_local: + if not can_user_use_local_model(current_user): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Local model is not available. Please contact administrator." ) - if backend_type == "aliyun": - from db.crud import get_system_setting - if not get_system_setting(db, "aliyun_api_key"): - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Aliyun API key not configured. Please contact administrator." - ) + backend_type = "local" try: validate_text_length(req_data.text) language = validate_language(req_data.language) - speaker = validate_speaker(req_data.speaker, backend_type) + speaker = validate_speaker(req_data.speaker) params = validate_generation_params({ 'max_new_tokens': req_data.max_new_tokens, @@ -430,48 +391,24 @@ async def create_voice_design_job( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): - from core.security import decrypt_api_key - from db.crud import get_user_preferences, can_user_use_local_model, get_voice_design, update_voice_design_usage + from db.crud import can_user_use_local_model, get_voice_design, update_voice_design_usage - user_prefs = get_user_preferences(db, current_user.id) - preferred_backend = user_prefs.get("default_backend", "aliyun") + if not can_user_use_local_model(current_user): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Local model is not available. Please contact administrator." + ) - can_use_local = can_user_use_local_model(current_user) - - backend_type = req_data.backend if hasattr(req_data, 'backend') and req_data.backend else preferred_backend - - saved_voice_id = None + backend_type = "local" if req_data.saved_design_id: saved_design = get_voice_design(db, req_data.saved_design_id, current_user.id) if not saved_design: raise HTTPException(status_code=404, detail="Saved voice design not found") - if saved_design.backend_type != backend_type: - raise HTTPException( - status_code=400, - detail=f"Saved design backend ({saved_design.backend_type}) doesn't match current backend ({backend_type})" - ) - req_data.instruct = saved_design.instruct - saved_voice_id = saved_design.aliyun_voice_id - update_voice_design_usage(db, req_data.saved_design_id, current_user.id) - if backend_type == "local" and not can_use_local: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Local model is not available. Please contact administrator." - ) - - if backend_type == "aliyun": - from db.crud import get_system_setting - if not get_system_setting(db, "aliyun_api_key"): - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Aliyun API key not configured. Please contact administrator." - ) - try: validate_text_length(req_data.text) language = validate_language(req_data.language) @@ -553,29 +490,15 @@ async def create_voice_clone_job( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): - from core.security import decrypt_api_key - from db.crud import get_user_preferences, can_user_use_local_model, get_voice_design + from db.crud import can_user_use_local_model, get_voice_design - user_prefs = get_user_preferences(db, current_user.id) - preferred_backend = user_prefs.get("default_backend", "aliyun") - - can_use_local = can_user_use_local_model(current_user) - - backend_type = backend if backend else preferred_backend - - if backend_type == "local" and not can_use_local: + if not can_user_use_local_model(current_user): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Local model is not available. Please contact administrator." ) - if backend_type == "aliyun": - from db.crud import get_system_setting - if not get_system_setting(db, "aliyun_api_key"): - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Aliyun API key not configured. Please contact administrator." - ) + backend_type = "local" ref_audio_data = None ref_audio_hash = None @@ -600,9 +523,6 @@ async def create_voice_clone_job( if not design: raise ValueError("Voice design not found") - if design.backend_type != backend_type: - raise ValueError(f"Voice design backend ({design.backend_type}) doesn't match request backend ({backend_type})") - if not design.voice_cache_id: raise ValueError("Voice design has no prepared clone prompt. Please call /voice-designs/{id}/prepare-clone first") diff --git a/qwen3-tts-backend/api/users.py b/qwen3-tts-backend/api/users.py index 52fab87..afe0dd8 100644 --- a/qwen3-tts-backend/api/users.py +++ b/qwen3-tts-backend/api/users.py @@ -5,7 +5,6 @@ from slowapi import Limiter from slowapi.util import get_remote_address from api.auth import get_current_user -from config import settings from core.security import get_password_hash from db.database import get_db from db.crud import ( @@ -17,7 +16,7 @@ from db.crud import ( update_user, delete_user ) -from schemas.user import User, UserCreateByAdmin, UserUpdate, UserListResponse, AliyunKeyUpdate, AliyunKeyVerifyResponse +from schemas.user import User, UserCreateByAdmin, UserUpdate, UserListResponse from schemas.audiobook import LLMConfigUpdate, LLMConfigResponse, NsfwSynopsisGenerationRequest, NsfwScriptGenerationRequest router = APIRouter(prefix="/users", tags=["users"]) @@ -181,63 +180,6 @@ async def delete_user_by_id( ) -@router.post("/system/aliyun-key") -@limiter.limit("5/minute") -async def set_system_aliyun_key( - request: Request, - key_data: AliyunKeyUpdate, - db: Session = Depends(get_db), - _: User = Depends(require_superuser) -): - from core.security import encrypt_api_key - from core.tts_service import AliyunTTSBackend - from db.crud import set_system_setting - - api_key = key_data.api_key.strip() - aliyun_backend = AliyunTTSBackend(api_key=api_key, region=settings.ALIYUN_REGION) - health = await aliyun_backend.health_check() - if not health.get("available", False): - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid Aliyun API key.") - set_system_setting(db, "aliyun_api_key", encrypt_api_key(api_key)) - return {"message": "Aliyun API key updated"} - - -@router.delete("/system/aliyun-key") -@limiter.limit("5/minute") -async def delete_system_aliyun_key( - request: Request, - db: Session = Depends(get_db), - _: User = Depends(require_superuser) -): - from db.crud import delete_system_setting - delete_system_setting(db, "aliyun_api_key") - return {"message": "Aliyun API key deleted"} - - -@router.get("/system/aliyun-key/verify", response_model=AliyunKeyVerifyResponse) -@limiter.limit("10/minute") -async def verify_system_aliyun_key( - request: Request, - db: Session = Depends(get_db), - _: User = Depends(require_superuser) -): - from core.security import decrypt_api_key - from core.tts_service import AliyunTTSBackend - from db.crud import get_system_setting - - encrypted = get_system_setting(db, "aliyun_api_key") - if not encrypted: - return AliyunKeyVerifyResponse(valid=False, message="No Aliyun API key configured") - api_key = decrypt_api_key(encrypted) - if not api_key: - return AliyunKeyVerifyResponse(valid=False, message="Failed to decrypt API key") - aliyun_backend = AliyunTTSBackend(api_key=api_key, region=settings.ALIYUN_REGION) - health = await aliyun_backend.health_check() - if health.get("available", False): - return AliyunKeyVerifyResponse(valid=True, message="Aliyun API key is valid and working") - return AliyunKeyVerifyResponse(valid=False, message="Aliyun API key is not working.") - - @router.put("/system/llm-config") @limiter.limit("10/minute") async def set_system_llm_config( diff --git a/qwen3-tts-backend/api/voice_designs.py b/qwen3-tts-backend/api/voice_designs.py index 70b2096..95623e5 100644 --- a/qwen3-tts-backend/api/voice_designs.py +++ b/qwen3-tts-backend/api/voice_designs.py @@ -33,9 +33,7 @@ def to_voice_design_response(design) -> VoiceDesignResponse: id=design.id, user_id=design.user_id, name=design.name, - backend_type=design.backend_type, instruct=design.instruct, - aliyun_voice_id=design.aliyun_voice_id, meta_data=meta_data, preview_text=design.preview_text, ref_audio_path=design.ref_audio_path, @@ -58,8 +56,6 @@ async def save_voice_design( user_id=current_user.id, name=data.name, instruct=data.instruct, - backend_type=data.backend_type, - aliyun_voice_id=data.aliyun_voice_id, meta_data=data.meta_data, preview_text=data.preview_text ) @@ -153,7 +149,6 @@ async def prepare_and_create_voice_design( user_id=current_user.id, name=data.name, instruct=data.instruct, - backend_type="local", meta_data=data.meta_data, preview_text=data.preview_text, voice_cache_id=cache_id, @@ -200,12 +195,6 @@ async def prepare_voice_clone_prompt( if not design: raise HTTPException(status_code=404, detail="Voice design not found") - if design.backend_type != "local": - raise HTTPException( - status_code=400, - detail="Voice clone prompt preparation is only supported for local backend" - ) - if not can_user_use_local_model(current_user): raise HTTPException( status_code=403, diff --git a/qwen3-tts-backend/config.py b/qwen3-tts-backend/config.py index b71d05a..cfb6509 100644 --- a/qwen3-tts-backend/config.py +++ b/qwen3-tts-backend/config.py @@ -37,12 +37,6 @@ class Settings(BaseSettings): MAX_TEXT_LENGTH: int = Field(default=1000) MAX_AUDIO_SIZE_MB: int = Field(default=10) - ALIYUN_REGION: str = Field(default="beijing") - - ALIYUN_MODEL_FLASH: str = Field(default="qwen3-tts-flash-realtime") - ALIYUN_MODEL_VC: str = Field(default="qwen3-tts-vc-realtime-2026-01-15") - ALIYUN_MODEL_VD: str = Field(default="qwen3-tts-vd-realtime-2026-01-15") - DEFAULT_BACKEND: str = Field(default="local") AUDIOBOOK_PARSE_CONCURRENCY: int = Field(default=3) diff --git a/qwen3-tts-backend/core/audiobook_service.py b/qwen3-tts-backend/core/audiobook_service.py index 28414bf..1bd0d7b 100644 --- a/qwen3-tts-backend/core/audiobook_service.py +++ b/qwen3-tts-backend/core/audiobook_service.py @@ -335,7 +335,7 @@ async def generate_ai_script(project_id: int, user: User, db: Session) -> None: crud.delete_audiobook_segments(db, project_id) crud.delete_audiobook_characters(db, project_id) - backend_type = user.user_preferences.get("default_backend", "aliyun") if user.user_preferences else "aliyun" + backend_type = "local" for char_data in characters_data: name = char_data.get("name", "旁白") @@ -449,7 +449,7 @@ async def generate_ai_script_chapters(project_id: int, user: User, db: Session) for c in db_characters ] char_map = {c.name: c for c in db_characters} - backend_type = user.user_preferences.get("default_backend", "aliyun") if user.user_preferences else "aliyun" + backend_type = "local" ps.append_line(key, f"[AI剧本] 开始生成 {num_chapters} 章大纲...\n") ps.append_line(key, "") @@ -618,7 +618,7 @@ async def continue_ai_script_chapters(project_id: int, additional_chapters: int, for c in db_characters ] char_map = {c.name: c for c in db_characters} - backend_type = user.user_preferences.get("default_backend", "aliyun") if user.user_preferences else "aliyun" + backend_type = "local" existing_chapters = crud.list_audiobook_chapters(db, project_id) existing_chapters_data = [ @@ -839,7 +839,7 @@ async def analyze_project(project_id: int, user: User, db: Session, turbo: bool crud.delete_audiobook_segments(db, project_id) crud.delete_audiobook_characters(db, project_id) - backend_type = user.user_preferences.get("default_backend", "aliyun") if user.user_preferences else "aliyun" + backend_type = "local" for char_data in characters_data: name = char_data.get("name", "旁白") @@ -1437,7 +1437,7 @@ async def process_all(project_id: int, user: User, db: Session) -> None: logger.info(f"process_all: project={project_id} complete") -async def generate_character_preview(project_id: int, char_id: int, user: User, db: Session) -> None: +async def generate_character_preview(project_id: int, char_id: int, user: User, db: Session, force_recreate: bool = False) -> None: """Generate a short audio preview for a specific character.""" project = crud.get_audiobook_project(db, project_id, user.id) if not project: @@ -1470,21 +1470,11 @@ async def generate_character_preview(project_id: int, char_id: int, user: User, preview_text = f"你好,我是{preview_name}{preview_desc}" from core.tts_service import TTSServiceFactory - from core.security import decrypt_api_key - backend_type = user.user_preferences.get("default_backend", "aliyun") if user.user_preferences else "aliyun" - user_api_key = None - if backend_type == "aliyun": - encrypted = crud.get_system_setting(db, "aliyun_api_key") - if encrypted: - user_api_key = decrypt_api_key(encrypted) - elif user.aliyun_api_key: - user_api_key = decrypt_api_key(user.aliyun_api_key) - - backend = await TTSServiceFactory.get_backend(backend_type, user_api_key) + backend = await TTSServiceFactory.get_backend() try: - if backend_type == "local" and not design.voice_cache_id: + if not design.voice_cache_id: logger.info(f"Local voice cache missing for char {char_id}. Bootstrapping now...") from core.model_manager import ModelManager from core.cache_manager import VoiceCacheManager @@ -1524,73 +1514,46 @@ async def generate_character_preview(project_id: int, char_id: int, user: User, db.commit() logger.info(f"Bootstrapped local voice cache for preview: design_id={design.id}, cache_id={cache_id}") - if backend_type == "aliyun" and not design.aliyun_voice_id: - from core.tts_service import AliyunTTSBackend - if isinstance(backend, AliyunTTSBackend): - try: - voice_id = await backend._create_voice_design( - instruct=_get_gendered_instruct(char.gender, design.instruct), - preview_text=preview_text, - ) - design.aliyun_voice_id = voice_id - db.commit() - logger.info(f"Bootstrapped aliyun voice_id for preview: design_id={design.id}, voice_id={voice_id}") - except Exception as e: - logger.warning(f"Failed to bootstrap aliyun voice_id for preview, falling back to instruct: {e}") - - if backend_type == "aliyun": - if design.aliyun_voice_id: - audio_bytes, _ = await backend.generate_voice_design( - {"text": preview_text, "language": "zh"}, - saved_voice_id=design.aliyun_voice_id - ) - else: - audio_bytes, _ = await backend.generate_voice_design({ - "text": preview_text, - "language": "zh", - "instruct": _get_gendered_instruct(char.gender, design.instruct), - }) - else: - if design.voice_cache_id: - from core.cache_manager import VoiceCacheManager - cache_manager = await VoiceCacheManager.get_instance() - cache_result = await cache_manager.get_cache_by_id(design.voice_cache_id, db) - x_vector = cache_result['data'] if cache_result else None - if x_vector: - audio_bytes, _ = await backend.generate_voice_clone( - { - "text": preview_text, - "language": "Auto", - "max_new_tokens": 512, - "temperature": 0.3, - "top_k": 10, - "top_p": 0.9, - "repetition_penalty": 1.05, - }, - x_vector=x_vector - ) - else: - audio_bytes, _ = await backend.generate_voice_design({ + if design.voice_cache_id: + from core.cache_manager import VoiceCacheManager + cache_manager = await VoiceCacheManager.get_instance() + cache_result = await cache_manager.get_cache_by_id(design.voice_cache_id, db) + x_vector = cache_result['data'] if cache_result else None + if x_vector: + audio_bytes, _ = await backend.generate_voice_clone( + { "text": preview_text, "language": "Auto", - "instruct": _get_gendered_instruct(char.gender, design.instruct), "max_new_tokens": 512, "temperature": 0.3, "top_k": 10, "top_p": 0.9, "repetition_penalty": 1.05, - }) + }, + x_vector=x_vector + ) else: audio_bytes, _ = await backend.generate_voice_design({ "text": preview_text, "language": "Auto", - "instruct": design.instruct, + "instruct": _get_gendered_instruct(char.gender, design.instruct), "max_new_tokens": 512, "temperature": 0.3, "top_k": 10, "top_p": 0.9, "repetition_penalty": 1.05, }) + else: + audio_bytes, _ = await backend.generate_voice_design({ + "text": preview_text, + "language": "Auto", + "instruct": design.instruct, + "max_new_tokens": 512, + "temperature": 0.3, + "top_k": 10, + "top_p": 0.9, + "repetition_penalty": 1.05, + }) with open(audio_path, "wb") as f: f.write(audio_bytes) @@ -1672,7 +1635,7 @@ async def generate_ai_script_nsfw(project_id: int, user: User, db: Session) -> N crud.delete_audiobook_segments(db, project_id) crud.delete_audiobook_characters(db, project_id) - backend_type = user.user_preferences.get("default_backend", "aliyun") if user.user_preferences else "aliyun" + backend_type = "local" for char_data in characters_data: name = char_data.get("name", "旁白") diff --git a/qwen3-tts-backend/core/tts_service.py b/qwen3-tts-backend/core/tts_service.py index cfb6b0c..8684989 100644 --- a/qwen3-tts-backend/core/tts_service.py +++ b/qwen3-tts-backend/core/tts_service.py @@ -1,12 +1,8 @@ import asyncio import functools -import time import logging from abc import ABC, abstractmethod from typing import Tuple, Optional -import websockets -import json -import base64 logger = logging.getLogger(__name__) @@ -167,266 +163,6 @@ class LocalTTSBackend(TTSBackend): return buffer.read() -class AliyunTTSBackend(TTSBackend): - def __init__(self, api_key: str, region: str): - self.api_key = api_key - self.region = region - self.ws_url = self._get_ws_url(region) - self.http_url = self._get_http_url(region) - - def _get_ws_url(self, region: str) -> str: - if region == "beijing": - return "wss://dashscope.aliyuncs.com/api-ws/v1/realtime" - else: - return "wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime" - - def _get_http_url(self, region: str) -> str: - if region == "beijing": - return "https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization" - else: - return "https://dashscope-intl.aliyuncs.com/api/v1/services/audio/tts/customization" - - async def generate_custom_voice(self, params: dict) -> Tuple[bytes, int]: - from core.config import settings - - voice = self._map_speaker(params['speaker']) - model = settings.ALIYUN_MODEL_FLASH - - return await self._generate_via_websocket( - model=model, - text=params['text'], - voice=voice, - language=params['language'] - ) - - async def generate_voice_design(self, params: dict, saved_voice_id: Optional[str] = None) -> Tuple[bytes, int]: - from core.config import settings - - if saved_voice_id: - voice_id = saved_voice_id - logger.info(f"Using saved Aliyun voice_id: {voice_id}") - else: - voice_id = await self._create_voice_design( - instruct=params['instruct'], - preview_text=params['text'] - ) - - model = settings.ALIYUN_MODEL_VD - - return await self._generate_via_websocket( - model=model, - text=params['text'], - voice=voice_id, - language=params['language'] - ) - - async def generate_voice_clone(self, params: dict, ref_audio_bytes: bytes) -> Tuple[bytes, int]: - from core.config import settings - - voice_id = await self._create_voice_clone(ref_audio_bytes) - - model = settings.ALIYUN_MODEL_VC - - return await self._generate_via_websocket( - model=model, - text=params['text'], - voice=voice_id, - language=params['language'] - ) - - async def _generate_via_websocket( - self, - model: str, - text: str, - voice: str, - language: str - ) -> Tuple[bytes, int]: - audio_chunks = [] - - url = f"{self.ws_url}?model={model}" - headers = {"Authorization": f"Bearer {self.api_key}"} - - async with websockets.connect(url, additional_headers=headers) as ws: - await ws.send(json.dumps({ - "type": "session.update", - "session": { - "mode": "server_commit", - "voice": voice, - "language_type": language, - "response_format": "pcm", - "sample_rate": 24000 - } - })) - - await ws.send(json.dumps({ - "type": "input_text_buffer.append", - "text": text - })) - - await ws.send(json.dumps({ - "type": "session.finish" - })) - - async for message in ws: - event = json.loads(message) - event_type = event.get('type') - - if event_type == 'response.audio.delta': - audio_data = base64.b64decode(event['delta']) - audio_chunks.append(audio_data) - elif event_type == 'session.finished': - break - elif event_type == 'error': - raise RuntimeError(f"Aliyun API error: {event.get('error')}") - - pcm_data = b''.join(audio_chunks) - wav_bytes = self._pcm_to_wav(pcm_data, 24000) - return wav_bytes, 24000 - - async def _create_voice_clone(self, ref_audio_bytes: bytes) -> str: - from core.config import settings - import httpx - - audio_b64 = base64.b64encode(ref_audio_bytes).decode() - data_uri = f"data:audio/wav;base64,{audio_b64}" - - payload = { - "model": "qwen-voice-enrollment", - "input": { - "action": "create", - "target_model": settings.ALIYUN_MODEL_VC, - "preferred_name": f"clone{int(time.time())}", - "audio": {"data": data_uri} - } - } - - headers = { - "Authorization": f"Bearer {self.api_key}", - "Content-Type": "application/json" - } - - logger.info(f"Voice clone request payload (audio truncated): {{'model': '{payload['model']}', 'input': {{'action': '{payload['input']['action']}', 'target_model': '{payload['input']['target_model']}', 'preferred_name': '{payload['input']['preferred_name']}', 'audio': ''}}}}") - - async with httpx.AsyncClient() as client: - resp = await client.post(self.http_url, json=payload, headers=headers, timeout=60) - - if resp.status_code != 200: - logger.error(f"Voice clone failed with status {resp.status_code}") - logger.error(f"Response body: {resp.text}") - - resp.raise_for_status() - result = resp.json() - return result['output']['voice'] - - async def _create_voice_design(self, instruct: str, preview_text: str) -> str: - from core.config import settings - import httpx - - payload = { - "model": "qwen-voice-design", - "input": { - "action": "create", - "target_model": settings.ALIYUN_MODEL_VD, - "voice_prompt": instruct, - "preview_text": preview_text, - "preferred_name": f"design{int(time.time())}", - "language": "zh" - }, - "parameters": { - "sample_rate": 24000, - "response_format": "wav" - } - } - - headers = { - "Authorization": f"Bearer {self.api_key}", - "Content-Type": "application/json" - } - - logger.info(f"Voice design request payload: {payload}") - - async with httpx.AsyncClient() as client: - resp = await client.post(self.http_url, json=payload, headers=headers, timeout=60) - - if resp.status_code != 200: - logger.error(f"Voice design failed with status {resp.status_code}") - logger.error(f"Response body: {resp.text}") - - resp.raise_for_status() - result = resp.json() - return result['output']['voice'] - - async def health_check(self) -> dict: - try: - from core.config import settings - url = f"{self.ws_url}?model={settings.ALIYUN_MODEL_FLASH}" - headers = {"Authorization": f"Bearer {self.api_key}"} - - async with websockets.connect(url, additional_headers=headers, close_timeout=3) as ws: - await ws.send(json.dumps({ - "type": "session.update", - "session": { - "mode": "server_commit", - "voice": "Cherry", - "language_type": "zh", - "response_format": "pcm", - "sample_rate": 24000 - } - })) - - await ws.send(json.dumps({ - "type": "input_text_buffer.append", - "text": "测试" - })) - - await ws.send(json.dumps({ - "type": "session.finish" - })) - - async for message in ws: - event = json.loads(message) - event_type = event.get('type') - - if event_type == 'error': - return {"available": False} - elif event_type in ['response.audio.delta', 'session.finished']: - return {"available": True} - - return {"available": True} - except Exception as e: - logger.warning(f"Aliyun health check failed: {e}") - return {"available": False} - - @staticmethod - def _pcm_to_wav(pcm_data: bytes, sample_rate: int) -> bytes: - import io - import wave - - wav_buffer = io.BytesIO() - with wave.open(wav_buffer, 'wb') as wav_file: - wav_file.setnchannels(1) - wav_file.setsampwidth(2) - wav_file.setframerate(sample_rate) - wav_file.writeframes(pcm_data) - - wav_buffer.seek(0) - return wav_buffer.read() - - @staticmethod - def _map_speaker(local_speaker: str) -> str: - mapping = { - "Ono_Anna": "Ono Anna", - "Female": "Cherry", - "Male": "Ethan" - } - - mapped = mapping.get(local_speaker) - if mapped: - return mapped - - return local_speaker - - class IndexTTS2Backend: _gpu_lock = asyncio.Lock() @@ -514,32 +250,10 @@ class IndexTTS2Backend: class TTSServiceFactory: _local_backend: Optional[LocalTTSBackend] = None - _aliyun_backend: Optional[AliyunTTSBackend] = None - _user_aliyun_backends: dict[str, AliyunTTSBackend] = {} @classmethod async def get_backend(cls, backend_type: str = None, user_api_key: Optional[str] = None) -> TTSBackend: - from core.config import settings - - if backend_type is None: - backend_type = settings.DEFAULT_BACKEND - - if backend_type == "local": - if cls._local_backend is None: - cls._local_backend = LocalTTSBackend() - await cls._local_backend.initialize() - return cls._local_backend - - elif backend_type == "aliyun": - if not user_api_key: - raise ValueError("Aliyun backend requires user API key. Please set your API key first.") - - if user_api_key not in cls._user_aliyun_backends: - cls._user_aliyun_backends[user_api_key] = AliyunTTSBackend( - api_key=user_api_key, - region=settings.ALIYUN_REGION - ) - return cls._user_aliyun_backends[user_api_key] - - else: - raise ValueError(f"Unknown backend type: {backend_type}") + if cls._local_backend is None: + cls._local_backend = LocalTTSBackend() + await cls._local_backend.initialize() + return cls._local_backend diff --git a/qwen3-tts-backend/db/crud.py b/qwen3-tts-backend/db/crud.py index d7d2197..f6e519e 100644 --- a/qwen3-tts-backend/db/crud.py +++ b/qwen3-tts-backend/db/crud.py @@ -114,21 +114,6 @@ def change_user_password( db.refresh(user) return user -def update_user_aliyun_key( - db: Session, - user_id: int, - encrypted_api_key: Optional[str] -) -> Optional[User]: - user = get_user_by_id(db, user_id) - if not user: - return None - - user.aliyun_api_key = encrypted_api_key - user.updated_at = datetime.utcnow() - db.commit() - db.refresh(user) - return user - def create_job(db: Session, user_id: int, job_type: str, input_data: Dict[str, Any]) -> Job: job = Job( user_id=user_id, @@ -244,8 +229,11 @@ def delete_cache_entry(db: Session, cache_id: int, user_id: int) -> bool: def get_user_preferences(db: Session, user_id: int) -> dict: user = get_user_by_id(db, user_id) if not user or not user.user_preferences: - return {"default_backend": "aliyun", "onboarding_completed": False} - return user.user_preferences + return {"default_backend": "local", "onboarding_completed": False} + prefs = dict(user.user_preferences) + if prefs.get("default_backend") == "aliyun": + prefs["default_backend"] = "local" + return prefs def update_user_preferences(db: Session, user_id: int, preferences: dict) -> Optional[User]: user = get_user_by_id(db, user_id) @@ -276,7 +264,7 @@ def update_system_setting(db: Session, key: str, value: dict) -> SystemSettings: return setting def can_user_use_local_model(user: User) -> bool: - return user.is_superuser or user.can_use_local_model + return True def can_user_use_nsfw(user: User) -> bool: return user.is_superuser or user.can_use_nsfw @@ -286,8 +274,6 @@ def create_voice_design( user_id: int, name: str, instruct: str, - backend_type: str, - aliyun_voice_id: Optional[str] = None, meta_data: Optional[Dict[str, Any]] = None, preview_text: Optional[str] = None, voice_cache_id: Optional[int] = None, @@ -297,9 +283,7 @@ def create_voice_design( design = VoiceDesign( user_id=user_id, name=name, - backend_type=backend_type, instruct=instruct, - aliyun_voice_id=aliyun_voice_id, meta_data=meta_data, preview_text=preview_text, voice_cache_id=voice_cache_id, @@ -331,8 +315,6 @@ def list_voice_designs( VoiceDesign.user_id == user_id, VoiceDesign.is_active == True ) - if backend_type: - query = query.filter(VoiceDesign.backend_type == backend_type) return query.order_by(VoiceDesign.last_used.desc()).offset(skip).limit(limit).all() def count_voice_designs( @@ -340,13 +322,10 @@ def count_voice_designs( user_id: int, backend_type: Optional[str] = None ) -> int: - query = db.query(VoiceDesign).filter( + return db.query(VoiceDesign).filter( VoiceDesign.user_id == user_id, VoiceDesign.is_active == True - ) - if backend_type: - query = query.filter(VoiceDesign.backend_type == backend_type) - return query.count() + ).count() def delete_voice_design(db: Session, design_id: int, user_id: int) -> bool: design = get_voice_design(db, design_id, user_id) @@ -609,7 +588,6 @@ def update_audiobook_character( description: Optional[str] = None, instruct: Optional[str] = None, voice_design_id: Optional[int] = None, - use_indextts2: Optional[bool] = None, ) -> Optional[AudiobookCharacter]: char = db.query(AudiobookCharacter).filter(AudiobookCharacter.id == char_id).first() if not char: @@ -624,8 +602,6 @@ def update_audiobook_character( char.instruct = instruct if voice_design_id is not None: char.voice_design_id = voice_design_id - if use_indextts2 is not None: - char.use_indextts2 = use_indextts2 db.commit() db.refresh(char) return char diff --git a/qwen3-tts-backend/db/models.py b/qwen3-tts-backend/db/models.py index ff56bf0..c09e8ef 100644 --- a/qwen3-tts-backend/db/models.py +++ b/qwen3-tts-backend/db/models.py @@ -34,13 +34,12 @@ class User(Base): hashed_password = Column(String(255), nullable=False) is_active = Column(Boolean, default=True, nullable=False) is_superuser = Column(Boolean, default=False, nullable=False) - aliyun_api_key = Column(Text, nullable=True) llm_api_key = Column(Text, nullable=True) llm_base_url = Column(String(500), nullable=True) llm_model = Column(String(200), nullable=True) can_use_local_model = Column(Boolean, default=False, nullable=False) can_use_nsfw = Column(Boolean, default=False, nullable=False) - user_preferences = Column(JSON, nullable=True, default=lambda: {"default_backend": "aliyun", "onboarding_completed": False}) + user_preferences = Column(JSON, nullable=True, default=lambda: {"default_backend": "local", "onboarding_completed": False}) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) @@ -105,9 +104,7 @@ class VoiceDesign(Base): id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True) name = Column(String(100), nullable=False) - backend_type = Column(String(20), nullable=False, index=True) instruct = Column(Text, nullable=False) - aliyun_voice_id = Column(String(255), nullable=True) meta_data = Column(JSON, nullable=True) preview_text = Column(Text, nullable=True) ref_audio_path = Column(String(500), nullable=True) @@ -121,7 +118,6 @@ class VoiceDesign(Base): user = relationship("User", back_populates="voice_designs") __table_args__ = ( - Index('idx_user_backend', 'user_id', 'backend_type'), Index('idx_user_active', 'user_id', 'is_active'), ) @@ -176,8 +172,6 @@ class AudiobookCharacter(Base): description = Column(Text, nullable=True) instruct = Column(Text, nullable=True) voice_design_id = Column(Integer, ForeignKey("voice_designs.id"), nullable=True) - use_indextts2 = Column(Boolean, default=False, nullable=False) - project = relationship("AudiobookProject", back_populates="characters") voice_design = relationship("VoiceDesign") segments = relationship("AudiobookSegment", back_populates="character") diff --git a/qwen3-tts-backend/main.py b/qwen3-tts-backend/main.py index 7e3fc75..8fc6826 100644 --- a/qwen3-tts-backend/main.py +++ b/qwen3-tts-backend/main.py @@ -233,12 +233,6 @@ async def health_check_details(current_user: User = Depends(get_current_user)): backends_status["local"] = local_health except Exception as e: backends_status["local"] = {"available": False, "error": str(e)} - - backends_status["aliyun"] = { - "available": True, - "region": settings.ALIYUN_REGION, - "note": "Requires user API key configuration" - } except Exception as e: logger.error(f"Backend health check failed: {e}") backends_status = {"error": str(e)} diff --git a/qwen3-tts-backend/schemas/audiobook.py b/qwen3-tts-backend/schemas/audiobook.py index aeffa48..424fcd7 100644 --- a/qwen3-tts-backend/schemas/audiobook.py +++ b/qwen3-tts-backend/schemas/audiobook.py @@ -61,7 +61,6 @@ class AudiobookCharacterResponse(BaseModel): voice_design_id: Optional[int] = None voice_design_name: Optional[str] = None voice_design_speaker: Optional[str] = None - use_indextts2: bool = False model_config = ConfigDict(from_attributes=True) @@ -105,7 +104,6 @@ class AudiobookCharacterEdit(BaseModel): description: Optional[str] = None instruct: Optional[str] = None voice_design_id: Optional[int] = None - use_indextts2: Optional[bool] = None class AudiobookSegmentResponse(BaseModel): diff --git a/qwen3-tts-backend/schemas/tts.py b/qwen3-tts-backend/schemas/tts.py index e9ab3ec..0271d51 100644 --- a/qwen3-tts-backend/schemas/tts.py +++ b/qwen3-tts-backend/schemas/tts.py @@ -24,7 +24,7 @@ class CustomVoiceRequest(BaseModel): top_k: Optional[int] = Field(default=50, ge=1, le=100) top_p: Optional[float] = Field(default=1.0, ge=0.0, le=1.0) repetition_penalty: Optional[float] = Field(default=1.05, ge=1.0, le=2.0) - backend: Optional[str] = Field(default=None, description="Backend type: local or aliyun") + backend: Optional[str] = Field(default=None) class VoiceDesignRequest(BaseModel): diff --git a/qwen3-tts-backend/schemas/user.py b/qwen3-tts-backend/schemas/user.py index 0ca61b9..5809281 100644 --- a/qwen3-tts-backend/schemas/user.py +++ b/qwen3-tts-backend/schemas/user.py @@ -118,18 +118,11 @@ class PasswordChange(BaseModel): raise ValueError('Passwords do not match') return self -class AliyunKeyUpdate(BaseModel): - api_key: str = Field(..., min_length=1, max_length=500) - -class AliyunKeyVerifyResponse(BaseModel): - valid: bool - message: str - class UserPreferences(BaseModel): - default_backend: str = Field(default="aliyun", pattern="^(local|aliyun)$") + default_backend: str = Field(default="local", pattern="^local$") onboarding_completed: bool = Field(default=False) class UserPreferencesResponse(BaseModel): - default_backend: str = Field(default="aliyun", pattern="^(local|aliyun)$") + default_backend: str = Field(default="local") onboarding_completed: bool = Field(default=False) - available_backends: list[str] = Field(default=["aliyun"]) + available_backends: list[str] = Field(default=["local"]) diff --git a/qwen3-tts-backend/schemas/voice_design.py b/qwen3-tts-backend/schemas/voice_design.py index 90814d7..bbf9931 100644 --- a/qwen3-tts-backend/schemas/voice_design.py +++ b/qwen3-tts-backend/schemas/voice_design.py @@ -5,8 +5,6 @@ from pydantic import BaseModel, Field class VoiceDesignCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) instruct: str = Field(..., min_length=1) - backend_type: str = Field(..., pattern="^(local|aliyun)$") - aliyun_voice_id: Optional[str] = None meta_data: Optional[Dict[str, Any]] = None preview_text: Optional[str] = None @@ -14,9 +12,7 @@ class VoiceDesignResponse(BaseModel): id: int user_id: int name: str - backend_type: str instruct: str - aliyun_voice_id: Optional[str] meta_data: Optional[Dict[str, Any]] preview_text: Optional[str] ref_audio_path: Optional[str] = None diff --git a/qwen3-tts-backend/utils/validation.py b/qwen3-tts-backend/utils/validation.py index 0fe0d58..98ef57d 100644 --- a/qwen3-tts-backend/utils/validation.py +++ b/qwen3-tts-backend/utils/validation.py @@ -23,22 +23,6 @@ SPEAKER_DESCRIPTIONS = { "Sohee": "Female, soft and melodious" } -ALIYUN_SPEAKERS = [ - "Vivian", "Serena", "Dylan", "Eric", - "Ryan", "Aiden", "Ono_Anna", "Sohee" -] - -ALIYUN_SPEAKER_DESCRIPTIONS = { - "Vivian": "Female, cute and lively (十三 - 拽拽的、可爱的小暴躁)", - "Serena": "Female, gentle and warm (苏瑶 - 温柔小姐姐)", - "Dylan": "Male, young and energetic (北京-晓东 - 北京胡同里长大的少年)", - "Eric": "Male, calm and steady (四川-程川 - 跳脱市井的四川成都男子)", - "Ryan": "Male, friendly and dramatic (甜茶 - 节奏拉满,戏感炸裂)", - "Aiden": "Male, deep and resonant (艾登 - 精通厨艺的美语大男孩)", - "Ono_Anna": "Female, cute and playful (小野杏 - 鬼灵精怪的青梅竹马)", - "Sohee": "Female, soft and melodious (素熙 - 温柔开朗的韩国欧尼)" -} - LOCAL_SPEAKERS = SUPPORTED_SPEAKERS.copy() LOCAL_SPEAKER_DESCRIPTIONS = SPEAKER_DESCRIPTIONS.copy() @@ -60,18 +44,13 @@ def validate_language(language: str) -> str: def validate_speaker(speaker: str, backend: str = "local") -> str: normalized = speaker.strip() - if backend == "aliyun": - speaker_list = ALIYUN_SPEAKERS - else: - speaker_list = LOCAL_SPEAKERS - - for supported in speaker_list: + for supported in LOCAL_SPEAKERS: if normalized.lower() == supported.lower(): return supported raise ValueError( - f"Unsupported speaker: {speaker} for backend '{backend}'. " - f"Supported speakers: {', '.join(speaker_list)}" + f"Unsupported speaker: {speaker}. " + f"Supported speakers: {', '.join(LOCAL_SPEAKERS)}" ) @@ -118,17 +97,10 @@ def get_supported_languages() -> List[str]: def get_supported_speakers(backend: str = "local") -> List[dict]: - if backend == "aliyun": - speakers = ALIYUN_SPEAKERS - descriptions = ALIYUN_SPEAKER_DESCRIPTIONS - else: - speakers = LOCAL_SPEAKERS - descriptions = LOCAL_SPEAKER_DESCRIPTIONS - return [ { "name": speaker, - "description": descriptions.get(speaker, "") + "description": LOCAL_SPEAKER_DESCRIPTIONS.get(speaker, "") } - for speaker in speakers + for speaker in LOCAL_SPEAKERS ] diff --git a/qwen3-tts-frontend/src/components/users/UserDialog.tsx b/qwen3-tts-frontend/src/components/users/UserDialog.tsx index 60781b7..40b857c 100644 --- a/qwen3-tts-frontend/src/components/users/UserDialog.tsx +++ b/qwen3-tts-frontend/src/components/users/UserDialog.tsx @@ -30,7 +30,6 @@ const createUserFormSchema = (t: (key: string) => string) => z.object({ password: z.string().optional(), is_active: z.boolean(), is_superuser: z.boolean(), - can_use_local_model: z.boolean(), can_use_nsfw: z.boolean(), }) @@ -63,7 +62,6 @@ export function UserDialog({ password: '', is_active: true, is_superuser: false, - can_use_local_model: false, can_use_nsfw: false, }, }) @@ -76,7 +74,6 @@ export function UserDialog({ password: '', is_active: user.is_active, is_superuser: user.is_superuser, - can_use_local_model: user.can_use_local_model, can_use_nsfw: user.can_use_nsfw ?? false, }) } else { @@ -86,7 +83,6 @@ export function UserDialog({ password: '', is_active: true, is_superuser: false, - can_use_local_model: false, can_use_nsfw: false, }) } @@ -189,27 +185,6 @@ export function UserDialog({ )} /> - ( - - - - -
- {t('user:canUseLocalModel')} -

- {t('user:canUseLocalModelDescription')} -

-
-
- )} - /> -
- {(user.is_superuser || user.can_use_local_model) && ( - {t('user:localModelPermission')} - )} {(user.is_superuser || user.can_use_nsfw) && ( {t('user:nsfwPermission')} )} @@ -146,13 +143,10 @@ export function UserTable({ users, isLoading, onEdit, onDelete }: UserTableProps
{t('common:actions')}:
- {(user.is_superuser || user.can_use_local_model) && ( - {t('user:localModelPermission')} - )} {(user.is_superuser || user.can_use_nsfw) && ( {t('user:nsfwPermission')} )} - {!user.is_superuser && !user.can_use_local_model && !user.can_use_nsfw && ( + {!user.is_superuser && !user.can_use_nsfw && ( {t('user:noPermission')} )}
diff --git a/qwen3-tts-frontend/src/contexts/UserPreferencesContext.tsx b/qwen3-tts-frontend/src/contexts/UserPreferencesContext.tsx index 6f38c88..856c7e6 100644 --- a/qwen3-tts-frontend/src/contexts/UserPreferencesContext.tsx +++ b/qwen3-tts-frontend/src/contexts/UserPreferencesContext.tsx @@ -9,7 +9,6 @@ interface UserPreferencesContextType { preferences: UserPreferences | null isLoading: boolean updatePreferences: (prefs: Partial) => Promise - hasAliyunKey: boolean refetchPreferences: () => Promise isBackendAvailable: (backend: string) => boolean changeLanguage: (lang: 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP' | 'ko-KR') => Promise @@ -20,7 +19,6 @@ const UserPreferencesContext = createContext(null) - const [hasAliyunKey, setHasAliyunKey] = useState(false) const [isLoading, setIsLoading] = useState(true) const fetchPreferences = async () => { @@ -34,13 +32,9 @@ export function UserPreferencesProvider({ children }: { children: ReactNode }) { try { setIsLoading(true) - const [prefs, keyVerification] = await Promise.all([ - authApi.getPreferences(), - authApi.verifyAliyunKey().catch(() => ({ valid: false, message: '' })), - ]) + const prefs = await authApi.getPreferences() setPreferences(prefs) - setHasAliyunKey(keyVerification.valid) const lang = prefs.language || detectBrowserLanguage() loadFontsForLanguage(lang) @@ -60,7 +54,7 @@ export function UserPreferencesProvider({ children }: { children: ReactNode }) { } else { const browserLang = detectBrowserLanguage() loadFontsForLanguage(browserLang) - setPreferences({ default_backend: 'aliyun', onboarding_completed: false }) + setPreferences({ default_backend: 'local', onboarding_completed: false }) } } finally { setIsLoading(false) @@ -90,10 +84,7 @@ export function UserPreferencesProvider({ children }: { children: ReactNode }) { } const isBackendAvailable = (backend: string) => { - if (!preferences?.available_backends) { - return backend === 'aliyun' - } - return preferences.available_backends.includes(backend) + return backend === 'local' } const changeLanguage = async (lang: 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP' | 'ko-KR') => { @@ -108,7 +99,6 @@ export function UserPreferencesProvider({ children }: { children: ReactNode }) { preferences, isLoading, updatePreferences, - hasAliyunKey, refetchPreferences: fetchPreferences, isBackendAvailable, changeLanguage, diff --git a/qwen3-tts-frontend/src/lib/api.ts b/qwen3-tts-frontend/src/lib/api.ts index 1c8330d..527be83 100644 --- a/qwen3-tts-frontend/src/lib/api.ts +++ b/qwen3-tts-frontend/src/lib/api.ts @@ -209,21 +209,6 @@ export const authApi = { await apiClient.put(API_ENDPOINTS.AUTH.PREFERENCES, data) }, - setAliyunKey: async (apiKey: string): Promise => { - await apiClient.post(API_ENDPOINTS.AUTH.SET_ALIYUN_KEY, { api_key: apiKey }) - }, - - deleteAliyunKey: async (): Promise => { - await apiClient.delete(API_ENDPOINTS.AUTH.SET_ALIYUN_KEY) - }, - - verifyAliyunKey: async (): Promise<{ valid: boolean; message: string }> => { - const response = await apiClient.get<{ valid: boolean; message: string }>( - API_ENDPOINTS.AUTH.VERIFY_ALIYUN_KEY - ) - return response.data - }, - getNsfwAccess: async (): Promise<{ has_access: boolean }> => { const response = await apiClient.get<{ has_access: boolean }>(API_ENDPOINTS.AUTH.NSFW_ACCESS) return response.data @@ -247,21 +232,6 @@ export interface UserUsageStats { } export const adminApi = { - setAliyunKey: async (apiKey: string): Promise => { - await apiClient.post(API_ENDPOINTS.ADMIN.SET_ALIYUN_KEY, { api_key: apiKey }) - }, - - deleteAliyunKey: async (): Promise => { - await apiClient.delete(API_ENDPOINTS.ADMIN.SET_ALIYUN_KEY) - }, - - verifyAliyunKey: async (): Promise<{ valid: boolean; message: string }> => { - const response = await apiClient.get<{ valid: boolean; message: string }>( - API_ENDPOINTS.ADMIN.VERIFY_ALIYUN_KEY - ) - return response.data - }, - getLLMConfig: async (): Promise<{ base_url?: string; model?: string; has_key: boolean }> => { const response = await apiClient.get<{ base_url?: string; model?: string; has_key: boolean }>( API_ENDPOINTS.ADMIN.LLM_CONFIG diff --git a/qwen3-tts-frontend/src/lib/api/audiobook.ts b/qwen3-tts-frontend/src/lib/api/audiobook.ts index 30d09a3..82ebe52 100644 --- a/qwen3-tts-frontend/src/lib/api/audiobook.ts +++ b/qwen3-tts-frontend/src/lib/api/audiobook.ts @@ -50,7 +50,6 @@ export interface AudiobookCharacter { voice_design_id?: number voice_design_name?: string voice_design_speaker?: string - use_indextts2?: boolean } export interface AudiobookChapter { @@ -175,7 +174,7 @@ export const audiobookApi = { updateCharacter: async ( projectId: number, charId: number, - data: { name?: string; gender?: string; description?: string; instruct?: string; voice_design_id?: number; use_indextts2?: boolean } + data: { name?: string; gender?: string; description?: string; instruct?: string; voice_design_id?: number } ): Promise => { const response = await apiClient.put( `/audiobook/projects/${projectId}/characters/${charId}`, diff --git a/qwen3-tts-frontend/src/lib/constants.ts b/qwen3-tts-frontend/src/lib/constants.ts index b10e18e..343d4f0 100644 --- a/qwen3-tts-frontend/src/lib/constants.ts +++ b/qwen3-tts-frontend/src/lib/constants.ts @@ -4,8 +4,6 @@ export const API_ENDPOINTS = { ME: '/auth/me', CHANGE_PASSWORD: '/auth/change-password', PREFERENCES: '/auth/preferences', - SET_ALIYUN_KEY: '/auth/aliyun-key', - VERIFY_ALIYUN_KEY: '/auth/aliyun-key/verify', NSFW_ACCESS: '/auth/nsfw-access', }, TTS: { @@ -30,8 +28,6 @@ export const API_ENDPOINTS = { DELETE: (id: number) => `/users/${id}`, }, ADMIN: { - SET_ALIYUN_KEY: '/users/system/aliyun-key', - VERIFY_ALIYUN_KEY: '/users/system/aliyun-key/verify', LLM_CONFIG: '/users/system/llm-config', GROK_CONFIG: '/users/system/grok-config', }, diff --git a/qwen3-tts-frontend/src/locales/en-US/onboarding.json b/qwen3-tts-frontend/src/locales/en-US/onboarding.json index 5dd6153..6704f9d 100644 --- a/qwen3-tts-frontend/src/locales/en-US/onboarding.json +++ b/qwen3-tts-frontend/src/locales/en-US/onboarding.json @@ -1,25 +1,12 @@ { "welcome": "Welcome to Qwen3 TTS", - "configureApiKey": "Configure Aliyun API Key", - "selectBackendDescription": "Please select your TTS backend mode, you can change it later in settings", - "enterApiKeyDescription": "Please enter your Aliyun API key, the system will verify its validity", "localModel": "Local Model", "localModelDescription": "Free to use local Qwen3-TTS model", "localModelNoPermission": "No local model permission, please contact administrator", - "aliyunApi": "Aliyun API", - "aliyunApiRecommended": "(Recommended)", - "aliyunApiDescription": "Requires API key configuration, pay-as-you-go", "skipConfig": "Skip Configuration", - "nextStep": "Next", "back": "Back", - "verifying": "Verifying...", - "verifyAndComplete": "Verify and Complete", - "apiKey": "API Key", - "howToGetApiKey": "How to get API key?", "skipSuccess": "Configuration skipped, using local mode by default", "operationFailed": "Operation failed, please retry", "configComplete": "Configuration complete, using local mode by default", - "configCompleteAliyun": "Configuration complete, using Aliyun mode by default", - "saveFailed": "Failed to save configuration, please retry", - "verifyFailed": "API key verification failed, please check and retry" + "saveFailed": "Failed to save configuration, please retry" } diff --git a/qwen3-tts-frontend/src/locales/en-US/settings.json b/qwen3-tts-frontend/src/locales/en-US/settings.json index 206b244..36eff9b 100644 --- a/qwen3-tts-frontend/src/locales/en-US/settings.json +++ b/qwen3-tts-frontend/src/locales/en-US/settings.json @@ -1,57 +1,12 @@ { - "settings": "Settings", - "generalSettings": "General Settings", - "backendSettings": "Backend Settings", - "apiSettings": "API Settings", - "preferencesSaved": "Preferences saved", - "preferencesSaveFailed": "Preferences save failed", - "defaultBackend": "Default Backend", - "local": "Local Model", - "aliyun": "Aliyun API", - "aliyunApiKey": "Aliyun API Key", - "apiKeyPlaceholder": "Enter API key", - "apiKeyDescription": "Used for Aliyun TTS service authentication", - "saveApiKey": "Save Key", - "apiKeySaved": "API key saved", - "apiKeySaveFailed": "API key save failed", - "showApiKey": "Show Key", - "hideApiKey": "Hide Key", - "testConnection": "Test Connection", - "connectionSuccess": "Connection successful", - "connectionFailed": "Connection failed", + "title": "Settings", + "description": "Manage your account settings and preferences", "language": "Interface Language", "languageDescription": "Select interface display language", "theme": "Theme", "themeLight": "Light", "themeDark": "Dark", "themeSystem": "System", - "title": "Settings", - "description": "Manage your account settings and preferences", - "backendPreference": "Backend Preference", - "backendPreferenceDescription": "Choose default TTS backend mode", - "localModel": "Local Model", - "localModelDescription": "Free to use local Qwen3-TTS model", - "localModelNoPermission": "Please contact admin to enable local model access", - "aliyunApi": "Aliyun API", - "aliyunApiDescription": "Use Aliyun TTS service", - "switchedToLocal": "Switched to local mode", - "switchedToAliyun": "Switched to Aliyun mode", - "saveFailed": "Save failed, please retry", - "apiKeyUpdated": "API key updated and verified successfully", - "apiKeyVerifyFailed": "API key verification failed", - "verifyFailed": "Verification failed", - "currentStatus": "Current Status:", - "configured": "Configured and valid", - "notConfigured": "Not configured", - "apiKey": "API Key", - "updating": "Updating...", - "addKey": "Add Key", - "updateKey": "Update Key", - "verifyKey": "Verify Key", - "deleteKey": "Delete Key", - "deleteKeyConfirm": "Are you sure you want to delete Aliyun API key? Will switch to local mode automatically.", - "keyDeleted": "API key deleted, switched to local mode", - "deleteFailed": "Delete failed", "accountInfo": "Account Information", "accountInfoDescription": "Your account basic information", "email": "Email", diff --git a/qwen3-tts-frontend/src/locales/en-US/tts.json b/qwen3-tts-frontend/src/locales/en-US/tts.json index bfb58c1..80cddd4 100644 --- a/qwen3-tts-frontend/src/locales/en-US/tts.json +++ b/qwen3-tts-frontend/src/locales/en-US/tts.json @@ -22,7 +22,6 @@ "pauseAudio": "Pause", "backend": "Backend Service", "localBackend": "Local Model", - "aliyunBackend": "Aliyun API", "backendSwitched": "Backend switched", "backendError": "Backend service error", "languageLabel": "Language", diff --git a/qwen3-tts-frontend/src/locales/en-US/voice.json b/qwen3-tts-frontend/src/locales/en-US/voice.json index dfff7d7..74eade0 100644 --- a/qwen3-tts-frontend/src/locales/en-US/voice.json +++ b/qwen3-tts-frontend/src/locales/en-US/voice.json @@ -61,6 +61,5 @@ "deleteFailed": "Delete failed", "deleteConfirmDesc": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", "local": "Local", - "aliyun": "Aliyun", "deleting": "Deleting..." } \ No newline at end of file diff --git a/qwen3-tts-frontend/src/locales/ja-JP/onboarding.json b/qwen3-tts-frontend/src/locales/ja-JP/onboarding.json index 0cc4763..106d105 100644 --- a/qwen3-tts-frontend/src/locales/ja-JP/onboarding.json +++ b/qwen3-tts-frontend/src/locales/ja-JP/onboarding.json @@ -1,25 +1,12 @@ { "welcome": "Qwen3 TTSへようこそ", - "configureApiKey": "Aliyun APIキーを設定", - "selectBackendDescription": "TTSバックエンドモードを選択してください。後で設定で変更できます", - "enterApiKeyDescription": "Aliyun APIキーを入力してください。システムがその有効性を検証します", "localModel": "ローカルモデル", "localModelDescription": "無料でローカルQwen3-TTSモデルを使用", "localModelNoPermission": "ローカルモデルの権限がありません。管理者にお問い合わせください", - "aliyunApi": "Aliyun API", - "aliyunApiRecommended": "(推奨)", - "aliyunApiDescription": "APIキーの設定が必要。従量課金制", "skipConfig": "設定をスキップ", - "nextStep": "次へ", "back": "戻る", - "verifying": "検証中...", - "verifyAndComplete": "検証して完了", - "apiKey": "APIキー", - "howToGetApiKey": "APIキーの取得方法", "skipSuccess": "設定をスキップしました。デフォルトでローカルモードを使用します", "operationFailed": "操作に失敗しました。再試行してください", "configComplete": "設定が完了しました。デフォルトでローカルモードを使用します", - "configCompleteAliyun": "設定が完了しました。デフォルトでAliyunモードを使用します", - "saveFailed": "設定の保存に失敗しました。再試行してください", - "verifyFailed": "APIキーの検証に失敗しました。確認して再試行してください" + "saveFailed": "設定の保存に失敗しました。再試行してください" } diff --git a/qwen3-tts-frontend/src/locales/ja-JP/settings.json b/qwen3-tts-frontend/src/locales/ja-JP/settings.json index c55ba93..42fe556 100644 --- a/qwen3-tts-frontend/src/locales/ja-JP/settings.json +++ b/qwen3-tts-frontend/src/locales/ja-JP/settings.json @@ -1,57 +1,12 @@ { - "settings": "設定", - "generalSettings": "一般設定", - "backendSettings": "バックエンド設定", - "apiSettings": "API設定", - "preferencesSaved": "設定を保存しました", - "preferencesSaveFailed": "設定の保存に失敗しました", - "defaultBackend": "デフォルトバックエンド", - "local": "ローカルモデル", - "aliyun": "Aliyun API", - "aliyunApiKey": "Aliyun APIキー", - "apiKeyPlaceholder": "APIキーを入力してください", - "apiKeyDescription": "Aliyun TTSサービスの認証に使用", - "saveApiKey": "キーを保存", - "apiKeySaved": "APIキーを保存しました", - "apiKeySaveFailed": "APIキーの保存に失敗しました", - "showApiKey": "キーを表示", - "hideApiKey": "キーを非表示", - "testConnection": "接続テスト", - "connectionSuccess": "接続成功", - "connectionFailed": "接続失敗", + "title": "設定", + "description": "アカウント設定と環境設定を管理", "language": "表示言語", "languageDescription": "インターフェース言語を選択", "theme": "テーマ", "themeLight": "ライト", "themeDark": "ダーク", "themeSystem": "システム設定", - "title": "設定", - "description": "アカウント設定と環境設定を管理", - "backendPreference": "バックエンド設定", - "backendPreferenceDescription": "デフォルトのTTSバックエンドモードを選択", - "localModel": "ローカルモデル", - "localModelDescription": "無料でローカルQwen3-TTSモデルを使用", - "localModelNoPermission": "管理者にローカルモデルの使用権限をお問い合わせください", - "aliyunApi": "Aliyun API", - "aliyunApiDescription": "Aliyun TTSサービスを使用", - "switchedToLocal": "ローカルモードに切り替えました", - "switchedToAliyun": "Aliyunモードに切り替えました", - "saveFailed": "保存に失敗しました。再試行してください", - "apiKeyUpdated": "APIキーを更新し、検証しました", - "apiKeyVerifyFailed": "APIキーの検証に失敗しました", - "verifyFailed": "検証に失敗しました", - "currentStatus": "現在のステータス:", - "configured": "設定済みで有効", - "notConfigured": "未設定", - "apiKey": "APIキー", - "updating": "更新中...", - "addKey": "キーを追加", - "updateKey": "キーを更新", - "verifyKey": "キーを検証", - "deleteKey": "キーを削除", - "deleteKeyConfirm": "Aliyun APIキーを削除してもよろしいですか?削除後は自動的にローカルモードに切り替わります。", - "keyDeleted": "APIキーを削除しました。ローカルモードに切り替えました", - "deleteFailed": "削除に失敗しました", "accountInfo": "アカウント情報", "accountInfoDescription": "アカウントの基本情報", "email": "メールアドレス", diff --git a/qwen3-tts-frontend/src/locales/ja-JP/tts.json b/qwen3-tts-frontend/src/locales/ja-JP/tts.json index 26a07bd..9e8e221 100644 --- a/qwen3-tts-frontend/src/locales/ja-JP/tts.json +++ b/qwen3-tts-frontend/src/locales/ja-JP/tts.json @@ -22,7 +22,6 @@ "pauseAudio": "一時停止", "backend": "バックエンドサービス", "localBackend": "ローカルモデル", - "aliyunBackend": "Alibaba Cloud API", "backendSwitched": "バックエンドを切り替えました", "backendError": "バックエンドサービスエラー", "languageLabel": "言語", diff --git a/qwen3-tts-frontend/src/locales/ja-JP/voice.json b/qwen3-tts-frontend/src/locales/ja-JP/voice.json index 27b3502..472eee1 100644 --- a/qwen3-tts-frontend/src/locales/ja-JP/voice.json +++ b/qwen3-tts-frontend/src/locales/ja-JP/voice.json @@ -61,6 +61,5 @@ "deleteFailed": "削除に失敗しました", "deleteConfirmDesc": "「{{name}}」を削除してもよろしいですか?この操作は元に戻せません。", "local": "ローカル", - "aliyun": "Aliyun", "deleting": "削除中..." } \ No newline at end of file diff --git a/qwen3-tts-frontend/src/locales/ko-KR/onboarding.json b/qwen3-tts-frontend/src/locales/ko-KR/onboarding.json index 452ef95..113ddb9 100644 --- a/qwen3-tts-frontend/src/locales/ko-KR/onboarding.json +++ b/qwen3-tts-frontend/src/locales/ko-KR/onboarding.json @@ -1,25 +1,12 @@ { "welcome": "Qwen3 TTS에 오신 것을 환영합니다", - "configureApiKey": "Aliyun API 키 설정", - "selectBackendDescription": "TTS 백엔드 모드를 선택하세요. 나중에 설정에서 변경할 수 있습니다", - "enterApiKeyDescription": "Aliyun API 키를 입력하세요. 시스템이 유효성을 검증합니다", "localModel": "로컬 모델", "localModelDescription": "무료로 로컬 Qwen3-TTS 모델 사용", "localModelNoPermission": "로컬 모델 권한이 없습니다. 관리자에게 문의하세요", - "aliyunApi": "Aliyun API", - "aliyunApiRecommended": "(권장)", - "aliyunApiDescription": "API 키 설정 필요. 사용량에 따라 과금", "skipConfig": "설정 건너뛰기", - "nextStep": "다음", "back": "뒤로", - "verifying": "검증 중...", - "verifyAndComplete": "검증 및 완료", - "apiKey": "API 키", - "howToGetApiKey": "API 키를 얻는 방법", "skipSuccess": "설정을 건너뛰었습니다. 기본적으로 로컬 모드를 사용합니다", "operationFailed": "작업에 실패했습니다. 다시 시도하세요", "configComplete": "설정이 완료되었습니다. 기본적으로 로컬 모드를 사용합니다", - "configCompleteAliyun": "설정이 완료되었습니다. 기본적으로 Aliyun 모드를 사용합니다", - "saveFailed": "설정 저장에 실패했습니다. 다시 시도하세요", - "verifyFailed": "API 키 검증에 실패했습니다. 확인 후 다시 시도하세요" + "saveFailed": "설정 저장에 실패했습니다. 다시 시도하세요" } diff --git a/qwen3-tts-frontend/src/locales/ko-KR/settings.json b/qwen3-tts-frontend/src/locales/ko-KR/settings.json index 5319d9d..c9cd7fc 100644 --- a/qwen3-tts-frontend/src/locales/ko-KR/settings.json +++ b/qwen3-tts-frontend/src/locales/ko-KR/settings.json @@ -1,57 +1,12 @@ { - "settings": "설정", - "generalSettings": "일반 설정", - "backendSettings": "백엔드 설정", - "apiSettings": "API 설정", - "preferencesSaved": "환경 설정이 저장되었습니다", - "preferencesSaveFailed": "환경 설정 저장에 실패했습니다", - "defaultBackend": "기본 백엔드", - "local": "로컬 모델", - "aliyun": "Aliyun API", - "aliyunApiKey": "Aliyun API 키", - "apiKeyPlaceholder": "API 키를 입력하세요", - "apiKeyDescription": "Aliyun TTS 서비스 인증에 사용", - "saveApiKey": "키 저장", - "apiKeySaved": "API 키가 저장되었습니다", - "apiKeySaveFailed": "API 키 저장에 실패했습니다", - "showApiKey": "키 표시", - "hideApiKey": "키 숨기기", - "testConnection": "연결 테스트", - "connectionSuccess": "연결 성공", - "connectionFailed": "연결 실패", + "title": "설정", + "description": "계정 설정 및 환경 설정 관리", "language": "인터페이스 언어", "languageDescription": "인터페이스 표시 언어 선택", "theme": "테마", "themeLight": "라이트", "themeDark": "다크", "themeSystem": "시스템 설정", - "title": "설정", - "description": "계정 설정 및 환경 설정 관리", - "backendPreference": "백엔드 설정", - "backendPreferenceDescription": "기본 TTS 백엔드 모드 선택", - "localModel": "로컬 모델", - "localModelDescription": "무료로 로컬 Qwen3-TTS 모델 사용", - "localModelNoPermission": "관리자에게 로컬 모델 사용 권한을 문의하세요", - "aliyunApi": "Aliyun API", - "aliyunApiDescription": "Aliyun TTS 서비스 사용", - "switchedToLocal": "로컬 모드로 전환했습니다", - "switchedToAliyun": "Aliyun 모드로 전환했습니다", - "saveFailed": "저장에 실패했습니다. 다시 시도하세요", - "apiKeyUpdated": "API 키가 업데이트되고 검증되었습니다", - "apiKeyVerifyFailed": "API 키 검증에 실패했습니다", - "verifyFailed": "검증에 실패했습니다", - "currentStatus": "현재 상태:", - "configured": "설정됨 및 유효함", - "notConfigured": "설정되지 않음", - "apiKey": "API 키", - "updating": "업데이트 중...", - "addKey": "키 추가", - "updateKey": "키 업데이트", - "verifyKey": "키 검증", - "deleteKey": "키 삭제", - "deleteKeyConfirm": "Aliyun API 키를 삭제하시겠습니까? 삭제 후 자동으로 로컬 모드로 전환됩니다.", - "keyDeleted": "API 키가 삭제되었습니다. 로컬 모드로 전환했습니다", - "deleteFailed": "삭제에 실패했습니다", "accountInfo": "계정 정보", "accountInfoDescription": "계정 기본 정보", "email": "이메일", diff --git a/qwen3-tts-frontend/src/locales/ko-KR/tts.json b/qwen3-tts-frontend/src/locales/ko-KR/tts.json index 8094140..c367794 100644 --- a/qwen3-tts-frontend/src/locales/ko-KR/tts.json +++ b/qwen3-tts-frontend/src/locales/ko-KR/tts.json @@ -22,7 +22,6 @@ "pauseAudio": "일시정지", "backend": "백엔드 서비스", "localBackend": "로컬 모델", - "aliyunBackend": "Alibaba Cloud API", "backendSwitched": "백엔드가 전환되었습니다", "backendError": "백엔드 서비스 오류", "languageLabel": "언어", diff --git a/qwen3-tts-frontend/src/locales/ko-KR/voice.json b/qwen3-tts-frontend/src/locales/ko-KR/voice.json index 22d45e6..1999a9d 100644 --- a/qwen3-tts-frontend/src/locales/ko-KR/voice.json +++ b/qwen3-tts-frontend/src/locales/ko-KR/voice.json @@ -61,6 +61,5 @@ "deleteFailed": "삭제 실패", "deleteConfirmDesc": "「{{name}}」을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", "local": "로컬", - "aliyun": "Aliyun", "deleting": "삭제 중..." } \ No newline at end of file diff --git a/qwen3-tts-frontend/src/locales/zh-CN/onboarding.json b/qwen3-tts-frontend/src/locales/zh-CN/onboarding.json index 0119522..a6a0f83 100644 --- a/qwen3-tts-frontend/src/locales/zh-CN/onboarding.json +++ b/qwen3-tts-frontend/src/locales/zh-CN/onboarding.json @@ -1,25 +1,12 @@ { "welcome": "欢迎使用 Qwen3 TTS", - "configureApiKey": "配置阿里云 API 密钥", - "selectBackendDescription": "请选择您的 TTS 后端模式,后续可在设置中修改", - "enterApiKeyDescription": "请输入您的阿里云 API 密钥,系统将验证其有效性", "localModel": "本地模型", "localModelDescription": "免费使用本地 Qwen3-TTS 模型", "localModelNoPermission": "无本地模型权限,请联系管理员", - "aliyunApi": "阿里云 API", - "aliyunApiRecommended": "(推荐)", - "aliyunApiDescription": "需要配置 API 密钥,按量计费", "skipConfig": "跳过配置", - "nextStep": "下一步", "back": "返回", - "verifying": "验证中...", - "verifyAndComplete": "验证并完成", - "apiKey": "API 密钥", - "howToGetApiKey": "如何获取 API 密钥?", "skipSuccess": "已跳过配置,默认使用本地模式", "operationFailed": "操作失败,请重试", "configComplete": "配置完成,默认使用本地模式", - "configCompleteAliyun": "配置完成,默认使用阿里云模式", - "saveFailed": "保存配置失败,请重试", - "verifyFailed": "API 密钥验证失败,请检查后重试" + "saveFailed": "保存配置失败,请重试" } diff --git a/qwen3-tts-frontend/src/locales/zh-CN/settings.json b/qwen3-tts-frontend/src/locales/zh-CN/settings.json index 27045c6..700fc6e 100644 --- a/qwen3-tts-frontend/src/locales/zh-CN/settings.json +++ b/qwen3-tts-frontend/src/locales/zh-CN/settings.json @@ -1,57 +1,12 @@ { - "settings": "设置", - "generalSettings": "通用设置", - "backendSettings": "后端设置", - "apiSettings": "API设置", - "preferencesSaved": "偏好设置已保存", - "preferencesSaveFailed": "偏好设置保存失败", - "defaultBackend": "默认后端", - "local": "本地模型", - "aliyun": "阿里云API", - "aliyunApiKey": "阿里云 API 密钥", - "apiKeyPlaceholder": "请输入 API 密钥", - "apiKeyDescription": "用于阿里云 TTS 服务认证", - "saveApiKey": "保存密钥", - "apiKeySaved": "API 密钥已保存", - "apiKeySaveFailed": "API 密钥保存失败", - "showApiKey": "显示密钥", - "hideApiKey": "隐藏密钥", - "testConnection": "测试连接", - "connectionSuccess": "连接成功", - "connectionFailed": "连接失败", + "title": "设置", + "description": "管理您的账户设置和偏好", "language": "界面语言", "languageDescription": "选择界面显示语言", "theme": "主题", "themeLight": "浅色", "themeDark": "深色", "themeSystem": "跟随系统", - "title": "设置", - "description": "管理您的账户设置和偏好", - "backendPreference": "后端偏好", - "backendPreferenceDescription": "选择默认的 TTS 后端模式", - "localModel": "本地模型", - "localModelDescription": "免费使用本地 Qwen3-TTS 模型", - "localModelNoPermission": "请联系管理员开启使用本地模型权限", - "aliyunApi": "阿里云 API", - "aliyunApiDescription": "使用阿里云 TTS 服务", - "switchedToLocal": "已切换到本地模式", - "switchedToAliyun": "已切换到阿里云模式", - "saveFailed": "保存失败,请重试", - "apiKeyUpdated": "API 密钥已更新并验证成功", - "apiKeyVerifyFailed": "API 密钥验证失败", - "verifyFailed": "验证失败", - "currentStatus": "当前状态:", - "configured": "已配置并有效", - "notConfigured": "未配置", - "apiKey": "API 密钥", - "updating": "更新中...", - "addKey": "添加密钥", - "updateKey": "更新密钥", - "verifyKey": "验证密钥", - "deleteKey": "删除密钥", - "deleteKeyConfirm": "确定要删除阿里云 API 密钥吗?删除后将自动切换到本地模式。", - "keyDeleted": "API 密钥已删除,已切换到本地模式", - "deleteFailed": "删除失败", "accountInfo": "账户信息", "accountInfoDescription": "您的账户基本信息", "email": "邮箱", diff --git a/qwen3-tts-frontend/src/locales/zh-CN/tts.json b/qwen3-tts-frontend/src/locales/zh-CN/tts.json index 1767ad5..d00c850 100644 --- a/qwen3-tts-frontend/src/locales/zh-CN/tts.json +++ b/qwen3-tts-frontend/src/locales/zh-CN/tts.json @@ -22,7 +22,6 @@ "pauseAudio": "暂停", "backend": "后端服务", "localBackend": "本地模型", - "aliyunBackend": "阿里云API", "backendSwitched": "后端已切换", "backendError": "后端服务错误", "languageLabel": "语言", diff --git a/qwen3-tts-frontend/src/locales/zh-CN/voice.json b/qwen3-tts-frontend/src/locales/zh-CN/voice.json index d108bf0..be3361e 100644 --- a/qwen3-tts-frontend/src/locales/zh-CN/voice.json +++ b/qwen3-tts-frontend/src/locales/zh-CN/voice.json @@ -61,6 +61,5 @@ "deleteFailed": "删除失败", "deleteConfirmDesc": "确定要删除「{{name}}」吗?此操作不可撤销。", "local": "本地", - "aliyun": "阿里云", "deleting": "删除中..." } \ No newline at end of file diff --git a/qwen3-tts-frontend/src/locales/zh-TW/onboarding.json b/qwen3-tts-frontend/src/locales/zh-TW/onboarding.json index 9a5728f..72094ba 100644 --- a/qwen3-tts-frontend/src/locales/zh-TW/onboarding.json +++ b/qwen3-tts-frontend/src/locales/zh-TW/onboarding.json @@ -1,25 +1,12 @@ { "welcome": "歡迎使用 Qwen3 TTS", - "configureApiKey": "設定阿里雲 API 金鑰", - "selectBackendDescription": "請選擇您的 TTS 後端模式,後續可在設定中修改", - "enterApiKeyDescription": "請輸入您的阿里雲 API 金鑰,系統將驗證其有效性", "localModel": "本機模型", "localModelDescription": "免費使用本機 Qwen3-TTS 模型", "localModelNoPermission": "無本機模型權限,請聯絡管理員", - "aliyunApi": "阿里雲 API", - "aliyunApiRecommended": "(推薦)", - "aliyunApiDescription": "需要設定 API 金鑰,按量計費", "skipConfig": "跳過設定", - "nextStep": "下一步", "back": "返回", - "verifying": "驗證中...", - "verifyAndComplete": "驗證並完成", - "apiKey": "API 金鑰", - "howToGetApiKey": "如何取得 API 金鑰?", "skipSuccess": "已跳過設定,預設使用本機模式", "operationFailed": "操作失敗,請重試", "configComplete": "設定完成,預設使用本機模式", - "configCompleteAliyun": "設定完成,預設使用阿里雲模式", - "saveFailed": "儲存設定失敗,請重試", - "verifyFailed": "API 金鑰驗證失敗,請檢查後重試" + "saveFailed": "儲存設定失敗,請重試" } diff --git a/qwen3-tts-frontend/src/locales/zh-TW/settings.json b/qwen3-tts-frontend/src/locales/zh-TW/settings.json index b6dda4a..ef984bb 100644 --- a/qwen3-tts-frontend/src/locales/zh-TW/settings.json +++ b/qwen3-tts-frontend/src/locales/zh-TW/settings.json @@ -1,57 +1,12 @@ { - "settings": "設定", - "generalSettings": "一般設定", - "backendSettings": "後端設定", - "apiSettings": "API設定", - "preferencesSaved": "偏好設定已儲存", - "preferencesSaveFailed": "偏好設定儲存失敗", - "defaultBackend": "預設後端", - "local": "本機模型", - "aliyun": "阿里雲API", - "aliyunApiKey": "阿里雲 API 金鑰", - "apiKeyPlaceholder": "請輸入 API 金鑰", - "apiKeyDescription": "用於阿里雲 TTS 服務認證", - "saveApiKey": "儲存金鑰", - "apiKeySaved": "API 金鑰已儲存", - "apiKeySaveFailed": "API 金鑰儲存失敗", - "showApiKey": "顯示金鑰", - "hideApiKey": "隱藏金鑰", - "testConnection": "測試連線", - "connectionSuccess": "連線成功", - "connectionFailed": "連線失敗", + "title": "設定", + "description": "管理您的帳戶設定和偏好", "language": "介面語言", "languageDescription": "選擇介面顯示語言", "theme": "主題", "themeLight": "淺色", "themeDark": "深色", "themeSystem": "跟隨系統", - "title": "設定", - "description": "管理您的帳戶設定和偏好", - "backendPreference": "後端偏好", - "backendPreferenceDescription": "選擇預設的 TTS 後端模式", - "localModel": "本機模型", - "localModelDescription": "免費使用本機 Qwen3-TTS 模型", - "localModelNoPermission": "請聯絡管理員開啟使用本機模型權限", - "aliyunApi": "阿里雲 API", - "aliyunApiDescription": "使用阿里雲 TTS 服務", - "switchedToLocal": "已切換到本機模式", - "switchedToAliyun": "已切換到阿里雲模式", - "saveFailed": "儲存失敗,請重試", - "apiKeyUpdated": "API 金鑰已更新並驗證成功", - "apiKeyVerifyFailed": "API 金鑰驗證失敗", - "verifyFailed": "驗證失敗", - "currentStatus": "目前狀態:", - "configured": "已設定且有效", - "notConfigured": "未設定", - "apiKey": "API 金鑰", - "updating": "更新中...", - "addKey": "新增金鑰", - "updateKey": "更新金鑰", - "verifyKey": "驗證金鑰", - "deleteKey": "刪除金鑰", - "deleteKeyConfirm": "確定要刪除阿里雲 API 金鑰嗎?刪除後將自動切換到本機模式。", - "keyDeleted": "API 金鑰已刪除,已切換到本機模式", - "deleteFailed": "刪除失敗", "accountInfo": "帳戶資訊", "accountInfoDescription": "您的帳戶基本資訊", "email": "電子郵件", diff --git a/qwen3-tts-frontend/src/locales/zh-TW/tts.json b/qwen3-tts-frontend/src/locales/zh-TW/tts.json index 21968b7..39abe09 100644 --- a/qwen3-tts-frontend/src/locales/zh-TW/tts.json +++ b/qwen3-tts-frontend/src/locales/zh-TW/tts.json @@ -22,7 +22,6 @@ "pauseAudio": "暫停", "backend": "後端服務", "localBackend": "本機模型", - "aliyunBackend": "阿里雲API", "backendSwitched": "後端已切換", "backendError": "後端服務錯誤", "languageLabel": "語言", diff --git a/qwen3-tts-frontend/src/locales/zh-TW/voice.json b/qwen3-tts-frontend/src/locales/zh-TW/voice.json index 15f6fd6..84bea3b 100644 --- a/qwen3-tts-frontend/src/locales/zh-TW/voice.json +++ b/qwen3-tts-frontend/src/locales/zh-TW/voice.json @@ -61,6 +61,5 @@ "deleteFailed": "刪除失敗", "deleteConfirmDesc": "確定要刪除「{{name}}」嗎?此操作無法撤銷。", "local": "本地", - "aliyun": "阿里雲", "deleting": "刪除中..." } \ No newline at end of file diff --git a/qwen3-tts-frontend/src/pages/Audiobook.tsx b/qwen3-tts-frontend/src/pages/Audiobook.tsx index d543fe7..c421566 100644 --- a/qwen3-tts-frontend/src/pages/Audiobook.tsx +++ b/qwen3-tts-frontend/src/pages/Audiobook.tsx @@ -1145,7 +1145,7 @@ function CharactersPanel({ }) { const { t } = useTranslation('audiobook') const [editingCharId, setEditingCharId] = useState(null) - const [editFields, setEditFields] = useState({ name: '', gender: '', description: '', instruct: '', use_indextts2: false }) + const [editFields, setEditFields] = useState({ name: '', gender: '', description: '', instruct: '' }) const [regeneratingVoices, setRegeneratingVoices] = useState>(new Set()) const [voiceKeys, setVoiceKeys] = useState>({}) const status = project.status @@ -1157,21 +1157,25 @@ function CharactersPanel({ const startEditChar = (char: AudiobookCharacter) => { setEditingCharId(char.id) - setEditFields({ name: char.name, gender: char.gender || '', description: char.description || '', instruct: char.instruct || '', use_indextts2: char.use_indextts2 ?? false }) + setEditFields({ name: char.name, gender: char.gender || '', description: char.description || '', instruct: char.instruct || '' }) } const saveEditChar = async (char: AudiobookCharacter) => { try { - await audiobookApi.updateCharacter(project.id, char.id, { + const updated = await audiobookApi.updateCharacter(project.id, char.id, { name: editFields.name || char.name, gender: editFields.gender || undefined, description: editFields.description, instruct: editFields.instruct, - use_indextts2: editFields.use_indextts2, + }) setEditingCharId(null) await onFetchDetail() - toast.success(t('projectCard.characters.savedSuccess')) + if (updated.voice_design_id) { + handleRegeneratePreview(char.id) + } else { + toast.success(t('projectCard.characters.savedSuccess')) + } } catch (e: any) { toast.error(formatApiError(e)) } @@ -1264,8 +1268,8 @@ function CharactersPanel({ disabled={regeneratingVoices.size > 0} > {regeneratingVoices.size > 0 - ? <>{t('projectCard.characters.regeneratingPreview')} - : <>{t('projectCard.characters.regenerateAll')} + ? <>全部 + : <>全部 } )} @@ -1366,25 +1370,24 @@ function CharactersPanel({ {!editingCharId && char.voice_design_id && (
- + {regeneratingVoices.has(char.id) + ?
{t('projectCard.characters.regeneratingPreview')}
+ : + }
- {status === 'characters_ready' && ( + {status === 'characters_ready' && !regeneratingVoices.has(char.id) && ( )}
@@ -1623,25 +1626,22 @@ function ChaptersPanel({ {doneCount > 0 && } {detail!.chapters.some(c => ['pending', 'error', 'ready'].includes(c.status)) && !isBackgroundGenerating && ( )} {detail!.chapters.some(c => c.status === 'ready') && ( )} {detail!.chapters.some(c => ['pending', 'error'].includes(c.status)) && detail!.chapters.some(c => c.status === 'ready') && ( )} {isAIMode && onContinueScript && ( )}
diff --git a/qwen3-tts-frontend/src/pages/Settings.tsx b/qwen3-tts-frontend/src/pages/Settings.tsx index a6e06f2..d5c511a 100644 --- a/qwen3-tts-frontend/src/pages/Settings.tsx +++ b/qwen3-tts-frontend/src/pages/Settings.tsx @@ -1,40 +1,22 @@ import { useState, useEffect } from 'react' -import { useForm } from 'react-hook-form' -import { zodResolver } from '@hookform/resolvers/zod' -import * as z from 'zod' import { toast } from 'sonner' import { useTranslation } from 'react-i18next' -import { Eye, EyeOff, Trash2, Check, X, ShieldCheck } from 'lucide-react' +import { Trash2, ShieldCheck } from 'lucide-react' import { Navbar } from '@/components/Navbar' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' -import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form' import { ChangePasswordDialog } from '@/components/users/ChangePasswordDialog' import { useAuth } from '@/contexts/AuthContext' import { useUserPreferences } from '@/contexts/UserPreferencesContext' import { authApi, adminApi } from '@/lib/api' import type { PasswordChangeRequest } from '@/types/auth' -const createApiKeySchema = (t: (key: string) => string) => z.object({ - api_key: z.string().min(1, t('auth:validation.apiKeyRequired')), -}) - export default function Settings() { const { t } = useTranslation(['settings', 'auth', 'user', 'common']) const { user } = useAuth() - const { preferences, hasAliyunKey, updatePreferences, refetchPreferences, isBackendAvailable } = useUserPreferences() - const [showApiKey, setShowApiKey] = useState(false) - const [isLoading, setIsLoading] = useState(false) + const { preferences } = useUserPreferences() const [showPasswordDialog, setShowPasswordDialog] = useState(false) const [isPasswordLoading, setIsPasswordLoading] = useState(false) const [llmBaseUrl, setLlmBaseUrl] = useState('') @@ -48,9 +30,6 @@ export default function Settings() { const [grokConfig, setGrokConfig] = useState<{ base_url?: string; model?: string; has_key: boolean } | null>(null) const [isGrokLoading, setIsGrokLoading] = useState(false) - const apiKeySchema = createApiKeySchema(t) - type ApiKeyFormValues = z.infer - useEffect(() => { if (user?.is_superuser) { adminApi.getLLMConfig().then(setLlmConfig).catch(() => {}) @@ -58,70 +37,6 @@ export default function Settings() { } }, [user?.is_superuser]) - const form = useForm({ - resolver: zodResolver(apiKeySchema), - defaultValues: { - api_key: '', - }, - }) - - const handleBackendChange = async (value: string) => { - try { - await updatePreferences({ default_backend: value as 'local' | 'aliyun' }) - toast.success(value === 'local' ? t('settings:switchedToLocal') : t('settings:switchedToAliyun')) - } catch (error) { - toast.error(t('settings:saveFailed')) - } - } - - const handleUpdateKey = async (data: ApiKeyFormValues) => { - try { - setIsLoading(true) - await adminApi.setAliyunKey(data.api_key) - await refetchPreferences() - form.reset() - toast.success(t('settings:apiKeyUpdated')) - } catch (error: any) { - toast.error(error.message || t('settings:apiKeyVerifyFailed')) - } finally { - setIsLoading(false) - } - } - - const handleVerifyKey = async () => { - try { - setIsLoading(true) - const result = await adminApi.verifyAliyunKey() - if (result.valid) { - toast.success(t('settings:apiKeySaved')) - } else { - toast.error(result.message || t('settings:apiKeyVerifyFailed')) - } - await refetchPreferences() - } catch (error: any) { - toast.error(error.message || t('settings:verifyFailed')) - } finally { - setIsLoading(false) - } - } - - const handleDeleteKey = async () => { - if (!confirm(t('settings:deleteKeyConfirm'))) { - return - } - - try { - setIsLoading(true) - await adminApi.deleteAliyunKey() - await refetchPreferences() - toast.success(t('settings:keyDeleted')) - } catch (error: any) { - toast.error(error.message || t('settings:deleteFailed')) - } finally { - setIsLoading(false) - } - } - const handleSaveLlmConfig = async () => { if (!llmBaseUrl || !llmApiKey || !llmModel) { toast.error('请填写完整的 LLM 配置') @@ -217,127 +132,6 @@ export default function Settings() {

{t('settings:description')}

- - - {t('settings:backendPreference')} - {t('settings:backendPreferenceDescription')} - - - -
- - -
-
- - -
-
-
-
- - - - - {t('settings:aliyunApiKey')} - {user.is_superuser && } - - - {user.is_superuser ? t('settings:apiKeyDescription') : '由管理员统一配置,所有用户共用'} - - - -
- {t('settings:currentStatus')} - {hasAliyunKey ? ( - - - {t('settings:configured')} - - ) : ( - - - {t('settings:notConfigured')} - - )} -
- - {user.is_superuser && ( -
- - ( - - {t('settings:apiKey')} - -
-
- - -
-
-
- -
- )} - /> -
- - {hasAliyunKey && ( - <> - - - - )} -
- - - )} -
-
- {user.is_superuser && ( diff --git a/qwen3-tts-frontend/src/types/auth.ts b/qwen3-tts-frontend/src/types/auth.ts index 4da78c3..88be073 100644 --- a/qwen3-tts-frontend/src/types/auth.ts +++ b/qwen3-tts-frontend/src/types/auth.ts @@ -33,7 +33,7 @@ export interface PasswordChangeRequest { } export interface UserPreferences { - default_backend: 'local' | 'aliyun' + default_backend: 'local' onboarding_completed: boolean available_backends?: string[] language?: 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP' | 'ko-KR' diff --git a/qwen3-tts-frontend/src/types/tts.ts b/qwen3-tts-frontend/src/types/tts.ts index 9428d40..c2391bd 100644 --- a/qwen3-tts-frontend/src/types/tts.ts +++ b/qwen3-tts-frontend/src/types/tts.ts @@ -59,6 +59,6 @@ export interface UnifiedSpeakerItem { source: SpeakerSource designId?: number instruct?: string - backendType?: 'local' | 'aliyun' + backendType?: 'local' hasRefAudio?: boolean } diff --git a/qwen3-tts-frontend/src/types/voice-design.ts b/qwen3-tts-frontend/src/types/voice-design.ts index ea58f30..59d2202 100644 --- a/qwen3-tts-frontend/src/types/voice-design.ts +++ b/qwen3-tts-frontend/src/types/voice-design.ts @@ -2,9 +2,7 @@ export interface VoiceDesign { id: number user_id: number name: string - backend_type: 'local' | 'aliyun' instruct: string - aliyun_voice_id?: string meta_data?: Record preview_text?: string ref_audio_path?: string @@ -16,8 +14,6 @@ export interface VoiceDesign { export interface VoiceDesignCreate { name: string instruct: string - backend_type: 'local' | 'aliyun' - aliyun_voice_id?: string meta_data?: Record preview_text?: string }