compendious commited on
Commit
2814ec9
·
unverified ·
1 Parent(s): 13072a8

Documentation

Browse files
README.md CHANGED
@@ -31,22 +31,34 @@ pinned: false
31
  | **Article / transcript** | Paste any text directly |
32
  | **File upload** | Drag-and-drop `.txt` files |
33
  | **Streaming** | Summaries stream token-by-token from Ollama via NDJSON |
34
- | **Model switching** | Choose between available Ollama models from the UI |
 
 
 
 
 
 
 
 
35
 
36
  ---
37
 
38
  ## API Endpoints
39
 
40
- | Method | Path | Description |
41
- |---------|-------------------------|-----------------------|
42
- | `GET` | `/health` | Health check |
43
- | `GET` | `/status` | Ollama statuses, etc. |
44
- | `GET` | `/models` | List available models |
45
- | `POST` | `/summarize/transcript` | Raw text summary |
46
- | `POST` | `/summarize/youtube` | YouTube video by URL |
47
- | `POST` | `/summarize/file` | `.txt` file summary |
48
-
49
- All `/summarize/*` endpoints accept an optional `model` field to override the default and require `X-API-Key` header (`PRECIS_API_KEY`).
 
 
 
 
50
 
51
  ---
52
 
@@ -78,17 +90,26 @@ cp .env.example .env
78
  # VITE_API_KEY must match PRECIS_API_KEY so the baked frontend can auth
79
  ```
80
 
81
- > **`.env.example` defaults for Docker (host Ollama):**
82
- > ```ini
83
- > OLLAMA_BASE_URL=http://127.0.0.1:11434 # for local `uvicorn` without Docker; Docker compose hard-codes http://host.docker.internal:11434 (host GPU)
84
- > DEFAULT_MODEL=phi4-mini:latest
85
- > AVAILABLE_MODELS=phi4-mini:latest,qwen3:4b
86
- > PRECIS_API_KEY=replace-with-a-long-random-secret
87
- > VITE_API_KEY=replace-with-a-long-random-secret
88
- > PRECIS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:8000
89
- > VITE_API_BASE_URL= # empty = same origin (correct for Docker)
90
- > # NOTE: OLLAMA_HOST_DIR removed — no Docker Ollama container, no bind mount. Host Ollama uses its native store.
91
- > ```
 
 
 
 
 
 
 
 
 
92
 
93
  ### 3. Run
94
 
@@ -116,7 +137,7 @@ The API will 503 until a model is installed. On **host**:
116
  ```bash
117
  ollama pull phi4-mini:latest
118
  # optional extras:
119
- ollama pull qwen3:4b
120
  ollama list
121
  ```
122
 
@@ -125,15 +146,15 @@ Then refresh http://localhost:5173 — the model selector populates automaticall
125
  #### Useful commands
126
 
127
  ```bash
128
- docker compose up --watch -d # detached with watch
129
- docker compose logs -f api # tail API logs (no ollama container anymore)
130
  docker compose logs -f frontend
131
  docker compose down # stop api+frontend
132
  docker compose ps
133
  curl http://localhost:8000/health
134
  curl http://localhost:8000/status
135
  curl http://host.docker.internal:11434/api/tags # verify host Ollama reachable from Docker
136
- # prod without watch/HMR (static frontend at 8000):
137
  docker compose -f docker-compose.yml up --build -d
138
  ```
139
 
@@ -142,7 +163,9 @@ docker compose -f docker-compose.yml up --build -d
142
  If you just want the API image and already run Ollama natively (`ollama serve` on host):
143
 
144
  ```bash
145
- docker build -t precis .
 
 
146
  docker run --rm -p 8000:8000 --env-file .env \
147
  -e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
148
  --add-host=host.docker.internal:host-gateway \
 
31
  | **Article / transcript** | Paste any text directly |
32
  | **File upload** | Drag-and-drop `.txt` files |
33
  | **Streaming** | Summaries stream token-by-token from Ollama via NDJSON |
34
+ | **Model switching** | Choose between available Ollama models from the UI with live VRAM warmup |
35
+
36
+ ### Keyboard Shortcuts
37
+
38
+ | Shortcut | Action | Behavior |
39
+ |---|---|---|
40
+ | <kbd>Ctrl</kbd> + <kbd>Enter</kbd> | **Generate** | Triggers summarization on the active tab |
41
+ | <kbd>Ctrl</kbd> + <kbd>C</kbd> | **Cancel** | Stops active generation; preserves streamed tokens as a `· partial` summary |
42
+ | <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>C</kbd> | **Copy Link** | Copies current YouTube URL to clipboard |
43
 
