Madras1 commited on
Commit
9eb54fe
·
verified ·
1 Parent(s): 7d9fc07

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -48
app.py CHANGED
@@ -12,9 +12,8 @@ from mistralai import Mistral
12
  import google.generativeai as genai
13
  from huggingface_hub import snapshot_download
14
 
15
- # --- SEGURANÇA: RATE LIMITER ANTI-SPAM ---
16
- # Permite 10 requisições por minuto por IP (ajustado para seus testes)
17
- MAX_REQUESTS_PER_MINUTE = 10
18
  BLOCK_TIME_SECONDS = 60
19
  ip_access_log = defaultdict(list)
20
 
@@ -23,11 +22,9 @@ def verify_rate_limit(request: gr.Request):
23
  client_ip = request.client.host
24
  current_time = time.time()
25
  ip_access_log[client_ip] = [t for t in ip_access_log[client_ip] if current_time - t < BLOCK_TIME_SECONDS]
26
-
27
  if len(ip_access_log[client_ip]) >= MAX_REQUESTS_PER_MINUTE:
28
- print(f"⛔ BLOQUEIO: IP {client_ip} barrado por spam.")
29
  return False
30
-
31
  ip_access_log[client_ip].append(current_time)
32
  return True
33
 
@@ -55,7 +52,7 @@ def download_local_model():
55
  try: snapshot_download(repo_id=LOCAL_MODEL_ID)
56
  except Exception as e: print(f"⚠️ Aviso: {e}")
57
 
58
- # --- BACKENDS DE EXECUÇÃO ---
59
 
60
  @spaces.GPU(duration=120)
61
  def run_local_h200(messages):
@@ -75,11 +72,10 @@ def run_groq(messages, model_id):
75
  for m in messages:
76
  if isinstance(m['content'], list): return "⚠️ Groq não lê imagens. Use Gemini/Pixtral."
77
  if not groq_client: return "❌ Erro: API Key Groq ausente."
78
-
79
  clean_msgs = [{"role": m['role'], "content": m['content']} for m in messages]
80
  try:
81
  completion = groq_client.chat.completions.create(
82
- model=model_id, messages=clean_msgs, temperature=0.7, max_tokens=8192 # Aumentei tokens para os GPT OSS
83
  )
84
  return completion.choices[0].message.content
85
  except Exception as e: return f"❌ Groq Error: {e}"
@@ -123,11 +119,11 @@ def run_gemini(messages, model_id):
123
  if os.path.exists(path): parts.append(Image.open(path))
124
  if parts: chat_history.append({"role": role, "parts": parts})
125
 
126
- last_msg_content = messages[-1]['content']
127
  current_parts = []
128
- if isinstance(last_msg_content, str): current_parts.append(last_msg_content)
129
- elif isinstance(last_msg_content, list):
130
- for item in last_msg_content:
131
  if item.get('type') == 'text': current_parts.append(item['text'])
132
  elif item.get('type') == 'image_url':
133
  path = item['image_url']['url']
@@ -138,22 +134,22 @@ def run_gemini(messages, model_id):
138
  return response.text
139
  except Exception as e: return f"❌ Gemini Error ({model_id}): {e}"
140
 
141
- # --- ROTEADOR INTELIGENTE ---
142
  def router(message, history, model_selector, request: gr.Request):
143
  if not verify_rate_limit(request):
144
  return f"⛔ LIMITADO: Aguarde para enviar mais mensagens."
145
 
146
- # Normalização de Histórico (Blindagem)
147
  formatted_history = []
148
- for turn in history:
149
- if isinstance(turn, dict): formatted_history.append(turn)
150
- elif isinstance(turn, (list, tuple)) and len(turn) >= 2:
151
- u = turn[0]['text'] if isinstance(turn[0], dict) and 'text' in turn[0] else str(turn[0])
152
- b = str(turn[1]) if turn[1] else ""
153
- formatted_history.append({"role": "user", "content": u})
154
- if b: formatted_history.append({"role": "assistant", "content": b})
 
 
155
 
156
- # Payload Atual
157
  current_content = []
158
  text = message.get("text", "")
159
  files = message.get("files", [])
@@ -163,8 +159,7 @@ def router(message, history, model_selector, request: gr.Request):
163
  if not files: formatted_history.append({"role": "user", "content": text})
164
  else: formatted_history.append({"role": "user", "content": current_content})
165
 
166
- # --- SELEÇÃO DE MODELOS (ATUALIZADA) ---
167
-
168
  if "Gemini" in model_selector:
169
  tid = "gemini-1.5-flash"
170
  if "3.0" in model_selector: tid = "gemini-3.0-pro-preview"
@@ -176,13 +171,12 @@ def router(message, history, model_selector, request: gr.Request):
176
  elif "Mistral" in model_selector:
177
  tid = "mistral-large-latest"
178
  if "Pixtral" in model_selector: tid = "pixtral-large-latest"
179
- elif "2509" in model_selector: tid = "magistral-medium-2509" # <--- Seu pedido!
180
  elif "2512" in model_selector: tid = "mistral-large-2512"
181
  elif "Codestral" in model_selector: tid = "codestral-2508"
182
  return run_mistral(formatted_history, tid)
183
 
184
  elif "Groq" in model_selector:
185
- # Mapeamento do seu Print
186
  if "120B" in model_selector: tid = "openai/gpt-oss-120b"
187
  elif "20B" in model_selector: tid = "openai/gpt-oss-20b"
188
  else: tid = "llama-3.3-70b-versatile"
@@ -195,35 +189,48 @@ def router(message, history, model_selector, request: gr.Request):
195
 
196
  # --- INTERFACE ---
197
  with gr.Blocks() as demo:
198
- gr.Markdown("# 🔀 APIDOST v5 (Full Arsenal & Secured)")
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  with gr.Row():
201
- model_dropdown = gr.Dropdown(
202
- choices=[
203
- "✨ Google: Gemini 3.0 Pro (Experimental)",
204
- "✨ Google: Gemini 2.5 Pro",
205
- "✨ Google: Gemini 2.5 Flash",
206
- "✨ Google: Gemini 2.0 Flash",
207
- "☁️ Groq: GPT OSS 120B (OpenAI) 🆕",
208
- "☁️ Groq: GPT OSS 20B (OpenAI) 🆕",
209
- "☁️ Groq: Llama 3.3 70B",
210
- "🇫🇷 Mistral: Magistral Medium 2509 🆕",
211
- "🇫🇷 Mistral: Pixtral Large (Vision) 🖼️",
212
- "🇫🇷 Mistral: Large 2512 (Dez/25)",
213
- "🇫🇷 Mistral: Codestral 2508",
214
- "🔥 Local H200: Qwen 2.5 Coder 32B"
215
- ],
216
- value="🔥 Local H200: Qwen 2.5 Coder 32B",
217
- label="Cérebro Escolhido",
218
- interactive=True
219
- )
220
 
 
221
  chat = gr.ChatInterface(
222
  fn=router,
223
  additional_inputs=[model_dropdown],
224
  multimodal=True,
225
  )
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  if __name__ == "__main__":
228
  download_local_model()
229
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
12
  import google.generativeai as genai
13
  from huggingface_hub import snapshot_download
14
 
15
+ # --- SEGURANÇA: RATE LIMITER ---
16
+ MAX_REQUESTS_PER_MINUTE = 15
 
17
  BLOCK_TIME_SECONDS = 60
18
  ip_access_log = defaultdict(list)
19
 
 
22
  client_ip = request.client.host
23
  current_time = time.time()
24
  ip_access_log[client_ip] = [t for t in ip_access_log[client_ip] if current_time - t < BLOCK_TIME_SECONDS]
 
25
  if len(ip_access_log[client_ip]) >= MAX_REQUESTS_PER_MINUTE:
26
+ print(f"⛔ BLOQUEIO: IP {client_ip} barrado.")
27
  return False
 
28
  ip_access_log[client_ip].append(current_time)
29
  return True
30
 
 
52
  try: snapshot_download(repo_id=LOCAL_MODEL_ID)
53
  except Exception as e: print(f"⚠️ Aviso: {e}")
54
 
55
+ # --- BACKENDS ---
56
 
57
  @spaces.GPU(duration=120)
58
  def run_local_h200(messages):
 
72
  for m in messages:
73
  if isinstance(m['content'], list): return "⚠️ Groq não lê imagens. Use Gemini/Pixtral."
74
  if not groq_client: return "❌ Erro: API Key Groq ausente."
 
75
  clean_msgs = [{"role": m['role'], "content": m['content']} for m in messages]
76
  try:
77
  completion = groq_client.chat.completions.create(
78
+ model=model_id, messages=clean_msgs, temperature=0.7, max_tokens=8192
79
  )
80
  return completion.choices[0].message.content
81
  except Exception as e: return f"❌ Groq Error: {e}"
 
119
  if os.path.exists(path): parts.append(Image.open(path))
120
  if parts: chat_history.append({"role": role, "parts": parts})
121
 
122
+ last_msg = messages[-1]['content']
123
  current_parts = []
124
+ if isinstance(last_msg, str): current_parts.append(last_msg)
125
+ elif isinstance(last_msg, list):
126
+ for item in last_msg:
127
  if item.get('type') == 'text': current_parts.append(item['text'])
128
  elif item.get('type') == 'image_url':
129
  path = item['image_url']['url']
 
134
  return response.text
135
  except Exception as e: return f"❌ Gemini Error ({model_id}): {e}"
136
 
