diff --git a/network-poc/hub-local.log b/network-poc/hub-local.log new file mode 100644 index 0000000..dba8b1c --- /dev/null +++ b/network-poc/hub-local.log @@ -0,0 +1,7 @@ + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s + Running `target/debug/hub` +2026-04-12T03:21:35.058711Z  INFO hub: Tietokanta alustettu +2026-04-12T03:21:35.061635Z  INFO hub: Kipinä Agent Hub v0.3.1 käynnistyy osoitteessa http://localhost:3000 +2026-04-12T03:21:49.577628Z  INFO hub: Solmu 1 yhdistyi osoitteesta 127.0.0.1 +2026-04-12T03:21:49.600021Z  INFO hub: Solmu 1 (natiivi) | 127.0.0.1 | Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM | varaus: 4 GB +2026-04-12T03:21:49.600099Z  INFO hub: GPU 0: Apple M2 Max | VRAM: 0/24576 MB | 0°C | 0% diff --git a/network-poc/hub/src/main.rs b/network-poc/hub/src/main.rs index a7bf9ab..ac89d25 100644 --- a/network-poc/hub/src/main.rs +++ b/network-poc/hub/src/main.rs @@ -652,6 +652,17 @@ async fn broadcast_stats(state: &Arc) { "tasks": completed }); let _ = state.stats_tx.send(stats_msg.to_string()); + + // Uutta: Laitetaan sama tieto myös kaikille yhdistyneille solmuille (viesti Hubilta Solmuille) + let node_status = serde_json::json!({ + "type": "network_status", + "active_nodes": total_nodes, + "tasks": completed + }); + let msg_str = node_status.to_string(); + for tx in state.node_channels.read().await.values() { + let _ = tx.send(msg_str.clone()); + } } /// Validoi client-viesti: pakollinen "type"-kenttä, sallittu tyyppi, validi JSON diff --git a/network-poc/native-node.log b/network-poc/native-node.log new file mode 100644 index 0000000..ebe7f5e --- /dev/null +++ b/network-poc/native-node.log @@ -0,0 +1,208 @@ +2026-04-12T02:49:51.405400Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:49:51.422359Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:49:51.437017Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:49:51.437041Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:49:51.441582Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:50:03.018835Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:50:03.036749Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:50:03.052051Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:50:03.052084Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:50:03.056985Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:50:14.540287Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:50:14.558901Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:50:14.572180Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:50:14.572210Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:50:14.575891Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:52:05.405865Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:52:05.422571Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:52:05.433853Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:52:05.433870Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:52:05.437718Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:52:11.707486Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T02:52:11.707646Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:7b-instruct-q4_K_M... +2026-04-12T02:52:12.713480Z  INFO native_node::inference: Malli qwen2.5-coder:7b-instruct-q4_K_M valmis +2026-04-12T02:52:12.713706Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T02:52:12.713749Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T02:52:12.719515Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T02:52:22.800662Z  INFO native_node: Tauotetaan solmun suoritus (Hub ei lähetä tehtäviä)... +2026-04-12T02:52:25.475326Z  INFO native_node: Jatketaan solmun suoritusta... +2026-04-12T02:52:28.692378Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:52:28.708978Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:52:28.723045Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:52:28.723071Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:52:28.728130Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:52:30.362566Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T02:52:30.362707Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:7b-instruct-q4_K_M... +2026-04-12T02:52:31.248236Z  INFO native_node::inference: Malli qwen2.5-coder:7b-instruct-q4_K_M valmis +2026-04-12T02:52:31.248469Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T02:52:31.248505Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T02:52:31.254260Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T02:53:35.385696Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:53:35.401489Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:53:35.412450Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:53:35.412471Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:53:35.416006Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:53:44.463643Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T02:53:44.463794Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:7b-instruct-q4_K_M... +2026-04-12T02:53:45.213997Z  INFO native_node::inference: Malli qwen2.5-coder:7b-instruct-q4_K_M valmis +2026-04-12T02:53:45.214232Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T02:53:45.214287Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T02:53:45.233548Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T02:57:27.480736Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:57:27.497388Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:57:27.508598Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:57:27.508629Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:57:27.512329Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:57:27.512356Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:3b +2026-04-12T02:57:27.512365Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:3b... +2026-04-12T02:57:28.357205Z  INFO native_node::inference: Malli qwen2.5-coder:3b valmis +2026-04-12T02:57:28.357432Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T02:57:28.357489Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:3b +2026-04-12T02:57:28.365906Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T02:57:50.406189Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T02:57:50.423119Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T02:57:50.433561Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T02:57:50.433582Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T02:57:50.437105Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T02:57:54.978974Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:3b +2026-04-12T02:57:54.979107Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:3b... +2026-04-12T02:57:55.795772Z  INFO native_node::inference: Malli qwen2.5-coder:3b valmis +2026-04-12T02:57:55.796000Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T02:57:55.796037Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:3b +2026-04-12T02:57:55.800614Z  WARN native_node: Hubiin yhdistäminen epäonnistui: IO error: Connection refused (os error 61) — yritetään uudelleen 5s... +2026-04-12T02:58:00.808617Z  WARN native_node: Hubiin yhdistäminen epäonnistui: IO error: Connection refused (os error 61) — yritetään uudelleen 5s... +2026-04-12T02:58:05.810771Z  WARN native_node: Hubiin yhdistäminen epäonnistui: IO error: Connection refused (os error 61) — yritetään uudelleen 5s... +2026-04-12T02:58:10.813443Z  WARN native_node: Hubiin yhdistäminen epäonnistui: IO error: Connection refused (os error 61) — yritetään uudelleen 5s... +2026-04-12T03:01:16.781321Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T03:01:16.794319Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T03:01:16.806165Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T03:01:16.806188Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T03:01:16.810275Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T03:01:18.325121Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:3b +2026-04-12T03:01:18.325250Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:3b... +2026-04-12T03:01:20.454444Z  INFO native_node::inference: Malli qwen2.5-coder:3b valmis +2026-04-12T03:01:20.454587Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T03:01:20.454618Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:3b +2026-04-12T03:01:20.468023Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T03:02:28.510843Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T03:02:28.526577Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T03:02:28.539782Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T03:02:28.539802Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T03:02:28.545400Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T03:02:32.541462Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:02:32.541603Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:7b-instruct-q4_K_M... +2026-04-12T03:02:33.365087Z  INFO native_node::inference: Malli qwen2.5-coder:7b-instruct-q4_K_M valmis +2026-04-12T03:02:33.365313Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T03:02:33.365349Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:02:33.401538Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T03:06:31.660670Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T03:06:31.676386Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T03:06:31.690957Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T03:06:31.690977Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T03:06:31.696155Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T03:06:33.075746Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:06:33.075900Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:7b-instruct-q4_K_M... +2026-04-12T03:06:34.006750Z  INFO native_node::inference: Malli qwen2.5-coder:7b-instruct-q4_K_M valmis +2026-04-12T03:06:34.006975Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T03:06:34.007013Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:06:34.012582Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T03:06:42.497863Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:06:46.162703Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 3664ms | 59.1 tok/s +2026-04-12T03:06:49.156537Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:06:49.655724Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 20 tok | 499ms | 57.5 tok/s +2026-04-12T03:06:52.299481Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:06:52.614573Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 314ms | 59.9 tok/s +2026-04-12T03:07:04.444950Z  INFO native_node: → task_id:f889ae9e-ff18-4867-826a-1399ce39ea11 | 41r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:07:10.060424Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 220 tok | 5615ms | 47.8 tok/s +2026-04-12T03:07:10.065996Z  INFO native_node: → task_id:52aaf7f1-7d6a-48df-9329-702bf4438329 | 64r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:07:13.387062Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 54 tok | 3320ms | 37.3 tok/s +2026-04-12T03:07:13.394231Z  INFO native_node: → task_id:bea80c1b-84f3-4859-8372-a01947a181f5 | 122r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:07:28.815501Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 435 tok | 15420ms | 33.8 tok/s +2026-04-12T03:07:28.849290Z  INFO native_node: → task_id:b33bfb94-5ea3-4483-bea6-6eae2e87f622 | 130r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:07:33.403851Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 73 tok | 4554ms | 36.0 tok/s +2026-04-12T03:07:33.410281Z  INFO native_node: → task_id:c7271b5b-9572-4c2d-b1ca-8573153eb818 | 124r prompti | "dev = "uvicorn main:app --reload"..." +2026-04-12T03:07:36.058218Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 3 tok | 2647ms | 66.7 tok/s +2026-04-12T03:07:36.063363Z  INFO native_node: → task_id:3f197227-4c45-4a17-8980-0f9d523b104a | 126r prompti | "Write a complete test_main.py file with TestClient...." +2026-04-12T03:08:04.081504Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 818 tok | 28017ms | 32.6 tok/s +2026-04-12T03:08:04.089182Z  INFO native_node: → task_id:95ff2b0d-b2e8-483b-83a4-68d7227a4784 | 28r prompti | "Write ONLY the Dockerfile, no explanations...." +2026-04-12T03:08:08.956198Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 127 tok | 4866ms | 33.3 tok/s +2026-04-12T03:08:08.962241Z  INFO native_node: → task_id:70a6888c-1327-462f-81e0-238d75c80e27 | 298r prompti | "CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0"..." +2026-04-12T03:08:20.512602Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 170 tok | 11550ms | 31.8 tok/s +2026-04-12T03:10:23.640488Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:24.016781Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 376ms | 59.8 tok/s +2026-04-12T03:10:28.471504Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:28.851913Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 380ms | 56.4 tok/s +2026-04-12T03:10:32.080898Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:32.761760Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 30 tok | 680ms | 56.2 tok/s +2026-04-12T03:10:33.543595Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:34.155195Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 27 tok | 611ms | 56.8 tok/s +2026-04-12T03:10:37.170032Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:37.490844Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 320ms | 59.3 tok/s +2026-04-12T03:10:41.071790Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:41.393921Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 321ms | 58.8 tok/s +2026-04-12T03:10:47.007835Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:47.352103Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 344ms | 56.9 tok/s +2026-04-12T03:10:55.861324Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:10:56.193953Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 332ms | 57.8 tok/s +2026-04-12T03:11:09.557527Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:11:09.890235Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 332ms | 58.7 tok/s +2026-04-12T03:11:11.846667Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:11:12.166974Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 320ms | 59.8 tok/s +2026-04-12T03:11:22.243681Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:11:22.590303Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 346ms | 56.8 tok/s +2026-04-12T03:11:43.577820Z  INFO native_node: → task_id:0d939424-723a-4898-b182-e9959e16abb9 | 41r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:11:50.105047Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 256 tok | 6527ms | 47.0 tok/s +2026-04-12T03:11:50.147446Z  INFO native_node: → task_id:a3492a26-284c-4874-80b6-4aeafdbb5a75 | 69r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:11:53.451037Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 55 tok | 3303ms | 39.0 tok/s +2026-04-12T03:11:53.459737Z  INFO native_node: → task_id:7cc73c11-57a8-4cf2-be31-7302e81d25c7 | 127r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:12:08.447730Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 435 tok | 14987ms | 35.1 tok/s +2026-04-12T03:12:08.455128Z  INFO native_node: → task_id:a7adc096-78b1-4314-93a2-26824e2c6ab1 | 135r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:12:13.297818Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 73 tok | 4842ms | 36.0 tok/s +2026-04-12T03:12:13.308601Z  INFO native_node: → task_id:cda5ff01-e88e-4c58-bf5d-24d7a449b4b2 | 128r prompti | "dev = "uvicorn main:app --reload"..." +2026-04-12T03:12:16.062246Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 3 tok | 2753ms | 70.0 tok/s +2026-04-12T03:12:16.070379Z  INFO native_node: → task_id:8d04d6eb-2439-4038-8ffe-ea37eec8d673 | 128r prompti | "Write a complete test_main.py file with TestClient...." +2026-04-12T03:12:40.311815Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 788 tok | 24240ms | 36.7 tok/s +2026-04-12T03:12:40.348709Z  INFO native_node: → task_id:b112c319-e2ad-4293-8699-4feb4f7cee5e | 30r prompti | "Write ONLY the Dockerfile, no explanations...." +2026-04-12T03:12:45.108493Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 145 tok | 4759ms | 38.6 tok/s +2026-04-12T03:12:45.151914Z  INFO native_node: → task_id:80d8e1cf-d536-4ac4-9577-08fbab53d159 | 295r prompti | "EXPOSE 8000..." +2026-04-12T03:12:55.265794Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 171 tok | 10113ms | 36.7 tok/s +2026-04-12T03:18:26.329119Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T03:18:26.350176Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T03:18:26.367757Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T03:18:26.367784Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T03:18:26.374430Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T03:18:29.330257Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:18:29.330419Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:7b-instruct-q4_K_M... +2026-04-12T03:18:30.297228Z  INFO native_node::inference: Malli qwen2.5-coder:7b-instruct-q4_K_M valmis +2026-04-12T03:18:30.297413Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T03:18:30.297502Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:18:30.304013Z  INFO native_node: Yhdistetty hubiin! +2026-04-12T03:19:02.300905Z  INFO native_node: → task_id:status-check | 1r prompti | "ping..." +2026-04-12T03:19:03.443612Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 11 tok | 1142ms | 58.2 tok/s +2026-04-12T03:19:11.592789Z  INFO native_node: → task_id:3625298a-8cf3-4cfc-b24f-96eb7d8487c3 | 41r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:19:17.955448Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 253 tok | 6362ms | 47.9 tok/s +2026-04-12T03:19:17.965059Z  INFO native_node: → task_id:d8d651b2-2d1b-4652-91c7-0e3d99f12ead | 69r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:19:21.159047Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 54 tok | 3193ms | 40.3 tok/s +2026-04-12T03:19:21.167536Z  INFO native_node: → task_id:fa5f4645-a440-4624-83a6-fb24799d0edc | 127r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:19:35.681742Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 435 tok | 14513ms | 36.2 tok/s +2026-04-12T03:19:35.691591Z  INFO native_node: → task_id:24684ea4-2b1b-41c2-b2b0-068fb4e38483 | 136r prompti | "Adapt the example to match the project description. Import f..." +2026-04-12T03:19:40.236213Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 76 tok | 4544ms | 37.9 tok/s +2026-04-12T03:19:40.244741Z  INFO native_node: → task_id:d4e407e9-a0fd-4b25-b355-317e16851854 | 129r prompti | "dev = "uv run uvicorn main:app --reload"..." +2026-04-12T03:19:43.089356Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 3 tok | 2844ms | 67.8 tok/s +2026-04-12T03:19:43.099954Z  INFO native_node: → task_id:7fa43b8d-8ed1-4f44-be45-bc99619ae74f | 129r prompti | "Write a complete test_main.py file with TestClient...." +2026-04-12T03:20:08.686318Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 773 tok | 25585ms | 34.0 tok/s +2026-04-12T03:20:08.696389Z  INFO native_node: → task_id:98a7c691-29f8-4385-9fe6-389d0edfb404 | 30r prompti | "Write ONLY the Dockerfile, no explanations...." +2026-04-12T03:20:12.560366Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 100 tok | 3863ms | 36.6 tok/s +2026-04-12T03:20:12.569728Z  INFO native_node: → task_id:b95245cb-6c5a-4a8e-b903-40f7471d2e72 | 289r prompti | "CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0"..." +2026-04-12T03:20:22.658899Z  INFO native_node: ✓ qwen2.5-coder:7b-instruct-q4_K_M | 174 tok | 10089ms | 36.3 tok/s +2026-04-12T03:21:37.867699Z  INFO native_node: Kipinä Native Node käynnistyy — hub: ws://127.0.0.1:3000/ws, varaus: 4 GB +2026-04-12T03:21:37.879381Z  INFO native_node: Järjestelmä: Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM +2026-04-12T03:21:37.899474Z  INFO native_node: GPU 0: Apple M2 Max (Apple) [Metal] | VRAM: ?/24576 MB | ? | kuormitus: ? +2026-04-12T03:21:37.899494Z  INFO native_node: Alustetaan Ollama-yhteyttä... +2026-04-12T03:21:37.903580Z  INFO native_node::inference: Ollama löytyi osoitteesta: http://localhost:11434 +2026-04-12T03:21:48.551879Z  INFO native_node::inference: Ollama backend: http://localhost:11434 | malli: qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:21:48.552045Z  INFO native_node::inference: Tarkistetaan malli qwen2.5-coder:7b-instruct-q4_K_M... +2026-04-12T03:21:49.569609Z  INFO native_node::inference: Malli qwen2.5-coder:7b-instruct-q4_K_M valmis +2026-04-12T03:21:49.569839Z  INFO native_node: Ollama valmis inferenssiin! +2026-04-12T03:21:49.569961Z  INFO native_node: Käytettävä kielimalli konfiguroitu (selected_task): qwen2.5-coder:7b-instruct-q4_K_M +2026-04-12T03:21:49.577531Z  INFO native_node: Yhdistetty hubiin! diff --git a/network-poc/native-node/Cargo.toml b/network-poc/native-node/Cargo.toml index 8f2b44d..1163a38 100644 --- a/network-poc/native-node/Cargo.toml +++ b/network-poc/native-node/Cargo.toml @@ -21,3 +21,6 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } dialoguer = "0.12.0" console = "0.16.3" +ratatui = "0.29.0" +crossterm = { version = "0.28.1", features = ["event-stream"] } +tracing-appender = "0.2.4" diff --git a/network-poc/native-node/src/inference.rs b/network-poc/native-node/src/inference.rs index 2815682..ab8f17b 100644 --- a/network-poc/native-node/src/inference.rs +++ b/network-poc/native-node/src/inference.rs @@ -47,10 +47,9 @@ impl LlmEngine { }; // Kysytään malli TUI:lla jos ei pakotettu ympäristöstä - let model = if let Ok(m) = std::env::var("OLLAMA_MODEL") { - m - } else { - crate::tui::select_model(&ollama_url, &client).await? + let model = match std::env::var("OLLAMA_MODEL") { + Ok(m) if !m.is_empty() => m, + _ => crate::tui::select_model(&ollama_url, &client).await? }; tracing::info!("Ollama backend: {} | malli: {}", ollama_url, model); diff --git a/network-poc/native-node/src/main.rs b/network-poc/native-node/src/main.rs index 8008e10..39ac673 100644 --- a/network-poc/native-node/src/main.rs +++ b/network-poc/native-node/src/main.rs @@ -6,6 +6,7 @@ use tokio_tungstenite::tungstenite::Message; mod inference; mod tui; +mod tui_dashboard; /// GPU-tietorakenne — yhtenäinen kaikille valmistajille struct GpuInfo { @@ -268,10 +269,24 @@ fn format_optional(val: Option, suffix: &str) -> String #[tokio::main] async fn main() { + let file_appender = tracing_appender::rolling::never(".", "native-node.log"); + let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); + tracing_subscriber::fmt() .with_env_filter("native_node=debug") + .with_writer(non_blocking) .init(); + // Hookataan paniikkitilanteet palauttamaan terminaalin raw-moodista + let original_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |panic_info| { + tui_dashboard::restore_terminal(); + original_hook(panic_info); + })); + + let tui_state = std::sync::Arc::new(tokio::sync::RwLock::new(tui_dashboard::DashboardState::new())); + let (cmd_tx, mut cmd_rx) = tokio::sync::mpsc::unbounded_channel::(); + let hub_url = std::env::var("HUB_URL").unwrap_or_else(|_| "ws://hub:3000/ws".to_string()); let allocated_gb: u32 = std::env::var("ALLOCATED_GB") .ok() @@ -287,6 +302,18 @@ async fn main() { sys["cpu_cores"], sys["ram_total_mb"] ); + + { + let mut st = tui_state.write().await; + st.sys_info = format!("{} | {} | {} ydintä | {} MB RAM", + sys["hostname"].as_str().unwrap_or("?"), + sys["os"].as_str().unwrap_or("?"), + sys["cpu_cores"], + sys["ram_total_mb"] + ); + let i = st.sys_info.clone(); + st.push_log("System", format!("Järjestelmä: {}", i), None); + } let gpus = collect_all_gpus(); if gpus.is_empty() { @@ -328,6 +355,20 @@ async fn main() { let active_model = llm.as_ref().map(|e| e.model_name()).unwrap_or_else(|| "unknown".to_string()); tracing::info!("Käytettävä kielimalli konfiguroitu (selected_task): {}", active_model); + + { + let mut st = tui_state.write().await; + st.model_name = active_model.clone(); + st.push_log("System", format!("Malli valmis: {}", active_model), None); + } + + // Käynnistetään graafinen TUI vasta kun TUI:n Prompt (LlmEngine::load) on ohitettu! + let ui_state = tui_state.clone(); + tokio::spawn(async move { + if let Err(e) = tui_dashboard::run_dashboard(ui_state, cmd_tx).await { + tracing::error!("Pääluupin TUI kaatui: {}", e); + } + }); // Haetaan paikalliset mallit hubille lähetettäväksi let mut available_models = None; @@ -355,22 +396,28 @@ async fn main() { continue; } - use tokio::io::AsyncBufReadExt; - let mut stdin_lines = tokio::io::BufReader::new(tokio::io::stdin()).lines(); - loop { tokio::select! { - line = stdin_lines.next_line() => { - if let Ok(Some(text)) = line { - let t = text.trim(); - if t == "p" || t == "pause" { + cmd = cmd_rx.recv() => { + if let Some(cmd_str) = cmd { + if cmd_str == "pause" { tracing::info!("Tauotetaan solmun suoritus (Hub ei lähetä tehtäviä)..."); let req = json!({"type": "status_update", "status": "paused"}); let _ = write.send(Message::Text(req.to_string())).await; - } else if t == "r" || t == "resume" || t == "s" { + { + let mut st = tui_state.write().await; + st.status = "PAUSED".to_string(); + st.push_log("Network", "Solmu siirretty taukotilaan".to_string(), None); + } + } else if cmd_str == "resume" { tracing::info!("Jatketaan solmun suoritusta..."); let req = json!({"type": "status_update", "status": "active"}); let _ = write.send(Message::Text(req.to_string())).await; + { + let mut st = tui_state.write().await; + st.status = "ACTIVE".to_string(); + st.push_log("System", "Suoritus jatkuu...".to_string(), None); + } } } } @@ -385,10 +432,32 @@ async fn main() { tracing::info!("Hub pakotti solmun tauolle (Pause)"); let req = json!({"type": "status_update", "status": "paused"}); let _ = write.send(Message::Text(req.to_string())).await; + { + let mut st = tui_state.write().await; + st.status = "PAUSED".to_string(); + st.push_log("Network", "Hub kytki solmun tauolle".to_string(), None); + } } else if action == "resume" { tracing::info!("Hub aktivoi solmun suorituksen (Resume)"); let req = json!({"type": "status_update", "status": "active"}); let _ = write.send(Message::Text(req.to_string())).await; + { + let mut st = tui_state.write().await; + st.status = "ACTIVE".to_string(); + st.push_log("Network", "Hub palautti solmun töihin".to_string(), None); + } + } + } + } + } + // Verkon globaali tila + if text.contains(r#""type":"network_status""#) { + if let Ok(status) = serde_json::from_str::(&text) { + if let Some(nodes) = status.get("active_nodes").and_then(|v| v.as_u64()) { + if let Some(tasks) = status.get("tasks").and_then(|v| v.as_u64()) { + let mut st = tui_state.write().await; + st.network_active_nodes = nodes as usize; + st.network_total_tasks = tasks; } } } @@ -407,17 +476,35 @@ async fn main() { let prompt_lines = prompt.lines().count(); let prompt_last: String = prompt.lines().last().unwrap_or("").chars().take(60).collect(); tracing::info!("→ task_id:{} | {}r prompti | \"{}...\"", task_id, prompt_lines, prompt_last); + { + let mut st = tui_state.write().await; + st.cur_task_id = Some(task_id.to_string()); + st.cur_prompt = Some(format!("→ {} riviä | \"{}...\"", prompt_lines, prompt_last)); + // Ei login puskemista vielä tässä! Yhdistetään se valmiin lohkoon yhdelle riville. + } let model_name = engine.model_name(); match engine.generate(prompt, max_tokens).await { Ok(result) => { + let tokens_sec = (result.tokens_per_sec * 10.0).round() / 10.0; tracing::info!( "✓ {} | {} tok | {:.0}ms | {:.1} tok/s", model_name, result.tokens_generated, result.duration_ms, - result.tokens_per_sec, + tokens_sec, ); + { + let mut st = tui_state.write().await; + st.tasks_completed += 1; + st.last_tokens_sec = tokens_sec as f64; + st.cur_task_id = None; + st.cur_prompt = None; + + let msg_type = if task_id == "status-check" { "Ping" } else { "Task" }; + let msg_text = format!("{} ({} tok)", task_id, result.tokens_generated); + st.push_log(msg_type, msg_text, Some(tokens_sec as f64)); + } let prompt_short: String = prompt.lines().last().unwrap_or("").chars().take(100).collect(); let done = json!({ "type": "llm_done", @@ -426,7 +513,7 @@ async fn main() { "response": result.text, "tokens_generated": result.tokens_generated, "duration_ms": result.duration_ms, - "tokens_per_sec": (result.tokens_per_sec * 10.0).round() / 10.0, + "tokens_per_sec": tokens_sec, "load_time_ms": 0, "task_id": task_id, }); @@ -434,6 +521,12 @@ async fn main() { } Err(e) => { tracing::error!("Inferenssivirhe: {}", e); + { + let mut st = tui_state.write().await; + st.cur_task_id = None; + st.cur_prompt = None; + st.push_log("System", format!("Virhe inferenssissä: {}", e), None); + } } } } @@ -449,7 +542,12 @@ async fn main() { tracing::info!("Vaihdetaan malli: {}", new_model); engine.set_model(new_model.to_string()); match engine.ensure_model().await { - Ok(()) => tracing::info!("Malli {} valmis!", new_model), + Ok(()) => { + tracing::info!("Malli {} valmis!", new_model); + let mut st = tui_state.write().await; + st.model_name = new_model.to_string(); + st.push_log("System", format!("Malli {} ladattu & valmis!", new_model), None); + } Err(e) => tracing::error!("Mallin lataus epäonnistui: {}", e), } } diff --git a/network-poc/native-node/src/tui_dashboard.rs b/network-poc/native-node/src/tui_dashboard.rs new file mode 100644 index 0000000..a9b251d --- /dev/null +++ b/network-poc/native-node/src/tui_dashboard.rs @@ -0,0 +1,223 @@ +use crossterm::{ + event::{self, Event, EventStream, KeyCode}, + execute, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, +}; +use ratatui::{ + backend::CrosstermBackend, + layout::{Constraint, Direction, Layout, Alignment}, + style::{Color, Modifier, Style}, + widgets::{Block, Borders, Paragraph, Wrap}, + Terminal, +}; +use std::io; +use tokio::sync::RwLock; +use std::sync::Arc; +use futures_util::StreamExt; +use std::time::Duration; + +#[derive(Clone)] +pub struct LogEntry { + pub ty: String, + pub msg: String, + pub speed: Option, +} + +pub struct DashboardState { + pub logs: Vec, + pub status: String, + pub node_id: Option, + pub sys_info: String, + pub model_name: String, + pub cur_task_id: Option, + pub cur_prompt: Option, + pub tasks_completed: u32, + pub last_tokens_sec: f64, + pub network_active_nodes: usize, + pub network_total_tasks: u64, +} + +impl DashboardState { + pub fn new() -> Self { + Self { + logs: Vec::new(), + status: "ACTIVE".to_string(), + node_id: None, + sys_info: "".to_string(), + model_name: "Yhdistetään...".to_string(), + cur_task_id: None, + cur_prompt: None, + tasks_completed: 0, + last_tokens_sec: 0.0, + network_active_nodes: 1, // oletetaan itsemme + network_total_tasks: 0, + } + } + + pub fn push_log(&mut self, ty: &str, msg: String, speed: Option) { + self.logs.push(LogEntry { + ty: ty.to_string(), + msg, + speed, + }); + if self.logs.len() > 100 { + self.logs.remove(0); + } + } +} + +pub async fn run_dashboard( + state: Arc>, + cmd_tx: tokio::sync::mpsc::UnboundedSender, +) -> Result<(), io::Error> { + enable_raw_mode()?; + let mut stdout = io::stdout(); + execute!(stdout, EnterAlternateScreen)?; + let backend = CrosstermBackend::new(stdout); + let mut terminal = Terminal::new(backend)?; + terminal.clear()?; + + let mut reader = EventStream::new(); + let mut interval = tokio::time::interval(Duration::from_millis(100)); + + loop { + tokio::select! { + _ = interval.tick() => { + let st = state.read().await; + terminal.draw(|f| ui(f, &st))?; + } + ev = reader.next() => { + if let Some(Ok(Event::Key(key))) = ev { + match key.code { + KeyCode::Char('q') | KeyCode::Esc => { + // Palautetaan näyttö ja suljetaan ohjelma + disable_raw_mode()?; + execute!(terminal.backend_mut(), LeaveAlternateScreen)?; + std::process::exit(0); + } + KeyCode::Char('p') | KeyCode::Char('P') => { + let _ = cmd_tx.send("pause".to_string()); + } + KeyCode::Char('r') | KeyCode::Char('R') | KeyCode::Char('s') => { + let _ = cmd_tx.send("resume".to_string()); + } + _ => {} + } + } + } + } + } +} + +pub fn restore_terminal() { + let _ = disable_raw_mode(); + let _ = execute!(io::stdout(), LeaveAlternateScreen); +} + +fn ui(f: &mut ratatui::Frame, st: &DashboardState) { + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(3), // Header + Constraint::Min(0), // Body + Constraint::Length(3), // Footer / Status + ].as_ref()) + .split(f.area()); + + // --- Header --- + let header_text = match st.node_id { + Some(id) => format!(" Kipinä Agentic Node #{} ", id), + None => " Kipinä Agentic Node (Yhdistää...) ".to_string(), + }; + let header = Paragraph::new(header_text) + .style(Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD)) + .alignment(Alignment::Center) + .block(Block::default().borders(Borders::ALL).style(Style::default().fg(Color::DarkGray))); + f.render_widget(header, chunks[0]); + + // --- Body --- + let body_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(7), // Yläosan info ja tehtävä + Constraint::Min(0), // Lokit / Chat alas + ].as_ref()) + .split(chunks[1]); + + let top_panels = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(40), // Vasen paneeli (Info) + Constraint::Percentage(60), // Oikea paneeli (Tehtävä) + ].as_ref()) + .split(body_chunks[0]); + + // Vasen paneeli: Laitteisto, Malli & Verkosto + let info_text = format!( + "🚀 Malli: {}\n💻 Järjestelmä: {}\n📊 Tehdyt: {} | Nopeus: {} t/s\n🌐 Verkosto: {} solmua | {} tehtävää", + st.model_name, st.sys_info, st.tasks_completed, st.last_tokens_sec, st.network_active_nodes, st.network_total_tasks + ); + let left_panel = Paragraph::new(info_text) + .block(Block::default().title(" Laitteisto ja AI ").borders(Borders::ALL)) + .style(Style::default().fg(Color::White)) + .wrap(Wrap { trim: true }); + f.render_widget(left_panel, top_panels[0]); + + // Oikea paneeli: Käynnissä oleva tehtävä + let task_title = match &st.cur_task_id { + Some(id) => format!(" Työn alla: {} ", id), + None => " Vapaana ".to_string(), + }; + let task_content = st.cur_prompt.clone().unwrap_or_else(|| "Odotetaan tehtäviä Hubilta...".to_string()); + + let task_style = if st.cur_task_id.is_some() { + Style::default().fg(Color::Magenta) + } else { + Style::default().fg(Color::DarkGray) + }; + + let task_panel = Paragraph::new(task_content) + .wrap(Wrap { trim: true }) + .block(Block::default().title(task_title).borders(Borders::ALL).style(task_style)); + f.render_widget(task_panel, top_panels[1]); + + // Alaosan paneeli: Tapahtumaloki koko leveydeltä + let area_height = body_chunks[1].height.saturating_sub(2) as usize; + let skip_count = if st.logs.len() > area_height { st.logs.len() - area_height } else { 0 }; + + let visible_logs: Vec = st.logs.iter().skip(skip_count).map(|log| { + let ty_color = match log.ty.as_str() { + "System" => Color::Yellow, + "Network" => Color::Blue, + "Task" => Color::Magenta, + "Ping" => Color::DarkGray, + _ => Color::White, + }; + + let speed_str = if let Some(s) = log.speed { + format!(" | {:.1} tok/s", s) + } else { + "".to_string() + }; + + ratatui::text::Line::from(vec![ + ratatui::text::Span::styled(format!("{: <8}", log.ty), Style::default().fg(ty_color).add_modifier(Modifier::BOLD)), + ratatui::text::Span::raw(" | "), + ratatui::text::Span::styled(log.msg.clone(), Style::default().fg(Color::White)), + ratatui::text::Span::styled(speed_str, Style::default().fg(ty_color)), + ]) + }).collect(); + + let logs_panel = Paragraph::new(visible_logs) + .block(Block::default().title(" Tapahtumaloki ").borders(Borders::ALL).style(Style::default().fg(Color::Cyan))); + f.render_widget(logs_panel, body_chunks[1]); + + // --- Footer / Status --- + let status_color = if st.status == "ACTIVE" { Color::Green } else { Color::Yellow }; + let status_text = format!(" Tila: {} | Komennot: [P] Pause / [R] Työhön / [Q] Sulje ", st.status); + let footer = Paragraph::new(status_text) + .style(Style::default().fg(status_color).add_modifier(Modifier::BOLD)) + .alignment(Alignment::Center) + .block(Block::default().borders(Borders::ALL)); + f.render_widget(footer, chunks[2]); +} diff --git a/network-poc/nodes.db b/network-poc/nodes.db index d71206e..8a24237 100644 Binary files a/network-poc/nodes.db and b/network-poc/nodes.db differ diff --git a/network-poc/start-local.sh b/network-poc/start-local.sh new file mode 100755 index 0000000..1c5e624 --- /dev/null +++ b/network-poc/start-local.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Kipinä Agentic Network lokaali pikatesti +# Tämä ohjelma käynnistää lokaalin Kipinä Hubin taustalle, ja heittää sen jälkeen näkyviin +# visuaalisen Natiivisolmun Ratatui-ruudun yhdistäen sen automaattisesti siihen. +# Kun poistut Ratatui-näytöstä (esim painamalla Q), niin skripti sammuttaa siististi +# myös taustalla pyörivän lokaalin Hubin! + +cd "$(dirname "$0")" + +echo "=========================================" +echo " 🔥 Kipinä Agentic Network - Local Run 🔥" +echo "=========================================" +echo "Varmistetaan portin 3000 vapaus..." +lsof -ti :3000 | xargs kill -9 2>/dev/null || true + +echo "" +echo "Käynnistetään Kipinä Hub taustalle..." +# Ohjataan Hubin logit erilliseen tiedostoon jottei se sotke näkymää! +env STATIC_DIR=frontend/dist cargo run -p hub > hub-local.log 2>&1 & +HUB_PID=$! + +# Odotellaan, että Hub saa portit kuunteluun +sleep 2 + +echo "Käynnistetään Natiivisolmu ja Ratatui-dashboard..." +# Käynnistetään TUI ja pakotetaan yhdistämään lokaaliin Hubiin. +env -u OLLAMA_MODEL HUB_URL=ws://127.0.0.1:3000/ws cargo run -p native-node + +# Kun TUI ohjelmasta on poistuttu +echo "" +echo "Dashboard suljettu! Ajetaan lokaali Hub (#$HUB_PID) siististi alas..." +kill $HUB_PID +echo "Kaikki sammutettu. Kiitos!"