44
  ---
45
 
46
  ## API Endpoints
47
 
48
+ | Method | Path | Auth Required | Description |
49
+ |---------|--------------------------|:-------------:|-------------|
50
+ | `GET` | `/health` | No | Service liveness check |
51
+ | `GET` | `/status` | No | Ollama reachability, model configuration, version info |
52
+ | `GET` | `/models` | No | Lists installed models, currently running VRAM models, and default |
53
+ | `POST` | `/warmup` | No | Pre-loads model into Ollama VRAM (`?model=<name>`) |
54
+ | `GET` | `/warmup/status` | No | Checks if model is currently loaded in memory (`?model=<name>`) |
55
+ | `POST` | `/unload` | No | Evicts a specific model or all models from VRAM |
56
+ | `GET` | `/api` | No | API root metadata and documentation links |
57
+ | `POST` | `/summarize/transcript` | `X-API-Key` | Plain-text summarization (JSON body) |
58
+ | `POST` | `/summarize/youtube` | `X-API-Key` | YouTube video transcript fetch + summary (JSON body) |
59
+ | `POST` | `/summarize/file` | `X-API-Key` | Plain `.txt` file upload (`multipart/form-data`, optional `?model=`) |
60
+
61
+ All `/summarize/*` endpoints stream responses via NDJSON (`application/x-ndjson`) and require the `X-API-Key` header matching `PRECIS_API_KEY`. Model reasoning and `<think>` blocks are isolated server-side and streamed as formatted markdown blockquotes.
62
 
63
  ---
64
 
 
90
  # VITE_API_KEY must match PRECIS_API_KEY so the baked frontend can auth
91
  ```
92
 
93
+ > **Configuration & Environment Variables:**
94
+ >
95
+ > | Variable | Default | Purpose |
96
+ > |---|---|---|
97
+ > | `OLLAMA_BASE_URL` | `http://127.0.0.1:11434` | Host Ollama URL (Docker Compose sets `http://host.docker.internal:11434`) |
98
+ > | `DEFAULT_MODEL` | `phi4-mini:latest` | Default model tag when none specified in request |
99
+ > | `AVAILABLE_MODELS` | `phi4-mini:latest` | Comma-separated allowlist of models |
100
+ > | `PRECIS_API_KEY` | *(required)* | Secret token checked against `X-API-Key` on `/summarize/*` |
101
+ > | `VITE_API_KEY` | *(required)* | Inlined into frontend bundle at build time to authenticate with API |
102
+ > | `VITE_API_BASE_URL` | `""` | Base API URL; empty string uses same origin (or Vite proxy in dev) |
103
+ > | `VITE_PROXY_TARGET` | `http://api:8000` | Target backend host used by Docker frontend container |
104
+ > | `PORT` | `8000` | Service listening port (defaults to `8000`, Hugging Face Spaces sets `7860`) |
105
+ > | `PRECIS_ALLOWED_ORIGINS` | `http://localhost:5173,http://localhost:8000` | CORS allowed origins |
106
+ > | `OLLAMA_KEEP_ALIVE` | `30m` | Duration Ollama retains loaded model in VRAM |
107
+ > | `MAX_SUMMARY_TOKENS` | `120` | Max tokens generated per summary |
108
+ > | `TEMPERATURE` | `0.2` | Generation sampling temperature |
109
+ > | `PRECIS_MAX_UPLOAD_BYTES` | `10485760` | Max upload size for `/summarize/file` (10 MB) |
110
+ > | `PRECIS_MAX_TRANSCRIPT_CHARS` | `250000` | Max characters allowed for text summarization |
111
+ > | `CHOKIDAR_USEPOLLING` | `1` | Enables filesystem polling for Vite HMR across Docker on Windows |
112
+ > | `CHOKIDAR_INTERVAL` | `1000` | Polling interval in milliseconds to prevent CPU thrashing |
113
 
114
  ### 3. Run
115
 
 
137
  ```bash
138
  ollama pull phi4-mini:latest
139
  # optional extras:
140
+ ollama pull qwen2.5:3b
141
  ollama list
142
  ```
143
 
 
146
  #### Useful commands
147
 
148
  ```bash
149
+ docker compose up --watch -d # detached with watch (api + frontend containers)
150
+ docker compose logs -f api # tail API logs
151
  docker compose logs -f frontend
152
  docker compose down # stop api+frontend
153
  docker compose ps
154
  curl http://localhost:8000/health
155
  curl http://localhost:8000/status
156
  curl http://host.docker.internal:11434/api/tags # verify host Ollama reachable from Docker
157
+ # prod without watch/HMR (static frontend baked into api image at 8000):
158
  docker compose -f docker-compose.yml up --build -d
159
  ```
