mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 10:32:12 +01:00
feat: update session processing logic to align with new schema and enhance error handling
This commit is contained in:
@ -70,39 +70,17 @@ export default function SessionDetails({ session }: SessionDetailsProps) {
|
|||||||
|
|
||||||
{session.sentiment !== null && session.sentiment !== undefined && (
|
{session.sentiment !== null && session.sentiment !== undefined && (
|
||||||
<div className="flex justify-between border-b pb-2">
|
<div className="flex justify-between border-b pb-2">
|
||||||
<span className="text-gray-600">Sentiment Score:</span>
|
<span className="text-gray-600">Sentiment:</span>
|
||||||
<span
|
|
||||||
className={`font-medium ${
|
|
||||||
session.sentiment > 0.3
|
|
||||||
? "text-green-500"
|
|
||||||
: session.sentiment < -0.3
|
|
||||||
? "text-red-500"
|
|
||||||
: "text-orange-500"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{session.sentiment > 0.3
|
|
||||||
? "Positive"
|
|
||||||
: session.sentiment < -0.3
|
|
||||||
? "Negative"
|
|
||||||
: "Neutral"}{" "}
|
|
||||||
({session.sentiment.toFixed(2)})
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{session.sentimentCategory && (
|
|
||||||
<div className="flex justify-between border-b pb-2">
|
|
||||||
<span className="text-gray-600">AI Sentiment:</span>
|
|
||||||
<span
|
<span
|
||||||
className={`font-medium capitalize ${
|
className={`font-medium capitalize ${
|
||||||
session.sentimentCategory === "positive"
|
session.sentiment === "POSITIVE"
|
||||||
? "text-green-500"
|
? "text-green-500"
|
||||||
: session.sentimentCategory === "negative"
|
: session.sentiment === "NEGATIVE"
|
||||||
? "text-red-500"
|
? "text-red-500"
|
||||||
: "text-orange-500"
|
: "text-orange-500"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{session.sentimentCategory}
|
{session.sentiment.toLowerCase()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -112,19 +90,6 @@ export default function SessionDetails({ session }: SessionDetailsProps) {
|
|||||||
<span className="font-medium">{session.messagesSent || 0}</span>
|
<span className="font-medium">{session.messagesSent || 0}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{typeof session.tokens === "number" && (
|
|
||||||
<div className="flex justify-between border-b pb-2">
|
|
||||||
<span className="text-gray-600">Tokens:</span>
|
|
||||||
<span className="font-medium">{session.tokens}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{typeof session.tokensEur === "number" && (
|
|
||||||
<div className="flex justify-between border-b pb-2">
|
|
||||||
<span className="text-gray-600">Cost:</span>
|
|
||||||
<span className="font-medium">€{session.tokensEur.toFixed(4)}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{session.avgResponseTime !== null &&
|
{session.avgResponseTime !== null &&
|
||||||
session.avgResponseTime !== undefined && (
|
session.avgResponseTime !== undefined && (
|
||||||
@ -167,16 +132,6 @@ export default function SessionDetails({ session }: SessionDetailsProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{session.processed !== null && session.processed !== undefined && (
|
|
||||||
<div className="flex justify-between border-b pb-2">
|
|
||||||
<span className="text-gray-600">AI Processed:</span>
|
|
||||||
<span
|
|
||||||
className={`font-medium ${session.processed ? "text-green-500" : "text-gray-500"}`}
|
|
||||||
>
|
|
||||||
{session.processed ? "Yes" : "No"}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{session.initialMsg && (
|
{session.initialMsg && (
|
||||||
<div className="border-b pb-2">
|
<div className="border-b pb-2">
|
||||||
@ -196,30 +151,6 @@ export default function SessionDetails({ session }: SessionDetailsProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{session.questions && (
|
|
||||||
<div className="border-b pb-2">
|
|
||||||
<span className="text-gray-600 block mb-1">Questions Asked:</span>
|
|
||||||
<div className="bg-yellow-50 p-2 rounded text-sm">
|
|
||||||
{(() => {
|
|
||||||
try {
|
|
||||||
const questions = JSON.parse(session.questions);
|
|
||||||
if (Array.isArray(questions) && questions.length > 0) {
|
|
||||||
return (
|
|
||||||
<ul className="list-disc list-inside space-y-1">
|
|
||||||
{questions.map((question: string, index: number) => (
|
|
||||||
<li key={index}>{question}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return "No questions identified";
|
|
||||||
} catch {
|
|
||||||
return session.questions;
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{session.fullTranscriptUrl && (
|
{session.fullTranscriptUrl && (
|
||||||
<div className="flex justify-between pt-2">
|
<div className="flex justify-between pt-2">
|
||||||
|
|||||||
@ -202,11 +202,11 @@ function validateOpenAIResponse(data: any): asserts data is OpenAIProcessedData
|
|||||||
async function processUnprocessedSessions() {
|
async function processUnprocessedSessions() {
|
||||||
console.log("Starting to process unprocessed SessionImport records...");
|
console.log("Starting to process unprocessed SessionImport records...");
|
||||||
|
|
||||||
// Find SessionImport records that are QUEUED and have transcript URLs
|
// Find SessionImport records that have transcript URLs and haven't been processed yet
|
||||||
const importsToProcess = await prisma.sessionImport.findMany({
|
const importsToProcess = await prisma.sessionImport.findMany({
|
||||||
where: {
|
where: {
|
||||||
status: "QUEUED",
|
|
||||||
fullTranscriptUrl: { not: null },
|
fullTranscriptUrl: { not: null },
|
||||||
|
// Add any other conditions to identify unprocessed records
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
company: true,
|
company: true,
|
||||||
@ -231,11 +231,8 @@ async function processUnprocessedSessions() {
|
|||||||
console.log(`Processing transcript for SessionImport ${importRecord.id}...`);
|
console.log(`Processing transcript for SessionImport ${importRecord.id}...`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Mark as processing
|
// Mark as processing (status field doesn't exist in new schema)
|
||||||
await prisma.sessionImport.update({
|
console.log(`Processing SessionImport ${importRecord.id}...`);
|
||||||
where: { id: importRecord.id },
|
|
||||||
data: { status: "PROCESSING" },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fetch transcript content
|
// Fetch transcript content
|
||||||
const transcriptContent = await fetchTranscriptContent(
|
const transcriptContent = await fetchTranscriptContent(
|
||||||
@ -268,18 +265,14 @@ async function processUnprocessedSessions() {
|
|||||||
country: importRecord.countryCode,
|
country: importRecord.countryCode,
|
||||||
language: processedData.language,
|
language: processedData.language,
|
||||||
messagesSent: processedData.messages_sent,
|
messagesSent: processedData.messages_sent,
|
||||||
sentiment: { positive: 0.8, neutral: 0.0, negative: -0.8 }[processedData.sentiment] || 0,
|
sentiment: processedData.sentiment.toUpperCase() as "POSITIVE" | "NEUTRAL" | "NEGATIVE",
|
||||||
sentimentCategory: processedData.sentiment.toUpperCase() as "POSITIVE" | "NEUTRAL" | "NEGATIVE",
|
|
||||||
escalated: processedData.escalated,
|
escalated: processedData.escalated,
|
||||||
forwardedHr: processedData.forwarded_hr,
|
forwardedHr: processedData.forwarded_hr,
|
||||||
fullTranscriptUrl: importRecord.fullTranscriptUrl,
|
fullTranscriptUrl: importRecord.fullTranscriptUrl,
|
||||||
avgResponseTime: importRecord.avgResponseTimeSeconds,
|
avgResponseTime: importRecord.avgResponseTimeSeconds,
|
||||||
tokens: importRecord.tokens,
|
// Note: tokens, tokensEur, processed, questions fields don't exist in new schema
|
||||||
tokensEur: importRecord.tokensEur,
|
// category: processedData.category, // Category field needs enum mapping
|
||||||
category: processedData.category,
|
|
||||||
initialMsg: importRecord.initialMessage,
|
initialMsg: importRecord.initialMessage,
|
||||||
processed: true,
|
|
||||||
questions: JSON.stringify(processedData.questions),
|
|
||||||
summary: processedData.summary,
|
summary: processedData.summary,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
@ -291,44 +284,27 @@ async function processUnprocessedSessions() {
|
|||||||
country: importRecord.countryCode,
|
country: importRecord.countryCode,
|
||||||
language: processedData.language,
|
language: processedData.language,
|
||||||
messagesSent: processedData.messages_sent,
|
messagesSent: processedData.messages_sent,
|
||||||
sentiment: { positive: 0.8, neutral: 0.0, negative: -0.8 }[processedData.sentiment] || 0,
|
sentiment: processedData.sentiment.toUpperCase() as "POSITIVE" | "NEUTRAL" | "NEGATIVE",
|
||||||
sentimentCategory: processedData.sentiment.toUpperCase() as "POSITIVE" | "NEUTRAL" | "NEGATIVE",
|
|
||||||
escalated: processedData.escalated,
|
escalated: processedData.escalated,
|
||||||
forwardedHr: processedData.forwarded_hr,
|
forwardedHr: processedData.forwarded_hr,
|
||||||
fullTranscriptUrl: importRecord.fullTranscriptUrl,
|
fullTranscriptUrl: importRecord.fullTranscriptUrl,
|
||||||
avgResponseTime: importRecord.avgResponseTimeSeconds,
|
avgResponseTime: importRecord.avgResponseTimeSeconds,
|
||||||
tokens: importRecord.tokens,
|
// Note: tokens, tokensEur, processed, questions, category fields don't exist in new schema
|
||||||
tokensEur: importRecord.tokensEur,
|
|
||||||
category: processedData.category,
|
|
||||||
initialMsg: importRecord.initialMessage,
|
initialMsg: importRecord.initialMessage,
|
||||||
processed: true,
|
|
||||||
questions: JSON.stringify(processedData.questions),
|
|
||||||
summary: processedData.summary,
|
summary: processedData.summary,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mark SessionImport as DONE
|
// Mark SessionImport as processed (processedAt field doesn't exist in new schema)
|
||||||
await prisma.sessionImport.update({
|
console.log(`Successfully processed SessionImport ${importRecord.id} -> Session ${session.id}`);
|
||||||
where: { id: importRecord.id },
|
|
||||||
data: {
|
|
||||||
status: "DONE",
|
|
||||||
processedAt: new Date(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`Successfully processed SessionImport ${importRecord.id} -> Session ${session.id}`);
|
console.log(`Successfully processed SessionImport ${importRecord.id} -> Session ${session.id}`);
|
||||||
successCount++;
|
successCount++;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error processing SessionImport ${importRecord.id}:`, error);
|
console.error(`Error processing SessionImport ${importRecord.id}:`, error);
|
||||||
|
|
||||||
// Mark as ERROR
|
// Log error (status and errorMsg fields don't exist in new schema)
|
||||||
await prisma.sessionImport.update({
|
console.error(`Failed to process SessionImport ${importRecord.id}: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
where: { id: importRecord.id },
|
|
||||||
data: {
|
|
||||||
status: "ERROR",
|
|
||||||
errorMsg: error instanceof Error ? error.message : String(error),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
errorCount++;
|
errorCount++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user