Skip to content

Commit 6828c1f

Browse files
committed
build(gh-action-&-readme): build the app in gh
1 parent 7341498 commit 6828c1f

2 files changed

Lines changed: 217 additions & 5 deletions

File tree

.github/workflows/build-nextjs.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: Build Next.js Application
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- development
8+
paths:
9+
- 'src/viewer/**'
10+
- '.github/workflows/build-nextjs.yml'
11+
pull_request:
12+
branches:
13+
- main
14+
- development
15+
paths:
16+
- 'src/viewer/**'
17+
- '.github/workflows/build-nextjs.yml'
18+
19+
jobs:
20+
build:
21+
runs-on: ubuntu-latest
22+
23+
defaults:
24+
run:
25+
working-directory: src/viewer
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
31+
- name: Setup Node.js
32+
uses: actions/setup-node@v4
33+
with:
34+
node-version: '20'
35+
36+
- name: Setup pnpm
37+
uses: pnpm/action-setup@v4
38+
with:
39+
version: 9.15.0
40+
41+
- name: Get pnpm store directory
42+
shell: bash
43+
run: |
44+
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
45+
46+
- name: Setup pnpm cache
47+
uses: actions/cache@v4
48+
with:
49+
path: ${{ env.STORE_PATH }}
50+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
51+
restore-keys: |
52+
${{ runner.os }}-pnpm-store-
53+
54+
- name: Install dependencies
55+
run: pnpm install --frozen-lockfile
56+
57+
- name: Check formatting
58+
run: pnpm run format:check
59+
60+
- name: Run linter
61+
run: pnpm run lint
62+
63+
- name: Run type check
64+
run: pnpm run type-check
65+
66+
- name: Run tests
67+
run: pnpm run test
68+
69+
- name: Build Next.js application
70+
run: pnpm run build
71+
72+
- name: Upload build artifacts
73+
uses: actions/upload-artifact@v4
74+
if: success()
75+
with:
76+
name: nextjs-build
77+
path: src/viewer/.next
78+
retention-days: 7

README.md

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,23 @@
22

33
A Python application that uses Vision Language Models (VLMs) to iteratively create original artwork in the style of famous artists. The system starts with a blank canvas and progressively adds strokes suggested by VLMs, building unique images that embody specific artistic styles.
44

5-
**Current Status**: Phase 4 complete - Provider-agnostic VLM client supporting Mistral API and LMStudio, with multi-stroke generation, evaluation, and strategy management.
5+
The project includes a Next.js viewer application for interactively exploring generated artworks, viewing stroke-by-stroke creation timelines, and examining metadata and evaluation scores.
6+
7+
**Current Status**: Phase 4 complete - Provider-agnostic VLM client supporting Mistral API and LMStudio, with multi-stroke generation, evaluation, strategy management, and interactive web viewer.
68

79
## Prerequisites
810

11+
### Python Backend
912
- **Python**: 3.12.2 or higher
1013
- **Conda**: Anaconda or Miniconda for environment management
1114
- A VLM provider (one of):
1215
- **Mistral API** (recommended): Get an API key at https://console.mistral.ai/
1316
- **LMStudio** (local): Download from https://lmstudio.ai/ and run with server enabled on port 1234
1417

18+
### Next.js Viewer (Optional)
19+
- **Node.js**: 18.0.0 or higher
20+
- **pnpm**: 9.15.0 or higher (install with `npm install -g pnpm`)
21+
1522
## Setup
1623

1724
### 1. Create Conda Environment
@@ -67,6 +74,14 @@ cd src/paint_by_language_model
6774
uv pip install -e ".[dev]"
6875
```
6976

77+
### 5. Install Viewer Dependencies (Optional)
78+
79+
To run the interactive web viewer:
80+
81+
```sh
82+
pnpm -C src/viewer install
83+
```
84+
7085
## Running the App
7186

7287
### Image Generation (Main Usage)
@@ -175,6 +190,7 @@ src/output/vangogh-001/
175190
├── final_artwork.jpeg # Final artwork (JPEG format)
176191
├── metadata.json # Generation metadata
177192
├── generation_report.md # Human-readable summary
193+
├── viewer_data.json # Aggregated data for web viewer (auto-generated)
178194
├── snapshots/ # Canvas images per iteration
179195
│ ├── iteration-001.png
180196
│ ├── iteration-002.png
@@ -190,6 +206,68 @@ src/output/vangogh-001/
190206
└── ...
191207
```
192208

