TaylorKaua commited on
Commit
2d5e2c7
·
verified ·
1 Parent(s): 6dde8db

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -300
app.py CHANGED
@@ -1,322 +1,113 @@
1
- # app.py - Versão ultra-robusta com múltiplos fallbacks
2
- import os
3
  import gradio as gr
4
- from huggingface_hub import InferenceClient, InferenceTimeoutError
5
- import time
6
- import logging
7
- from typing import Generator, Optional
8
 
9
- # Configuração de logging para debugging
10
- logging.basicConfig(level=logging.INFO)
11
- logger = logging.getLogger(__name__)
12
-
13
- # Modelos em ordem de prioridade (do mais específico para o mais genérico)
14
- FALLBACK_MODELS = [
15
- "LLM4Binary/sk2decompile-struct-6.7b", # Modelo original
16
- "mradermacher/sk2decompile-struct-6.7b-GGUF", # Versão GGUF
17
- "meta-llama/Meta-Llama-3-8B-Instruct", # Fallback genérico confiável
18
- "mistralai/Mistral-7B-Instruct-v0.2", # Outro fallback
19
- "google/gemma-2b-it" # Fallback leve
20
- ]
21
-
22
- def get_valid_token(hf_token_obj: Optional[object] = None) -> str:
23
- """Obtém um token válido de múltiplas fontes com fallbacks"""
24
  try:
25
- # Tenta obter token do objeto OAuth
26
- if hf_token_obj and hasattr(hf_token_obj, "token") and hf_token_obj.token:
27
- logger.info("Usando token do OAuth")
28
- return hf_token_obj.token
29
-
30
- # Tenta variável de ambiente
31
- env_token = os.getenv("HF_TOKEN", "").strip()
32
- if env_token:
33
- logger.info("Usando token da variável de ambiente HF_TOKEN")
34
- return env_token
35
-
36
- # Tenta arquivo .env
37
- try:
38
- from dotenv import load_dotenv
39
- load_dotenv()
40
- env_token = os.getenv("HF_TOKEN", "").strip()
41
- if env_token:
42
- logger.info("Usando token do arquivo .env")
43
- return env_token
44
- except ImportError:
45
- pass
46
-
47
- # Último fallback: tenta sem token (alguns modelos públicos permitem)
48
- logger.warning("Nenhum token encontrado. Tentando sem autenticação...")
49
- return None
50
-
51
  except Exception as e:
52
- logger.error(f"Erro ao obter token: {e}")
53
- return None
54
 
55
- def create_client(model_id: str, token: Optional[str] = None) -> InferenceClient:
56
- """Cria um cliente de inferência com configurações seguras"""
 
 
 
 
 
57
  try:
58
- # Configurações seguras com timeout
59
- timeout = 60 # 60 segundos para operações complexas
 
60
 
61
- logger.info(f"Criando cliente para modelo: {model_id}")
62
- client = InferenceClient(
63
- model=model_id,
64
- token=token,
65
- timeout=timeout
66
- )
67
 
68
- # Teste rápido de conexão
69
- test_response = client.post(
70
- json={"inputs": "test"},
71
- model=model_id,
72
- timeout=10 # timeout curto para teste
73
- )
 
 
 
74
 
75
- if test_response.status_code in [200, 400]: # 400 pode ser erro de input, mas API está respondendo
76
- logger.info(f"Conexão bem-sucedida com {model_id}")
77
- return client
78
 
79
- logger.warning(f"Teste falhou com status {test_response.status_code} para {model_id}")
80
- return None
 
81
 
