console: play the call recording alongside the transcript
The voice agent uploads a dual-channel WAV of each call to blob storage; until now the console showed only the transcript's conclusions, not the audio. Add a player wherever the call is read: - THE CALL panel on the lead gets an inline "Call recording" player. - The transcript dialog gets the player above the turns, so a reviewer can listen while reading — the words and the audio are the same evidence. Both read row.call_recording_url (the platform's own field for this, surfaced on the lead by backend 107) and use preload="none", so a multi-MB WAV is only fetched when someone actually presses play. The player simply does not render when a lead has no recording. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
bd4ced41ac
commit
e0d51159f6
@ -42,7 +42,7 @@ function turnsFrom(text) {
|
|||||||
return out.filter((t) => t.text)
|
return out.filter((t) => t.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CallTranscript({ text, name, onClose }) {
|
export default function CallTranscript({ text, audio, name, onClose }) {
|
||||||
const ref = useRef(null)
|
const ref = useRef(null)
|
||||||
const restore = useRef(null)
|
const restore = useRef(null)
|
||||||
const turns = turnsFrom(text)
|
const turns = turnsFrom(text)
|
||||||
@ -82,6 +82,16 @@ export default function CallTranscript({ text, name, onClose }) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{audio ? (
|
||||||
|
<div className="conv__audio">
|
||||||
|
{/* Listen along with the transcript. preload=none so opening the
|
||||||
|
dialog does not pull a multi-MB WAV until the user hits play. */}
|
||||||
|
<audio controls preload="none" src={audio}>
|
||||||
|
Your browser cannot play this recording.
|
||||||
|
</audio>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<div className="conv__body">
|
<div className="conv__body">
|
||||||
{turns.length ? turns.map((t, i) => (
|
{turns.length ? turns.map((t, i) => (
|
||||||
<div key={i} className={'bub bub--' + t.side}>
|
<div key={i} className={'bub bub--' + t.side}>
|
||||||
|
|||||||
@ -76,3 +76,13 @@
|
|||||||
background: var(--zk-tint);
|
background: var(--zk-tint);
|
||||||
border-radius: var(--r-md);
|
border-radius: var(--r-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The call recording, played from inside the transcript dialog. */
|
||||||
|
.conv__audio {
|
||||||
|
padding: 12px 20px 4px;
|
||||||
|
border-bottom: 1px solid var(--zk-line-soft);
|
||||||
|
}
|
||||||
|
.conv__audio audio {
|
||||||
|
width: 100%;
|
||||||
|
height: 38px;
|
||||||
|
}
|
||||||
|
|||||||
@ -838,6 +838,17 @@ blocked ? (
|
|||||||
Read what was actually said
|
Read what was actually said
|
||||||
</button>
|
</button>
|
||||||
) : null}
|
) : null}
|
||||||
|
{title === 'The call' && row.call_recording_url ? (
|
||||||
|
/* The recording itself, to play alongside the transcript.
|
||||||
|
preload=none keeps the multi-MB WAV off the wire until
|
||||||
|
a person actually presses play. */
|
||||||
|
<div className="glance__rec">
|
||||||
|
<span className="glance__rec-l">Call recording</span>
|
||||||
|
<audio controls preload="none" src={row.call_recording_url}>
|
||||||
|
Your browser cannot play this recording.
|
||||||
|
</audio>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</section>
|
</section>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -864,7 +875,7 @@ blocked ? (
|
|||||||
<AgentCard agentKey={openAgent} onClose={() => setOpenAgent(null)} />
|
<AgentCard agentKey={openAgent} onClose={() => setOpenAgent(null)} />
|
||||||
) : null}
|
) : null}
|
||||||
{showCall ? (
|
{showCall ? (
|
||||||
<CallTranscript text={row.call_transcript} name={row.customer_name} onClose={() => setShowCall(false)} />
|
<CallTranscript text={row.call_transcript} audio={row.call_recording_url} name={row.customer_name} onClose={() => setShowCall(false)} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{showFile ? (
|
{showFile ? (
|
||||||
|
|||||||
@ -1727,6 +1727,24 @@
|
|||||||
/* An action that belongs to one card, not to the panel. Quiet until hovered:
|
/* An action that belongs to one card, not to the panel. Quiet until hovered:
|
||||||
the notes above it are the answer most of the time, and the transcript is
|
the notes above it are the answer most of the time, and the transcript is
|
||||||
the follow-up question. */
|
the follow-up question. */
|
||||||
|
.glance__rec {
|
||||||
|
margin-top: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.glance__rec-l {
|
||||||
|
font-size: var(--fs-3xs);
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--zk-grey);
|
||||||
|
}
|
||||||
|
.glance__rec audio {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
.glance__act {
|
.glance__act {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user