209+
**Note**: `viewer_data.json` is automatically generated after each successful generation. This aggregated file contains all iteration data needed by the web viewer.
210+
211+
## Interactive Viewer
212+
213+
### Running the Viewer
214+
215+
The Next.js viewer provides an interactive web interface for exploring generated artworks:
216+
217+
```sh
218+
pnpm -C src/viewer dev
219+
```
220+
221+
View the gallery at: http://localhost:3000
222+
223+
### Features
224+
225+
- **Gallery View**: Browse all generated artworks with preview cards
226+
- **Inspector**: Step through artwork creation stroke-by-stroke
227+
- **Timeline Playback**: Animate the creation process with play/pause controls
228+
- **Metadata Display**: View artist name, subject, scores, and generation statistics
229+
- **Evaluation Insights**: See VLM feedback for each iteration (strengths, weaknesses, suggestions)
230+
- **Stroke Details**: Examine individual stroke parameters, colors, and reasoning
231+
232+
### Preparing Data for the Viewer
233+
234+
**Automatic Export**: `viewer_data.json` is automatically generated after each successful artwork generation.
235+
236+
**Manual Export**: To re-export data for existing artworks:
237+
238+
```sh
239+
conda activate paint-by-language-model
240+
python -c "from src.paint_by_language_model.services.viewer_data_export import export_viewer_data; export_viewer_data('vangogh-001')"
241+
```
242+
243+
**Copy to Viewer**: Copy artwork directories to the viewer's public data folder:
244+
245+
```sh
246+
# Copy (for production builds)
247+
cp -r src/output/vangogh-001 src/viewer/public/data/vangogh-001
248+
```
249+
250+
**Minify for Production**: Reduce file sizes before deployment:
251+
252+
```sh
253+
conda activate paint-by-language-model
254+
python scripts/minify_viewer_data.py
255+
```
256+
257+
### Building for Production
258+
259+
```sh
260+
pnpm -C src/viewer build
261+
pnpm -C src/viewer start # Serves optimized production build
262+
```
263+
264+
Or export static HTML:
265+
266+
```sh
267+
pnpm -C src/viewer build
268+
# Static files are in src/viewer/out/
269+
```
270+
193271
## Output Examples
194272

