Spaces:
Sleeping
Sleeping
Download app.py from amogaddy/neuronal-gpu: direct link, hf CLI and curl.
- Browser
- Download file 6.35 kB
-
https://huggingface.co/spaces/amogaddy/neuronal-gpu/resolve/main/app.py
- Command line
-
hf download hf://spaces/amogaddy/neuronal-gpu/app.py
-
curl -L -o app.py https://huggingface.co/spaces/amogaddy/neuronal-gpu/resolve/main/app.py
6.35 kB
| """Neuronal su ZeroGPU: qui gira SOLO il modello. | |
| La pagina, gli strumenti, la voce, i ricordi e le sessioni stanno nello Space col container | |
| (amogaddy/neuronal). Quando quello deve calcolare chiama `sessione`: qui parte il modello sulla GPU, | |
| si collega al container, fa i calcoli che gli vengono chiesti e dopo pochi secondi restituisce la GPU. | |
| All'accensione, sulla CPU (non consuma tempo di GPU): scarica llama.cpp e il modello, compila neuronal-brain.""" | |
| import asyncio, glob, hmac, os, re, subprocess, tarfile, time, urllib.request | |
| import gradio as gr | |
| import spaces | |
| from huggingface_hub import hf_hub_download | |
| from ponte import ponte | |
| QUI = os.path.dirname(os.path.abspath(__file__)) | |
| BASE = "/tmp/neuronal" | |
| LLAMA = "https://github.com/ggml-org/llama.cpp/releases/download/b11200/" | |
| PACCHETTI = ["llama-b11200-bin-ubuntu-cuda-12.8-x64.tar.gz", "cudart-llama-b11200-bin-ubuntu-cuda-12.8-x64.tar.gz"] | |
| # llama.cpp è compilato per una libreria di sistema più nuova di quella dello Space: se ne affianca una copia | |
| UBUNTU = "http://archive.ubuntu.com/ubuntu/pool/main/g/" | |
| DEB = [("glibc/", r"libc6_2\.39-0ubuntu8[.\d]*_amd64\.deb"), ("gcc-14/", r"libstdc\+\+6_14[^\"]*24\.04[.\d]*_amd64\.deb"), | |
| ("gcc-14/", r"libgcc-s1_14[^\"]*24\.04[.\d]*_amd64\.deb"), ("gcc-14/", r"libgomp1_14[^\"]*24\.04[.\d]*_amd64\.deb")] | |
| CHIAVE = os.environ.get("NEURONAL_CHIAVE", "") | |
| MASSIMO = 110 # durata massima di una sessione di GPU, in secondi | |
| REGISTRO = os.path.join(BASE, "sessioni.log") | |
| def prepara(): | |
| os.makedirs(BASE, exist_ok=True) | |
| t = time.time() | |
| for nome in PACCHETTI: | |
| fatto = os.path.join(BASE, nome + ".ok") | |
| if not os.path.exists(fatto): | |
| arch = os.path.join(BASE, nome) | |
| urllib.request.urlretrieve(LLAMA + nome, arch) | |
| with tarfile.open(arch) as tar: | |
| tar.extractall(os.path.join(BASE, "llama")) | |
| os.remove(arch) | |
| open(fatto, "w").close() | |
| libs = sorted({d for d, _, fs in os.walk(os.path.join(BASE, "llama")) if any(".so" in f for f in fs)}) | |
| llama = next(d for d in libs if os.path.exists(os.path.join(d, "libllama.so"))) | |
| sistema = os.path.join(BASE, "glibc") | |
| if not os.path.exists(os.path.join(sistema, ".ok")): | |
| for cartella, modello in DEB: | |
| elenco = urllib.request.urlopen(UBUNTU + cartella, timeout=60).read().decode() | |
| nome = sorted(set(re.findall(modello, elenco)))[-1] | |
| deb = os.path.join(BASE, nome) | |
| urllib.request.urlretrieve(UBUNTU + cartella + nome, deb) | |
| subprocess.run(["dpkg-deb", "-x", deb, sistema], check=True) | |
| os.remove(deb) | |
| open(os.path.join(sistema, ".ok"), "w").close() | |
| sis = os.path.join(sistema, "usr", "lib", "x86_64-linux-gnu") | |
| if not os.path.exists(os.path.join(sis, "libc.so.6")): | |
| sis = os.path.join(sistema, "lib", "x86_64-linux-gnu") | |
| cervello = os.path.join(BASE, "neuronal-brain") | |
| src = os.path.join(QUI, "src") | |
| subprocess.run(["gcc", "-O2", "-std=gnu11", "-o", cervello, os.path.join(src, "brain_worker.c"), os.path.join(src, "brain.c"), | |
| "-I" + src, "-I" + os.path.join(src, "llama"), "-L" + llama, "-lmtmd", "-lllama", "-lggml", "-lggml-base", | |
| "-lm", "-lpthread", "-Wl,--allow-shlib-undefined"], check=True) | |
| modello = hf_hub_download("prism-ml/Bonsai-27B-gguf", "Bonsai-27B-Q1_0.gguf") | |
| visione = hf_hub_download("prism-ml/Bonsai-27B-gguf", "Bonsai-27B-mmproj-Q8_0.gguf") | |
| print(f"Pronto in {time.time() - t:.0f} s: llama.cpp, modello e neuronal-brain.", flush=True) | |
| percorsi = os.pathsep.join([sis] + libs + ["/usr/lib/x86_64-linux-gnu"]) | |
| return [os.path.join(sis, "ld-linux-x86-64.so.2"), "--library-path", percorsi, cervello, modello, llama, visione, "32768"] | |
| COMANDO = prepara() | |
| def valida(chiave): | |
| return bool(CHIAVE) and hmac.compare_digest(str(chiave), CHIAVE) | |
| def limita(secondi): | |
| try: | |
| return max(10, min(int(secondi), MASSIMO)) | |
| except (TypeError, ValueError): | |
| return 10 | |
| def durata(chiave, url, secondi): | |
| """Quanta GPU chiedere: il tempo della sessione più il margine per chiudere. ZeroGPU concede la sessione | |
| solo se nel tempo del giorno ne resta almeno altrettanto, ma conta solo quello usato davvero.""" | |
| return limita(secondi) + 8 | |
| def sessione(chiave, url, secondi): | |
| """Avvia il modello sulla GPU e lo collega al motore di Neuronal che l'ha chiesto.""" | |
| if not valida(chiave): | |
| return "chiave sbagliata" | |
| if not re.fullmatch(r"wss?://[A-Za-z0-9.\-:]+/ws\?role=brain&ticket=[0-9a-f]{16,40}", str(url)): | |
| return "indirizzo non valido" | |
| secondi = limita(secondi) | |
| with open(REGISTRO, "ab") as reg: | |
| reg.write(f"\n--- {time.strftime('%H:%M:%S')} sessione di {secondi} s\n".encode()) | |
| reg.flush() | |
| try: | |
| usati = asyncio.run(ponte(COMANDO, url, secondi, stderr=reg)) | |
| except Exception as e: | |
| reg.write(f"ponte: {type(e).__name__}: {e}\n".encode()) | |
| return f"collegamento al motore non riuscito ({type(e).__name__})" | |
| return f"ok {usati:.1f}" | |
| def diagnosi(chiave): | |
| """Le ultime righe scritte dal modello (per capire un problema senza usare la GPU).""" | |
| if not valida(chiave): | |
| return "chiave sbagliata" | |
| try: | |
| return open(REGISTRO, encoding="utf-8", errors="replace").read()[-6000:] | |
| except OSError: | |
| return "nessuna sessione finora" | |
| with gr.Blocks(title="Neuronal GPU") as pagina: | |
| gr.Markdown("# 🧠 Neuronal — il modello\nQui gira solo il modello di Neuronal, sulla GPU. " | |
| "Per usarlo vai su **[amogaddy/neuronal](https://huggingface.co/spaces/amogaddy/neuronal)**: " | |
| "la pagina, gli strumenti e la voce sono lì.\n\nMade in Italy 🇮🇹") | |
| with gr.Accordion("Servizio (lo usa il motore di Neuronal)", open=False): | |
| chiave = gr.Textbox(label="Chiave", type="password") | |
| url = gr.Textbox(label="Motore") | |
| secondi = gr.Number(label="Secondi", value=50) | |
| esito = gr.Textbox(label="Esito", lines=12) | |
| gr.Button("Sessione").click(sessione, [chiave, url, secondi], esito, api_name="sessione") | |
| gr.Button("Diagnosi").click(diagnosi, [chiave], esito, api_name="diagnosi") | |
| pagina.launch(show_error=True) | |