Files
john 05e173b293 Ship native iOS app, Wiki/TTS backend, and skeleton loading UX.
Replace the WebView shell with SwiftUI screens, add account-scoped Wiki and TTS APIs with adaptive review and photo scan support, and keep web/iOS pages usable while data loads asynchronously.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 15:13:59 +08:00

116 lines
5.0 KiB
Python
Raw Permalink 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.
import base64
import json
import os
import tempfile
import unittest
from unittest.mock import MagicMock, patch
from services.tts_service import TtsService, TtsServiceError, tts_service
class _FakeResponse:
def __init__(self, body: bytes, content_type: str = "application/json"):
self._body = body
self.headers = MagicMock()
self.headers.get_content_type.return_value = content_type
def read(self):
return self._body
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
class TtsServiceTest(unittest.TestCase):
def tearDown(self):
get_settings = __import__("config", fromlist=["get_settings"]).get_settings
get_settings.cache_clear()
def test_not_configured_when_disabled(self):
with patch.dict(
os.environ,
{"TKMIND_TTS_ENABLED": "false", "TKMIND_TTS_BASE_URL": "http://127.0.0.1:19200"},
clear=False,
):
__import__("config", fromlist=["get_settings"]).get_settings.cache_clear()
self.assertFalse(tts_service.is_configured())
@patch("services.tts_service._open_tts_request")
def test_request_includes_user_agent(self, urlopen_mock: MagicMock):
wav = b"RIFFxxxx"
payload = {"code": 0, "data": base64.b64encode(wav).decode("ascii")}
urlopen_mock.return_value = _FakeResponse(json.dumps(payload).encode("utf-8"))
with patch.dict(
os.environ,
{"TKMIND_TTS_BASE_URL": "https://asr.tkmind.cn", "TKMIND_TTS_ENABLED": "true"},
clear=False,
):
__import__("config", fromlist=["get_settings"]).get_settings.cache_clear()
with tempfile.TemporaryDirectory() as tmp:
with patch("services.tts_service._CACHE_DIR", __import__("pathlib").Path(tmp)):
tts_service.synthesize("apple")
request = urlopen_mock.call_args.args[0]
self.assertEqual(request.get_header("User-agent"), "WordLoop-TTS/1.0")
@patch("services.tts_service._open_tts_request")
def test_synthesize_parses_json_base64(self, urlopen_mock: MagicMock):
wav = b"RIFFxxxx"
payload = {"code": 0, "message": "ok", "data": base64.b64encode(wav).decode("ascii")}
urlopen_mock.return_value = _FakeResponse(json.dumps(payload).encode("utf-8"))
with patch.dict(
os.environ,
{"TKMIND_TTS_BASE_URL": "http://127.0.0.1:19200", "TKMIND_TTS_ENABLED": "true"},
clear=False,
):
__import__("config", fromlist=["get_settings"]).get_settings.cache_clear()
with tempfile.TemporaryDirectory() as tmp:
with patch("services.tts_service._CACHE_DIR", __import__("pathlib").Path(tmp)):
audio, content_type = tts_service.synthesize("apple")
self.assertEqual(audio, wav)
self.assertEqual(content_type, "audio/wav")
@patch("services.tts_service._open_tts_request")
def test_synthesize_uses_cache_on_second_call(self, urlopen_mock: MagicMock):
wav = b"RIFFcached"
payload = {"code": 0, "data": base64.b64encode(wav).decode("ascii")}
urlopen_mock.return_value = _FakeResponse(json.dumps(payload).encode("utf-8"))
with patch.dict(
os.environ,
{"TKMIND_TTS_BASE_URL": "http://127.0.0.1:19200", "TKMIND_TTS_ENABLED": "true"},
clear=False,
):
__import__("config", fromlist=["get_settings"]).get_settings.cache_clear()
with tempfile.TemporaryDirectory() as tmp:
with patch("services.tts_service._CACHE_DIR", __import__("pathlib").Path(tmp)):
first, _ = tts_service.synthesize("apple")
second, _ = tts_service.synthesize("apple")
self.assertEqual(first, second)
self.assertEqual(urlopen_mock.call_count, 1)
@patch("services.tts_service._open_tts_request")
def test_upstream_error_message(self, urlopen_mock: MagicMock):
payload = {"code": 500, "message": "TTS 未启用(ENABLE_TTS=false", "data": None}
urlopen_mock.return_value = _FakeResponse(json.dumps(payload).encode("utf-8"))
with patch.dict(
os.environ,
{"TKMIND_TTS_BASE_URL": "http://127.0.0.1:19200", "TKMIND_TTS_ENABLED": "true"},
clear=False,
):
__import__("config", fromlist=["get_settings"]).get_settings.cache_clear()
with tempfile.TemporaryDirectory() as tmp:
with patch("services.tts_service._CACHE_DIR", __import__("pathlib").Path(tmp)):
with self.assertRaises(TtsServiceError) as ctx:
tts_service.synthesize("apple")
self.assertIn("TTS 未启用", str(ctx.exception))
def test_extract_audio_base64_from_dict(self):
value = TtsService._extract_audio_base64({"audio": "abc"})
self.assertEqual(value, "abc")