82
- except InferenceTimeoutError:
83
- logger.warning(f"Timeout ao conectar com {model_id}")
84
- return None
85
- except Exception as e:
86
- logger.error(f"Erro ao criar cliente para {model_id}: {e}")
87
- return None
88
-
89
- def try_models(messages, max_tokens, temperature, top_p, token):
90
- """Tenta múltiplos modelos em ordem até obter sucesso"""
91
- for model_id in FALLBACK_MODELS:
92
- try:
93
- logger.info(f"Tentando modelo: {model_id}")
94
- client = create_client(model_id, token)
95
-
96
- if not client:
97
- logger.warning(f"Cliente inválido para {model_id}, pulando...")
98
- continue
99
-
100
- # Tenta streaming primeiro
101
- response = ""
102
- stream_success = False
103
-
104
- try:
105
- stream = client.chat_completion(
106
- messages=messages,
107
- max_tokens=max_tokens,
108
- stream=True,
109
- temperature=temperature,
110
- top_p=top_p,
111
- timeout=120 # timeout maior para streaming
112
- )
113
-
114
- for chunk in stream:
115
- if hasattr(chunk, "choices") and chunk.choices:
116
- choice = chunk.choices[0]
117
- if hasattr(choice, "delta") and hasattr(choice.delta, "content"):
118
- token_content = choice.delta.content or ""
119
- if token_content:
120
- response += token_content
121
- yield response
122
- stream_success = True
123
-
124
- if stream_success and response.strip():
125
- logger.info(f"Resposta obtida com sucesso de: {model_id} (streaming)")
126
- return
127
-
128
- except Exception as stream_error:
129
- logger.warning(f"Erro no streaming com {model_id}: {stream_error}")
130
-
131
- # Fallback para chamada síncrona se streaming falhar
132
- if not stream_success:
133
- logger.info(f"Tentando chamada síncrona com {model_id}")
134
- try:
135
- full_response = client.chat_completion(
136
- messages=messages,
137
- max_tokens=max_tokens,
138
- stream=False,
139
- temperature=temperature,
140
- top_p=top_p,
141
- timeout=60
142
- )
143
-
144
- # Extrai resposta de múltiplas formas possíveis
145
- if hasattr(full_response, "choices") and full_response.choices:
146
- choice = full_response.choices[0]
147
- if hasattr(choice, "message") and hasattr(choice.message, "content"):
148
- response = choice.message.content
149
- elif hasattr(choice, "text"):
150
- response = choice.text
151
- elif isinstance(full_response, dict):
152
- if "generated_text" in full_response:
153
- response = full_response["generated_text"]
154
- elif "choices" in full_response and full_response["choices"]:
155
- first_choice = full_response["choices"][0]
156
- if "message" in first_choice and "content" in first_choice["message"]:
157
- response = first_choice["message"]["content"]
158
-
159
- if response and response.strip():
160
- logger.info(f"Resposta obtida com sucesso de: {model_id} (síncrono)")
161
- yield response
162
- return
163
-
164
- except Exception as sync_error:
165
- logger.warning(f"Erro na chamada síncrona com {model_id}: {sync_error}")
166
-
167
- # Pequena pausa entre tentativas para não sobrecarregar
168
- time.sleep(1)
169
-
170
- except Exception as model_error:
171
- logger.error(f"Erro geral com modelo {model_id}: {model_error}")
172
- continue
173
 
174
- # Se todos os modelos falharem
175
- error_msg = (
176
- "❌ **Erro persistente**: Nenhum modelo disponível no momento.\n\n"
177
- "💡 **Soluções sugeridas**:\n"
178
- "1. Verifique sua conexão com a internet\n"
179
- "2. Configure um token HF válido em Settings → Secrets\n"
180
- "3. Tente novamente em alguns minutos\n\n"
181
- f"📋 Últimos modelos tentados: {', '.join(FALLBACK_MODELS[:3])}"
182
- )
183
- logger.error("Todos os modelos falharam")
184
- yield error_msg
185
 
186
- def respond(message: str, history: list, system_message: str, max_tokens: int, temperature: float, top_p: float, hf_token_obj=None) -> Generator[str, None, None]:
187
- """Função de resposta ultra-resiliente"""
 
 
188
 
189
- # Validação de entrada
190
- if not message or not message.strip():
191
- yield "❌ **Mensagem vazia**: Por favor, digite uma mensagem válida."
192
- return
193
-
194
- # Obtém token válido
195
- token = get_valid_token(hf_token_obj)
196
- if not token:
197
- warning_msg = (
198
- "⚠️ **Sem autenticação**: Operando em modo limitado.\n"
199
- "Para melhor performance e acesso a mais modelos:\n"
200
- "1. Configure HF_TOKEN em Settings → Secrets\n"
201
- "2. Ou faça login na interface\n\n"
202
- "Tentando com modelos públicos..."
203
- )
204
- yield warning_msg
205
- # Não retorna aqui, continua tentando com modelos públicos
206
-
207
- # Prepara mensagens
208
- messages = []
209
-
210
- # Adiciona mensagem de sistema se válida
211
- if system_message and system_message.strip():
212
- messages.append({"role": "system", "content": system_message.strip()})
213
- else:
214
- # Mensagem de sistema padrão segura
215
- messages.append({"role": "system", "content": "Você é um assistente útil e especializado em análise de estruturas de código."})
216
-
217
- # Processa histórico com segurança
218
- if history:
219
- for entry in history:
220
- try:
221
- if isinstance(entry, dict) and "role" in entry and "content" in entry:
222
- messages.append(entry)
223
- elif isinstance(entry, list) and len(entry) >= 2:
224
- # Formato [(user_msg, bot_response), ...]
225
- if entry[0]: # mensagem do usuário
226
- messages.append({"role": "user", "content": str(entry[0])})
227
- if entry[1]: # resposta do bot
228
- messages.append({"role": "assistant", "content": str(entry[1])})
229
- except Exception as e:
230
- logger.warning(f"Erro ao processar histórico: {e}")
231
- continue
232
 
