Skip to content

fix(app): compute conversation duration from transcript, not session span#7528

Open
lucidsif wants to merge 1 commit into
BasedHardware:mainfrom
lucidsif:fix/conversation-duration-4056
Open

fix(app): compute conversation duration from transcript, not session span#7528
lucidsif wants to merge 1 commit into
BasedHardware:mainfrom
lucidsif:fix/conversation-duration-4056

Conversation

@lucidsif
Copy link
Copy Markdown

@lucidsif lucidsif commented May 28, 2026

Summary

Hello! Thanks for this wonderful omi app and open source software. I opened this draft PR to address this issue I just re-opened. Please feel free to comment, open your own PR, or provide any feedback. Please note that I updated the code and PR (mostly refactors, tests, and description changes) after the bot checked this PR.

Bug

The conversation duration is far longer than the actual conversation. This is happening whether I use my own local STT server or a cloud provider's like Deepgram's.

ServerConversation.getDurationInSeconds() returned finishedAt - startedAt whenever both timestamps were set. started_at is set to the audio-streaming session origin not to the individual conversation, so for short conversations the displayed duration over-counts by however long the streaming session had been open which is often waylonger than the actual duration.

Root cause

getDurationInSeconds() preferred finishedAt.difference(startedAt). A correct transcript-based calculation already exists (_getDurationInSecondsByTranscripts()), but was only used as a fallback when timestamps were null. Because started_at reflects when the streaming session opened and persists across conversations until the stream resets, multiple conversations created in one session share an early started_at, and processing promptly does not help. I would notice multiple conversations have a similar length of time/duration padding.

Fix

Prefer the transcript-derived duration when transcript segments exist and keep the finishedAt - startedAt delta only as a fallback for segment-less conversations. No API or schema changes and minimal changes in the branching.

Before / After

For ~10s of speech recorded during a streaming session that had been open ~10 minutes:

  • Before: ~600s shown
  • After: ~10s shown

Verification

  • Logic-only change in a model method. No API, type, or generated files affected.
  • Reproduced the bug and traced the fix against live conversation data.
  • Behavior is provider-independent (observed on both cloud services like Deepgram and local STT).
  • Wrote unit tests and regression tests.

@lucidsif lucidsif marked this pull request as draft May 28, 2026 19:26
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Greptile Summary

This PR fixes a long-standing over-counting bug in ServerConversation.getDurationInSeconds(). The started_at timestamp reflects the streaming-session origin rather than the individual conversation start, causing displayed durations to include all the idle time before the conversation began.

  • getDurationInSeconds() now prefers the transcript-derived duration (last segment end time) whenever transcriptSegments is non-empty, falling back to finishedAt − startedAt only for segment-less conversations.
  • A new test file adds six targeted cases: the primary regression scenario (~10 s speech in a ~600 s session), multi-segment max-end selection, the no-segment timestamp fallback, the fully-null zero case, and two unchanged regression paths.

Confidence Score: 5/5

Safe to merge — the change is a one-line guard in a model helper with no API, schema, or UI contract changes, and it is backed by six targeted unit tests.

The fix correctly re-orders the two existing duration strategies: transcript offsets are now the primary path and the session-timestamp delta is the fallback. Both code paths already existed and are well-understood; the only change is which one runs first. Unit tests confirm the primary bug scenario (600 s session / 12 s speech → returns 12) as well as edge cases.

No files require special attention.

Important Files Changed

Filename Overview
app/lib/backend/schema/conversation.dart Single-line guard added to getDurationInSeconds(): timestamps are now only used as a fallback when transcriptSegments is empty, fixing the over-counted duration bug (#4056).
app/test/unit/conversation_duration_test.dart New unit test file covering the primary fix path, multi-segment max-end logic, the no-segments fallback, the zero-duration edge case, and two regression paths; all scenarios are well-chosen.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["getDurationInSeconds()"] --> B{transcriptSegments empty?}
    B -- "Yes (no speech data)" --> C{finishedAt AND startedAt set?}
    C -- Yes --> D["return finishedAt − startedAt\n(session-span fallback)"]
    C -- No --> E["return 0"]
    B -- "No (speech segments present)" --> F["_getDurationInSecondsByTranscripts()"]
    F --> G["iterate segments,\nfind max end time"]
    G --> H["return lastEndTime.toInt()\n(actual speech duration)"]
Loading

Reviews (2): Last reviewed commit: "fix(app): compute conversation duration ..." | Re-trigger Greptile

@lucidsif lucidsif force-pushed the fix/conversation-duration-4056 branch 3 times, most recently from 2e9106f to 466aa5f Compare May 28, 2026 20:04
…span

getDurationInSeconds() returned finishedAt - startedAt whenever both were
set. started_at is anchored to the audio-streaming session origin (not the
conversation), so for short conversations the value over-counts by however
long the streaming session had been open — often 20-30+ minutes shown for
1-2 minutes of speech.

Prefer the existing transcript-derived calculation when segments are present;
keep the timestamp delta only as a fallback for segment-less conversations.

Adds unit tests (test/unit/conversation_duration_test.dart): the new
segment-span behavior (single + multi-segment), plus regression coverage that
the unchanged paths still hold — segment-less + timestamps -> delta,
segments + no timestamps -> transcript span, and the empty/partial cases -> 0.

Fixes BasedHardware#4056
@lucidsif lucidsif force-pushed the fix/conversation-duration-4056 branch from 466aa5f to 1349347 Compare May 28, 2026 20:19
@lucidsif lucidsif marked this pull request as ready for review May 28, 2026 20:28
Copy link
Copy Markdown
Collaborator

@kodjima33 kodjima33 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks — transcript-based duration is the right fix

@lucidsif
Copy link
Copy Markdown
Author

thank you for the review @kodjima33. looks like the lint check workflow is still awaiting maintainer approval to run (first-contribution gate). i'm not sure how this works exactly. let me know if there's anything you want me to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants