Skip to content

fix: pass user's configured name to transcript formatter for summary …#5369

Open
bzanghi wants to merge 2 commits intoBasedHardware:mainfrom
bzanghi:fix/speaker-name-in-transcript-summary
Open

fix: pass user's configured name to transcript formatter for summary …#5369
bzanghi wants to merge 2 commits intoBasedHardware:mainfrom
bzanghi:fix/speaker-name-in-transcript-summary

Conversation

@bzanghi
Copy link

@bzanghi bzanghi commented Mar 5, 2026

…generation

When generating conversation summaries, the transcript passed to the LLM was using the generic 'User' placeholder instead of the user's actual configured name (e.g. 'Stephen' instead of 'User').

Root cause: TranscriptSegment.segments_as_string() accepts a user_name parameter but get_transcript() never forwarded it, so it always defaulted to 'User'.

Fix:

  • Add user_name param to Conversation.get_transcript() and CreateConversation.get_transcript() and pass it through to segments_as_string()
  • In _get_structured() and _trigger_apps(), fetch the user's display name via get_user_name(uid) (Redis-cached, fast) and pass it to get_transcript()

Result: summaries now say 'Stephen: ...' instead of 'User: ...' when the user has configured their name in app settings.

Fixes #5319

…generation

When generating conversation summaries, the transcript passed to the LLM
was using the generic 'User' placeholder instead of the user's actual
configured name (e.g. 'Stephen' instead of 'User').

Root cause: TranscriptSegment.segments_as_string() accepts a user_name
parameter but get_transcript() never forwarded it, so it always
defaulted to 'User'.

Fix:
- Add user_name param to Conversation.get_transcript() and
  CreateConversation.get_transcript() and pass it through to
  segments_as_string()
- In _get_structured() and _trigger_apps(), fetch the user's display
  name via get_user_name(uid) (Redis-cached, fast) and pass it to
  get_transcript()

Result: summaries now say 'Stephen: ...' instead of 'User: ...' when
the user has configured their name in app settings.

Fixes BasedHardware#5319
@greptile-apps
Copy link

greptile-apps bot commented Mar 5, 2026

Greptile Summary

This PR fixes a UX gap where AI-generated conversation summaries displayed the generic User: label instead of the user's configured name (e.g. Stephen:). The fix threads a new optional user_name parameter through Conversation.get_transcript() / CreateConversation.get_transcript() into TranscriptSegment.segments_as_string(), and resolves the name by calling get_user_name(uid) in _get_structured() and _trigger_apps() before building the transcript string.

Key concerns:

  • Redis cache is disabled in get_user_name — The cache-read line (get_cached_user_name) is commented out in database/auth.py, so every call makes a live Firebase Auth + optional Firestore network request. The PR description claims this function is "Redis-cached, fast", but that is currently inaccurate. This adds two synchronous network calls per conversation on the processing critical path.
  • user_name fetched unnecessarily for external/workflow sources — In _get_structured, get_user_name is called unconditionally at the top of the function, but for workflow and external_integration conversation sources the function returns early before the transcript is ever built — making the Firebase call wasteful for those paths.
  • Duplicate fetch_get_structured and _trigger_apps each independently call get_user_name for the same uid; the value could be fetched once and passed through to avoid the second network call.

Confidence Score: 3/5

  • The correctness of the feature is sound, but the implementation adds uncached Firebase Auth calls on every conversation processing path, contradicting the PR description's performance claim.
  • The model-layer changes are clean and backward-compatible. The functional behavior is correct in all cases (graceful fallback to 'User' when no name is configured or lookup fails). However, the Redis cache read in get_user_name is disabled, meaning two live Firebase network calls are added per conversation on the processing critical path. Additionally, one of those calls is made unconditionally even for conversation sources where the result is never used. These performance issues reduce confidence.
  • Pay close attention to backend/utils/conversations/process_conversation.py — specifically the placement and frequency of get_user_name calls relative to early-return paths and the disabled Redis cache.

Important Files Changed

Filename Overview
backend/models/conversation.py Adds optional user_name parameter to get_transcript() on both Conversation and CreateConversation and forwards it to TranscriptSegment.segments_as_string(). The change is backward-compatible (parameter defaults to None, and segments_as_string falls back to 'User' when None).
backend/utils/conversations/process_conversation.py Adds get_user_name import and two call-sites (_get_structured and _trigger_apps) to fetch the user's display name before building the transcript. However, the Redis cache read in get_user_name is commented out, making every call a live Firebase Auth network request, and user_name is fetched in _get_structured even for early-return workflow/external-integration paths where it is never used.

