akra35567 commited on
Commit
6607dfe
·
1 Parent(s): 95affee

Update modules/local_llm.py

Browse files
Files changed (1) hide show
  1. modules/local_llm.py +87 -51
modules/local_llm.py CHANGED
@@ -1,71 +1,107 @@
1
- # modules/local_llm.py (ATUALIZADO + EXPORT CERTO)
2
  import os
3
  from loguru import logger
4
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
5
 
 
6
  MODEL_DIR = "/app/models/hermes-7b"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  class LocalLLM:
9
  def __init__(self):
10
  self.generator = None
11
- self._load_model()
12
 
13
- def _load_model(self):
14
- try:
15
- logger.info(f"Carregando Hermes 7B 8-bit (CPU) de: {MODEL_DIR}")
16
-
17
- if not os.path.exists(f"{MODEL_DIR}/config.json"):
18
- logger.error(f"MODELO NÃO ENCONTRADO EM: {MODEL_DIR}")
19
- self.generator = None
20
- return
21
-
22
- if not any(f.endswith((".safetensors", ".bin")) for f in os.listdir(MODEL_DIR)):
23
- logger.error("NENHUM SHARD ENCONTRADO! RECONSTRUIR COM DOCKERFILE!")
24
- self.generator = None
25
- return
26
-
27
- offload_dir = "/tmp/offload"
28
- os.makedirs(offload_dir, exist_ok=True)
29
-
30
- tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR, use_fast=True)
31
-
32
- model = AutoModelForCausalLM.from_pretrained(
33
- MODEL_DIR,
34
- device_map="cpu",
35
- torch_dtype="float16",
36
- low_cpu_mem_usage=True,
37
- offload_folder=offload_dir,
38
- offload_state_dict=True
39
- )
40
 
41
- self.generator = pipeline(
42
- "text-generation",
43
- model=model,
44
- tokenizer=tokenizer,
45
- max_new_tokens=256,
46
- temperature=0.8,
47
- do_sample=True,
48
- repetition_penalty=1.1,
49
- return_full_text=False
50
- )
51
 
52
- logger.info("HERMES 7B 8-BIT (CPU) CARREGADO COM SUCESSO!")
53
- except Exception as e:
54
- logger.error(f"ERRO AO CARREGAR MODELO: {e}")
55
- import traceback
56
- logger.error(traceback.format_exc())
57
- self.generator = None
 
 
 
 
 
 
58
 
59
  def is_available(self) -> bool:
60
  return self.generator is not None
61
 
62
  def generate(self, prompt: str, max_tokens: int = 256, temperature: float = 0.8) -> str:
63
  if not self.is_available():
64
- return "Desculpa, kota... o modelo não carregou."
65
 
66
  try:
67
- logger.info(f"[HERMES] Gerando com max_tokens={max_tokens}, temp={temperature}")
68
-
69
  output = self.generator(
70
  prompt,
71
  max_new_tokens=max_tokens,
@@ -75,11 +111,11 @@ class LocalLLM:
75
  return_full_text=False
76
  )
77
  text = output[0]["generated_text"].strip()
78
- logger.info(f"[HERMES] Resposta: {text[:60]}...")
79
  return text
80
  except Exception as e:
81
- logger.error(f"ERRO NA GERAÇÃO LOCAL: {e}")
82
  return "Bué, deu pau no Hermes local..."
83
 
84
- # EXPORTA COM NOME QUE O api.py ESPERA
85
  HermesLLM = LocalLLM
 
1
+ # modules/local_llm.py
2
  import os
3
  from loguru import logger
4
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
5
 
6
+ # === CONFIGURAÇÕES ===
7
  MODEL_DIR = "/app/models/hermes-7b"
