File size: 8,762 Bytes
d601f7c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Brain: il modello linguistico con i suoi neuroni reali esposti.
// Osserva le attivazioni FFN (ffn_swiglu-L) di ogni strato durante il calcolo e applica
// gli interventi (spegnimento / amplificazione) prima che il resto della rete le legga.
#pragma once
#include <stdbool.h>
#include <stddef.h>

typedef struct Brain Brain;

typedef struct {
    int  n_layer;
    int  n_ff;        // neuroni FFN per strato
    long n_neurons;   // n_layer * n_ff
    int  n_embd;      // dimensione del flusso residuo
} BrainInfo;

// Area creata (neurogenesi): neuroni aggiunti alla rete, calcolati dentro il modello.
// Il neurone k legge l'ingresso FFN x del suo strato e, se si attiva, scrive nell'uscita FFN:
//   a = tonic ? 1 : clamp((w_in·x - bias) * scale, 0, 1)      uscita += gain * a * w_out
typedef struct {
    int    n;             // neuroni
    int   *layer;         // [n]
    float *w_in;          // [n][n_embd]
    float *bias, *scale;  // [n]
    float *w_out;         // [n][n_embd]
    float  gain;
    bool   enabled, tonic;
} BrainArea;

typedef enum { ROLE_SYSTEM, ROLE_USER, ROLE_ASSISTANT } Role;
// Perché si è fermata l'ultima generazione.
typedef enum { STOP_END, STOP_MAX, STOP_LOOP, STOP_USER } BrainStop;
typedef struct { Role role; const char *text; } ChatMsg;

typedef struct {
    bool     thinking;      // ragionamento attivo
    int      think_budget;  // massimo token di ragionamento (<= 0: nessun limite)
    int      max_tokens;    // massimo token totali generati
    float    temperature;   // <= 0: greedy (deterministico)
    unsigned seed;
    float    repeat_penalty; // > 1 penalizza i token recenti (contro i loop); 0 o 1 = spenta
    bool     tools;          // strumenti attivi: si ferma dopo </tool_call> e non scambia il codice per un loop
    const unsigned char *image_rgb;   // immagine allegata all'ultimo messaggio dell'utente (RGB, 3 byte per pixel)
    int      image_w, image_h;
} GenOpts;

// Chiamata per ogni frammento generato. thought = parte del ragionamento.
// Ritorna false per interrompere la generazione.
typedef bool (*brain_token_fn)(void *ud, const char *piece, bool thought);

// backend_dir: cartella con ggml-cuda.dll e ggml-cpu-*.dll (NULL = cartella dell'eseguibile).
// n_gpu_layers: strati caricati sulla GPU (999 = tutti).
Brain    *brain_open(const char *model_path, int n_ctx, const char *backend_dir, int n_gpu_layers);
void      brain_close(Brain *b);
// Visione: carica il proiettore delle immagini (neuronal-visione.gguf). Si chiama una volta; true se pronta.
bool      brain_vision_open(Brain *b, const char *mmproj_path);
bool      brain_has_vision(const Brain *b);
BrainInfo brain_info(const Brain *b);

// Attivazione dell'ultimo token calcolato: [n_layer][n_ff].
const float *brain_last_activation(const Brain *b);

// Accumulo di |a| per neurone su tutti i token calcolati tra begin e end (per la mappatura).
void          brain_accum_begin(Brain *b);
const double *brain_accum(const Brain *b, long *n_tokens);   // [n_layer][n_ff]
void          brain_accum_end(Brain *b);

// Fa "leggere" un testo al modello senza generare. Ritorna i token letti o -1.
int brain_feed(Brain *b, const char *text);

// Conversazione. Ritorna i token generati o -1. answer riceve la risposta (senza ragionamento).
int brain_chat(Brain *b, const ChatMsg *msgs, int n_msgs, const GenOpts *opts,
               brain_token_fn fn, void *ud, char *answer, size_t answer_cap);

// Interventi sui neuroni. factor: 0 = spento, 1 = normale, >1 amplificato, <0 invertito.
// Ogni chiamata è un'operazione annullabile. Ritorna il numero di neuroni modificati o -1.
int  brain_set_neurons(Brain *b, int layer, const int *idx, int n, float factor);
// I k neuroni più attivi (|a|) dello strato, dall'ultima attivazione. Ritorna quanti.
// Da chiamare dal thread che esegue il modello (l'attivazione cambia durante il calcolo).
int  brain_top_neurons(const Brain *b, int layer, int k, int *out);
// Indici dei k valori più grandi in modulo di a[0..n), in ordine decrescente. Ritorna quanti.
int  top_abs(const float *a, int n, int k, int *out);
bool brain_undo(Brain *b);
void brain_reset(Brain *b);
// Neuroni modificati per strato (array di n_layer elementi). Ritorna il totale.
long brain_intervention_counts(Brain *b, int *per_layer);
float brain_neuron_factor(Brain *b, int layer, int idx);
// Elenco dei neuroni modificati (fino a cap). Ritorna quanti ne ha scritti.
int  brain_intervention_list(Brain *b, int *layer, int *idx, float *factor, int cap);

