MISTRAL - CHATBOT
Simon-Pierre Boucher
2024-09-14

This code defines a ChatBot class that interacts with Mistral's API to generate conversational text responses. Here's a detailed summary of how the code works:

1. Environment Setup:

  • The environment variables are loaded from a .env file using load_dotenv().
  • The API key is fetched using os.getenv("MISTRAL_API_KEY").

2. ChatBot Class:

  • The ChatBot class is initialized with various parameters, including:
    • api_key: The Mistral API key.
    • model: The model to use for text generation (e.g., codestral-mamba-latest by default).
    • temperature and top_p: Control randomness and diversity of the output.
    • max_tokens, min_tokens: Set token limits for the generated response.
    • tool_choice, safe_prompt: Options for tool integration and safety prompts.
  • It keeps track of the conversation history in self.conversation_history, which is a list of all messages exchanged during the conversation.

3. Adding Messages:

  • The method add_message() appends a message to the conversation history with two parameters:
    • role: Specifies who is sending the message ("user" or "assistant").
    • content: The actual text of the message.

4. Getting Responses:

  • The method get_response() takes the user input, adds it to the conversation history, and then calls the generate_mistral_text() method to get a response from the Mistral API.
  • The response (the assistant's message) is extracted from the API result and added back to the conversation history.
  • It then returns the assistant's reply to the user. If an error occurs during the API call, an error message is displayed.

5. Mistral Text Generation:

  • The generate_mistral_text() method sends a POST request to the Mistral API to generate a text response. It uses the following key parameters:
    • model: The specific AI model to use.
    • messages: A list of conversation messages (history), including both the user's inputs and previous assistant replies.
    • Optional settings: Parameters like temperature, top_p, max_tokens, stop, random_seed allow customization of the response generation process.
  • The API request is sent using the requests.post() method, with error handling to catch and print any request-related issues.

6. Example Usage:

  • A ChatBot instance is created with a specific model (mistral-large-latest) and the settings for text generation.
  • The user input "Can you suggest 5 dinner ideas for this week?" is passed to the get_response() method.
  • The bot generates a response, and it is printed.

Summary of Workflow:

  1. User input is received.
  2. User message is added to conversation history.
  3. API request is sent to Mistral with the entire conversation history.
  4. Assistant's response is extracted from the API's response.
  5. Response is added to the conversation history and printed.

This implementation allows for dynamic, ongoing conversations with Mistral's text-generation API by maintaining a history of interactions and building context over multiple turns of dialogue.

In [2]:
import os
import requests
from dotenv import load_dotenv
from IPython.display import display, HTML
import re

# Charger les variables d'environnement depuis le fichier .env
load_dotenv()
# Obtenir la clé API depuis les variables d'environnement
api_key = os.getenv("MISTRAL_API_KEY")
In [3]:
import requests

class ChatBot:
    def __init__(self, api_key, model="codestral-mamba-latest", temperature=0.7, top_p=1.0, max_tokens=None, min_tokens=None, stream=False, stop=None, random_seed=None, tool_choice="auto", safe_prompt=False):
        """
        Initialize the ChatBot with API key and parameters.
        
        Parameters:
        - api_key (str): The API key for Mistral.
        - model (str): The model to use for text generation.
        - temperature (float): Controls randomness in the output (0-1.5).
        - top_p (float): Nucleus sampling (0-1).
        - max_tokens (int): The maximum number of tokens to generate in the completion.
        - min_tokens (int): The minimum number of tokens to generate in the completion.
        - stream (bool): Whether to stream back partial progress.
        - stop (str or list): Stop generation if this token or one of these tokens is detected.
        - random_seed (int): The seed to use for random sampling.
        - tool_choice (str): Tool choice for the response ("auto", "none", "any").
        - safe_prompt (bool): Whether to inject a safety prompt before all conversations.
        """
        self.api_key = api_key
        self.model = model
        self.temperature = temperature
        self.top_p = top_p
        self.max_tokens = max_tokens
        self.min_tokens = min_tokens
        self.stream = stream
        self.stop = stop
        self.random_seed = random_seed
        self.tool_choice = tool_choice
        self.safe_prompt = safe_prompt
        self.conversation_history = []

    def add_message(self, role, content):
        """
        Add a message to the conversation history.
        
        Parameters:
        - role (str): The role of the sender ("system", "user", or "assistant").
        - content (str): The content of the message.
        """
        self.conversation_history.append({"role": role, "content": content})

    def get_response(self, user_input):
        """
        Get a response from the Mistral API based on the user input.
        
        Parameters:
        - user_input (str): The user's input message.
        
        Returns:
        - assistant_reply (str): The assistant's generated response.
        """
        # Add user input to conversation history
        self.add_message("user", user_input)

        # Call the Mistral API to get a response
        response = self.generate_mistral_text(
            self.api_key,
            self.model,
            self.conversation_history,
            temperature=self.temperature,
            top_p=self.top_p,
            max_tokens=self.max_tokens,
            min_tokens=self.min_tokens,
            stream=self.stream,
            stop=self.stop,
            random_seed=self.random_seed,
            tool_choice=self.tool_choice,
            safe_prompt=self.safe_prompt
        )

        if response:
            # Extract the assistant's reply
            assistant_reply = response.get("choices", [])[0].get("message", {}).get("content", "No reply found.")
            # Add assistant's reply to conversation history
            self.add_message("assistant", assistant_reply)
            return assistant_reply
        else:
            return "Sorry, I couldn't generate a response."

    def generate_mistral_text(self, api_key, model, messages, temperature=0.7, top_p=1.0, max_tokens=None, min_tokens=None, stream=False, stop=None, random_seed=None, tool_choice="auto", safe_prompt=False):
        """
        Generate text using Mistral's API.
        
        Parameters:
        - api_key (str): The API key for Mistral.
        - model (str): The model to use for text generation.
        - messages (list): A list of messages to pass to the API in a conversation format.
        - temperature (float): Controls randomness in the output (0-1.5).
        - top_p (float): Nucleus sampling (0-1).
        - max_tokens (int): The maximum number of tokens to generate in the completion.
        - min_tokens (int): The minimum number of tokens to generate in the completion.
        - stream (bool): Whether to stream back partial progress.
        - stop (str or list): Stop generation if this token or one of these tokens is detected.
        - random_seed (int): The seed to use for random sampling.
        - tool_choice (str): Tool choice for the response ("auto", "none", "any").
        - safe_prompt (bool): Whether to inject a safety prompt before all conversations.
        
        Returns:
        - response (dict): The API response as a dictionary.
        """
        url = "https://api.mistral.ai/v1/chat/completions"
        headers = {
            "Content-Type": "application/json",
            "Accept": "application/json",
            "Authorization": f"Bearer {api_key}"
        }
        data = {
            "model": model,
            "messages": messages,
            "temperature": temperature,
            "top_p": top_p,
            "stream": stream,
            "tool_choice": tool_choice,
            "safe_prompt": safe_prompt
        }

        # Optional parameters
        if max_tokens is not None:
            data["max_tokens"] = max_tokens
        if min_tokens is not None:
            data["min_tokens"] = min_tokens
        if stop is not None:
            data["stop"] = stop
        if random_seed is not None:
            data["random_seed"] = random_seed

        try:
            response = requests.post(url, headers=headers, json=data)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"An error occurred: {e}")
            return None