233
- # Adiciona mensagem atual
234
- messages.append({"role": "user", "content": message.strip()})
235
 
236
- logger.info(f"Mensagens preparadas: {messages}")
 
 
 
 
237
 
238
- # Tenta obter resposta com múltiplos fallbacks
239
- try:
240
- yield from try_models(messages, max_tokens, temperature, top_p, token)
241
- except Exception as final_error:
242
- logger.critical(f"Erro crítico inesperado: {final_error}")
243
- yield (
244
- "❌ **Erro crítico**: Ocorreu um problema inesperado.\n\n"
245
- f"```python\n{str(final_error)}\n```\n\n"
246
- "Por favor, recarregue a página e tente novamente."
247
- )
248
-
249
- # Interface do usuário - simples e robusta
250
- with gr.Blocks(title="Assistente de Análise de Código") as demo:
251
- gr.Markdown("# 🔍 Assistente de Análise de Estruturas de Código")
252
- gr.Markdown("### Versão robusta com múltiplos fallbacks e recuperação de erros")
253
 
254
- chatbot = gr.ChatInterface(
255
- respond,
256
- type="messages",
257
- additional_inputs=[
258
- gr.Textbox(
259
- value="Você é um especialista em análise de estruturas de código e decompilação. Forneça respostas técnicas detalhadas e precisas.",
260
- label="System Message",
261
- lines=3
262
- ),
263
- gr.Slider(
264
- minimum=1, maximum=4096, value=1024, step=1,
265
- label="Max Tokens (aumente para respostas mais longas)"
266
- ),
267
- gr.Slider(
268
- minimum=0.0, maximum=2.0, value=0.3, step=0.1,
269
- label="Temperature (0.0 = preciso, 2.0 = criativo)"
270
- ),
271
- gr.Slider(
272
- minimum=0.1, maximum=1.0, value=0.9, step=0.05,
273
- label="Top-p (0.1 = focado, 1.0 = diverso)"
274
- ),
275
- ],
276
- examples=[
277
- ["Analise esta função vulnerável: `def process_input(data): eval(data)`"],
278
- ["Qual a estrutura de memória desta classe C++?"],
279
- ["Explique o assembly x86 deste código binário"],
280
- ["Como funciona o mecanismo de herança neste código?"],
281
- ],
282
- cache_examples=False,
283
- analytics_enabled=False,
284
  )
285
 
286
- with gr.Accordion("ℹ️ Informações e Solução de Problemas", open=False):
287
- gr.Markdown("""
288
- ### Este aplicativo é 100% robusto:
289
-
290
- - **Múltiplos fallbacks**: Tenta até 5 modelos diferentes
291
- - **Recuperação de erros**: Nunca falha completamente
292
- - **Autenticação flexível**: Usa token do ambiente ou OAuth
293
- - **Timeouts seguros**: Previne travamentos
294
- - **Validação rigorosa**: Checa todas as entradas
295
-
296
- ### 🛠️ Se ainda encontrar problemas:
297
-
298
- 1. **Configure HF_TOKEN**: Vá em Settings → Secrets e adicione seu token
299
- 2. **Recarregue a página**: Às vezes a conexão precisa ser renovada
300
- 3. **Simplifique sua query**: Modelos têm limites de contexto
301
- 4. **Verifique sua internet**: Necessária para chamadas à API
302
-
303
- ### 📊 Modelos utilizados (em ordem de prioridade):
304
- 1. LLM4Binary/sk2decompile-struct-6.7b (especializado)
305
- 2. mradermacher/sk2decompile-struct-6.7b-GGUF (GGUF)
306
- 3. Meta-Llama-3-8B-Instruct (genérico confiável)
307
- 4. Mistral-7B-Instruct-v0.2 (alternativo)
308
- 5. Gemma-2b-it (fallback leve)
309
- """)
310
 
311
  if __name__ == "__main__":
312
- # Configurações de lançamento ultra-seguras
313
- demo.launch(
314
- server_name="0.0.0.0",
315
- server_port=7860,
316
- share=False,
317
- show_api=False,
318
- favicon_path="https://huggingface.co/front/assets/huggingface_logo-noborder.svg",
319
- allowed_paths=["."],
320
- auth=None, # Não força autenticação
321
- debug=False, # Produção
322
- )
 
 
 
1
  import gradio as gr
2
+ import torch
3
+ from transformers import AutoModelForCausalLM, AutoTokenizer
4
+ import re
 
5
 
