mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 12:12:09 +01:00
Improves transcript viewer with Markdown support
Adds Markdown rendering to the transcript viewer for enhanced formatting. This change integrates `react-markdown` to parse and render transcript content, allowing for richer text formatting, including links and other Markdown elements. It also adds a toggle to switch between raw and formatted text, and displays a message when transcript content is unavailable. The UI of the transcript viewer has been improved to be more user-friendly with titles and descriptions.
This commit is contained in:
@ -17,19 +17,19 @@ interface SessionCreateData {
|
||||
* @returns The transcript content or null if fetching fails
|
||||
*/
|
||||
async function fetchTranscriptContent(url: string): Promise<string | null> {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
process.stderr.write(
|
||||
`Error fetching transcript: ${response.statusText}\n`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
return await response.text();
|
||||
} catch (error) {
|
||||
process.stderr.write(`Failed to fetch transcript: ${error}\n`);
|
||||
return null;
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
process.stderr.write(
|
||||
`Error fetching transcript: ${response.statusText}\n`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
return await response.text();
|
||||
} catch (error) {
|
||||
process.stderr.write(`Failed to fetch transcript: ${error}\n`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default async function handler(
|
||||
@ -107,13 +107,13 @@ export default async function handler(
|
||||
? session.endTime
|
||||
: new Date();
|
||||
|
||||
// Fetch transcript content if URL is available
|
||||
let transcriptContent: string | null = null;
|
||||
if (session.fullTranscriptUrl) {
|
||||
transcriptContent = await fetchTranscriptContent(
|
||||
session.fullTranscriptUrl
|
||||
);
|
||||
}
|
||||
// Fetch transcript content if URL is available
|
||||
let transcriptContent: string | null = null;
|
||||
if (session.fullTranscriptUrl) {
|
||||
transcriptContent = await fetchTranscriptContent(
|
||||
session.fullTranscriptUrl
|
||||
);
|
||||
}
|
||||
|
||||
// Only include fields that are properly typed for Prisma
|
||||
await prisma.session.create({
|
||||
@ -136,7 +136,7 @@ export default async function handler(
|
||||
? session.forwardedHr
|
||||
: null,
|
||||
fullTranscriptUrl: session.fullTranscriptUrl || null,
|
||||
transcriptContent: transcriptContent, // Add the transcript content
|
||||
transcriptContent: transcriptContent, // Add the transcript content
|
||||
avgResponseTime:
|
||||
typeof session.avgResponseTime === "number"
|
||||
? session.avgResponseTime
|
||||
|
||||
62
pages/api/dashboard/session/[id].ts
Normal file
62
pages/api/dashboard/session/[id].ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { prisma } from "../../../../lib/prisma";
|
||||
import { ChatSession } from "../../../../lib/types";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
if (!id || typeof id !== "string") {
|
||||
return res.status(400).json({ error: "Session ID is required" });
|
||||
}
|
||||
|
||||
try {
|
||||
const prismaSession = await prisma.session.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (!prismaSession) {
|
||||
return res.status(404).json({ error: "Session not found" });
|
||||
}
|
||||
|
||||
// Map Prisma session object to ChatSession type
|
||||
const session: ChatSession = {
|
||||
...prismaSession,
|
||||
sessionId: prismaSession.id, // Assuming ChatSession's sessionId is Prisma's id
|
||||
startTime: new Date(prismaSession.startTime),
|
||||
endTime: prismaSession.endTime ? new Date(prismaSession.endTime) : null,
|
||||
createdAt: new Date(prismaSession.createdAt),
|
||||
updatedAt: new Date(prismaSession.updatedAt),
|
||||
userId: prismaSession.userId === undefined ? null : prismaSession.userId,
|
||||
category: prismaSession.category === undefined ? null : prismaSession.category,
|
||||
language: prismaSession.language === undefined ? null : prismaSession.language,
|
||||
country: prismaSession.country === undefined ? null : prismaSession.country,
|
||||
ipAddress: prismaSession.ipAddress === undefined ? null : prismaSession.ipAddress,
|
||||
sentiment: prismaSession.sentiment === undefined ? null : prismaSession.sentiment,
|
||||
messagesSent: prismaSession.messagesSent === undefined ? undefined : prismaSession.messagesSent,
|
||||
avgResponseTime: prismaSession.avgResponseTime === undefined ? null : prismaSession.avgResponseTime,
|
||||
escalated: prismaSession.escalated === undefined ? undefined : prismaSession.escalated,
|
||||
forwardedHr: prismaSession.forwardedHr === undefined ? undefined : prismaSession.forwardedHr,
|
||||
tokens: prismaSession.tokens === undefined ? undefined : prismaSession.tokens,
|
||||
tokensEur: prismaSession.tokensEur === undefined ? undefined : prismaSession.tokensEur,
|
||||
initialMsg: prismaSession.initialMsg === undefined ? null : prismaSession.initialMsg,
|
||||
fullTranscriptUrl: prismaSession.fullTranscriptUrl === undefined ? null : prismaSession.fullTranscriptUrl,
|
||||
transcriptContent: prismaSession.transcriptContent === undefined ? null : prismaSession.transcriptContent,
|
||||
};
|
||||
|
||||
return res.status(200).json({ session });
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch session ${id}:`, error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "An unknown error occurred";
|
||||
return res
|
||||
.status(500)
|
||||
.json({ error: "Failed to fetch session", details: errorMessage });
|
||||
}
|
||||
}
|
||||
73
pages/api/dashboard/sessions.ts
Normal file
73
pages/api/dashboard/sessions.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { prisma } from "../../../lib/prisma";
|
||||
import { ChatSession } from "../../../lib/types";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { searchTerm } = req.query;
|
||||
|
||||
try {
|
||||
let prismaSessions;
|
||||
|
||||
if (searchTerm && typeof searchTerm === "string" && searchTerm.trim() !== "") {
|
||||
const searchConditions = [
|
||||
{ id: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ category: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ initialMsg: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ transcriptContent: { contains: searchTerm, mode: "insensitive" } },
|
||||
];
|
||||
|
||||
prismaSessions = await prisma.session.findMany({
|
||||
where: {
|
||||
OR: searchConditions,
|
||||
},
|
||||
orderBy: {
|
||||
startTime: "desc",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
prismaSessions = await prisma.session.findMany({
|
||||
orderBy: {
|
||||
startTime: "desc",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const sessions: ChatSession[] = prismaSessions.map(ps => ({
|
||||
...ps,
|
||||
sessionId: ps.id,
|
||||
startTime: new Date(ps.startTime),
|
||||
endTime: ps.endTime ? new Date(ps.endTime) : null,
|
||||
createdAt: new Date(ps.createdAt),
|
||||
updatedAt: new Date(ps.updatedAt),
|
||||
userId: ps.userId === undefined ? null : ps.userId,
|
||||
category: ps.category === undefined ? null : ps.category,
|
||||
language: ps.language === undefined ? null : ps.language,
|
||||
country: ps.country === undefined ? null : ps.country,
|
||||
ipAddress: ps.ipAddress === undefined ? null : ps.ipAddress,
|
||||
sentiment: ps.sentiment === undefined ? null : ps.sentiment,
|
||||
messagesSent: ps.messagesSent === undefined ? undefined : ps.messagesSent,
|
||||
avgResponseTime: ps.avgResponseTime === undefined ? null : ps.avgResponseTime,
|
||||
escalated: ps.escalated === undefined ? undefined : ps.escalated,
|
||||
forwardedHr: ps.forwardedHr === undefined ? undefined : ps.forwardedHr,
|
||||
tokens: ps.tokens === undefined ? undefined : ps.tokens,
|
||||
tokensEur: ps.tokensEur === undefined ? undefined : ps.tokensEur,
|
||||
initialMsg: ps.initialMsg === undefined ? null : ps.initialMsg,
|
||||
fullTranscriptUrl: ps.fullTranscriptUrl === undefined ? null : ps.fullTranscriptUrl,
|
||||
transcriptContent: ps.transcriptContent === undefined ? null : ps.transcriptContent,
|
||||
}));
|
||||
|
||||
return res.status(200).json({ sessions });
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch sessions:", error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "An unknown error occurred";
|
||||
return res.status(500).json({ error: "Failed to fetch sessions", details: errorMessage });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user