Madras1 commited on
Commit
638ac62
·
verified ·
1 Parent(s): 0c8d890

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -25
app.py CHANGED
@@ -2,12 +2,14 @@ import gradio as gr
2
  import spaces
3
  import torch
4
  import os
 
 
5
  from transformers import AutoModelForCausalLM, AutoTokenizer
6
  from groq import Groq
7
  from mistralai import Mistral
8
  import google.generativeai as genai
9
 
10
- # --- CONFIGURAÇÕES ---
11
 
12
  # 1. LOCAL (H200)
13
  LOCAL_MODEL_ID = "Qwen/Qwen2.5-Coder-32B-Instruct"
@@ -25,9 +27,18 @@ gemini_key = os.environ.get("GEMINI_API_KEY")
25
  if gemini_key:
26
  genai.configure(api_key=gemini_key)
27
 
 
 
 
 
 
28
  # --- FUNÇÃO 1: LOCAL H200 (ZeroGPU) ---
29
  @spaces.GPU(duration=60)
30
  def run_local_h200(messages):
 
 
 
 
31
  global local_model, local_tokenizer
32
  if local_model is None:
33
  print(f"🐢 Carregando {LOCAL_MODEL_ID}...")
@@ -43,6 +54,10 @@ def run_local_h200(messages):
43
 
44
  # --- FUNÇÃO 2: GROQ ---
45
  def run_groq(messages, model_id):
 
 
 
 
46
  if not groq_client: return "❌ Erro: Configure a GROQ_API_KEY."
47
  try:
