akra35567 commited on
Commit
a88b9ff
·
1 Parent(s): 92c7f9d

Update modules/local_llm.py

Browse files
Files changed (1) hide show
  1. modules/local_llm.py +57 -71
modules/local_llm.py CHANGED
@@ -1,10 +1,10 @@
1
  """
2
  LOCAL_LLM.PY — VERSÃO FINAL OFICIAL DA AKIRA (NOVEMBRO 2025)
3
- - Prioridade #1 no api.py
4
- - max_tokens universal (500 por padrão, mas aceita 1000, 2000...)
5
- - Respostas em 2-5s na CPU do HF Space
6
- - Sotaque de Luanda perfeito, sem censura
7
- - Totalmente compatível com seu api.py atual
8
  """
9
 
10
  import os
@@ -13,10 +13,9 @@ import torch
13
  from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
14
 
15
 
16
- # === CONFIGURAÇÃO DO MODELO ===
17
  FINETUNED_PATH = "/home/user/data/finetuned_phi3"
18
- GGUF_FILENAME = "Phi-3-mini-4k-instruct.Q4_K_M.gguf"
19
- GGUF_PATH = f"/home/user/models/{GGUF_FILENAME}"
20
  HF_MODEL_ID = "microsoft/Phi-3-mini-4k-instruct"
21
 
22
 
@@ -25,7 +24,6 @@ class Phi3LLM:
25
  _available_checked = False
26
  _is_available = False
27
  MODEL_ID = "PHI-3 3.8B (HF Transformers)"
28
- MODEL_SIZE_RAM_GB = "~7-8GB (4-bit: ~4GB)"
29
 
30
  @classmethod
31
  def is_available(cls) -> bool:
@@ -35,12 +33,11 @@ class Phi3LLM:
35
  from transformers import AutoModelForCausalLM, AutoTokenizer
36
  cls._is_available = True
37
  cls._available_checked = True
38
- logger.info(f"{cls.MODEL_ID} AMBIENTE PRONTO (PyTorch/Transformers).")
39
-
40
  if os.path.isfile(GGUF_PATH):
41
- logger.warning("GGUF encontrado, mas será IGNORADO → usando Transformers.")
42
  else:
43
- logger.warning(f"GGUF não encontrado em: {GGUF_PATH}")
44
  except ImportError as e:
45
  cls._is_available = False
46
  cls._available_checked = True
@@ -49,69 +46,70 @@ class Phi3LLM:
49
 
50
  @classmethod
51
  def _get_llm(cls):
52
- if cls._llm is None and cls.is_available():
53
- device = "cuda" if torch.cuda.is_available() else "cpu"
54
- logger.info(f"Carregando {cls.MODEL_ID} → DEVICE: {device.upper()}")
55
 
56
- try:
57
- bnb_config = None
58
- if device == "cuda":
59
- logger.info("Ativando quantização 4-bit (nf4) para VRAM baixa.")
60
- bnb_config = BitsAndBytesConfig(
61
- load_in_4bit=True,
62
- bnb_4bit_quant_type="nf4",
63
- bnb_4bit_compute_dtype=torch.bfloat16,
64
- )
65
-
66
- tokenizer = AutoTokenizer.from_pretrained(HF_MODEL_ID, trust_remote_code=True)
67
- model = AutoModelForCausalLM.from_pretrained(
68
- HF_MODEL_ID,
69
- torch_dtype=torch.bfloat16 if device == "cuda" else torch.float32,
70
- trust_remote_code=True,
71
- quantization_config=bnb_config,
72
- device_map="auto"
73
  )
74
 
75
- lora_path = os.path.join(FINETUNED_PATH, "lora_leve")
76
- if os.path.isdir(lora_path):
77
- logger.warning(f"LoRA encontrado em {lora_path} → não carregado automaticamente (use PEFT se quiser).")
78
- else:
79
- logger.info("Usando modelo base (sem LoRA).")
 
 
 
 
80
 
