Spaces:
Runtime error
Runtime error
from flask import Flask, request, jsonify | |
import pymongo | |
from routes.auth_routes import auth_bp | |
from flask_cors import CORS | |
import os | |
from werkzeug.utils import secure_filename | |
from utils.audioextraction import extract_audio | |
from utils.expressions import analyze_video_emotions | |
from utils.transcription import speech_to_text_long | |
from utils.vocals import predict_emotion | |
from utils.vocabulary import evaluate_vocabulary | |
from groq import Groq | |
import pandas as pd | |
from bson import ObjectId | |
import json | |
from dotenv import load_dotenv | |
from datetime import datetime | |
from utils.models import load_models | |
load_dotenv() | |
app = Flask(__name__) | |
CORS(app) | |
# Load models on startup | |
models = load_models() | |
# MongoDB connection | |
client = pymongo.MongoClient("mongodb+srv://pmsankheb23:[email protected]/") | |
db = client["Eloquence"] | |
collections_user = db["user"] | |
reports_collection = db["reports"] | |
overall_reports_collection = db["overall_reports"] | |
# Groq client setup | |
groq_client = Groq(api_key=os.environ.get("GROQ_API_KEY")) | |
# Configure upload folder | |
UPLOAD_FOLDER = 'uploads' | |
ALLOWED_EXTENSIONS = {'mp4', 'webm', 'wav'} | |
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER | |
if not os.path.exists(UPLOAD_FOLDER): | |
os.makedirs(UPLOAD_FOLDER) | |
def allowed_file(filename): | |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS | |
def convert_objectid_to_string(data): | |
if isinstance(data, dict): | |
new_dict = {} | |
for k, v in data.items(): | |
if isinstance(v, datetime): | |
new_dict[k] = v.isoformat() | |
else: | |
new_dict[k] = convert_objectid_to_string(v) | |
return new_dict | |
elif isinstance(data, list): | |
return [convert_objectid_to_string(item) for item in data] | |
elif isinstance(data, ObjectId): | |
return str(data) | |
return data | |
app.register_blueprint(auth_bp) | |
def home(): | |
return "Hello World" | |
def upload_file(): | |
if 'file' not in request.files: | |
return jsonify({"error": "No file part"}), 400 | |
file = request.files['file'] | |
context = request.form.get('context', '') | |
title = request.form.get('title', 'Untitled Session') | |
mode = request.form.get('mode', 'video') | |
user_id = request.form.get('userId') | |
if not user_id: | |
return jsonify({"error": "User ID is required"}), 400 | |
if file.filename == '': | |
return jsonify({"error": "No selected file"}), 400 | |
if file and allowed_file(file.filename): | |
filename = secure_filename(file.filename) | |
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) | |
file.save(file_path) | |
audio_path = os.path.join(app.config['UPLOAD_FOLDER'], 'output.wav') | |
if not extract_audio(file_path, audio_path): | |
os.remove(file_path) | |
return jsonify({"error": "Failed to process audio from the file"}), 500 | |
emotion_analysis = pd.DataFrame() | |
if mode == "video": | |
emotion_analysis = analyze_video_emotions(file_path, models["fer"]) | |
transcription = speech_to_text_long(audio_path, models["whisper"]) | |
audio_emotion = predict_emotion( | |
audio_path, | |
models["emotion_model"], | |
models["emotion_feature_extractor"], | |
models["emotion_id2label"], | |
) | |
vocabulary_report = evaluate_vocabulary(transcription, context) | |
scores = generate_scores(transcription, audio_emotion, emotion_analysis) | |
speech_report = generate_speech_report(transcription, context, audio_emotion) | |
expression_report = generate_expression_report(emotion_analysis) if mode == "video" else "No expression analysis for audio-only mode." | |
report_data = { | |
"userId": user_id, | |
"title": title, | |
"context": context, | |
"transcription": transcription, | |
"vocabulary_report": vocabulary_report, | |
"speech_report": speech_report, | |
"expression_report": expression_report, | |
"scores": scores, | |
"createdAt": datetime.utcnow() | |
} | |
result = reports_collection.insert_one(report_data) | |
report_data["_id"] = str(result.inserted_id) | |
update_overall_reports(user_id) | |
os.remove(file_path) | |
os.remove(audio_path) | |
return jsonify(convert_objectid_to_string(report_data)), 200 | |
return jsonify({"error": "File type not allowed"}), 400 | |
def chat(): | |
try: | |
data = request.get_json() | |
user_id = data.get('userId') | |
user_message = data.get('message') | |
if not user_id or not user_message: | |
return jsonify({"error": "User ID and message are required"}), 400 | |
user_reports = list(reports_collection.find({"userId": user_id})) | |
reports_summary = "Here is a summary of the user's past performance:\n" | |
for report in user_reports: | |
reports_summary += f"- Session '{report.get('title', 'Untitled')}':\n" | |
reports_summary += f" - Vocabulary Score: {report['scores']['vocabulary']}\n" | |
reports_summary += f" - Voice Score: {report['scores']['voice']}\n" | |
reports_summary += f" - Expressions Score: {report['scores']['expressions']}\n" | |
reports_summary += f" - Feedback: {report.get('speech_report', '')}\n\n" | |
system_message = f""" | |
You are 'Eloquence AI', a friendly and expert public speaking coach. Your goal is to help users improve their speaking skills by providing constructive, encouraging, and actionable feedback. | |
User's Past Performance Summary: | |
{reports_summary} | |
Based on this history and the user's current message, provide a helpful and encouraging response. Be conversational and supportive. | |
""" | |
chat_completion = groq_client.chat.completions.create( | |
messages=[ | |
{"role": "system", "content": system_message}, | |
{"role": "user", "content": user_message}, | |
], | |
model="llama3-70b-8192", | |
) | |
ai_response = chat_completion.choices[0].message.content | |
return jsonify({"response": ai_response}), 200 | |
except Exception as e: | |
print(f"Error in /chat endpoint: {e}") | |
return jsonify({"error": "An internal error occurred"}), 500 | |
def update_overall_reports(user_id): | |
user_reports = list(reports_collection.find({"userId": user_id})) | |
if not user_reports: | |
return | |
num_reports = len(user_reports) | |
avg_vocabulary = sum(r["scores"]["vocabulary"] for r in user_reports) / num_reports | |
avg_voice = sum(r["scores"]["voice"] for r in user_reports) / num_reports | |
avg_expressions = sum(r["scores"]["expressions"] for r in user_reports) / num_reports | |
overall_report_data = { | |
"userId": user_id, | |
"avg_vocabulary": avg_vocabulary, | |
"avg_voice": avg_voice, | |
"avg_expressions": avg_expressions, | |
"overall_reports": generate_overall_reports(user_reports) | |
} | |
overall_reports_collection.update_one( | |
{"userId": user_id}, | |
{"$set": overall_report_data}, | |
upsert=True | |
) | |
def get_user_reports_list(): | |
user_id = request.args.get('userId') | |
if not user_id: | |
return jsonify({"error": "User ID is required"}), 400 | |
user_reports = list(reports_collection.find({"userId": user_id})) | |
if not user_reports: | |
return jsonify([]), 200 | |
return jsonify(convert_objectid_to_string(user_reports)), 200 | |
def get_user_reports(): | |
user_id = request.args.get('userId') | |
if not user_id: | |
return jsonify({"error": "User ID is required"}), 400 | |
overall_report = overall_reports_collection.find_one({"userId": user_id}) | |
if not overall_report: | |
return jsonify({"error": "No overall report found for the user"}), 404 | |
return jsonify(convert_objectid_to_string(overall_report)), 200 | |
def generate_report(system_message, user_message): | |
try: | |
chat_completion = groq_client.chat.completions.create( | |
messages=[ | |
{"role": "system", "content": system_message}, | |
{"role": "user", "content": user_message}, | |
], | |
model="llama3-70b-8192", | |
) | |
return chat_completion.choices[0].message.content | |
except Exception as e: | |
print(f"Error generating report: {e}") | |
return "Could not generate report due to an API error." | |
def generate_overall_reports(user_reports): | |
reports_json = json.dumps(convert_objectid_to_string(user_reports), indent=2) | |
voice_report = generate_report( | |
"You are an expert in speech analysis...", | |
f"Reports: {reports_json}\nProvide a short one paragraph report summarizing the user's overall performance in Voice..." | |
) | |
expressions_report = generate_report( | |
"You are an expert in facial expression analysis...", | |
f"Reports: {reports_json}\nProvide a short one paragraph report summarizing the user's overall performance in Facial Expressions..." | |
) | |
vocabulary_report = generate_report( | |
"You are an expert in language and vocabulary analysis...", | |
f"Reports: {reports_json}\nProvide a short one paragraph report summarizing the user's overall performance in Vocabulary..." | |
) | |
return { | |
"voice_report": voice_report, | |
"expressions_report": expressions_report, | |
"vocabulary_report": vocabulary_report, | |
} | |
def generate_scores(transcription, audio_emotion, emotion_analysis): | |
system_message = """ | |
You are an expert in speech analysis. Based on the provided data, generate scores (out of 100) for Vocabulary, Voice, and Expressions. | |
Provide only the three scores in JSON format, like: | |
{"vocabulary": 85, "voice": 78, "expressions": 90} | |
""" | |
emotion_str = emotion_analysis.to_string(index=False) if not emotion_analysis.empty else "No facial data" | |
user_message = f""" | |
Transcription: {transcription} | |
Audio Emotion Data: {audio_emotion} | |
Facial Emotion Analysis: {emotion_str} | |
Provide only the JSON output with numeric scores. | |
""" | |
report_content = generate_report(system_message, user_message) | |
try: | |
return json.loads(report_content) | |
except (json.JSONDecodeError, TypeError): | |
return {"vocabulary": 0, "voice": 0, "expressions": 0} | |
def generate_speech_report(transcription, context, audio_emotion): | |
system_message = f"Context: \"{context}\". Evaluate if emotions in audio match. Emotion data: {audio_emotion}." | |
user_message = "Provide a short one paragraph report on the emotional appropriateness of speech..." | |
return generate_report(system_message, user_message) | |
def generate_expression_report(emotion_analysis_str): | |
system_message = f"Evaluate the following emotion data: {emotion_analysis_str}." | |
user_message = "Provide a short one paragraph report on the emotional appropriateness of facial expressions..." | |
return generate_report(system_message, user_message) | |
if __name__ == '__main__': | |
app.run(debug=True) | |