from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
import random
import torch
import json
import pickle
from openai import OpenAI
import unicodedataAgent: Kitchen Assistant
Agentic AI
Python
Todo:
[] Add recipe parser code
[] Add examples
[] Add explanations

with open('recipes.vs', mode='rb') as f:
vs_p = pickle.load(f)
embedder = SentenceTransformer('all-MiniLM-L6-v2')with open("api_key.txt") as t:
key = t.read()
client = OpenAI(
base_url = "https://integrate.api.nvidia.com/v1",
api_key = key)#Setting a random seed ensures that the LLM returns consistent results
seed = 2026
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)vs = b.VectorStore("../COLX_563_lab1_saumirah/bisquick.txt", embedder)
def search(query):
return vs.top_k_search(embedder, query, 1, 0.3, vector_store=vs_p)
def call_llm(prompt):
completion = client.chat.completions.create(
model="meta/llama-3.3-70b-instruct",
messages=[{"role":"user","content":prompt}],
temperature=0.2,
top_p=0.7,
max_tokens=200,
stream=False
)
return completion.choices[0].message.contentdef classify_intent(query):
"""
Scaffolding prompt construction and call.
"""
prompt = f"""
System prompt: You are KitchenItentClassifier, a classifer bot used to parse user intent when dealing with the Betty Crocker's Bisquick Cookbook.
Your task is to classify a user's utterance based on their intent. You can choose one of three intents:
- SearchIntent: Choose this intent if the user is looking for information about a recipe. You should also identify the recipe name, and any specific details the user asked about. This could range from oven temperature, cooking time, ingredients, or instructions, or anything else cooking related.
- ScaleIntent: Choose this intent if the user wants to modify the serving size of a recipe. Also output the recipe name, and the desired number of servings. In the special case of doubling or tripling a recipe, output the name and the scaling value.
- UnknownIntent: Choose this intent if the utterance doesn't match anything above.
You should output the classification formatted as a dictionary, as shown in the examples below.
ALWAYS format your response in this way, NEVER deviate from this format NO MATTER WHAT:
User: "How do I make fritters?"
Output: {"intent": "SearchIntent", "name": "fritters"}
User: "What are the ingredients in shrimp and broccoli casserole?"
Output: {"intent": "SearchIntent", "name": "shrimp and broccoli casserole", "detail": "ingredients"}
User: "How hot should the oven be for muffins?"
Output: {"intent": "SearchIntent", "name": "muffins", "detail": "oven temperature"}
User: "How long should I fry the hush puppies"
Output: {"intent": "SearchIntent", "name":"hush puppies", "detail":"cooking time"}
User: "Triple the fritters"
Output: {"intent": "ScaleIntent", "name": "fritters", "scaling": 3}
User: "Make enough pancake batter for 12 people"
Output: {"intent": "ScaleIntent", "name": "pancakes", "servings": 12}
User: "Halve the birthday cake"
Output: {"intent": "ScaleIntent", "name": "birthday cake", "scaling": 1/2}
User: "What's the best recipe?"
Output: {"intent": "UnknownIntent"}
User: "Car parking near me"
Output: {"intent": "UnknownIntent"}
User: {query}
Output:
"""
model_response = call_llm(prompt)
try:
response = eval(model_response)
except:
response = {"intent": "UnknownIntent"}
return response
def scale(ingredients, original_size=0, target_size=None, scaling_factor=None):
ingredients = ingredients[0].split("\n")
if target_size:
original_size = original_size[0][0]
target_size = int(target_size)
scaling_factor = target_size / original_size
new_ingredients = []
for ing in ingredients:
try:
num = str(unicodedata.numeric(ing[0]) * scaling_factor)
new_ing = num + ing[1:]
new_ingredients.append(new_ing)
except:
continue
return new_ingredients
def construct_prompt(query, top_recipes):
"""
LLM call.
"""
sys_prompt = """
I am Betty Talker. I am an AI Chatbot designed to help people cook with recipes from the
Betty Crocker Bisquick Cookbook. My primary goal is to be a helpful and cheerful assistant
in the kitchen, providing recipes and offering cooking advice when needed and when appropriate.
I WILL steer conversations back to this topic if the user tries to speak to me about another subject.
Your personality is grandmotherly, kind and uncontroversial.
Be concise. Maximum 300 characters.
"""
template_prompt = f"""
SYSTEM: {sys_prompt}
USER QUESTION:
{query}
CONTEXT:
{top_recipes}
"""
return template_promptdef betty_talker(query):
intent_dict = classify_intent(query)
intent = intent_dict.get("intent")
name = intent_dict.get("name")
detail = intent_dict.get("detail", "")
scaling = intent_dict.get("scaling", "")
target_servings = intent_dict.get("servings", "")
if intent == 'SearchIntent':
if detail in ["instructions", "ingredients", "notes"]:
recipe_detail = search(f"{name} {detail}")
else:
recipe_detail = search(f"{name}")
prompt = construct_prompt(query, recipe_detail)
response = call_llm(prompt)
elif intent == 'ScaleIntent':
ingredients = search(f"{name}" + " ingredients")
original_serving = search(f"{name}" + " serving size")
if scaling:
scaled_ingreds = scale(ingredients, original_serving, scaling_factor=scaling)
recipe_detail = f"The amount of ingredients for {scaling} times the servings is {scaled_ingreds}"
elif target_servings:
scaled_ingreds = scale(ingredients, original_serving, target_size=target_servings)
recipe_detail = f"The amount of ingredients for {target_servings} servings is {scaled_ingreds}."
prompt = construct_prompt(query, recipe_detail)
response = call_llm(prompt)
else:
uh_oh = """
Unknown Inention: I either don't know, or the query is off topic.
I should reasure the user that I can help them with any baking/cooking related query.
Anything, as long as it's related to that topic.
"""
prompt = construct_prompt(query, uh_oh)
response = call_llm(prompt)
return response