feat(tts): report per-request metrics - #2260
Conversation
|
send_tts_request_final_marker() 是一个内部“结束信号”,用于通知 report_controller: |
Review:
|
Review:
|
Review:
|
Review:
|
|
Review: feat(tts): report per-request metrics Small, focused change — the version bumps are consistent across manifest.json and pyproject.toml, and the placement inside the existing request_tts flow is reasonable. A few things worth addressing before merge.
send_tts_request_metrics does not exist anywhere in this repo today — it comes from the unmerged TEN-framework/ten_ai_base#118. But manifest.json still pins ten_ai_base at version "0.7". If #118 ships the new method in a version outside the 0.7 range that resolves here, any deployment picking up rime_tts 0.4.11 with an older ten_ai_base fails at runtime with AttributeError on the first TTS request — and because the call sits inside request_tts, the broad
await self.send_tts_request_metrics(...)
await self.client.send_text(t)If send_text raises (ModuleVendorException on a dead WebSocket is handled explicitly a few lines below), a request has already been counted for text that never reached Rime. Moving the report after the awaited send makes the metric reflect work actually performed. If the intent is "attempted requests", that is a defensible choice — worth a short comment saying so.
self.metrics_add_output_characters(len(t.text)) # unguarded
if t.text:
await self.send_tts_request_metrics(..., output_characters=len(t.text))Two character counters that disagree on empty text. Since len("") == 0, the guard mostly just avoids a no-op event — fine, but guarding both or neither would keep the two reconcilable downstream. Related and more important: for a streaming request, request_tts is called once per text chunk with the same request_id, so one logical request emits N metrics events with N different request_time_ms values. Does the consumer sum output_characters per request_id, or treat each event as a distinct request? If the latter, request counts inflate by chunk count.
The file uses datetime throughout (self.request_start_ts = datetime.now()); this adds a second time module for one call. int(datetime.now().timestamp() * 1000) avoids the new import and matches local convention. Also worth deciding deliberately: the extension already records request_start_ts. If request_time_ms means when the request started, request_start_ts is the value you want — the current code reports per-chunk send time, which differs for every chunk after the first.
No test asserts the new event. tests/test_metrics.py already inspects the metrics data payload for nested ttfb, so extending it to assert a request-metrics event with the expected request_id and output_characters would be cheap — and would catch the dependency mismatch in item 1 at test time instead of at runtime. The PR notes only test_params.py was run. Since this touches the shared request_tts path, please also run test_metrics.py, test_state_machine.py, and test_basic.py against a ten_ai_base build containing #118.
Nine other TTS extensions call metrics_add_output_characters but none report request metrics. Until they do, dashboards built on this signal show rime only. If this is a deliberate pilot, a note in the PR body or a tracking issue for the remaining vendors would help. Summary: items 1 and 2 are worth fixing before merge; 3-6 are improvements. No security concerns — no secrets, no new network egress, no untrusted input handling. Commit message and branch name both follow the repo conventions. |
|
Review: feat(tts): report per-request metrics Small, focused diff, and the version bump is applied consistently to both manifest.json and pyproject.toml. Most of my feedback concerns merge ordering and the semantics of the new call rather than the mechanics of the change. 1. Blocking: the new API does not exist in this repo yet, and the failure mode is silent
Two things make that worse than a normal missing-dependency error:
Two recommendations, independent of each other and both worth doing:
2. Per-send vs per-request granularity The PR title says per-request metrics; the body says each WebSocket text send. Those are different, and the code implements the second. Rime is a streaming WS extension, so Worth confirming against the base API contract: if the downstream sink keys on 3. Full utterance text in the metrics pipeline
Please confirm the metrics sink has the same handling and retention expectations as logs. If it does not, consider truncating, hashing, or reporting character count only. This is a question rather than a defect claim, since the sink lives in ten_ai_base and I could not inspect it from here. 4. Time base
5. The The line immediately above, 6. Test coverage No tests accompany this change. The PR body reports
7. Conventions Commit and PR title follow the conventional-commits format correctly. The branch name The patch-level bump is defensible for internal telemetry, though this does add a new outbound emission. No Nothing here is hard to address. Item 1 is the one I would resolve before merge: the reordering is a two-line move, and the version constraint needs to reflect the dependency the code now has. |
ReviewTight, well-scoped change: one call site, version bumped consistently in both 1. Hard dependency on an unmerged change (blocking)
Consequence if this lands first: every 2. Metrics call sits in front of the audio send pathawait self.send_tts_request_metrics(...)
await self.client.send_text(t)Two effects from this ordering:
Suggest moving it after await self.client.send_text(t)
try:
await self.send_tts_request_metrics(...)
except Exception as e:
self.ten_env.log_warn(f"Failed to report TTS request metrics: {e}")Metrics should never be able to block audio. 3. Per-send vs per-request semanticsThe title says "per-request metrics" but the implementation is per-send. Is that intended? If the consumer counts requests or treats 4. Time source
5. Minor
6. Test coverageNo test accompanies the change. Nothing here is difficult to address — the ordering fix and a semantics decision on point 3 are the substantive ones. |
ReviewTight, well-scoped change — 7 lines of logic, version bumps in both Merge ordering (blocking)
The failure mode if this lands first is worth spelling out, because it is quiet rather than loud. The new Metrics failure can break synthesisRelated, and true even after #118 lands: this if t.text:
try:
await self.send_tts_request_metrics(...)
except Exception as e:
self.ten_env.log_warn(f"Failed to report TTS request metrics: {e}")Alternatively, guarantee non-raising in the base method — but the guard here is cheap and local. Per-send vs per-requestThe title says "per-request metrics" but the implementation reports per send. The description ("report each Rime WebSocket text send") suggests this is deliberate, and the Reported before the send succeedsThe call precedes Inconsistent notion of "empty"The Minor: the guard also diverges from the unguarded Version pin tightening
Smaller notes
SummaryThe mechanics are sound and the change is appropriately small. Before merge I would want the upstream dependency released, the metrics |
Summary
Dependency
Testing
tests/test_params.py(1 passed)OpenAI TTS request reporting is inherited entirely from ten_ai_base and requires no package change here. Bytedance duplex is owned by the conversational_agent repository.