In [4]:
bot = ChatBot(api_key, model="mistral-large-latest", temperature=0.7, top_p=1.0, max_tokens=2000)
In [5]:
user_input = "Can you suggest 5 dinner ideas for this week?"
response = bot.get_response(user_input)
print("Assistant:", response)
Assistant: Absolutely, I'd be happy to help you plan your dinners for the week. Here are five dinner ideas that offer a mix of flavors and ease of preparation:

1. **Monday - One-Pot Lemon Herb Chicken and Rice**
   - Sauté chicken breasts in a large pot, then set them aside.
   - In the same pot, cook rice with chicken broth, lemon zest, lemon juice, garlic, and herbs like thyme and rosemary.
   - Once the rice is almost done, nestle the chicken back into the pot and let it finish cooking.

2. **Tuesday - Vegetarian Stuffed Bell Peppers**
   - Halve bell peppers lengthwise and remove seeds.
   - Fill them with a mixture of cooked quinoa, black beans, corn, diced tomatoes, onion, and your choice of seasoning.
   - Bake until the peppers are tender and serve with a side salad.

3. **Wednesday - Baked Salmon with Asparagus**
   - Place salmon fillets on a baking sheet, season with salt, pepper, lemon slices, and dill.
   - Toss asparagus with olive oil, salt, and pepper, and arrange them around the salmon.
   - Bake until the salmon is cooked through and the asparagus is tender.

4. **Thursday - Easy Bolognese with Pasta**
   - Brown some ground beef or turkey in a pan, then add onions, garlic, and carrots.
   - Stir in canned tomatoes, tomato paste, and Italian seasoning. Let it simmer.
   - Serve over your favorite pasta with a side of garlic bread.

5. **Friday - Sheet Pan Fajitas**
   - Slice bell peppers, onions, and chicken breast. Toss them with olive oil, fajita seasoning, salt, and pepper.
   - Spread the mixture evenly on a sheet pan and bake until the chicken is cooked through and the vegetables are tender.
   - Serve with warm tortillas, sour cream, guacamole, and fresh salsa.

