Mahmous commited on
Commit
c3cdaaf
·
verified ·
1 Parent(s): 8d171d0

Update api.py

Browse files
Files changed (1) hide show
  1. api.py +63 -38
api.py CHANGED
@@ -1,6 +1,6 @@
1
  import os
2
  import traceback
3
- from flask import Flask, request, jsonify
4
  from flask_cors import CORS
5
  from dotenv import load_dotenv
6
  from langdetect import detect
@@ -8,37 +8,44 @@ from deep_translator import GoogleTranslator
8
  from sentence_transformers import SentenceTransformer
9
  from pinecone import Pinecone
10
  from openai import OpenAI
 
11
 
12
  # ---------- Config ----------
13
  DATASET_PATH = "data/coaching_millionaer_dataset.json"
14
  load_dotenv(override=True)
15
 
16
- # Load secrets from Hugging Face Space
17
- HF_TOKEN = os.getenv("HF_TOKEN")
18
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
19
  PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
20
  PINECONE_INDEX_NAME = "ebook"
21
 
22
- # ---------- App ----------
23
  app = Flask(__name__)
24
  CORS(app, resources={r"/ask": {"origins": "*"}})
25
 
26
- # ---------- LLM Client ----------
27
  client = None
28
  try:
29
- if HF_TOKEN:
30
- # Use Hugging Face Inference Provider
31
- client = OpenAI(
32
- base_url="https://router.huggingface.co/v1",
33
- api_key=HF_TOKEN,
34
- )
35
- print("✅ Using Hugging Face Inference Provider (OpenAI-compatible API)")
36
- elif OPENAI_API_KEY:
37
- # Fallback to OpenAI if provided
38
- client = OpenAI(api_key=OPENAI_API_KEY)
39
- print("✅ Using OpenAI client directly")
40
- else:
41
- raise ValueError("No valid API key found. Set HF_TOKEN or OPENAI_API_KEY.")
 
 
 
 
 
 
42
  except Exception as e:
43
  print(f"❌ Failed to initialize LLM client: {e}")
44
  client = None
@@ -94,6 +101,7 @@ def detect_language(question: str) -> str:
94
  except Exception:
95
  return "unknown"
96
 
 
97
  def normalize_language(lang: str, text: str) -> str:
98
  if lang == "nl" and any(
99
  word in text.lower() for word in ["wer", "was", "wie", "javid", "coaching"]
@@ -101,6 +109,7 @@ def normalize_language(lang: str, text: str) -> str:
101
  return "de"
102
  return lang
103
 
 
104
  def system_prompt_book_only() -> str:
105
  return (
106
  "You are CoachingBot, a professional mentor trained on the book 'Coaching Millionär' by Javid Niazi-Hoffmann. "
@@ -111,6 +120,7 @@ def system_prompt_book_only() -> str:
111
  "Always respond in the same language as the user's question."
112
  )
113
 
 
114
  def system_prompt_fallback() -> str:
115
  return (
116
  "You are CoachingBot, a helpful business and life mentor. "
@@ -119,6 +129,7 @@ def system_prompt_fallback() -> str:
119
  "Do not invent book citations."
120
  )
121
 
 
122
  def format_answers(question: str, answer: str, results):
123
  pages = [f"Seite {r.get('page', '')}" for r in results if r.get("page")]
124
  source = ", ".join(pages) if pages else "No source"
@@ -191,10 +202,10 @@ def ask():
191
  if client is None:
192
  return jsonify(format_answers(question, "⚠️ No language model initialized.", results)), 200
193
 
194
- # ---------- LLM Query ----------
195
  try:
196
  response = client.chat.completions.create(
197
- model="openai/gpt-oss-120b:cerebras", # Hugging Face model
198
  messages=[
199
  {"role": "system", "content": sys_prompt},
200
  {"role": "user", "content": user_content},
@@ -207,10 +218,8 @@ def ask():
207
  return jsonify(format_answers(question, f"⚠️ LLM call failed: {e}", results)), 200
208
 
209
  return jsonify(format_answers(question, answer, results))
210
-
211
- from flask import send_file
212
- import tempfile
213
 
 
214
  @app.route("/voice", methods=["POST"])
215
  def voice_chat():
216
  try:
@@ -218,39 +227,53 @@ def voice_chat():
218
  if not audio:
219
  return jsonify({"error": "No audio file uploaded"}), 400
220
 
 
221
  with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp:
222
  audio.save(tmp.name)
223
  audio_path = tmp.name
224
 
225
- # Step 1️⃣: Transcribe using OpenAI Whisper or any STT
226
  transcription = client.audio.transcriptions.create(
227
  model="whisper-1",
228
- file=open(audio_path, "rb")
229
  )
230
  text = transcription.text.strip()
231
  print(f"🎤 Transcribed: {text}")
232
 
233
- # Step 2️⃣: Get mentoring answer from your existing /ask logic
234
- data = {"question": text}
235
- with app.test_request_context(json=data):
236
- response = ask()
237
- response_json = response.get_json()
 
 
 
 
 
 
 
 
 
 
 
238
 
239
  # Step 3️⃣: Optional TTS response
240
- answer_text = response_json["answers"][0]["answer"]
241
  speech_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
242
  with client.audio.speech.with_streaming_response.create(
243
  model="gpt-4o-mini-tts",
244
  voice="alloy",
245
- input=answer_text
246
  ) as speech:
247
  speech.stream_to_file(speech_file.name)
248
 
249
- return jsonify({
250
- "transcript": text,
251
- "answer": answer_text,
252
- "audio_url": f"/audio/{os.path.basename(speech_file.name)}"
253
- })
 
 
 
254
  except Exception as e:
255
  traceback.print_exc()
256
  return jsonify({"error": str(e)}), 500
@@ -258,7 +281,9 @@ def voice_chat():
258
 
259
  @app.route("/audio/<filename>")
260
  def serve_audio(filename):
261
- return send_file(os.path.join(tempfile.gettempdir(), filename), mimetype="audio/mpeg")
 
 
262
 
263
  # ---------- Run ----------
264
  if __name__ == "__main__":
 
1
  import os
2
  import traceback
3
+ from flask import Flask, request, jsonify, send_file
4
  from flask_cors import CORS
5
  from dotenv import load_dotenv
6
  from langdetect import detect
 
8
  from sentence_transformers import SentenceTransformer
9
  from pinecone import Pinecone
10
  from openai import OpenAI
11
+ import tempfile
12
 
13
  # ---------- Config ----------
14
  DATASET_PATH = "data/coaching_millionaer_dataset.json"
15
  load_dotenv(override=True)
16
 
17
+ # Environment variables
18
+ HF_TOKEN = os.getenv("HF_TOKEN") # (commented logic below if you want to re-enable HF)
19
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
20
  PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
21
  PINECONE_INDEX_NAME = "ebook"
22
 
23
+ # ---------- Flask App ----------
24
  app = Flask(__name__)
25
  CORS(app, resources={r"/ask": {"origins": "*"}})
26
 
27
+ # ---------- LLM Client Setup ----------
28
  client = None
29
  try:
30
+ # --- OLD Hugging Face Setup (disabled) ---
31
+ # if HF_TOKEN:
32
+ # client = OpenAI(
33
+ # base_url="https://router.huggingface.co/v1",
34
+ # api_key=HF_TOKEN,
35
+ # )
36
+ # print("✅ Using Hugging Face Inference Provider (OpenAI-compatible API)")
37
+ # elif OPENAI_API_KEY:
38
+ # client = OpenAI(api_key=OPENAI_API_KEY)
39
+ # print("✅ Using OpenAI client directly")
40
+ # else:
41
+ # raise ValueError("No valid API key found. Set HF_TOKEN or OPENAI_API_KEY.")
42
+
43
+ # --- NEW: Unified OpenAI Client (for Whisper, GPT, and TTS) ---
44
+ if not OPENAI_API_KEY:
45
+ raise ValueError("⚠️ Missing OPENAI_API_KEY in environment variables")
46
+ client = OpenAI(api_key=OPENAI_API_KEY)
47
+ print("✅ Using OpenAI API for all tasks (Whisper, GPT, TTS)")
48
+
49
  except Exception as e:
50
  print(f"❌ Failed to initialize LLM client: {e}")
51
  client = None
 
101
  except Exception:
102
  return "unknown"
103
 
104
+
105
  def normalize_language(lang: str, text: str) -> str:
106
  if lang == "nl" and any(
107
  word in text.lower() for word in ["wer", "was", "wie", "javid", "coaching"]
 
109
  return "de"
110
  return lang
111
 
112
+
113
  def system_prompt_book_only() -> str:
114
  return (
115
  "You are CoachingBot, a professional mentor trained on the book 'Coaching Millionär' by Javid Niazi-Hoffmann. "
 
120
  "Always respond in the same language as the user's question."
121
  )
122
 
123
+
124
  def system_prompt_fallback() -> str:
125
  return (
126
  "You are CoachingBot, a helpful business and life mentor. "
 
129
  "Do not invent book citations."
130
  )
131
 
132
+
133
  def format_answers(question: str, answer: str, results):
134
  pages = [f"Seite {r.get('page', '')}" for r in results if r.get("page")]
135
  source = ", ".join(pages) if pages else "No source"
 
202
  if client is None:
203
  return jsonify(format_answers(question, "⚠️ No language model initialized.", results)), 200
204
 
205
+ # ---------- LLM Query (OpenAI) ----------
206
  try:
207
  response = client.chat.completions.create(
208
+ model="gpt-4o-mini", # switched to OpenAI model
209
  messages=[
210
  {"role": "system", "content": sys_prompt},
211
  {"role": "user", "content": user_content},
 
218
  return jsonify(format_answers(question, f"⚠️ LLM call failed: {e}", results)), 200
219
 
220
  return jsonify(format_answers(question, answer, results))
 
 
 
221
 
222
+ # ---------- Voice Chat ----------
223
  @app.route("/voice", methods=["POST"])
224
  def voice_chat():
225
  try:
 
227
  if not audio:
228
  return jsonify({"error": "No audio file uploaded"}), 400
229
 
230
+ # Save temporary audio
231
  with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp:
232
  audio.save(tmp.name)
233
  audio_path = tmp.name
234
 
235
+ # Step 1️⃣: Transcribe via OpenAI Whisper
236
  transcription = client.audio.transcriptions.create(
237
  model="whisper-1",
238
+ file=open(audio_path, "rb"),
239
  )
240
  text = transcription.text.strip()
241
  print(f"🎤 Transcribed: {text}")
242
 
243
+ # Step 2️⃣: Generate answer via GPT
244
+ response = client.chat.completions.create(
245
+ model="gpt-4o-mini",
246
+ messages=[
247
+ {
248
+ "role": "system",
249
+ "content": (
250
+ "You are CoachingBot, a professional mentor helping users improve their mindset, "
251
+ "motivation, and business success. Be clear, empathetic, and practical."
252
+ ),
253
+ },
254
+ {"role": "user", "content": text},
255
+ ],
256
+ max_tokens=700,
257
+ )
258
+ answer_text = response.choices[0].message.content.strip()
259
 
260
  # Step 3️⃣: Optional TTS response
 
261
  speech_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
262
  with client.audio.speech.with_streaming_response.create(
263
  model="gpt-4o-mini-tts",
264
  voice="alloy",
265
+ input=answer_text,
266
  ) as speech:
267
  speech.stream_to_file(speech_file.name)
268
 
269
+ return jsonify(
270
+ {
271
+ "transcript": text,
272
+ "answer": answer_text,
273
+ "audio_url": f"/audio/{os.path.basename(speech_file.name)}",
274
+ }
275
+ )
276
+
277
  except Exception as e:
278
  traceback.print_exc()
279
  return jsonify({"error": str(e)}), 500
 
281
 
282
  @app.route("/audio/<filename>")
283
  def serve_audio(filename):
284
+ return send_file(
285
+ os.path.join(tempfile.gettempdir(), filename), mimetype="audio/mpeg"
286
+ )
287
 
288
  # ---------- Run ----------
289
  if __name__ == "__main__":