Implement complete AI Photo Edit tool with mask-scoped regeneration

This commit implements a full-stack AI photo editing application that
allows users to regenerate only selected areas of images using AI.

Features implemented:
- Frontend (React + Fabric.js):
  * Interactive canvas with selection tools (rectangle, ellipse, lasso)
  * Real-time selection preview and editing
  * Mode toggle (A: patch only, B: patch + context)
  * Feather slider for edge blending (0-50px)
  * Prompt input for AI instructions
  * Edit history viewer with revert capability
  * Responsive UI with dark theme

- Backend (FastAPI):
  * RESTful API for projects and edits
  * SQLite database for metadata storage
  * Image processing pipeline with PIL/OpenCV
  * AI provider interface (pluggable)
  * Support for OpenAI, Stability AI, and mock providers
  * Feathered alpha blending for smooth compositing
  * Complete edit history tracking
  * File-based storage for images and edits

- Image Processing:
  * Patch extraction from bounding boxes
  * Mask generation for all selection types
  * Feathered edge blending
  * Patch compositing back to full image
  * No pixels modified outside selection
  * All edits reversible

- Infrastructure:
  * Docker Compose orchestration
  * Production and development configurations
  * Nginx reverse proxy for frontend
  * Hot-reload support for development
  * Volume persistence for data

Architecture follows specification exactly:
- Only selected regions are regenerated
- Full image pixels preserved outside mask
- Two-mode operation (cost vs quality)
- Complete edit history and reversibility
- Self-hosted with external AI API calls

All components are fully functional and ready for deployment.
This commit is contained in:
Claude
2026-01-24 02:58:41 +00:00
parent 8cea0a382e
commit c8078d4652
47 changed files with 3471 additions and 1 deletions
+112
View File
@@ -0,0 +1,112 @@
.app {
min-height: 100vh;
background-color: #1a1a1a;
}
.error-banner {
background-color: #ff4444;
color: white;
padding: 12px 16px;
border-radius: 6px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.error-banner button {
background: none;
color: white;
font-size: 20px;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.project-setup {
max-width: 600px;
margin: 0 auto;
padding: 40px;
background-color: #2a2a2a;
border-radius: 8px;
border: 1px solid #444;
}
.project-setup h2 {
font-size: 24px;
margin-bottom: 24px;
text-align: center;
}
.setup-form {
display: flex;
flex-direction: column;
gap: 20px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.form-group label {
font-size: 14px;
font-weight: 600;
color: #cccccc;
}
.form-group input {
width: 100%;
}
.file-name {
font-size: 12px;
color: #00ff00;
margin-top: 4px;
}
.create-project-btn {
background-color: #0066ff;
color: white;
padding: 14px 20px;
font-size: 16px;
font-weight: 600;
margin-top: 10px;
}
.create-project-btn:hover:not(:disabled) {
background-color: #0055dd;
}
.workspace {
display: grid;
grid-template-columns: 1fr 400px;
gap: 20px;
min-height: 600px;
}
@media (max-width: 1200px) {
.workspace {
grid-template-columns: 1fr;
}
}
.left-panel {
display: flex;
flex-direction: column;
}
.right-panel {
display: flex;
flex-direction: column;
gap: 20px;
}
.history-wrapper {
flex: 1;
min-height: 0;
}