195273
### Generation Summary (console output)
@@ -347,35 +425,40 @@ Edit [src/paint_by_language_model/config.py](src/paint_by_language_model/config.
347425

348426
## Architecture
349427

350-
### Current Components
428+
### Python Backend Components
351429

352430
- **Generation Orchestrator** ([generation_orchestrator.py](src/paint_by_language_model/generation_orchestrator.py))
353431
- Main entry point for generation workflow
354432
- Coordinates all components (canvas, VLMs, strategy)
355433
- Handles iteration loop and stopping conditions
356434
- Supports resumable generation
435+
- Auto-exports viewer data on completion
357436

358437
- **Canvas Manager** ([services/canvas_manager.py](src/paint_by_language_model/services/canvas_manager.py))
359438
- Manages image canvas with PIL
360-
- Applies strokes (lines, curves, fills)
439+
- Applies strokes (lines, arcs, polylines, circles, splatters)
361440
- Validates stroke parameters
362441
- Saves snapshots
442+
- Delegates rendering to `StrokeRendererFactory`
363443

364444
- **Stroke VLM Client** ([services/stroke_vlm_client.py](src/paint_by_language_model/services/stroke_vlm_client.py))
365445
- Queries VLMs with canvas images
366-
- Builds prompts with artist context
367-
- Parses JSON responses robustly
446+
- Builds prompts with artist context and strategy
447+
- Parses JSON responses robustly (handles malformed VLM output)
448+
- Supports batch stroke generation
368449
- Tracks interaction history for debugging
369450

370451
- **Evaluation VLM Client** ([services/evaluation_vlm_client.py](src/paint_by_language_model/services/evaluation_vlm_client.py))
371452
- Evaluates canvas against target artist style
372453
- Returns style scores (0-100)
373454
- Provides strengths, weaknesses, and suggestions
455+
- Guides strategy updates
374456

375457
- **Strategy Manager** ([strategy_manager.py](src/paint_by_language_model/strategy_manager.py))
376458
- Manages multi-iteration context
377459
- Saves and loads strategy files
378460
- Provides recent strategy window for prompts
461+
- Tracks strategic evolution over iterations
379462

380463
- **VLM Client** ([vlm_client.py](src/paint_by_language_model/vlm_client.py))
381464
- Provider-agnostic client for OpenAI-compatible APIs (Mistral, LMStudio)
@@ -384,6 +467,53 @@ Edit [src/paint_by_language_model/config.py](src/paint_by_language_model/config.
384467
- Rate-limit retry with exponential backoff (HTTP 429)
385468
- Configurable temperature per request
386469

470+
- **Viewer Data Export** ([services/viewer_data_export.py](src/paint_by_language_model/services/viewer_data_export.py))
471+
- Aggregates iteration data into `viewer_data.json`
472+
- Embeds base64-encoded snapshot images
473+
- Auto-exports after successful generation
474+
- Optimized format for web viewer performance
475+
476+
- **GIF Generator** ([services/gif_generator.py](src/paint_by_language_model/services/gif_generator.py))
477+
- Creates animated timelapses from iteration snapshots
478+
- Resizes frames for manageable file sizes
479+
- Configurable frame duration and looping
480+
- Auto-generates `timelapse.gif` on completion
481+
482+
- **Stroke Renderers** ([services/renderers/](src/paint_by_language_model/services/renderers/))
483+
- Modular rendering system for different stroke types
484+
- Implementations: line, arc, polyline, circle, splatter
485+
- Factory pattern for extensibility
486+
- Consistent parameter validation
487+
488+
### Next.js Viewer (Frontend)
489+
490+
- **Gallery** ([src/viewer/src/app/page.tsx](src/viewer/src/app/page.tsx))
491+
- Homepage displaying all generated artworks
492+
- Responsive grid of artwork cards
493+
- Static generation at build time
494+
495+
- **Inspector** ([src/viewer/src/app/inspect/[artworkId]/page.tsx](src/viewer/src/app/inspect/[artworkId]/page.tsx))
496+
- Interactive artwork viewer with timeline
497+
- Stroke-by-stroke playback controls
498+
- Side panel with metadata, evaluation scores, and stroke details
499+
- Canvas overlay rendering
500+
501+
- **Components**:
502+
- `StrokeCanvas`: HTML5 canvas for rendering strokes
503+
- `Timeline`: Interactive timeline with play/pause controls
504+
- `SidePanel`: Metadata, evaluations, and stroke information
505+
- `Toolbar`: Playback controls and display options
506+
- `ArtworkCard`: Preview cards in gallery view
507+
- `Gallery`: Responsive grid layout
508+
509+
### Data Flow
510+
511+
1. **Generation**: Python backend creates artwork → saves iteration files
512+
2. **Export**: `viewer_data.json` generated with aggregated data + base64 images
513+
3. **Deployment**: Link/copy artwork folders to `src/viewer/public/data/`
514+
4. **Build**: Next.js discovers artworks → generates static pages
515+
5. **Runtime**: Client-side React components render interactive UI
516+
387517
### Data Models
388518

389519
- **Stroke** ([models/stroke.py](src/paint_by_language_model/models/stroke.py)) - Drawing operation parameters
@@ -397,3 +527,7 @@ Edit [src/paint_by_language_model/config.py](src/paint_by_language_model/config.
397527
- [x] Phase 2: Generation orchestrator & CLI
398528
- [x] Phase 3: Additional stroke types (arc, polyline, circle, splatter), multiple strokes per iteration
399529
- [x] Phase 4: Provider-agnostic VLM client (Mistral API + LMStudio)
530+
- [x] Phase 5: Interactive Next.js viewer with timeline playback
531+
- [ ] Phase 6: Advanced stroke types and rendering techniques
532+
- [ ] Phase 7: Multi-model VLM comparison and A/B testing
533+
- [ ] Phase 8: Public deployment and gallery hosting

0 commit comments

Comments
 (0)