Spaces:
Running
Running
# app.py | |
import os | |
import requests # To download the audio file from Twilio's URL | |
from flask import Flask, request | |
from dotenv import load_dotenv | |
# Use the new top-level import and types | |
from google import genai | |
from google.genai import types | |
from twilio.twiml.messaging_response import MessagingResponse | |
# --- Define Calculator Functions for the Model to Use --- | |
# The SDK uses the function signature (name, parameters) and docstring | |
# to tell the model how and when to use these tools. | |
def add(a: float, b: float): | |
""" | |
Adds two numbers together. | |
Args: | |
a: The first number. | |
b: The second number. | |
""" | |
print(f"Tool Call: add(a={a}, b={b})") | |
return a + b | |
def subtract(a: float, b: float): | |
""" | |
Subtracts the second number from the first. | |
Args: | |
a: The number to subtract from. | |
b: The number to subtract. | |
""" | |
print(f"Tool Call: subtract(a={a}, b={b})") | |
return a - b | |
def multiply(a: float, b: float): | |
""" | |
Multiplies two numbers. | |
Args: | |
a: The first number. | |
b: The second number. | |
""" | |
print(f"Tool Call: multiply(a={a}, b={b})") | |
return a * b | |
def divide(a: float, b: float): | |
""" | |
Divides the first number by the second. | |
Args: | |
a: The numerator. | |
b: The denominator. | |
""" | |
print(f"Tool Call: divide(a={a}, b={b})") | |
if b == 0: | |
return "Error: Cannot divide by zero." | |
return a / b | |
# A list of all the functions the model can call | |
calculator_tools = [add, subtract, multiply, divide] | |
# --- Initialize Flask App and APIs --- | |
# Load environment variables from .env file | |
load_dotenv(r"C:\Users\Vaibhav Arora\Documents\MyExperimentsandCodes\APPS_WEBSITES\CANADA_WHOLESALE_PROJECT\GITHUB_REPOS\mvp-vue\wholesale-grocery-app\AIAPPS\.env") | |
app = Flask(__name__) | |
# Configure the Gemini API and initialize the client | |
try: | |
client = genai.Client(api_key=os.environ.get("GEMINI_API_KEY")) | |
print("Gemini client and calculator tools initialized successfully.") | |
except Exception as e: | |
print(f"Error initializing Gemini client: {e}") | |
client = None | |
# --- Define the Webhook Endpoint --- | |
def sms_reply(): | |
"""Respond to incoming text or audio messages, using calculator functions if needed.""" | |
twilio_resp = MessagingResponse() | |
if not client: | |
twilio_resp.message("The AI client is not configured correctly. Please check the server logs.") | |
return str(twilio_resp) | |
# Prepare the contents list for the Gemini API call | |
contents = [] | |
# Check if the incoming message contains media | |
num_media = int(request.values.get('NumMedia', 0)) | |
if num_media > 0: | |
media_url = request.values.get('MediaUrl0') | |
mime_type = request.values.get('MediaContentType0') | |
# Process only if the media is audio | |
if 'audio' in mime_type: | |
print(f"Received audio message. URL: {media_url}, MIME Type: {mime_type}") | |
# Download the audio file from the Twilio URL | |
audio_response = requests.get(media_url) | |
if audio_response.status_code == 200: | |
audio_bytes = audio_response.content | |
audio_part = types.Part.from_bytes(data=audio_bytes, mime_type=mime_type) | |
prompt = "Please transcribe this audio. If it contains a calculation or a question, please answer it." | |
contents = [prompt, audio_part] | |
else: | |
error_message = "Sorry, I couldn't download the audio file to process it. Please try again." | |
twilio_resp.message(error_message) | |
return str(twilio_resp) | |
else: | |
# Handle non-audio media like images or videos | |
twilio_resp.message("Sorry, I can only process text and audio messages.") | |
return str(twilio_resp) | |
else: | |
# Fallback to text message processing | |
incoming_msg = request.values.get('Body', '').strip() | |
print(f"Received text message: '{incoming_msg}'") | |
if not incoming_msg: | |
twilio_resp.message("Please send a text or audio message to get a response.") | |
return str(twilio_resp) | |
contents = [incoming_msg] | |
if not contents: | |
twilio_resp.message("Could not determine content to process. Please send a message.") | |
return str(twilio_resp) | |
try: | |
print("Sending content to Gemini with calculator tools...") | |
# Configure the request to use our calculator functions | |
config = types.GenerateContentConfig(tools=calculator_tools) | |
# The SDK handles the multi-turn process for function calling automatically | |
gemini_response = client.models.generate_content( | |
model="gemini-2.5-flash", | |
contents=contents, # This will contain either text or [prompt, audio_part] | |
config=config, | |
) | |
# This is the final text answer after any function calls have been resolved. | |
ai_answer = gemini_response.text | |
print(f"Gemini final response: '{ai_answer}'") | |
# Add the Gemini response to the TwiML message | |
twilio_resp.message(ai_answer) | |
except Exception as e: | |
print(f"An error occurred with the Gemini API: {e}") | |
# Send a user-friendly error message | |
error_message = "Sorry, I'm having trouble connecting to my brain right now. Please try again later." | |
twilio_resp.message(error_message) | |
return str(twilio_resp) | |
# --- Run the Flask App --- | |
if __name__ == "__main__": | |
app.run(debug=True, port=5000) |