6f84d90dff
Implements full speech-to-speech pipeline (all 4 phases): Backend (Phase 1): - services/stt.py: lazy WhisperModel singleton, run_in_executor transcription - services/tts.py: lazy KPipeline singleton, WAV synthesis at 24kHz/16-bit - routes/voice.py: /api/voice/status, /voices, /transcribe, /synthesise - config.py: VOICE_ENABLED, STT_BACKEND, STT_MODEL, TTS_BACKEND env vars - app.py: load STT/TTS models at startup when VOICE_ENABLED=true - llm.py: voice_mode + voice_speech_style params inject speak-naturally prefix - generation_task.py: voice_mode passed through from chat route - chat.py: "voice" conversation type allowed + excluded from retention cleanup - pyproject.toml + Dockerfile: faster-whisper, kokoro, soundfile dependencies Frontend (Phases 2–4): - composables/useVoiceRecorder.ts: MediaRecorder PTT wrapper - composables/useVoiceAudio.ts: AudioContext WAV playback wrapper - BriefingView.vue: Listen button (TTS read-aloud), auto-TTS mode, mic PTT - VoiceOverlay.vue: global floating PTT button; creates/reuses voice conv; full record→transcribe→stream→TTS flow; Space bar hold-to-talk via App.vue - SettingsView.vue: Voice tab (status badge, speech style, voice/speed) - App.vue: mounts VoiceOverlay; Space keydown/keyup fires voice:ptt-toggle - api/client.ts: getVoiceStatus, getVoiceList, transcribeAudio, synthesiseSpeech Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
58 lines
1.3 KiB
TOML
58 lines
1.3 KiB
TOML
[build-system]
|
|
requires = ["setuptools>=68.0", "setuptools-scm>=8.0"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[project]
|
|
name = "fabledassistant"
|
|
version = "0.1.0"
|
|
description = "Self-hosted note-taking and task-tracking app with LLM integration"
|
|
requires-python = ">=3.12"
|
|
dependencies = [
|
|
"quart>=0.19",
|
|
"sqlalchemy[asyncio]>=2.0",
|
|
"asyncpg>=0.29",
|
|
"alembic>=1.13",
|
|
"httpx>=0.27",
|
|
"hypercorn>=0.17",
|
|
"bcrypt>=4.0",
|
|
"aiosmtplib>=3.0",
|
|
"caldav>=1.3",
|
|
"icalendar>=5.0",
|
|
"feedparser>=6.0",
|
|
"APScheduler>=3.10,<4.0",
|
|
"pywebpush>=2.0",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"pytest>=8.0",
|
|
"pytest-asyncio>=0.23",
|
|
"ruff>=0.6",
|
|
]
|
|
voice = [
|
|
"faster-whisper>=1.0",
|
|
"kokoro>=0.9",
|
|
"soundfile>=0.12",
|
|
]
|
|
|
|
[tool.setuptools.packages.find]
|
|
where = ["src"]
|
|
|
|
[tool.pytest.ini_options]
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|
|
|
|
[tool.ruff]
|
|
line-length = 120
|
|
target-version = "py312"
|
|
|
|
[tool.ruff.lint]
|
|
# E = pycodestyle errors, F = pyflakes (catches unused imports, undefined names)
|
|
# Start conservative — add more rules as the codebase gains coverage.
|
|
select = ["E", "F"]
|
|
ignore = [
|
|
"E501", # line too long — long lines are acceptable in this codebase
|
|
"E402", # module-level import not at top — common in Quart app factories
|
|
"F401", # imported but unused — some re-exports are intentional
|
|
]
|