Salesforce Custom Conversation Summary with LLM Model Selection

Salesforce Custom Conversation Summary with LLM Model Selection

Salesforce Models API can be used for LLM Model selection for conversation summary.

In this Blog Post, I have used Custom Metadata Type to store the Model Name and API Name.

Custom Metadata Type for LLM Models:

We can make use of Connect REST API to get/fetch the Conversation Entries for the Messaging Session record.

Steps:

1. Create a Connected App. In the Callback URL, use a temporary URL. The temporary URL should be updated later after completing the Step 2. Get the Callback URL from the Auth. Provider and update it.

2. Create an Auth. Provider.

Don’t forget to update the Callback URL in the connected app.

3. Create a Named Credential.

Sample Code:

Apex Class for the Lightning Web Component:

public class ConversationSummaryController {
    
    @AuraEnabled( cacheable = true )
    public static String summarizeEntries( 
        String strMessagingSessionId,
        String selectedModel
    ) {
        
        String strResponse;
        String strConcatenatedMessages = 'Summarize the following:\n';
        
        // Fetching Messaging Session record
        MessagingSession objMS = [
            SELECT Conversation.ConversationIdentifier, ConversationId
            FROM MessagingSession
            WHERE Id =: strMessagingSessionId
        ];
        System.debug(
            'ConversationIdentifier is ' + 
            objMS.Conversation.ConversationIdentifier
        );
        
        // GET Request to Connect API
        Http h = new Http();  
        HttpRequest req = new HttpRequest();  
        req.setEndpoint( 
            'callout:Fetch_Conversation_Entries' + 
            '/services/data/v60.0/connect/conversation/' + 
            objMS.Conversation.ConversationIdentifier + 
            '/entries?queryDirection=FromStart' 
        );  
        req.setMethod( 'GET' );  
        HttpResponse res = h.send(req);  
        system.debug( 
            'Conversation Entries are ' + res.getBody() 
        );  
        
        Map < String, Object > jsonMap = 
            ( Map < String, Object > )JSON.deserializeUntyped( res.getBody() );
        
        List < Object > conversationEntries = ( List < Object > ) jsonMap.get( 'conversationEntries' );
        
        for ( Object objEntry : conversationEntries ) {
            
            Map < String, Object > entryMap = ( Map < String, Object > ) objEntry;
            Map < String, Object > senderMap = ( Map < String, Object > ) entryMap.get( 'sender' );
            strConcatenatedMessages += ( String ) entryMap.get( 'messageText' ) + '\n';
            
        }
        
        // Creating generate text request
        aiplatform.ModelsAPI.createGenerations_Request request = 
            new aiplatform.ModelsAPI.createGenerations_Request();
        
        // Specifying model 
        System.debug( 'selectedModel is:' + selectedModel );
        request.modelName = selectedModel;
        
        // Create request body
        aiplatform.ModelsAPI_GenerationRequest requestBody = 
            new aiplatform.ModelsAPI_GenerationRequest();
        request.body = requestBody;
        
        // Add prompt to body
        requestBody.prompt = strConcatenatedMessages;
        
        try {
            
            // Invoking the Models API
            aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI();
            aiplatform.ModelsAPI.createGenerations_Response response =
                modelsAPI.createGenerations(request);
            System.debug(
                'Models API response: ' + 
                response.Code200.generation.generatedText
            );
            strResponse = response.Code200.generation.generatedText;
        
        // Handling Exception
        } catch( aiplatform.ModelsAPI.createGenerations_ResponseException e ) {
            
            System.debug(
                'Response code: ' + 
                e.responseCode
            );
            System.debug(
                'The following exception occurred: ' + e
            );
            strResponse = e.toString();
            
        }
        
        return strResponse;
        
    }

}

Sample Lightning Web Component:

HTML:

<template>
    <lightning-card title="Conversation Summary" icon-name="standard:conversation">
        <div class="slds-m-around_medium">
            <div style="width: 250px;">
                <lightning-combobox
                    name="Select Model"
                    label="Select Model"
                    value={selectedModel}
                    placeholder="Select Model"
                    options={modelOptions}
                    onchange={handleChange}>
                </lightning-combobox>
                <br/>
            </div>
            <template if:true={conversationSummary}>
                <p>{conversationSummary}</p>
            </template>
        </div>
        <div slot="footer">
            <template if:true={selectedModel}>
                <lightning-button 
                    label="Summarize" 
                    title="Summarize" 
                    icon-name="utility:refresh" 
                    icon-position="right" 
                    onclick={summarizeConversation}>
                </lightning-button>
            </template>
        </div>
    </lightning-card>
</template>

JavaScript:

import { LightningElement, api, wire } from 'lwc';
import { gql, graphql } from 'lightning/uiGraphQLApi';
import summarizeEntries from '@salesforce/apex/ConversationSummaryController.summarizeEntries';

export default class ConversationSummary extends LightningElement {

    @api recordId;
    conversationSummary;
    selectedModel;

    @wire( graphql, {
        query: gql`
            query getSamples {
                uiapi {
                    query {
                        LLM__mdt {
                            edges {
                                node {
                                    MasterLabel {
                                        value
                                    }
                                    Value__c : Value__c {
                                        value
                                    }
                                }
                            }
                        }
                    }
                }
            }
        `
    } )
    graphql;

    get modelOptions() {

        console.log( this.graphql );
        return this.graphql.data?.uiapi.query.LLM__mdt.edges.map(
            ( edge ) => ( {
                label: edge.node.MasterLabel.value,
                value: edge.node.Value__c.value
            }
        ) );
    }

    handleChange( event ) {
        this.selectedModel = event.target.value;
    }

    summarizeConversation() {

        summarizeEntries( { 
            strMessagingSessionId: this.recordId,
            selectedModel: this.selectedModel
        } )    
        .then( result => {  
            
            console.log( 'result is', JSON.stringify( result ) );
            this.conversationSummary = result;  

        } )  
        .catch( error => {  
            
            console.log( 'Error Occured', JSON.stringify( error ) );
            this.error = error;  

        } );  

    }

}

js-meta.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>63.0</apiVersion>
    <isExposed>true</isExposed> 
    <targets> 
        <target>lightning__RecordPage</target> 
    </targets> 
</LightningComponentBundle>

Output:

Leave a Reply