-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.example.yaml
More file actions
245 lines (228 loc) · 10.1 KB
/
Copy pathconfig.example.yaml
File metadata and controls
245 lines (228 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# Saymo config template. Copy this file to `config.yaml` (gitignored) and fill in
# your own values. All secrets use `${ENV_VAR}` — keep them in your shell or a
# .env, never commit keys here.
user:
# Your display name in prompts and turn-detection.
name: "Your Name"
# Any short forms / nicknames that colleagues use on the call.
name_variants:
- "Your Name"
# Optional — used by prompts that accept {user_role}, {team_name}, {tech_stack}.
role: "" # e.g. "Senior Engineer"
team: "" # e.g. "Platform"
tech_stack: "" # e.g. "Python, Kubernetes, Postgres"
language: ru # `ru` or `en`
audio:
capture_device: "BlackHole 16ch"
playback_device: "BlackHole 2ch"
monitor_device: "" # e.g. "External Headphones" — to hear yourself
recording_device: "" # mic used for voice-sample recording
sample_rate: 16000
channels: 1
chunk_size: 1024
# --- Mic input chain ---
# Run `saymo mic-check` to have Saymo measure your room + mic and print
# ready-to-paste values for these fields. Defaults below are no-op, so an
# un-calibrated install behaves identically to before the calibration
# feature was added.
input_gain_db: 0.0 # +3..+12 = louder; -3..-12 = quieter; 0 = off
noise_gate_db: -120.0 # frames below this RMS (dB) go silent; -120 disables
highpass_cutoff_hz: 0.0 # cuts rumble/hum; try 80 Hz for close-talk mics; 0 disables
noise_reduction: false # spectral denoise via `noisereduce` (soft dep, pip-installed)
noise_reduction_strength: 0.75 # 0..1 — higher = more aggressive, more artefacts
stt:
engine: whisper # `whisper` (local) or `deepgram` (cloud)
whisper:
model_size: small
device: cpu
compute_type: int8
deepgram:
api_key: ${DEEPGRAM_API_KEY}
model: nova-3
language: ru
diarization:
enabled: false # optional; disabled keeps base install lightweight
engine: disabled # `disabled` or `pyannote`
model: pyannote/speaker-diarization-3.1
device: cpu # cpu | mps | cuda, depending on backend support
min_speakers: 1
max_speakers: 4
auth_token_env: SAYMO_DIARIZATION_TOKEN # env var name, not the token value
meeting_memory:
enabled: true
retain_transcripts: true # false keeps metadata but blanks transcript text
base_dir: "" # defaults to ~/.saymo/trigger_samples/
default_window_seconds: 8.0
summary_max_items: 5
analysis:
llm_provider: ollama # `ollama` (local, default) or `anthropic` (cloud)
anthropic:
api_key: ${ANTHROPIC_API_KEY}
model: claude-sonnet-4-20250514
turn_detection:
keyword_trigger: true
llm_trigger: true
llm_interval_seconds: 5
confidence_threshold: 0.8
tts:
# Voice-cloning engines (primary — speak in the user's voice):
# `coqui_clone` — XTTS v2, zero-shot or fine-tuned
# `qwen3_clone` — Qwen3-TTS 12Hz with LoRA adapter (Apple Silicon)
# Fallback engines (do NOT sound like the user):
# `piper` — ~60 MB download, offline
# `macos_say` — built-in, zero install
engine: coqui_clone
# Optional override for the live auto-mode / Q&A path. When set, _auto()
# uses this engine for spontaneous replies while `engine` above keeps
# handling slower prepare-time synthesis. Typical split: prepare with
# coqui_clone (quality), realtime with qwen3_clone (latency). Empty
# means "use `engine` for both".
realtime_engine: ""
piper:
model_path: ""
macos_say:
voice: Milena
obsidian:
vault_path: "" # e.g. "~/Documents/Obsidian Vault"
subfolder: ""
date_format: "%Y-%m-%d"
ollama:
url: http://localhost:11434
model: qwen2.5-coder:7b
jira:
url: "" # e.g. https://your-company.atlassian.net
token: ${JIRA_TOKEN}
project_key: "" # e.g. "ABC" — scopes JQL queries to one project
user_query: "assignee = currentUser() AND updated >= -1d ORDER BY updated DESC"
worklog_query: "worklogAuthor = currentUser() AND worklogDate >= -10d"
max_results: 15
team_members: {} # Optional: {jira_username: Display Name} for team scrum report
speech:
style: concise
language: ru
source: obsidian # `obsidian` | `jira` | `confluence` | `file`
composer: ollama # `ollama` | `anthropic`
safety:
require_confirmation: true # require a second trigger mention before auto-speaking
confirmation_timeout_seconds: 6.0 # seconds to wait for that second mention
hotkey_speak: "<cmd>+<shift>+s" # force prepared playback in auto-mode
hotkey_stop: "<cmd>+<shift>+x"
hotkey_toggle: "<cmd>+<shift>+m"
hotkey_takeover: "<cmd>+<shift>+u" # manual answer mode: pause auto + best-effort mic switch
hotkey_approved_speak: "<cmd>+<shift>+a"
hotkey_skip: "<cmd>+<shift>+k"
hotkey_capture_marker: "<cmd>+<shift>+c"
hotkey_status: "<cmd>+<shift>+i"
hotkey_hard_disable: "<cmd>+<shift>+h"
max_speech_duration: 120
live:
# Runtime tuning for `saymo auto`. Meeting profiles can override these under
# `meetings.<name>.live` without editing source.
chunk_seconds: 4.0 # audio window sent to Whisper
overlap_seconds: 2.0 # overlap between adjacent windows
read_timeout_seconds: 3.0 # wait for the next captured chunk
trigger_cooldown_seconds: 45.0 # suppress duplicate name hits after answer
silence_rms_threshold: 0.001 # skip quiet windows before Whisper
pre_speak_delay_seconds: 2.0 # pause after trigger before playback
# Meeting profiles — each one picks a source plugin, a call provider, and the
# trigger phrases used by `saymo auto`. Add as many as you need.
meetings:
personal:
description: "Personal update — first-person brief"
provider: glip
team: false
source: obsidian
trigger_phrases:
- "Your Name"
# Optional addressing overrides for this profile. Patterns are regular
# expressions; use {trigger} where the matched trigger phrase should appear.
# addressing:
# handoff_patterns:
# - "\\bпусть\\s+{trigger}\\s+ответит\\b"
# mention_only_patterns:
# - "\\bэскалировали\\s+{trigger}\\b"
# Optional live tuning just for this profile:
# live:
# chunk_seconds: 3.0
# overlap_seconds: 1.0
# trigger_cooldown_seconds: 25.0
team:
description: "Team update — you + teammates"
provider: glip
team: true
source: obsidian
trigger_phrases:
- "Your Name"
- "your team"
# Prompt templates — overrides for the defaults in saymo/speech/ollama_composer.py.
# Placeholders are resolved at runtime; see module docstrings for the full list.
prompts:
# standup_ru: |
# Ты — помощник для ежедневных встреч. Составь отчёт на русском...
# Заметки за вчера ({yesterday_date}):
# ---
# {yesterday_notes}
# ---
# Заметки на сегодня ({today_date}):
# ---
# {today_notes}
# ---
# standup_en: |
# You are a speaking assistant. Compose a brief verbal update in English...
# team_scrum_ru: |
# Ты — помощник для командных митингов...
# autonomous_daily_ru: |
# Ты — автономный голосовой ассистент...
# qa_system_ru: |
# Ты — {user_name}, {user_role}...
# expand_ru: |
# Тебе дали заметки. Перепиши в устную речь...
# Project-specific vocabulary — merged on top of the default abbreviation map
# in saymo/tts/text_normalizer.py. Use this instead of editing source.
vocabulary:
abbreviations: {} # e.g. { MYAPI: "май-эй-пи-ай", K8S: "кубернетес" }
# Run `saymo trigger-check -p personal --mic` and add exact Whisper
# mis-hearings with `saymo trigger-setup -p personal --heard "..."`.
# It is safe to paste a whole transcript; Saymo saves only the name variant.
fuzzy_expansions: {} # e.g. { Alex: ["Alex", "Алекс", "Саша", "Саня"] }
# Tier-A response cache — pre-synthesised short answers for common stand-up
# follow-up questions. Lets real-time Q&A work on CPU-only machines: at
# runtime `_auto()` looks up a matching cached answer and plays it in ~100 ms
# instead of synthesising live. Defaults live in
# `saymo/analysis/response_cache.py::DEFAULT_RESPONSE_LIBRARY`. Entries under
# `library` extend or override those defaults — add your own intents or
# replace the wording of existing ones without touching source.
responses:
enabled: true
confidence_threshold: 0.6 # 0..1 — lower = more willing to match loose wording
cache_dir: "" # empty → ~/.saymo/audio_cache/responses/
# When cache misses a match, try synthesising a live answer via Ollama
# + TTS. Off by default because it's slow (several seconds) and can
# make auto-mode feel sluggish. Turn on only if you often get questions
# that aren't covered by cached variants.
live_fallback: false
# When true, runs a small Ollama classifier BEFORE the keyword match.
# Catches rephrasings the keyword matcher misses (e.g. "когда сдашь"
# → eta_generic). Adds ~1s latency; turn off if CPU-constrained.
intent_classifier: false
# Use `saymo trigger-check -p personal --text "Your Name, what is the status?"`
# to preview trigger/addressing/question/cache decisions before a call.
library: {}
# Example — uncomment to override the default generic status answer:
# status_generic:
# triggers:
# - "как дела"
# - "что по задаче"
# variants:
# - "В работе, детали скину в чат после митинга."
# description: "Generic status, my wording"
#
# Example — add a new intent that is not in the default library:
# release_today:
# triggers:
# - "когда релиз"
# - "когда выкатка"
# variants:
# - "Планирую выкатить сегодня после обеда."
# - "Релиз уезжает на стейдж до конца дня."
# description: "Project-specific release question"