← Vissza a főoldalra

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.

Docker Compose FastAPI LangChain · FAISS Three.js · WebSocket Ollama · Qwen 2.5 Nginx Proxy Manager

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.

A

AI Code Linter

C/C++ beágyazott kód elemzése, magyarázata és unit teszt generálás LLM-mel.

R

Datasheet AI (RAG)

PDF adatlapok vektorizálása FAISS-szal, majd kontextushű kérdezés.

3D

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.

ℹ️
Előfeltétel. A rendszer működéséhez az Ollama futnia kell a gazdagépen a szükséges modellekkel (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.

graph LR U["🌐 Böngésző"] -->|"HTTPS 443"| NPM["Nginx Proxy Manager
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ásKonténerHost portBelső portSzerep
webmajerimre_web808080Statikus HTML/JS kiszolgálás (Nginx)
apimajerimre_api80018000AI Code Linter (FastAPI)
api_ragmajerimre_api_rag80028000Datasheet RAG (FastAPI + LangChain)
api_3d ÚJmajerimre_api_3d80038000Digital Twin szimuláció + AI vezérlés
api_scope ÚJmajerimre_api_scope80048000AI 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
💡
Miért közös hálózat? A 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.

ÚtvonalCélSzolgáltatásMegjegyzés
/:8080webStatikus felületek (alapértelmezett)
/analyze:8001apiKód-elemzés
/upload, /chat:8002api_ragPDF feltöltés & RAG chat
/cmd ÚJ:8003api_3dAI vezérlőparancs (HTTP POST)
/ws ÚJ:8003api_3dWebSocket — igényli az upgrade fejléceket
/scope/ ÚJ:8004api_scopeEgy 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;
}
⚠️
HTTPS & WebSocket. A proxy mögött, HTTPS oldalon a böngészőnek 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 ./html mappa a /usr/share/nginx/html alá, az ./others pedig a …/others alá 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

  1. A felhasználó a CodeLinter.html felületen beilleszt egy kódrészletet és kiválaszt egy feladatot (memória-audit, unit teszt, magyarázat).
  2. A böngésző POST /analyze kérést küld.
  3. A backend összeállít egy „senior beágyazott mérnök” rendszerpromptot, és elküldi az Ollamának.
  4. A qwen2.5:1.5b modell 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)}
🔌
host.docker.internal — speciális DNS-név, amely a konténerből a gazdagép hálózati interfészére mutat; a :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

  1. Feltöltés & indexelés: a PDF-et darabokra (chunks) bontja, a nomic-embed-text modellel vektorokká alakítja, és egy FAISS adatbázisba menti a vector_store mappába.
  2. 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.5b modellnek.

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"]}
💾
Perzisztencia. A 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ételStátusz3D szín
temperature > 90OverheatingPiros
rpm > 2000High RPM WarningNarancs
rpm < 500Stall RiskPiros
egyébkéntNominalZö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.
🛠️
Megbízhatóság. A szimulátor clamp-eli az értékeket a fizikai határok közé, a broadcast pedig kiszűri a váratlanul lecsatlakozott klienseket, így egyetlen megszakadt kapcsolat sem állítja meg a sugárzást.

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> }).

sequenceDiagram autonumber participant U as Felhasználó participant F as Simulation.html participant A as api_3d /cmd participant O as Ollama participant W as WebSocket kliensek U->>F: "Lassíts 800 RPM-re" F->>A: POST /cmd { command } A->>O: prompt + állapot (format=json) O-->>A: { response, action: set_rpm 800 } A->>A: rpm = 800 (clamp + státusz) A-->>W: broadcast új állapot A-->>F: { response } F-->>U: AI válasz + 3D modell reagál

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;
🔁
Öngyógyító kapcsolat. Ha a WebSocket megszakad, a kliens automatikusan újracsatlakozik, és a szerver a csatlakozás pillanatában rögtön elküldi az aktuális állapotot — nincs üres képernyő.

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.

🧭
Névtér. Minden végpont a /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:

HibaHatásTipikus ok
Ringingcsillapodó lengés az élekenhiányzó lezárás / impedanciaeltérés
Glitchvéletlen tüskékEMI / laza érintkezés
Clippinglevágott csúcsoktelítés / tápfeszültség-korlát
50 Hz Humhálózati zúgásföldhurok / rossz árnyékolás
Dropoutjel-kimaradásszakadó 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.

BuszVonalakDemó
I²CSCL, SDABME280 hőmérséklet-regiszter olvasás
SPICS, CLK, MOSI, MISOszenzor-regiszter olvasás (mode 0)
UARTTX (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.
🎬
Bemutató egy kattintással. A „Start Guided Tour” gomb automatikusan végigveszi a jeleket, a hibákat (élő AI-diagnózissal) és a busz-dekódolást — nem kell semmit beállítani.

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 a dark-mode osztá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 / #38bdf8 alaphangokra é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');
});
🎨
Egységes élmény. Mivel a kulcs (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.

ModellSzerepHasználó szolgáltatás
qwen2.5:1.5bKód-elemzés, RAG válasz, AI vezérlés, jel/busz-diagnózisapi, api_rag, api_3d, api_scope
nomic-embed-textSzö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
🔁
Proxy újratöltése. Miután először hozzáadtad a 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őoldalhttps://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ódusVégpontPortKérés törzseLeírás
POST/analyze8001{ code_snippet, task_type }Kódrészlet elemzése
POST/upload8002multipart/form-data (file)PDF feltöltés & vektorizálás
POST/chat8002{ question }RAG kérdés a dokumentumhoz
GET/8003Állapot / health check
WS/ws8003Valós idejű telemetria-folyam
POST/cmd8003{ command }Természetes nyelvű AI vezérlőparancs
WS/scope/ws8004Élő jel-/telemetria-folyam
POST/scope/preset8004{ name }Demó betöltése (jel / hiba / busz)
POST/scope/analyze8004AI jel-diagnózis / busz-magyarázat
GET/scope/health8004Á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ünetValószínű okMegoldá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.
🔍
Gyors diagnosztika. Az api_3d a GET / végponton visszaadja az aktuális állapotot — WebSocket nélkül is ellenőrizheted, hogy a szimulátor fut-e.