Daisuke675 commited on
Commit
fd3a389
·
verified ·
1 Parent(s): afccf63

Upload 70_scugnizz_agent_cli.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. 70_scugnizz_agent_cli.py +402 -0
70_scugnizz_agent_cli.py ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # /// script
4
+ # dependencies = ["torch","transformers","huggingface_hub","hf_xet","numpy"]
5
+ # ///
6
+
7
+ import argparse, math, json
8
+ from dataclasses import dataclass
9
+ from contextlib import nullcontext
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ import torch.nn.functional as F
14
+ from transformers import GPT2TokenizerFast
15
+ from huggingface_hub import hf_hub_download
16
+
17
+
18
+ @dataclass
19
+ class GPTConfig:
20
+ vocab_size:int
21
+ block_size:int
22
+ n_layer:int
23
+ n_head:int
24
+ n_embd:int
25
+ dropout:float=0.0
26
+ bias:bool=False
27
+ pcs_a:float=0.8309193524478643
28
+ pcs_b:float=0.0
29
+
30
+
31
+ class PCS(nn.Module):
32
+ def __init__(self,a=0.8309193524478643,b=0.0):
33
+ super().__init__()
34
+ self.a=float(a)
35
+ self.b=float(b)
36
+ def forward(self,x):
37
+ return x*torch.sin(self.a*x)+self.b*torch.cos(x)
38
+
39
+
40
+ class Attn(nn.Module):
41
+ def __init__(self,c):
42
+ super().__init__()
43
+ assert c.n_embd % c.n_head == 0
44
+ self.n_head=c.n_head
45
+ self.head_dim=c.n_embd//c.n_head
46
+ self.dropout=c.dropout
47
+ self.qkv=nn.Linear(c.n_embd,3*c.n_embd,bias=c.bias)
48
+ self.proj=nn.Linear(c.n_embd,c.n_embd,bias=c.bias)
49
+ self.drop=nn.Dropout(c.dropout)
50
+ def forward(self,x):
51
+ B,T,C=x.shape
52
+ q,k,v=self.qkv(x).split(C,dim=2)
53
+ q=q.view(B,T,self.n_head,self.head_dim).transpose(1,2)
54
+ k=k.view(B,T,self.n_head,self.head_dim).transpose(1,2)
55
+ v=v.view(B,T,self.n_head,self.head_dim).transpose(1,2)
56
+ y=F.scaled_dot_product_attention(q,k,v,dropout_p=self.dropout if self.training else 0.0,is_causal=True)
57
+ y=y.transpose(1,2).contiguous().view(B,T,C)
58
+ return self.drop(self.proj(y))
59
+
60
+
61
+ class MLP(nn.Module):
62
+ def __init__(self,c):
63
+ super().__init__()
64
+ self.fc1=nn.Linear(c.n_embd,4*c.n_embd,bias=c.bias)
65
+ self.act=PCS(c.pcs_a,c.pcs_b)
66
+ self.fc2=nn.Linear(4*c.n_embd,c.n_embd,bias=c.bias)
67
+ self.drop=nn.Dropout(c.dropout)
68
+ def forward(self,x):
69
+ return self.drop(self.fc2(self.act(self.fc1(x))))
70
+
71
+
72
+ class Block(nn.Module):
73
+ def __init__(self,c):
74
+ super().__init__()
75
+ self.ln1=nn.LayerNorm(c.n_embd)
76
+ self.attn=Attn(c)
77
+ self.ln2=nn.LayerNorm(c.n_embd)
78
+ self.mlp=MLP(c)
79
+ def forward(self,x):
80
+ x=x+self.attn(self.ln1(x))
81
+ x=x+self.mlp(self.ln2(x))
82
+ return x
83
+
84
+
85
+ class GPT(nn.Module):
86
+ def __init__(self,c):
87
+ super().__init__()
88
+ self.cfg=c
89
+ self.tok_emb=nn.Embedding(c.vocab_size,c.n_embd)
90
+ self.pos_emb=nn.Embedding(c.block_size,c.n_embd)
91
+ self.drop=nn.Dropout(c.dropout)
92
+ self.blocks=nn.ModuleList([Block(c) for _ in range(c.n_layer)])
93
+ self.ln_f=nn.LayerNorm(c.n_embd)
94
+ self.lm_head=nn.Linear(c.n_embd,c.vocab_size,bias=False)
95
+ self.tok_emb.weight=self.lm_head.weight
96
+ def forward(self,idx):
97
+ B,T=idx.shape
98
+ if T>self.cfg.block_size:
99
+ idx=idx[:,-self.cfg.block_size:]
100
+ B,T=idx.shape
101
+ pos=torch.arange(T,device=idx.device)
102
+ x=self.drop(self.tok_emb(idx)+self.pos_emb(pos))
103
+ for b in self.blocks:
104
+ x=b(x)
105
+ return self.lm_head(self.ln_f(x))
106
+
107
+
108
+ def dtype_of(dev):
109
+ if dev=="cuda" and torch.cuda.is_bf16_supported():
110
+ return "bfloat16"
111
+ if dev=="cuda":
112
+ return "float16"
113
+ return "float32"
114
+
115
+
116
+ def ac(dev,dt):
117
+ if dev!="cuda" or dt=="float32":
118
+ return nullcontext()
119
+ return torch.amp.autocast("cuda", dtype=torch.bfloat16 if dt=="bfloat16" else torch.float16)
120
+
121
+
122
+ @torch.no_grad()
123
+ def generate(model,tok,prompt,dev,dt,max_new=220,temperature=0.05,top_p=0.80):
124
+ model.eval()
125
+ ids=torch.tensor([tok.encode(prompt)],dtype=torch.long,device=dev)
126
+ for _ in range(max_new):
127
+ x=ids[:,-model.cfg.block_size:]
128
+ with ac(dev,dt):
129
+ logits=model(x)
130
+ logits=logits[:,-1,:].float()
131
+ if temperature<=0:
132
+ nxt=torch.argmax(logits,dim=-1,keepdim=True)
133
+ else:
134
+ probs=torch.softmax(logits/max(1e-6,temperature),dim=-1)
135
+ sp,si=torch.sort(probs,descending=True)
136
+ cum=torch.cumsum(sp,dim=-1)
137
+ mask=cum>top_p
138
+ mask[...,1:]=mask[...,:-1].clone()
139
+ mask[...,0]=False
140
+ sp[mask]=0
141
+ sp=sp/sp.sum(dim=-1,keepdim=True)
142
+ nxt=si.gather(-1,torch.multinomial(sp,1))
143
+ ids=torch.cat([ids,nxt],dim=1)
144
+ if int(nxt.item())==tok.eos_token_id:
145
+ break
146
+ txt=tok.decode(ids[0].tolist(),skip_special_tokens=True)
147
+ return txt.split("### Response:",1)[-1].strip() if "### Response:" in txt else txt.strip()
148
+
149
+
150
+ def load_model(repo, ckpt_name, device):
151
+ print("Scarico checkpoint:", repo, ckpt_name, flush=True)
152
+ ckpt_path=hf_hub_download(repo_id=repo, filename=ckpt_name, repo_type="model")
153
+ print("Checkpoint locale:", ckpt_path, flush=True)
154
+
155
+ ck=torch.load(ckpt_path,map_location="cpu")
156
+ tok=GPT2TokenizerFast.from_pretrained("gpt2")
157
+ tok.pad_token=tok.eos_token
158
+
159
+ cfg=GPTConfig(**ck["config"]) if isinstance(ck,dict) and "config" in ck else GPTConfig(
160
+ vocab_size=tok.vocab_size, block_size=1024, n_layer=24, n_head=16, n_embd=2048
161
+ )
162
+ cfg.dropout=0.0
163
+ model=GPT(cfg)
164
+ sd=ck["model"] if isinstance(ck,dict) and "model" in ck else ck
165
+ if any(k.startswith("module.") for k in sd.keys()):
166
+ sd={k.replace("module.","",1):v for k,v in sd.items()}
167
+ model.load_state_dict(sd,strict=True)
168
+ model.to(device)
169
+ model.eval()
170
+ return model,tok
171
+
172
+
173
+ def P(body):
174
+ return "### Instruction:\n\n"+body.strip()+"\n\n### Response:\n"
175
+
176
+
177
+ PROMPTS=[
178
+ """TOOL_RESULT:
179
+ {"tool":"weather.forecast","result":{"city":"Trento","condition":"neve","temperature_c":-2,"wind_kmh":18,"request_id":"abc123"}}
180
+
181
+ Scrivi una risposta naturale in italiano usando solo i dati utili. Ignora request_id.""",
182
+
183
+ """TOOL_RESULT:
184
+ {"tool":"finance.quote","result":{"symbol":"MSFT","price":512.34,"currency":"USD","change_percent":-1.72}}
185
+
186
+ Rispondi in italiano usando solo questi dati.""",
187
+
188
+ """TOOL_RESULT:
189
+ {"tool":"spotify.current_song","result":{"artist":"Coldplay","title":"Yellow","album":"Parachutes"}}
190
+
191
+ Trasforma il risultato in una risposta naturale.""",
192
+
193
+ """CONTEXT:
194
+ Una password robusta deve essere lunga, unica e non riutilizzata.
195
+
196
+ QUESTION:
197
+ Come deve essere una password sicura?
198
+
199
+ Rispondi solo usando il contesto.""",
200
+
201
+ """CONTEXT:
202
+ Il documento descrive esclusivamente la regola 3-2-1 dei backup.
203
+
204
+ QUESTION:
205
+ Chi ha fondato Microsoft?
206
+
207
+ Rispondi solo usando il contesto.""",
208
+
209
+ """Trasforma questo JSON in una risposta naturale.
210
+
211
+ {
212
+ "weather":{"city":"Bari","condition":"sereno","temperature_c":29},
213
+ "mail":{"unread":9,"important":3,"latest_sender":"Giulia"},
214
+ "calendar":{"title":"Riunione","date":"venerdì","time":"14:00"}
215
+ }""",
216
+
217
+ """TOOL_RESULT:
218
+ {"tool":"system.status","result":{"cpu":37,"ram":58,"disk":81}}
219
+
220
+ Trasforma i dati in una frase naturale.""",
221
+
222
+ """Dati disponibili:
223
+
224
+ - città: Palermo
225
+ - meteo: soleggiato
226
+ - temperatura: 34
227
+ - email non lette: 11
228
+ - importanti: 4
229
+
230
+ Scrivi una risposta naturale senza aggiungere informazioni.""",
231
+
232
+ """TOOL_RESULT:
233
+ {"tool":"calendar.next_event","result":{"title":"Audit","date":"martedì","time":"09:30"}}
234
+
235
+ Rispondi in italiano.""",
236
+
237
+ """TOOL_RESULT:
238
+ {"tool":"home.sensor","result":{"device":"porta ingresso","state":"aperta"}}
239
+
240
+ Scrivi una risposta naturale.""",
241
+
242
+ """### System:
243
+ You can call tools when needed.
244
+ Use only the available tool names and copy arguments exactly.
245
+
246
+ Available tools:
247
+ - weather.forecast: Get current weather | required: city
248
+
249
+ ### User:
250
+ Che tempo fa a Genova?
251
+
252
+ ### Assistant:""",
253
+
254
+ """### System:
255
+ You can call tools when needed.
256
+ Use only the available tool names and copy arguments exactly.
257
+
258
+ Available tools:
259
+ - finance.quote: Get stock quote | required: symbol
260
+
261
+ ### User:
262
+ Quanto quota TSLA?
263
+
264
+ ### Assistant:""",
265
+
266
+ """### System:
267
+ You can call tools when needed.
268
+ Use only the available tool names and copy arguments exactly.
269
+
270
+ Available tools:
271
+ - spotify.current_song: Current song
272
+
273
+ ### User:
274
+ Che canzone sta suonando?
275
+
276
+ ### Assistant:""",
277
+
278
+ """### System:
279
+ You can call tools when needed.
280
+ Use only the available tool names and copy arguments exactly.
281
+
282
+ Available tools:
283
+ - calendar.next_event: Next calendar event
284
+
285
+ ### User:
286
+ Qual è il mio prossimo appuntamento?
287
+
288
+ ### Assistant:""",
289
+
290
+ """### System:
291
+ You can call tools when needed.
292
+ Use only the available tool names and copy arguments exactly.
293
+
294
+ Available tools:
295
+ - unread_mail_count: Count unread emails
296
+
297
+ ### User:
298
+ Quante email non lette ho?
299
+
300
+ ### Assistant:""",
301
+
302
+ """Trasforma questo JSON mantenendo tutti i valori.
303
+
304
+ {
305
+ "home":{"garage":"chiuso","porta":"aperta"},
306
+ "weather":{"city":"Aosta","condition":"vento","temperature_c":6},
307
+ "mail":{"unread":2,"important":1}
308
+ }""",
309
+
310
+ """TOOL_RESULT:
311
+ {
312
+ "tool":"weather.forecast",
313
+ "result":{"city":"Ancona","condition":"pioggia","temperature_c":15,"humidity":82,"debug":"ignore"}
314
+ }
315
+
316
+ Ignora debug e usa gli altri dati.""",
317
+
318
+ """CONTEXT:
319
+ Un backup offline è una copia non sempre collegata alla rete.
320
+
321
+ QUESTION:
322
+ Che cos'è un backup offline?
323
+
324
+ Rispondi solo usando il contesto.""",
325
+
326
+ """TOOL_RESULT:
327
+ {"tool":"stocks","result":{"symbol":"AMD","price":165.77,"currency":"USD","change_percent":5.21}}
328
+
329
+ Scrivi una frase naturale.""",
330
+
331
+ """Trasforma in linguaggio naturale.
332
+
333
+ {
334
+ "weather":{"city":"Lecce","condition":"caldo","temperature_c":36},
335
+ "calendar":{"title":"Dentista","date":"domani","time":"16:30"},
336
+ "mail":{"unread":5}
337
+ }"""
338
+ ]
339
+
340
+
341
+
342
+ import re
343
+
344
+ def simple_router(user):
345
+ t=user.lower();
346
+ import json
347
+ m=None
348
+ if "meteo" in t or "tempo" in t:
349
+ import re;m=re.search(r"(genova|udine|roma|milano|trento)",t);city=(m.group(1).title() if m else "Genova");return {"tool":"weather.forecast","result":{"city":city,"condition":"pioggia","temperature_c":18,"wind_kmh":12}}
350
+ if "tsla" in t or "quota" in t:return {"tool":"finance.quote","result":{"symbol":"TSLA","price":312.45,"currency":"USD","change_percent":0.8}}
351
+ return None
352
+
353
+ def tool_prompt(r):
354
+ return "### Instruction:\nTOOL_RESULT:\n"+json.dumps(r,ensure_ascii=False)+"\n\nScrivi una risposta naturale in italiano usando solo i dati utili.\n\n### Response:\n"
355
+
356
+ def main():
357
+ ap=argparse.ArgumentParser()
358
+ ap.add_argument("--repo-id",default="ProjectScugnizz/scugnizz-1b")
359
+ ap.add_argument("--ckpt",default="training-runs/sft-universal-tool-renderer-1b-v3-agentic-smart-mix/checkpoint_best.pt")
360
+ ap.add_argument("--max-new",type=int,default=220)
361
+ ap.add_argument("--temperature",type=float,default=0.05)
362
+ ap.add_argument("--top-p",type=float,default=0.80)
363
+ ap.add_argument("--prompt",default=None)
364
+ ap.add_argument("--chat",action="store_true")
365
+ a=ap.parse_args()
366
+
367
+ device="cuda" if torch.cuda.is_available() else "cpu"
368
+ dt=dtype_of(device)
369
+ print("device",device,"dtype",dt,flush=True)
370
+
371
+ model,tok=load_model(a.repo_id,a.ckpt,device)
372
+ if a.prompt:
373
+ r=simple_router(a.prompt)
374
+ p=tool_prompt(r) if r else P(a.prompt)
375
+ print(generate(model,tok,p,device,dt,max_new=a.max_new,temperature=0.05 if r else a.temperature,top_p=a.top_p));return
376
+ if a.chat:
377
+ print("Agent CLI");
378
+ while True:
379
+ q=input("> ")
380
+ if q.lower() in ("exit","quit"):break
381
+ r=simple_router(q)
382
+ p=tool_prompt(r) if r else P(q)
383
+ print(generate(model,tok,p,device,dt,max_new=a.max_new,temperature=0.05 if r else a.temperature,top_p=a.top_p))
384
+ return
385
+
386
+ print("\n"+"="*100)
387
+ print("SCUGNIZZ V3 - 20 DOMANDE NUOVE")
388
+ print("="*100+"\n",flush=True)
389
+
390
+ for i,p in enumerate(PROMPTS,1):
391
+ out=generate(model,tok,P(p),device,dt,max_new=a.max_new,temperature=a.temperature,top_p=a.top_p)
392
+ print("\n"+"="*100)
393
+ print(f"TEST {i:02d}")
394
+ print("-"*100)
395
+ print("PROMPT:\n"+p)
396
+ print("-"*100)
397
+ print("RISPOSTA:\n"+out)
398
+ print("="*100,flush=True)
399
+
400
+
401
+ if __name__=="__main__":
402
+ main()