Enjoy your week of meals! Remember, you can always adjust these ideas based on your dietary needs and preferences.
In [6]:
user_input = "Can you give me the recipe for the first idea?"
response = bot.get_response(user_input)
print("Assistant:", response)
Assistant: Certainly! Here's a more detailed recipe for the One-Pot Lemon Herb Chicken and Rice:

**Ingredients:**

* 4 boneless, skinless chicken breasts
* Salt and pepper, to taste
* 2 tbsp olive oil
* 1 small onion, finely chopped
* 2 cloves garlic, minced
* 1 cup uncooked long-grain white rice
* 2 cups low-sodium chicken broth
* Zest and juice of 1 lemon
* 1 tsp dried thyme (or 1 tbsp fresh thyme leaves)
* 1 tsp dried rosemary (or 1 tbsp fresh rosemary, finely chopped)
* 1 bay leaf
* Fresh parsley, chopped (for garnish)

**Instructions:**

1. **Season the chicken:** Pat the chicken breasts dry with paper towels and season both sides with salt and pepper.

2. **Sauté the chicken:** Heat the olive oil in a large, deep skillet or Dutch oven over medium-high heat. Add the chicken breasts and cook until browned, about 5-7 minutes per side. Remove the chicken from the skillet and set it aside.

3. **Cook the onion and garlic:** In the same skillet, add the chopped onion and cook until softened, about 5 minutes. Add the minced garlic and cook for an additional 1 minute, stirring frequently to prevent burning.

4. **Add the rice and herbs:** Stir in the uncooked rice, chicken broth, lemon zest, lemon juice, thyme, rosemary, and bay leaf. Bring the mixture to a boil.

5. **Cook the rice:** Once boiling, reduce the heat to low, cover the skillet, and let the rice simmer for about 15 minutes, or until most of the liquid has been absorbed and the rice is almost cooked.

6. **Add the chicken back in:** Nestle the chicken breasts back into the skillet, on top of the rice. Spoon some of the rice and liquid over the chicken. Cover the skillet again and cook for an additional 15-20 minutes, or until the chicken is cooked through and the rice is tender.

7. **Rest and serve:** Remove the skillet from the heat and let the dish rest, covered, for 10 minutes. This will allow the flavors to meld and the liquid to distribute evenly. Garnish with chopped fresh parsley before serving.

Enjoy your One-Pot Lemon Herb Chicken and Rice! This dish pairs well with a side of steamed vegetables or a simple green salad.
In [7]:
user_input = "Can you give me the recipe for the second idea?"
response = bot.get_response(user_input)
print("Assistant:", response)
Assistant: Of course! Here's a detailed recipe for the Vegetarian Stuffed Bell Peppers:

**Ingredients:**

* 4 large bell peppers, any color, halved lengthwise and seeds removed
* 1 cup cooked quinoa
* 1 can (15 oz) black beans, drained and rinsed
* 1 cup frozen corn, thawed
* 1 cup diced tomatoes (canned or fresh)
* ½ small onion, finely chopped
* 2 cloves garlic, minced
* 1 tsp ground cumin
* 1 tsp chili powder
* ½ tsp smoked paprika (optional)
* Salt and pepper, to taste
* 1 cup shredded cheese (e.g., cheddar, Monterey Jack, or Mexican blend), plus extra for topping
* 2 tbsp olive oil
* 2 tbsp fresh cilantro, chopped (for garnish)
* Optional toppings: sour cream, Greek yogurt, avocado, or guacamole

**Instructions:**

1. **Preheat the oven:** Preheat your oven to 375°F (190°C) and lightly grease a baking dish large enough to hold the bell pepper halves.

2. **Prepare the filling:** In a large bowl, combine the cooked quinoa, black beans, corn, diced tomatoes, chopped onion, minced garlic, cumin, chili powder, smoked paprika (if using), salt, and pepper. Mix well to combine. Stir in the shredded cheese.

3. **Stuff the bell peppers:** Place the bell pepper halves in the prepared baking dish, cut side up. Spoon the quinoa and bean mixture evenly into each pepper half, pressing down gently to compact the filling.

4. **Bake:** Drizzle the olive oil over the stuffed peppers and cover the baking dish with foil. Bake for 30 minutes. Remove the foil, sprinkle additional shredded cheese on top of each pepper, and bake for an additional 10-15 minutes, or until the peppers are tender and the cheese is melted and golden.

5. **Serve:** Let the stuffed bell peppers cool for a few minutes before serving. Garnish with chopped fresh cilantro and your choice of optional toppings, such as sour cream, Greek yogurt, avocado, or guacamole.

Enjoy your Vegetarian Stuffed Bell Peppers! You can serve them with a side salad or some crusty bread to complete the meal.

**Tip:** To make this dish vegan, simply omit the cheese or use a plant-based cheese alternative. You can also customize the filling ingredients based on your preferences or what you have on hand.