137
+ # --- ROTEADOR ---
138
  def router(message, history, model_selector, request: gr.Request):
139
  if not verify_rate_limit(request):
140
  return f"⛔ LIMITADO: Aguarde para enviar mais mensagens."
141
 
 
142
  formatted_history = []
143
+ # Proteção contra history=None ou formatos estranhos
144
+ if history:
145
+ for turn in history:
146
+ if isinstance(turn, dict): formatted_history.append(turn)
147
+ elif isinstance(turn, (list, tuple)) and len(turn) >= 2:
148
+ u = turn[0]['text'] if isinstance(turn[0], dict) and 'text' in turn[0] else str(turn[0])
149
+ b = str(turn[1]) if turn[1] else ""
150
+ formatted_history.append({"role": "user", "content": u})
151
+ if b: formatted_history.append({"role": "assistant", "content": b})
152
 
 
153
  current_content = []
154
  text = message.get("text", "")
155
  files = message.get("files", [])
 
159
  if not files: formatted_history.append({"role": "user", "content": text})
160
  else: formatted_history.append({"role": "user", "content": current_content})
161
 
162
+ # SELEÇÃO (IDs CORRIGIDOS DO SEU PRINT)
 
163
  if "Gemini" in model_selector:
164
  tid = "gemini-1.5-flash"
165
  if "3.0" in model_selector: tid = "gemini-3.0-pro-preview"
 
171
  elif "Mistral" in model_selector:
172
  tid = "mistral-large-latest"
173
  if "Pixtral" in model_selector: tid = "pixtral-large-latest"
174
+ elif "2509" in model_selector: tid = "magistral-medium-2509" # Pedido aceito
175
  elif "2512" in model_selector: tid = "mistral-large-2512"
176
  elif "Codestral" in model_selector: tid = "codestral-2508"
177
  return run_mistral(formatted_history, tid)
178
 
179
  elif "Groq" in model_selector:
 
180
  if "120B" in model_selector: tid = "openai/gpt-oss-120b"
181
  elif "20B" in model_selector: tid = "openai/gpt-oss-20b"
182
  else: tid = "llama-3.3-70b-versatile"
 
189
 
190
  # --- INTERFACE ---
191
  with gr.Blocks() as demo:
192
+ gr.Markdown("# 🔀 APIDOST v6 (Endpoint Fixed)")
193
 
194
+ # Lista de Modelos Atualizada
195
+ models_list = [
196
+ "✨ Google: Gemini 3.0 Pro (Experimental)",
197
+ "✨ Google: Gemini 2.5 Pro",
198
+ "✨ Google: Gemini 2.5 Flash",
199
+ "✨ Google: Gemini 2.0 Flash",
200
+ "☁️ Groq: GPT OSS 120B (OpenAI) 🆕",
201
+ "☁️ Groq: GPT OSS 20B (OpenAI) 🆕",
202
+ "☁️ Groq: Llama 3.3 70B",
203
+ "🇫🇷 Mistral: Magistral Medium 2509 🆕",
204
+ "🇫🇷 Mistral: Pixtral Large (Vision) 🖼️",
205
+ "🇫🇷 Mistral: Large 2512 (Dez/25)",
206
+ "🇫🇷 Mistral: Codestral 2508",
207
+ "🔥 Local H200: Qwen 2.5 Coder 32B"
208
+ ]
209
+
210
  with gr.Row():
211
+ model_dropdown = gr.Dropdown(choices=models_list, value=models_list[-1], label="Cérebro", interactive=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
+ # 1. Interface de Chat VISUAL (para você testar no HuggingFace)
214
  chat = gr.ChatInterface(
215
  fn=router,
216
  additional_inputs=[model_dropdown],
217
  multimodal=True,
218
  )
219
 
220
+ # 2. PONTE DE API INVISÍVEL (A SOLUÇÃO DO SEU PROBLEMA)
221
+ # Isso cria explicitamente o endpoint "/chat" que o seu JavaScript está procurando.
222
+ # Ele aceita 'message' (multimodal), 'history' (estado) e 'model_selector' (dropdown).
223
+ api_bridge = gr.Interface(
224
+ fn=router,
225
+ inputs=[
226
+ gr.MultimodalTextbox(label="message"), # O JS manda {text:..., files:...}
227
+ gr.State(value=[], label="history"), # O JS pode mandar lista vazia []
228
+ gr.Dropdown(choices=models_list, label="model_selector") # O JS manda a string do modelo
229
+ ],
230
+ outputs=[gr.Textbox(label="response")],
231
+ api_name="chat" # <--- AQUI! Isso garante que activeClient.predict("/chat") funcione.
232
+ )
233
+
234
  if __name__ == "__main__":
235
  download_local_model()
236
+ demo.queue(api_open=True).launch(server_name="0.0.0.0", server_port=7860)