Skip to content

Conversation

@smankovsky
Copy link
Member

@smankovsky smankovsky commented Sep 29, 2025

User description

Screenshot 2025-09-29 at 19 30 03 Screenshot 2025-09-29 at 19 31 45

PR Type

Enhancement


Description

  • Add transcript copy functionality with formatting

  • Include speaker names and timestamps

  • Show success notification on copy

  • Improve transcript formatting with topics


Changes walkthrough 📝

Relevant files
Enhancement
finalSummary.tsx
Add transcript copy button with success notification         

www/app/(app)/transcripts/[transcriptId]/finalSummary.tsx

  • Added copy transcript button with icon
  • Implemented clipboard functionality using buildTranscriptWithTopics
  • Added success toast notification with checkmark
  • Imported necessary dependencies (LuCopy, LuCheck icons)
  • +51/-1   
    buildTranscriptWithTopics.ts
    Create transcript formatting utility                                         

    www/app/(app)/transcripts/buildTranscriptWithTopics.ts

  • Created new utility function to format transcript with topics
  • Added speaker name resolution from participants data
  • Implemented timestamp formatting for topics and segments
  • Structured output with markdown-like formatting
  • +60/-0   
    shareCopy.tsx
    Update transcript copy with new formatting utility             

    www/app/(app)/transcripts/shareCopy.tsx

  • Updated copy transcript functionality to use new
    buildTranscriptWithTopics utility
  • Added participant data fetching with useTranscriptParticipants hook
  • Replaced simple text concatenation with formatted transcript
  • +11/-6   

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • @vercel
    Copy link

    vercel bot commented Sep 29, 2025

    The latest updates on your projects. Learn more about Vercel for GitHub.

    Project Deployment Preview Comments Updated (UTC)
    reflector Ready Ready Preview Comment Sep 29, 2025 5:38pm
    reflector-media Ready Ready Preview Comment Sep 29, 2025 5:38pm

    @pr-agent-monadical
    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Error Handling

    The copy functionality has empty catch blocks for clipboard operations. Consider adding proper error handling to inform users when copying fails.

    navigator.clipboard
      .writeText(text)
      .then(() => {
        toaster
          .create({
            placement: "top",
            duration: 2500,
            render: () => (
              <div className="chakra-ui-light">
                <div
                  style={{
                    background: "#38A169",
                    color: "white",
                    padding: "8px 12px",
                    borderRadius: 6,
                    display: "flex",
                    alignItems: "center",
                    gap: 8,
                    boxShadow: "rgba(0,0,0,0.25) 0px 4px 12px",
                  }}
                >
                  <LuCheck /> Transcript copied
                </div>
              </div>
            ),
          })
          .then(() => {});
      })
      .catch(() => {});
    Type Safety

    The function assumes speaker is a number when calling getSpeakerName, but casts it with 'as number' which could lead to runtime errors if the data structure changes.

    const speaker = getSpeakerName(seg.speaker as number, participants);

    Comment on lines +145 to +173
    navigator.clipboard
    .writeText(text)
    .then(() => {
    toaster
    .create({
    placement: "top",
    duration: 2500,
    render: () => (
    <div className="chakra-ui-light">
    <div
    style={{
    background: "#38A169",
    color: "white",
    padding: "8px 12px",
    borderRadius: 6,
    display: "flex",
    alignItems: "center",
    gap: 8,
    boxShadow: "rgba(0,0,0,0.25) 0px 4px 12px",
    }}
    >
    <LuCheck /> Transcript copied
    </div>
    </div>
    ),
    })
    .then(() => {});
    })
    .catch(() => {});
    Copy link
    Contributor

    Choose a reason for hiding this comment

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

    Suggestion: Add proper error handling in the clipboard operation's catch block to inform the user when copying fails, rather than silently ignoring errors. [general, importance: 7]

    Suggested change
    navigator.clipboard
    .writeText(text)
    .then(() => {
    toaster
    .create({
    placement: "top",
    duration: 2500,
    render: () => (
    <div className="chakra-ui-light">
    <div
    style={{
    background: "#38A169",
    color: "white",
    padding: "8px 12px",
    borderRadius: 6,
    display: "flex",
    alignItems: "center",
    gap: 8,
    boxShadow: "rgba(0,0,0,0.25) 0px 4px 12px",
    }}
    >
    <LuCheck /> Transcript copied
    </div>
    </div>
    ),
    })
    .then(() => {});
    })
    .catch(() => {});
    navigator.clipboard
    .writeText(text)
    .then(() => {
    toaster
    .create({
    placement: "top",
    duration: 2500,
    render: () => (
    <div className="chakra-ui-light">
    <div
    style={{
    background: "#38A169",
    color: "white",
    padding: "8px 12px",
    borderRadius: 6,
    display: "flex",
    alignItems: "center",
    gap: 8,
    boxShadow: "rgba(0,0,0,0.25) 0px 4px 12px",
    }}
    >
    <LuCheck /> Transcript copied
    </div>
    </div>
    ),
    })
    .then(() => {});
    })
    .catch((error) => {
    toaster.create({
    placement: "top",
    duration: 2500,
    render: () => (
    <div className="chakra-ui-light">
    <div
    style={{
    background: "#E53E3E",
    color: "white",
    padding: "8px 12px",
    borderRadius: 6,
    display: "flex",
    alignItems: "center",
    gap: 8,
    boxShadow: "rgba(0,0,0,0.25) 0px 4px 12px",
    }}
    >
    Failed to copy transcript
    </div>
    </div>
    ),
    });
    });

    Comment on lines +139 to +145
    const text = buildTranscriptWithTopics(
    props.topicsResponse || [],
    participantsQuery?.data || null,
    props.transcriptResponse?.title || null,
    );
    if (!text) return;
    navigator.clipboard
    Copy link
    Contributor

    Choose a reason for hiding this comment

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

    Suggestion: Check if participantsQuery is still loading before using its data. The current implementation might cause issues if the query hasn't completed when the copy function is triggered. [possible issue, importance: 8]

    Suggested change
    const text = buildTranscriptWithTopics(
    props.topicsResponse || [],
    participantsQuery?.data || null,
    props.transcriptResponse?.title || null,
    );
    if (!text) return;
    navigator.clipboard
    if (participantsQuery.isLoading) {
    toaster.create({
    placement: "top",
    duration: 2500,
    render: () => (
    <div className="chakra-ui-light">
    <div style={{
    background: "#ED8936",
    color: "white",
    padding: "8px 12px",
    borderRadius: 6,
    display: "flex",
    alignItems: "center",
    gap: 8,
    boxShadow: "rgba(0,0,0,0.25) 0px 4px 12px",
    }}>
    Please wait for participant data to load
    </div>
    </div>
    ),
    });
    return;
    }
    const text = buildTranscriptWithTopics(
    props.topicsResponse || [],
    participantsQuery?.data || null,
    props.transcriptResponse?.title || null,
    );
    if (!text) return;

    Comment on lines +7 to +13
    function getSpeakerName(
    speakerNumber: number,
    participants?: Participant[] | null,
    ): string {
    const name = participants?.find((p) => p.speaker === speakerNumber)?.name;
    return name && name.trim().length > 0 ? name : `Speaker ${speakerNumber}`;
    }
    Copy link
    Contributor

    Choose a reason for hiding this comment

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

    Suggestion: Add a type check for speakerNumber before using it to find a participant. If speakerNumber is undefined or null, the function might return incorrect results. [general, importance: 6]

    Suggested change
    function getSpeakerName(
    speakerNumber: number,
    participants?: Participant[] | null,
    ): string {
    const name = participants?.find((p) => p.speaker === speakerNumber)?.name;
    return name && name.trim().length > 0 ? name : `Speaker ${speakerNumber}`;
    }
    function getSpeakerName(
    speakerNumber: number,
    participants?: Participant[] | null,
    ): string {
    if (speakerNumber === undefined || speakerNumber === null) {
    return "Unknown Speaker";
    }
    const name = participants?.find((p) => p.speaker === speakerNumber)?.name;
    return name && name.trim().length > 0 ? name : `Speaker ${speakerNumber}`;
    }

    Copy link
    Member

    @tito tito left a comment

    Choose a reason for hiding this comment

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

    I think you could have leverage the webvtt field instead of the old topics list, but that works too.

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

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    break "copy transcript" from "share" into its own button Copy transcript is wrongly formatted and does not have diarization information

    2 participants