160
 
 
163
  If you just want the API image and already run Ollama natively (`ollama serve` on host):
164
 
165
  ```bash
166
+ docker build -t precis \
167
+ --build-arg PRECIS_API_KEY=your-secret-key \
168
+ --build-arg VITE_API_KEY=your-secret-key .
169
  docker run --rm -p 8000:8000 --env-file .env \
170
  -e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
171
  --add-host=host.docker.internal:host-gateway \
frontend/README.md CHANGED
@@ -2,11 +2,53 @@
2
 
3
  React 19 + Vite frontend for Précis. See the [root README](../README.md) for full setup instructions.
4
 
5
- Navigate to the `frontend/` folder, then run:
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  ```bash
8
  npm install
9
  npm run dev
10
  ```
11
 
12
- Requires the backend API running at `http://localhost:5173`.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  React 19 + Vite frontend for Précis. See the [root README](../README.md) for full setup instructions.
4
 
5
+ ## Development
6
+
7
+ ### 1. With Docker (Recommended)
8
+ From the repository root, run:
9
+
10
+ ```bash
11
+ docker compose up --watch -d
12
+ ```
13
+
14
+ The frontend container starts the Vite dev server at `http://localhost:5173` with HMR enabled, proxying API requests to the backend container at `http://api:8000`.
15
+
16
+ ### 2. Manual (Without Docker)
17
+ From the `frontend/` directory:
18
 
19
  ```bash
20
  npm install
21
  npm run dev
22
  ```
23
 
24
+ Served at `http://localhost:5173`. Requires the backend API running at `http://localhost:8000` (requests to `/health`, `/status`, `/models`, `/warmup`, `/unload`, and `/summarize` are proxied via `vite.config.js`).
25
+
26
+ ## Production Build
27
+
28
+ ```bash
29
+ npm run build
30
+ ```
31
+
32
+ Generates an optimized static bundle in `frontend/dist/`. In production or single-container Docker deployments, the FastAPI backend automatically detects `frontend/dist` and serves the single-page application directly from `/`.
33
+
34
+ ## Environment Variables
35
+
36
+ Read at build/dev time from the repo root `.env` or injected by Docker Compose:
37
+
38
+ | Variable | Description |
39
+ |---|---|
40
+ | `VITE_API_KEY` | API secret key inlined into the frontend bundle at build time; sent as `X-API-Key` to authorize with the backend. Must match `PRECIS_API_KEY`. |
41
+ | `VITE_API_BASE_URL` | Base API URL. Leave empty (`""`) to use same-origin (production) or the Vite dev proxy. |
42
+ | `VITE_PROXY_TARGET` | Proxy destination for Vite in dev mode (default: `http://localhost:8000`, set to `http://api:8000` inside Docker Compose). |
43
+
44
+ ## Architecture
45
+
46
+ * **`src/App.jsx`**: Main application shell with tab controls (YouTube, Text, File) and model selector with active VRAM status indicators.
47
+ * **`src/hooks/useStreaming.js`**: Custom hook for reading NDJSON streams (`ReadableStream` -> `TextDecoder`). Uses `requestAnimationFrame` frame-throttling (~60fps) to eliminate UI lag during rapid token delivery. Supports in-flight cancellation while preserving partial summaries.
48
+ * **`src/components/InlineResult.jsx`**: Renders markdown output, streaming status indicators, and model reasoning tags.
49
+
50
+ ### Keyboard Shortcuts
51
+
52
+ * <kbd>Ctrl</kbd> + <kbd>Enter</kbd>: Submit active form and generate summary.
53
+ * <kbd>Ctrl</kbd> + <kbd>C</kbd>: Cancel active generation and keep streamed tokens as a `· partial` result.
54
+ * <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>C</kbd>: Copy current YouTube URL to clipboard.
frontend/src/App.css CHANGED
@@ -339,7 +339,6 @@
339
  color: var(--color-danger-fg);
340
  }
341
 
342
- .inline-result--loading,
343
  .inline-result--streaming {
344
  background-color: var(--color-canvas-inset);
345
  border-color: var(--color-border-muted);
@@ -521,7 +520,7 @@
521
  background-color: #24292f;
522
  color: #ffffff;
523
  font-size: 11px;
524
- font-family: var(--font-family-sans);
525
  font-weight: 500;
526
  padding: 5px 8px;
527
  border-radius: 6px;
 
339
  color: var(--color-danger-fg);
340
  }
