Commit graph

73 commits

Author SHA1 Message Date
Vadym Samoilenko
bd4e600ec7 config: add admin emails for Vadym and Dave Porter
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 16:51:37 +01:00
Vadym Samoilenko
22a5ce83af feat: admin users can rotate Kling credentials in real-time via UI
- Add runtime_config.php: credential store backed by runtime_config.json
  (gitignored). Falls back to .env values so existing envs need no migration.
- Add admin_api.php: status / test_kling / update_kling endpoints gated
  behind ADMIN_EMAILS allowlist. Accepts Bearer idToken when SSO enabled;
  uses mock dev@localhost when SSO disabled.
- config.php: replace KLING_ACCESS_KEY/SECRET_KEY defines with ADMIN_EMAILS
- kling_api.php: read credentials via getKlingCredentials() on every request
  so rotations take effect immediately without a server restart
- All .env templates: add ADMIN_EMAILS= (dev@localhost populated in .env.local)
- AdminSettings.jsx: modal with masked status, Test Connection, Save Credentials
- AppContent.jsx: admin status check on mount; Settings gear shown to admins
- Fix production URL in .env.production/.env.example (optical-prod.oliver.solutions)
- .gitignore: exclude backend/runtime_config.json

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 16:45:27 +01:00
Vadym Samoilenko
a2358ba01c fix: correct Kling API params per official docs
- camera_control: only kling-v1 and kling-v1-5 support it (not v3)
- For preset types (down_back etc.), config must be absent — only
  'simple' type uses config fields
- camera_control and image_tail are mutually exclusive in I2V
- cfg_scale not supported by kling-v2.x models — now skipped
- duration sent as string to match API examples
- v3/v3-omni removed from camera control UI list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:38:31 +01:00
Vadym Samoilenko
746cd42f6c fix: restrict camera control to supported models; update model list
Camera/motion control is only supported by kling-v1, kling-v1-5,
kling-v3, kling-v3-omni. Backend silently drops the camera_control
field for all other models. Frontend hides the camera control UI
and auto-clears the selection when switching to an unsupported model.

New models added: kling-v3-omni, kling-video-o1, kling-v1 (cam ctrl),
kling-v2-master. Duration validation loosened for v3/v3-omni (3-15s).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:35:34 +01:00
Vadym Samoilenko
fa7c67af6a refactor: move video prompt optimization to backend
Client-side Gemini calls were hitting the frontend API key's rate limits
and exposing the key in the browser. The optimizer now POSTs to
video_api.php (action=optimize_prompt) which calls Gemini server-side
using the backend key.

Rate-limited responses (429) silently fall back to the simple prompt
generator without showing an error.

Removes the @google/generative-ai import from VideoGenTab.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:32:30 +01:00
Vadym Samoilenko
5a17565731 fix: Kling I2V uses image/image_tail fields with clean base64
Kling image2video endpoint expects:
  image: "<base64>" (no data URI prefix)
  image_tail: "<base64>" (optional, for interpolation)

Not image_url/image_tail_url with data URIs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:27:58 +01:00
Vadym Samoilenko
68690b819a fix: durationSeconds must be integer not string in Veo API
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:24:47 +01:00
Vadym Samoilenko
dbe5ef3f11 fix: revert Veo I2V image format to bytesBase64Encoded
The Veo predictLongRunning endpoint is a predict-style API (not
generateContent) and expects image data as:
  { "bytesBase64Encoded": "...", "mimeType": "image/jpeg" }

The previous session switched it to inlineData (generateContent format),
causing the API to reject it with:
  "inlineData isn't supported by this model"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:23:32 +01:00
Vadym Samoilenko
866ff126d7 fix: nginx client_max_body_size 100M + silent 429 fallback
nginx inside the Docker container defaults to 1MB body limit —
base64 image payloads exceed this and return a 413 HTML page,
causing the "Unexpected token '<'" JSON parse error on video_api.php.

Gemini 429 rate limit errors on prompt optimization now fall back
silently instead of surfacing an error to the user.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:21:36 +01:00
Vadym Samoilenko
59e71b0bcc fix: safer deploy — build first, up only on success, --no-cache
Old: `up -d --build` stops old container before building → if build fails, service is down
New:
  1. `build --no-cache` — full rebuild, fails without touching running container
  2. `up -d --force-recreate` — only runs if build succeeded
  3. health check after start to catch silent failures

