nexusbert commited on
Commit
2de3dcb
·
1 Parent(s): 05b6c9e

Use google-genai client for Gemini and pin ytmusicapi 1.10

Browse files
Files changed (2) hide show
  1. app.py +47 -45
  2. requirements.txt +1 -0
app.py CHANGED
@@ -11,6 +11,7 @@ from dotenv import load_dotenv
11
  from fastapi import FastAPI, File, HTTPException, UploadFile
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from pydantic import BaseModel
 
14
 
15
  from ytmusic_client import (
16
  YouTubeMusicError,
@@ -33,10 +34,12 @@ if GEMINI_API_KEY:
33
 
34
  if not GEMINI_API_KEY or GEMINI_API_KEY == "YOUR_API_KEY_HERE":
35
  print("⚠️ WARNING: GEMINI_API_KEY not found or using placeholder.")
 
36
  else:
37
  masked_key = f"{GEMINI_API_KEY[:4]}...{GEMINI_API_KEY[-4:]}"
38
  print(f"✅ API Key detected: {masked_key} (Length: {len(GEMINI_API_KEY)})")
39
  print(f"✅ Using Gemini model: {GEMINI_MODEL}")
 
40
 
41
  YTMUSIC_OAUTH_FILE = os.getenv("YTMUSIC_OAUTH_FILE", "oauth.json")
42
  YTMUSIC_CLIENT_ID = os.getenv("YTMUSIC_CLIENT_ID")
@@ -109,38 +112,43 @@ def _analyze_face_deepface(image_bytes: bytes) -> tuple[str, float]:
109
 
110
 
111
  def _analyze_face_gemini(image_bytes: bytes) -> tuple[str, float]:
112
- if not GEMINI_API_KEY or GEMINI_API_KEY == "YOUR_API_KEY_HERE":
113
  raise ValueError("GEMINI_API_KEY not configured")
114
-
115
- base64_image = base64.b64encode(image_bytes).decode('utf-8')
116
-
117
  prompt = """
118
  You are an emotion detection AI. Analyze the facial expression in this image.
119
  DO NOT use 'disgust'.
120
-
121
  Return ONLY a valid JSON object with this exact structure:
122
  {
123
  "dominant_emotion": "happy|sad|angry|neutral|fear|surprise",
124
  "confidence": 0.0-1.0
125
  }
126
  """
127
-
128
- url = f"https://generativelanguage.googleapis.com/v1/models/{GEMINI_MODEL}:generateContent?key={GEMINI_API_KEY}"
129
- payload = {
130
- "contents": [{"parts": [{"text": prompt}, {"inline_data": {"mime_type": "image/jpeg", "data": base64_image}}]}],
131
- "generationConfig": {"response_mime_type": "application/json"}
132
- }
133
-
134
- raw_response = requests.post(url, json=payload)
135
- response = raw_response.json()
136
-
137
- if 'error' in response:
138
- raise ValueError(f"Gemini API Error: {response['error']['message']}")
139
-
140
- if 'candidates' not in response:
141
- raise ValueError("Image blocked by AI Safety Filters")
142
-
143
- result = json.loads(response['candidates'][0]['content']['parts'][0]['text'])
 
 
 
 
 
 
 
144
 
145
  emotion_map = {
146
  "happy": "joy",
@@ -158,39 +166,33 @@ def _analyze_face_gemini(image_bytes: bytes) -> tuple[str, float]:
158
 
159
 
160
  def _analyze_text_gemini(text: str) -> tuple[str, float]:
161
- if not GEMINI_API_KEY or GEMINI_API_KEY == "YOUR_API_KEY_HERE":
162
  raise ValueError("GEMINI_API_KEY not configured")
163
-
164
  prompt = f"""
165
- Analyze the emotional tone of this text: "{text}"
166
-
167
  Return ONLY a valid JSON object with this exact structure:
168
  {{
169
  "dominant_emotion": "joy|sadness|anger|neutral|fear|surprise",
170
  "confidence": 0.0-1.0
171
  }}
172
  """
173
-
174
- url = f"https://generativelanguage.googleapis.com/v1/models/{GEMINI_MODEL}:generateContent?key={GEMINI_API_KEY}"
175
- payload = {
176
- "contents": [{"parts": [{"text": prompt}]}],
177
- "generationConfig": {"response_mime_type": "application/json"}
178
- }
179
-
180
- raw_response = requests.post(url, json=payload)
181
- response = raw_response.json()
182
-
183
- if 'error' in response:
184
- raise ValueError(f"Gemini API Error: {response['error']['message']}")
185
-
186
- if 'candidates' not in response:
187
- raise ValueError("Text analysis blocked")
188
-
189
- result = json.loads(response['candidates'][0]['content']['parts'][0]['text'])
190
-
191
  dominant = result.get("dominant_emotion", "neutral").lower()
192
  confidence = float(result.get("confidence", 0.5))
193
-
194
  return dominant, confidence
195
 
196
 
 
11
  from fastapi import FastAPI, File, HTTPException, UploadFile
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from pydantic import BaseModel
14
+ from google import genai
15
 
16
  from ytmusic_client import (
17
  YouTubeMusicError,
 
34
 
35
  if not GEMINI_API_KEY or GEMINI_API_KEY == "YOUR_API_KEY_HERE":
36
  print("⚠️ WARNING: GEMINI_API_KEY not found or using placeholder.")
37
+ GEMINI_CLIENT = None
38
  else:
39
  masked_key = f"{GEMINI_API_KEY[:4]}...{GEMINI_API_KEY[-4:]}"
40
  print(f"✅ API Key detected: {masked_key} (Length: {len(GEMINI_API_KEY)})")
41
  print(f"✅ Using Gemini model: {GEMINI_MODEL}")
42
+ GEMINI_CLIENT = genai.Client(api_key=GEMINI_API_KEY)
43
 
44
  YTMUSIC_OAUTH_FILE = os.getenv("YTMUSIC_OAUTH_FILE", "oauth.json")
45
  YTMUSIC_CLIENT_ID = os.getenv("YTMUSIC_CLIENT_ID")
 
112
 
113
 
114
  def _analyze_face_gemini(image_bytes: bytes) -> tuple[str, float]:
115
+ if GEMINI_CLIENT is None:
116
  raise ValueError("GEMINI_API_KEY not configured")
117
+
 
 
118
  prompt = """
119
  You are an emotion detection AI. Analyze the facial expression in this image.
120
  DO NOT use 'disgust'.
121
+
122
  Return ONLY a valid JSON object with this exact structure:
123
  {
124
  "dominant_emotion": "happy|sad|angry|neutral|fear|surprise",
125
  "confidence": 0.0-1.0
126
  }
127
  """
128
+
129
+ response = GEMINI_CLIENT.models.generate_content(
130
+ model=GEMINI_MODEL,
131
+ contents=[
132
+ {
133
+ "role": "user",
134
+ "parts": [
135
+ {"text": prompt},
136
+ {
137
+ "inline_data": {
138
+ "mime_type": "image/jpeg",
139
+ "data": base64.b64encode(image_bytes).decode("utf-8"),
140
+ }
141
+ },
142
+ ],
143
+ }
144
+ ],
145
+ )
146
+
147
+ text = response.text or ""
148
+ try:
149
+ result = json.loads(text)
150
+ except Exception:
151
+ raise ValueError(f"Gemini response not JSON: {text}")
152
 
153
  emotion_map = {
154
  "happy": "joy",
 
166
 
167
 
168
  def _analyze_text_gemini(text: str) -> tuple[str, float]:
169
+ if GEMINI_CLIENT is None:
170
  raise ValueError("GEMINI_API_KEY not configured")
171
+
172
  prompt = f"""
173
+ Analyze the emotional tone of this text: \"{text}\"
174
+
175
  Return ONLY a valid JSON object with this exact structure:
176
  {{
177
  "dominant_emotion": "joy|sadness|anger|neutral|fear|surprise",
178
  "confidence": 0.0-1.0
179
  }}
180
  """
181
+
182
+ response = GEMINI_CLIENT.models.generate_content(
183
+ model=GEMINI_MODEL,
184
+ contents=prompt,
185
+ )
186
+
187
+ raw_text = response.text or ""
188
+ try:
189
+ result = json.loads(raw_text)
190
+ except Exception:
191
+ raise ValueError(f"Gemini response not JSON: {raw_text}")
192
+
 
 
 
 
 
 
193
  dominant = result.get("dominant_emotion", "neutral").lower()
194
  confidence = float(result.get("confidence", 0.5))
195
+
196
  return dominant, confidence
197
 
198
 
requirements.txt CHANGED
@@ -9,3 +9,4 @@ python-dotenv
9
  tf-keras
10
  tensorflow
11
  python-multipart
 
 
9
  tf-keras
10
  tensorflow
11
  python-multipart
12
+ google-genai