6
+ # Carrega o modelo e tokenizer - adaptar conforme a documentação específica do modelo
7
+ def load_model():
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  try:
9
+ print("Carregando modelo LLM4Binary/sk2decompile-struct-6.7b...")
10
+ tokenizer = AutoTokenizer.from_pretrained("LLM4Binary/sk2decompile-struct-6.7b")
11
+ model = AutoModelForCausalLM.from_pretrained(
12
+ "LLM4Binary/sk2decompile-struct-6.7b",
13
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
14
+ device_map="auto" if torch.cuda.is_available() else None
15
+ )
16
+ print("Modelo carregado com sucesso!")
17
+ return model, tokenizer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  except Exception as e:
19
+ print(f"Erro ao carregar modelo: {e}")
20
+ return None, None
21
 
22
+ # Função de decompilação - precisa ser adaptada conforme a API do modelo
23
+ def decompile_binary(assembly_code, max_length=512, temperature=0.7):
24
+ model, tokenizer = load_model()
25
+
26
+ if model is None or tokenizer is None:
27
+ return "Erro ao carregar o modelo. Verifique se o nome do modelo está correto."
28
+
29
  try:
30
+ # Formata o input conforme esperado pelo modelo de decompilação
31
+ # Este formato precisa ser adaptado baseado na documentação do modelo específico
32
+ prompt = f"Decompile the following x86 assembly to C code:\n\n{assembly_code}\n\nC code:"
33
 
34
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1024)
35
+ if torch.cuda.is_available():
36
+ inputs = {k: v.cuda() for k, v in inputs.items()}
 
 
 
37
 
38
+ with torch.no_grad():
39
+ outputs = model.generate(
40
+ **inputs,
41
+ max_new_tokens=max_length,
42
+ temperature=temperature,
43
+ do_sample=True,
44
+ top_p=0.95,
45
+ pad_token_id=tokenizer.eos_token_id
46
+ )
47
 
48
+ decompiled_code = tokenizer.decode(outputs[0], skip_special_tokens=True)
 
 
49
 
50
+ # Extrai apenas o código C gerado (remove o prompt original)
51
+ if "C code:" in decompiled_code:
52
+ decompiled_code = decompiled_code.split("C code:")[1].strip()
53
 
54
+ return decompiled_code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ except Exception as e:
57
+ return f"Erro durante a decompilação: {str(e)}"
 
 
 
 
 
 
 
 
 
58
 
59
+ # Interface Gradio
60
+ with gr.Blocks(title="Binary Decompiler") as demo:
61
+ gr.Markdown("# 🧠 SK²Decompile - Binary to C Code Decompiler")
62
+ gr.Markdown("Decompile x86 assembly code to readable C code using LLM4Binary/sk2decompile-struct-6.7b")
63
 
64
+ with gr.Row():
65
+ with gr.Column():
66
+ assembly_input = gr.Textbox(
67
+ label="Assembly Code (x86)",
68
+ placeholder="Digite ou cole seu código assembly aqui...",
69
+ lines=15,
70
+ max_lines=30
71
+ )
72
+ with gr.Row():
73
+ max_length = gr.Slider(128, 1024, value=512, step=1, label="Max Length")
74
+ temperature = gr.Slider(0.1, 1.0, value=0.7, step=0.1, label="Temperature")
75
+
76
+ decompile_btn = gr.Button("Decompile", variant="primary")
77
+
78
+ with gr.Column():
79
+ c_output = gr.Code(
80
+ label="Decompiled C Code",
81
+ language="c",
82
+ lines=20
83
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
+ gr.Markdown("### Exemplo de uso:")
86
+ gr.Markdown("```\nmov eax, 5\nadd eax, ebx\nret\n```")
87
 
88
+ # Exemplos predefinidos
89
+ examples = [
90
+ ["mov eax, 5\nadd eax, ebx\nret"],
91
+ ["push ebp\nmov ebp, esp\nmov eax, [ebp+8]\nadd eax, [ebp+12]\npop ebp\nret"]
92
+ ]
93
 
94
+ gr.Examples(
95
+ examples=examples,
96
+ inputs=assembly_input,
97
+ outputs=c_output,
98
+ fn=decompile_binary,
99
+ cache_examples=True
100
+ )
 
 
 
 
 
 
 
 
101
 
102
+ decompile_btn.click(
103
+ fn=decompile_binary,
104
+ inputs=[assembly_input, max_length, temperature],
105
+ outputs=c_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  )
107
 
108
+ gr.Markdown("---")
109
+ gr.Markdown("🔗 **Model**: [LLM4Binary/sk2decompile-struct-6.7b](https://huggingface.co/LLM4Binary/sk2decompile-struct-6.7b)")
110
+ gr.Markdown("💡 **Note**: Este é um modelo de 6.7B parâmetros especializado em decompilação binária. Para melhores resultados, forneça funções assembly completas.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
  if __name__ == "__main__":
113
+ demo.launch()