1
0
forked from erp-dev/erp
Files
erpnew/flower/utils/speech.py
2026-07-01 11:51:13 +08:00

74 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""语音播报工具。"""
from __future__ import annotations
import json
from dataclasses import dataclass
from typing import Any
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
from django.conf import settings
@dataclass(frozen=True)
class SpeakResponse:
status_code: int
raw: Any
def play_speech(
*,
text: str,
endpoint: str | None = None,
timeout_seconds: float = 10.0,
) -> SpeakResponse:
"""调用语音播报服务。
默认 endpoint 读取 settings.SPEAK_ENDPOINT。
请求格式POST JSON {'text': '<text>'}
"""
content = (text or '').strip()
if not content:
raise ValueError('text 不能为空')
if not getattr(settings, 'SPEECH_ENABLED', True):
return SpeakResponse(status_code=0, raw={'status': 'disabled'})
url = (endpoint or getattr(settings, 'SPEAK_ENDPOINT', '') or '').strip()
if not url:
raise ValueError('SPEAK_ENDPOINT 未配置')
payload = {'text': content}
data = json.dumps(payload, ensure_ascii=False).encode('utf-8')
headers = {'Content-Type': 'application/json'}
api_key = (getattr(settings, 'SPEAK_API_KEY', '') or '').strip()
if api_key:
headers['X-Api-Key'] = api_key
req = Request(
url=url,
data=data,
headers=headers,
method='POST',
)
try:
with urlopen(req, timeout=float(timeout_seconds)) as resp:
body = resp.read().decode('utf-8', errors='replace')
status_code = int(getattr(resp, 'status', 200) or 200)
except HTTPError as exc:
body = ''
try:
body = exc.read().decode('utf-8', errors='replace')
except Exception:
pass
raise RuntimeError(f'Speak service HTTPError: status={exc.code}, body={body}') from exc
except URLError as exc:
raise RuntimeError(f'Speak service URLError: {exc}') from exc
try:
raw = json.loads(body) if body else {}
except Exception:
raw = {'raw_text': body}
return SpeakResponse(status_code=status_code, raw=raw)