Handling AI Interactions with the Chat Service Layer

In the previous lesson, we explored the ChatManager class, which plays a crucial role in managing chat data within our application. Now, we will take the next step in our journey by building the Chat Service Layer. This layer is essential for integrating the language model with chat sessions, allowing us to process user messages and generate AI responses. By the end of this lesson, you will understand how to set up the ChatService class, create chat sessions, and process messages using OpenAI's API.

The service layer acts as a bridge between the model layer, where data is managed, and the AI model, which generates responses. It is responsible for orchestrating the flow of data and ensuring that user interactions are handled smoothly. Let's dive into the details of setting up this important component.

Setting Up the ChatService Class

The ChatService class is the heart of our service layer. It is responsible for managing chat sessions and interacting with the OpenAI client to generate AI responses. To begin, we need to set up the class and its components.

First, we require the necessary modules, including the ChatManager from our previous lesson and the OpenAI client. We also use the securerandom module to generate unique chat IDs. Here's how the class is initialized:

require 'securerandom'
require 'openai'
require_relative 'models/chat_manager'

class ChatService
  def initialize
    @chat_manager = ChatManager.new
    @openai_client = OpenAI::Client.new(access_token: ENV['OPENAI_API_KEY'], uri_base: ENV['OPENAI_BASE_URL'])
    @system_prompt = load_system_prompt('data/system_prompt.txt')
  end
end

In this setup, we instantiate ChatManager to manage chat data, initialize the OpenAI client, and load the system_prompt using the load_system_prompt method, which we'll discuss next. It's important to note that the OpenAI client is initialized once per instance of ChatService, which is efficient for performance. However, if your API key or base URL is incorrect or missing from the environment variables, this setup will raise an error at runtime. You might consider adding a basic check or a warning log for missing credentials during initialization.

Loading the System Prompt

The system prompt is a crucial component that guides the AI's responses. It provides context and instructions for the AI, ensuring that it behaves in a manner consistent with our application's goals. In this section, we'll implement the load_system_prompt method to load the prompt from a file.

def load_system_prompt(file_path)
  begin
    File.read(file_path)
  rescue => e
    puts "Error loading system prompt: #{e}"
    "You are a helpful assistant."
  end
end

This method attempts to read the system prompt from a specified file path. If successful, it returns the prompt as a string. In case of an error, it prints an error message and returns a default prompt. This ensures that the application can continue functioning even if the file is missing or corrupted.

Creating a New Chat Session

Creating a new chat session is a fundamental task of the ChatService. The create_chat method is responsible for generating a unique chat ID and initializing a chat session using the ChatManager.

def create_chat(user_id)
  chat_id = SecureRandom.uuid
  @chat_manager.create_chat(user_id, chat_id, @system_prompt)
  chat_id
end

In this method, we generate a unique chat_id using the SecureRandom.uuid. We then call the create_chat method of ChatManager, passing the user_id, chat_id, and system_prompt. This initializes a new chat session, which is ready to receive messages.

Processing User Messages

The process_message method is where the magic happens. It processes user messages, interacts with the OpenAI client to generate AI responses, and updates the chat history. Below, we outline the steps involved in this process, followed by the corresponding code implementation:

  1. Retrieve the chat using get_chat, and raise an error if the chat is not found.
  2. Add the user's message to the chat history.
  3. Send the conversation, including the system prompt and all messages, to the OpenAI client to generate a response.
  4. Add the AI's response to the chat history and return it to the user.
  5. Handle any errors with the AI client gracefully.
def process_message(user_id, chat_id, message)
  # Step 1: Retrieve the chat
  chat = @chat_manager.get_chat(user_id, chat_id)
  raise "Chat not found" unless chat

  # Step 2: Add user message to chat history
  @chat_manager.add_message(user_id, chat_id, "user", message)

  begin
    # Step 3: Get AI response
    conversation = @chat_manager.get_conversation(user_id, chat_id)

    response = @openai_client.chat(
      parameters: {
        model: "gpt-4",
        messages: conversation
      }
    )

    ai_message = response.dig("choices", 0, "message", "content").strip

    # Step 4: Add AI response to chat history
    @chat_manager.add_message(user_id, chat_id, "assistant", ai_message)

    ai_message

  rescue => e
    # Step 5: Handle errors
    raise "Error getting AI response: #{e}"
  end
end

In the context of a customer service agent, we configure our model with specific parameters to optimize its performance. The temperature is set to 0.7, which balances creativity and coherence in the AI's responses, ensuring they are both engaging and relevant. The max_tokens is set to 500, allowing the model to provide detailed and informative answers without overwhelming the user, thus maintaining a smooth and effective customer service experience.

Example: Simulating a Chat Session

Let's see the ChatService in action by simulating a chat session. We'll use the main.rb file to create a chat session and process a user message.

require_relative 'services/chat_service'

# Initialize the chat service
chat_service = ChatService.new

# Simulate a user ID
user_id = "user123"

# Create a new chat session
chat_id = chat_service.create_chat(user_id)
puts "Chat session created with ID: #{chat_id}"

# Simulate sending a message
user_message = "Hello, how are you?"

begin
  ai_response = chat_service.process_message(user_id, chat_id, user_message)
  puts "AI Response: #{ai_response}"
rescue => e
  puts "Error: #{e}"
end

In this example, we initialize the ChatService, simulate a user ID, and create a new chat session, printing the chat ID. We then simulate sending a message and print the AI's response, demonstrating the flow from user input to AI response and showcasing the functionality of the ChatService.

Chat session created with ID: 01a17870-8a4f-4b6f-a3ce-f04e1136d597
AI Response: Hello! I'm here to help with any questions or concerns you might have regarding our IT services. How can I assist you today?

This output illustrates a successful interaction where a new chat session is created, and the AI responds to the user's greeting with a helpful message. The AI's response is tailored to assist with IT services, showcasing the system's ability to provide relevant and context-aware assistance.

Summary and Next Steps

In this lesson, we explored the ChatService class and its role in integrating the language model with chat sessions. We learned how to set up the class, load the system prompt, create chat sessions, and process user messages. The service layer is a vital component of our chatbot application, ensuring that user interactions are handled smoothly and efficiently.

As you move on to the practice exercises, take the opportunity to experiment with the ChatService functionality. This hands-on practice will reinforce the concepts covered in this lesson and prepare you for the next steps in our course. Keep up the great work, and I look forward to seeing your progress!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal