Use generated short id for llm asr tts

This commit is contained in:
Xin Wang
2026-02-12 19:05:50 +08:00
parent 14991af1bf
commit 28ca003662
6 changed files with 98 additions and 27 deletions

17
api/app/id_generator.py Normal file
View File

@@ -0,0 +1,17 @@
import uuid
from typing import Any, Type
from sqlalchemy.orm import Session
def short_id(prefix: str, size: int = 8) -> str:
return f"{prefix}_{uuid.uuid4().hex[:size]}"
def unique_short_id(prefix: str, db: Session, model_cls: Type[Any], size: int = 8) -> str:
for _ in range(10):
candidate = short_id(prefix, size=size)
exists = db.query(model_cls.id).filter(model_cls.id == candidate).first()
if not exists:
return candidate
raise RuntimeError(f"failed to generate unique id for {model_cls.__name__}")

View File

@@ -1,6 +1,5 @@
import os
import time
import uuid
from typing import List, Optional
import httpx
@@ -8,6 +7,7 @@ from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from sqlalchemy.orm import Session
from ..db import get_db
from ..id_generator import unique_short_id
from ..models import ASRModel
from ..schemas import (
ASRModelCreate, ASRModelUpdate, ASRModelOut,
@@ -72,7 +72,7 @@ def get_asr_model(id: str, db: Session = Depends(get_db)):
def create_asr_model(data: ASRModelCreate, db: Session = Depends(get_db)):
"""创建ASR模型"""
asr_model = ASRModel(
id=data.id or str(uuid.uuid4())[:8],
id=unique_short_id("asr", db, ASRModel),
user_id=1, # 默认用户
name=data.name,
vendor=data.vendor,

View File

@@ -1,12 +1,12 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List, Optional
import uuid
import httpx
import time
from datetime import datetime
from ..db import get_db
from ..id_generator import unique_short_id
from ..models import LLMModel
from ..schemas import (
LLMModelCreate, LLMModelUpdate, LLMModelOut,
@@ -53,7 +53,7 @@ def get_llm_model(id: str, db: Session = Depends(get_db)):
def create_llm_model(data: LLMModelCreate, db: Session = Depends(get_db)):
"""创建LLM模型"""
llm_model = LLMModel(
id=data.id or str(uuid.uuid4())[:8],
id=unique_short_id("llm", db, LLMModel),
user_id=1, # 默认用户
name=data.name,
vendor=data.vendor,

View File

@@ -1,6 +1,5 @@
import base64
import os
import uuid
from typing import Optional
import httpx
@@ -8,6 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from ..db import get_db
from ..id_generator import unique_short_id
from ..models import Voice
from ..schemas import VoiceCreate, VoiceOut, VoicePreviewRequest, VoicePreviewResponse, VoiceUpdate
@@ -78,7 +78,7 @@ def create_voice(data: VoiceCreate, db: Session = Depends(get_db)):
voice_key = raw_id if ":" in raw_id else f"{model}:{raw_id}"
voice = Voice(
id=data.id or str(uuid.uuid4())[:8],
id=unique_short_id("tts", db, Voice),
user_id=1,
name=data.name,
vendor=vendor,

View File

@@ -9,8 +9,29 @@ from contextlib import contextmanager
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from app.db import Base, engine, DATABASE_URL
from app.id_generator import short_id
from app.models import Voice, Assistant, KnowledgeBase, Workflow, LLMModel, ASRModel, KnowledgeDocument
VOICE_MODEL = "FunAudioLLM/CosyVoice2-0.5B"
SEED_VOICE_IDS = {
"alex": short_id("tts"),
"david": short_id("tts"),
"bella": short_id("tts"),
"claire": short_id("tts"),
}
SEED_LLM_IDS = {
"deepseek_chat": short_id("llm"),
"glm_4": short_id("llm"),
"embedding_3_small": short_id("llm"),
}
SEED_ASR_IDS = {
"sensevoice_small": short_id("asr"),
"telespeech_asr": short_id("asr"),
}
def ensure_db_dir():
"""确保 SQLite 数据目录存在。"""
@@ -105,15 +126,51 @@ def init_default_data():
# 参考: https://docs.siliconflow.cn/cn/api-reference/audio/create-speech
voices = [
# 男声 (Male Voices)
Voice(id="alex", name="Alex", vendor="OpenAI Compatible", gender="Male", language="en",
description="Steady male voice.", is_system=True),
Voice(id="david", name="David", vendor="OpenAI Compatible", gender="Male", language="en",
description="Cheerful male voice.", is_system=True),
Voice(
id=SEED_VOICE_IDS["alex"],
name="Alex",
vendor="OpenAI Compatible",
gender="Male",
language="en",
description="Steady male voice.",
model=VOICE_MODEL,
voice_key=f"{VOICE_MODEL}:alex",
is_system=True,
),
Voice(
id=SEED_VOICE_IDS["david"],
name="David",
vendor="OpenAI Compatible",
gender="Male",
language="en",
description="Cheerful male voice.",
model=VOICE_MODEL,
voice_key=f"{VOICE_MODEL}:david",
is_system=True,
),
# 女声 (Female Voices)
Voice(id="bella", name="Bella", vendor="OpenAI Compatible", gender="Female", language="en",
description="Passionate female voice.", is_system=True),
Voice(id="claire", name="Claire", vendor="OpenAI Compatible", gender="Female", language="en",
description="Gentle female voice.", is_system=True),
Voice(
id=SEED_VOICE_IDS["bella"],
name="Bella",
vendor="OpenAI Compatible",
gender="Female",
language="en",
description="Passionate female voice.",
model=VOICE_MODEL,
voice_key=f"{VOICE_MODEL}:bella",
is_system=True,
),
Voice(
id=SEED_VOICE_IDS["claire"],
name="Claire",
vendor="OpenAI Compatible",
gender="Female",
language="en",
description="Gentle female voice.",
model=VOICE_MODEL,
voice_key=f"{VOICE_MODEL}:claire",
is_system=True,
),
]
seed_if_empty(db, Voice, voices, "✅ 默认声音数据已初始化 (OpenAI Compatible CosyVoice 2.0)")
@@ -144,14 +201,14 @@ def init_default_assistants():
prompt="你是一个友好的AI助手请用简洁清晰的语言回答用户的问题。",
language="zh",
voice_output_enabled=True,
voice="anna",
voice=SEED_VOICE_IDS["bella"],
speed=1.0,
hotwords=[],
tools=["current_time"],
interruption_sensitivity=500,
config_mode="platform",
llm_model_id="deepseek-chat",
asr_model_id="paraformer-v2",
llm_model_id=SEED_LLM_IDS["deepseek_chat"],
asr_model_id=SEED_ASR_IDS["sensevoice_small"],
),
Assistant(
id="customer_service",
@@ -162,7 +219,7 @@ def init_default_assistants():
prompt="你是一个专业的客服人员,耐心解答客户问题,提供优质的服务体验。",
language="zh",
voice_output_enabled=True,
voice="bella",
voice=SEED_VOICE_IDS["claire"],
speed=1.0,
hotwords=["客服", "投诉", "咨询"],
tools=["current_time"],
@@ -178,7 +235,7 @@ def init_default_assistants():
prompt="You are a friendly English tutor. Help users practice English conversation and explain grammar points clearly.",
language="en",
voice_output_enabled=True,
voice="alex",
voice=SEED_VOICE_IDS["alex"],
speed=1.0,
hotwords=["grammar", "vocabulary", "practice"],
tools=["current_time"],
@@ -257,7 +314,7 @@ def init_default_llm_models():
with db_session() as db:
llm_models = [
LLMModel(
id="deepseek-chat",
id=SEED_LLM_IDS["deepseek_chat"],
user_id=1,
name="DeepSeek Chat",
vendor="OpenAI Compatible",
@@ -270,7 +327,7 @@ def init_default_llm_models():
enabled=True,
),
LLMModel(
id="glm-4",
id=SEED_LLM_IDS["glm_4"],
user_id=1,
name="GLM-4",
vendor="ZhipuAI",
@@ -283,7 +340,7 @@ def init_default_llm_models():
enabled=True,
),
LLMModel(
id="text-embedding-3-small",
id=SEED_LLM_IDS["embedding_3_small"],
user_id=1,
name="Embedding 3 Small",
vendor="OpenAI Compatible",
@@ -302,7 +359,7 @@ def init_default_asr_models():
with db_session() as db:
asr_models = [
ASRModel(
id="FunAudioLLM/SenseVoiceSmall",
id=SEED_ASR_IDS["sensevoice_small"],
user_id=1,
name="FunAudioLLM/SenseVoiceSmall",
vendor="OpenAI Compatible",
@@ -316,7 +373,7 @@ def init_default_asr_models():
enabled=True,
),
ASRModel(
id="TeleAI/TeleSpeechASR",
id=SEED_ASR_IDS["telespeech_asr"],
user_id=1,
name="TeleAI/TeleSpeechASR",
vendor="OpenAI Compatible",

View File

@@ -297,7 +297,6 @@ export const fetchVoices = async (): Promise<Voice[]> => {
export const createVoice = async (data: Partial<Voice>): Promise<Voice> => {
const payload = {
id: data.id || undefined,
name: data.name || 'New Voice',
vendor: data.vendor || 'OpenAI Compatible',
gender: data.gender || 'Female',
@@ -359,7 +358,6 @@ export const fetchASRModels = async (): Promise<ASRModel[]> => {
export const createASRModel = async (data: Partial<ASRModel>): Promise<ASRModel> => {
const payload = {
id: data.id || undefined,
name: data.name || 'New ASR Model',
vendor: data.vendor || 'OpenAI Compatible',
language: data.language || 'zh',
@@ -450,7 +448,6 @@ export const fetchLLMModels = async (): Promise<LLMModel[]> => {
export const createLLMModel = async (data: Partial<LLMModel>): Promise<LLMModel> => {
const payload = {
id: data.id || undefined,
name: data.name || 'New LLM Model',
vendor: data.vendor || 'OpenAI Compatible',
type: data.type || 'text',