// Autodiagnosi: sospende o riattiva tutti gli interventi manuali senza perderli.
void      brain_interventions_enable(Brain *b, bool on);
BrainStop brain_last_stop(const Brain *b);

// Modifiche strutturali (macroaree eliminate o riconvertite): si sommano agli interventi ma non
// fanno parte di annulla/ripristina. idx NULL = tutti i neuroni dello strato. Ritorna quanti o -1.
int  brain_struct_set(Brain *b, int layer, const int *idx, int n, float factor);
void brain_struct_clear(Brain *b);

// Esercitazione di infezione: fattore separato da tutto il resto (1 = sano). Ritorna true se è cambiato.
bool  brain_infect_set(Brain *b, int layer, int idx, float factor);
float brain_infect_get(Brain *b, int layer, int idx);
void  brain_infect_clear(Brain *b);   // anche i neuroni delle aree
// Infezione di un neurone di un'area creata (k = indice nell'area). Ritorna true se è cambiato.
bool  brain_area_infect(Brain *b, int id, int k, float factor);
// Attività media dei neuroni dell'area nell'ultimo accumulo (brain_accum_begin/end). Ritorna quanti o -1.
int   brain_area_accum(Brain *b, int id, float *out, int cap);

// Cattura: somma per strato dell'ingresso FFN (x) e dell'uscita dello strato (l_out) su tutti i token.
void          brain_capture_begin(Brain *b);
const double *brain_capture_x(const Brain *b, long *n_tokens);   // [n_layer][n_embd]
const double *brain_capture_out(const Brain *b);                 // [n_layer][n_embd]
const float  *brain_capture_last(const Brain *b);                // [n_layer][n_embd] ingresso FFN dell'ultimo token
void          brain_capture_end(Brain *b);

// Aree create. id scelto dal chiamante (stabile tra gli avvii). La brain copia i dati.
bool brain_area_add(Brain *b, int id, const BrainArea *a);
bool brain_area_update(Brain *b, int id, bool enabled, float gain);
bool brain_area_remove(Brain *b, int id);
// Attivazioni dell'ultimo token dei neuroni dell'area (fino a cap). Ritorna quanti o -1.
int  brain_area_activation(Brain *b, int id, float *out, int cap);

// ---- Calcolo delegato ---------------------------------------------------------------------------------
// Lettura e generazione possono girare in un altro processo, su una GPU presa in prestito per pochi secondi.
// Interventi, aree e ogni dato letto dal programma restano qui: prima del calcolo viaggia lo stato dei neuroni,
// dopo tornano le attivazioni. Se il collegamento manca o cade si calcola qui, come sempre.
typedef struct {
    void *ud;
    // C'è un cervello remoto con almeno need_s secondi a disposizione? 1 sì, 0 no, -1 c'è ma il tempo non basta.
    // request: se non c'è lo chiede e aspetta un po'.
    int   (*acquire)(void *ud, int need_s, bool request);
    unsigned (*epoch)(void *ud);                              // cambia a ogni nuovo cervello remoto (mai 0)
    bool  (*send)(void *ud, const void *data, size_t len);
    // Blocco ricevuto (da liberare) o NULL se è caduto o il tempo è scaduto. timeout_ms: 0 = solo se c'è già, < 0 = senza limite.
    void *(*recv)(void *ud, size_t *len, int timeout_ms);
    void  (*drop)(void *ud);                                  // chiude il collegamento
} BrainLink;
void brain_link_set(Brain *b, const BrainLink *l);
// Da chiamare ogni tanto da un altro thread: se il cervello remoto è fermo da idle_s secondi (o il suo tempo
// sta finendo) recupera i dati rimasti di là e lo congeda, così la GPU torna libera.
void brain_link_idle(Brain *b, double idle_s);
// Lato remoto: serve le richieste finché arriva il congedo o cade il collegamento (usa send e recv).
void brain_serve(Brain *b, const BrainLink *l, const char *mmproj_path);
// I k neuroni più attivi dello strato nell'ultimo token, i loro valori e la media di |a|. Ritorna quanti.
// Vale anche mentre il calcolo è delegato (fino a 32 neuroni).
int  brain_layer_top(Brain *b, int layer, int k, int *idx, float *val, float *mean);

// OCR: il modello trascrive il testo di un'immagine (file jpg, png, bmp, gif...). Serve la visione (brain_vision_open).
// Ritorna i token scritti, -1 se la lettura è fallita, -2 se la visione non è disponibile, -3 se il file non è un'immagine.
int brain_ocr(Brain *b, const unsigned char *file, size_t len, char *out, size_t cap);