Add automatic API documentation system with OpenAPI 3.0 spec
## Features Added: - **Automatic Documentation Generation**: Uses next-swagger-doc to scan API routes - **Interactive Swagger UI**: Try-it-out functionality for testing endpoints - **OpenAPI 3.0 Specification**: Industry-standard API documentation format - **Comprehensive Schemas**: Type definitions for all request/response objects ## New Documentation System: - `/docs` - Interactive Swagger UI documentation page - `/api/docs` - OpenAPI specification JSON endpoint - `src/lib/swagger.ts` - Documentation configuration and schemas - Complete JSDoc examples for batch classification endpoint ## Documentation Features: - Real-time API testing from documentation interface - Detailed request/response examples and schemas - Parameter validation and error response documentation - Organized by tags (Classification, Captioning, Tags, etc.) - Dark/light mode support with loading states ## AI Roadmap & Guides: - `AIROADMAP.md` - Comprehensive roadmap for future AI enhancements - `API_DOCUMENTATION.md` - Complete guide for maintaining documentation ## Benefits: - Documentation stays automatically synchronized with code changes - No separate docs to maintain - generated from JSDoc comments - Professional API documentation for integration and development - Export capabilities for Postman, Insomnia, and other tools 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
85c1479d94
commit
a204168c00
197
AIROADMAP.md
Normal file
197
AIROADMAP.md
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
# AI Roadmap for Photo Tagging, Classification, and Search
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
- ✅ **Dual-Model Classification**: ViT (objects) + CLIP (style/artistic concepts)
|
||||||
|
- ✅ **Image Captioning**: BLIP for natural language descriptions
|
||||||
|
- ✅ **Batch Processing**: Auto-tag and caption entire photo libraries
|
||||||
|
- ✅ **Tag Management**: Create, clear, and organize tags with UI
|
||||||
|
- ✅ **Performance Optimized**: Thumbnail-first processing with fallbacks
|
||||||
|
|
||||||
|
## Phase 1: Enhanced Classification Models (Q1 2024)
|
||||||
|
|
||||||
|
### 1.1 Specialized Domain Models
|
||||||
|
- **Face Recognition**: Add `Xenova/face-detection` for person identification
|
||||||
|
- Detect and count faces in photos
|
||||||
|
- Age/gender estimation capabilities
|
||||||
|
- Group photos by detected people
|
||||||
|
- **Scene Classification**: `Xenova/vit-base-patch16-224-scene`
|
||||||
|
- Indoor vs outdoor scene detection
|
||||||
|
- Specific location types (kitchen, bedroom, park, etc.)
|
||||||
|
- **Emotion Detection**: Face-based emotion classification
|
||||||
|
- Happy, sad, surprised, etc. from facial expressions
|
||||||
|
|
||||||
|
### 1.2 Multi-Modal Understanding
|
||||||
|
- **OCR Integration**: `Xenova/trocr-base-printed` for text in images
|
||||||
|
- Extract text from signs, documents, screenshots
|
||||||
|
- Automatic tagging based on detected text content
|
||||||
|
- **Color Analysis**: Implement dominant color extraction
|
||||||
|
- Tag photos by color palette (warm, cool, monochrome)
|
||||||
|
- Season detection based on color analysis
|
||||||
|
- **Quality Assessment**: Technical photo quality scoring
|
||||||
|
- Blur detection, exposure analysis, composition scoring
|
||||||
|
|
||||||
|
### 1.3 Fine-tuned Photography Models
|
||||||
|
- **Photography-Specific CLIP**: Train on photography datasets
|
||||||
|
- Better understanding of camera techniques
|
||||||
|
- Lens types, shooting modes, creative effects
|
||||||
|
- **Art Style Classification**: Historical and contemporary art styles
|
||||||
|
- Renaissance, Impressionist, Modern, Street Art, etc.
|
||||||
|
|
||||||
|
## Phase 2: Advanced Search and Discovery (Q2 2024)
|
||||||
|
|
||||||
|
### 2.1 Semantic Search
|
||||||
|
- **Vector Embeddings**: Store CLIP embeddings for each photo
|
||||||
|
- Enable "find similar photos" functionality
|
||||||
|
- Search by natural language descriptions
|
||||||
|
- **Hybrid Search**: Combine text search with visual similarity
|
||||||
|
- "Find beach photos that look like this sunset"
|
||||||
|
- Cross-modal search capabilities
|
||||||
|
|
||||||
|
### 2.2 Intelligent Grouping
|
||||||
|
- **Event Detection**: Group photos by time/location/people
|
||||||
|
- Automatic album creation for trips, parties, holidays
|
||||||
|
- **Duplicate Detection**: Advanced perceptual hashing
|
||||||
|
- Find near-duplicates and variations
|
||||||
|
- Suggest best photo from similar shots
|
||||||
|
- **Series Recognition**: Detect photo sequences/bursts
|
||||||
|
- Panorama detection, HDR sequences, time-lapses
|
||||||
|
|
||||||
|
### 2.3 Content-Aware Filtering
|
||||||
|
- **Smart Collections**: AI-generated photo collections
|
||||||
|
- "Best portraits", "Golden hour photos", "Action shots"
|
||||||
|
- **Contextual Recommendations**: Suggest photos based on current view
|
||||||
|
- "More photos like this", "From the same event"
|
||||||
|
- **Quality Filtering**: Automatically hide blurry/poor quality photos
|
||||||
|
|
||||||
|
## Phase 3: Personalized AI Assistant (Q3 2024)
|
||||||
|
|
||||||
|
### 3.1 Learning User Preferences
|
||||||
|
- **Favorite Detection**: Learn what makes users favorite photos
|
||||||
|
- Personalized quality scoring
|
||||||
|
- Suggest photos to review/favorite
|
||||||
|
- **Custom Label Training**: User-specific classification
|
||||||
|
- Train on user's existing tags
|
||||||
|
- Recognize personal objects, places, people
|
||||||
|
|
||||||
|
### 3.2 Interactive Tagging
|
||||||
|
- **Tag Suggestions**: AI-powered tag recommendations during manual tagging
|
||||||
|
- **Batch Validation**: Review and approve AI-generated tags
|
||||||
|
- Confidence scoring with user feedback loop
|
||||||
|
- **Active Learning**: Improve models based on user corrections
|
||||||
|
|
||||||
|
### 3.3 Natural Language Interface
|
||||||
|
- **Query Understanding**: Parse complex natural language searches
|
||||||
|
- "Show me outdoor photos from last summer with more than 3 people"
|
||||||
|
- **Photo Descriptions**: Generate detailed alt-text for accessibility
|
||||||
|
- **Story Generation**: Create narratives from photo sequences
|
||||||
|
|
||||||
|
## Phase 4: Advanced Computer Vision (Q4 2024)
|
||||||
|
|
||||||
|
### 4.1 Object Detection and Segmentation
|
||||||
|
- **YOLO Integration**: `Xenova/yolov8n` for precise object detection
|
||||||
|
- Bounding boxes around detected objects
|
||||||
|
- Count objects in photos (5 people, 3 cars, etc.)
|
||||||
|
- **Segmentation Models**: `Xenova/sam-vit-base` for object segmentation
|
||||||
|
- Extract individual objects from photos
|
||||||
|
- Background removal capabilities
|
||||||
|
|
||||||
|
### 4.2 Spatial Understanding
|
||||||
|
- **Depth Estimation**: `Xenova/dpt-large` for depth perception
|
||||||
|
- Understand 3D structure of photos
|
||||||
|
- Foreground/background classification
|
||||||
|
- **Pose Estimation**: Human pose detection in photos
|
||||||
|
- Activity recognition (running, sitting, dancing)
|
||||||
|
- Sports/exercise classification
|
||||||
|
|
||||||
|
### 4.3 Temporal Analysis
|
||||||
|
- **Video Frame Analysis**: Extract keyframes from videos
|
||||||
|
- Apply photo AI models to video content
|
||||||
|
- **Motion Detection**: Analyze camera movement and subject motion
|
||||||
|
- **Sequence Understanding**: Understand photo relationships over time
|
||||||
|
|
||||||
|
## Phase 5: Multimodal AI Integration (2025)
|
||||||
|
|
||||||
|
### 5.1 Audio-Visual Analysis
|
||||||
|
- **Audio Classification**: For photos with associated audio/video
|
||||||
|
- Environment sounds, music, speech detection
|
||||||
|
- **Cross-Modal Retrieval**: Search photos using audio descriptions
|
||||||
|
|
||||||
|
### 5.2 3D Understanding
|
||||||
|
- **Stereo Vision**: Process photo pairs for depth information
|
||||||
|
- **3D Scene Reconstruction**: Build 3D models from photo sequences
|
||||||
|
- **AR/VR Integration**: Spatial photo organization in 3D space
|
||||||
|
|
||||||
|
### 5.3 Advanced Generation
|
||||||
|
- **Style Transfer**: Apply artistic styles to photos locally
|
||||||
|
- **Photo Enhancement**: AI-powered photo improvement
|
||||||
|
- Denoising, super-resolution, colorization
|
||||||
|
- **Creative Variants**: Generate artistic variations of photos
|
||||||
|
|
||||||
|
## Technical Implementation Strategy
|
||||||
|
|
||||||
|
### Model Selection Criteria
|
||||||
|
1. **Size Constraints**: Prioritize smaller models (<500MB each)
|
||||||
|
2. **Performance**: Ensure real-time processing on consumer hardware
|
||||||
|
3. **Accuracy**: Balance model size vs classification quality
|
||||||
|
4. **Compatibility**: Ensure Transformers.js support
|
||||||
|
|
||||||
|
### Infrastructure Enhancements
|
||||||
|
- **Model Caching**: Intelligent model loading/unloading
|
||||||
|
- **Web Workers**: Background processing to maintain UI responsiveness
|
||||||
|
- **Progressive Loading**: Load models on-demand based on user actions
|
||||||
|
- **Offline Support**: Full functionality without internet connection
|
||||||
|
|
||||||
|
### Data Management
|
||||||
|
- **Embedding Storage**: Efficient vector storage for similarity search
|
||||||
|
- **Incremental Processing**: Process only new/changed photos
|
||||||
|
- **Backup Integration**: Sync AI-generated metadata across devices
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
### User Experience
|
||||||
|
- **Search Accuracy**: Percentage of successful photo searches
|
||||||
|
- **Tagging Efficiency**: Reduction in manual tagging time
|
||||||
|
- **Discovery Rate**: How often users find unexpected relevant photos
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- **Processing Speed**: Photos processed per minute
|
||||||
|
- **Memory Usage**: RAM consumption during batch operations
|
||||||
|
- **Model Load Time**: Time to initialize AI models
|
||||||
|
|
||||||
|
### Quality
|
||||||
|
- **Tag Precision**: Accuracy of automatically generated tags
|
||||||
|
- **User Satisfaction**: Approval rate of AI suggestions
|
||||||
|
- **Coverage**: Percentage of photos with meaningful tags
|
||||||
|
|
||||||
|
## Resource Requirements
|
||||||
|
|
||||||
|
### Development
|
||||||
|
- **Model Research**: Evaluate and test new Transformers.js models
|
||||||
|
- **Performance Optimization**: GPU acceleration, WebGL optimizations
|
||||||
|
- **UI/UX Design**: Intuitive interfaces for AI-powered features
|
||||||
|
|
||||||
|
### Infrastructure
|
||||||
|
- **Testing Framework**: Automated testing for AI model accuracy
|
||||||
|
- **Benchmarking**: Performance testing across different hardware
|
||||||
|
- **Documentation**: User guides for AI features
|
||||||
|
|
||||||
|
## Risk Mitigation
|
||||||
|
|
||||||
|
### Privacy & Security
|
||||||
|
- **Local Processing**: All AI models run locally, no data leaves device
|
||||||
|
- **Data Encryption**: Encrypt AI-generated metadata
|
||||||
|
- **User Control**: Always allow manual override of AI decisions
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- **Graceful Degradation**: Fallback to simpler models on low-end devices
|
||||||
|
- **Memory Management**: Prevent out-of-memory errors during batch processing
|
||||||
|
- **User Feedback**: Clear progress indicators and cancellation options
|
||||||
|
|
||||||
|
### Model Updates
|
||||||
|
- **Backward Compatibility**: Ensure new models work with existing data
|
||||||
|
- **Migration Tools**: Convert between different model outputs
|
||||||
|
- **Version Management**: Track which AI models generated which tags
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This roadmap prioritizes **local-first AI** with no cloud dependencies, ensuring privacy while delivering powerful photo organization capabilities. Each phase builds upon previous work while introducing new capabilities for comprehensive photo understanding and search.
|
198
API_DOCUMENTATION.md
Normal file
198
API_DOCUMENTATION.md
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
# API Documentation Setup Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
I've set up **automatic API documentation** using `next-swagger-doc` that stays in sync with your code changes. Here's how it works:
|
||||||
|
|
||||||
|
## ✅ What's Implemented
|
||||||
|
|
||||||
|
### 1. **Documentation Generator** (`src/lib/swagger.ts`)
|
||||||
|
- Automatically scans your API routes in `src/app/api/`
|
||||||
|
- Generates OpenAPI 3.0 spec from JSDoc comments
|
||||||
|
- Includes all schemas, examples, and descriptions
|
||||||
|
|
||||||
|
### 2. **Documentation Viewer** (`/api/docs/page`)
|
||||||
|
- Interactive Swagger UI interface
|
||||||
|
- Try-it-out functionality for testing endpoints
|
||||||
|
- Dark/light mode support
|
||||||
|
|
||||||
|
### 3. **API Endpoint** (`/api/docs`)
|
||||||
|
- Serves the generated OpenAPI spec as JSON
|
||||||
|
- Can be consumed by external tools
|
||||||
|
|
||||||
|
## 🚀 Usage
|
||||||
|
|
||||||
|
### Access Documentation
|
||||||
|
Visit `http://localhost:3000/api/docs/page` to see your interactive API documentation.
|
||||||
|
|
||||||
|
### Add Documentation to New Routes
|
||||||
|
|
||||||
|
Add JSDoc comments above your route handlers:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/your-endpoint:
|
||||||
|
* post:
|
||||||
|
* summary: Brief description of what this endpoint does
|
||||||
|
* description: Detailed description with more context
|
||||||
|
* tags: [YourTag]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* param1: { type: 'string', description: 'Parameter description' }
|
||||||
|
* param2: { type: 'number', minimum: 0, maximum: 1 }
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success response
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* result: { type: 'string' }
|
||||||
|
* 400:
|
||||||
|
* description: Bad request
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Error'
|
||||||
|
*/
|
||||||
|
export async function POST(request: NextRequest) {
|
||||||
|
// Your route handler code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 Example Documentation
|
||||||
|
|
||||||
|
I've already documented the **batch classification endpoint** as an example:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/classify/batch:
|
||||||
|
* post:
|
||||||
|
* summary: Batch classify photos using AI models
|
||||||
|
* description: Process multiple photos with AI classification using ViT for objects and optionally CLIP for artistic/style concepts.
|
||||||
|
* tags: [Classification]
|
||||||
|
* requestBody:
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/BatchClassifyRequest'
|
||||||
|
* examples:
|
||||||
|
* basic:
|
||||||
|
* summary: Basic batch classification
|
||||||
|
* value:
|
||||||
|
* limit: 10
|
||||||
|
* minConfidence: 0.3
|
||||||
|
* onlyUntagged: true
|
||||||
|
* comprehensive:
|
||||||
|
* summary: Comprehensive mode with dual models
|
||||||
|
* value:
|
||||||
|
* comprehensive: true
|
||||||
|
* minConfidence: 0.05
|
||||||
|
* maxResults: 25
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Benefits
|
||||||
|
|
||||||
|
### 1. **Always Up-to-Date**
|
||||||
|
- Documentation is generated from your actual code
|
||||||
|
- No separate docs to maintain
|
||||||
|
- Automatically reflects API changes
|
||||||
|
|
||||||
|
### 2. **Interactive Testing**
|
||||||
|
- Built-in "Try it out" functionality
|
||||||
|
- Test endpoints directly from documentation
|
||||||
|
- See real request/response examples
|
||||||
|
|
||||||
|
### 3. **Developer Experience**
|
||||||
|
- Comprehensive schemas and examples
|
||||||
|
- Clear parameter descriptions
|
||||||
|
- Error response documentation
|
||||||
|
|
||||||
|
### 4. **Integration Ready**
|
||||||
|
- Standard OpenAPI 3.0 format
|
||||||
|
- Can be imported into Postman, Insomnia
|
||||||
|
- Works with code generators
|
||||||
|
|
||||||
|
## 🔧 Extending Documentation
|
||||||
|
|
||||||
|
### Add More Route Documentation
|
||||||
|
|
||||||
|
For each API route, add JSDoc comments with:
|
||||||
|
|
||||||
|
1. **Summary**: One-line description
|
||||||
|
2. **Description**: Detailed explanation
|
||||||
|
3. **Tags**: Group related endpoints
|
||||||
|
4. **Parameters**: Query parameters, path parameters
|
||||||
|
5. **Request Body**: Expected input schema
|
||||||
|
6. **Responses**: All possible response codes and schemas
|
||||||
|
7. **Examples**: Real usage examples
|
||||||
|
|
||||||
|
### Custom Schemas
|
||||||
|
|
||||||
|
Define reusable schemas in `src/lib/swagger.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
YourCustomSchema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string', description: 'Unique identifier' },
|
||||||
|
name: { type: 'string', description: 'Display name' }
|
||||||
|
},
|
||||||
|
required: ['id', 'name']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples with Multiple Scenarios
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
examples:
|
||||||
|
basic_usage:
|
||||||
|
summary: Basic usage
|
||||||
|
value: { param: "value" }
|
||||||
|
advanced_usage:
|
||||||
|
summary: Advanced with all options
|
||||||
|
value: { param: "value", advanced: true }
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎨 Customization
|
||||||
|
|
||||||
|
### Styling
|
||||||
|
- Documentation UI automatically matches your app's theme
|
||||||
|
- Supports dark/light mode switching
|
||||||
|
|
||||||
|
### Organization
|
||||||
|
- Use **tags** to group related endpoints
|
||||||
|
- Order endpoints by adding them to the `tags` array in swagger.ts
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
- Add authentication schemas when needed
|
||||||
|
- Document API keys, bearer tokens, etc.
|
||||||
|
|
||||||
|
## 📝 Next Steps
|
||||||
|
|
||||||
|
1. **Document Remaining Routes**: Add JSDoc comments to all your API endpoints
|
||||||
|
2. **Add Examples**: Include realistic request/response examples
|
||||||
|
3. **Test Documentation**: Use the interactive UI to verify all endpoints work
|
||||||
|
4. **Export for External Use**: Generate OpenAPI spec for Postman/other tools
|
||||||
|
|
||||||
|
## 🚨 Important Notes
|
||||||
|
|
||||||
|
- The documentation page is at `/api/docs/page` (not just `/api/docs`)
|
||||||
|
- Swagger UI requires client-side rendering, so it's in the `page.tsx` file
|
||||||
|
- The generator automatically scans all files in `src/app/api/` for JSDoc comments
|
||||||
|
- Restart the dev server after adding new documentation to see changes
|
||||||
|
|
||||||
|
Your API documentation will automatically stay in sync as you develop new features! 🎉
|
@ -36,4 +36,5 @@
|
|||||||
|
|
||||||
# Audit
|
# Audit
|
||||||
- When asked if there are libraries to accomblish custom functionality, check npm
|
- When asked if there are libraries to accomblish custom functionality, check npm
|
||||||
- When asked for alternatives give multiple options with pros and cons
|
- When asked for alternatives give multiple options with pros and cons
|
||||||
|
- don't change any code unless I confirm
|
3391
package-lock.json
generated
3391
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -20,10 +20,13 @@
|
|||||||
"exif-reader": "^2.0.2",
|
"exif-reader": "^2.0.2",
|
||||||
"glob": "^11.0.3",
|
"glob": "^11.0.3",
|
||||||
"next": "^15.5.0",
|
"next": "^15.5.0",
|
||||||
|
"next-swagger-doc": "^0.4.1",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"react-share": "^5.2.2",
|
"react-share": "^5.2.2",
|
||||||
"sharp": "^0.34.3"
|
"redoc": "^2.5.0",
|
||||||
|
"sharp": "^0.34.3",
|
||||||
|
"swagger-ui-react": "^5.27.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.12",
|
"@tailwindcss/postcss": "^4.1.12",
|
||||||
|
@ -24,6 +24,76 @@ interface BatchClassifyRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/classify/batch:
|
||||||
|
* post:
|
||||||
|
* summary: Batch classify photos using AI models
|
||||||
|
* description: Process multiple photos with AI classification using ViT for objects and optionally CLIP for artistic/style concepts. Supports comprehensive mode for maximum tag diversity.
|
||||||
|
* tags: [Classification]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/BatchClassifyRequest'
|
||||||
|
* examples:
|
||||||
|
* basic:
|
||||||
|
* summary: Basic batch classification
|
||||||
|
* value:
|
||||||
|
* limit: 10
|
||||||
|
* minConfidence: 0.3
|
||||||
|
* onlyUntagged: true
|
||||||
|
* comprehensive:
|
||||||
|
* summary: Comprehensive mode with dual models
|
||||||
|
* value:
|
||||||
|
* limit: 5
|
||||||
|
* comprehensive: true
|
||||||
|
* minConfidence: 0.05
|
||||||
|
* maxResults: 25
|
||||||
|
* onlyUntagged: true
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Classification results with summary statistics
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* summary:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* processed: { type: 'integer', description: 'Number of photos processed' }
|
||||||
|
* successful: { type: 'integer', description: 'Number of successful classifications' }
|
||||||
|
* failed: { type: 'integer', description: 'Number of failed classifications' }
|
||||||
|
* totalTagsAdded: { type: 'integer', description: 'Total tags added to database' }
|
||||||
|
* config: { $ref: '#/components/schemas/ClassifierConfig' }
|
||||||
|
* results:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* photoId: { type: 'string' }
|
||||||
|
* filename: { type: 'string' }
|
||||||
|
* tagsAdded: { type: 'integer' }
|
||||||
|
* topTags:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/ClassificationResult'
|
||||||
|
* hasMore: { type: 'boolean', description: 'Whether more photos are available to process' }
|
||||||
|
* 400:
|
||||||
|
* description: Invalid request parameters
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Error'
|
||||||
|
* 500:
|
||||||
|
* description: Server error during classification
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Error'
|
||||||
|
*/
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
const body: BatchClassifyRequest = await request.json()
|
const body: BatchClassifyRequest = await request.json()
|
||||||
@ -220,7 +290,47 @@ export async function POST(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get classification status
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/classify/batch:
|
||||||
|
* get:
|
||||||
|
* summary: Get classification status and statistics
|
||||||
|
* description: Returns statistics about photo classification status including total photos, tagged/untagged counts, and most common tags.
|
||||||
|
* tags: [Classification]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: directory
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Optional directory to filter statistics
|
||||||
|
* example: /Users/photos/2024
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Classification status and statistics
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* total: { type: 'integer', description: 'Total number of photos' }
|
||||||
|
* tagged: { type: 'integer', description: 'Number of photos with tags' }
|
||||||
|
* untagged: { type: 'integer', description: 'Number of photos without tags' }
|
||||||
|
* taggedPercentage: { type: 'integer', description: 'Percentage of photos with tags' }
|
||||||
|
* topTags:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* name: { type: 'string', description: 'Tag name' }
|
||||||
|
* count: { type: 'integer', description: 'Number of photos with this tag' }
|
||||||
|
* classifierReady: { type: 'boolean', description: 'Whether AI classifier is ready' }
|
||||||
|
* 500:
|
||||||
|
* description: Server error
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Error'
|
||||||
|
*/
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
const { searchParams } = new URL(request.url)
|
const { searchParams } = new URL(request.url)
|
||||||
|
15
src/app/api/docs/route.ts
Normal file
15
src/app/api/docs/route.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { getApiDocs } from '@/lib/swagger'
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
const spec = await getApiDocs()
|
||||||
|
return NextResponse.json(spec)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error generating API docs:', error)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to generate API documentation' },
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
88
src/app/docs/page.tsx
Normal file
88
src/app/docs/page.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
|
||||||
|
// Dynamically import Swagger UI to avoid SSR issues
|
||||||
|
const SwaggerUI = dynamic(() => import('swagger-ui-react'), {
|
||||||
|
ssr: false,
|
||||||
|
loading: () => <div className="text-center p-8">Loading Swagger UI...</div>
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function ApiDocsPage() {
|
||||||
|
const [spec, setSpec] = useState(null)
|
||||||
|
const [error, setError] = useState(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/api/docs')
|
||||||
|
.then(res => {
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${res.status}`)
|
||||||
|
}
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then(setSpec)
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Failed to load API docs:', error)
|
||||||
|
setError(error.message)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-white dark:bg-gray-900 flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="text-red-500 text-6xl mb-4">⚠️</div>
|
||||||
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
|
Failed to Load API Documentation
|
||||||
|
</h1>
|
||||||
|
<p className="text-gray-600 dark:text-gray-400 mb-4">
|
||||||
|
Error: {error}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => window.location.reload()}
|
||||||
|
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||||
|
>
|
||||||
|
Retry
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!spec) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-white dark:bg-gray-900 flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
|
||||||
|
<p className="mt-4 text-gray-600 dark:text-gray-400">Loading API Documentation...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-white dark:bg-gray-900">
|
||||||
|
<div className="container mx-auto px-4 py-8">
|
||||||
|
<div className="mb-8 text-center">
|
||||||
|
<h1 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
||||||
|
Photo Gallery AI API Documentation
|
||||||
|
</h1>
|
||||||
|
<p className="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||||
|
Complete API reference for the AI-powered photo organization system.
|
||||||
|
All endpoints run locally with no cloud dependencies.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6">
|
||||||
|
<SwaggerUI
|
||||||
|
spec={spec}
|
||||||
|
docExpansion="list"
|
||||||
|
defaultModelsExpandDepth={1}
|
||||||
|
tryItOutEnabled={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
143
src/lib/swagger.ts
Normal file
143
src/lib/swagger.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { createSwaggerSpec } from 'next-swagger-doc'
|
||||||
|
|
||||||
|
export const getApiDocs = async () => {
|
||||||
|
const spec = createSwaggerSpec({
|
||||||
|
apiFolder: 'src/app/api',
|
||||||
|
definition: {
|
||||||
|
openapi: '3.0.0',
|
||||||
|
info: {
|
||||||
|
title: 'Photo Gallery AI API',
|
||||||
|
version: '1.0.0',
|
||||||
|
description: `
|
||||||
|
AI-powered photo organization and classification API.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- **Dual-Model Classification**: ViT (objects) + CLIP (style/artistic concepts)
|
||||||
|
- **Image Captioning**: BLIP model for detailed descriptions
|
||||||
|
- **Batch Processing**: Process entire photo libraries
|
||||||
|
- **Tag Management**: Create, organize, and clear tags
|
||||||
|
- **Local AI**: All processing happens locally, no cloud dependencies
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
All endpoints are currently open access for local usage.
|
||||||
|
|
||||||
|
## Rate Limits
|
||||||
|
No rate limits - designed for local usage.
|
||||||
|
`,
|
||||||
|
contact: {
|
||||||
|
name: 'Photo Gallery API',
|
||||||
|
url: 'https://github.com/yourproject'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
servers: [
|
||||||
|
{ url: 'http://localhost:3000', description: 'Development server' },
|
||||||
|
{ url: 'https://yourdomain.com', description: 'Production server' }
|
||||||
|
],
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
name: 'Photos',
|
||||||
|
description: 'Photo management operations'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Classification',
|
||||||
|
description: 'AI-powered image classification and tagging'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Captioning',
|
||||||
|
description: 'AI-powered image captioning and descriptions'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Tags',
|
||||||
|
description: 'Tag management and organization'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Configuration',
|
||||||
|
description: 'AI model configuration and settings'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
Photo: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string', description: 'Unique photo identifier' },
|
||||||
|
filename: { type: 'string', description: 'Original filename' },
|
||||||
|
filepath: { type: 'string', description: 'Full file path' },
|
||||||
|
directory: { type: 'string', description: 'Parent directory' },
|
||||||
|
filesize: { type: 'integer', description: 'File size in bytes' },
|
||||||
|
width: { type: 'integer', description: 'Image width in pixels' },
|
||||||
|
height: { type: 'integer', description: 'Image height in pixels' },
|
||||||
|
format: { type: 'string', description: 'Image format (JPEG, PNG, etc.)' },
|
||||||
|
favorite: { type: 'boolean', description: 'Is photo marked as favorite' },
|
||||||
|
rating: { type: 'integer', minimum: 0, maximum: 5, description: 'Photo rating (0-5 stars)' },
|
||||||
|
description: { type: 'string', description: 'AI-generated or user description' },
|
||||||
|
created_at: { type: 'string', format: 'date-time', description: 'Photo creation date' },
|
||||||
|
modified_at: { type: 'string', format: 'date-time', description: 'Last modification date' },
|
||||||
|
indexed_at: { type: 'string', format: 'date-time', description: 'When photo was indexed' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tag: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string', description: 'Unique tag identifier' },
|
||||||
|
name: { type: 'string', description: 'Tag name' },
|
||||||
|
color: { type: 'string', description: 'Tag color in hex format' },
|
||||||
|
created_at: { type: 'string', format: 'date-time', description: 'Tag creation date' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClassificationResult: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
label: { type: 'string', description: 'Classification label' },
|
||||||
|
score: { type: 'number', minimum: 0, maximum: 1, description: 'Confidence score (0-1)' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CaptionResult: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
caption: { type: 'string', description: 'Generated caption text' },
|
||||||
|
confidence: { type: 'number', minimum: 0, maximum: 1, description: 'Caption confidence score' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClassifierConfig: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
minConfidence: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 1,
|
||||||
|
description: 'Minimum confidence threshold for classifications'
|
||||||
|
},
|
||||||
|
maxResults: {
|
||||||
|
type: 'integer',
|
||||||
|
minimum: 1,
|
||||||
|
maximum: 50,
|
||||||
|
description: 'Maximum number of results to return'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BatchClassifyRequest: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
directory: { type: 'string', description: 'Directory to process (optional)' },
|
||||||
|
limit: { type: 'integer', minimum: 1, maximum: 100, description: 'Number of photos to process per batch' },
|
||||||
|
offset: { type: 'integer', minimum: 0, description: 'Offset for pagination' },
|
||||||
|
minConfidence: { type: 'number', minimum: 0, maximum: 1, description: 'Minimum confidence threshold' },
|
||||||
|
maxResults: { type: 'integer', minimum: 1, maximum: 50, description: 'Maximum results per photo' },
|
||||||
|
onlyUntagged: { type: 'boolean', description: 'Process only photos without existing tags' },
|
||||||
|
comprehensive: { type: 'boolean', description: 'Use both ViT + CLIP models for more diverse tags' },
|
||||||
|
dryRun: { type: 'boolean', description: 'Preview results without saving to database' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Error: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
error: { type: 'string', description: 'Error message' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return spec
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user