Persist call transcripts and source call audio from DB
This commit is contained in:
@@ -8,6 +8,7 @@ import logoutMutation from "./graphql/operations/logout.graphql?raw";
|
||||
import logPilotNoteMutation from "./graphql/operations/log-pilot-note.graphql?raw";
|
||||
import createCalendarEventMutation from "./graphql/operations/create-calendar-event.graphql?raw";
|
||||
import createCommunicationMutation from "./graphql/operations/create-communication.graphql?raw";
|
||||
import updateCommunicationTranscriptMutation from "./graphql/operations/update-communication-transcript.graphql?raw";
|
||||
import updateFeedDecisionMutation from "./graphql/operations/update-feed-decision.graphql?raw";
|
||||
import chatConversationsQuery from "./graphql/operations/chat-conversations.graphql?raw";
|
||||
import createChatConversationMutation from "./graphql/operations/create-chat-conversation.graphql?raw";
|
||||
@@ -1982,6 +1983,13 @@ async function transcribeCallItem(item: CommItem) {
|
||||
const itemId = item.id;
|
||||
if (callTranscriptLoading.value[itemId]) return;
|
||||
if (callTranscriptText.value[itemId]) return;
|
||||
if (Array.isArray(item.transcript) && item.transcript.length) {
|
||||
const persisted = item.transcript.map((line) => String(line ?? "").trim()).filter(Boolean).join("\n");
|
||||
if (persisted) {
|
||||
callTranscriptText.value[itemId] = persisted;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const audioUrl = getCallAudioUrl(item);
|
||||
if (!audioUrl) {
|
||||
@@ -2003,6 +2011,11 @@ async function transcribeCallItem(item: CommItem) {
|
||||
});
|
||||
const text = String(result?.text ?? "").trim();
|
||||
callTranscriptText.value[itemId] = text || "(empty transcript)";
|
||||
await gqlFetch<{ updateCommunicationTranscript: { ok: boolean; id: string } }>(updateCommunicationTranscriptMutation, {
|
||||
id: itemId,
|
||||
transcript: text ? [text] : [],
|
||||
});
|
||||
await refreshCrmData();
|
||||
} catch (error: any) {
|
||||
callTranscriptError.value[itemId] = String(error?.message ?? error ?? "Transcription failed");
|
||||
} finally {
|
||||
@@ -3221,6 +3234,7 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
||||
<svg viewBox="0 0 24 24" class="h-4 w-4 shrink-0 fill-current text-base-content/75">
|
||||
<path d="M14 3a1 1 0 0 0-1 1v4.59l-1.7 1.7A2 2 0 0 0 10.7 12H8v2h2.7a2 2 0 0 0 .6 1.41L13 17.1V21l2-1.2v-2.7l1.7-1.7A2 2 0 0 0 17.3 14H20v-2h-2.7a2 2 0 0 0-.6-1.41L15 8.9V4a1 1 0 0 0-1-1Z" />
|
||||
</svg>
|
||||
<span class="min-w-0 flex-1 truncate text-xs text-base-content/80">{{ latestPinnedLabel }}</span>
|
||||
<span class="shrink-0 text-xs text-base-content/75">{{ selectedCommPinnedStream.length }}</span>
|
||||
</button>
|
||||
|
||||
@@ -3231,8 +3245,7 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
||||
>
|
||||
<div v-if="entry.kind === 'pin'" class="flex justify-center">
|
||||
<article class="w-full max-w-[460px] rounded-xl border border-base-300 bg-base-100 p-3">
|
||||
<p class="text-[11px] font-semibold uppercase tracking-wide text-base-content/65">Pinned note</p>
|
||||
<p class="mt-1 text-sm text-base-content/85">{{ entry.text }}</p>
|
||||
<p class="text-sm text-base-content/85">{{ entry.text }}</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
mutation UpdateCommunicationTranscriptMutation($id: ID!, $transcript: [String!]!) {
|
||||
updateCommunicationTranscript(id: $id, transcript: $transcript) {
|
||||
ok
|
||||
id
|
||||
}
|
||||
}
|
||||
@@ -552,6 +552,29 @@ async function createCommunication(auth: AuthContext | null, input: {
|
||||
return { ok: true, id: created.id };
|
||||
}
|
||||
|
||||
async function updateCommunicationTranscript(auth: AuthContext | null, id: string, transcript: string[]) {
|
||||
const ctx = requireAuth(auth);
|
||||
const messageId = String(id ?? "").trim();
|
||||
if (!messageId) throw new Error("id is required");
|
||||
|
||||
const lines = Array.isArray(transcript)
|
||||
? transcript.map((line) => String(line ?? "").trim()).filter(Boolean)
|
||||
: [];
|
||||
|
||||
const updated = await prisma.contactMessage.updateMany({
|
||||
where: {
|
||||
id: messageId,
|
||||
contact: { teamId: ctx.teamId },
|
||||
},
|
||||
data: {
|
||||
transcriptJson: lines,
|
||||
},
|
||||
});
|
||||
|
||||
if (!updated.count) throw new Error("communication not found");
|
||||
return { ok: true, id: messageId };
|
||||
}
|
||||
|
||||
async function updateFeedDecision(auth: AuthContext | null, id: string, decision: "accepted" | "rejected" | "pending", decisionNote?: string) {
|
||||
const ctx = requireAuth(auth);
|
||||
|
||||
@@ -769,6 +792,7 @@ export const crmGraphqlSchema = buildSchema(`
|
||||
toggleContactPin(contact: String!, text: String!): PinToggleResult!
|
||||
createCalendarEvent(input: CreateCalendarEventInput!): CalendarEvent!
|
||||
createCommunication(input: CreateCommunicationInput!): MutationWithIdResult!
|
||||
updateCommunicationTranscript(id: ID!, transcript: [String!]!): MutationWithIdResult!
|
||||
updateFeedDecision(id: ID!, decision: String!, decisionNote: String): MutationWithIdResult!
|
||||
}
|
||||
|
||||
@@ -1027,6 +1051,11 @@ export const crmGraphqlRoot = {
|
||||
context: GraphQLContext,
|
||||
) => createCommunication(context.auth, args.input),
|
||||
|
||||
updateCommunicationTranscript: async (
|
||||
args: { id: string; transcript: string[] },
|
||||
context: GraphQLContext,
|
||||
) => updateCommunicationTranscript(context.auth, args.id, args.transcript),
|
||||
|
||||
updateFeedDecision: async (
|
||||
args: { id: string; decision: "accepted" | "rejected" | "pending"; decisionNote?: string },
|
||||
context: GraphQLContext,
|
||||
|
||||
Reference in New Issue
Block a user