48
  completion = groq_client.chat.completions.create(
@@ -51,52 +66,133 @@ def run_groq(messages, model_id):
51
  return completion.choices[0].message.content
52
  except Exception as e: return f"❌ Groq Error: {e}"
53
 
54
- # --- FUNÇÃO 3: MISTRAL (IDs Novos da sua lista!) ---
55
  def run_mistral(messages, model_id):
56
  if not mistral_client: return "❌ Erro: Configure a MISTRAL_API_KEY."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  try:
58
- print(f"🇫🇷 Mistral Target: {model_id}")
59
- res = mistral_client.chat.complete(model=model_id, messages=messages)
60
  return res.choices[0].message.content
61
- except Exception as e: return f"❌ Mistral Error: {e}"
 
 
 
62
 
63
- # --- FUNÇÃO 4: GEMINI (Modo "Hacker" - Aceita o que vc mandar) ---
64
  def run_gemini(messages, model_id):
65
  if not gemini_key: return "❌ Erro: Configure a GEMINI_API_KEY."
66
  try:
67
  model = genai.GenerativeModel(model_id)
68
- full_prompt = "\n".join([f"{m['role'].title()}: {m['content']}" for m in messages])
69
- response = model.generate_content(full_prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  return response.text
71
  except Exception as e: return f"❌ Gemini Error ({model_id}): {e}"
72
 
73
- # --- ROTEADOR ---
74
  def router(message, history, model_selector):
 
 
 
75
  messages = []
76
  for user_msg, bot_msg in history:
77
- if user_msg: messages.append({"role": "user", "content": user_msg})
78
- if bot_msg: messages.append({"role": "assistant", "content": bot_msg})
79
- messages.append({"role": "user", "content": message})
 
 
 
 
 
 
 
 
 
80
 
81
- # --- MAPEAMENTO DE MODELOS ---
 
 
 
82
 
83
- # Rota Google (Seus modelos "Future")
 
 
 
 
 
 
 
 
 
84
  if "Gemini 3" in model_selector:
85
- return run_gemini(messages, "gemini-3.0-pro-exp") # Tentativa de ID
 
 
86
  elif "Gemini 2.5 Flash" in model_selector:
87
- return run_gemini(messages, "gemini-2.0-flash-exp") # O Experimental atual
 
 
88
 
89
  # Rota Groq
90
  elif "Llama 3.3" in model_selector:
91
  return run_groq(messages, "llama-3.3-70b-versatile")
92
 
93
- # Rota Mistral (Sua Lista VIP)
 
 
94
  elif "Mistral Large 2512" in model_selector:
95
  return run_mistral(messages, "mistral-large-2512")
96
- elif "Pixtral Large" in model_selector:
97
- return run_mistral(messages, "pixtral-large-latest") # Multimodal!
98
  elif "Magistral Medium" in model_selector:
99
- return run_mistral(messages, "magistral-medium-latest") # Exclusivo
100
  elif "Codestral 2508" in model_selector:
101
  return run_mistral(messages, "codestral-2508")
102
 
@@ -108,26 +204,34 @@ def router(message, history, model_selector):
108
 
109
  # --- UI ---
110
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
111
- gr.Markdown("# 🔀 APIDOST Router V5: Unleashed")
112
 
113
  with gr.Row():
114
  model_dropdown = gr.Dropdown(
115
  choices=[
116
- "✨ Google: Gemini 3 (Experimental)",
 
117
  "✨ Google: Gemini 2.5 Flash",
 
118
  "☁️ Groq: Llama 3.3 70B",
 
119
  "🇫🇷 Mistral: Large 2512 (Dez/25)",
120
- "🇫🇷 Mistral: Pixtral Large (Vision)",
121
  "🇫🇷 Mistral: Magistral Medium (VIP)",
122
  "🇫🇷 Mistral: Codestral 2508 (Code)",
123
  "🔥 Local H200: Qwen 2.5 Coder"
124
  ],
125
- value="🇫🇷 Mistral: Large 2512 (Dez/25)",
126
  label="Escolha o Cérebro",
127
  interactive=True
128
  )
129
 
130
- chat = gr.ChatInterface(fn=router, additional_inputs=[model_dropdown])
 
 
 
 
 
 
131
 
132
  if __name__ == "__main__":
133
  demo.launch()
 
2
  import spaces
3
  import torch
4
  import os
5
+ import base64
6
+ from PIL import Image
7
  from transformers import AutoModelForCausalLM, AutoTokenizer
8
  from groq import Groq
9
  from mistralai import Mistral
10
  import google.generativeai as genai
11
 
12
+ # --- CONFIGURAÇÕES GLOBAIS ---
13
 
14
  # 1. LOCAL (H200)
15
  LOCAL_MODEL_ID = "Qwen/Qwen2.5-Coder-32B-Instruct"
 
27
  if gemini_key:
28
  genai.configure(api_key=gemini_key)
29
 
30
+ # --- HELPER: Converte imagem para Base64 (Para Mistral) ---
31
+ def encode_image(image_path):
32
+ with open(image_path, "rb") as image_file:
33
+ return base64.b64encode(image_file.read()).decode('utf-8')
34
+
35
  # --- FUNÇÃO 1: LOCAL H200 (ZeroGPU) ---
36
  @spaces.GPU(duration=60)
37
  def run_local_h200(messages):
38
+ # Verifica se tem imagem (não suportado)
39
+ if isinstance(messages[-1]['content'], list):
40
+ return "⚠️ Erro: O modelo local Qwen não suporta imagens."
41
+
42
  global local_model, local_tokenizer
43
  if local_model is None:
44
  print(f"🐢 Carregando {LOCAL_MODEL_ID}...")
 
54
 
55
  # --- FUNÇÃO 2: GROQ ---
56
  def run_groq(messages, model_id):
57
+ # Verifica se tem imagem (não suportado)
58
+ if isinstance(messages[-1]['content'], list):
59
+ return "⚠️ Erro: Os modelos da Groq não suportam imagens."
60
+
61
  if not groq_client: return "❌ Erro: Configure a GROQ_API_KEY."
62
  try:
63
  completion = groq_client.chat.completions.create(
 
66
  return completion.choices[0].message.content
67
  except Exception as e: return f"❌ Groq Error: {e}"
68
 
69
+ # --- FUNÇÃO 3: MISTRAL (Com suporte a Pixtral/Imagem) ---
70
  def run_mistral(messages, model_id):
71
  if not mistral_client: return "❌ Erro: Configure a MISTRAL_API_KEY."
72
+
73
+ # Processa mensagens para lidar com imagens para o Pixtral
74
+ processed_messages = []
75
+ for msg in messages:
76
+ if isinstance(msg['content'], list):
77
+ # É uma mensagem multimodal
78
+ content_list = []
79
+ for item in msg['content']:
80
+ if item['type'] == 'text':
81
+ content_list.append({"type": "text", "text": item['text']})
82
+ elif item['type'] == 'image_url':
83
+ # Gradio passa o caminho do arquivo, convertemos para base64 data URL
84
+ image_path = item['image_url']['url']
85
+ base64_image = encode_image(image_path)
86
+ # Assumindo JPEG por padrão, o ideal seria detectar
87
+ content_list.append({
88
+ "type": "image_url",
89
+ "image_url": f"data:image/jpeg;base64,{base64_image}"
90
+ })
91
+ processed_messages.append({"role": msg['role'], "content": content_list})
92
+ else:
93
+ # Mensagem só de texto
94
+ processed_messages.append(msg)
95
+
96
  try:
97
+ print(f"🇫🇷 Mistral Target: {model_id} (Multimodal: {'pixtral' in model_id})")
98
+ res = mistral_client.chat.complete(model=model_id, messages=processed_messages)
99
  return res.choices[0].message.content
100
+ except Exception as e:
101
+ if "image" in str(e).lower() and "pixtral" not in model_id:
102
+ return f"⚠️ Erro: Você enviou uma imagem, mas o modelo '{model_id}' não suporta. Use o Pixtral."
103
+ return f"❌ Mistral Error: {e}"
104
 
105
+ # --- FUNÇÃO 4: GEMINI (Com suporte a Imagem) ---
106
  def run_gemini(messages, model_id):
107
  if not gemini_key: return "❌ Erro: Configure a GEMINI_API_KEY."
108
  try:
109
  model = genai.GenerativeModel(model_id)
110
+
111
+ gemini_history = []
112
+ for m in messages:
113
+ role = "user" if m['role'] == 'user' else "model"
114
+
115
+ if isinstance(m['content'], list):
116
+ # Mensagem multimodal
117
+ parts = []
118
+ for item in m['content']:
119
+ if item['type'] == 'text':
120
+ parts.append(item['text'])
121
+ elif item['type'] == 'image_url':
122
+ # Gemini aceita PIL Image ou caminho
123
+ image_path = item['image_url']['url']
124
+ img = Image.open(image_path)
125
+ parts.append(img)
126
+ gemini_history.append({"role": role, "parts": parts})
127
+ else:
128
+ # Mensagem só de texto
129
+ gemini_history.append({"role": role, "parts": [m['content']]})
130
+
131
+ # A última mensagem é o prompt atual
132
+ prompt_parts = gemini_history.pop()
133
+
134
+ # Inicia o chat com o histórico
135
+ chat = model.start_chat(history=gemini_history)
136
+ response = chat.send_message(prompt_parts['parts'])
137
+
138
  return response.text
139
  except Exception as e: return f"❌ Gemini Error ({model_id}): {e}"
140
 
141
+ # --- ROTEADOR CENTRAL (Adaptado para Multimodal) ---
142
  def router(message, history, model_selector):
143
+ # 'message' agora é um dicionário: {"text": "...", "files": ["path/to/image.jpg"]}
144
+
145
+ # 1. Formata o Histórico
146
  messages = []
147
  for user_msg, bot_msg in history:
148
+ # Mensagem do usuário (pode ter imagem)
149
+ if isinstance(user_msg, dict):
150
+ content = [{"type": "text", "text": user_msg.get("text", "")}]
151
+ for file_path in user_msg.get("files", []):
152
+ content.append({"type": "image_url", "image_url": {"url": file_path}})
153
+ messages.append({"role": "user", "content": content})
154
+ elif user_msg:
155
+ messages.append({"role": "user", "content": user_msg})
156
+
157
+ # Mensagem do bot (sempre texto por enquanto)
158
+ if bot_msg:
159
+ messages.append({"role": "assistant", "content": bot_msg})
160
 
161
+ # 2. Formata a Mensagem Atual
162
+ current_content = [{"type": "text", "text": message.get("text", "")}]
163
+ for file_path in message.get("files", []):
164
+ current_content.append({"type": "image_url", "image_url": {"url": file_path}})
165
 
166
+ # Se for só texto, simplifica para string (para compatibilidade com funções antigas)
167
+ if len(current_content) == 1 and current_content[0]['type'] == 'text' and not message.get("files"):
168
+ messages.append({"role": "user", "content": current_content[0]['text']})
169
+ else:
170
+ # Se tiver imagem ou for misto, manda a lista estruturada
171
+ messages.append({"role": "user", "content": current_content})
172
+
173
+ # --- MAPEAMENTO DE MODELOS (SEUS IDs COMPROVADOS!) ---
174
+
175
+ # Rota Google
176
  if "Gemini 3" in model_selector:
177
+ return run_gemini(messages, "gemini-3.0-pro-preview") #
178
+ elif "Gemini 2.5 Pro" in model_selector:
179
+ return run_gemini(messages, "gemini-2.5-pro") #
180
  elif "Gemini 2.5 Flash" in model_selector:
181
+ return run_gemini(messages, "gemini-2.5-flash") #
182
+ elif "Gemini 2.0 Flash" in model_selector:
183
+ return run_gemini(messages, "gemini-2.0-flash") #
184
 
185
  # Rota Groq
186
  elif "Llama 3.3" in model_selector:
187
  return run_groq(messages, "llama-3.3-70b-versatile")
188
 
189
+ # Rota Mistral
190
+ elif "Pixtral Large" in model_selector:
191
+ return run_mistral(messages, "pixtral-large-latest") # VISÃO!
192
  elif "Mistral Large 2512" in model_selector:
193
  return run_mistral(messages, "mistral-large-2512")
 
 
194
  elif "Magistral Medium" in model_selector:
195
+ return run_mistral(messages, "magistral-medium-latest")
196
  elif "Codestral 2508" in model_selector:
197
  return run_mistral(messages, "codestral-2508")
198
 
 
204
 
205
  # --- UI ---
206
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
207
+ gr.Markdown("# 🔀 APIDOST Router V6: Vision Unleashed")
208
 
209
  with gr.Row():
210
  model_dropdown = gr.Dropdown(
211
  choices=[
212
+ "✨ Google: Gemini 3.0 Pro (Preview)",
213
+ "✨ Google: Gemini 2.5 Pro",
214
  "✨ Google: Gemini 2.5 Flash",
215
+ "✨ Google: Gemini 2.0 Flash",
216
  "☁️ Groq: Llama 3.3 70B",
217
+ "🇫🇷 Mistral: Pixtral Large (Vision) 🖼️",
218
  "🇫🇷 Mistral: Large 2512 (Dez/25)",
 
219
  "🇫🇷 Mistral: Magistral Medium (VIP)",
220
  "🇫🇷 Mistral: Codestral 2508 (Code)",
221
  "🔥 Local H200: Qwen 2.5 Coder"
222
  ],
223
+ value="🇫🇷 Mistral: Pixtral Large (Vision) 🖼️",
224
  label="Escolha o Cérebro",
225
  interactive=True
226
  )
227
 
228
+ # ATENÇÃO: multimodal=True HABILITA O UPLOAD DE IMAGENS
229
+ chat = gr.ChatInterface(
230
+ fn=router,
231
+ additional_inputs=[model_dropdown],
232
+ multimodal=True, # O SEGREDO ESTÁ AQUI!
233
+ textbox=gr.MultimodalTextbox(placeholder="Digite e/ou cole uma imagem...", file_types=["image"], interactive=True)
234
+ )
235
 
236
  if __name__ == "__main__":
237
  demo.launch()