Lokális AI Mikroszolgáltatás-rendszer
Docker-alapú mérnöki platform egyetlen Mac Mini gépen, amely több, teljesen lokálisan futó mesterséges intelligencia eszközt tesz elérhetővé — külső felhő nélkül, az adatok elhagyása nélkül.
1 Áttekintés
Négy Docker-szolgáltatás, egy közös hálózat, egy lokális LLM-motor.
A rendszer célja, hogy specializált mérnöki AI-eszközöket kínáljon egy egységes, letisztult webes felületről. Minden AI-következtetés a gazdagépen futó Ollama motorral történik, így nincs külső API-függőség, és az adatok nem hagyják el a gépet. A négy konténer egy közös Docker-hálózaton kommunikál egymással és — a host.docker.internal néven keresztül — a gazdagéppel.
AI Code Linter
C/C++ beágyazott kód elemzése, magyarázata és unit teszt generálás LLM-mel.
Datasheet AI (RAG)
PDF adatlapok vektorizálása FAISS-szal, majd kontextushű kérdezés.
AI Digital Twin ÚJ
Valós idejű 3D motor-szimuláció WebSocketen, természetes nyelvű AI-vezérléssel.
Sötét mód ÚJ
Egységes, alapértelmezetten aktív sötét téma minden oldalon, mentett preferenciával.
qwen2.5:1.5b, nomic-embed-text). Részletek a 9. fejezetben.2 Architektúra és Docker Compose
A publikus forgalom egy Nginx Proxy Manager (NPM) reverse proxyn keresztül érkezik (majerimre.duckdns.org, TLS-terminálással), amely útvonal alapján irányítja a kéréseket a megfelelő háttérszolgáltatáshoz. Minden szolgáltatás a proxy_default külső Docker-hálózaton osztozik.
majerimre.duckdns.org"] NPM -->|"/"| WEB["web · Nginx
:8080 (statikus UI)"] NPM -->|"/analyze"| API["api · Code Linter
:8001"] NPM -->|"/chat · /upload"| RAG["api_rag · RAG
:8002"] NPM -->|"/cmd · /ws"| SIM["api_3d · Digital Twin
:8003"] NPM -->|"/scope/"| SCOPE["api_scope · Oscilloscope
:8004"] API -->|"HTTP"| OLL[("Ollama
host:11434")] RAG -->|"embed + chat"| OLL SIM -->|"/cmd → LLM"| OLL SCOPE -->|"/scope/analyze"| OLL classDef svc fill:#12203c,stroke:#38bdf8,color:#dbe4f3; classDef ext fill:#1b1230,stroke:#818cf8,color:#e9e4ff; class WEB,API,RAG,SIM,SCOPE svc; class NPM,OLL ext;
1. ábra — Kérés-útvonalak a reverse proxytól a szolgáltatásokig és az Ollama motorig.
Szolgáltatások és portok
| Szolgáltatás | Konténer | Host port | Belső port | Szerep |
|---|---|---|---|---|
web | majerimre_web | 8080 | 80 | Statikus HTML/JS kiszolgálás (Nginx) |
api | majerimre_api | 8001 | 8000 | AI Code Linter (FastAPI) |
api_rag | majerimre_api_rag | 8002 | 8000 | Datasheet RAG (FastAPI + LangChain) |
api_3d ÚJ | majerimre_api_3d | 8003 | 8000 | Digital Twin szimuláció + AI vezérlés |
api_scope ÚJ | majerimre_api_scope | 8004 | 8000 | AI oszcilloszkóp: jel + FFT + busz-dekóder |
A teljes docker-compose.yaml
services:
web:
image: nginx:alpine
container_name: majerimre_web
restart: unless-stopped
ports:
- '8080:80'
volumes:
- ./html:/usr/share/nginx/html
- ./others:/usr/share/nginx/html/others
networks:
- proxy_default
api:
build: ./api
container_name: majerimre_api
restart: unless-stopped
ports:
- '8001:8000'
networks:
- proxy_default
api_rag:
build: ./api_rag
container_name: majerimre_api_rag
restart: unless-stopped
ports:
- '8002:8000'
networks:
- proxy_default
api_3d: # ÚJ szolgáltatás
build: ./api_3d
container_name: majerimre_api_3d
restart: unless-stopped
ports:
- '8003:8000'
networks:
- proxy_default
api_scope: # ÚJ szolgáltatás (oszcilloszkóp)
build: ./api_scope
container_name: majerimre_api_scope
restart: unless-stopped
ports:
- '8004:8000'
networks:
- proxy_default
networks:
proxy_default:
external: true
proxy_default hálózat teszi lehetővé, hogy a konténerek — és maga a reverse proxy — konténernév vagy a gazdagép LAN-címe alapján elérjék egymást, valamint a host.docker.internal néven a gazdagépen futó Ollamát.3 Reverse proxy — Nginx Proxy Manager
Az NPM egy külön Docker-stackben fut, és a majerimre.duckdns.org hoszthoz útvonal alapú irányítást végez. Emiatt tudnak a frontend oldalak relatív URL-eket (/analyze, /chat, /cmd …) használni: a böngésző ugyanarra a domainre küld, a proxy pedig a helyes háttérportra továbbít.
| Útvonal | Cél | Szolgáltatás | Megjegyzés |
|---|---|---|---|
/ | :8080 | web | Statikus felületek (alapértelmezett) |
/analyze | :8001 | api | Kód-elemzés |
/upload, /chat | :8002 | api_rag | PDF feltöltés & RAG chat |
/cmd ÚJ | :8003 | api_3d | AI vezérlőparancs (HTTP POST) |
/ws ÚJ | :8003 | api_3d | WebSocket — igényli az upgrade fejléceket |
/scope/ ÚJ | :8004 | api_scope | Egy prefix minden szkóp-végponthoz (WS + HTTP) |
Egyedi konfiguráció a WebSockethez
Az NPM által generált proxy_host/1.conf fájl a szolgáltatás újragenerálásakor felülíródik, ezért az új útvonalak a nem felülírt, egyedi include-fájlba kerülnek:
Proxy/data/nginx/custom/server_proxy.conf
# AI parancs végpont (HTTP POST) -> api_3d
location /cmd {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.68.103:8003;
}
# Valós idejű telemetria (WebSocket) -> api_3d
location /ws {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.68.103:8003;
# A WebSocket "upgrade" kézfogáshoz kötelező:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
# AI oszcilloszkóp — egy prefix visz mindent a 8004-re (WS + HTTP)
location /scope/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.68.103:8004;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
wss://-t kell használnia — a ws:// „mixed content” hibát okoz. A Simulation.html ezt automatikusan kezeli (lásd 7. fejezet).4 A web szolgáltatás (Nginx)
Ez a konténer szolgálja ki a böngészőnek a statikus felületeket. Könnyűsúlyú nginx:alpine image, amely a host 8080-as portját a konténer 80-as portjára képezi le.
- Kötetek (volumes): a helyi
./htmlmappa a/usr/share/nginx/htmlalá, az./otherspedig a…/othersalá csatolódik. Így a HTML-módosítások azonnal látszanak, a konténer újraépítése nélkül. - Kiszolgált oldalak:
index.html(irányítópult),CodeLinter.html,DatasheetAI.html,Simulation.htmlÚJ,Scope.htmlÚJ és a jelen dokumentáció. - Sötét mód: minden oldal ugyanazt a — alapértelmezetten aktív — sötét témát és kapcsolót használja (lásd 9. fejezet).
5 Az api szolgáltatás — AI Code Linter
Egy tömör FastAPI alkalmazás, amely beágyazott (C/C++) kódrészleteket elemez az Ollama LLM-mel.
Működés
- A felhasználó a
CodeLinter.htmlfelületen beilleszt egy kódrészletet és kiválaszt egy feladatot (memória-audit, unit teszt, magyarázat). - A böngésző
POST /analyzekérést küld. - A backend összeállít egy „senior beágyazott mérnök” rendszerpromptot, és elküldi az Ollamának.
- A
qwen2.5:1.5bmodell választ generál, amit a felület megjelenít.
Backend — api/main.py
from fastapi import FastAPI
from pydantic import BaseModel
import requests
app = FastAPI(title="Majer Imre - Helyi AI Asszisztens API")
class CodeRequest(BaseModel):
code_snippet: str
task_type: str
OLLAMA_URL = "http://host.docker.internal:11434/api/generate"
@app.post("/analyze")
def analyze_code(request: CodeRequest):
system_prompt = (
"You are a senior software engineer specializing in embedded systems. "
"ALWAYS generate your final response entirely in English, "
"keep it concise, professional, and technical."
)
payload = {
"model": "qwen2.5:1.5b",
"prompt": f"{system_prompt}\n\nTask: {request.task_type}\nCode:\n{request.code_snippet}",
"stream": False,
}
try:
response = requests.post(OLLAMA_URL, json=payload)
response.raise_for_status()
return {"status": "success", "ai_response": response.json().get("response", "")}
except Exception as e:
return {"status": "error", "message": str(e)}
:11434 az Ollama alapértelmezett portja.6 Az api_rag szolgáltatás — Datasheet AI (RAG)
Egy LangChain-alapú Retrieval-Augmented Generation rendszer: PDF adatlapokat vektorizál, majd a dokumentum kontextusából válaszol.
Működési elv
- Feltöltés & indexelés: a PDF-et darabokra (chunks) bontja, a
nomic-embed-textmodellel vektorokká alakítja, és egyFAISSadatbázisba menti avector_storemappába. - Kérdezés & generálás: a kérdéshez legrelevánsabb darabokat visszakeresi (retriever, k=3), majd a kontextussal együtt átadja a
qwen2.5:1.5bmodellnek.
Backend — api_rag/main.py (kivonat)
embeddings = OllamaEmbeddings(model="nomic-embed-text", base_url=OLLAMA_BASE_URL)
llm = ChatOllama(model="qwen2.5:1.5b", base_url=OLLAMA_BASE_URL)
@app.post("/chat")
def ask_question(request: ChatRequest):
if not os.path.exists(f"{VECTOR_DIR}/index.faiss"):
return {"status": "error", "message": "Please upload a datasheet first!"}
vectorstore = FAISS.load_local(VECTOR_DIR, embeddings, allow_dangerous_deserialization=True)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
prompt = PromptTemplate.from_template(
"You are a senior hardware engineer. Use the retrieved datasheet context "
"to answer. If it is not in the context, say so.\nContext: {context}\nQuestion: {input}"
)
rag_chain = create_retrieval_chain(retriever, create_stuff_documents_chain(llm, prompt))
return {"status": "success", "answer": rag_chain.invoke({"input": request.question})["answer"]}
vector_store mappa megőrzi a vektorizált adatlapot, így az a konténer újraindítása után is elérhető marad.7 Az api_3d szolgáltatás — AI Digital Twin ÚJ
Egy „digitális iker”: a böngészőben futó 3D modellt valós időben egy háttérszimulátor és egy LLM-vezérlő irányítja.
A szolgáltatás egyszerre két szerepet tölt be: (1) szimulátor, amely folyamatosan mérnöki mérőszámokat (fordulatszám, hőmérséklet, feszültség) generál, és (2) AI vezérlő, amely természetes nyelvű parancsokat értelmez, és módosítja a szimuláció állapotát.
7.1 Állapotmodell
Egy globális szótár tartja nyilván az iker aktuális állapotát; a szimulátor és a /cmd végpont is ezt módosítja.
simulation_state = {
"rpm": 1200.0,
"temperature": 45.5,
"voltage": 12.1,
"status": "Nominal",
}
RPM_LIMITS = (0.0, 3000.0) # az értékeket ezek közé szorítjuk (clamp)
TEMP_LIMITS = (20.0, 120.0)
VOLT_LIMITS = (0.0, 24.0)
7.2 Állapot (státusz) logika
| Feltétel | Státusz | 3D szín |
|---|---|---|
temperature > 90 | Overheating | Piros |
rpm > 2000 | High RPM Warning | Narancs |
rpm < 500 | Stall Risk | Piros |
| egyébként | Nominal | Zöld |
7.3 Háttérszimulátor (asyncio)
Egy másodpercenként futó, nem blokkoló feladat kis, véletlenszerű ingadozásokkal „életre kelti” az ikret, majd az új állapotot minden csatlakozott kliensnek elküldi.
async def run_simulator():
while True:
simulation_state["rpm"] = _clamp(
simulation_state["rpm"] + random.uniform(-15, 15), RPM_LIMITS)
simulation_state["temperature"] = _clamp(
simulation_state["temperature"] + random.uniform(-0.3, 0.3), TEMP_LIMITS)
simulation_state["voltage"] = _clamp(
simulation_state["voltage"] + random.uniform(-0.05, 0.05), VOLT_LIMITS)
_recompute_status()
await manager.broadcast_state()
await asyncio.sleep(1)
# A feladatot a FastAPI lifespan-kezelője indítja el induláskor.
7.4 WebSocket — /ws
A kapcsolatkezelő nyilvántartja az aktív klienseket, és minden állapotfrissítést szétküld nekik.
class ConnectionManager:
def __init__(self):
self.active_connections: list[WebSocket] = []
async def connect(self, ws: WebSocket):
await ws.accept()
self.active_connections.append(ws)
async def broadcast_state(self):
message = json.dumps(simulation_state)
for ws in list(self.active_connections):
try:
await ws.send_text(message)
except Exception:
self.disconnect(ws) # elhalt kapcsolat eltávolítása
7.5 AI vezérlő végpont — /cmd
A végpont az aktuális állapotot kontextusként átadja az LLM-nek, amely egyetlen JSON-objektumban ad vissza (1) egy természetes nyelvű response-t a felhasználónak, és (2) egy gépi action-t a szimuláció vezérléséhez.
@app.post("/cmd")
async def process_command(req: CommandRequest):
payload = {
"model": "qwen2.5:1.5b",
"prompt": f"{system_prompt}\n\nUser Command: '{req.command}'",
"format": "json", # strukturált JSON kikényszerítése
"stream": False,
}
response = requests.post(OLLAMA_URL, json=payload, timeout=120)
ai_output = json.loads(response.json().get("response") or "{}")
action = ai_output.get("action")
if isinstance(action, dict):
if action.get("action") == "set_rpm" and action.get("value") is not None:
simulation_state["rpm"] = _clamp(float(action["value"]), RPM_LIMITS)
elif action.get("action") == "set_voltage" and action.get("value") is not None:
simulation_state["voltage"] = _clamp(float(action["value"]), VOLT_LIMITS)
_recompute_status()
await manager.broadcast_state() # azonnali frissítés minden kliensnek
return JSONResponse({"status": "success", "response": ai_output.get("response", "")})
Érvényes AI-akciók: set_rpm, set_voltage, report_status (formátum: { "action": "set_rpm", "value": <szám> }).
2. ábra — Egy vezérlőparancs teljes útja a felhasználótól a 3D modell frissüléséig.
7.6 Frontend — Simulation.html (Three.js)
A felület egy hengerrel jelképezett motort renderel, valós idejű telemetriát mutat, és parancsmezőt kínál. A modell forgási sebessége az RPM-hez, színe a státuszhoz igazodik.
Végpont-feloldás (dev vs. proxy)
Éles környezetben minden azonos eredetű (a proxy irányít); helyi fejlesztéskor, amikor az oldalt közvetlenül a :8080 szolgálja ki, a frontend a :8003 portra csatlakozik (a backend engedélyezi a CORS-t).
function resolveEndpoints() {
if (window.location.host.includes(':8080')) { // helyi fejlesztés
const host = window.location.hostname;
return { http: `http://${host}:8003`, ws: `ws://${host}:8003` };
}
const wsProto = window.location.protocol === 'https:' ? 'wss' : 'ws'; // proxy mögött
return { http: '', ws: `${wsProto}://${window.location.host}` };
}
Telemetria fogadása és 3D frissítés
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
currentRPM = data.rpm;
rpmEl.innerText = data.rpm.toFixed(0);
tempEl.innerText = data.temperature.toFixed(1);
voltEl.innerText = data.voltage.toFixed(1);
statusEl.innerText = data.status;
motor.material.color.set(statusColor(data.status)); // szín a státusz szerint
};
// A render-ciklusban a forgás sebessége az RPM-mel arányos:
motor.rotation.z += currentRPM / 6000;
Függőségek — api_3d/requirements.txt
fastapi
uvicorn[standard]
requests
websockets
8 Az api_scope szolgáltatás — AI Oszcilloszkóp ÚJ
Neon oszcilloszkóp: élő jel-stream, FFT-spektrum, hibainjektálás élő AI-diagnózissal, és I²C/SPI/UART busz-dekódolás.
A szolgáltatás egyszerre műszer (folyamatosan jelmintákat streamel WebSocketen) és AI-diagnoszta (a mérésekből vagy a dekódolt buszból következtet). Az architektúra az api_3d bevált mintáit hasznosítja újra: ConnectionManager, háttér-broadcast loop, lifespan, CORS és az Ollama-hívás.
/scope/ prefix alatt van (/scope/ws, /scope/preset, /scope/analyze …), így a proxynál egyetlen location /scope/ blokk elég, és nincs ütközés az api_3d /ws és /cmd útjaival.8.1 Jelmotor és mérések
Egy háttérfeladat (~20 fps) NumPy-jal állítja elő a csatornák mintáit, kiszámítja a méréseket (Vpp, Vrms, frekvencia, kitöltés) és az FFT-spektrumot, majd egy kompakt keretet küld a böngészőnek.
def synth(ch, t):
f = ch["freq"]; frac = (f * t) % 1.0
if ch["waveform"] == "sine":
y = np.sin(2 * np.pi * f * t)
elif ch["waveform"] in ("square", "pwm"):
y = np.where(frac < ch["duty"], 1.0, -1.0)
elif ch["waveform"] == "composite":
p = 2 * np.pi * f * t
y = (np.sin(p) + 0.5*np.sin(3*p) + 0.3*np.sin(5*p)) / 1.8
# ... triangle / saw / noise ...
return ch["amp"] * y + ch["offset"]
8.2 Hibainjektálás
A hibademók a jelre valósághű zavarokat tesznek — ezekre reagál az AI:
| Hiba | Hatás | Tipikus ok |
|---|---|---|
| Ringing | csillapodó lengés az éleken | hiányzó lezárás / impedanciaeltérés |
| Glitch | véletlen tüskék | EMI / laza érintkezés |
| Clipping | levágott csúcsok | telítés / tápfeszültség-korlát |
| 50 Hz Hum | hálózati zúgás | földhurok / rossz árnyékolás |
| Dropout | jel-kimaradás | szakadó kontaktus |
8.3 Busz-dekóder (I²C / SPI / UART)
Egy ismert byte-sorozatból előáll a digitális vonalak hullámformája és a dekódolt annotációk (START, cím, ACK, adat, STOP), amelyeket az AI is elmagyaráz.
| Busz | Vonalak | Demó |
|---|---|---|
| I²C | SCL, SDA | BME280 hőmérséklet-regiszter olvasás |
| SPI | CS, CLK, MOSI, MISO | szenzor-regiszter olvasás (mode 0) |
| UART | TX (8N1) | „HELLO” @ 9600 baud |
8.4 Kontextusfüggő AI-elemzés — /scope/analyze
Ugyanaz a végpont jel- és busz-módban is működik: jel esetén a mérésekből és az aktív hibákból diagnosztizál, busz esetén a dekódolt tranzakciót magyarázza el.
if scope_state["mode"] == "bus":
user_prompt = f"Decoded transaction: {scope_state['bus']['summary']}"
else:
meas = measurements(y, t)
faults = [k for k, v in scope_state["faults"].items() if v]
user_prompt = (f"Measurements: {json.dumps(meas)}. "
f"Detected anomalies: {faults or 'none'}.")
# ... Ollama qwen2.5:1.5b, ugyanaz a minta, mint az api_3d /cmd ...
8.5 Frontend — Scope.html
Canvas-alapú CRT-oszcilloszkóp foszfor-utánvilágítással, külön FFT-panellel és busz-annotációkkal. A végpont-feloldás ugyanaz, mint az api_3d-nél (helyi :8004 vs. proxy).
- Demó-gombok: jelek, hibák és buszok — mindegyik egy kattintás.
- Vezetett Túra: egy gomb végigpörgeti az összes demót feliratokkal — ideális bemutatóhoz.
- Élő AI: preset/hiba betöltésekor automatikusan lefut a diagnózis.
Végpontok
WS /scope/ws— élő keret-stream (csatornák, mérések, spektrum, vagy busz).POST /scope/preset— demó betöltése (jel / hiba / busz).POST /scope/analyze— AI-diagnózis / busz-magyarázat.POST /scope/config,/scope/fault— kézi vezérlés.GET /scope/health— állapot.
9 Sötét mód ÚJ
Minden oldal ugyanazt a sötét témát és lebegő kapcsolót használja. A sötét mód az alapértelmezett; a felhasználó választása a localStorage-ban tárolódik, és — közös kulcs révén — oldalak között is érvényesül.
- Alapértelmezés: a
<body>már a betöltéskor megkapja adark-modeosztályt (nincs „felvillanó” világos állapot). - Perzisztencia: közös kulcs (
darkMode) minden oldalon; csak explicit „disabled” érték kapcsol világosra. - Következetesség: a színpaletta a
#0b1120/#131c31/#38bdf8alaphangokra épül; a kódblokkok mindkét témában sötétek maradnak.
const body = document.body;
// Sötét az alapértelmezett — csak a kifejezett kikapcsolás vált világosra:
const isDarkMode = localStorage.getItem('darkMode') !== 'disabled';
function applyDarkMode(enable) {
body.classList.toggle('dark-mode', enable);
darkModeToggle.textContent = enable ? 'Light Mode' : 'Dark Mode';
}
applyDarkMode(isDarkMode);
darkModeToggle.addEventListener('click', () => {
const current = body.classList.contains('dark-mode');
applyDarkMode(!current);
localStorage.setItem('darkMode', current ? 'disabled' : 'enabled');
});
darkMode) minden oldalon közös, ha az egyik felületen átváltasz, a beállítás a főoldalon és az összes al-oldalon is megmarad.10 Ollama a gazdagépen
Az összes AI-funkció az Ollama nyílt forráskódú LLM-futtatókörnyezetre épül, amely a gazdagépen (Mac Mini) fut. A konténerek a host.docker.internal:11434 címen érik el.
| Modell | Szerep | Használó szolgáltatás |
|---|---|---|
qwen2.5:1.5b | Kód-elemzés, RAG válasz, AI vezérlés, jel/busz-diagnózis | api, api_rag, api_3d, api_scope |
nomic-embed-text | Szöveg → vektor (embedding) | api_rag |
ollama pull qwen2.5:1.5b
ollama pull nomic-embed-text
11 Telepítés és kezelés
Első indítás
A docker-compose.yaml mellett futtatva:
docker compose up --build -d
--build— felépíti (vagy újraépíti) a szolgáltatások image-eit.-d— háttérben (detached) futtatja a konténereket.
Csak az új szolgáltatás építése/frissítése
# Egy szolgáltatás felépítése és indítása (pl. api_3d vagy api_scope)
docker compose up -d --build api_3d
docker compose up -d --build api_scope
# Naplók követése
docker compose logs -f api_scope
server_proxy.conf egyedi include-ot, töltsd újra / indítsd újra az NPM konténert, hogy a /cmd, /ws és /scope/ útvonalak életbe lépjenek.Leállítás
docker compose down
Hozzáférés a felületekhez
| Felület | Éles (proxy) | Helyi (dev) |
|---|---|---|
| Főoldal | https://majerimre.duckdns.org/ | http://localhost:8080/ |
| AI Code Linter | …/CodeLinter.html | …:8080/CodeLinter.html |
| Datasheet AI | …/DatasheetAI.html | …:8080/DatasheetAI.html |
| Digital Twin ÚJ | …/Simulation.html | …:8080/Simulation.html |
| Oscilloscope Lab ÚJ | …/Scope.html | …:8080/Scope.html |
12 API referencia
| Metódus | Végpont | Port | Kérés törzse | Leírás |
|---|---|---|---|---|
| POST | /analyze | 8001 | { code_snippet, task_type } | Kódrészlet elemzése |
| POST | /upload | 8002 | multipart/form-data (file) | PDF feltöltés & vektorizálás |
| POST | /chat | 8002 | { question } | RAG kérdés a dokumentumhoz |
| GET | / | 8003 | — | Állapot / health check |
| WS | /ws | 8003 | — | Valós idejű telemetria-folyam |
| POST | /cmd | 8003 | { command } | Természetes nyelvű AI vezérlőparancs |
| WS | /scope/ws | 8004 | — | Élő jel-/telemetria-folyam |
| POST | /scope/preset | 8004 | { name } | Demó betöltése (jel / hiba / busz) |
| POST | /scope/analyze | 8004 | — | AI jel-diagnózis / busz-magyarázat |
| GET | /scope/health | 8004 | — | Állapot / health check |
13 Fájlstruktúra
majerimre/
├── docker-compose.yaml # 4 szolgáltatás + proxy_default hálózat
├── api/ # AI Code Linter
│ ├── Dockerfile
│ ├── main.py
│ └── requirements.txt
├── api_rag/ # Datasheet RAG
│ ├── Dockerfile
│ ├── main.py
│ ├── requirements.txt
│ └── vector_store/ # perzisztens FAISS index
├── api_3d/ # Digital Twin ── ÚJ
│ ├── Dockerfile
│ ├── main.py # szimulátor + WebSocket + /cmd
│ └── requirements.txt
├── api_scope/ # AI Oszcilloszkóp ── ÚJ
│ ├── Dockerfile
│ ├── main.py # jelmotor + FFT + busz-dekóder + /scope/*
│ └── requirements.txt # (numpy is)
├── html/
│ ├── index.html # irányítópult (sötét mód)
│ ├── CodeLinter.html
│ ├── DatasheetAI.html
│ ├── Simulation.html # 3D iker felület ── ÚJ
│ ├── Scope.html # oszcilloszkóp felület ── ÚJ
│ ├── documentation.html # ← EZ A FÁJL
│ └── others/
│ └── BME280_Datasheet.pdf
└── others/
└── Dokumentacio.md
Proxy/ # Nginx Proxy Manager (külön stack)
└── data/nginx/custom/
└── server_proxy.conf # /cmd, /ws és /scope/ útválasztás ── ÚJ
14 Hibaelhárítás
| Tünet | Valószínű ok | Megoldás |
|---|---|---|
| A 3D nézet nem frissül, nincs telemetria | WebSocket nem jön létre | Ellenőrizd, hogy fut-e az api_3d (docker ps), és a proxyban a /ws az upgrade fejlécekkel van beállítva. |
| „Could not reach AI service” | Ollama nem elérhető vagy hiányzik a modell | Indítsd az Ollamát, és futtasd: ollama pull qwen2.5:1.5b. |
| Mixed-content hiba a WebSocketnél | HTTPS oldalon ws:// használat |
A proxy mögött a frontend automatikusan wss://-t használ — éles címről (nem :8080) nyisd meg. |
| CORS hiba helyi fejlesztésnél | Közvetlen :8003 elérés más eredetről |
Az api_3d engedélyezi a CORS-t; győződj meg róla, hogy az új image fut (--build). |
| „Please upload a datasheet first!” | Nincs FAISS index | Tölts fel egy PDF-et a Datasheet AI felületen a kérdezés előtt. |
| A szkóp nem rajzol / nincs jel | A /scope/ nincs átvezetve, vagy nem fut az api_scope |
Ellenőrizd a proxy /scope/ blokkját (upgrade fejlécek) és a curl http://localhost:8004/scope/health választ. |
| Port ütközés induláskor | 8001–8004 vagy 8080 foglalt | Szabadítsd fel a portot, vagy módosítsd a leképezést a docker-compose.yaml-ban. |
api_3d a GET / végponton visszaadja az aktuális állapotot — WebSocket nélkül is ellenőrizheted, hogy a szimulátor fut-e.