Files
xiaoxia-saas/scripts/seed_test_voice_clones.py
xiaoxia 2f26541188
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m16s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m36s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m26s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m17s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 3m46s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m9s
CI/CD Pipeline / Integration Tests (push) Successful in 1m52s
CI/CD Pipeline / Unit Tests (push) Successful in 8m39s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 12m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 31s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 40s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 45s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m1s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
fix: 修复预置音色voice_id并填充preview_url (#1216)
2026-08-02 08:55:14 +08:00

181 lines
5.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""Seed test voice clone profiles for staging E2E testing.
Usage:
# On staging (inside Docker container):
docker exec -it staging-api python scripts/seed_test_voice_clones.py
# Locally (requires DATABASE_URL env):
DATABASE_URL=postgresql+psycopg://... python scripts/seed_test_voice_clones.py
Creates test VoiceCloneProfile records for known staging test accounts,
so that the frontend E2E tests can verify clone voice list and preview.
"""
from __future__ import annotations
import logging
import os
import sys
from datetime import datetime, timezone
from uuid import uuid4
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
# Test accounts and their seed data
SEED_DATA = [
{
"email": "18314979086@163.com",
"clones": [
{
"name": "测试音色-温柔女声",
"description": "用于E2E测试的克隆音色(温柔女声)",
"voice_id": "longxiaochun_v3",
"gender": "female",
"language": "zh-CN",
},
{
"name": "测试音色-磁性男声",
"description": "用于E2E测试的克隆音色(磁性男声)",
"voice_id": "longsanshu_v3",
"gender": "male",
"language": "zh-CN",
},
],
},
]
def get_db_session():
"""Create a SQLAlchemy session from environment."""
try:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
database_url = os.environ.get("DATABASE_URL", "")
if not database_url:
# Try loading from shared config
try:
from packages.shared.config import get_shared_settings
settings = get_shared_settings()
database_url = settings.effective_database_url
except Exception:
logger.error("DATABASE_URL not set and could not load from config")
sys.exit(1)
engine = create_engine(database_url)
Session = sessionmaker(bind=engine)
return Session()
except ImportError:
logger.error("sqlalchemy not installed")
sys.exit(1)
def find_user(session, email: str) -> dict | None:
"""Find user by email."""
from sqlalchemy import text
result = session.execute(text("SELECT id, email, display_name FROM users WHERE email = :email"), {"email": email})
row = result.fetchone()
if row:
return {"id": row[0], "email": row[1], "display_name": row[2]}
return None
def clone_exists(session, user_id: str, name: str) -> bool:
"""Check if a clone profile with this name already exists for the user."""
from sqlalchemy import text
result = session.execute(
text("SELECT COUNT(*) FROM voice_clone_profiles WHERE user_id = :uid AND name = :name AND status != 'deleted'"),
{"uid": user_id, "name": name},
)
return result.scalar() > 0
def create_clone_profile(session, user_id: str, clone_data: dict) -> str:
"""Create a VoiceCloneProfile record."""
from sqlalchemy import text
profile_id = uuid4().hex
now = datetime.now(timezone.utc)
session.execute(
text("""
INSERT INTO voice_clone_profiles
(id, user_id, name, description, source_audio_url, voice_id,
voice_model, language, gender, status, error_message,
retry_count, max_retries, metadata, created_at, updated_at)
VALUES
(:id, :uid, :name, :desc, :audio_url, :voice_id,
:voice_model, :lang, :gender, :status, '',
0, 3, '{}', :now, :now)
"""),
{
"id": profile_id,
"uid": user_id,
"name": clone_data["name"],
"desc": clone_data.get("description", ""),
"audio_url": "",
"voice_id": clone_data["voice_id"],
"voice_model": "cosyvoice-v3-flash",
"lang": clone_data.get("language", "zh-CN"),
"gender": clone_data.get("gender", "unknown"),
"status": "ready",
"now": now,
},
)
return profile_id
def main():
logger.info("=== Seed Test Voice Clones ===")
session = get_db_session()
total_created = 0
total_skipped = 0
for account in SEED_DATA:
email = account["email"]
user = find_user(session, email)
if not user:
logger.warning("User not found: %s — skipping", email)
continue
logger.info("Found user: %s (id=%s, name=%s)", email, user["id"], user["display_name"])
for clone_data in account.get("clones", []):
name = clone_data["name"]
if clone_exists(session, user["id"], name):
logger.info(" Clone '%s' already exists — skipping", name)
total_skipped += 1
continue
try:
profile_id = create_clone_profile(session, user["id"], clone_data)
logger.info(" Created clone '%s' (id=%s, voice_id=%s)", name, profile_id, clone_data["voice_id"])
total_created += 1
except Exception as e:
logger.error(" Failed to create clone '%s': %s", name, e)
session.rollback()
continue
try:
session.commit()
logger.info("=== Done: %d created, %d skipped ===", total_created, total_skipped)
except Exception as e:
logger.error("Failed to commit: %s", e)
session.rollback()
sys.exit(1)
finally:
session.close()
if __name__ == "__main__":
main()