Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/vocametrix/_generated/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Auto-generated � do not edit. Run `python tasks.py regenerate` to update.
"""A client library for accessing Vocametrix API"""

""" A client library for accessing Vocametrix API """
from .client import AuthenticatedClient, Client

__all__ = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class PostAnalyzePhonemesLiveResponse200:
language (str | Unset): Echoed language code processed.
transcription (str | Unset): Space-separated sequence of detected phonemes (empty string if silence).
phoneme_count (float | Unset): Total number of phonemes detected.
phonemes (list[PostAnalyzePhonemesLiveResponse200PhonemesItem] | Unset): Array of the phoneme labels detected,
in order.
phonemes (list[PostAnalyzePhonemesLiveResponse200PhonemesItem] | Unset): Array of unique phoneme labels, in
order of first appearance (duplicates removed). Use `transcription` or `phoneme_timings` for the full sequence.
phoneme_timings (list[PostAnalyzePhonemesLiveResponse200PhonemeTimingsItem] | Unset): Array of `{ phoneme,
start, end, duration, confidence, second_phoneme, second_confidence }` — one entry per phoneme.
`second_phoneme`/`second_confidence` (French champion models only) is the runner-up at that phoneme's most
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class PostLanguageChatPronunciationBody:
Attributes:
message (str): REQUIRED. The learner's message in the target language.
language (str): REQUIRED. Target language being learned.
age_level (str): REQUIRED. Categorical age/level label.
age_level (str): REQUIRED. CEFR level of the learner (A1, A2, B1, B2, C1, C2).
topic (str): REQUIRED. Conversation topic.
native_language (str | Unset): Optional. The learner's native language code.
thread_id (str | Unset): Optional. Thread ID for multi-turn continuity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class PostLanguageChatVocabularyBody:
language (str): REQUIRED. Target language the user is learning (en-US, fr-FR, es-ES, de-DE, etc.)
native_language (str): REQUIRED. The user's native language code — used to localize vocabulary hints and
corrections
age_level (str): Age/level (child-beginner, teen-intermediate, adult-advanced, etc.)
age_level (str): CEFR level of the learner (A1, A2, B1, B2, C1, C2)
topic (str): Conversation topic (family, travel, food, work, hobbies, etc.)
thread_id (str | Unset): Optional thread ID to continue previous conversation
email (str | Unset): Optional user email for tracking
Expand Down
32 changes: 7 additions & 25 deletions tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ def test_stuttering_raises_on_timeout(tmp_path, client):


@respx.mock
def test_client_email_used_as_namespace_default(tmp_path):
"""email set at client level should appear in upload requests."""
def test_client_email_not_sent_in_uploads(tmp_path):
"""email is deprecated: a client-level email is no longer sent in upload requests."""
client = VocametrixClient(api_key="key", email="user@example.com")
wav = tmp_path / "vowel.wav"
wav.write_bytes(b"RIFF" + b"\x00" * 40)
Expand All @@ -221,11 +221,11 @@ def capture_assign(request):
client.avqi.calculate(sustained_vowel=str(wav))
client.close()

assert captured_email.get("value") == "user@example.com"
assert "value" not in captured_email


@respx.mock
def test_per_call_email_overrides_client_default(tmp_path):
def test_per_call_email_not_sent_in_uploads(tmp_path):
client = VocametrixClient(api_key="key", email="client@example.com")
wav = tmp_path / "vowel.wav"
wav.write_bytes(b"RIFF" + b"\x00" * 40)
Expand All @@ -248,7 +248,7 @@ def capture_assign(request):
client.dsi.calculate(sustained_vowel=str(wav), email="override@example.com")
client.close()

assert captured_email.get("value") == "override@example.com"
assert "value" not in captured_email


@pytest.mark.asyncio
Expand Down Expand Up @@ -315,7 +315,7 @@ def test_transcription_event_importable_from_top_level():


@respx.mock
def test_default_email_is_info_vocametrix(tmp_path):
def test_default_client_sends_no_email(tmp_path):
wav = tmp_path / "v.wav"
wav.write_bytes(b"RIFF" + b"\x00" * 40)
captured = {}
Expand All @@ -335,7 +335,7 @@ def capture(request):
with VocametrixClient(api_key="key") as c:
c.avqi.calculate(sustained_vowel=str(wav))

assert captured.get("email") == "info@vocametrix.com"
assert "email" not in captured



Expand Down Expand Up @@ -427,12 +427,6 @@ def test_client_has_ai_agents_namespace():
assert hasattr(c.ai_agents, "interpret_metrics")


def test_client_has_speech_coaching_namespace():
with VocametrixClient(api_key="key") as c:
assert hasattr(c, "speech_coaching")
assert hasattr(c.speech_coaching, "analyze")
assert hasattr(c.speech_coaching, "analyze_batch")
assert hasattr(c.speech_coaching, "get_batch_result")


@respx.mock
Expand All @@ -447,15 +441,3 @@ def test_ai_agents_therapy_plan():
)
assert result["recommendation"] == "rest your voice"


@respx.mock
def test_speech_coaching_analyze():
respx.post(f"{BASE}/api/coaching-analysis").mock(
return_value=httpx.Response(200, json={"score": 87.5})
)
with VocametrixClient(api_key="key") as c:
result = c.speech_coaching.analyze(
reference_audio_url="https://cdn.example.com/ref.wav",
learner_audio_url="https://cdn.example.com/learner.wav",
)
assert result["score"] == 87.5