J.A.R.V.I.S.
Architektura systému
Node.js + Express na VPS Hetzner. Komunikuje s Claude API, Firebase, ElevenLabs a Resend. Běží pod PM2 jako daemon.
Čistý HTML/CSS/JS — žádné frameworky. Dva soubory: index.html (desktop) a mobile.html (mobil).
Claude Sonnet 4 přes Anthropic API. Dynamické tokeny: 200 (chat) / 600 (detail) / 800 (vyhledávání).
Firebase Firestore — osobní paměť, záznamy, konverzace, nastavení. Admin SDK — bezpečné přes service account.
Jak JARVIS funguje
Uživatel napíše nebo řekne zprávu → Frontend ji pošle na backend přes API → Backend zavolá Claude s celým kontextem (paměť, záznamy, nastavení, shrnutí konverzací) → Claude odpoví + přidá ACTION bloky → Backend zpracuje akce (ulož, pošli email, schůzka...) → Frontend zobrazí text a přehraje hlas přes ElevenLabs.
Aktuální stav
Služby a přístupy
| Služba | K čemu | URL | Přihlášení | Stav |
|---|---|---|---|---|
| Hetzner VPS | Server kde běží JARVIS backend | hetzner.com | tony.patka@gmail.com | OK |
| Namecheap | Doména jarvisconnect.world (do 4/2027) | namecheap.com | účet tonypatka | OK |
| Firebase | Databáze — paměť, záznamy, konverzace | firebase.google.com | Google účet, projekt: jarvis-ce3c2 | OK |
| Anthropic | Claude AI — mozek JARVISe | console.anthropic.com | tony.patka@gmail.com | OK |
| ElevenLabs | Hlas JARVISe (TTS) | elevenlabs.io | tony.patka@gmail.com | KREDITY VYČERPÁNY — obnoví se v 5/2026 |
| Resend | Email notifikace, remindery, schůzky | resend.com | tony.patka@gmail.com | DOMÉNA NEOVĚŘENA |
API klíče na serveru
Uloženy v souboru /opt/jarvis/backend/.env
API_KEY=... # JARVIS přístupový klíč (x-api-key header)
FIREBASE_PROJECT_ID=jarvis-ce3c2
FIREBASE_KEY_PATH=/opt/jarvis/backend/firebase-key.json
ELEVENLABS_API_KEY=...
ELEVENLABS_VOICE_ID=R333ZGt1Xqpc9p73wpC1
RESEND_API_KEY=...
GMAIL_USER=tony.patka@gmail.com
PORT=3000
NODE_ENV=production
URL adresy
| Co | URL | Poznámka |
|---|---|---|
| Desktop verze | https://jarvisconnect.world | Hlavní chat rozhraní |
| Mobilní verze | https://jarvisconnect.world/mobile.html | Optimalizováno pro telefon |
| Health check | https://jarvisconnect.world/health | Ověření že server běží |
| Firebase konzole | console.firebase.google.com/project/jarvis-ce3c2 | Data, pravidla, indexy |
| Hetzner konzole | console.hetzner.cloud | Server správa, restart, konzole |
Přihlášení do JARVISe
Na přihlašovací obrazovce zadej x-api-key — to je ochranný klíč uložený v .env souboru. Není to heslo od žádné služby.
VPS Server
| IP adresa | 178.104.115.23 |
| Typ | CX22 — 2 vCPU, 4GB RAM, 80GB disk |
| OS | Ubuntu 24.04 LTS |
| Lokalita | Nuremberg, eu-central |
| Cena | ~10€/měsíc |
ssh root@178.104.115.23
SSH klíč: C:\Users\antonin.patka\.ssh\id_ed25519
BAT soubor pro rychlé přihlášení: jarvis_ssh.bat na ploše
PM2 — správa procesů
pm2 status # stav JARVISe pm2 restart jarvis # restart po nahrání nového kódu pm2 logs jarvis --lines 20 --nostream # zobrazit logy pm2 logs jarvis # živé logy (Ctrl+C pro ukončení)
Restart serveru
Pokud server nereaguje — Hetzner konzole → klikni na server → záložka Power → Power cycle (ne Power off!).
SCP — nahrávání souborů na server
Spouštět z lokálního PowerShellu (NE ze SSH session!):
# Stažení ze serveru (přidej _SERVER do názvu) scp root@178.104.115.23:/opt/jarvis/backend/core/agent.js "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\agent_SERVER.js" # Nahrání na server scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\agent.js" root@178.104.115.23:/opt/jarvis/backend/core/agent.js # Po nahrání vždy restartovat pm2 restart jarvis
Struktura souborů
├── backend/
│ ├── index.js # Express server, schedulery, TTS endpoint, /api/meeting
│ ├── .env # API klíče — NIKDY do kódu!
│ ├── firebase-key.json # Firebase service account
│ ├── package.json
│ ├── core/
│ │ ├── agent.js # Claude API, system prompt, ACTION parser
│ │ ├── memory.js # Firebase CRUD — paměť, záznamy, konverzace
│ │ ├── tts.js # ElevenLabs TTS, preprocessing textu
│ │ ├── email.js # Resend API — sendReminder, sendMeeting (ICS)
│ │ ├── firebase.js # Firebase Admin SDK inicializace
│ │ └── auth.js # x-api-key middleware
│ └── routes/
│ ├── chat.js # /api/chat — hlavní endpoint, zpracování akcí
│ ├── memory.js # /api/memory, /api/records
│ └── settings.js # /api/settings
└── frontend/
├── index.html # Desktop rozhraní
└── mobile.html # Mobilní rozhraní
Lokální složka na PC
├── agent.js # upravenou verzi nahraješ na server
├── agent_SERVER.js # stažená verze ze serveru (pro čtení)
├── chat.js / chat_SERVER.js
├── index.js / index_SERVER.js
├── index.html / index_SERVER.html
├── mobile.html / mobile_SERVER.html
├── tts.js / tts_SERVER.js
├── email.js / email_SERVER.js
└── memory.js / memory_SERVER.js
_SERVER pro čtení. Upravené soubory se nahrávají bez suffixu.
Verze souborů
# Zobrazit všechny verze najednou echo "=== VERZE ===" && \ head -1 /opt/jarvis/backend/index.js && \ head -1 /opt/jarvis/backend/core/agent.js && \ head -1 /opt/jarvis/backend/core/memory.js && \ head -1 /opt/jarvis/backend/core/tts.js && \ head -1 /opt/jarvis/backend/core/email.js && \ head -1 /opt/jarvis/backend/routes/chat.js && \ head -1 /opt/jarvis/frontend/index.html && \ head -1 /opt/jarvis/frontend/mobile.html
Aktuální verze
Příkazy
SSH přihlášení
ssh root@178.104.115.23
PM2 správa
pm2 status pm2 restart jarvis pm2 logs jarvis --lines 20 --nostream pm2 logs jarvis
SCP — stažení ze serveru
scp root@178.104.115.23:/opt/jarvis/backend/core/agent.js "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\agent_SERVER.js" scp root@178.104.115.23:/opt/jarvis/backend/core/memory.js "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\memory_SERVER.js" scp root@178.104.115.23:/opt/jarvis/backend/core/tts.js "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\tts_SERVER.js" scp root@178.104.115.23:/opt/jarvis/backend/core/email.js "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\email_SERVER.js" scp root@178.104.115.23:/opt/jarvis/backend/routes/chat.js "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\chat_SERVER.js" scp root@178.104.115.23:/opt/jarvis/backend/index.js "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\index_SERVER.js" scp root@178.104.115.23:/opt/jarvis/frontend/index.html "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\index_SERVER.html" scp root@178.104.115.23:/opt/jarvis/frontend/mobile.html "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\mobile_SERVER.html"
SCP — nahrání na server
scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\agent.js" root@178.104.115.23:/opt/jarvis/backend/core/agent.js scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\memory.js" root@178.104.115.23:/opt/jarvis/backend/core/memory.js scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\tts.js" root@178.104.115.23:/opt/jarvis/backend/core/tts.js scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\email.js" root@178.104.115.23:/opt/jarvis/backend/core/email.js scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\chat.js" root@178.104.115.23:/opt/jarvis/backend/routes/chat.js scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\index.js" root@178.104.115.23:/opt/jarvis/backend/index.js scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\index.html" root@178.104.115.23:/opt/jarvis/frontend/index.html scp "C:\Users\antonin.patka\Desktop\J.A.R.V.I.S\Program\mobile.html" root@178.104.115.23:/opt/jarvis/frontend/mobile.html
Firebase — správa dat
# Zobrazit summaries (shrnutí konverzací)
cd /opt/jarvis/backend && node -e "
require('dotenv').config();
const {getDb} = require('./core/firebase');
getDb().collection('users').doc('default').collection('summaries').get().then(function(snap) {
snap.docs.forEach(function(d) { console.log(d.id, '|', d.data().summary); });
process.exit(0);
});
"
# Smazat konkrétní summary
cd /opt/jarvis/backend && node -e "
require('dotenv').config();
const {getDb} = require('./core/firebase');
getDb().collection('users').doc('default').collection('summaries').doc('DOC_ID').delete().then(function() {
console.log('Smazano'); process.exit(0);
});
"
# Zobrazit záznamy
cd /opt/jarvis/backend && node -e "
require('dotenv').config();
const {getDb} = require('./core/firebase');
getDb().collection('users').doc('default').collection('records').get().then(function(snap) {
snap.docs.forEach(function(d) { console.log(d.id, '|', JSON.stringify(d.data()).substring(0, 150)); });
process.exit(0);
});
"
Hlas (TTS)
| Model | eleven_turbo_v2_5 |
| Voice ID | R333ZGt1Xqpc9p73wpC1 |
| Jazyk | cs (čeština) |
| Stability | 0.30 |
| Similarity boost | 0.75 |
| Style | 0.40 |
Před odesláním do ElevenLabs se text automaticky čistí:
✓ Odstraní markdown (**, *, #)
✓ Čísla 0-999 → česká slova
✓ Stupně Celsia → "stupňů Celsia"
✓ % → "percent"
✓ km/h → "kilometrů za hodinu"
✓ Odstraní URL adresy
Aktuální stav
Proč eleven_turbo_v2_5 místo eleven_multilingual_v2?
Původní model eleven_multilingual_v2 způsoboval přepínání do maďarštiny při delších odpovědích. Model eleven_turbo_v2_5 s language_code: 'cs' je stabilnější a spolehlivě mluví česky.
Po obnovení kreditů — zapnout paralelní TTS
V chat.js nahradit:
// VYPNUTO — zapnout po obnovení kreditů
await memory.saveConversation(...);
var audioBuffer = null;
// ZAPNOUT ZPĚT:
var [saveResult, audioBuffer] = await Promise.all([
memory.saveConversation(conversationId, msgs, convTitle, convCategory, userId),
result.reply ? synthesize(result.reply, voiceId).catch(function() { return null; }) : Promise.resolve(null)
]);
Vlastní hlas — Voice Cloning
ElevenLabs nabízí nahrání vlastního hlasu. Instant cloning (1-5 min nahrávky) je zdarma v některých plánech, Professional cloning (30+ min) vyžaduje Creator plán ($22/měsíc). Kredity se stále spotřebovávají bez ohledu na to zda jde o klonovaný hlas.
Paměť a data
Struktura databáze
└── default/
├── settings # nastavení (briefingTime, sarcasm, voice...)
├── personality # osobnostní profil
├── memory/ # osobní paměť (klíč-hodnota)
│ ├── jmeno: "Antonín"
│ └── ...
├── records/ # záznamy (recepty, úkoly, pracovní...)
│ ├── {id}: {category, name, content, reminderDate}
│ └── ...
├── conversations/ # chat historie
│ ├── conv_1234: {messages, title, category}
│ └── briefing_2026-05-05: {messages}
└── summaries/ # shrnutí konverzací (kontext pro AI)
└── conv_1234: {summary, title}
Jak JARVIS ukládá věci
| Co řekneš | Co se stane | Kde se uloží |
|---|---|---|
| "Zapamatuj si že preferuji krátké odpovědi" | ACTION: remember | memory kolekce |
| "Ulož recept na..." | ACTION: save_record | records/Recepty |
| "Smaž úkol Vyzvednout auto" | ACTION: delete_record | smaže z records |
| "Buď více sarkastický" | ACTION: set_setting sarcasm | settings |
| "Připomeň mi zítra v 8" | ACTION: save_record + reminderDate | records + email scheduler |
Firebase security rules
Nastaveno na allow read, write: if false — přístup z internetu zablokován. Backend používá Admin SDK který pravidla obchází — JARVIS funguje normálně.
Ranní briefing
Jak funguje
Briefing se generuje automaticky každé ráno 10 minut před nastaveným časem (výchozí 7:00 → generuje se v 6:50). Výsledek se uloží do Firebase. Při prvním otevření JARVISe se přečte a přehraje.
Nastavení briefingu
Desktop JARVIS → záložka Nastavení → sekce RANNÍ BRIEFING:
| Nastavení | Výchozí hodnota | Popis |
|---|---|---|
| Čas | 07:00 | Kdy se briefing přečte uživateli |
| Lokace | Valašské Meziříčí, Česká republika | Pro počasí a místní zprávy |
| Témata | hlavní zprávy, počasí, doprava | Co briefing obsahuje |
Obsah briefingu
Briefing generuje Claude s web searchem — vyhledá aktuální zprávy a počasí pro nastavenou lokaci. Styl: JARVIS, suchý humor, max 5 vět, žádné odrážky.
Schůzky a emaily
Naplánování schůzky
Řekni JARVISovi: "Naplánuj schůzku s Novákem v pátek v 10:00"
JARVIS pošle email na tony.patka@gmail.com s ICS přílohou. ICS soubor lze importovat do Google Calendar, Outlook nebo jakéhokoli jiného kalendáře.
Název schůzky, datum a čas (Prague timezone), místo (volitelné), popis (volitelné), organizátor: J.A.R.V.I.S. <jarvis@jarvisconnect.world>
Posílání emailu na povel
Řekni: "Pošli email s předmětem Test a textem Ahoj"
Pokud neřekneš adresáta, pošle se na tony.patka@gmail.com.
Automatické remindery
Při uložení záznamu s datem: "Připomeň mi zítra v 8 vyzvednout auto"
Reminder scheduler běží každých 5 minut a kontroluje záznamy s prošlým reminderDate.
jarvisconnect.world stále čeká na DNS ověření. Schůzky fungují (odesílají se), ale remindery mohou mít problémy s doručením.
Historie vývoje
Chyby a řešení
Příčina: Staré summaries v Firebase z debugovacích konverzací obsahovaly zmínku o wake wordu.
Špatné řešení: Přidat zákaz do system promptu — zahlazuje chybu, neopravuje příčinu.
Správné řešení: Smazat problematické summaries z Firebase + opravit summarizer aby wake word nezapisoval do nových shrnutí.
Příčina: markReminderSent hledalo záznam podle name místo ID. Vždy vrátilo prázdný výsledek, takže reminder nikdy nebyl označen jako odeslaný.
Řešení: Opravit na hledání podle document ID + přidat sending flag + interval 5 minut. Plus smazat duplicitní záznamy "Ranní briefing - timing" z Firebase.
Příčina: Model eleven_multilingual_v2 automaticky detekuje jazyk a přepíná — při delších textech nebo zvláštních znacích přepnul do maďarštiny.
Řešení: Přepnout na eleven_turbo_v2_5 s language_code: 'cs'. Agresivní čištění textu před odesláním.
Příčina: AudioContext.decodeAudioData() nedokáže dekódovat neúplný MP3 stream. Vyžaduje kompletní audio soubor.
Špatné řešení: elevenRes.body.pipe(res) — funguje na serveru ale browser to neumí přehrát.
Správné řešení (budoucí): MediaSource API se SourceBuffer — umí zpracovávat audio stream po chunkcích. Složitější implementace.
Příčina: SCP se spouštělo ze SSH session na serveru — server se snažil připojit sám na sebe.
Řešení: SCP vždy spouštět z lokálního PowerShellu na PC, ne ze SSH session.
Příčina: ElevenLabs s češtinou četl anglické slovo "sir" jako české "sýr".
Řešení: Odstraněno ze všech příkladů v system promptu. Zachováno "pane" které funguje správně.
Příčina: Flag briefingPlayedToday byl uložen jen v paměti JavaScriptu — při obnovení stránky se resetoval.
Řešení: localStorage s datem — přežije obnovení stránky i zavření prohlížeče. Obnovení jen druhý den.
Příčina: Paralelní TTS generoval audio při každé odpovědi — i když uživatel neposlouchal. 30 120 kreditů za cca 3 týdny.
Řešení krátkodobé: Vypnout paralelní TTS, šetřit kredity do obnovení v květnu.
Řešení dlouhodobé: Generovat TTS jen na vyžádání (uživatel klikne na přehrát) nebo přejít na levnější alternativu (OpenAI TTS, Kokoro).
Roadmapa
🔴 Akutní
✓ ElevenLabs kredity — obnoví se v květnu 2026, pak zapnout paralelní TTS zpět
✓ Resend doména — dořešit DNS ověření jarvisconnect.world
✓ Scrollování na mobilu — stále nedokončeno
🟡 Sprint 5
| Úkol | Poznámka |
|---|---|
| Google Calendar OAuth2 | Čtení + zápis schůzek přímo do Google Calendar |
| Gmail OAuth2 | Čtení prioritních emailů |
| Předgenerovaný TTS pro briefing | Audio připraveno předem, přehraje se okamžitě |
| Dynamická osobnost z Firebase | JARVIS si pamatuje změny osobnosti mezi sezeními |
🟠 Sprint 6
| Úkol | Poznámka |
|---|---|
| Android app | React Native nebo nativní — hands-free provoz |
| Picovoice wake word | Skutečný "Jarvisi" bez otevřené appky |
| Push notifikace | Nativní app notifikace |
| Streaming TTS | MediaSource API — okamžitý start mluvení |
⚪ Backlog
| Úkol |
|---|
| Logout tlačítko viditelné v desktop UI |
| Outlook integrace |
| Smart home (Home Assistant) |
| RPi hlasová stanice |
| Multi-user / rodina |
| Lokální LLM fallback |
| Speaker recognition |
| PWA ikona na ploše |