Prometech Computer Sciences Corp commited on
Commit
2514f4f
·
verified ·
1 Parent(s): 85eb6c7

Update prettybird_brain.py

Browse files
Files changed (1) hide show
  1. prettybird_brain.py +234 -109
prettybird_brain.py CHANGED
@@ -1,117 +1,242 @@
1
- import torch
 
 
 
 
 
 
 
 
 
2
  import json
3
  import re
4
- import os
5
- import transformers
6
- from transformers import LogitsProcessor, LogitsProcessorList, AutoModelForCausalLM, AutoTokenizer
7
-
8
- CONTROLLED_REASONING_CORE = "You are a helpful assistant with a Controlled Reasoning Core. Please reason step by step."
9
-
10
- class InterventionLogitsProcessor(LogitsProcessor):
11
- def __init__(self, boost_token_id, boost_value=2.0):
12
- self.boost_token_id = boost_token_id
13
- self.boost_value = boost_value
14
-
15
- def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor:
16
- scores[:, self.boost_token_id] += self.boost_value
17
- return scores
18
-
19
- class prettybird_bce_basic_brain_mini:
20
- def __init__(self, model_path="qwen_merged", device="cuda" if torch.cuda.is_available() else "cpu"):
21
- self.device = device
22
- print(f"Transformers version: {transformers.__version__}")
23
-
24
- local_path = model_path
25
- if not os.path.exists(local_path):
26
- if os.path.exists(os.path.join("llama.cpp", model_path)):
27
- local_path = os.path.join("llama.cpp", model_path)
28
- elif os.path.exists("/content/qwen_merged"):
29
- local_path = "/content/qwen_merged"
30
-
31
- final_path = local_path if os.path.exists(local_path) else "Qwen/Qwen2.5-Math-1.5B-Instruct"
32
- print(f"Loading model from {final_path}...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  try:
35
- # Attempt Native Load (trust_remote_code=False) first
36
- self.tokenizer = AutoTokenizer.from_pretrained(final_path, trust_remote_code=False)
37
- self.model = AutoModelForCausalLM.from_pretrained(
38
- final_path,
39
- device_map=device,
40
- trust_remote_code=False,
41
- torch_dtype=torch.float16
42
- )
43
- print("Loaded natively.")
44
- except Exception as e:
45
- print(f"Native load failed: {e}. Trying remote code...")
46
- try:
47
- self.tokenizer = AutoTokenizer.from_pretrained(final_path, trust_remote_code=True)
48
- self.model = AutoModelForCausalLM.from_pretrained(
49
- final_path,
50
- device_map=device,
51
- trust_remote_code=True,
52
- torch_dtype=torch.float16
53
- )
54
- print("Loaded with remote code.")
55
- except Exception as e2:
56
- raise RuntimeError(f"Failed to load model: {e2}")
57
-
58
- if self.tokenizer.pad_token is None:
59
- self.tokenizer.pad_token = self.tokenizer.eos_token
60
-
61
- def math_reward(self, response):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  score = 0.0
63
- if re.search(r"\\boxed\{.*?\}", response):
64
- score += 1.0
65
- if len(response) > 50:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  score += 0.5
 
67
  return score
68
 
69
- def parameter_editing(self, layer_idx=0, noise_scale=1e-5):
70
- print(f"Editing parameters in layer {layer_idx}...")
71
- try:
72
- with torch.no_grad():
73
- if hasattr(self.model, 'model'):
74
- layers = self.model.model.layers
75
- else:
76
- layers = self.model.layers
77
- weights = layers[layer_idx].self_attn.q_proj.weight
78
- noise = torch.randn_like(weights) * noise_scale
79
- weights.add_(noise)
80
- print("Parameter editing complete.")
81
- except Exception as e:
82
- print(f"Error editing params: {e}")
83
-
84
- def run_tool(self, tool_name, query):
85
- if tool_name == "calculator":
86
- try:
87
- clean_query = re.sub(r"[^0-9+\-*/(). ]", "", query)
88
- if not clean_query.strip(): return "Invalid"
89
- return str(eval(clean_query))
90
- except:
91
- return "Error"
92
- return "Unknown"
93
-
94
- def generate_response(self, query, use_tool=False, use_intervention=False):
95
- input_text = query
96
- if use_tool or "calculate" in query.lower():
97
- match = re.search(r"([\d\.\s\+\-\*\/\(\)]+)", query)
98
- if match and len(match.group(1).strip()) > 3:
99
- res = self.run_tool("calculator", match.group(1))
100
- input_text += f"\nTool Result: {res}"
101
-
102
- messages = [{"role": "system", "content": CONTROLLED_REASONING_CORE}, {"role": "user", "content": input_text}]
103
- inputs = self.tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to(self.device)
104
-
105
- logits_processor = LogitsProcessorList()
106
- if use_intervention:
107
- print("Applying intervention...")
108
- ids = self.tokenizer.encode("Therefore", add_special_tokens=False)
109
- if ids:
110
- logits_processor.append(InterventionLogitsProcessor(ids[0], 5.0))
111
-
112
- outputs = self.model.generate(inputs, max_new_tokens=100, logits_processor=logits_processor, do_sample=True)
113
- response = self.tokenizer.decode(outputs[0][len(inputs[0]):], skip_special_tokens=True)
114
-
115
- print(f"Response: {response}")
116
- print(f"Reward: {self.math_reward(response)}")
117
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ PrettyBird Skull Engine
6
+ - GGUF = mathematical optimization brain (skull)
7
+ - Bodies = interchangeable (text/image/audio/video/3D adapters)
8
+ - Single-file, backend-clean, optimizer-compatible
9
+ """
10
+
11
  import json
12
  import re
13
+ import ast
14
+ import numpy as np
15
+ from dataclasses import dataclass
16
+ from typing import Any, Dict, List, Optional, Tuple
17
+
18
+ from llama_cpp import Llama
19
+
20
+
21
+ # ============================================================
22
+ # 1) SYSTEM PROMPT (FINAL – kilitli)
23
+ # ============================================================
24
+ SYSTEM_PROMPT = """You are a controlled reasoning core operating as a mathematical optimization brain.
25
+
26
+ You are NOT an autonomous agent.
27
+ You operate under an external Python-based optimization and behavior orchestration system (BCE).
28
+
29
+ Hard rules:
30
+ - Output MUST be valid JSON.
31
+ - Output MUST contain ONLY JSON.
32
+ - Do NOT reveal chain-of-thought.
33
+ - Use double quotes only.
34
+ - Keep structure deterministic across revisions.
35
+
36
+ If information is missing, list it in "needs".
37
+
38
+ JSON CONTRACT:
39
+ {
40
+ "version": "1.0",
41
+ "task": "",
42
+ "assumptions": [],
43
+ "needs": [],
44
+ "candidates": [
45
+ {
46
+ "id": "c1",
47
+ "solution": {},
48
+ "constraints": [
49
+ {"name": "", "status": "pass|fail|unknown", "note": ""}
50
+ ],
51
+ "objective_estimate": {"primary": 0.0, "notes": ""},
52
+ "rationale_summary": ""
53
+ }
54
+ ],
55
+ "revision_instructions": "If controller feedback arrives, edit only referenced fields and preserve all others exactly."
56
+ }
57
+ """
58
+
59
+
60
+ # ============================================================
61
+ # 2) Güvenli mini-tool (opsiyonel, math destek)
62
+ # ============================================================
63
+ _ALLOWED_AST = {
64
+ ast.Expression, ast.BinOp, ast.UnaryOp, ast.Constant,
65
+ ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Pow, ast.Mod,
66
+ ast.USub, ast.UAdd,
67
+ }
68
 
69
+ def safe_calc(expr: str) -> Optional[float]:
70
+ if not re.fullmatch(r"[0-9\.\s\+\-\*\/\(\)]+", expr):
71
+ return None
72
+ try:
73
+ tree = ast.parse(expr, mode="eval")
74
+ for n in ast.walk(tree):
75
+ if type(n) not in _ALLOWED_AST:
76
+ return None
77
+ return float(eval(compile(tree, "<calc>", "eval"), {"__builtins__": {}}))
78
+ except Exception:
79
+ return None
80
+
81
+
82
+ # ============================================================
83
+ # 3) Skull (GGUF Math Brain)
84
+ # ============================================================
85
+ @dataclass
86
+ class Skull:
87
+ gguf_path: str
88
+ n_ctx: int = 8192
89
+ n_gpu_layers: int = 0
90
+ chat_format: str = "chatml"
91
+ verbose: bool = False
92
+
93
+ def __post_init__(self):
94
+ self.llm = Llama(
95
+ model_path=self.gguf_path,
96
+ n_ctx=self.n_ctx,
97
+ n_gpu_layers=self.n_gpu_layers,
98
+ chat_format=self.chat_format,
99
+ verbose=self.verbose,
100
+ )
101
+
102
+ def _parse_json(self, text: str) -> Dict[str, Any]:
103
+ t = text.strip()
104
  try:
105
+ return json.loads(t)
106
+ except json.JSONDecodeError:
107
+ s, e = t.find("{"), t.rfind("}")
108
+ if s != -1 and e != -1 and e > s:
109
+ return json.loads(t[s:e+1])
110
+ raise
111
+
112
+ def think(
113
+ self,
114
+ observation: Dict[str, Any],
115
+ temperature: float = 0.2,
116
+ top_p: float = 0.9,
117
+ max_tokens: int = 512,
118
+ ) -> Dict[str, Any]:
119
+
120
+ messages = [
121
+ {"role": "system", "content": SYSTEM_PROMPT},
122
+ {"role": "user", "content": json.dumps(observation, ensure_ascii=False)},
123
+ ]
124
+
125
+ resp = self.llm.create_chat_completion(
126
+ messages=messages,
127
+ temperature=temperature,
128
+ top_p=top_p,
129
+ max_tokens=max_tokens,
130
+ response_format={"type": "json_object"},
131
+ )
132
+
133
+ content = resp["choices"][0]["message"]["content"]
134
+ return self._parse_json(content)
135
+
136
+
137
+ # ============================================================
138
+ # 4) Objective + Constraint (C)
139
+ # ============================================================
140
+ class ObjectiveEngine:
141
+ """
142
+ GGUF çıktısını tekrar değerlendiren deterministik katman.
143
+ """
144
+
145
+ def score(self, result: Dict[str, Any]) -> float:
146
  score = 0.0
147
+
148
+ # valid JSON already guaranteed
149
+ cands = result.get("candidates", [])
150
+ if not cands:
151
+ return -1e9
152
+
153
+ c = cands[0]
154
+
155
+ # constraint satisfaction
156
+ for con in c.get("constraints", []):
157
+ if con.get("status") == "pass":
158
+ score += 1.0
159
+ elif con.get("status") == "fail":
160
+ score -= 2.0
161
+
162
+ # model's own estimate
163
+ oe = c.get("objective_estimate", {})
164
+ if isinstance(oe.get("primary"), (int, float)):
165
+ score += float(oe["primary"])
166
+
167
+ # small structure bonus
168
+ if isinstance(c.get("solution"), dict):
169
  score += 0.5
170
+
171
  return score
172
 
173
+
174
+ # ============================================================
175
+ # 5) Body (örnek: text body)
176
+ # ============================================================
177
+ class TextBody:
178
+ def observe(self, text: str) -> Dict[str, Any]:
179
+ # İleride image/audio/video/3D body'ler aynı fonksiyonu sağlar
180
+ return {
181
+ "task": "optimization_request",
182
+ "body": "text",
183
+ "input": text,
184
+ }
185
+
186
+
187
+ # ============================================================
188
+ # 6) Orchestrator (brain loop)
189
+ # ============================================================
190
+ class BrainSystem:
191
+ def __init__(self, skull: Skull, body: Any):
192
+ self.skull = skull
193
+ self.body = body
194
+ self.objective = ObjectiveEngine()
195
+
196
+ def run(self, raw_input: Any, rounds: int = 2) -> Dict[str, Any]:
197
+ obs = self.body.observe(raw_input)
198
+
199
+ best = None
200
+ best_score = -1e18
201
+
202
+ for r in range(rounds):
203
+ result = self.skull.think(obs)
204
+ score = self.objective.score(result)
205
+
206
+ if score > best_score:
207
+ best = result
208
+ best_score = score
209
+
210
+ # revise loop (hafif)
211
+ if result.get("needs"):
212
+ obs["_feedback"] = {
213
+ "issue": "missing_data",
214
+ "needs": result["needs"],
215
+ }
216
+
217
+ return {
218
+ "best_score": best_score,
219
+ "decision": best,
220
+ }
221
+
222
+
223
+ # ============================================================
224
+ # 7) Demo
225
+ # ============================================================
226
+ if __name__ == "__main__":
227
+ skull = Skull(
228
+ gguf_path="prettybird_bce_basic_brain_mini_q4_k_m.gguf",
229
+ n_ctx=8192,
230
+ n_gpu_layers=0,
231
+ chat_format="chatml",
232
+ )
233
+
234
+ body = TextBody()
235
+ brain = BrainSystem(skull, body)
236
+
237
+ output = brain.run(
238
+ "5 işi 2 makineye ata ve makespan minimize et. Süreler: [3,5,2,6,4].",
239
+ rounds=2,
240
+ )
241
+
242
+ print(json.dumps(output, ensure_ascii=False, indent=2))