File size: 4,787 Bytes
542c664 f7dfda2 aa9a7de 542c664 aa9a7de 542c664 aa9a7de 542c664 aa9a7de 542c664 f7dfda2 542c664 b473cde f7dfda2 7cc7551 d2734dc aa9a7de b234367 aa9a7de 9ae828b aa9a7de dc8ac69 9ae828b dc8ac69 aa9a7de d2734dc f7dfda2 aa9a7de 542c664 d73f8f9 9ae828b aa9a7de 9ae828b aa9a7de 542c664 aa9a7de f7dfda2 542c664 d2734dc f7dfda2 9ae828b d2734dc b473cde aa9a7de f7dfda2 aa9a7de f7dfda2 aa9a7de 69346ea b473cde aa9a7de |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
import builtins
import os
import shutil
import io
import time
import uvicorn
from fastapi import FastAPI, UploadFile, File, Form, HTTPException
from fastapi.responses import StreamingResponse
from huggingface_hub import snapshot_download
# 🔴 核心:在所有 import 之前,必须先劫持 input
builtins.input = lambda prompt="": "y"
# 适配 Space 路径,本地运行时请确保此目录存在
os.environ["GENIE_DATA_DIR"] = "/app/GenieData"
# 下载环境
if not os.path.exists("/app/GenieData/G2P"):
print("📦 Downloading GenieData Assets...")
snapshot_download(repo_id="High-Logic/Genie", allow_patterns=["GenieData/*"], local_dir="/app", local_dir_use_symlinks=False)
import genie_tts
app = FastAPI()
# 角色模型存放根目录
MODELS_ROOT = "/app/models"
os.makedirs(MODELS_ROOT, exist_ok=True)
# 默认设置(加载 models/base 和 models/god)
genie_tts.load_character("Base", "/app/models/base", "zh")
genie_tts.load_character("god", "/app/models/god", "zh")
# 记录每个角色的默认参考音频
REF_CACHE = {
"Base": {
"path": "/app/models/base/ref.wav",
"text": "琴是个称职的好团长。看到她认真工作的样子,就连我也忍不住想要多帮她一把。",
"lang": "zh"
},
"god": {
"path": "/app/models/god/ref.wav",
"text": "很多人的一生,写于纸上也不过几行,大多都是些无聊的故事啊。",
"lang": "zh"
}
}
@app.post("/load_model")
async def load_model(character_name: str = Form(...), model_path: str = Form(...), language: str = Form("zh")):
"""
动态加载新模型 API
model_path: 相对于 /app 的路径,例如 "models/my_character"
"""
full_path = os.path.join("/app", model_path)
if not os.path.exists(full_path):
raise HTTPException(status_code=404, detail=f"Model path not found: {full_path}")
try:
print(f"📦 Loading character: {character_name} from {full_path}")
genie_tts.load_character(character_name, full_path, language)
return {"status": "success", "message": f"Character '{character_name}' loaded."}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/upload_and_tts")
async def upload_and_tts(
character_name: str = Form("Default"),
prompt_text: str = Form(...),
text: str = Form(...),
language: str = Form("zh"),
file: UploadFile = File(...)
):
"""
上传临时参考音频并生成语音
"""
try:
ts = int(time.time() * 1000)
save_path = f"/tmp/ref_{ts}.wav"
os.makedirs("/tmp", exist_ok=True)
with open(save_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
print(f"🔥 [Custom] Using temp audio for {character_name}: {save_path}")
genie_tts.set_reference_audio(character_name, save_path, prompt_text, language)
out_path = f"/tmp/out_{ts}.wav"
genie_tts.tts(character_name, text, save_path=out_path, play=False)
def iterfile():
with open(out_path, "rb") as f:
yield from f
try:
os.remove(save_path)
os.remove(out_path)
except: pass
return StreamingResponse(iterfile(), media_type="audio/wav")
except Exception as e:
print(f"❌ Error in upload/tts: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/tts")
async def dynamic_tts(
text: str = Form(...),
character_name: str = Form("Default"),
prompt_text: str = Form(None),
prompt_lang: str = Form("zh"),
use_default_ref: bool = Form(True)
):
"""
通用 TTS 接口,支持切换已加载的角色
"""
try:
# 如果提供了 prompt_text 且不是用默认参考,则尝试更新该角色的参考(假设已经有 ref.wav 在该角色目录下)
# 这里为了简化,如果没传特定音频,就用 REF_CACHE 里的
ref_info = REF_CACHE.get(character_name, REF_CACHE["Default"])
# 允许通过 API 动态覆盖当前参考文本(不换音频文件)
final_text = prompt_text if prompt_text else ref_info["text"]
genie_tts.set_reference_audio(character_name, ref_info["path"], final_text, prompt_lang)
out_path = f"/tmp/out_dyn_{int(time.time())}.wav"
genie_tts.tts(character_name, text, save_path=out_path, play=False)
return StreamingResponse(open(out_path, "rb"), media_type="audio/wav")
except Exception as e:
print(f"❌ Error: {e}")
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)
|