Simplify editor cleanup and keep live ASR metadata
Some checks are pending
ci / test-and-build (push) Waiting to run
Some checks are pending
ci / test-and-build (push) Waiting to run
Keep the daemon path on the full ASR result so word timings and detected language survive into the editor pipeline instead of falling back to a plain transcript string. Add PipelineEngine.run_asr_result(), have aman call it when live ASR data is available, and cover the word-aware alignment behavior in the daemon tests. Collapse the llama cleanup flow to a single JSON-shaped completion while leaving the legacy pass1/pass2 parameters in place as compatibility no-ops. Validated with PYTHONPATH=src python3 -m unittest tests.test_aiprocess tests.test_aman.
This commit is contained in:
parent
8c1f7c1e13
commit
fa91f313c4
5 changed files with 166 additions and 84 deletions
|
|
@ -186,6 +186,29 @@ class LlamaWarmupTests(unittest.TestCase):
|
|||
with self.assertRaisesRegex(RuntimeError, "expected JSON"):
|
||||
processor.warmup(profile="default")
|
||||
|
||||
def test_process_with_metrics_uses_single_completion_timing_shape(self):
|
||||
processor = object.__new__(LlamaProcessor)
|
||||
client = _WarmupClient(
|
||||
{"choices": [{"message": {"content": '{"cleaned_text":"friday"}'}}]}
|
||||
)
|
||||
processor.client = client
|
||||
|
||||
cleaned_text, timings = processor.process_with_metrics(
|
||||
"thursday, I mean friday",
|
||||
lang="en",
|
||||
dictionary_context="",
|
||||
profile="default",
|
||||
)
|
||||
|
||||
self.assertEqual(cleaned_text, "friday")
|
||||
self.assertEqual(len(client.calls), 1)
|
||||
call = client.calls[0]
|
||||
self.assertEqual(call["messages"][0]["content"], aiprocess.SYSTEM_PROMPT)
|
||||
self.assertIn('{"cleaned_text":"..."}', call["messages"][1]["content"])
|
||||
self.assertEqual(timings.pass1_ms, 0.0)
|
||||
self.assertGreater(timings.pass2_ms, 0.0)
|
||||
self.assertEqual(timings.pass2_ms, timings.total_ms)
|
||||
|
||||
|
||||
class ModelChecksumTests(unittest.TestCase):
|
||||
def test_accepts_expected_checksum_case_insensitive(self):
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ if str(SRC) not in sys.path:
|
|||
|
||||
import aman
|
||||
from config import Config, VocabularyReplacement
|
||||
from stages.asr_whisper import AsrResult, AsrSegment, AsrWord
|
||||
|
||||
|
||||
class FakeDesktop:
|
||||
|
|
@ -144,6 +145,21 @@ class FakeStream:
|
|||
self.close_calls += 1
|
||||
|
||||
|
||||
def _asr_result(text: str, words: list[str], *, language: str = "auto") -> AsrResult:
|
||||
asr_words: list[AsrWord] = []
|
||||
start = 0.0
|
||||
for token in words:
|
||||
asr_words.append(AsrWord(text=token, start_s=start, end_s=start + 0.1, prob=0.9))
|
||||
start += 0.2
|
||||
return AsrResult(
|
||||
raw_text=text,
|
||||
language=language,
|
||||
latency_ms=5.0,
|
||||
words=asr_words,
|
||||
segments=[AsrSegment(text=text, start_s=0.0, end_s=max(start, 0.1))],
|
||||
)
|
||||
|
||||
|
||||
class DaemonTests(unittest.TestCase):
|
||||
def _config(self) -> Config:
|
||||
cfg = Config()
|
||||
|
|
@ -248,6 +264,53 @@ class DaemonTests(unittest.TestCase):
|
|||
self.assertEqual(desktop.inject_calls, [])
|
||||
self.assertEqual(daemon.get_state(), aman.State.IDLE)
|
||||
|
||||
@patch("aman.stop_audio_recording", return_value=FakeAudio(8))
|
||||
@patch("aman.start_audio_recording", return_value=(object(), object()))
|
||||
def test_live_path_uses_asr_words_for_alignment_correction(self, _start_mock, _stop_mock):
|
||||
desktop = FakeDesktop()
|
||||
ai_processor = FakeAIProcessor()
|
||||
daemon = self._build_daemon(desktop, FakeModel(), verbose=False, ai_processor=ai_processor)
|
||||
daemon.asr_stage.transcribe = lambda _audio: _asr_result(
|
||||
"set alarm for 6 i mean 7",
|
||||
["set", "alarm", "for", "6", "i", "mean", "7"],
|
||||
language="en",
|
||||
)
|
||||
daemon._start_stop_worker = (
|
||||
lambda stream, record, trigger, process_audio: daemon._stop_and_process(
|
||||
stream, record, trigger, process_audio
|
||||
)
|
||||
)
|
||||
|
||||
daemon.toggle()
|
||||
daemon.toggle()
|
||||
|
||||
self.assertEqual(desktop.inject_calls, [("set alarm for 7", "clipboard", False)])
|
||||
self.assertEqual(ai_processor.last_kwargs.get("lang"), "en")
|
||||
|
||||
@patch("aman.stop_audio_recording", return_value=FakeAudio(8))
|
||||
@patch("aman.start_audio_recording", return_value=(object(), object()))
|
||||
def test_live_path_calls_word_aware_pipeline_entrypoint(self, _start_mock, _stop_mock):
|
||||
desktop = FakeDesktop()
|
||||
daemon = self._build_daemon(desktop, FakeModel(), verbose=False)
|
||||
asr_result = _asr_result(
|
||||
"set alarm for 6 i mean 7",
|
||||
["set", "alarm", "for", "6", "i", "mean", "7"],
|
||||
language="en",
|
||||
)
|
||||
daemon.asr_stage.transcribe = lambda _audio: asr_result
|
||||
daemon._start_stop_worker = (
|
||||
lambda stream, record, trigger, process_audio: daemon._stop_and_process(
|
||||
stream, record, trigger, process_audio
|
||||
)
|
||||
)
|
||||
|
||||
with patch.object(daemon.pipeline, "run_asr_result", wraps=daemon.pipeline.run_asr_result) as run_asr:
|
||||
daemon.toggle()
|
||||
daemon.toggle()
|
||||
|
||||
run_asr.assert_called_once()
|
||||
self.assertIs(run_asr.call_args.args[0], asr_result)
|
||||
|
||||
def test_transcribe_skips_hints_when_model_does_not_support_them(self):
|
||||
desktop = FakeDesktop()
|
||||
model = FakeModel(text="hello")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue