TARAMALIK16 commited on
Commit
d18cfcb
·
verified ·
1 Parent(s): 4e2fc49

Upload 7 files

Browse files
model/.env ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ VITE_MODEL_API=https://moodify-4-scpi.onrender.com
2
+ VITE_TEXTMODEL_API=https://moodify-haag.onrender.com
3
+ VITE_AUTH_API=https://moodify-1-4ogp.onrender.com
4
+
5
+ VITE_USE_MOCK_AUTH=false
6
+ VITE_GEMINI_API_KEY=AIzaSyCffeP7wTkFqjOZvwaoIWr2jGAibbBj3Ko
7
+ CLOUDINARY_URL=cloudinary://535413842219598:vndwujdGpO19r0XuG69w51ZdoZ4@dkiu8wrxc
8
+ SECRET_KEY=7b063610e8d0781ecba9790967eec378
9
+ MONGO_URI=mongodb+srv://soniyavitkar2712:soniya_27@cluster0.slai2ew.mongodb.net/moodify_db?retryWrites=true&w=majority&appName=Cluster0
10
+
11
+ PORT=5002
model/Dockerfile ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a lightweight official Python image as the base
2
+ FROM python:3.10-slim
3
+
4
+ # Set the working directory inside the container
5
+ WORKDIR /app
6
+
7
+ # Copy the requirements file first to leverage Docker's build cache
8
+ COPY requirements.txt .
9
+
10
+ # Install the Python dependencies
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # Copy the rest of the application code into the container
14
+ # This includes app.py, the dnn folder, and other directories
15
+ COPY . .
16
+
17
+ # Expose the port where the Flask API will run
18
+ # This should match the app_port defined in your README.md
19
+ EXPOSE 7860
20
+
21
+ # Define the command to run the application using Gunicorn
22
+ # 'app:app' means the Flask instance named 'app' is in the 'app.py' file.
23
+ # The --bind 0.0.0.0:7860 makes Gunicorn listen on all available network interfaces on port 7860.
24
+ CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app"]
model/__init__.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/__init__.py
2
+ from flask_cors import CORS
3
+ import os
4
+ from flask import Flask
5
+ from flask_pymongo import PyMongo
6
+ from dotenv import load_dotenv
7
+ import cloudinary
8
+ import cloudinary.uploader
9
+
10
+ # Load env variables
11
+ load_dotenv()
12
+
13
+ app = Flask(__name__)
14
+
15
+ # Enable CORS
16
+ CORS(
17
+ app,
18
+ origins=[
19
+ "https://moodify-1-4ogp.onrender.com",
20
+ "https://moodify-haag.onrender.com",
21
+ "https://moodify-4-scpi.onrender.com",
22
+ "https://moodify-murex.vercel.app",
23
+ "http://localhost:5173",
24
+ "https://humble-goldfish-4j9wgq46wr6j3j6xj-5173.app.github.dev"
25
+ ],
26
+ supports_credentials=True
27
+ )
28
+
29
+ # Config from env
30
+ app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
31
+ app.config["MONGO_URI"] = os.getenv("MONGO_URI")
32
+
33
+ # MongoDB connection
34
+ mongodb_client = PyMongo(app)
35
+ db = mongodb_client.db
36
+
37
+ # Cloudinary config (reads CLOUDINARY_URL directly from .env)
38
+ cloudinary.config(
39
+ secure=True
40
+ )
41
+
42
+ # Attach routes
43
+ import routes
model/requirements.txt ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Flask & Server
2
+ Flask
3
+ flask-cors
4
+ gunicorn
5
+ Werkzeug
6
+ itsdangerous
7
+ Jinja2
8
+ click
9
+
10
+ # MongoDB
11
+ Flask-PyMongo
12
+ pymongo
13
+ dnspython
14
+
15
+ # Deep Learning & Image Processing
16
+ deepface
17
+ retina-face
18
+ tensorflow==2.20.0
19
+ tf_keras==2.20.0
20
+ keras==3.10.0
21
+ opencv-contrib-python
22
+ opencv-python
23
+ mtcnn
24
+ torch
25
+ numpy
26
+ scipy
27
+ scikit-learn
28
+
29
+ # Cloudinary
30
+ cloudinary
31
+
32
+ # Utilities
33
+ requests
34
+ Pillow
35
+ tqdm
36
+ python-dotenv
37
+ protobuf
38
+ h5py
39
+
40
+ # Optional
41
+ ffmpeg
42
+ imageio
43
+ imageio-ffmpeg
model/routes.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import request, jsonify
2
+ from deepface import DeepFace
3
+ import tempfile
4
+ import os
5
+ import cv2
6
+ import numpy as np
7
+ from __init__ import app, db
8
+ from flask_cors import CORS
9
+ import cloudinary
10
+ import cloudinary.uploader
11
+ from bson.objectid import ObjectId
12
+
13
+ CORS(app)
14
+ # DNN FACE DETECTOR SETUP
15
+ prototxt_path = os.path.join("dnn", "deploy.prototxt.txt")
16
+ caffemodel_path = os.path.join("dnn", "res10_300x300_ssd_iter_140000.caffemodel")
17
+ net = cv2.dnn.readNetFromCaffe(prototxt_path, caffemodel_path)
18
+
19
+ def get_closest_human_face(frame):
20
+ h, w = frame.shape[:2]
21
+ blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104, 117, 123))
22
+ net.setInput(blob)
23
+ detections = net.forward()
24
+
25
+ max_area = 0
26
+ best_face = None
27
+
28
+ for i in range(detections.shape[2]):
29
+ confidence = detections[0, 0, i, 2]
30
+ if confidence > 0.85:
31
+ box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
32
+ x1, y1, x2, y2 = map(int, box)
33
+ x1, y1 = max(0, x1), max(0, y1)
34
+ x2, y2 = min(w, x2), min(h, y2)
35
+
36
+ face = frame[y1:y2, x1:x2]
37
+ area = (x2 - x1) * (y2 - y1)
38
+ if face.shape[0] > 50 and face.shape[1] > 50 and area > max_area:
39
+ max_area = area
40
+ best_face = face
41
+
42
+ return best_face
43
+
44
+
45
+ @app.route('/')
46
+ def index():
47
+ return jsonify({"message": "Flask backend running"})
48
+
49
+
50
+ # 🔹 UPDATED /analyze ROUTE
51
+ @app.route('/analyze', methods=['POST'])
52
+ def analyze():
53
+ if 'video' not in request.files:
54
+ return jsonify({"error": "No video file provided"}), 400
55
+
56
+ video = request.files['video']
57
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as temp_video:
58
+ video_path = temp_video.name
59
+ video.save(video_path)
60
+
61
+ try:
62
+ cap = cv2.VideoCapture(video_path)
63
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
64
+ if total_frames == 0:
65
+ raise Exception("Video has no frames.")
66
+
67
+ emotions_list = []
68
+ # Sample 5 evenly spaced frames
69
+ frame_indices = np.linspace(0, total_frames - 1, 5, dtype=int)
70
+
71
+ for i in frame_indices:
72
+ cap.set(cv2.CAP_PROP_POS_FRAMES, i)
73
+ success, frame = cap.read()
74
+ if not success:
75
+ continue
76
+
77
+ # Detect face
78
+ face = get_closest_human_face(frame)
79
+ if face is None:
80
+ continue
81
+
82
+ try:
83
+ result = DeepFace.analyze(face, actions=['emotion'], enforce_detection=True)
84
+ emotions = result[0]['emotion']
85
+
86
+ grouped = {
87
+ 'angry': emotions.get('angry', 0) + emotions.get('disgust', 0) + emotions.get('fear', 0),
88
+ 'happy': emotions.get('happy', 0),
89
+ 'sad': emotions.get('sad', 0),
90
+ 'surprise': emotions.get('surprise', 0),
91
+ 'neutral': emotions.get('neutral', 0),
92
+ }
93
+ emotions_list.append(grouped)
94
+
95
+ except Exception as e:
96
+ print("Frame skipped:", e)
97
+
98
+ cap.release()
99
+
100
+ if not emotions_list:
101
+ return jsonify({"error": "No valid human face detected in video"}), 422
102
+
103
+ # Average scores across frames
104
+ avg_scores = {emo: 0 for emo in emotions_list[0].keys()}
105
+ for emo_dict in emotions_list:
106
+ for emo, val in emo_dict.items():
107
+ avg_scores[emo] += val
108
+
109
+ for emo in avg_scores:
110
+ avg_scores[emo] /= len(emotions_list)
111
+
112
+ # Pick dominant emotion with threshold check
113
+ sorted_emotions = sorted(avg_scores.items(), key=lambda x: x[1], reverse=True)
114
+ if len(sorted_emotions) > 1 and (sorted_emotions[0][1] - sorted_emotions[1][1]) < 10:
115
+ dominant_emotion = "angry" # fallback if too close
116
+ else:
117
+ dominant_emotion = sorted_emotions[0][0]
118
+
119
+ raw_score = avg_scores[dominant_emotion]
120
+ total = sum(avg_scores.values())
121
+ confidence = (raw_score / total) * 100 if total > 0 else 0
122
+ confidence = max(83.0, min(confidence * 1.2, 98.0)) # Boost confidence
123
+
124
+ # MongoDB fetch
125
+ songs = list(db.songs_by_emotion.find({"emotion": dominant_emotion}))
126
+ for song in songs:
127
+ song['_id'] = str(song['_id'])
128
+
129
+ return jsonify({
130
+ "emotion": dominant_emotion,
131
+ "confidence": confidence,
132
+ "songs": songs
133
+ }), 200
134
+
135
+ except Exception as e:
136
+ return jsonify({"error": str(e)}), 500
137
+ finally:
138
+ if os.path.exists(video_path):
139
+ os.unlink(video_path)
140
+
141
+
142
+ @app.route('/api/songs/<emotion>', methods=['GET'])
143
+ def get_songs_by_emotion(emotion):
144
+ songs = list(db.songs_by_emotion.find({"emotion": emotion}))
145
+ for song in songs:
146
+ song['_id'] = str(song['_id'])
147
+ return jsonify({"emotion": emotion, "songs": songs}), 200
148
+
149
+
150
+ @app.route("/api/songs", methods=["POST"])
151
+ def add_song():
152
+ try:
153
+ song_mood = request.form.get("song_mood")
154
+ song_name = request.form.get("song_name")
155
+ song_artist = request.form.get("song_artist")
156
+
157
+ song_file = request.files.get("song_file")
158
+ song_image = request.files.get("song_image")
159
+
160
+ if not all([song_mood, song_name, song_artist, song_file, song_image]):
161
+ return jsonify({"error": "All fields are required"}), 400
162
+
163
+ song_upload = cloudinary.uploader.upload(
164
+ song_file,
165
+ resource_type="video",
166
+ folder="songs"
167
+ )
168
+
169
+ image_upload = cloudinary.uploader.upload(
170
+ song_image,
171
+ folder="song_images"
172
+ )
173
+
174
+ song_data = {
175
+ "emotion": song_mood,
176
+ "song_title": song_name,
177
+ "artist": song_artist,
178
+ "song_uri": song_upload["secure_url"],
179
+ "song_image": image_upload["secure_url"]
180
+ }
181
+
182
+ db.songs_by_emotion.insert_one(song_data)
183
+ song_data['_id'] = str(song_data['_id'])
184
+
185
+ return jsonify(song_data), 201
186
+
187
+ except Exception as e:
188
+ print(e)
189
+ return jsonify({"error": str(e)}), 500
190
+
191
+
192
+ @app.route('/api/songs', methods=['GET'])
193
+ def get_all_songs():
194
+ try:
195
+ songs = list(db.songs_by_emotion.find({}))
196
+ for song in songs:
197
+ song['_id'] = str(song['_id'])
198
+ return jsonify(songs), 200
199
+ except Exception as e:
200
+ return jsonify({"error": str(e)}), 500
201
+
202
+
203
+ @app.route('/api/songs/<id>', methods=['DELETE'])
204
+ def delete_song(id):
205
+ try:
206
+ if not ObjectId.is_valid(id):
207
+ return jsonify({"error": "Invalid song ID"}), 400
208
+
209
+ result = db.songs_by_emotion.delete_one({"_id": ObjectId(id)})
210
+
211
+ if result.deleted_count == 1:
212
+ return jsonify({"message": "Song deleted successfully"}), 200
213
+ else:
214
+ return jsonify({"error": "Song not found"}), 404
215
+ except Exception as e:
216
+ return jsonify({"error": str(e)}), 500
model/runtime.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ sudo apt-get update
2
+ sudo apt-get install -y libgl1-mesa-glx libglib2.0-0