8
+ FINETUNED_PATH = "/app/data/finetuned_hermes"
9
+
10
+ # === SINGLETON GLOBAL (COMPARTILHADO COM treinamento.py) ===
11
+ _HERMES_GLOBAL = None
12
+
13
+
14
+ def _get_hermes_singleton():
15
+ """Carrega ou retorna Hermes com LoRA (singleton global)"""
16
+ global _HERMES_GLOBAL
17
+ if _HERMES_GLOBAL is not None:
18
+ logger.debug("Reusando Hermes 7B global (local_llm)")
19
+ return _HERMES_GLOBAL
20
+
21
+ logger.info("Carregando Hermes 7B UMA VEZ (local + finetune)...")
22
+
23
+ try:
24
+ if not os.path.exists(f"{MODEL_DIR}/config.json"):
25
+ logger.error("config.json NÃO ENCONTRADO!")
26
+ return None
27
+
28
+ # Verifica shards
29
+ shards = [f for f in os.listdir(MODEL_DIR) if f.endswith(".safetensors")]
30
+ if len(shards) != 4:
31
+ logger.error(f"APENAS {len(shards)} SHARDS .safetensors! FALTANDO!")
32
+ return None
33
+
34
+ # Carrega tokenizer
35
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR, use_fast=True)
36
+ if tokenizer.pad_token is None:
37
+ tokenizer.pad_token = tokenizer.eos_token
38
+
39
+ # Carrega base model (CPU, low mem)
40
+ model = AutoModelForCausalLM.from_pretrained(
41
+ MODEL_DIR,
42
+ device_map="cpu",
43
+ torch_dtype="float16",
44
+ low_cpu_mem_usage=True,
45
+ offload_folder="/tmp/offload",
46
+ offload_state_dict=True
47
+ )
48
+
49
+ # Carrega LoRA se existir
50
+ if os.path.exists(f"{FINETUNED_PATH}/adapter_config.json"):
51
+ from peft import PeftModel
52
+ logger.info("Carregando LoRA finetuned...")
53
+ model = PeftModel.from_pretrained(model, FINETUNED_PATH)
54
+ logger.info("LoRA ANGOLANO CARREGADO!")
55
+ else:
56
+ logger.info("Nenhum LoRA encontrado. Usando base.")
57
+
58
+ _HERMES_GLOBAL = (model, tokenizer)
59
+ logger.info("Hermes 7B GLOBAL carregado com sucesso!")
60
+ return _HERMES_GLOBAL
61
+
62
+ except Exception as e:
63
+ logger.error(f"Erro ao carregar Hermes global: {e}")
64
+ import traceback
65
+ logger.error(traceback.format_exc())
66
+ return None
67
+
68
 
69
  class LocalLLM:
70
  def __init__(self):
71
  self.generator = None
72
+ self._load_pipeline()
73
 
74
+ def _load_pipeline(self):
75
+ result = _get_hermes_singleton()
76
+ if not result:
77
+ logger.error("Hermes não carregado. Pipeline indisponível.")
78
+ self.generator = None
79
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
+ model, tokenizer = result
 
 
 
 
 
 
 
 
 
82
 
83
+ self.generator = pipeline(
84
+ "text-generation",
85
+ model=model,
86
+ tokenizer=tokenizer,
87
+ max_new_tokens=256,
88
+ temperature=0.8,
89
+ do_sample=True,
90
+ repetition_penalty=1.1,
91
+ return_full_text=False,
92
+ device_map="cpu"
93
+ )
94
+ logger.info("Pipeline LOCAL conectado ao Hermes com LoRA!")
95
 
96
  def is_available(self) -> bool:
97
  return self.generator is not None
98
 
99
  def generate(self, prompt: str, max_tokens: int = 256, temperature: float = 0.8) -> str:
100
  if not self.is_available():
101
+ return "Desculpa, kota... o modelo off."
102
 
103
  try:
104
+ logger.info(f"[LOCAL] Gerando: max_tokens={max_tokens}, temp={temperature}")
 
105
  output = self.generator(
106
  prompt,
107
  max_new_tokens=max_tokens,
 
111
  return_full_text=False
112
  )
113
  text = output[0]["generated_text"].strip()
114
+ logger.info(f"[LOCAL] Resposta: {text[:60]}...")
115
  return text
116
  except Exception as e:
117
+ logger.error(f"Erro na geração local: {e}")
118
  return "Bué, deu pau no Hermes local..."
119
 
120
+ # EXPORTA PARA api.py
121
  HermesLLM = LocalLLM