# MVP Automation Platform


## AI Cost Tracking

![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.0.40-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
![AI Cost](https://img.shields.io/badge/AI%20Cost-$14.09-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-24.5h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)

- 🤖 **LLM usage:** $14.0885 (48 commits)
- 👤 **Human dev:** ~$2446 (24.5h @ $100/h, 30min dedup)

Generated on 2026-06-06 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)

---

> System kompilujący intencje biznesowe (język naturalny) do wykonywalnych procesów w kontenerach Docker — z konwersacyjnym AI i dynamicznym UI.

## Architektura

```
Użytkownik (tekst / głos / GUI)
        │
        ▼
┌──────────────────────────┐
│   NLP Service            │
│  ├─ Parser (rules/LLM)   │  ← rozumie język naturalny
│  ├─ Mapper (determ.)     │  ← buduje DSL
│  ├─ Orchestrator         │  ← conversation loop
│  └─ Schema generator     │  ← dynamic UI forms
└──────────┬───────────────┘
           ▼
┌──────────────────┐     ┌──────────────┐
│     Backend      │────▶│    Worker    │
│  (API Gateway)   │     │  (Executors) │
│  DSL Engine      │     └──────────────┘
└──────┬───────────┘
       │
  ┌────┴────┐
  │ Postgres│
  └─────────┘
```

**Zasada:** LLM rozumie → Pydantic waliduje → Mapper buduje → Docker wykonuje

## Integracja z nlp2cmd

Repozytorium zawiera dwa poziomy:

| Warstwa | Lokalizacja | Rola |
|---------|-------------|------|
| **Platforma MVP** | `backend/`, `nlp-service/`, `worker/` | Workflow DSL (faktury, e-mail, raporty) w Docker |
| **SDK (wydzielone)** | `packages/dsl-*`, `nlp2dsl-*`, `workflow-export`, `testql-conversations` | Kontrakty, walidacja, artefakty, eksport markpact/pactown |
| **Mapa środowiska** | [`env2llm`](../../semcod/env2llm) (semcod) | `environment.doql.less`, `SystemMapIR`, registry |
| **Pakiety IR** | `packages/pact-ir`, `nlp2cmd-*` | IntentIR / ExecutionPlanIR — wspólny język z nlp2cmd i Propact |

### Podział odpowiedzialności

| Narzędzie | Zadanie |
|-----------|---------|
| **`nlp2dsl show "query"`** | Struktura zapytania (IntentIR) — **bez wykonania** |
| **`nlp2cmd plan "query"`** | Plan → Propact markdown; `--execute` → hybrid executor (Propact + nlp2cmd) |
| **`nlp2cmd -q "query" -r`** | Legacy runtime nlp2cmd (shell / browser / canvas) |
| **`examples/*/scenario.py`** | Demo platformy MVP (wymaga `docker compose up`; `main.py` = punkt wejścia) |

### Instalacja pakietów (dev)

```bash
./scripts/setup-dev.sh          # pakiety IR + SDK + nlp2cmd[integration]
# lub tylko pakiety:
./packages/install-dev.sh

export NLP2CMD_INTEGRATION=1
```

```bash
nlp2dsl show "znajdz pliki *.py w src"               # IntentIR JSON
nlp2cmd plan "znajdz pliki *.py w src"               # Propact markdown
nlp2cmd plan "znajdz pliki *.py w src" --explain     # + execution_route
nlp2cmd plan "znajdz pliki *.py w src" --execute     # hybrid executor
NLP2CMD_SHOW_STRUCTURE=1 nlp2cmd -q "query"          # analiza na wejściu nlp2cmd
```

Szczegóły: [`packages/README.md`](packages/README.md) · walidacja kontraktów: [`docs/intract-integration.md`](docs/intract-integration.md) · walidacja requestu: [`docs/validation.md`](docs/validation.md)

### Architektura pakietów IR

```mermaid
flowchart LR
    Q[NL query] --> SHOW[nlp2dsl show]
    Q --> PLAN[nlp2cmd plan]

    subgraph pkgs [packages/]
        IR[IntentIR]
        EPIR[ExecutionPlanIR]
    end

    SHOW --> IR
    SHOW --> EPIR
    PLAN --> IR --> EPIR --> MD[Propact markdown]

    EPIR -.->|NLP2CMD_INTRACT_GATE| GATE[PlanStepGate w nlp2cmd]
```

| Narzędzie | Walidacja struktury | Kontrakty Intract |
|-----------|--------------------|--------------------|
| `nlp2dsl show` | Pydantic + confidence | opcjonalnie `--plan` + `INTRACT_GATE` |
| `nlp2cmd plan` | `needs_clarification` zawsze | opcjonalnie `INTRACT_GATE` |
| `nlp2cmd -q -r` | ActionRegistry (legacy) | opcjonalnie `INTRACT_GATE` |

### Kodowanie UTF-8 (polskie znaki)

**Nie wymaga ręcznej konfiguracji.** Import `nlp2dsl_sdk` oraz CLI (`nlp2dsl`, `nlp2dsl-demo`, `nlp2dsl-show`) automatycznie ustawiają stdio i locale na UTF-8 (naprawia m.in. `znajd?` → `znajdź`).

Szczegóły: [`docs/encoding.md`](docs/encoding.md)

Wyłączenie: `NLP2DSL_UTF8=0`

### Artefakty przykładów (NLP → DSL → CMD → process)

`examples/NN-name/.nlp2dsl/` — DOQL env (`env2llm`), manifest/pipeline/process (`nlp2dsl-artifacts`), TestQL (`testql-conversations`).

| Pakiet | Pliki |
|--------|-------|
| `env2llm` | `registry/environment.doql.less` |
| `nlp2dsl-artifacts` | `manifest.yaml`, `pipeline/`, `process/`, `commands.testql.toon.yaml` |
| `workflow-export` | `generated/markpact/`, `generated/pactown/` (examples 03, 04, 14) |
| `nlp2dsl-stack` | `generated/docker-compose.stack.yaml`, cron (example 13) |

Generowanie: `bash examples/run-all.sh` · docs: [`docs/artifacts.md`](docs/artifacts.md) · pakiety: [`packages/README.md`](packages/README.md)

## Szybki start

```bash
git clone <repo-url> && cd nlp2dsl
cp .env.example .env
# Uzupełnij klucze API (opcjonalne - system działa z parserem reguł)
docker compose up --build
# Poczekaj na health (SDK robi to automatycznie w przykładach):
curl -s http://localhost:8010/health && curl -s http://localhost:8012/health && curl -s http://localhost:8004/health
```

| Serwis | URL | Opis |
|--------|-----|------|
| Backend API | http://localhost:8010/docs | Gateway + workflow engine |
| NLP Service | http://localhost:8012/docs | NLP + conversation + schema |
| Worker | http://localhost:8004/docs | Executory akcji |

> Port **8012** (nie 8002) — 8002 bywa zajęty przez Mullm Projector. Zmienne: `NLP2DSL_BACKEND_HOST_PORT`, `NLP2DSL_NLP_HOST_PORT`, `NLP2DSL_WORKER_HOST_PORT` w `.env`.

### Walidacja requestu

Struktura zapytania (`environment.doql.less` / SystemMapIR) determinuje reguły walidacji w każdej fazie (preflight → DSL ready → execute → post-exec). Autonomiczna pętla naprawia brakujące dane i niepoprawne załączniki PDF zanim zapyta użytkownika.

Szczegóły: [`docs/validation.md`](docs/validation.md) · [`docs/process-agent.md`](docs/process-agent.md) · [`docs/reflection-model.md`](docs/reflection-model.md)

## Przykłady i tryb interaktywny

Szczegóły (Intract vs MVP, walidacja, logi, dialog): **[`examples/README.md`](examples/README.md)**

```bash
# env2llm nie jest na PyPI — najpierw lokalne pakiety (semcod/env2llm + packages/)
bash scripts/install-local-deps.sh && pip install -e .
# lub: ./scripts/setup-dev.sh
docker compose up -d
python3 examples/06-interactive-chat/main.py --interactive   # rozmowa w terminalu
python3 examples/07-email-conversation/main.py               # e-mail + uzupełnianie body
./examples/run-all.sh
```

## Conversation Loop (AI Dialog)

System prowadzi konwersację, dopytuje o brakujące dane i generuje dynamiczny formularz UI.

### Rozpocznij rozmowę

```bash
# Tekst
curl -X POST http://localhost:8010/workflow/chat/start \
  -H "Content-Type: application/json" \
  -d '{"text": "Chcę wysłać fakturę"}'

# Audio (STT via Deepgram)
curl -X POST http://localhost:8010/workflow/chat/start \
  -F "audio=@nagranie.wav"
```

Odpowiedź (brakujące dane):
```json
{
  "conversation_id": "a1b2c3d4e5f6",
  "status": "in_progress",
  "message": "Podaj: kwotę, adres e-mail odbiorcy",
  "missing": ["send_invoice.amount", "send_invoice.to"],
  "form": {
    "action": "send_invoice",
    "fields": [
      {"name": "amount", "type": "number", "label": "Kwota", "required": true},
      {"name": "to", "type": "email", "label": "Adres e-mail odbiorcy", "required": true},
      {"name": "currency", "type": "select", "label": "Waluta", "required": false, "options": ["PLN","EUR","USD","GBP"]}
    ]
  }
}
```

### Uzupełnij dane

```bash
# Tekst
curl -X POST http://localhost:8010/workflow/chat/message \
  -H "Content-Type: application/json" \
  -d '{"conversation_id": "a1b2c3d4e5f6", "text": "1500 PLN na klient@firma.pl"}'

# Audio (STT via Deepgram)
curl -X POST http://localhost:8010/workflow/chat/message \
  -F "conversation_id=a1b2c3d4e5f6" \
  -F "audio=@odpowiedz.wav"
```

### Uruchom workflow

```bash
curl -X POST http://localhost:8010/workflow/chat/message \
  -H "Content-Type: application/json" \
  -d '{"conversation_id": "a1b2c3d4e5f6", "text": "uruchom"}'
```

## Schema-driven UI

Backend generuje schematy formularzy dynamicznie z rejestru akcji:

```bash
# Wszystkie akcje
curl http://localhost:8010/workflow/actions/schema

# Konkretna akcja
curl http://localhost:8010/workflow/actions/schema/send_invoice
```

Frontend renderuje formularze automatycznie z tych schematów — zero ręcznych formularzy.

## One-shot Pipeline (bez dialogu)

```bash
# Generuj DSL
curl -X POST http://localhost:8010/workflow/from-text \
  -H "Content-Type: application/json" \
  -d '{"text": "Co tydzień generuj raport sprzedaży w PDF i wyślij email do manager@firma.pl"}'

# Generuj + wykonaj
curl -X POST http://localhost:8010/workflow/from-text \
  -H "Content-Type: application/json" \
  -d '{"text": "Wyślij fakturę na 1500 PLN do klient@firma.pl", "execute": true}'
```

## Bezpośrednie uruchomienie DSL (JSON)

```bash
curl -X POST http://localhost:8010/workflow/run \
  -H "Content-Type: application/json" \
  -d '{
    "name": "invoice_and_email",
    "steps": [
      {"action": "send_invoice", "config": {"amount": 1500, "to": "klient@firma.pl", "currency": "PLN"}},
      {"action": "send_email", "config": {"to": "klient@firma.pl", "subject": "Faktura wystawiona"}}
    ]
  }'
```

## Dostępne akcje

| Akcja | Wymagane | Aliasy PL |
|-------|----------|-----------|
| `send_invoice` | `amount`, `to` | faktura, rachunek |
| `send_email` | `to` | email, maila, napisz |
| `generate_report` | `report_type` | raport, zestawienie |
| `crm_update` | `entity` | aktualizuj crm |
| `notify_slack` | `channel` | powiadom, slack |

### Composite intents (auto-wykrywane)

`invoice_and_notify` · `invoice_and_email` · `report_and_email` · `full_invoice_flow` · `full_report_flow`

## Tryby NLP

| Mode | Opis |
|------|------|
| `rules` | Offline, regex + aliasy (domyślny) |
| `llm` | LLM API (OpenAI / Anthropic / Ollama) |
| `auto` | Rules first, LLM fallback |

## Speech-to-Text (Deepgram)

System obsługuje wejście głosowe w Conversation Loop:

```bash
# Konfiguracja w .env
DEEPGRAM_API_KEY=

# Użycie
curl -X POST http://localhost:8010/workflow/chat/start \
  -F "audio=@nagranie.wav"
```

### Obsługiwane formaty audio:
- WAV, MP3, M4A, OGG, FLAC
- Język: polski (domyślny), konfigurowalny
- Model: nova-3-general (Deepgram)

### Streaming STT:
Dla konwersacji w czasie rzeczywistym użyj WebSocket:
```python
from audio_parser import StreamingSTT

stt = StreamingSTT(language="pl")
await stt.start()
await stt.send_audio(chunk)
transcript = await stt.get_transcript()
```

## Voice Chat UI (PWA)

System zawiera gotowy interfejs webowy z obsługą głosową:

```bash
# Otwórz w przeglądarce
http://localhost:8012/chat
```

### Funkcje:
- 🎤 **Voice input** - kliknij Start Voice i mów
- 📝 **Text input** - wpisz wiadomość ręcznie
- 🔄 **Real-time** - WebSocket streaming
- 📱 **PWA** - instaluj jako aplikację mobilną/desktopową

### Automatyczny start:
```html
<!-- Auto-connect i auto-voice na onload -->
<body onload="initVoice()">
```

### Kiosk mode (desktop/embedded):
```bash
# Chrome kiosk
chrome --kiosk --autoplay-policy=no-user-gesture-required http://localhost:8012/chat

# Electron app
npm install electron
# main.js: win.loadURL('http://localhost:8012/chat')
```

## Tauri desktop wrapper
 
 Jeśli chcesz desktopową powłokę zamiast samej przeglądarki, użyj wrappera w `tauri-wrapper/`.
 Ten projekt otwiera istniejący backendowy ekran `/chat`, więc nie duplikuje logiki STT/TTS.
 W trybie dev wrapper uruchamia lokalny launcher na `http://127.0.0.1:1420`, a potem przechodzi do backendowego czatu, gdy `/health` odpowie OK.

Jeśli na Twoim Linuxie Tauri blokują brakujące biblioteki WebKitGTK/GTK, użyj browserowego fallbacku:
`cd tauri-wrapper && npm run desktop` albo `bash ./desktop.sh`.
Otwiera on ten sam `/chat` w Chrome/Chromium w trybie `--app`.

### Linux prerequisites
Na Linuxie Tauri v1 wymaga systemowych bibliotek WebKitGTK/GTK. Jeśli `npm run dev` kończy się błędem z brakującymi `libsoup-2.4` albo `javascriptcoregtk-4.0`, doinstaluj:
```bash
sudo apt install build-essential curl wget file libssl-dev libgtk-3-dev \
  libwebkit2gtk-4.0-dev libsoup2.4-dev libjavascriptcoregtk-4.0-dev \
  libayatana-appindicator3-dev librsvg2-dev
```
Jeśli używasz innej dystrybucji, zainstaluj odpowiednie odpowiedniki pakietów deweloperskich WebKitGTK/GTK.

### Uruchomienie

```bash
cd tauri-wrapper
npm install
npm run dev
```

Jeśli nie chcesz instalować bibliotek systemowych albo Tauri nie startuje, użyj:

```bash
cd tauri-wrapper
npm run desktop
```

Launcher sprawdza backend pod `http://127.0.0.1:8012` i dopiero potem przełącza do `http://127.0.0.1:8012/chat`.

### Build

```bash
cd tauri-wrapper
npm run build
```

### Desktop fallback launcher

Jeśli chcesz ominąć Tauri na danym systemie, użyj `tauri-wrapper/desktop.sh`.
Skrypt czeka na backend, a potem otwiera voice chat w Chrome/Chromium w trybie `--app`.
To dobre rozwiązanie, gdy środowisko nie ma wymaganych bibliotek WebKitGTK dla Tauri.

Konfiguracja LLM:

1. Skopiuj `.env.example` → `.env`
2. Uzupełnij klucz API wybranego providera:

```env
# OpenRouter (domyślny)
OPENROUTER_API_KEY=
LLM_MODEL=openrouter/openai/gpt-5-mini

# Speech-to-Text (Deepgram)
DEEPGRAM_API_KEY=

# Lub OpenAI
OPENAI_API_KEY=
LLM_MODEL=gpt-4o-mini

# Lub Anthropic
ANTHROPIC_API_KEY=
LLM_MODEL=claude-sonnet-4-...

# Lub Ollama (lokalny)
OLLAMA_API_BASE=http://localhost:11434
LLM_MODEL=ollama/llama3
```

Zmienne są automatycznie przekazywane do kontenerów w `docker-compose.yml`.

## Struktura projektu

```
nlp2dsl/
├── docker-compose.yml
├── .env.example                 # Konfiguracja LLM i serwisów (porty 8010/8012/8004)
├── nlp2dsl_sdk/                 # SDK klienta, DOQL, walidacja, reflection
├── docs/                        # Dokumentacja (indeks: docs/README.md)
├── examples/                    # Przykłady użycia
│   ├── 01-invoice/
│   ├── 02-email/
│   ├── 03-report-and-notify/
│   ├── 04-scheduled-report/
│   ├── 05-conversation-flow/
│   ├── README.md
│   ├── EXECUTION_REPORT.md
│   └── MISSING_CONFIGURATION.md
├── backend/                     # API Gateway + Workflow Engine
│   └── app/
│       ├── main.py
│       ├── engine.py            # Workflow execution + pre-step validation
│       └── routers/chat.py      # Chat proxy + auto_execute
├── nlp-service/                 # NLP → DSL Pipeline
│   └── app/
│       ├── conversation/        # orchestrator, autonomous_loop, process_agent
│       ├── validation/          # step_validator, attachment, path_policy
│       ├── registry.py          # Actions registry (migracja → DOQL)
│       └── ...
├── worker/                      # Imperatywne executory + invoice_pdf
│   └── worker.py
├── tauri-wrapper/               # Desktop wrapper Tauri dla `/chat`
└── README.md
```

Pełna dokumentacja: [`docs/README.md`](docs/README.md)

## Przykłady użycia

Zobacz `examples/README.md` dla pełnej listy przykładów:

Jeśli chcesz od razu uruchomić gotowy scenariusz bez tworzenia wrappera, użyj pakietowego CLI:

```bash
nlp2dsl-demo --list
nlp2dsl-demo gallery
```

```bash
# Uruchom wszystkie przykłady
cd examples
for dir in */; do
    echo "Testing $dir"
    cd "$dir"
    python3 main.py
    cd - > /dev/null
done
```

### Dostępne przykłady:

| Przykład | Link | Opis | Koncepcje |
|----------|------|------|-----------|
| **01-invoice** | [📁 examples/01-invoice/](examples/01-invoice/) | Faktura autonomiczna + PDF + walidacja strict | DOQL autofill, attachment_validation, reflection |
| **02-email** | [📁 examples/02-email/](examples/02-email/) | Różne sposoby wysyłania e-maili | Aliasy komend, parametry |
| **03-report-and-notify** | [📁 examples/03-report-and-notify/](examples/03-report-and-notify/) | Raporty + powiadomienia na wiele kanałów | Composite intents, multi-step |
| **04-scheduled-report** | [📁 examples/04-scheduled-report/](examples/04-scheduled-report/) | Zaplanowane raporty (daily/weekly/monthly) | Triggers, schedule |
| **05-conversation-flow** | [📁 examples/05-conversation-flow/](examples/05-conversation-flow/) | Pełny cykl konwersacyjny od startu do wykonania | Chat API, state management |

#### Szybki start z przykładami:

```bash
bash scripts/install-local-deps.sh && pip install -e .
docker compose up -d                        # backend + nlp-service + worker
python3 examples/01-invoice/main.py       # czeka na /health (do 120 s)

./examples/run-all.sh                       # wszystkie przykłady
# lub pojedynczo:
cd examples/01-invoice && python3 main.py
```

SDK (`ensure_services`) sprawdza `http://localhost:8010`, `:8012`, `:8004` — nie uruchamiaj `main.py` w tej samej linii co `compose up` bez oczekiwania (race przy starcie uvicorn).

Logi serwisu NLP (z **roota** repo, nie `examples/docker-compose.yml`):

```bash
docker compose logs -f nlp-service
```

## Obsługa błędów i fallback

System jest odporny na brakującą konfigurację:

- **Brak kluczy LLM**: Automatycznie używa parsera reguł
- **Brak Redis**: In-memory storage (utrata danych przy restarcie)
- **Brak bazy**: Ograniczone funkcje (brak historii)
- **Mock integracje**: Worker zwraca symulowane odpowiedzi

Szczegóły w `examples/MISSING_CONFIGURATION.md`.

## Docker i .env

Każdy przykład zawiera:
- `Dockerfile` - konteneryzacja
- `requirements.txt` - zależności Python
- `.env.example` - szablon konfiguracji

Opcjonalne serwisy pomocnicze:
```bash
docker compose -f examples/docker-compose.yml --profile email up -d smtp-mock
docker compose -f examples/docker-compose.yml --profile storage up -d minio
```

## Dodanie nowej akcji

1. `nlp-service/app/registry.py` — dodaj do `ACTIONS_REGISTRY`
2. `worker/worker.py` — dodaj handler `@action("nazwa")`
3. `docker compose up --build`


## License

Licensed under Apache-2.0.