341
 
 
342
  .inline-result--streaming {
343
  background-color: var(--color-canvas-inset);
344
  border-color: var(--color-border-muted);
 
520
  background-color: #24292f;
521
  color: #ffffff;
522
  font-size: 11px;
523
+ font-family: var(--font-family);
524
  font-weight: 500;
525
  padding: 5px 8px;
526
  border-radius: 6px;
frontend/src/index.css CHANGED
@@ -120,20 +120,6 @@ body {
120
  background-color: var(--color-btn-primary-hover-bg);
121
  }
122
 
123
- .btn-lg {
124
- padding: 10px 24px;
125
- font-size: 16px;
126
- line-height: 24px;
127
- }
128
-
129
- /* Card styles */
130
- .card {
131
- background-color: var(--color-canvas-subtle);
132
- border: 1px solid var(--color-border-default);
133
- border-radius: var(--radius-1);
134
- padding: var(--spacing-4);
135
- }
136
-
137
  /* Input styles */
138
  .input {
139
  width: 100%;
@@ -207,17 +193,6 @@ body {
207
  color: var(--color-fg-muted);
208
  }
209
 
210
- .dropzone-text {
211
- font-size: 16px;
212
- color: var(--color-fg-muted);
213
- text-align: center;
214
- }
215
-
216
- .dropzone-hint {
217
- font-size: 12px;
218
- color: var(--color-fg-subtle);
219
- }
220
-
221
  /* Animations */
222
  @keyframes fadeIn {
223
  from {
@@ -230,23 +205,10 @@ body {
230
  }
231
  }
232
 
233
- @keyframes pulse {
234
- 0%, 100% {
235
- opacity: 1;
236
- }
237
- 50% {
238
- opacity: 0.5;
239
- }
240
- }
241
-
242
  .fade-in {
243
  animation: fadeIn 0.3s ease-out forwards;
244
  }
245
 
246
- .pulse {
247
- animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
248
- }
249
-
250
  /* Scrollbar */
251
  ::-webkit-scrollbar {
252
  width: 8px;
 
120
  background-color: var(--color-btn-primary-hover-bg);
121
  }
122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  /* Input styles */
124
  .input {
125
  width: 100%;
 
193
  color: var(--color-fg-muted);
194
  }
195
 
 
 
 
 
 
 
 
 
 
 
 
196
  /* Animations */
197
  @keyframes fadeIn {
198
  from {
 
205
  }
206
  }
207
 
 
 
 
 
 
 
 
 
 
208
  .fade-in {
209
  animation: fadeIn 0.3s ease-out forwards;
210
  }
211
 
 
 
 
 
212
  /* Scrollbar */
213
  ::-webkit-scrollbar {
214
  width: 8px;
frontend/src/main.jsx CHANGED
@@ -6,6 +6,5 @@ import App from './App.jsx'
6
  // caused duplicate /models + /warmup calls on every reload → perceived lag
7
  // and "stops after script fetching" race. We run without it for stability.
8
  // Re-enable only if you need to audit effects.
9
- // import { StrictMode } from 'react'
10
 
11
  createRoot(document.getElementById('root')).render(<App />)
 
6
  // caused duplicate /models + /warmup calls on every reload → perceived lag
7
  // and "stops after script fetching" race. We run without it for stability.
8
  // Re-enable only if you need to audit effects.
 
9
 
10
  createRoot(document.getElementById('root')).render(<App />)
scripts/cleaners/clean_ds.py CHANGED
@@ -22,7 +22,7 @@ def write_jsonl(rows, output_path):
22
  with open(output_path, 'w', encoding='utf-8') as f:
23
  for row in rows:
24
  new_data = {
25
- "id": i,
26
  "original_source": "DialogSum",
27
  "dialogue": row["dialogue"],
28
  "summary": row["summary"],
 
22
  with open(output_path, 'w', encoding='utf-8') as f:
23
  for row in rows:
24
  new_data = {
25
+ "id": row["id"],
26
  "original_source": "DialogSum",
27
  "dialogue": row["dialogue"],
28
  "summary": row["summary"],
scripts/cleaners/clean_ms.py CHANGED
@@ -24,7 +24,7 @@ def write_jsonl(lines, output_path):
24
  for line in lines:
25
  data = json.loads(line)
26
  new_data = {
27
- "id": i,
28
  "original_source": "MediaSum",
29
  "url": data["url"],
30
  "summary": data["summary"],
 
24
  for line in lines:
25
  data = json.loads(line)
26
  new_data = {
27
+ "id": data["id"],
28
  "original_source": "MediaSum",
29
  "url": data["url"],
30
  "summary": data["summary"],