--no-cache ensures PHP/JS file changes are always picked up (no stale layer cache)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:16:33 +01:00
Vadym Samoilenko
c030b47fcf fix: upgrade prompt optimizer to gemini-2.0-flash
gemini-2.0-flash-lite has lower RPM limits even on paid plans.
gemini-2.0-flash has higher quotas and better quality optimization.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:14:24 +01:00
Vadym Samoilenko
53c4e9f8a3 fix: GD safety check + zlib-dev for robust Alpine build
- video_api.php: check function_exists('imagecreatefromstring') before calling GD
  — undefined function causes PHP fatal error even with @ suppressor, kills php-fpm
- Dockerfile: add zlib-dev (required for libpng on some Alpine versions)
- Dockerfile: verify GD loaded after install (build log confirmation)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 18:09:54 +01:00
Vadym Samoilenko
e43432e08c fix: correct Kling and Veo API parameter formats
Kling:
- camera_control.type: use preset name directly (down_back etc.), not 'predefined'
- camera_control.config: all 6 integer fields required even for preset types
- duration: cast to integer (API rejects strings)
- I2V images: use image_url/image_tail_url with data URI prefix (not plain base64 in image/image_tail)

Veo:
- image/lastFrame: use inlineData format (Gemini API), not bytesBase64Encoded (Vertex AI)
- durationSeconds: send as string "4"/"6"/"8", not integer

Docker:
- Add uploads.ini: post_max_size=100M, upload_max_filesize=100M, memory_limit=512M
  (ini_set cannot override these at runtime in php-fpm)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:59:56 +01:00
