Compare commits
2 Commits
2a87020b48
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
584543395c | ||
|
|
fb753ce1b1 |
@@ -6,5 +6,5 @@ MIMO_API_KEY=your_api_key_here
|
|||||||
|
|
||||||
# 以下为可选配置(有默认值)
|
# 以下为可选配置(有默认值)
|
||||||
# MIMO_API_ENDPOINT=https://api.xiaomimimo.com/v1/chat/completions
|
# MIMO_API_ENDPOINT=https://api.xiaomimimo.com/v1/chat/completions
|
||||||
# MIMO_TTS_MODEL=mimo-v2-audio-tts
|
# MIMO_TTS_MODEL=mimo-v2-tts
|
||||||
# MIMO_VOICE=mimo_default
|
# MIMO_VOICE=mimo_default
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ App 模板变量:`{{speakText}}`(文本)、`{{speakSpeed}}`(语速 5-50
|
|||||||
|------|------|--------|------|
|
|------|------|--------|------|
|
||||||
| `MIMO_API_KEY` | ✅ | - | MiMo TTS API Key |
|
| `MIMO_API_KEY` | ✅ | - | MiMo TTS API Key |
|
||||||
| `MIMO_API_ENDPOINT` | ❌ | `https://api.xiaomimimo.com/v1/chat/completions` | API 地址 |
|
| `MIMO_API_ENDPOINT` | ❌ | `https://api.xiaomimimo.com/v1/chat/completions` | API 地址 |
|
||||||
| `MIMO_TTS_MODEL` | ❌ | `mimo-v2-audio-tts` | 模型名称 |
|
| `MIMO_TTS_MODEL` | ❌ | `mimo-v2-tts` | 模型名称 |
|
||||||
| `MIMO_VOICE` | ❌ | `mimo_default` | 默认音色 |
|
| `MIMO_VOICE` | ❌ | `mimo_default` | 默认音色 |
|
||||||
| `API_TOKEN` | ❌ | - | 管理接口 Bearer Token(留空则不鉴权) |
|
| `API_TOKEN` | ❌ | - | 管理接口 Bearer Token(留空则不鉴权) |
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ MIMO_API_ENDPOINT = os.environ.get(
|
|||||||
"MIMO_API_ENDPOINT", "https://api.xiaomimimo.com/v1/chat/completions"
|
"MIMO_API_ENDPOINT", "https://api.xiaomimimo.com/v1/chat/completions"
|
||||||
)
|
)
|
||||||
MIMO_API_KEY = os.environ.get("MIMO_API_KEY", "")
|
MIMO_API_KEY = os.environ.get("MIMO_API_KEY", "")
|
||||||
MIMO_TTS_MODEL = os.environ.get("MIMO_TTS_MODEL", "mimo-v2-audio-tts")
|
MIMO_TTS_MODEL = os.environ.get("MIMO_TTS_MODEL", "mimo-v2-tts")
|
||||||
MIMO_VOICE = os.environ.get("MIMO_VOICE", "mimo_default")
|
MIMO_VOICE = os.environ.get("MIMO_VOICE", "mimo_default")
|
||||||
|
|
||||||
# 服务器配置
|
# 服务器配置
|
||||||
|
|||||||
16
app/main.py
16
app/main.py
@@ -25,10 +25,12 @@ import config
|
|||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
format="%(asctime)s %(message)s",
|
||||||
datefmt="%Y-%m-%d %H:%M:%S",
|
datefmt="%H:%M:%S",
|
||||||
)
|
)
|
||||||
logger = logging.getLogger("tts-proxy")
|
logger = logging.getLogger("tts")
|
||||||
|
# 静默 httpx 内部日志
|
||||||
|
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||||
|
|
||||||
# ── Text Segmentation ─────────────────────────────────────────────────────
|
# ── Text Segmentation ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -152,7 +154,7 @@ async def call_mimo_tts(text: str, style: str = "", voice: str = "") -> bytes:
|
|||||||
elapsed = round(time.time() - t0, 2)
|
elapsed = round(time.time() - t0, 2)
|
||||||
|
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
logger.error(f"MiMo TTS HTTP {resp.status_code}, {elapsed}s, {resp.text[:200]}")
|
logger.error(f"TTS FAIL http={resp.status_code} {elapsed}s")
|
||||||
err = HTTPException(502, f"MiMo TTS API 错误: HTTP {resp.status_code}")
|
err = HTTPException(502, f"MiMo TTS API 错误: HTTP {resp.status_code}")
|
||||||
if resp.status_code >= 500 and attempt < MAX_TTS_RETRIES:
|
if resp.status_code >= 500 and attempt < MAX_TTS_RETRIES:
|
||||||
last_exc = err
|
last_exc = err
|
||||||
@@ -166,14 +168,14 @@ async def call_mimo_tts(text: str, style: str = "", voice: str = "") -> bytes:
|
|||||||
|
|
||||||
audio_b64 = data["choices"][0]["message"]["audio"]["data"]
|
audio_b64 = data["choices"][0]["message"]["audio"]["data"]
|
||||||
wav_bytes = base64.b64decode(audio_b64)
|
wav_bytes = base64.b64decode(audio_b64)
|
||||||
logger.info(f"MiMo TTS OK: {len(wav_bytes)} bytes, {elapsed}s (attempt {attempt})")
|
logger.info(f"TTS OK {len(wav_bytes)//1024}KB {elapsed}s")
|
||||||
return wav_bytes
|
return wav_bytes
|
||||||
|
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
elapsed = round(time.time() - t0, 2)
|
elapsed = round(time.time() - t0, 2)
|
||||||
logger.error(f"MiMo TTS 异常: {e}, {elapsed}s, attempt {attempt}")
|
logger.error(f"TTS ERR {e} {elapsed}s")
|
||||||
last_exc = HTTPException(502, f"MiMo TTS 异常: {e}")
|
last_exc = HTTPException(502, f"MiMo TTS 异常: {e}")
|
||||||
if attempt < MAX_TTS_RETRIES:
|
if attempt < MAX_TTS_RETRIES:
|
||||||
await asyncio.sleep(1.5 * attempt)
|
await asyncio.sleep(1.5 * attempt)
|
||||||
@@ -205,7 +207,7 @@ async def generate_mp3(text: str, style: str = "", voice: str = "") -> bytes:
|
|||||||
return mp3_bytes
|
return mp3_bytes
|
||||||
|
|
||||||
# 多段
|
# 多段
|
||||||
logger.info(f"文本 {len(text)} 字, 分 {len(chunks)} 段生成")
|
logger.info(f"SPLIT {len(text)}字 → {len(chunks)}段")
|
||||||
mp3_paths = []
|
mp3_paths = []
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
wav_bytes = await call_mimo_tts(chunk, style, voice)
|
wav_bytes = await call_mimo_tts(chunk, style, voice)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- MIMO_API_KEY=${MIMO_API_KEY}
|
- MIMO_API_KEY=${MIMO_API_KEY}
|
||||||
- MIMO_API_ENDPOINT=${MIMO_API_ENDPOINT:-https://api.xiaomimimo.com/v1/chat/completions}
|
- MIMO_API_ENDPOINT=${MIMO_API_ENDPOINT:-https://api.xiaomimimo.com/v1/chat/completions}
|
||||||
- MIMO_TTS_MODEL=${MIMO_TTS_MODEL:-mimo-v2-audio-tts}
|
- MIMO_TTS_MODEL=${MIMO_TTS_MODEL:-mimo-v2-tts}
|
||||||
- MIMO_VOICE=${MIMO_VOICE:-mimo_default}
|
- MIMO_VOICE=${MIMO_VOICE:-mimo_default}
|
||||||
- API_TOKEN=${API_TOKEN:-}
|
- API_TOKEN=${API_TOKEN:-}
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
Reference in New Issue
Block a user