FitBot – Un agente chatbot per il fitness

FitBot - Chatbot for fitness

Come Creare un Agente di Chatbot Utilizzando la Chiamata di Funzioni di OpenAI

Foto di Gary Butterfield su Unsplash

Introduzione

In un’era in cui la consapevolezza della salute è al centro dell’attenzione e la ricerca di uno stile di vita equilibrato è diventata un’aspirazione universale, la nutrizione rappresenta indubbiamente un pilastro centrale.

Tuttavia, la complessità dei piani alimentari e l’abbondanza di dati nutrizionali spesso rappresentano ostacoli nel nostro percorso per raggiungere questo equilibrio. Un esempio comune di tale scenario è rappresentato dalle persone affette da diabete, che necessitano di una guida alimentare costante e accurata per gestire efficacemente i livelli di zucchero nel sangue. Non sarebbe trasformativo avere accesso a un assistente nutrizionale personalizzato a nostra disposizione digitale?

In questo contesto, sfruttare la tecnologia per assistere nella guida nutrizionale diventa non solo vantaggioso, ma essenziale. Integrando l’intelligenza artificiale all’avanguardia con un database nutrizionale completo, è possibile creare uno strumento potente che può assistere le persone nel loro percorso di salute.

**Il codice per questo progetto si trova in questo repository GitHub: link**

Panoramica del Progetto

Il cuore del progetto consiste nella creazione di un chatbot, chiamato FitBot, che è alimentato dalle funzioni di OpenAI e si basa sul framework ReAct (Reasoning and Acting) (Figura 1).

È progettato per fornire informazioni e consigli nutrizionali, raggiungendo questo obiettivo interpretando le abitudini alimentari dell’utente e integrando un’API di dati nutrizionali.

Approccio Tecnico

Sfruttando il framework ReAct, FitBot mantiene la natura interattiva di una conversazione e può fornire una spiegazione dettagliata per ogni consiglio che fornisce. Si collega anche a un database nutrizionale esterno, garantendo consigli alimentari accurati e aggiornati.

Figura 1: ReAct combina il ragionamento (ad esempio, la motivazione del pensiero) e l'azione. Fonte immagine: link

Dietro le Quinte con FitBot

FitBot combina le capacità di GPT-4 di OpenAI con l’elaborazione dinamica di ReAct per capire le domande dietetiche, suggerire alternative adatte e fornire consigli personalizzati. Tutto questo mantenendo un tono conversazionale, rendendo i consigli nutrizionali accessibili e coinvolgenti.

Ciò che distingue FitBot è la sua capacità di interfacciarsi con un database nutrizionale esterno. Ciò consente a FitBot di fornire informazioni precise e aggiornate agli utenti, garantendo che i consigli forniti siano affidabili e basati su dati accurati.

Nelle prossime sezioni, approfondiremo il codice e vedremo come i componenti di FitBot vengono sviluppati e interagiscono tra loro, offrendo una panoramica completa del funzionamento interno di questo progetto innovativo.

Costruzione di FitBot: Il Codice Spiegato

Questo progetto ha quattro script principali utilizzati per elaborare i dati e visualizzarli in un’interfaccia utente:

  1. fitness_agent.py: Questo file contiene la classe FitnessAgent, che sfrutta le funzioni di OpenAI per abilitare le funzionalità richieste da FitBot.
  2. chatbot.py: Questo file contiene il codice per l’interfaccia utente di FitBot, che viene implementata utilizzando la libreria Gradio.
  3. agents.py: Questo file contiene la classe Agent, che viene utilizzata per gestire le conversazioni con l’API di OpenAI. Questo codice si basa su uno script sviluppato da James Briggs nella libreria funkagent.
  4. parser.py: Questo file contiene il codice per il parsing delle descrizioni delle funzioni in stringhe di documentazione in funzioni di OpenAI.

Definizione delle Nostre Funzioni

Per creare un chatbot in grado di fornire consigli nutrizionali e fitness accurati e utili, abbiamo dovuto considerare quali informazioni sarebbero state più preziose per l’utente finale. Questo è il motivo alla base dell’implementazione delle funzioni spiegate in precedenza.

