test(backend): add comprehensive test coverage for backend modules

Added a new `.coveragerc` file configuring coverage thresholds and exclusions.
Included `pytest.ini` to enable coverage reporting for multiple backend modules (`main`, `llm`, `prompt`, `geoip`, `tts_asr`) with a 90 % fail‑under requirement and detailed HTML output.
Implemented a suite of unit tests:

* `test_geoip.py` – validates geo‑location lookup logic.
* `test_llm_extended.py` – tests LLm response extraction and Ollama interactions.
* `test_main_endpoints.py` – covers API endpoints for completions, OCR, and TTS.
* `test_prompt_extended.py` – verifies language sanitization, timestamp generation, and prompt building.
* `test_tts_asr_coverage.py` – checks device detection, cache clearing, and model loading under various environment configurations.
* `test_tts_asr_extended.py` – further tests TTS/ASR device selection and time‑outs.

Updated `backend/requirements.txt` to use newer, compatible packages, removed obsolete testing dependencies, and added `qwen-tts`.
Modified `backend/tts_asr.py` to work with the new `Qwen3TTSModel`, simplified imports, and adjusted device mapping logic.

Additionally, frontend changes added a new `TreeNodeItem` component, updated Markdown rendering, added TTS instruction fields, and reworked context menu handling.

No breaking changes were introduced.
This commit is contained in:
2026-04-07 23:38:23 +08:00
parent bece7be267
commit 2fdc996af9
19 changed files with 3420 additions and 2325 deletions

View File

@@ -117,14 +117,14 @@ export async function fetchSuggestion(prefix, suffix, languageId, signal, apiUrl
}
}
export async function fetchTTS(text, voice = 'af_bella', rate = 1.0, apiUrl = TTS_URL) {
export async function fetchTTS(text, instruct = '', apiUrl = TTS_URL) {
const res = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
},
body: JSON.stringify({ text, voice, rate, format: 'wav' }),
body: JSON.stringify({ text, instruct, speaker: 'Vivian', format: 'wav' }),
})
if (!res.ok) {