Vadym Samoilenko
07aa52438c fix: accept any relative URL for Kling video validation
After changing the video URL prefix to /lux-studio/api/generated_videos/,
the old /generated_videos/ check caused a false-positive validation error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:42:25 +01:00
Vadym Samoilenko
3f10b53f9c fix: add GD extension, fix Kling video URLs and undefined variable
- Dockerfile: install GD (libpng + libjpeg) for Veo I2V image resizing
- Dockerfile: create generated_videos/ dir with write permissions
- kling_api.php: fix video URL /generated_videos/ → /lux-studio/api/generated_videos/ (nginx couldn't find files at old path)
- kling_api.php: fix undefined \$path → \$endpoint in error log

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:27:12 +01:00
Vadym Samoilenko
f221c33773 fix: add config.php and unignore it so Docker builds include it
All backend PHP files require config.php as their first include.
It was gitignored and missing, causing PHP fatal errors that produced
empty responses — breaking JSON parsing in the frontend.

The new config.php has no hardcoded secrets; it reads all values
(GEMINI_API_KEY, KLING_ACCESS_KEY, KLING_SECRET_KEY, SSO_*) from
the .env file via env_loader.php.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:12:38 +01:00
Vadym Samoilenko
8c91232f30 fix: overwrite .env.production with .env.optical in Docker build
Vite loads .env.production with higher priority than .env in production
mode — optical URLs were being overridden by ai-sandbox values.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:30:26 +01:00
Vadym Samoilenko
498b667903 fix: copy PHP files before composer install (classmap needs them)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:20:41 +01:00
Vadym Samoilenko
234b13ee31 fix: use --no-security-blocking for older composer version
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:20:02 +01:00
Vadym Samoilenko
5591d46397 fix: skip composer audit for firebase/php-jwt advisory (SSO disabled)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:19:12 +01:00
Vadym Samoilenko
db4322bcd7 fix: rewrite deploy-optical.sh for Docker Compose pattern
git pull → docker compose up --build → Apache include (idempotent) → reload.
No longer assumes PHP/Node on host; runs without sudo except Apache steps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:17:56 +01:00
Vadym Samoilenko
03671abcaa feat: add Docker setup for optical-prod deployment
Multi-stage Dockerfile (node:20 builder + php:8.2-fpm-alpine runtime),
nginx serving frontend SPA + PHP-FPM backend at /lux-studio/, supervisord
managing both processes. docker-compose.prod.yml on port 8085, .env.optical
mounted read-only, uploads in a named volume.
Apache include at deploy/apache-lux-studio.conf proxies /lux-studio/ → :8085.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:13:52 +01:00
Vadym Samoilenko
18cc2aa869 config: update Azure AD Client ID and add optical-dev deployment
Replace old SSO Client IDs with new IT-provisioned ID (a321d54f) across
all env templates and CLAUDE.md. Add frontend/.env.optical, backend/.env.optical,
and deploy-optical.sh targeting optical-prod.oliver.solutions/lux-studio/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:06:24 +01:00
Simeon.Schecter
95e6946807 feat: Kling integration, prompt optimizer rework, and stability fixes
Kling video generation:
- Full T2V, I2V, extend, and lip sync workflows via Kling API
- V3, V2.6, V2.5 Turbo, V2.1 Master, V1.6 model support
- Resolution selector (720p std / 1080p pro) with model constraints
- Native audio toggle with dialogue input for Kling
- Video ID tracking for extend and lip sync chains
- Camera control presets (pan, tilt, arc)

Prompt optimizer rework:
- Intent-preserving refinement (camera, action, mood are sacred)
- Mode-aware: T2V adds subject/environment detail, I2V describes only motion
- Reference images analyzed for content, not re-described
- Platform-specific quality anchors woven into positive prompt
- Negative prompts removed from optimizer (positive-only approach)
- 15-60 word target for concise, effective prompts

Backend fixes:
- Gemini responseModalities: ['TEXT', 'IMAGE'] for Flash model compatibility
- Veo first-frame resize to exact target dimensions (prevents letterboxing)
- Session directory re-creation in saveImage (auto-cleanup race condition)
- Kling API error logging with HTTP codes and payload details
- Lip sync endpoint updated to /v1/videos/lip-sync with video_id

Frontend stability:
- Tab persistence via CSS hidden (generation survives tab switches)
- Project switch protection (confirm dialog when generation in progress)
- Retina thumbnails (480px/q0.8) for library grid — prevents OOM crashes
- Thumbnail backfill migration for existing project items
- Project items refresh on tab visibility and after save
- 1:1 aspect ratio container for Kling videos
- Expanded video view matches library modal behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 21:51:03 -04:00
Simeon.Schecter
696d8a985c style: tabs flush left with generous logo spacing, bump to 14px
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:46:10 -04:00
Simeon.Schecter
0fdb43fecf style: simplify storyboard exports — let the images speak
PNG: Remove card backgrounds, borders, header bars, and empty
annotation text. Just images in a grid with a small frame number.

PDF: Reduce margins and label reservation to maximize image size.
Frame number and annotation condensed to one small line below.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:44:46 -04:00
Simeon.Schecter
b94c5c6b2a style: separate tabs from logo, spread across header
Tabs now float between logo and user info via justify-between,
giving the logo more breathing room.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:40:15 -04:00
Simeon.Schecter
a7d409b7fc style: remove icons from tab navigation, text only
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:39:05 -04:00
Simeon.Schecter
390450d873 style: try IBM Plex Sans + IBM Plex Mono as unified family
Matched sans+mono from same family. More Univers-like, technical.
Previous commit (6c47a79) has Space Grotesk for comparison.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:37:43 -04:00
Simeon.Schecter
6c47a7967f style: switch primary typeface from DM Sans to Space Grotesk
Geometric grotesque with equipment personality. Keeps JetBrains Mono
for data text. Base size stays 12px.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:35:29 -04:00
Simeon.Schecter
5ad83aca48 style: reduce base font size from 13px to 12px
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:29:52 -04:00
Simeon.Schecter
02dd46e9d7 style: modals use bg-slate-800 to pop above dark overlay
Slate-925 panels are nearly invisible against black/60 overlays.
Modals need to be clearly visible, so they use slate-800.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:26:57 -04:00
Simeon.Schecter
b522f94ca9 style: minimize panel contrast — slate-925 panels on slate-950 ground
Custom slate-925 (#080d1b) sits just one shade above the 950 ground,
making panels barely visible. The content is the interface, not the
chrome. Reverts the inverted-depth experiment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:23:44 -04:00
Simeon.Schecter
43833d7474 style: invert depth — lighter surround, darker content wells
Page ground from bg-slate-950 to bg-slate-800. Content panels stay
bg-slate-900, creating inset wells rather than floating cards.
Like a Braun control panel with recessed dark areas.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:21:20 -04:00
Simeon.Schecter
2a52106ba0 style: restore uppercase tracking on section labels in Image/Video Gen
Zone markers (Preset, Camera Body, Lens Kit, Duration, etc.) get
uppercase + wide tracking like Braun hi-fi category labels. Modal
form labels and interactive toggles stay sentence case.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:19:30 -04:00
Simeon.Schecter
efe5757edf style: add JetBrains Mono for data/spec text
Second typographic voice for timestamps, dimensions, file sizes,
session IDs, costs, word counts, resolution specs, and version number.
Like lens barrel markings — the data speaks in mono, the UI in sans.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:15:05 -04:00
Simeon.Schecter
addce12347 style: reduce base font size from 14px to 13px
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:08:39 -04:00
Simeon.Schecter
a096cd8d88 style: standardize backgrounds to strict 5-tone scale (950/900/800/700/600)
Remove all opacity variants (bg-slate-900/50, bg-slate-800/50, etc.) in
favor of opaque tones. Inputs standardized to bg-slate-800 (Elevated).
hover:bg-slate-800 promoted to hover:bg-slate-700 (Interactive tier).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:06:34 -04:00
Simeon.Schecter
fdfb8ceb2e style: restore purple Optimize button in Image Gen and Video Gen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:00:28 -04:00
Simeon.Schecter
7051d260fe style: remove tab underline indicator, let type color speak
Active tab is already distinguished by gold text color. The
underline was redundant decoration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:56:55 -04:00
Simeon.Schecter
af3f8f0536 style: revert toggle buttons back to gold
Off-white toggles did not improve things -- gold selected state
was already working well. Reverts 4c4c857.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:55:28 -04:00
Simeon.Schecter
4c4c8575e5 style: change selected toggle buttons from gold to off-white
Replace bg-cinema-gold with bg-slate-200 on all 21 toggle/selector
buttons. Gold now reserved exclusively for primary CTA buttons
(Generate Image, Generate Video). Creates quieter UI that lets
generated images and video stand out.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:52:57 -04:00
Simeon.Schecter
036884bf91 style: remove decorative borders, keep only functional ones
Strip panel/card wrapper borders, section separator borders, tooltip
borders, and modal borders. Remaining borders are all functional:
input fields, focus states, status indicators (green/red/amber),
dashed upload zones, active selection states, and type badges.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:50:20 -04:00
Simeon.Schecter
c5002b8c6b style: drop all type weight from medium (500) to normal (400)
DM Sans at weight 400 is clean and readable — hierarchy now comes
entirely from size, not weight. Lighter overall feel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:44:32 -04:00
Simeon.Schecter
0093b6dc92 style: Rams refinement on ProjectsTab
Thin font weights, tighten border radii, remove dropdown shadows,
strip uppercase from section headers, flatten video placeholder
gradient, replace indigo/purple action buttons with neutral slate,
consolidate move/select toggles to cinema-gold. Keep type badges
(IMG/VID/KLING) as functional color indicators.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:33:48 -04:00
Simeon.Schecter
c5dcc68056 style: Rams refinement on VideoGenTab
Strip uppercase+tracking from all labels, thin font weights to medium,
tighten all border radii, replace indigo-to-purple gradient with neutral
slate button, flatten container gradient, consolidate indigo workflow
selector to cinema-gold, remove all indigo color references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:31:53 -04:00
Simeon.Schecter
f1315a1662 style: Rams refinement on CinePromptStudio
Strip uppercase+tracking from all labels, thin font-bold to font-medium,
tighten all border radii, replace indigo-to-purple gradient with neutral
slate button, remove tooltip shadow, consolidate purple focus mode badge
to slate, remove decorative hover:scale on copy button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:30:14 -04:00
Simeon.Schecter
d8c6f8db29 style: Rams refinement on VideoPlayer and StoryboardEditor
Tighten border radius (rounded-xl/lg→rounded), remove decorative
shadows, replace indigo Generate Video button with neutral slate,
thin heading font weights to medium.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:28:44 -04:00
Simeon.Schecter
6ba469c7b9 style: Rams refinement on LoginPage and AppContent
Thin font weights (bold→medium, semibold→medium), tighten border
radius (rounded-lg→rounded), reduce shadow (xl→sm) on login card.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:27:31 -04:00
Simeon.Schecter
c7ec58ff7f style: add DM Sans font and 14px base sizing
Switch from system font stack to DM Sans (Google Fonts, variable weight)
and reduce base font-size to 14px for a more compact, professional feel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:27:02 -04:00