1. get_nutritional_info: Questa funzione è fondamentale per qualsiasi chatbot orientato al fitness. Le persone spesso non dispongono di informazioni chiare sul contenuto nutrizionale degli alimenti che consumano. Utilizzando l’endpoint Nutrition di API Ninjas per recuperare dati nutrizionali in tempo reale per vari alimenti, possiamo aiutare gli utenti a prendere decisioni alimentari informate. I dati restituiti possono includere dettagli come calorie, proteine, carboidrati, grassi e altro ancora, offrendo una panoramica completa del profilo nutrizionale di un alimento.

def get_nutritional_info(self, query: str) -> dict:    """Recupera le informazioni nutrizionali per un determinato alimento    :param query: L'alimento per cui ottenere le informazioni nutrizionali    :return: Le informazioni nutrizionali dell'alimento    """    api_url = 'https://api.api-ninjas.com/v1/nutrition?query={}'.format(query)    response = requests.get(api_url, headers={'X-Api-Key': self.nut_api_key})    if response.status_code == requests.codes.ok:        return response.json()  # Utilizza json invece di testo per dati più strutturati    else:        return {"Errore": response.status_code, "Messaggio": response.text}

2. calculate_bmr: Il Basal Metabolic Rate (BMR) è una cifra chiave per comprendere il metabolismo di un individuo. È la quantità di energia consumata durante il riposo ed è strettamente correlata all’età, al peso, all’altezza e al sesso. La capacità di calcolare il BMR fornisce all’assistente virtuale una base per aiutare gli utenti a capire quante calorie il loro corpo ha bisogno per funzionare, anche senza alcuna attività fisica.

def calculate_bmr(weight: float, height: float, age: int, gender: str, equation: str = 'mifflin_st_jeor') -> float:    """Calcola il Basal Metabolic Rate (BMR) per una persona    :param weight: Il peso della persona in kg    :param height: L'altezza della persona in cm    :param age: L'età della persona in anni    :param gender: Il sesso della persona ('maschio' o 'femmina')    :param equation: L'equazione da utilizzare per il calcolo del BMR ('harris_benedict' o 'mifflin_st_jeor')    :return: Il BMR della persona    """    if equation.lower() == 'mifflin_st_jeor':        if gender.lower() == 'maschio':            return (10 * weight) + (6.25 * height) - (5 * age) + 5        else:  # 'femmina'            return (10 * weight) + (6.25 * height) - (5 * age) - 161    else:  # 'harris_benedict'        if gender.lower() == 'maschio':            return 88.362 + (13.397 * weight) + (4.799 * height) - (5.677 * age)        else:  # 'femmina'            return 447.593 + (9.247 * weight) + (3.098 * height) - (4.330 * age)

3. calculate_tdee: Comprendere il Total Daily Energy Expenditure (TDEE) è fondamentale per creare una dieta personalizzata o un piano di esercizio. Il TDEE tiene conto non solo del BMR, ma anche delle calorie bruciate durante le attività quotidiane e l’esercizio fisico. Conoscere il proprio TDEE può aiutare gli utenti a pianificare in modo più efficace la propria dieta e routine di esercizio, per mantenere, perdere o aumentare di peso.

def calculate_tdee(bmr: float, activity_level: str) -> float:    """Calcola il Total Daily Energy Expenditure (TDEE) per una persona    :param bmr: Il BMR della persona    :param activity_level: Il livello di attività della persona    ('sedentario', 'poco_attivo', 'moderatamente_attivo', 'molto_attivo', 'super_attivo')    :return: Il TDEE della persona    """    activity_factors = {        'sedentario': 1.2,        'poco_attivo': 1.375,        'moderatamente_attivo': 1.55,        'molto_attivo': 1.725,        'super_attivo': 1.9,    }    return bmr * activity_factors.get(activity_level, 1)

4. calculate_ibw: Conoscere il Peso Corporeo Ideale (IBW) può fornire agli utenti un peso obiettivo considerato salutare per la loro altezza e sesso. Sebbene l’IBW non sia una misura perfetta (non tiene conto di fattori come la massa muscolare), fornisce agli utenti un’idea generale di quale dovrebbe essere il loro peso per una salute ottimale.

def calculate_ibw(height: float, gender: str) -> float:    """Calcola il Peso Corporeo Ideale (IBW)    :param height: L'altezza della persona in pollici    :param gender: Il sesso della persona ("maschio" o "femmina")    :return: Il Peso Corporeo Ideale in kg    """    if gender.lower() == 'maschio':        if height <= 60:  # 5 piedi = 60 pollici            return 50        else:            return 50 + 2.3 * (height - 60)    elif gender.lower() == 'femmina':        if height <= 60:            return 45.5        else:            return 45.5 + 2.3 * (height - 60)    else:        raise ValueError("Sesso non valido. Previsto 'maschio' o 'femmina'.")

4. calculate_bmi: l’Indice di Massa Corporea (BMI) è un calcolo semplice che utilizza l’altezza e il peso di una persona. La formula è BMI = kg/m^2 dove kg è il peso di una persona in chilogrammi e m^2 è la sua altezza in metri al quadrato. Il BMI non misura direttamente il grasso corporeo, ma la ricerca ha dimostrato che il BMI è moderatamente correlato con misure più dirette del grasso corporeo. Fornisce un utile indicatore per capire se una persona è sottopeso, ha un peso sano, è in sovrappeso o obesa.

def calculate_bmi(weight: float, height: float) -> float:    """Calcola l'Indice di Massa Corporea (BMI) per una persona    :param weight: Il peso della persona in kg    :param height: L'altezza della persona in cm    :return: Il BMI della persona    """    height_meters = height / 100  # converti cm in metri    bmi = weight / (height_meters ** 2)    return round(bmi, 2)  # arrotonda a 2 decimali per leggibilità

Costruzione dell’Agente: Incapsulamento delle Funzioni

Dopo aver stabilito le funzioni essenziali, il nostro prossimo passo è integrarle nell’agente chatbot. Questo incapsulamento consente al bot di sfruttare le funzioni e fornire risposte pertinenti e accurate in base alle query dell’utente.

Ecco come puoi creare l’agente:

# Istantia l'agentefitness_agent = FitnessAgent(openai_api_key, nut_api_key)

Puoi verificare le funzioni con cui è arricchito:

# Puoi visualizzare le istruzioni delle funzioni elaborateprint(fitness_agent.functions)

Output:

[   {      "name":"get_nutritional_info",      "description":"Recupera le informazioni nutrizionali per un determinato alimento",      "parameters":{         "type":"object",         "properties":{            "query":{               "description":"L'alimento per cui ottenere le informazioni nutrizionali",               "type":"string"            }         }      },      "required":[         "query"      ]   },   {      "name":"calculate_bmr",      "description":"Calcola il Tasso Metabolico Basale (BMR) per una persona",      "parameters":{         "type":"object",         "properties":{            "weight":{               "description":"Il peso della persona in kg",               "type":"number"            },            "height":{               "description":"L'altezza della persona in cm",               "type":"number"            },            "age":{               "description":"L'età della persona in anni",               "type":"integer"            },            "gender":{               "description":"Il genere della persona ('maschio' o 'femmina')",               "type":"string"            },            "equation":{               "description":"L'equazione da utilizzare per il calcolo del BMR ('harris_benedict' o 'mifflin_st_jeor')",               "type":"string"            }         }      },      "required":[         "weight",         "height",         "age",         "gender",         "equation"      ]   },   {      "name":"calculate_tdee",      "description":"Calcola il Dispendio Energetico Giornaliero Totale (TDEE) per una persona",      "parameters":{         "type":"object",         "properties":{            "bmr":{               "description":"Il BMR della persona",               "type":"number"            },            "activity_level":{               "description":"Il livello di attività della persona",               "type":"string"            }         }      },      "required":[         "bmr",         "activity_level"      ]   }]

Interazione con l’Agente: Conversazioni con l’Utente

