Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/models/conversation.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ const conversationSchema = new mongoose.Schema<IConversation, ConversationModel>
resources: {
type: [resourceSchema],
default: []
},
summary: {
type: String,
default: ''
}
},
{
Expand Down
59 changes: 59 additions & 0 deletions src/services/conversation.service/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,24 @@ import schedule from '../../jobs/schedule.js'
import defineJob from '../../jobs/define.js'
import logger from '../../config/logger.js'
import adapterService from '../adapter.service.js'
import { getChatPromptResponse } from '../../agents/helpers/llmChain.js'
import { coreLLMModel, coreLLMPlatform, getModelChat } from '../../agents/helpers/getModelChat.js'
import { Conversation, User } from '../../models/index.js'
import { formatTranscript, formatMultiUserConversationHistory } from '../../agents/helpers/llmInputFormatters.js'
import getConversationHistory from '../../agents/helpers/getConversationHistory.js'

const transcriptBatchInterval = 30
const SUMMARIZATION_PROMPT = `
Please summarize what happened during this conversation. Where possible, also draw conclusions about outcomes of the discussion.
When available, use as reference the listed speaker(s), moderator(s) and their bios, and event description.

- **IMPORTANT**: you are summarizing for the event attendees. You are not worried about things like engagement or metrics. You want to provide a clear and concise summary of the key points and outcomes in a digestible format.
- **LENGTH**: write no more than three paragraphs. Be selective — prioritize the most significant points and outcomes over completeness.
- The tone is friendly and conversational.
- The event content will be made up of a transcript as well as participant messages.
- The transcript is drawing from what was said by the speakers in the event, or in some cases might be a video presentation of some kind. Be aware that speakers are generally allowed to use whatever media they would like during the conversation.
- The participant messages are from attendees in a group chat either on Zoom or within a custom-built front-end app.
- Participants might want to know what other participants were saying relative to the event wrap-up.`

export const updateTranscriptStatus = async (
conversation,
Expand Down Expand Up @@ -68,8 +84,51 @@ export async function doStopConversation(conversation) {
await adapterService.stop(adapter)
}
doc.active = false

if (doc.transcript) {
await updateTranscriptStatus(doc, 'stopped')
const owner = await User.findById(conversation.owner)

if (owner) {
const conversationDoc = await Conversation.findOne({ _id: conversation._id }).populate('channels').populate({ path: 'messages', match: { channels: { $in: ['transcript', 'chat'] } } })

if (conversationDoc) {
const llm = await getModelChat(coreLLMPlatform, coreLLMModel, {maxTokens: 2000})
const sortedMessages = conversationDoc.messages.sort(
(a, b) => (a.createdAt?.getTime() ?? 0) - (b.createdAt?.getTime() ?? 0)
)
const transcriptMessages = sortedMessages.filter((m) => m.channels?.includes('transcript'))
const transcript = formatTranscript(transcriptMessages, 'UTC')

const chatHistory = getConversationHistory(sortedMessages, { channels: ['chat'] })
const sharedChat =
formatMultiUserConversationHistory(chatHistory)
.map((m) => (m.role === 'assistant' ? `Assistant: ${m.content}` : m.content))
.join('\n') || 'No shared chat messages yet.'

// Get speaker and moderator information if available
const speakers = `${conversationDoc.presenters?.map((p) => `${p.name}: ${p.bio}`).join(', ')}` || 'Not provided'
const moderators = `${conversationDoc.moderators?.map((m) => `${m.name}: ${m.bio}`).join(', ')}` || 'Not provided'
const eventDescription = conversationDoc.description || 'Not provided'

const structuredSummary = await getChatPromptResponse(
llm,
SUMMARIZATION_PROMPT,
`
Event Transcript: {transcript},
Shared Chat: {sharedChat},
Speaker(s): {speakers},
Moderator(s): {moderators},
Event Description: {eventDescription}
`,
{ transcript, sharedChat, speakers, moderators, eventDescription }
)

logger.debug(`Conversation summary generated for conversation ${doc._id}`)

doc.summary = structuredSummary
} else logger.warn(`No conversation document found for conversation ${doc._id}`)
} else logger.warn(`No owner found for conversation ${doc._id}`)
}
await doc.save()
return doc
Expand Down
1 change: 1 addition & 0 deletions src/types/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ export interface IConversation {
createdAt?: Date
updatedAt?: Date
messageCount(): number
summary?: string
}

export interface IPoll {
Expand Down
Loading