From 08b4e1ea933694f14a9d2bca9c71d55d8fe03e3e Mon Sep 17 00:00:00 2001 From: ranaalmaaz55 <50968377-ranaalmaaz55@users.noreply.replit.com> Date: Sun, 25 Jan 2026 05:56:48 +0000 Subject: [PATCH 1/8] Integrate Replit AI features and update project configuration Update api.py to use Replit AI Integrations for OpenAI API key and base URL, and change the model to "gpt-4o-mini". Modify frontend.py to use "localhost" for the backend API URL and add error handling for connection issues. Update requirements.txt to include 'openai', 'pydantic', 'python-dotenv', and 'requests'. Create replit.md documentation detailing the project setup, architecture, and dependencies. Add run.py script to manage backend and frontend processes for Replit environment. Replit-Commit-Author: Agent Replit-Commit-Session-Id: c1582ad0-2a4d-421f-abef-a344959f5e0b Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 46394778-ce7b-485f-9526-7aef3b6794af Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/5e51078b-5ac9-4f4e-a1d5-c7167392f72e/c1582ad0-2a4d-421f-abef-a344959f5e0b/qTLLDNh Replit-Helium-Checkpoint-Created: true --- .replit | 44 ++++++++++++++++++++++++++++++++++++++++++++ api.py | 29 +++++++++++++---------------- frontend.py | 38 +++++++++++++++++++------------------- replit.md | 34 ++++++++++++++++++++++++++++++++++ requirements.txt | 4 ++++ run.py | 25 +++++++++++++++++++++++++ 6 files changed, 139 insertions(+), 35 deletions(-) create mode 100644 .replit create mode 100644 replit.md create mode 100644 run.py diff --git a/.replit b/.replit new file mode 100644 index 0000000..055350d --- /dev/null +++ b/.replit @@ -0,0 +1,44 @@ +modules = ["python-3.11"] +[agent] +expertMode = true +integrations = ["python_openai_ai_integrations:1.0.0"] + +[nix] +channel = "stable-25_05" +packages = ["glibcLocales"] + +[workflows] +runButton = "Project" + +[[workflows.workflow]] +name = "Project" +mode = "parallel" +author = "agent" + +[[workflows.workflow.tasks]] +task = "workflow.run" +args = "AI Personal Trainer" + +[[workflows.workflow]] +name = "AI Personal Trainer" +author = "agent" + +[[workflows.workflow.tasks]] +task = "shell.exec" +args = "python run.py" +waitForPort = 5000 + +[workflows.workflow.metadata] +outputType = "webview" + +[[ports]] +localPort = 5000 +externalPort = 80 + +[[ports]] +localPort = 8000 +externalPort = 8000 + +[deployment] +deploymentTarget = "autoscale" +run = ["python", "run.py"] diff --git a/api.py b/api.py index 41af6e1..4d4fd2e 100644 --- a/api.py +++ b/api.py @@ -1,18 +1,18 @@ -# personal_trainer_agent.py -from fastapi import FastAPI, Request +from fastapi import FastAPI from pydantic import BaseModel -import openai -from dotenv import load_dotenv +from openai import OpenAI import os -load_dotenv() -client = openai.OpenAI() -# Initialize FastAPI app -app = FastAPI() +AI_INTEGRATIONS_OPENAI_API_KEY = os.environ.get("AI_INTEGRATIONS_OPENAI_API_KEY") +AI_INTEGRATIONS_OPENAI_BASE_URL = os.environ.get("AI_INTEGRATIONS_OPENAI_BASE_URL") + +client = OpenAI( + api_key=AI_INTEGRATIONS_OPENAI_API_KEY, + base_url=AI_INTEGRATIONS_OPENAI_BASE_URL +) -# ✅ Replace with your actual API key +app = FastAPI() -# Define data structure for user inputs class UserInfo(BaseModel): goal: str experience: str @@ -21,11 +21,6 @@ class UserInfo(BaseModel): @app.post("/generate_plan/") async def generate_plan(user: UserInfo): - """ - Basic AI Agent: - - Takes user's fitness info - - Generates a simple gym plan - """ prompt = f""" You are a personal fitness trainer. Create a 1-week gym plan for someone with: @@ -37,8 +32,10 @@ async def generate_plan(user: UserInfo): Return the plan as a simple, structured list (Day 1, Day 2, ...). """ + # the newest OpenAI model is "gpt-5" which was released August 7, 2025. + # do not change this unless explicitly requested by the user response = client.chat.completions.create( - model="gpt-3.5-turbo", + model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=0.7 ) diff --git a/frontend.py b/frontend.py index 7548d8d..9a35a53 100644 --- a/frontend.py +++ b/frontend.py @@ -1,38 +1,38 @@ import streamlit as st import requests +import os -# --- Streamlit page setup --- -st.set_page_config(page_title="AI Personal Trainer 💪", page_icon="🏋️") +st.set_page_config(page_title="AI Personal Trainer", page_icon="💪") st.title("💪 Your AI Personal Trainer") st.write("Answer a few questions and get your personalized gym plan instantly.") -# --- User input form --- with st.form("trainer_form"): - goal = st.text_input("🎯 What’s your fitness goal? (e.g. build muscle, lose fat, stay fit)") + goal = st.text_input("🎯 What's your fitness goal? (e.g. build muscle, lose fat, stay fit)") experience = st.selectbox("🔥 Your experience level:", ["Beginner", "Intermediate", "Advanced"]) days_per_week = st.slider("📅 How many days per week can you train?", 1, 7, 4) equipment = st.text_area("🏋️ What equipment do you have? (e.g. dumbbells, resistance bands, gym access)") submitted = st.form_submit_button("Generate Plan 🚀") -# --- Backend API URL --- -API_URL = "http://127.0.0.1:8000/generate_plan/" # update if deployed +API_URL = "http://localhost:8000/generate_plan/" -# --- Call the FastAPI backend --- if submitted: if not goal or not equipment: st.warning("⚠️ Please fill in all fields before submitting.") else: with st.spinner("Generating your gym plan..."): - response = requests.post(API_URL, json={ - "goal": goal, - "experience": experience, - "days_per_week": days_per_week, - "equipment": equipment - }) + try: + response = requests.post(API_URL, json={ + "goal": goal, + "experience": experience, + "days_per_week": days_per_week, + "equipment": equipment + }) - if response.status_code == 200: - plan = response.json()["gym_plan"] - st.success("🏋️ Here’s your personalized plan:") - st.markdown(plan) - else: - st.error("❌ Something went wrong. Make sure the FastAPI server is running.") + if response.status_code == 200: + plan = response.json()["gym_plan"] + st.success("🏋️ Here's your personalized plan:") + st.markdown(plan) + else: + st.error("❌ Something went wrong. Please try again.") + except requests.exceptions.ConnectionError: + st.error("❌ Could not connect to the backend. Please make sure the server is running.") diff --git a/replit.md b/replit.md new file mode 100644 index 0000000..55cef4b --- /dev/null +++ b/replit.md @@ -0,0 +1,34 @@ +# AI Personal Trainer + +## Overview +A full-stack AI application that generates personalized gym workout plans using OpenAI. + +## Architecture +- **Frontend**: Streamlit (port 5000) - User interface for collecting fitness goals +- **Backend**: FastAPI with uvicorn (port 8000) - API for generating workout plans +- **AI**: OpenAI GPT-4o-mini via Replit AI Integrations + +## Running the Application +The application is run via `python run.py` which: +1. Starts the FastAPI backend on localhost:8000 +2. Starts the Streamlit frontend on 0.0.0.0:5000 + +## Project Structure +``` +├── api.py # FastAPI backend with OpenAI integration +├── frontend.py # Streamlit frontend +├── run.py # Launcher script for both services +├── main.py # CLI version (not used in web app) +├── requirements.txt +└── replit.md +``` + +## Dependencies +- fastapi, uvicorn - Web API framework +- streamlit - Frontend framework +- openai - AI integration (uses Replit AI Integrations) +- pydantic - Data validation + +## Notes +- OpenAI access is provided through Replit AI Integrations (no API key needed) +- Backend runs on localhost, frontend binds to 0.0.0.0 for Replit proxy access diff --git a/requirements.txt b/requirements.txt index c40678e..195fd4c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,7 @@ streamlit pandas transformers dotenv +openai +pydantic +python-dotenv +requests diff --git a/run.py b/run.py new file mode 100644 index 0000000..2fb440c --- /dev/null +++ b/run.py @@ -0,0 +1,25 @@ +import subprocess +import sys +import time + +backend_process = subprocess.Popen( + [sys.executable, "-m", "uvicorn", "api:app", "--host", "localhost", "--port", "8000"], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT +) + +time.sleep(2) + +frontend_process = subprocess.Popen( + [sys.executable, "-m", "streamlit", "run", "frontend.py", + "--server.port", "5000", + "--server.address", "0.0.0.0", + "--server.headless", "true", + "--browser.gatherUsageStats", "false"], +) + +try: + frontend_process.wait() +except KeyboardInterrupt: + backend_process.terminate() + frontend_process.terminate() From 95155992bbe04786e67b4cfe90d75810a0f4bb81 Mon Sep 17 00:00:00 2001 From: Rana <50968377-ranaalmaaz55@users.noreply.replit.com> Date: Tue, 27 Jan 2026 20:06:27 +0000 Subject: [PATCH 2/8] New Update --- .replit | 24 ++- api.py | 44 ------ auth.py | 47 ++++++ backend/personal_trainer_agent.py | 104 +++++++++---- db.py | 78 ++++++++++ dbSQLAlchemy.py | 110 +++++++++++++ frontend.py | 251 ++++++++++++++++++++++++++---- frontend/step2_streamlit_app.py | 61 +++++--- main.py | 241 +++++++++++++++++++--------- my_database.db | Bin 0 -> 28672 bytes run.py | 27 +--- 11 files changed, 758 insertions(+), 229 deletions(-) delete mode 100644 api.py create mode 100644 auth.py create mode 100644 db.py create mode 100644 dbSQLAlchemy.py create mode 100644 my_database.db diff --git a/.replit b/.replit index 055350d..481a96c 100644 --- a/.replit +++ b/.replit @@ -5,7 +5,7 @@ integrations = ["python_openai_ai_integrations:1.0.0"] [nix] channel = "stable-25_05" -packages = ["glibcLocales"] +packages = ["glibcLocales", "mailutils"] [workflows] runButton = "Project" @@ -31,14 +31,30 @@ waitForPort = 5000 [workflows.workflow.metadata] outputType = "webview" +[[ports]] +localPort = 3000 +externalPort = 3000 + [[ports]] localPort = 5000 externalPort = 80 [[ports]] localPort = 8000 -externalPort = 8000 +externalPort = 8081 + +[[ports]] +localPort = 8080 +externalPort = 8080 + +[[ports]] +localPort = 8501 +externalPort = 8099 [deployment] -deploymentTarget = "autoscale" -run = ["python", "run.py"] +run = "uvicorn main:app --host 0.0.0.0 --port 8000" + +[[ports]] +localPort = 8000 +externalPort = 8081 + diff --git a/api.py b/api.py deleted file mode 100644 index 4d4fd2e..0000000 --- a/api.py +++ /dev/null @@ -1,44 +0,0 @@ -from fastapi import FastAPI -from pydantic import BaseModel -from openai import OpenAI -import os - -AI_INTEGRATIONS_OPENAI_API_KEY = os.environ.get("AI_INTEGRATIONS_OPENAI_API_KEY") -AI_INTEGRATIONS_OPENAI_BASE_URL = os.environ.get("AI_INTEGRATIONS_OPENAI_BASE_URL") - -client = OpenAI( - api_key=AI_INTEGRATIONS_OPENAI_API_KEY, - base_url=AI_INTEGRATIONS_OPENAI_BASE_URL -) - -app = FastAPI() - -class UserInfo(BaseModel): - goal: str - experience: str - days_per_week: int - equipment: str - -@app.post("/generate_plan/") -async def generate_plan(user: UserInfo): - prompt = f""" - You are a personal fitness trainer. - Create a 1-week gym plan for someone with: - - Goal: {user.goal} - - Experience level: {user.experience} - - Days per week available: {user.days_per_week} - - Available equipment: {user.equipment} - - Return the plan as a simple, structured list (Day 1, Day 2, ...). - """ - - # the newest OpenAI model is "gpt-5" which was released August 7, 2025. - # do not change this unless explicitly requested by the user - response = client.chat.completions.create( - model="gpt-4o-mini", - messages=[{"role": "user", "content": prompt}], - temperature=0.7 - ) - - plan = response.choices[0].message.content - return {"gym_plan": plan} diff --git a/auth.py b/auth.py new file mode 100644 index 0000000..e1c4c05 --- /dev/null +++ b/auth.py @@ -0,0 +1,47 @@ +import streamlit as st +import requests +import uuid + +st.title("Login/Signup") +username = st.text_input("Username") + +if "session_id" in st.session_state and "username" in st.session_state: + st.switch_page("frontend.py") + + +if st.button("Login"): + if username: + st.session_state.session_id = str(uuid.uuid4()) + API_BASE = "http://localhost:8000/login/" + # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/login/" + response = requests.post(API_URL, json={"username": username, "session_id": st.session_state.session_id}) + + if response.status_code == 200: + if response.json()["exists"]: + st.session_state.username = username + st.success("Logged in successfully!") + st.switch_page("frontend.py") + else: + st.warning("User not found. Please sign up.") + else: + st.error("Failed to connect to the server.") + else: + st.error("Username is required") + +if st.button("Signup"): + if username: + st.session_state.session_id = str(uuid.uuid4()) + API_BASE = "http://localhost:8000/signup/" + # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/signup/" + response = requests.post(API_URL, json={"username": username, "session_id": st.session_state.session_id}) + if response.status_code == 200: + if response.json()["exists"]: + st.warning("Username already exists. Please login or choose a different username.") + else: + st.session_state.username = username + st.success("Signed up successfully!") + st.switch_page("frontend.py") + else: + st.error("Failed to connect to the server.") + else: + st.error("Username is required") diff --git a/backend/personal_trainer_agent.py b/backend/personal_trainer_agent.py index 01bd007..8c7ada1 100644 --- a/backend/personal_trainer_agent.py +++ b/backend/personal_trainer_agent.py @@ -2,47 +2,84 @@ from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from dotenv import load_dotenv -from openai import OpenAI import os +from groq import Groq -# Chemin vers le fichier .env (même dossier que ce script) -dotenv_path = os.path.join(os.path.dirname(__file__), ".env") -load_dotenv(dotenv_path) +# # Chemin vers le fichier .env (même dossier que ce script) +# dotenv_path = os.path.join(os.path.dirname(__file__), ".env") +# load_dotenv(dotenv_path) -# Vérifier que la clé est présente -api_key = os.getenv("OPENAI_API_KEY") -if not api_key: - raise ValueError("Veuillez définir votre clé OpenAI dans le fichier .env !") +# # Vérifier que la clé est présente +# api_key = os.getenv("OPENAI_API_KEY") +# if not api_key: +# raise ValueError("Veuillez définir votre clé OpenAI dans le fichier .env !") -print("Clé API détectée :", api_key is not None) # juste pour vérifier +# print("Clé API détectée :", api_key is not None) # juste pour vérifier -# Créer le client OpenAI avec la clé -client = OpenAI(api_key=api_key) +# # Créer le client OpenAI avec la clé +# client = OpenAI(api_key=api_key) -# Création de l'application FastAPI -app = FastAPI() +# # Création de l'application FastAPI +# app = FastAPI() + +# app.add_middleware( +# CORSMiddleware, +# allow_origins=["*"], +# allow_credentials=True, +# allow_methods=["*"], +# allow_headers=["*"], +# ) + +# # Modèle pour les entrées utilisateur +# class UserInput(BaseModel): +# goal: str +# experience: str +# days: int +# equipment: str + +# # Route pour générer le plan +# @app.post("/generate_plan") +# def generate_plan(data: UserInput): +# if data.days <= 0: +# return {"error": "Le nombre de jours doit être supérieur à 0"} + +# prompt = f""" +# You are an expert fitness coach. +# Create a weekly workout plan: +# - Goal: {data.goal} +# - Experience: {data.experience} +# - Days/week: {data.days} +# - Equipment: {data.equipment} +# """ + +# try: +# response = client.chat.completions.create( +# model="gpt-4o-mini", +# messages=[ +# {"role": "system", "content": "You are an expert fitness coach."}, +# {"role": "user", "content": prompt} +# ] +# ) +# plan_text = response.choices[0].message["content"] +# return {"plan": plan_text} -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) +# except Exception as e: +# return {"error": str(e)} + +load_dotenv() +key = os.getenv("Groq_API") +client = Groq(api_key=key) -# Modèle pour les entrées utilisateur class UserInput(BaseModel): goal: str experience: str - days: int + days_per_week: int equipment: str -# Route pour générer le plan -@app.post("/generate_plan") -def generate_plan(data: UserInput): - if data.days <= 0: - return {"error": "Le nombre de jours doit être supérieur à 0"} +app = FastAPI() +@app. post("/generate_plan/") +def generate_plan(data: UserInput): prompt = f""" You are an expert fitness coach. Create a weekly workout plan: @@ -51,17 +88,16 @@ def generate_plan(data: UserInput): - Days/week: {data.days} - Equipment: {data.equipment} """ - try: - response = client.chat.completions.create( - model="gpt-4o-mini", + response = client.chat.completions.create( + model="llama3-8b-8192", messages=[ {"role": "system", "content": "You are an expert fitness coach."}, {"role": "user", "content": prompt} ] ) - plan_text = response.choices[0].message["content"] - return {"plan": plan_text} - + plan_text = response.choices[0].message.content + return {"gym_plan": plan_text} + except Exception as e: - return {"error": str(e)} + return {"error": str(e)} \ No newline at end of file diff --git a/db.py b/db.py new file mode 100644 index 0000000..bfad719 --- /dev/null +++ b/db.py @@ -0,0 +1,78 @@ +# db.py +import sqlite3 +from contextlib import closing +from pathlib import Path + +DB_PATH = Path("chat.db") + + +def get_connection(): + """Return a SQLite connection.""" + return sqlite3.connect(DB_PATH, check_same_thread=False) + + +def init_db(): + """Create the users table if it does not exist.""" + with closing(get_connection()) as conn: + cursor = conn.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS users ( + username TEXT PRIMARY KEY, + session_id TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + + CREATE TABLE IF NOT EXISTS chat_messages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL, + role TEXT CHECK(role IN ('user', 'assistant')), + content TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (session_id) REFERENCES users(session_id) + ); + CREATE TABLE IF NOT EXISTS plans ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL, + session_id TEXT NOT NULL, + plan_type TEXT, + content TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (username) REFERENCES users(username) + FOREIGN KEY (session_id) REFERENCES users(session_id), + FOREIGN KEY (username) REFERENCES users(username) + ); + CREATE TABLE IF NOT EXISTS user_preferences ( + username TEXT PRIMARY KEY, + preferences_json TEXT, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (username) REFERENCES users(username) + ); + """) + conn.commit() + + +# CRUD helpers +def create_user(username: str, session_id: str): + with closing(get_connection()) as conn: + cursor = conn.cursor() + cursor.execute( + "INSERT INTO users (username, session_id) VALUES (?, ?)", + (username, session_id)) + conn.commit() + + +def get_user(username: str): + with closing(get_connection()) as conn: + cursor = conn.cursor() + cursor.execute( + "SELECT username, session_id FROM users WHERE username = ?", + (username, )) + return cursor.fetchone() + + +def update_session_id(username: str, session_id: str): + with closing(get_connection()) as conn: + cursor = conn.cursor() + cursor.execute("UPDATE users SET session_id = ? WHERE username = ?", + (session_id, username)) + conn.commit() diff --git a/dbSQLAlchemy.py b/dbSQLAlchemy.py new file mode 100644 index 0000000..f1fc0a7 --- /dev/null +++ b/dbSQLAlchemy.py @@ -0,0 +1,110 @@ +# db_sqlalchemy.py +from sqlalchemy import Column, String, DateTime, create_engine, Integer, ForeignKey +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from datetime import datetime +from sqlalchemy import create_engine + +#connrct to db or create if not exists +engine = create_engine('sqlite:///my_database.db', echo=True) +Base = declarative_base() + +# User model +class User(Base): + __tablename__ = "users" + + username = Column(String, primary_key=True) + session_id = Column(String, nullable=False) + created_at = Column(DateTime, default=datetime.utcnow) + +class ChatMessage(Base): + __tablename__ = "chat_messages" + + id = Column(Integer, primary_key=True, autoincrement=True) + username = Column(String, ForeignKey("users.username"), nullable=False) + role = Column(String, nullable=False) + content = Column(String, nullable=False) + created_at = Column(DateTime, default=datetime.utcnow) + +class Plan(Base): + __tablename__ = "plans" + + id = Column(Integer, primary_key=True, autoincrement=True) + username = Column(String, ForeignKey("users.username"), nullable=False) + content = Column(String, nullable=False) + created_at = Column(DateTime, default=datetime.utcnow) + +class UserPreferences(Base): + __tablename__ = "user_preferences" + username = Column(String, ForeignKey("users.username"), primary_key=True) + preferences_json = Column(String, nullable=False) + updated_at = Column(DateTime, default=datetime.utcnow) + + +# Create tables +Base.metadata.create_all(bind=engine) + +#Session factory to interact with db +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +session = SessionLocal() + +# CRUD helpers +def get_user(db_session, username: str): + return db_session.query(User).filter_by(username=username).first() + + +def create_user(db_session, username: str, session_id: str): + user = User(username=username, session_id=session_id) + db_session.add(user) + db_session.commit() + db_session.refresh(user) + return user + + +def update_session(db_session, username: str, session_id: str): + user = get_user(db_session, username) + if user: + user.session_id = session_id + db_session.commit() + db_session.refresh(user) + return username + + +def create_chat_message(db_session, username: str, role: str, content: str): + chat_message = ChatMessage(username=username, role=role, content=content) + db_session.add(chat_message) + db_session.commit() + db_session.refresh(chat_message) + +def create_plan(db_session, username: str, session_id: str, content: str): + plan = Plan(username=username, session_id=session_id, content=content) + db_session.add(plan) + db_session.commit() + db_session.refresh(plan) + return plan + +def create_user_preferences(db_session, username: str, preferences_json: str): + user_preferences = UserPreferences(username=username, preferences_json=preferences_json) + db_session.add(user_preferences) + db_session.commit() + db_session.refresh(user_preferences) + return user_preferences + +def get_user_preferences(db_session, username: str): + return db_session.query(UserPreferences).filter_by(username=username).first() + +def update_user_preferences(db_session, username: str, preferences_json: str): + user_preferences = get_user_preferences(db_session, username) + if user_preferences: + user_preferences.preferences_json = preferences_json + db_session.commit() + db_session.refresh(user_preferences) + return user_preferences + return None + +def get_chat_messages(db_session, username: str): + return db_session.query(ChatMessage).filter_by(username=username).order_by(ChatMessage.created_at.asc()).all() + +def get_plans(db_session, username: str): + return db_session.query(Plan).filter_by(username=username).all() + diff --git a/frontend.py b/frontend.py index 9a35a53..6c6d914 100644 --- a/frontend.py +++ b/frontend.py @@ -1,38 +1,231 @@ +# import streamlit as st +# import requests +# import os + +# st.set_page_config(page_title="AI Personal Trainer", page_icon="💪") +# st.title("💪 Your AI Personal Trainer") +# st.write( +# "Answer a few questions and get your personalized gym plan instantly.") + +# with st.form("trainer_form"): +# goal = st.text_input( +# "🎯 What's your fitness goal? (e.g. build muscle, lose fat, stay fit)") +# experience = st.selectbox("🔥 Your experience level:", +# ["Beginner", "Intermediate", "Advanced"]) +# days_per_week = st.slider("📅 How many days per week can you train?", 1, 7, +# 4) +# equipment = st.text_area( +# "🏋️ What equipment do you have? (e.g. dumbbells, resistance bands, gym access)" +# ) +# submitted = st.form_submit_button("Generate Plan 🚀") + +# API_URL = "http://buildinpublic.ranaalmaaz55.repl.co/generate_plan/" + +# if submitted: +# if not goal or not equipment: +# st.warning("⚠️ Please fill in all fields before submitting.") +# else: +# with st.spinner("Generating your gym plan..."): +# try: +# response = requests.post(API_URL, +# json={ +# "goal": goal, +# "experience": experience, +# "days_per_week": days_per_week, +# "equipment": equipment +# }) + +# if response.status_code == 200: +# plan = response.json()["gym_plan"] +# st.success("🏋️ Here's your personalized plan:") +# st.markdown(plan) +# else: +# st.error("❌ Something went wrong. Please try again.") +# except requests.exceptions.ConnectionError: +# st.error( +# "❌ Could not connect to the backend. Please make sure the server is running." +# ) + + import streamlit as st import requests import os +# ------------------------------- +# Page config +# ------------------------------- st.set_page_config(page_title="AI Personal Trainer", page_icon="💪") st.title("💪 Your AI Personal Trainer") -st.write("Answer a few questions and get your personalized gym plan instantly.") - -with st.form("trainer_form"): - goal = st.text_input("🎯 What's your fitness goal? (e.g. build muscle, lose fat, stay fit)") - experience = st.selectbox("🔥 Your experience level:", ["Beginner", "Intermediate", "Advanced"]) - days_per_week = st.slider("📅 How many days per week can you train?", 1, 7, 4) - equipment = st.text_area("🏋️ What equipment do you have? (e.g. dumbbells, resistance bands, gym access)") - submitted = st.form_submit_button("Generate Plan 🚀") - -API_URL = "http://localhost:8000/generate_plan/" - -if submitted: - if not goal or not equipment: - st.warning("⚠️ Please fill in all fields before submitting.") - else: - with st.spinner("Generating your gym plan..."): - try: - response = requests.post(API_URL, json={ - "goal": goal, - "experience": experience, - "days_per_week": days_per_week, - "equipment": equipment - }) + +# ------------------------------- +# Backend URLs +# ------------------------------- +API_BASE = "http://localhost:8000" +# API_BASE = "https://buildinpublic.ranaalmaaz55.repl.co" +PREFERENCES_API = f"{API_BASE}/update_preferences" +CHAT_API = f"{API_BASE}/chat" +HISTORY_API = f"{API_BASE}/chat_history" + +# ------------------------------- +# Session guards +# ------------------------------- +if "username" not in st.session_state or "session_id" not in st.session_state: + st.error("⚠️ You must be logged in to access this page.") + st.switch_page("auth.py") + +# ------------------------------- +# UI state +# ------------------------------- +if "messages" not in st.session_state: + st.session_state.messages = [] + +# ------------------------------- +# Tabs +# ------------------------------- +tab_preferences, tab_chat = st.tabs(["⚙️ Preferences", "💬 Chatbot"]) + +# ===================================================== +# TAB 1: USER PREFERENCES +# ===================================================== +with tab_preferences: + st.subheader("⚙️ Personal Preferences") + + with st.form("preferences_form"): + goal = st.text_input( + "🎯 Fitness goal", + placeholder="Build muscle, lose fat, stay fit..." + ) + + experience = st.selectbox( + "🔥 Experience level", + ["Beginner", "Intermediate", "Advanced"] + ) + + tone = st.selectbox( + "🗣️ Coaching tone", + ["Motivational", "Strict", "Friendly", "Neutral"] + ) + + days_per_week = st.slider( + "📅 Training days per week", + 1, 7, 4 + ) + + equipment = st.text_area( + "🏋️ Available equipment", + placeholder="Dumbbells, resistance bands, gym access..." + ) + + save_preferences = st.form_submit_button("💾 Save Preferences") + + if save_preferences: + if not goal or not equipment: + st.warning("⚠️ Please fill in all required fields.") + else: + with st.spinner("Saving your preferences..."): + response = requests.post( + PREFERENCES_API, + json={ + "username": st.session_state.username, + "goal": goal, + "experience": experience, + "tone": tone, + "days_per_week": days_per_week, + "equipment": equipment, + } + ) if response.status_code == 200: - plan = response.json()["gym_plan"] - st.success("🏋️ Here's your personalized plan:") - st.markdown(plan) + st.success("✅ Preferences saved successfully!") else: - st.error("❌ Something went wrong. Please try again.") - except requests.exceptions.ConnectionError: - st.error("❌ Could not connect to the backend. Please make sure the server is running.") + st.error("❌ Failed to save preferences.") + +# ===================================================== +# TAB 2: CHATBOT +# ===================================================== +with tab_chat: + st.subheader("💬 Chat with your AI Trainer") + + # ------------------------------- + # Load previous messages once + # ------------------------------- + if not st.session_state.messages: + history_response = requests.get(f"{HISTORY_API}/{st.session_state.username}") + + if history_response.status_code == 200: + st.session_state.messages = history_response.json()["messages"] + + # ------------------------------- + # Display chat history + # ------------------------------- + for msg in st.session_state.messages: + if msg.role == "user": + with st.chat_message("user"): + st.markdown( + f"
" + f"{msg.content}
", + unsafe_allow_html=True + ) + else: + with st.chat_message("assistant"): + st.markdown( + f"
" + f"{msg.content}
", + unsafe_allow_html=True + ) + + # ------------------------------- + # Input + Send button + # ------------------------------- + col1, col2 = st.columns([5, 1]) + + with col1: + user_input = st.text_input( + "Type your message", + placeholder="Ask about workouts, nutrition, recovery..." + ) + + with col2: + send_clicked = st.button("Send ➤") + + if send_clicked and user_input: + # Show user message + st.session_state.messages.append({ + "role": "user", + "content": user_input + }) + + with st.chat_message("user"): + st.markdown( + f"
" + f"{user_input}
", + unsafe_allow_html=True + ) + + # Call backend + with st.chat_message("assistant"): + with st.spinner("Thinking..."): + response = requests.post( + CHAT_API, + json={ + "username": st.session_state.username, + "message": user_input, + "messages": st.session_state.messages + } + ) + + if response.status_code == 200: + assistant_reply = response.json()["response"] + else: + assistant_reply = "❌ Something went wrong." + + st.markdown( + f"
" + f"{assistant_reply}
", + unsafe_allow_html=True + ) + + st.session_state.messages.append({ + "role": "assistant", + "content": assistant_reply + }) diff --git a/frontend/step2_streamlit_app.py b/frontend/step2_streamlit_app.py index 99fef1a..420c5d9 100644 --- a/frontend/step2_streamlit_app.py +++ b/frontend/step2_streamlit_app.py @@ -1,28 +1,47 @@ import streamlit as st import requests +import os -st.set_page_config(page_title="AI Trainer", page_icon="💪", layout="centered") +st.set_page_config(page_title="AI Personal Trainer", page_icon="💪") +st.title("💪 Your AI Personal Trainer") +st.write( + "Answer a few questions and get your personalized gym plan instantly.") -st.title("💪 AI Personal Trainer Agent") -st.write("Fill the form and get your personalized gym plan instantly.") +with st.form("trainer_form"): + goal = st.text_input( + "🎯 What's your fitness goal? (e.g. build muscle, lose fat, stay fit)") + experience = st.selectbox("🔥 Your experience level:", + ["Beginner", "Intermediate", "Advanced"]) + days_per_week = st.slider("📅 How many days per week can you train?", 1, 7, + 4) + equipment = st.text_area( + "🏋️ What equipment do you have? (e.g. dumbbells, resistance bands, gym access)" + ) + submitted = st.form_submit_button("Generate Plan 🚀") -goal = st.selectbox("🎯 Your Goal", ["Lose weight", "Build muscle", "Endurance", "Get toned"]) -experience = st.selectbox("📊 Experience Level", ["Beginner", "Intermediate", Advanced"]) -days = st.slider("📅 Training Days per Week", 1, 7, 3) -equipment = st.text_input("🏋️ Equipment Available") +API_URL = "http://localhost:8000/generate_plan/" -if st.button("Generate Plan 🚀"): - data = { - "goal": goal, - "experience": experience, - "days": days, - "equipment": equipment - } - - response = requests.post("http://localhost:8000/generate_plan", json=data) - - if response.status_code == 200: - st.success("Your Personalized Plan:") - st.write(response.json()["plan"]) +if submitted: + if not goal or not equipment: + st.warning("⚠️ Please fill in all fields before submitting.") else: - st.error("Error connecting to backend.") + with st.spinner("Generating your gym plan..."): + try: + response = requests.post(API_URL, + json={ + "goal": goal, + "experience": experience, + "days_per_week": days_per_week, + "equipment": equipment + }) + + if response.status_code == 200: + plan = response.json()["gym_plan"] + st.success("🏋️ Here's your personalized plan:") + st.markdown(plan) + else: + st.error("❌ Something went wrong. Please try again.") + except requests.exceptions.ConnectionError: + st.error( + "❌ Could not connect to the backend. Please make sure the server is running." + ) diff --git a/main.py b/main.py index 30324f9..636341b 100644 --- a/main.py +++ b/main.py @@ -1,82 +1,177 @@ -import openai -from dotenv import load_dotenv -import os from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel -from typing import List +from dotenv import load_dotenv +import os +from groq import Groq +import dbSQLAlchemy as db +from langchain_core.prompts import ChatPromptTemplate +from langchain_groq import ChatGroq +from langchain_core.runnables.history import RunnableWithMessageHistory +from langchain_core.messages import AIMessage, HumanMessage +from langchain_core.runnables import RunnableSequence + -# Load environment variables load_dotenv() -client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) - -# ------------------- -# CLI: original script -# ------------------- -def main(): - print("💪 Welcome to your AI Personal Trainer!") - goal = input("What's your fitness goal? ") - experience = input("What's your experience level (beginner/intermediate/advanced)? ") - days = input("How many days per week can you train? ") - equipment = input("What equipment do you have? ") - - prompt = f""" - You are a personal trainer. Create a 1-week gym plan for someone with: - Goal: {goal} - Experience: {experience} - Days per week: {days} - Equipment: {equipment} - Return it as a structured text plan (Day 1, Day 2...). - """ - - # UPDATED TO NEW API - response = client.chat.completions.create( - model="gpt-4o-mini", - messages=[{"role": "user", "content": prompt}], - temperature=0.7 - ) - - print("\n🏋️ Your Gym Plan:\n") - print(response.choices[0].message.content) - -# ------------------- -# Web API: FastAPI -# ------------------- -app = FastAPI(title="AI Personal Trainer API") - -# Home route so you don't get 404 -@app.get("/") -def home(): - return {"message": "API is running — go to /docs"} - -class UserData(BaseModel): +key = os.getenv("GroqAPI") +client = Groq(api_key=key) +llm = ChatGroq(temperature=0.7, model="llama3-8b-8192", api_key=key) + +# Build LangChain memory +def build_memory(messages: list): + history = [ + HumanMessage(content=m["content"]) if m["role"] == "user" + else AIMessage(content=m["content"]) + for m in messages + ] + + return history + + +# Build prompt template + +def build_prompt_template(): + return ChatPromptTemplate.from_messages([ + ("system", + """You are an AI personal trainer. + + User preferences: + - Goal: {goal} + - Experience: {experience} + - Days per week: {days_per_week} + - Equipment: {equipment} + - Coaching tone: {tone} + + Adapt all responses to these preferences.""" + ), + ("ai", "{chat_history}"), + ("human", "{input}") + ]) + + +class UserInput(BaseModel): + username: str goal: str experience: str days_per_week: int - equipment: List[str] = [] - -@app.post("/generate_plan") -def generate_plan(user: UserData): - prompt = f""" - You are a personal trainer. Create a 1-week gym plan for someone with: - Goal: {user.goal} - Experience: {user.experience} - Days per week: {user.days_per_week} - Equipment: {', '.join(user.equipment)} - Return it as a structured text plan (Day 1, Day 2...). - """ - - # CORRECT NEW API CALL - response = client.chat.completions.create( - model="gpt-4o-mini", - messages=[{"role": "user", "content": prompt}], - temperature=0.7 - ) - - return {"plan": response.choices[0].message.content} - -# ------------------- -# Run CLI if script is executed directly -# ------------------- + equipment: str + tone: str + +class ChatInput(BaseModel): + username: str + message: str + messages: list + +class AuthInput(BaseModel): + username: str + session_id: str + + +app = FastAPI() + + +# @app.post("/generate_plan/") +# def generate_plan(data: UserInput): +# prompt = f""" +# You are an expert fitness coach. +# Create a weekly workout plan: +# - Goal: {data.goal} +# - Experience: {data.experience} +# - Days/week: {data.days_per_week} +# - Equipment: {data.equipment} +# """ +# try: +# response = client.chat.completions.create( +# model="llama3-8b-8192", +# messages=[{ +# "role": "system", +# "content": "You are an expert fitness coach." +# }, { +# "role": "user", +# "content": prompt +# }]) +# plan_text = response.choices[0].message.content +# return {"gym_plan": plan_text} + +# except Exception as e: +# return {"error": str(e)} + +@app.post("/login/") +def login(data: AuthInput): + if data.username: + user = db.get_user(db.session, data.username) + if user: + db.update_session(db.session, data.username, data.session_id) + return {"exists": True} + else: + return {"exists": False} + +@app.post("/signup/") +def signup(data: AuthInput): + if data.username: + user = db.get_user(db.session, data.username) + if user: + return {"exists": True} + else: + db.create_user(db.session, data.username, data.session_id) + return {"exists": False} + +@app.post("/update_preferences/") +def update_preferences(data: UserInput): + preferences_json = { + "goal": data.goal, + "experience": data.experience, + "days_per_week": data.days_per_week, + "equipment": data.equipment, + "tone": data.tone + } + db.update_user_preferences(db.session, data.username, str(preferences_json)) + +@app.get("/chat_history/{username}") +def get_chat_history(username: str): + messages = db.get_chat_messages(db.session, username) + return {"messages": messages} + + +@app.post("/chat/") +def chat(data: ChatInput): + # 1. Load user preferences + user_preferences = db.get_user_preferences(db.session, data.username) + + # 2. Build memory + memory = build_memory(data.messages) + + # 3. Build prompt template + prompt = build_prompt_template() + + # 4. Combine prompt and LLM into a RunnableSequence + chain = RunnableSequence([prompt, llm]) + + # 5. Invoke chain with context + response = chain.invoke({ + "goal": user_preferences.preferences_json["goal"], + "experience": user_preferences.preferences_json["experience"], + "days_per_week": user_preferences.preferences_json["days_per_week"], + "equipment": user_preferences.preferences_json["equipment"], + "tone": user_preferences.preferences_json["tone"], + "chat_history": memory.messages, # <-- new way to access messages + "input": data.message + }) + + assistant_reply = response.content + + # 6. Save messages to DB + db.create_chat_message(db.session, data.username, "user", data.message) + db.create_chat_message(db.session, data.username, "assistant", assistant_reply) + + + return {"response": assistant_reply} + + + if __name__ == "__main__": - main() + import uvicorn + port = int(os.environ.get("PORT", 8000)) + uvicorn.run(app, host="0.0.0.0", port=port) + diff --git a/my_database.db b/my_database.db new file mode 100644 index 0000000000000000000000000000000000000000..6c4049f23bb5a409d79ccf91d0be4ca6211a6093 GIT binary patch literal 28672 zcmeI((Qnc~9Ki8*V;~L4-fH5@y=_gzM13}j*i9m1T5x7hO@*7oK+Ae1@s;h_Xa58L z8~-1DvsY7H31Py2+lx#k;U(Dt5DJUfoTCcM~~RGWKV&Jd?2uhf*!~%WcnX4O}s3J?pw+c~tCMRedcCrc#`= zy!MNhCwj*N(RGd2+uumJ-63(``J3xwMmxqq+GW9P16{MBl%HXOwuEkAIy^| z>-)=b`45(_R4!|!ioLgIUcJrShUY=zPo+}9d#MVYoq||lNOO%xqSG6=hi(xnk8dSV z98Fg94x=!UVX|`4FqSu}jz@p%xu|YeY}+;$7a7NF5`-#iN`>&VOKZaZ2LV{l;*OcE z<+AZBrL#O%TZOe~;xs94$XJ!`={O4gbe~ow^q;8ad+At?vsJbq+w0O!{meDBojy)( z=|@UkH@mu_Ab Date: Wed, 28 Jan 2026 08:04:35 +0000 Subject: [PATCH 3/8] Update application to correctly start backend and frontend services Modify main.py to remove the local uvicorn run command, and introduce a start.sh script to properly launch the FastAPI backend on 0.0.0.0:8000 and the Streamlit frontend on 0.0.0.0:8081. Replit-Commit-Author: Agent Replit-Commit-Session-Id: c1582ad0-2a4d-421f-abef-a344959f5e0b Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 172a0ba0-d30c-436d-8a65-58905eebfa50 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/5e51078b-5ac9-4f4e-a1d5-c7167392f72e/c1582ad0-2a4d-421f-abef-a344959f5e0b/qTLLDNh Replit-Helium-Checkpoint-Created: true --- .replit | 8 +------- main.py | 6 +----- start.sh | 8 ++++++++ 3 files changed, 10 insertions(+), 12 deletions(-) create mode 100644 start.sh diff --git a/.replit b/.replit index 481a96c..0ef1153 100644 --- a/.replit +++ b/.replit @@ -41,7 +41,6 @@ externalPort = 80 [[ports]] localPort = 8000 -externalPort = 8081 [[ports]] localPort = 8080 @@ -49,12 +48,7 @@ externalPort = 8080 [[ports]] localPort = 8501 -externalPort = 8099 [deployment] -run = "uvicorn main:app --host 0.0.0.0 --port 8000" - -[[ports]] -localPort = 8000 -externalPort = 8081 +run = "bash start.sh" diff --git a/main.py b/main.py index 636341b..bbc65c5 100644 --- a/main.py +++ b/main.py @@ -168,10 +168,6 @@ def chat(data: ChatInput): return {"response": assistant_reply} - -if __name__ == "__main__": - import uvicorn - port = int(os.environ.get("PORT", 8000)) - uvicorn.run(app, host="0.0.0.0", port=port) + diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..f2ef606 --- /dev/null +++ b/start.sh @@ -0,0 +1,8 @@ +# start.sh +#!/bin/bash + +# Start FastAPI in the background on port 8000 (adjust if needed, but 8000 is common) +uvicorn main:app --host 0.0.0.0 --port 8000 & + +# Start Streamlit in the foreground (Replit will show this in the web view) +streamlit run auth.py --server.port 8081 --server.address 0.0.0.0 \ No newline at end of file From 723da035311ae0be8afc6928c636a76dc03306f8 Mon Sep 17 00:00:00 2001 From: ranaalmaaz55 <50968377-ranaalmaaz55@users.noreply.replit.com> Date: Wed, 28 Jan 2026 09:14:00 +0000 Subject: [PATCH 4/8] Update application to run both backend and frontend services simultaneously Fixes inconsistent API URL usage in auth.py and updates run.py to launch uvicorn backend on port 8000 and Streamlit frontend on port 5000. Replit-Commit-Author: Agent Replit-Commit-Session-Id: c1582ad0-2a4d-421f-abef-a344959f5e0b Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 770336d0-cc94-4f16-95dd-a702c8d3be20 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/5e51078b-5ac9-4f4e-a1d5-c7167392f72e/c1582ad0-2a4d-421f-abef-a344959f5e0b/qTLLDNh Replit-Helium-Checkpoint-Created: true --- auth.py | 4 ++-- frontend.py | 6 +++--- run.py | 27 ++++++++++++++++++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/auth.py b/auth.py index e1c4c05..ff04314 100644 --- a/auth.py +++ b/auth.py @@ -14,7 +14,7 @@ st.session_state.session_id = str(uuid.uuid4()) API_BASE = "http://localhost:8000/login/" # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/login/" - response = requests.post(API_URL, json={"username": username, "session_id": st.session_state.session_id}) + response = requests.post(API_BASE, json={"username": username, "session_id": st.session_state.session_id}) if response.status_code == 200: if response.json()["exists"]: @@ -33,7 +33,7 @@ st.session_state.session_id = str(uuid.uuid4()) API_BASE = "http://localhost:8000/signup/" # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/signup/" - response = requests.post(API_URL, json={"username": username, "session_id": st.session_state.session_id}) + response = requests.post(API_BASE, json={"username": username, "session_id": st.session_state.session_id}) if response.status_code == 200: if response.json()["exists"]: st.warning("Username already exists. Please login or choose a different username.") diff --git a/frontend.py b/frontend.py index 6c6d914..81bd6fd 100644 --- a/frontend.py +++ b/frontend.py @@ -62,9 +62,9 @@ # ------------------------------- API_BASE = "http://localhost:8000" # API_BASE = "https://buildinpublic.ranaalmaaz55.repl.co" -PREFERENCES_API = f"{API_BASE}/update_preferences" -CHAT_API = f"{API_BASE}/chat" -HISTORY_API = f"{API_BASE}/chat_history" +PREFERENCES_API = f"{API_BASE}/update_preferences/" +CHAT_API = f"{API_BASE}/chat/" +HISTORY_API = f"{API_BASE}/chat_history/" # ------------------------------- # Session guards diff --git a/run.py b/run.py index ab2ed63..a3bccd5 100644 --- a/run.py +++ b/run.py @@ -1,4 +1,25 @@ -import uvicorn +import subprocess +import sys +import time -if __name__ == "__main__": - uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) +backend_process = subprocess.Popen( + [sys.executable, "-m", "uvicorn", "main:app", "--host", "localhost", "--port", "8000", "--reload"], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT +) + +time.sleep(2) + +frontend_process = subprocess.Popen( + [sys.executable, "-m", "streamlit", "run", "auth.py", + "--server.port", "5000", + "--server.address", "0.0.0.0", + "--server.headless", "true", + "--browser.gatherUsageStats", "false"], +) + +try: + frontend_process.wait() +except KeyboardInterrupt: + backend_process.terminate() + frontend_process.terminate() From 7aeac507b084185c24041e609a1a8bf04104796b Mon Sep 17 00:00:00 2001 From: ranaalmaaz55 <50968377-ranaalmaaz55@users.noreply.replit.com> Date: Wed, 28 Jan 2026 11:28:26 +0000 Subject: [PATCH 5/8] Fix chatbot errors and improve user preference handling Refactor auth.py, remove unused frontend.py, and update main.py to address issues with user preference storage, access, and API endpoint redirection. Replit-Commit-Author: Agent Replit-Commit-Session-Id: c1582ad0-2a4d-421f-abef-a344959f5e0b Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 8ce81780-7bb8-42bd-a905-4e91d1694166 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/5e51078b-5ac9-4f4e-a1d5-c7167392f72e/c1582ad0-2a4d-421f-abef-a344959f5e0b/qTLLDNh Replit-Helium-Checkpoint-Created: true --- auth.py | 8 ++++---- main.py | 13 ++++++++----- my_database.db | Bin 28672 -> 28672 bytes frontend.py => pages/frontend.py | 0 4 files changed, 12 insertions(+), 9 deletions(-) rename frontend.py => pages/frontend.py (100%) diff --git a/auth.py b/auth.py index ff04314..5337e9f 100644 --- a/auth.py +++ b/auth.py @@ -6,7 +6,7 @@ username = st.text_input("Username") if "session_id" in st.session_state and "username" in st.session_state: - st.switch_page("frontend.py") + st.switch_page("pages/frontend.py") if st.button("Login"): @@ -20,7 +20,7 @@ if response.json()["exists"]: st.session_state.username = username st.success("Logged in successfully!") - st.switch_page("frontend.py") + st.switch_page("pages/frontend.py") else: st.warning("User not found. Please sign up.") else: @@ -33,14 +33,14 @@ st.session_state.session_id = str(uuid.uuid4()) API_BASE = "http://localhost:8000/signup/" # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/signup/" - response = requests.post(API_BASE, json={"username": username, "session_id": st.session_state.session_id}) + response = requests.post(API_BASEE, json={"username": username, "session_id": st.session_state.session_id}) if response.status_code == 200: if response.json()["exists"]: st.warning("Username already exists. Please login or choose a different username.") else: st.session_state.username = username st.success("Signed up successfully!") - st.switch_page("frontend.py") + st.switch_page(pages/"frontend.py") else: st.error("Failed to connect to the server.") else: diff --git a/main.py b/main.py index bbc65c5..9fa2461 100644 --- a/main.py +++ b/main.py @@ -10,12 +10,14 @@ from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_core.messages import AIMessage, HumanMessage from langchain_core.runnables import RunnableSequence - +from pydantic import SecretStr load_dotenv() key = os.getenv("GroqAPI") +if not key: + raise ValueError("Groq API key not found in environment variables.") client = Groq(api_key=key) -llm = ChatGroq(temperature=0.7, model="llama3-8b-8192", api_key=key) +llm = ChatGroq(temperature=0.7, model="llama3-8b-8192", api_key=SecretStr(key)) # Build LangChain memory def build_memory(messages: list): @@ -145,8 +147,9 @@ def chat(data: ChatInput): prompt = build_prompt_template() # 4. Combine prompt and LLM into a RunnableSequence - chain = RunnableSequence([prompt, llm]) - + chain = RunnableSequence(prompt, llm) + if not user_preferences: + return {"response": "Please set your preferences first."} # 5. Invoke chain with context response = chain.invoke({ "goal": user_preferences.preferences_json["goal"], @@ -154,7 +157,7 @@ def chat(data: ChatInput): "days_per_week": user_preferences.preferences_json["days_per_week"], "equipment": user_preferences.preferences_json["equipment"], "tone": user_preferences.preferences_json["tone"], - "chat_history": memory.messages, # <-- new way to access messages + "chat_history": memory, "input": data.message }) diff --git a/my_database.db b/my_database.db index 6c4049f23bb5a409d79ccf91d0be4ca6211a6093..5dd75446040302524c3c9e6df84f921b21a36f4c 100644 GIT binary patch delta 137 zcmZp8z}WDBae_1>&qNt#MxKocOZeFs`FAkz@7OFTu#P{-jgdt()G;VAFVP~=GC3v5 zB2_mv)yzQG#3I#9*TOV8N!KhT&B)x`Aj!niFv-Zk$V}J3P}j&p!NAhW$im9VT+h(b n%-GPBi-CcGk^ct+{|}(K@Ax^{nMFB4rt)rPRQRvINI?Jq4tOKC delta 33 pcmZp8z}WDBae_1>%S0JxMwX2UOZYdl1pJX- Date: Wed, 28 Jan 2026 18:32:42 +0000 Subject: [PATCH 6/8] Update user profile and chat functionality for better personalization Fixes bugs in user preference handling, updates API calls, and refactors database models. Replit-Commit-Author: Agent Replit-Commit-Session-Id: c1582ad0-2a4d-421f-abef-a344959f5e0b Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: bfe3b6b8-cf3f-45aa-a18f-301e68c30b48 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/5e51078b-5ac9-4f4e-a1d5-c7167392f72e/c1582ad0-2a4d-421f-abef-a344959f5e0b/qTLLDNh Replit-Helium-Checkpoint-Created: true --- .replit | 2 +- auth.py | 4 +-- dbSQLAlchemy.py | 31 +++++++++--------- main.py | 82 +++++++++++++++++++++++++++++++--------------- my_database.db | Bin 28672 -> 49152 bytes pages/frontend.py | 14 ++++---- requirements.txt | 3 ++ 7 files changed, 85 insertions(+), 51 deletions(-) diff --git a/.replit b/.replit index 0ef1153..b9f4c9b 100644 --- a/.replit +++ b/.replit @@ -5,7 +5,7 @@ integrations = ["python_openai_ai_integrations:1.0.0"] [nix] channel = "stable-25_05" -packages = ["glibcLocales", "mailutils"] +packages = ["glibcLocales", "libxcrypt", "mailutils"] [workflows] runButton = "Project" diff --git a/auth.py b/auth.py index 5337e9f..90c186c 100644 --- a/auth.py +++ b/auth.py @@ -33,14 +33,14 @@ st.session_state.session_id = str(uuid.uuid4()) API_BASE = "http://localhost:8000/signup/" # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/signup/" - response = requests.post(API_BASEE, json={"username": username, "session_id": st.session_state.session_id}) + response = requests.post(API_BASE, json={"username": username, "session_id": st.session_state.session_id}) if response.status_code == 200: if response.json()["exists"]: st.warning("Username already exists. Please login or choose a different username.") else: st.session_state.username = username st.success("Signed up successfully!") - st.switch_page(pages/"frontend.py") + st.switch_page("pages/frontend.py") else: st.error("Failed to connect to the server.") else: diff --git a/dbSQLAlchemy.py b/dbSQLAlchemy.py index f1fc0a7..2d4504d 100644 --- a/dbSQLAlchemy.py +++ b/dbSQLAlchemy.py @@ -3,7 +3,6 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from datetime import datetime -from sqlalchemy import create_engine #connrct to db or create if not exists engine = create_engine('sqlite:///my_database.db', echo=True) @@ -26,19 +25,21 @@ class ChatMessage(Base): content = Column(String, nullable=False) created_at = Column(DateTime, default=datetime.utcnow) -class Plan(Base): - __tablename__ = "plans" +# class Plan(Base): +# __tablename__ = "plans" - id = Column(Integer, primary_key=True, autoincrement=True) - username = Column(String, ForeignKey("users.username"), nullable=False) - content = Column(String, nullable=False) - created_at = Column(DateTime, default=datetime.utcnow) +# id = Column(Integer, primary_key=True, autoincrement=True) +# username = Column(String, ForeignKey("users.username"), nullable=False) +# content = Column(String, nullable=False) +# created_at = Column(DateTime, default=datetime.utcnow) class UserPreferences(Base): __tablename__ = "user_preferences" username = Column(String, ForeignKey("users.username"), primary_key=True) preferences_json = Column(String, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow) + age = Column(Integer) + gender = Column(String) # Create tables @@ -76,12 +77,12 @@ def create_chat_message(db_session, username: str, role: str, content: str): db_session.commit() db_session.refresh(chat_message) -def create_plan(db_session, username: str, session_id: str, content: str): - plan = Plan(username=username, session_id=session_id, content=content) - db_session.add(plan) - db_session.commit() - db_session.refresh(plan) - return plan +# def create_plan(db_session, username: str, session_id: str, content: str): +# plan = Plan(username=username, session_id=session_id, content=content) +# db_session.add(plan) +# db_session.commit() +# db_session.refresh(plan) +# return plan def create_user_preferences(db_session, username: str, preferences_json: str): user_preferences = UserPreferences(username=username, preferences_json=preferences_json) @@ -105,6 +106,6 @@ def update_user_preferences(db_session, username: str, preferences_json: str): def get_chat_messages(db_session, username: str): return db_session.query(ChatMessage).filter_by(username=username).order_by(ChatMessage.created_at.asc()).all() -def get_plans(db_session, username: str): - return db_session.query(Plan).filter_by(username=username).all() +# def get_plans(db_session, username: str): +# return db_session.query(Plan).filter_by(username=username).all() diff --git a/main.py b/main.py index 9fa2461..725b563 100644 --- a/main.py +++ b/main.py @@ -5,37 +5,40 @@ import os from groq import Groq import dbSQLAlchemy as db -from langchain_core.prompts import ChatPromptTemplate +from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_groq import ChatGroq from langchain_core.runnables.history import RunnableWithMessageHistory -from langchain_core.messages import AIMessage, HumanMessage +# from langchain_core.messages import AIMessage, HumanMessage from langchain_core.runnables import RunnableSequence from pydantic import SecretStr +import json +from langchain.memory import ConversationBufferMemory load_dotenv() key = os.getenv("GroqAPI") if not key: raise ValueError("Groq API key not found in environment variables.") client = Groq(api_key=key) -llm = ChatGroq(temperature=0.7, model="llama3-8b-8192", api_key=SecretStr(key)) - -# Build LangChain memory -def build_memory(messages: list): - history = [ - HumanMessage(content=m["content"]) if m["role"] == "user" - else AIMessage(content=m["content"]) - for m in messages - ] +llm = ChatGroq(temperature=0.7, model="llama-3.1-8b-instant", api_key=SecretStr(key)) + +# # Build LangChain memory +# def build_memory(messages: list): +# history = [ +# HumanMessage(content=m["content"]) if m["role"] == "user" +# else AIMessage(content=m["content"]) +# for m in messages +# ] - return history +# return history # Build prompt template def build_prompt_template(): return ChatPromptTemplate.from_messages([ - ("system", - """You are an AI personal trainer. + ( + "system", + """You are an AI personal trainer. User preferences: - Goal: {goal} @@ -46,13 +49,16 @@ def build_prompt_template(): Adapt all responses to these preferences.""" ), - ("ai", "{chat_history}"), + MessagesPlaceholder(variable_name="chat_history"), ("human", "{input}") ]) + class UserInput(BaseModel): username: str + age: int + gender: str goal: str experience: str days_per_week: int @@ -62,7 +68,6 @@ class UserInput(BaseModel): class ChatInput(BaseModel): username: str message: str - messages: list class AuthInput(BaseModel): username: str @@ -121,47 +126,70 @@ def signup(data: AuthInput): @app.post("/update_preferences/") def update_preferences(data: UserInput): preferences_json = { + "age": data.age, + "gender": data.gender, "goal": data.goal, "experience": data.experience, "days_per_week": data.days_per_week, "equipment": data.equipment, "tone": data.tone } - db.update_user_preferences(db.session, data.username, str(preferences_json)) + if not db.get_user_preferences(db.session, data.username): + db.create_user_preferences(db.session, data.username, json.dumps(preferences_json)) + else: + db.update_user_preferences(db.session, data.username, json.dumps(preferences_json)) @app.get("/chat_history/{username}") def get_chat_history(username: str): messages = db.get_chat_messages(db.session, username) - return {"messages": messages} + return {"messages": [ + {"role": msg.role, "content": msg.content} for msg in messages + ] + } @app.post("/chat/") def chat(data: ChatInput): + print("connected to fastapi") # 1. Load user preferences user_preferences = db.get_user_preferences(db.session, data.username) - + messages = db.get_chat_messages(db.session, data.username) # 2. Build memory - memory = build_memory(data.messages) + print("got preferences and history") + memory = build_memory([ + {"role": msg.role, "content": msg.content} + for msg in messages + ]) + print("memory built") # 3. Build prompt template prompt = build_prompt_template() - + print("prompt built") # 4. Combine prompt and LLM into a RunnableSequence chain = RunnableSequence(prompt, llm) + print("chain built") if not user_preferences: return {"response": "Please set your preferences first."} + + preferences = json.loads(str(user_preferences.preferences_json)) + print("Memory:", memory) # 5. Invoke chain with context response = chain.invoke({ - "goal": user_preferences.preferences_json["goal"], - "experience": user_preferences.preferences_json["experience"], - "days_per_week": user_preferences.preferences_json["days_per_week"], - "equipment": user_preferences.preferences_json["equipment"], - "tone": user_preferences.preferences_json["tone"], + "goal": + preferences["goal"], + "experience": + preferences["experience"], + "days_per_week": + preferences["days_per_week"], + "equipment": + preferences["equipment"], + "tone": + preferences["tone"], "chat_history": memory, "input": data.message }) - assistant_reply = response.content + assistant_reply = str(response.content) # 6. Save messages to DB db.create_chat_message(db.session, data.username, "user", data.message) diff --git a/my_database.db b/my_database.db index 5dd75446040302524c3c9e6df84f921b21a36f4c..6a3c51c1a7bbf197a2bbd865803a6a2e08d46dc7 100644 GIT binary patch literal 49152 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 jVRZ5ccc+dX;d6ZU=gTX>KK%mmuQh_ znVgbjk*b@TYG$BoVv%a5Yhjw4q-&OvW@K(|kYr+Mm^AsByc|&b4+j1pn*|Nt@o)a2 Y&mk~r1IuO>gFpN*nvrWWqrrcE0Hr`B#{d8T diff --git a/pages/frontend.py b/pages/frontend.py index 81bd6fd..3787d26 100644 --- a/pages/frontend.py +++ b/pages/frontend.py @@ -91,6 +91,8 @@ st.subheader("⚙️ Personal Preferences") with st.form("preferences_form"): + age = st.number_input("👶 Age", min_value=18, max_value=60, value=20) + gender = st.radio("👤 Gender", ["Male", "Female"]) goal = st.text_input( "🎯 Fitness goal", placeholder="Build muscle, lose fat, stay fit..." @@ -159,18 +161,18 @@ # Display chat history # ------------------------------- for msg in st.session_state.messages: - if msg.role == "user": + if msg["role"] == "user": with st.chat_message("user"): st.markdown( f"
" - f"{msg.content}
", + f"{msg['content']}", unsafe_allow_html=True ) else: with st.chat_message("assistant"): st.markdown( f"
" - f"{msg.content}
", + f"{msg['content']}", unsafe_allow_html=True ) @@ -205,15 +207,15 @@ # Call backend with st.chat_message("assistant"): with st.spinner("Thinking..."): + st.write("⏳ Generating response...") response = requests.post( CHAT_API, json={ "username": st.session_state.username, - "message": user_input, - "messages": st.session_state.messages + "message": user_input } ) - + st.write(response.status_code) if response.status_code == 200: assistant_reply = response.json()["response"] else: diff --git a/requirements.txt b/requirements.txt index 195fd4c..02c1649 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,6 @@ openai pydantic python-dotenv requests +groq +langchain-core +langchain-groq From e1286ad0b1face0029f2b0566cff73c00dec2bfc Mon Sep 17 00:00:00 2001 From: Rana <50968377-ranaalmaaz55@users.noreply.replit.com> Date: Thu, 29 Jan 2026 16:52:43 +0000 Subject: [PATCH 7/8] My updates --- .gitignore | 8 +- ai_personal_trainer.zip | Bin 6055 -> 0 bytes auth.py | 75 ++++++------ backend/personal_trainer_agent.py | 103 ----------------- db.py | 78 ------------- dbSQLAlchemy.py | 22 +--- frontend/step2_streamlit_app.py | 47 -------- main.py | 51 +++----- my_database.db | Bin 49152 -> 24576 bytes pages/frontend.py | 185 +++++++++--------------------- replit.md | 34 ------ requirement.txt/fastapi.txt | 6 - 12 files changed, 120 insertions(+), 489 deletions(-) delete mode 100644 ai_personal_trainer.zip delete mode 100644 backend/personal_trainer_agent.py delete mode 100644 db.py delete mode 100644 frontend/step2_streamlit_app.py delete mode 100644 replit.md delete mode 100644 requirement.txt/fastapi.txt diff --git a/.gitignore b/.gitignore index 8a5d4a6..21650ab 100644 --- a/.gitignore +++ b/.gitignore @@ -215,4 +215,10 @@ marimo/_lsp/ __marimo__/ # Streamlit -.streamlit/secrets.toml \ No newline at end of file +.streamlit/secrets.toml + +# Replit +.replit +replit.nix +replit.md +BuildInPublic/ \ No newline at end of file diff --git a/ai_personal_trainer.zip b/ai_personal_trainer.zip deleted file mode 100644 index 0dda8d675b9c2010594b6619433018b7b22f649a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6055 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 ZiugD6B62SR0JzA{J7kBw4`~|!_z#N1S(5+& diff --git a/auth.py b/auth.py index 90c186c..24f1488 100644 --- a/auth.py +++ b/auth.py @@ -6,42 +6,51 @@ username = st.text_input("Username") if "session_id" in st.session_state and "username" in st.session_state: - st.switch_page("pages/frontend.py") - + st.switch_page("pages/frontend.py") +# Logging in if st.button("Login"): - if username: - st.session_state.session_id = str(uuid.uuid4()) - API_BASE = "http://localhost:8000/login/" - # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/login/" - response = requests.post(API_BASE, json={"username": username, "session_id": st.session_state.session_id}) - - if response.status_code == 200: - if response.json()["exists"]: - st.session_state.username = username - st.success("Logged in successfully!") - st.switch_page("pages/frontend.py") - else: - st.warning("User not found. Please sign up.") - else: + if username: + st.session_state.session_id = str(uuid.uuid4()) + API_BASE = "http://localhost:8000/login/" + response = requests.post(API_BASE, + json={ + "username": username, + "session_id": st.session_state.session_id + }) + + if response.status_code == 200: + if response.json()["exists"]: + st.session_state.username = username + st.success("Logged in successfully!") + st.switch_page("pages/frontend.py") + else: + st.warning("User not found. Please sign up.") + else: st.error("Failed to connect to the server.") - else: - st.error("Username is required") + else: + st.error("Username is required") +# Signing up if st.button("Signup"): - if username: - st.session_state.session_id = str(uuid.uuid4()) - API_BASE = "http://localhost:8000/signup/" - # API_BASE = "http://buildinpublic.ranaalmaaz55.repl.co/signup/" - response = requests.post(API_BASE, json={"username": username, "session_id": st.session_state.session_id}) - if response.status_code == 200: - if response.json()["exists"]: - st.warning("Username already exists. Please login or choose a different username.") - else: - st.session_state.username = username - st.success("Signed up successfully!") - st.switch_page("pages/frontend.py") - else: + if username: + st.session_state.session_id = str(uuid.uuid4()) + API_BASE = "http://localhost:8000/signup/" + response = requests.post(API_BASE, + json={ + "username": username, + "session_id": st.session_state.session_id + }) + if response.status_code == 200: + if response.json()["exists"]: + st.warning( + "Username already exists. Please login or choose a different username." + ) + else: + st.session_state.username = username + st.success("Signed up successfully!") + st.switch_page("pages/frontend.py") + else: st.error("Failed to connect to the server.") - else: - st.error("Username is required") + else: + st.error("Username is required") diff --git a/backend/personal_trainer_agent.py b/backend/personal_trainer_agent.py deleted file mode 100644 index 8c7ada1..0000000 --- a/backend/personal_trainer_agent.py +++ /dev/null @@ -1,103 +0,0 @@ -from fastapi import FastAPI -from fastapi.middleware.cors import CORSMiddleware -from pydantic import BaseModel -from dotenv import load_dotenv -import os -from groq import Groq - -# # Chemin vers le fichier .env (même dossier que ce script) -# dotenv_path = os.path.join(os.path.dirname(__file__), ".env") -# load_dotenv(dotenv_path) - -# # Vérifier que la clé est présente -# api_key = os.getenv("OPENAI_API_KEY") -# if not api_key: -# raise ValueError("Veuillez définir votre clé OpenAI dans le fichier .env !") - -# print("Clé API détectée :", api_key is not None) # juste pour vérifier - -# # Créer le client OpenAI avec la clé -# client = OpenAI(api_key=api_key) - -# # Création de l'application FastAPI -# app = FastAPI() - -# app.add_middleware( -# CORSMiddleware, -# allow_origins=["*"], -# allow_credentials=True, -# allow_methods=["*"], -# allow_headers=["*"], -# ) - -# # Modèle pour les entrées utilisateur -# class UserInput(BaseModel): -# goal: str -# experience: str -# days: int -# equipment: str - -# # Route pour générer le plan -# @app.post("/generate_plan") -# def generate_plan(data: UserInput): -# if data.days <= 0: -# return {"error": "Le nombre de jours doit être supérieur à 0"} - -# prompt = f""" -# You are an expert fitness coach. -# Create a weekly workout plan: -# - Goal: {data.goal} -# - Experience: {data.experience} -# - Days/week: {data.days} -# - Equipment: {data.equipment} -# """ - -# try: -# response = client.chat.completions.create( -# model="gpt-4o-mini", -# messages=[ -# {"role": "system", "content": "You are an expert fitness coach."}, -# {"role": "user", "content": prompt} -# ] -# ) -# plan_text = response.choices[0].message["content"] -# return {"plan": plan_text} - -# except Exception as e: -# return {"error": str(e)} - -load_dotenv() -key = os.getenv("Groq_API") -client = Groq(api_key=key) - -class UserInput(BaseModel): - goal: str - experience: str - days_per_week: int - equipment: str - -app = FastAPI() - -@app. post("/generate_plan/") -def generate_plan(data: UserInput): - prompt = f""" - You are an expert fitness coach. - Create a weekly workout plan: - - Goal: {data.goal} - - Experience: {data.experience} - - Days/week: {data.days} - - Equipment: {data.equipment} - """ - try: - response = client.chat.completions.create( - model="llama3-8b-8192", - messages=[ - {"role": "system", "content": "You are an expert fitness coach."}, - {"role": "user", "content": prompt} - ] - ) - plan_text = response.choices[0].message.content - return {"gym_plan": plan_text} - - except Exception as e: - return {"error": str(e)} \ No newline at end of file diff --git a/db.py b/db.py deleted file mode 100644 index bfad719..0000000 --- a/db.py +++ /dev/null @@ -1,78 +0,0 @@ -# db.py -import sqlite3 -from contextlib import closing -from pathlib import Path - -DB_PATH = Path("chat.db") - - -def get_connection(): - """Return a SQLite connection.""" - return sqlite3.connect(DB_PATH, check_same_thread=False) - - -def init_db(): - """Create the users table if it does not exist.""" - with closing(get_connection()) as conn: - cursor = conn.cursor() - cursor.execute(""" - CREATE TABLE IF NOT EXISTS users ( - username TEXT PRIMARY KEY, - session_id TEXT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP - ); - - CREATE TABLE IF NOT EXISTS chat_messages ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - session_id TEXT NOT NULL, - role TEXT CHECK(role IN ('user', 'assistant')), - content TEXT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (session_id) REFERENCES users(session_id) - ); - CREATE TABLE IF NOT EXISTS plans ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username TEXT NOT NULL, - session_id TEXT NOT NULL, - plan_type TEXT, - content TEXT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (username) REFERENCES users(username) - FOREIGN KEY (session_id) REFERENCES users(session_id), - FOREIGN KEY (username) REFERENCES users(username) - ); - CREATE TABLE IF NOT EXISTS user_preferences ( - username TEXT PRIMARY KEY, - preferences_json TEXT, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (username) REFERENCES users(username) - ); - """) - conn.commit() - - -# CRUD helpers -def create_user(username: str, session_id: str): - with closing(get_connection()) as conn: - cursor = conn.cursor() - cursor.execute( - "INSERT INTO users (username, session_id) VALUES (?, ?)", - (username, session_id)) - conn.commit() - - -def get_user(username: str): - with closing(get_connection()) as conn: - cursor = conn.cursor() - cursor.execute( - "SELECT username, session_id FROM users WHERE username = ?", - (username, )) - return cursor.fetchone() - - -def update_session_id(username: str, session_id: str): - with closing(get_connection()) as conn: - cursor = conn.cursor() - cursor.execute("UPDATE users SET session_id = ? WHERE username = ?", - (session_id, username)) - conn.commit() diff --git a/dbSQLAlchemy.py b/dbSQLAlchemy.py index 2d4504d..c2c2e79 100644 --- a/dbSQLAlchemy.py +++ b/dbSQLAlchemy.py @@ -1,14 +1,12 @@ -# db_sqlalchemy.py from sqlalchemy import Column, String, DateTime, create_engine, Integer, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from datetime import datetime -#connrct to db or create if not exists +#connect to db or create if not exists engine = create_engine('sqlite:///my_database.db', echo=True) Base = declarative_base() -# User model class User(Base): __tablename__ = "users" @@ -25,13 +23,6 @@ class ChatMessage(Base): content = Column(String, nullable=False) created_at = Column(DateTime, default=datetime.utcnow) -# class Plan(Base): -# __tablename__ = "plans" - -# id = Column(Integer, primary_key=True, autoincrement=True) -# username = Column(String, ForeignKey("users.username"), nullable=False) -# content = Column(String, nullable=False) -# created_at = Column(DateTime, default=datetime.utcnow) class UserPreferences(Base): __tablename__ = "user_preferences" @@ -77,12 +68,7 @@ def create_chat_message(db_session, username: str, role: str, content: str): db_session.commit() db_session.refresh(chat_message) -# def create_plan(db_session, username: str, session_id: str, content: str): -# plan = Plan(username=username, session_id=session_id, content=content) -# db_session.add(plan) -# db_session.commit() -# db_session.refresh(plan) -# return plan + def create_user_preferences(db_session, username: str, preferences_json: str): user_preferences = UserPreferences(username=username, preferences_json=preferences_json) @@ -105,7 +91,3 @@ def update_user_preferences(db_session, username: str, preferences_json: str): def get_chat_messages(db_session, username: str): return db_session.query(ChatMessage).filter_by(username=username).order_by(ChatMessage.created_at.asc()).all() - -# def get_plans(db_session, username: str): -# return db_session.query(Plan).filter_by(username=username).all() - diff --git a/frontend/step2_streamlit_app.py b/frontend/step2_streamlit_app.py deleted file mode 100644 index 420c5d9..0000000 --- a/frontend/step2_streamlit_app.py +++ /dev/null @@ -1,47 +0,0 @@ -import streamlit as st -import requests -import os - -st.set_page_config(page_title="AI Personal Trainer", page_icon="💪") -st.title("💪 Your AI Personal Trainer") -st.write( - "Answer a few questions and get your personalized gym plan instantly.") - -with st.form("trainer_form"): - goal = st.text_input( - "🎯 What's your fitness goal? (e.g. build muscle, lose fat, stay fit)") - experience = st.selectbox("🔥 Your experience level:", - ["Beginner", "Intermediate", "Advanced"]) - days_per_week = st.slider("📅 How many days per week can you train?", 1, 7, - 4) - equipment = st.text_area( - "🏋️ What equipment do you have? (e.g. dumbbells, resistance bands, gym access)" - ) - submitted = st.form_submit_button("Generate Plan 🚀") - -API_URL = "http://localhost:8000/generate_plan/" - -if submitted: - if not goal or not equipment: - st.warning("⚠️ Please fill in all fields before submitting.") - else: - with st.spinner("Generating your gym plan..."): - try: - response = requests.post(API_URL, - json={ - "goal": goal, - "experience": experience, - "days_per_week": days_per_week, - "equipment": equipment - }) - - if response.status_code == 200: - plan = response.json()["gym_plan"] - st.success("🏋️ Here's your personalized plan:") - st.markdown(plan) - else: - st.error("❌ Something went wrong. Please try again.") - except requests.exceptions.ConnectionError: - st.error( - "❌ Could not connect to the backend. Please make sure the server is running." - ) diff --git a/main.py b/main.py index 725b563..2f3c447 100644 --- a/main.py +++ b/main.py @@ -8,11 +8,10 @@ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_groq import ChatGroq from langchain_core.runnables.history import RunnableWithMessageHistory -# from langchain_core.messages import AIMessage, HumanMessage +from langchain_core.messages import AIMessage, HumanMessage from langchain_core.runnables import RunnableSequence from pydantic import SecretStr import json -from langchain.memory import ConversationBufferMemory load_dotenv() key = os.getenv("GroqAPI") @@ -21,15 +20,15 @@ client = Groq(api_key=key) llm = ChatGroq(temperature=0.7, model="llama-3.1-8b-instant", api_key=SecretStr(key)) -# # Build LangChain memory -# def build_memory(messages: list): -# history = [ -# HumanMessage(content=m["content"]) if m["role"] == "user" -# else AIMessage(content=m["content"]) -# for m in messages -# ] +# Build LangChain memory +def build_memory(messages: list): + history = [ + HumanMessage(content=m["content"]) if m["role"] == "user" + else AIMessage(content=m["content"]) + for m in messages + ] -# return history + return history # Build prompt template @@ -64,6 +63,8 @@ class UserInput(BaseModel): days_per_week: int equipment: str tone: str + weight: int + height: int class ChatInput(BaseModel): username: str @@ -77,32 +78,6 @@ class AuthInput(BaseModel): app = FastAPI() -# @app.post("/generate_plan/") -# def generate_plan(data: UserInput): -# prompt = f""" -# You are an expert fitness coach. -# Create a weekly workout plan: -# - Goal: {data.goal} -# - Experience: {data.experience} -# - Days/week: {data.days_per_week} -# - Equipment: {data.equipment} -# """ -# try: -# response = client.chat.completions.create( -# model="llama3-8b-8192", -# messages=[{ -# "role": "system", -# "content": "You are an expert fitness coach." -# }, { -# "role": "user", -# "content": prompt -# }]) -# plan_text = response.choices[0].message.content -# return {"gym_plan": plan_text} - -# except Exception as e: -# return {"error": str(e)} - @app.post("/login/") def login(data: AuthInput): if data.username: @@ -132,7 +107,9 @@ def update_preferences(data: UserInput): "experience": data.experience, "days_per_week": data.days_per_week, "equipment": data.equipment, - "tone": data.tone + "tone": data.tone, + "weight": data.weight, + "height": data.height } if not db.get_user_preferences(db.session, data.username): db.create_user_preferences(db.session, data.username, json.dumps(preferences_json)) diff --git a/my_database.db b/my_database.db index 6a3c51c1a7bbf197a2bbd865803a6a2e08d46dc7..3971ede501f456fe9e9ff410f891c000eff0501f 100644 GIT binary patch literal 24576 zcmeI4OK;mo5P+#X>_kZFUJUovsSCt$V5)lg5fw!%JG3LzkyA;okwYP@$g#+nB5Ce2 zj#2c`&aNcKa+TK2sR%}pY;hm6v)|6ng3DR8zu65G!eN{a zgo29op_R*7UjbN_b%Q=L^clad(wA%F3;Lfs_x){OZ&-y_f8L(^!@7R!wKZ3s`}KoQ zZ@s?#+uMqBIul?5On?b60Vco%m;e)C0!-jC1YXQvn_aN&+{^Ej=!KX`OuI>nhnQmI zqP%#0eXHfvI}UW}o4XEN%!Rx8n>sBL1B7qut*wXk7Bu%d(A?kMU4i_~bCSDHWgJZ{ zlqH@}=ymDN>H)RYX*_atUC~EqG&|0Y)6$oHj66)o0(8pbR^w5<^#s0lp1|F)8p}Fo zd#~j*cA7fpO$M}_ZKvflx16@=h&)#*zx?I(nT58UvjS@6xjYW(cCRZk6`Sks#g2DN z7gJ_l+`2luu(XtWd0@c0zEIr(N=e<26BpMekWOT2o`E;+^#sXr|Hc3&GSfJm&fkqA zg^`+C$xU$@_6e$i_pUsD{3tiOu&|JOF?VKX#<=8_iSFxe(Lnr*8A;+8#8H>nOtZ4f z^kmF$IlsJoWoF@vg?}1qIUHZ9@8$LVy>**Dxw)S$dh?43FaajO1egF5U;<2l2`~XB zzyz286ZoGI*v?&>->NfC(@GCh(pS zn7ulGQ|}(==l@r3{BF(tLVx(h1egF5U;<2l2{3{8g}|$WE3?-8$3Jz=0~0|Zmr{vH zQBd!r$Bn(_3Ow1{U;0+Z0)Oo^q4Usz?MAEJfp*7v44u7$dh0hJzI1l-h}0e|cKfN@3LEf38_2ok9^EotIiE+7c;} z*aJTfz5ME#Uih4Xi*;b`nRYZ(q!%%!A=Z$mYB$1CuEC~oj|`Q~^H4V5j8Ph&oXHks z5+@kyo)c+fn>6e_f;zPo!nc{F3F1_^M9B1$M)OSzm(rdH8EwJM((p{VOI0Ou2SOWu zp#FjH2v4O3Ep0SpT-sPV;s|N*2|#FjNKwLEuwmzCHDGkvxObhTN&X#BzphzPs z5-6H}Lp!Y2U>Eyi(`z4RLQQ2uP6$n9+ggUK)55-#)DjacV0} zv~}x1`%ByIIY<+7FIeHIPpig!)-FpefcpFVN0OgwUZmS<_9}G^XhQvV`U%oe$UG zT^~;3^oab#&_}G=r6LT1h=`dP9vc7Siqs2YqbqqeRIX2q3M9`AJBfm|qJ6(eenHPY zId&_?Pv~OXW1p6!aY9|xhtrKTg{~h3#~Fe)2-C4BGZc)IN~Ess5G-=Zf+o95X5t0p z`?Mb<2j+$uSs0L5g+XMK!}3XZOezpXnI%a~ZhPc``!s))uLZUh*`a^xrTS2T(L=ja zjN+{CgA5T9xVvuOCm)ifa(PH8(jbT|EiAA@$3{928|@VsFF2o=1*he}Ueg&aGF!W} zrnG3SnYzqOKEAK4*H+gHYa7KNfC(@GCcp%k026pu0zV$)X6IiV*DXswGyi^( ze)?ds2Ib-kEDnFYfvy&}aUeom)M>E@b;_pM+Z}Ew=yZHe+ZloWISP|I+BMcWwACfM zl-Z^I)g#KR>eA!AUR}5uE4_=N%PQKL)k%+H6+AOr%G4UA4>u-tWv!QQwkheVv{wA# yZ}Ccp%k025#WOn?b60Vco%m;e*_{}UL;|NjNJU#zhJ literal 49152 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 jVRZ5ccc+dX;d6ZU=" f"{msg['content']}", - unsafe_allow_html=True - ) + unsafe_allow_html=True) else: with st.chat_message("assistant"): st.markdown( f"
" f"{msg['content']}
", - unsafe_allow_html=True - ) + unsafe_allow_html=True) - # ------------------------------- - # Input + Send button - # ------------------------------- + # Chat input col1, col2 = st.columns([5, 1]) with col1: user_input = st.text_input( "Type your message", - placeholder="Ask about workouts, nutrition, recovery..." - ) + placeholder="Ask about workouts, nutrition, recovery...") with col2: send_clicked = st.button("Send ➤") @@ -201,20 +129,18 @@ st.markdown( f"
" f"{user_input}
", - unsafe_allow_html=True - ) + unsafe_allow_html=True) # Call backend with st.chat_message("assistant"): with st.spinner("Thinking..."): st.write("⏳ Generating response...") - response = requests.post( - CHAT_API, - json={ - "username": st.session_state.username, - "message": user_input - } - ) + response = requests.post(CHAT_API, + json={ + "username": + st.session_state.username, + "message": user_input + }) st.write(response.status_code) if response.status_code == 200: assistant_reply = response.json()["response"] @@ -224,8 +150,7 @@ st.markdown( f"
" f"{assistant_reply}
", - unsafe_allow_html=True - ) + unsafe_allow_html=True) st.session_state.messages.append({ "role": "assistant", diff --git a/replit.md b/replit.md deleted file mode 100644 index 55cef4b..0000000 --- a/replit.md +++ /dev/null @@ -1,34 +0,0 @@ -# AI Personal Trainer - -## Overview -A full-stack AI application that generates personalized gym workout plans using OpenAI. - -## Architecture -- **Frontend**: Streamlit (port 5000) - User interface for collecting fitness goals -- **Backend**: FastAPI with uvicorn (port 8000) - API for generating workout plans -- **AI**: OpenAI GPT-4o-mini via Replit AI Integrations - -## Running the Application -The application is run via `python run.py` which: -1. Starts the FastAPI backend on localhost:8000 -2. Starts the Streamlit frontend on 0.0.0.0:5000 - -## Project Structure -``` -├── api.py # FastAPI backend with OpenAI integration -├── frontend.py # Streamlit frontend -├── run.py # Launcher script for both services -├── main.py # CLI version (not used in web app) -├── requirements.txt -└── replit.md -``` - -## Dependencies -- fastapi, uvicorn - Web API framework -- streamlit - Frontend framework -- openai - AI integration (uses Replit AI Integrations) -- pydantic - Data validation - -## Notes -- OpenAI access is provided through Replit AI Integrations (no API key needed) -- Backend runs on localhost, frontend binds to 0.0.0.0 for Replit proxy access diff --git a/requirement.txt/fastapi.txt b/requirement.txt/fastapi.txt deleted file mode 100644 index 8e559cf..0000000 --- a/requirement.txt/fastapi.txt +++ /dev/null @@ -1,6 +0,0 @@ -fastapi -uvicorn -openai -python-dotenv -streamlit -requests From b491e722848dc527f0391a6df1e6bc35ae0f779a Mon Sep 17 00:00:00 2001 From: Rana <50968377-ranaalmaaz55@users.noreply.replit.com> Date: Thu, 29 Jan 2026 17:35:39 +0000 Subject: [PATCH 8/8] Final --- .replit | 54 ------------------------------------------------- .sample.env | 1 - my_database.db | Bin 24576 -> 0 bytes 3 files changed, 55 deletions(-) delete mode 100644 .replit delete mode 100644 .sample.env delete mode 100644 my_database.db diff --git a/.replit b/.replit deleted file mode 100644 index b9f4c9b..0000000 --- a/.replit +++ /dev/null @@ -1,54 +0,0 @@ -modules = ["python-3.11"] -[agent] -expertMode = true -integrations = ["python_openai_ai_integrations:1.0.0"] - -[nix] -channel = "stable-25_05" -packages = ["glibcLocales", "libxcrypt", "mailutils"] - -[workflows] -runButton = "Project" - -[[workflows.workflow]] -name = "Project" -mode = "parallel" -author = "agent" - -[[workflows.workflow.tasks]] -task = "workflow.run" -args = "AI Personal Trainer" - -[[workflows.workflow]] -name = "AI Personal Trainer" -author = "agent" - -[[workflows.workflow.tasks]] -task = "shell.exec" -args = "python run.py" -waitForPort = 5000 - -[workflows.workflow.metadata] -outputType = "webview" - -[[ports]] -localPort = 3000 -externalPort = 3000 - -[[ports]] -localPort = 5000 -externalPort = 80 - -[[ports]] -localPort = 8000 - -[[ports]] -localPort = 8080 -externalPort = 8080 - -[[ports]] -localPort = 8501 - -[deployment] -run = "bash start.sh" - diff --git a/.sample.env b/.sample.env deleted file mode 100644 index ac74257..0000000 --- a/.sample.env +++ /dev/null @@ -1 +0,0 @@ -OPENAI_API_KEY='' \ No newline at end of file diff --git a/my_database.db b/my_database.db deleted file mode 100644 index 3971ede501f456fe9e9ff410f891c000eff0501f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 zcmeI4OK;mo5P+#X>_kZFUJUovsSCt$V5)lg5fw!%JG3LzkyA;okwYP@$g#+nB5Ce2 zj#2c`&aNcKa+TK2sR%}pY;hm6v)|6ng3DR8zu65G!eN{a zgo29op_R*7UjbN_b%Q=L^clad(wA%F3;Lfs_x){OZ&-y_f8L(^!@7R!wKZ3s`}KoQ zZ@s?#+uMqBIul?5On?b60Vco%m;e)C0!-jC1YXQvn_aN&+{^Ej=!KX`OuI>nhnQmI zqP%#0eXHfvI}UW}o4XEN%!Rx8n>sBL1B7qut*wXk7Bu%d(A?kMU4i_~bCSDHWgJZ{ zlqH@}=ymDN>H)RYX*_atUC~EqG&|0Y)6$oHj66)o0(8pbR^w5<^#s0lp1|F)8p}Fo zd#~j*cA7fpO$M}_ZKvflx16@=h&)#*zx?I(nT58UvjS@6xjYW(cCRZk6`Sks#g2DN z7gJ_l+`2luu(XtWd0@c0zEIr(N=e<26BpMekWOT2o`E;+^#sXr|Hc3&GSfJm&fkqA zg^`+C$xU$@_6e$i_pUsD{3tiOu&|JOF?VKX#<=8_iSFxe(Lnr*8A;+8#8H>nOtZ4f z^kmF$IlsJoWoF@vg?}1qIUHZ9@8$LVy>**Dxw)S$dh?43FaajO1egF5U;<2l2`~XB zzyz286ZoGI*v?&>->NfC(@GCh(pS zn7ulGQ|}(==l@r3{BF(tLVx(h1egF5U;<2l2{3{8g}|$WE3?-8$3Jz=0~0|Zmr{vH zQBd!r$Bn(_3Ow1{U;0+Z0)Oo^q4Usz?MAEJfp*7v44u7$dh0hJzI1l-h}0e|cKfN@3LEf38_2ok9^EotIiE+7c;} z*aJTfz5ME#Uih4Xi*;b`nRYZ(q!%%!A=Z$mYB$1CuEC~oj|`Q~^H4V5j8Ph&oXHks z5+@kyo)c+fn>6e_f;zPo!nc{F3F1_^M9B1$M)OSzm(rdH8EwJM((p{VOI0Ou2SOWu zp#FjH2v4O3Ep0SpT-sPV;s|N*2|#FjNKwLEuwmzCHDGkvxObhTN&X#BzphzPs z5-6H}Lp!Y2U>Eyi(`z4RLQQ2uP6$n9+ggUK)55-#)DjacV0} zv~}x1`%ByIIY<+7FIeHIPpig!)-FpefcpFVN0OgwUZmS<_9}G^XhQvV`U%oe$UG zT^~;3^oab#&_}G=r6LT1h=`dP9vc7Siqs2YqbqqeRIX2q3M9`AJBfm|qJ6(eenHPY zId&_?Pv~OXW1p6!aY9|xhtrKTg{~h3#~Fe)2-C4BGZc)IN~Ess5G-=Zf+o95X5t0p z`?Mb<2j+$uSs0L5g+XMK!}3XZOezpXnI%a~ZhPc``!s))uLZUh*`a^xrTS2T(L=ja zjN+{CgA5T9xVvuOCm)ifa(PH8(jbT|EiAA@$3{928|@VsFF2o=1*he}Ueg&aGF!W} zrnG3SnYzqOKEAK4*H+gHYa7KNfC(@GCcp%k026pu0zV$)X6IiV*DXswGyi^( ze)?ds2Ib-kEDnFYfvy&}aUeom)M>E@b;_pM+Z}Ew=yZHe+ZloWISP|I+BMcWwACfM zl-Z^I)g#KR>eA!AUR}5uE4_=N%PQKL)k%+H6+AOr%G4UA4>u-tWv!QQwkheVv{wA# yZ}Ccp%k025#WOn?b60Vco%m;e*_{}UL;|NjNJU#zhJ