// 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 #include 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 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);