Sequence Diagram

sequenceDiagram
    participant C as Caller
    participant GS as _get_structured()
    participant TA as _trigger_apps()
    participant GA as get_user_name()<br/>(database/auth.py)
    participant FB as Firebase Auth
    participant FS as Firestore
    participant TR as get_transcript()<br/>(Conversation model)
    participant SS as segments_as_string()

    C->>GS: uid, conversation, people
    GS->>GA: get_user_name(uid, use_default=False)
    GA->>FB: auth.get_user(uid) [uncached - Redis read disabled]
    FB-->>GA: user or error
    alt no display_name
        GA->>FS: db.collection('users').document(uid).get()
        FS-->>GA: Firestore doc
    end
    GA-->>GS: user_name (or None)
    GS->>TR: get_transcript(False, people, user_name)
    TR->>SS: segments_as_string(segments, user_name=user_name)
    SS-->>TR: "Stephen: Hello..."
    TR-->>GS: transcript_text
    GS-->>C: Structured, discarded

    C->>TA: uid, conversation, people
    TA->>GA: get_user_name(uid, use_default=False)
    Note over GA,FB: Second uncached Firebase call<br/>(same uid, same result)
    GA->>FB: auth.get_user(uid)
    FB-->>GA: user
    GA-->>TA: user_name
    TA->>TR: get_transcript(False, people, user_name)
    TR->>SS: segments_as_string(segments, user_name=user_name)
    SS-->>TR: "Stephen: Hello..."
    TR-->>TA: transcript_text
Loading

Last reviewed commit: 187daa1


# Fetch the user's configured display name so transcripts use real names
# instead of the generic "User" placeholder during summary generation.
user_name = get_user_name(uid, use_default=False)
Copy link

Choose a reason for hiding this comment

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

Redis cache is disabled — uncached Firebase Auth call on every conversation

The PR description states get_user_name() is "Redis-cached, fast", but the cache-read line in database/auth.py is commented out:

def get_user_name(uid: str, use_default: bool = True):
    # if cached_name := get_cached_user_name(uid):  ← disabled
    #     return cached_name
    user = get_user_from_uid(uid)  # always hits Firebase Auth

This means every invocation of get_user_name makes a live synchronous Firebase Auth network call (and a potential Firestore fallback call). This PR adds two such calls per conversation — one here in _get_structured and a second one in _trigger_apps (line 299) — where there were none before. These calls happen on the critical path of conversation processing and will add measurable latency.

The fix should either:

  1. Re-enable the Redis cache read in get_user_name, or
  2. Fetch user_name once (e.g. pass it into both functions from the caller) rather than calling get_user_name independently in each function.

Comment on lines 86 to +147
@@ -139,7 +144,7 @@ def _get_structured(
# not supported conversation source
raise HTTPException(status_code=400, detail=f'Invalid conversation source: {conversation.text_source}')

transcript_text = conversation.get_transcript(False, people=people)
transcript_text = conversation.get_transcript(False, people=people, user_name=user_name)
Copy link

Choose a reason for hiding this comment

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

user_name fetched but unused for workflow/external-integration sources

get_user_name is called unconditionally at line 91, but for workflow and external_integration conversation sources the function returns early (lines 112–145) before ever reaching conversation.get_transcript(…, user_name=user_name) at line 147. The Firebase Auth call is wasted for those code paths.

Moving the fetch to just before where it is used (after the early-return block) avoids the unnecessary network call for external/workflow sources:

# After the early-return block for workflow / external_integration:
transcript_text = conversation.get_transcript(False, people=people, user_name=get_user_name(uid, use_default=False))

Or alternatively, guard the fetch:

user_name = None
if conversation.source not in (ConversationSource.workflow, ConversationSource.external_integration):
    user_name = get_user_name(uid, use_default=False)

…avoid duplicate calls

Address Greptile review feedback:
- Move get_user_name() call from _get_structured() and _trigger_apps() up
  to process_conversation(), so it's fetched once per conversation and
  passed down as a parameter to both functions
- This eliminates the duplicate Firebase Auth call that was made
  separately in each function for the same uid
- _get_structured() no longer calls get_user_name() unconditionally
  before early-return paths for workflow/external-integration sources;
  the call now sits at the process_conversation() level, which only
  handles omi/ble source conversations on this code path
- Both _get_structured() and _trigger_apps() accept user_name as an
  optional parameter (default None), maintaining backward compatibility
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.

Pass speaker name instead of "User" in transcript for summary generation

1 participant