Dopo aver incapsulato le funzioni definite all’interno di FitnessAgent, possiamo simulare una conversazione con il nostro bot. Utilizzando il metodo ask() della classe FitnessAgent, possiamo facilmente inserire le query dell’utente nel nostro bot e stampare le risposte che genera.

Ad esempio, chiediamo al bot alcune informazioni nutrizionali su un alimento comune:

# Definisci una domandauser_input = "Qual è il valore nutrizionale di una banana?"# Ottieni la risposta grezza della chatresponse = fitness_agent.ask(user_input)# Stampa la risposta finaleprint(response['choices'][0]['message']['content'])

Output:

Un servizio di 100 grammi di banana contiene tipicamente:- Calorie: 89,4- Grassi totali: 0,3 grammi, di cui Grassi Saturi sono 0,1 grammi- Proteine: 1,1 grammi- Sodio: 1 milligrammo- Potassio: 22 milligrammi- Colesterolo: 0 milligrammi- Carboidrati totali: 23,2 grammi, di cui Fibra Alimentare è 2,6 grammi e Zuccheri sono 12,3 grammiQuesti valori possono variare in base alle dimensioni esatte e alla maturità della banana. Inoltre, tieni presente che le banane sono una buona fonte di potassio alimentare e vitamina C.

In questo esempio, FitBot utilizza efficacemente la funzione get_nutritional_info() per recuperare e visualizzare il valore nutrizionale di una banana.

FitBot può gestire anche richieste più complesse. Ad esempio, può calcolare il Dispendio Energetico Giornaliero Totale (TDEE) di una persona se vengono forniti i dati necessari:

# Definire una domandauser_input = "Qual è il TDEE di un uomo di 30 anni, alto 180 cm, pesa 80 kg e fa esercizio 3 volte a settimana?"# Ottenere una risposta di chat grezzaresponse = fitness_agent.ask(user_input)# Stampare la risposta finalprint(response['choices'][0]['message']['content'])

Output:

Il Dispendio Energetico Giornaliero Totale (TDEE) di un uomo di 30 anni, alto 180 cm, pesa 80 kg, e fa esercizio 3 volte a settimana con esercizio "moderato" secondo l'equazione di Harris-Benedict sarebbe di circa 2574 calorie al giorno. Questa è solo una stima approssimativa e i risultati individuali possono variare in base a molteplici fattori come la velocità del metabolismo, l'attività fisica specifica e altro ancora. Ecco una semplice descrizione del processo:1. Calcolo del Tasso Metabolico Basale (BMR) - Questo è il numero di calorie che una persona brucerebbe semplicemente esistendo, senza alcuna attività. Per gli uomini, l'equazione di Harris-Benedict per calcolare il BMR è BMR = 88.362 + (13.397 * peso in kg) + (4.799 * altezza in cm) - (5.677 * età in anni)Per i valori forniti, il BMR viene a circa 1783 calorie.2. Regolazione per l'Attività - Il BMR può essere quindi regolato per il livello di attività fisica utilizzando i seguenti moltiplicatori:- Sedentario (poca o nessuna attività): BMR * 1.2- Leggermente attivo (esercizio leggero/sport 1-3 giorni/settimana): BMR * 1.375- Moderatamente attivo (esercizio/sport moderato 3-5 giorni/settimana): BMR * 1.55- Molto attivo (esercizio intenso/sport 6-7 giorni a settimana): BMR * 1.725- Super attivo (esercizio molto intenso/lavoro fisico e esercizio 2 volte al giorno): BMR * 1.9Per qualcuno che fa esercizio 3 volte a settimana, potremmo prendere il moltiplicatore a 1.55 (Moderatamente attivo). Quindi, TDEE = BMR * Moltiplicatore di Attività = 1783 * 1.55 = circa 2764 calorie.Nota: Le reali necessità caloriche totali possono essere leggermente superiori o inferiori poiché questo calcolo non tiene conto del rapporto muscoli/grasso, tipi specifici di attività, ecc.

Confrontiamo questo output con ChatGPT vanilla basato su GPT-4:

TDEE, o Dispendio Energetico Giornaliero Totale, rappresenta il numero totale di calorie che una persona ha bisogno di consumare in un giorno per mantenere il proprio peso attuale, considerando il proprio livello di attività fisica.Prima è necessario calcolare il Tasso Metabolico Basale (BMR), che è la quantità di energia spesa a riposo. Ci sono diverse equazioni per calcolare il BMR, una delle più comunemente utilizzate è l'equazione di Mifflin-St. Jeor:Per gli uomini: BMR = 10 * peso(kg) + 6.25 * altezza(cm) - 5 * età(a) + 5Quindi, per il tuo caso:BMR = 10 * 80kg + 6.25 * 180cm - 5 * 30a + 5BMR = 800 + 1125 - 150 + 5 = 1780 kcal/giornoQuesta è la quantità di calorie necessarie per mantenere il funzionamento del corpo a riposo.Per includere l'attività fisica nell'equazione, moltiplichiamo il BMR per il Livello di Attività Fisica (PAL). Per qualcuno che fa esercizio 3 volte a settimana, un PAL comune è 1.375 (esercizio moderato).Quindi, TDEE = BMR * PALTDEE = 1780 kcal/giorno * 1.375 = 2447.5 kcal/giornoQuindi, un uomo di 30 anni, alto 180 cm, pesa 80 kg e fa esercizio 3 volte a settimana avrebbe bisogno di circa 2448 calorie al giorno per mantenere il suo peso attuale. Si prega di notare che si tratta solo di una stima; le reali esigenze caloriche possono variare in base a molti fattori, tra cui genetica e composizione corporea. Consultare sempre un operatore sanitario o un dietologo registrato per consigli personalizzati.

Integrazione del Chatbot con l’Interfaccia Utente

Ora che abbiamo costruito il nostro agente fitness e lo abbiamo dotato di funzionalità utili, vogliamo presentarlo in un’interfaccia facile da usare.

Per questo, utilizziamo Gradio, una libreria Python che ci permette di creare interfacce utente web condivisibili in modo rapido e conveniente. In questa sezione, ti guideremo nell’integrazione del nostro chatbot con un’interfaccia utente Gradio.

Ecco la struttura generale della nostra interfaccia:

def main():    openai_api_key = gr.components.Textbox(        lines=1,        label="Inserisci la chiave API di OpenAI",        type="password",    )    nut_api_key = gr.components.Textbox(        lines=1,        label="Inserisci la chiave API di Nutrizione",        type="password",    )    question = gr.components.Textbox(        lines=3,        label="Inserisci il tuo messaggio",    )    output_history = gr.outputs.HTML(        label="Conversazione Aggiornata",    )    inputs = [        openai_api_key,        nut_api_key,        question,    ]    iface = gr.Interface(        fn=partial(get_response),        inputs=inputs,        outputs=[output_history],        title="Agente Fitness",        description="Un semplice chatbot che utilizza un Agente Fitness e Gradio con la cronologia della conversazione",        allow_flagging=False,    )    iface.launch()if __name__ == "__main__":    main()

Questa è la nostra funzione main, il punto di ingresso del nostro script. Iniziamo creando caselle di testo per l’utente in modo che possa inserire la propria chiave API di OpenAI e la chiave API di Nutrizione. Le chiavi sono impostate sul tipo password per nascondere l’input. Successivamente, forniamo una casella di testo per l’utente per fare la propria domanda. La risposta del bot verrà visualizzata come HTML in un’area denominata “Conversazione Aggiornata”.

Le voci di input e l’output vengono quindi passati all’interfaccia Gradio, che viene lanciata quando lo script viene eseguito.

La funzione get_response interagisce con l’agente fitness:

def get_response(openai_api_key, nut_api_key, user_input, action=None):    set_openai_api_key(openai_api_key)    set_nut_api_key(nut_api_key)    fitness_agent = FitnessAgent(openai_api_key, nut_api_key)    # Ottieni la risposta grezza dalla chat    fitness_agent.ask(user_input)    memory = fitness_agent.agent.chat_history    # Itera attraverso i messaggi in ChatMessageHistory e formatta l'output    updated_conversation = '<div style="background-color: hsl(30, 100%, 30%); color: white; padding: 5px; margin-bottom: 10px; text-align: center; font-size: 1.5em;">Cronologia della Chat</div>'    logger.info(memory)    for i, message in enumerate(memory):        if i != 0:            if message['role'] == 'user':                prefix = "Utente: "                background_color = "hsl(0, 0%, 40%)"  # Sfondo grigio scuro                text_color = "hsl(0, 0%, 100%)"  # Testo bianco            else:                prefix = "Chatbot: "                background_color = "hsl(0, 0%, 95%)"  # Sfondo bianco                text_color = "hsl(0, 0%, 0%)"  # Testo nero            updated_conversation += f'<div style="color: {text_color}; background-color: {background_color}; margin: 5px; padding: 5px;">{prefix}{message["content"]}</div>'    return updated_conversation

In get_response, impostiamo le chiavi API di OpenAI e Nutrizione utilizzando le funzioni set_openai_api_key e set_nut_api_key, quindi inizializziamo il nostro agente fitness. Successivamente, chiamiamo il metodo ask dell’agente con la domanda dell’utente e memorizziamo la cronologia della conversazione. Ogni messaggio nella cronologia della conversazione viene quindi formattato come una stringa HTML e aggiunto a updated_conversation. Questa stringa HTML viene restituita e visualizzata nell’interfaccia Gradio.

Uno Sguardo all’Interfaccia Risultante

Dopo aver integrato i calcoli essenziali e la logica della conversazione, e aver racchiuso tutto questo in un’interfaccia utente piacevole con Gradio, il nostro FitBot è pronto per interagire!

Ecco come appare l’interfaccia finale:

Figura 2: Interfaccia UI di Gradio per il chatbot. Immagine dell'Autore.

Sull’interfaccia, noterai tre caselle di input in cui puoi inserire le chiavi necessarie per OpenAI e l’endpoint di Ninjas Nutrition API, così come il messaggio dell’utente per il Fitness Agent.

Sommario

In questo articolo abbiamo descritto la creazione di FitBot, un completo Fitness Agent che utilizza GPT-4 di OpenAI, un potente modello di intelligenza artificiale in grado di comprendere e rispondere a complessi quesiti degli utenti.

Abbiamo iniziato costruendo delle funzioni per calcolare importanti metriche di salute come il Tasso Metabolico Basale (BMR), la Spesa Energetica Quotidiana Totale (TDEE) e l’Indice di Massa Corporea (BMI). Questi calcoli costituiscono la base per la capacità del Fitness Agent di fornire consigli precisi e personalizzati in materia di fitness e nutrizione.

In seguito, abbiamo integrato un endpoint di Nutrition API di Ninjas. Questo ha permesso al Fitness Agent di accedere e fornire informazioni nutrizionali precise, un componente fondamentale per qualsiasi piano di fitness e dieta completo.

Abbiamo poi mostrato come costruire una logica di conversazione per rendere il Fitness Agent più interattivo. È in grado di gestire un flusso di conversazione, consentendogli di rispondere a diverse domande degli utenti e guidarli efficacemente nel loro percorso di fitness.

Infine, abbiamo racchiuso tutte queste funzionalità in un’interfaccia utente visivamente accattivante utilizzando Gradio. Il risultato è un Fitness Agent che non solo è intelligente, ma anche facile da usare, offrendo consigli chiari e completi in un formato facilmente comprensibile.

TL;DR: In questo articolo abbiamo costruito FitBot, un Fitness Agent che utilizza GPT-4 di OpenAI, in grado di fornire consigli personalizzati su fitness e nutrizione. Abbiamo implementato funzioni per il calcolo di importanti metriche di salute (BMR, TDEE, BMI), integrato un’API di Nutrizione per informazioni dietetiche precise e racchiuso tutto in un’interfaccia utente intuitiva utilizzando Gradio. Questo progetto mette in mostra il potere dell’IA nella salute e nel fitness, semplificando complessi calcoli, offrendo consigli personalizzati e presentandoli tutti attraverso un’interfaccia utente accattivante.

Grazie per aver letto!

  • Seguimi su Linkedin!