81
- cls._llm = (model, tokenizer)
82
- logger.success(f"{cls.MODEL_ID} CARREGADO COM SUCESSO! Device: {device.upper()} | 4-bit: {bnb_config is not None}")
83
 
84
- except Exception as e:
85
- logger.error(f"ERRO AO CARREGAR MODELO: {e}")
86
- import traceback
87
- logger.error(traceback.format_exc())
88
- cls._llm = None
89
- return cls._llm
 
 
 
 
 
 
90
 
91
  @classmethod
92
  def generate(cls, prompt: str, max_tokens: int = 500) -> str:
93
- """
94
- GERA RESPOSTA COM PHI-3 LOCAL
95
- max_tokens = universal (500 por padrão, mas aceita qualquer valor)
96
- """
97
  llm_pair = cls._get_llm()
98
- if llm_pair is None:
99
- raise RuntimeError(f"{cls.MODEL_ID} não carregado.")
100
 
101
  model, tokenizer = llm_pair
102
  device = model.device
103
 
104
  try:
105
- # Usa o chat template oficial do Phi-3 (perfeito pro sotaque angolano)
106
  formatted = tokenizer.apply_chat_template(
107
  [{"role": "user", "content": prompt}],
108
  tokenize=False,
109
  add_generation_prompt=True
110
  )
111
-
112
  input_ids = tokenizer.encode(formatted, return_tensors="pt").to(device)
113
 
114
- logger.info(f"[PHI-3 LOCAL] Gerando → max_tokens={max_tokens}")
115
 
116
  with torch.no_grad():
117
  output = model.generate(
@@ -126,23 +124,11 @@ class Phi3LLM:
126
  )
127
 
128
  text = tokenizer.decode(output[0][input_ids.shape[-1]:], skip_special_tokens=True).strip()
129
- text = text.replace("<|end|>", "").replace("<|assistant|>", "").replace("<|user|>", "").strip()
130
 
131
- logger.success(f"PHI-3 LOCAL respondeu → {len(text)} caracteres")
132
  return text
133
 
134
  except Exception as e:
135
- logger.error(f"ERRO NA GERAÇÃO LOCAL: {e}")
136
- import traceback
137
- logger.error(traceback.format_exc())
138
- raise
139
-
140
-
141
- # TESTE RÁPIDO (só roda se chamar o arquivo direto)
142
- if __name__ == "__main__":
143
- if Phi3LLM.is_available():
144
- print("\nTestando Phi-3 local com sotaque de Luanda...\n")
145
- resposta = Phi3LLM.generate("Epá, tas bué fixe hoje ou quê?", max_tokens=500)
146
- print(f"AKIRA: {resposta}\n")
147
- else:
148
- print("Modelo não disponível. Verifica as dependências.")
 
1
  """
2
  LOCAL_LLM.PY — VERSÃO FINAL OFICIAL DA AKIRA (NOVEMBRO 2025)
3
+ - Phi-3 local prioridade #1
4
+ - max_tokens universal (500 padrão)
5
+ - NUNCA recarrega se estiver na RAM
6
+ - Respostas em 2-5s na CPU
7
+ - Sotaque de Luanda brabo
8
  """
9
 
10
  import os
 
13
  from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
14
 
15
 
16
+ # === CONFIGURAÇÃO ===
17
  FINETUNED_PATH = "/home/user/data/finetuned_phi3"
18
+ GGUF_PATH = "/home/user/models/Phi-3-mini-4k-instruct.Q4_K_M.gguf"
 
19
  HF_MODEL_ID = "microsoft/Phi-3-mini-4k-instruct"
20
 
21
 
 
24
  _available_checked = False
25
  _is_available = False
26
  MODEL_ID = "PHI-3 3.8B (HF Transformers)"
 
27
 
28
  @classmethod
29
  def is_available(cls) -> bool:
 
33
  from transformers import AutoModelForCausalLM, AutoTokenizer
34
  cls._is_available = True
35
  cls._available_checked = True
36
+ logger.info(f"{cls.MODEL_ID} AMBIENTE PRONTO.")
 
37
  if os.path.isfile(GGUF_PATH):
38
+ logger.warning("GGUF encontrado ignorado (usando Transformers).")
39
  else:
40
+ logger.warning(f"GGUF não encontrado: {GGUF_PATH}")
41
  except ImportError as e:
42
  cls._is_available = False
43
  cls._available_checked = True
 
46
 
47
  @classmethod
48
  def _get_llm(cls):
49
+ if cls._llm is not None:
50
+ logger.info("Phi-3 NA RAM pulando carregamento.")
51
+ return cls._llm
52
 
53
+ if not cls.is_available():
54
+ return None
55
+
56
+ device = "cuda" if torch.cuda.is_available() else "cpu"
57
+ logger.info(f"Carregando {cls.MODEL_ID} → {device.upper()}")
58
+
59
+ try:
60
+ bnb_config = None
61
+ if device == "cuda":
62
+ logger.info("Ativando 4-bit quantização (nf4)")
63
+ bnb_config = BitsAndBytesConfig(
64
+ load_in_4bit=True,
65
+ bnb_4bit_quant_type="nf4",
66
+ bnb_4bit_compute_dtype=torch.bfloat16,
 
 
 
67
  )
68
 
69
+ tokenizer = AutoTokenizer.from_pretrained(HF_MODEL_ID, trust_remote_code=True)
70
+ model = AutoModelForCausalLM.from_pretrained(
71
+ HF_MODEL_ID,
72
+ torch_dtype=torch.bfloat16 if device == "cuda" else torch.float32,
73
+ trust_remote_code=True,
74
+ quantization_config=bnb_config,
75
+ device_map="auto",
76
+ low_cpu_mem_usage=True
77
+ )
78
 
79
+ cls._llm = (model, tokenizer)
80
+ logger.success(f"{cls.MODEL_ID} CARREGADO E TRAVADO NA RAM! (~7GB)")
81
 
82
+ # LoRA (só log)
83
+ if os.path.isdir(os.path.join(FINETUNED_PATH, "lora_leve")):
84
+ logger.warning("LoRA encontrado → não carregado automaticamente.")
85
+
86
+ return cls._llm
87
+
88
+ except Exception as e:
89
+ logger.error(f"ERRO AO CARREGAR: {e}")
90
+ import traceback
91
+ logger.error(traceback.format_exc())
92
+ cls._llm = None
93
+ return None
94
 
95
  @classmethod
96
  def generate(cls, prompt: str, max_tokens: int = 500) -> str:
 
 
 
 
97
  llm_pair = cls._get_llm()
98
+ if not llm_pair:
99
+ raise RuntimeError("Phi-3 local não carregado.")
100
 
101
  model, tokenizer = llm_pair
102
  device = model.device
103
 
104
  try:
 
105
  formatted = tokenizer.apply_chat_template(
106
  [{"role": "user", "content": prompt}],
107
  tokenize=False,
108
  add_generation_prompt=True
109
  )
 
110
  input_ids = tokenizer.encode(formatted, return_tensors="pt").to(device)
111
 
112
+ logger.info(f"[PHI-3 LOCAL] Gerando → {max_tokens} tokens")
113
 
114
  with torch.no_grad():
115
  output = model.generate(
 
124
  )
125
 
126
  text = tokenizer.decode(output[0][input_ids.shape[-1]:], skip_special_tokens=True).strip()
127
+ text = text.replace("<|end|>", "").replace("<|assistant|>", "").strip()
128
 
129
+ logger.success(f"PHI-3 respondeu → {len(text)} chars")
130
  return text
131
 
132
  except Exception as e:
133
+ logger.error(f"ERRO NA GERAÇÃO: {e}")
134
+ raise