BrandFrame AI is a robust backend API built with PHP Laravel, designed to facilitate AI-powered image generation for branding purposes. It integrates with the Bria AI API for creative asset generation, manages brand presets, and handles product image uploads and batch processing through a queued job system.
- User Authentication: Secure user registration, login, and logout using Laravel Sanctum for API token management.
- Product Image Uploads: API endpoint for authenticated users to upload product images for AI processing.
- AI Image Generation: On-demand generation of product images styled according to various "shot types" (e.g., lifestyle, hero, white background) via integration with Bria AI.
- Brand Preset Management: Allows users to create, retrieve, update, and delete custom brand presets, which define specific styling and compositional elements for AI image generation.
- Preset Application: Apply saved brand presets to uploaded product images to generate new styled images.
- Batch Image Processing: Efficiently process multiple product images with a single brand preset using a background queue system, dispatching
ProcessImageWithBriaAIjobs. - Generated Image Management: Users can view and delete their previously generated AI images.
- Database Integration: Persistent storage for users, brand presets, and generated image metadata.
To set up BrandFrame AI locally, follow these steps:
- Clone the Repository:
git clone https://github.com/Ace-g-ops/BrandFrame-AI.git cd BrandFrame-AI - Install PHP Dependencies:
composer install
- Install JavaScript Dependencies:
npm install # or yarn install - Copy Environment File:
cp .env.example .env
- Generate Application Key:
php artisan key:generate
- Configure Environment Variables:
Edit the
.envfile with your database credentials and API keys. Refer to the "Environment Variables" section for details. - Run Database Migrations:
php artisan migrate
- Link Storage:
php artisan storage:link
- Build Frontend Assets:
npm run build # or yarn build - Start the Laravel Development Server:
php artisan serve
- Start the Queue Listener (for batch processing):
In a separate terminal, run:
php artisan queue:listen
The following environment variables are required for the application to function correctly. Create a .env file based on .env.example and populate these values.
APP_NAME: Name of the application (e.g.,Laravel)APP_ENV: Application environment (e.g.,local,production)APP_KEY: Unique application key (generated byphp artisan key:generate)APP_DEBUG: Enable/disable debug mode (e.g.,true,false)APP_URL: Application URL (e.g.,http://localhost)DB_CONNECTION: Database connection driver (e.g.,mariadb,mysql,sqlite)DB_HOST: Database host (e.g.,127.0.0.1)DB_PORT: Database port (e.g.,3306)DB_DATABASE: Database name (e.g.,brandframeai)DB_USERNAME: Database username (e.g.,root)DB_PASSWORD: Database password (e.g.,nullor your password)SESSION_DRIVER: Session driver (e.g.,database)SESSION_LIFETIME: Session lifetime in minutes (e.g.,120)QUEUE_CONNECTION: Queue driver (e.g.,database)BRIA_API_KEY: API key for Bria AI integration (provided by Bria AI)MAIL_MAILER: Mail driver (e.g.,log,smtp)MAIL_HOST: Mail host (e.g.,127.0.0.1)MAIL_PORT: Mail port (e.g.,2525)MAIL_USERNAME: Mail username (e.g.,null)MAIL_PASSWORD: Mail password (e.g.,null)MAIL_FROM_ADDRESS: Sender email address (e.g.,"hello@example.com")MAIL_FROM_NAME: Sender name (e.g.,"${APP_NAME}")AWS_ACCESS_KEY_ID: AWS Access Key ID (if using AWS S3 for storage)AWS_SECRET_ACCESS_KEY: AWS Secret Access Key (if using AWS S3 for storage)AWS_DEFAULT_REGION: AWS default region (e.g.,us-east-1)AWS_BUCKET: AWS S3 bucket name
http://localhost:8000/api (assuming php artisan serve is running on default port)
All protected routes require a Bearer token in the Authorization header.
Example: Authorization: Bearer YOUR_AUTH_TOKEN
Registers a new user. Request:
{
"name": "John Doe",
"email": "john.doe@example.com",
"password": "StrongPassword123"
}Response:
{
"token": "YOUR_GENERATED_API_TOKEN",
"user": {
"name": "John Doe",
"email": "john.doe@example.com",
"updated_at": "2023-10-27T10:00:00.000000Z",
"created_at": "2023-10-27T10:00:00.000000Z",
"id": 1
}
}Errors:
422 Unprocessable Entity: Validation failed (e.g., email already exists, invalid password format).
Authenticates a user and issues an API token. Request:
{
"email": "john.doe@example.com",
"password": "StrongPassword123"
}Response:
{
"user": {
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"email_verified_at": null,
"created_at": "2023-10-27T10:00:00.000000Z",
"updated_at": "2023-10-27T10:00:00.000000Z"
},
"token": "YOUR_GENERATED_API_TOKEN"
}Errors:
422 Unprocessable Entity: Validation failed (e.g., missing email/password).404 Not Found: User with the provided email not found.401 Unauthorized: Invalid credentials (incorrect password).
Logs out the authenticated user by revoking their current API token. Requires authentication. Request: (No body) Response:
{
"message": "Logged out successfully"
}Errors:
401 Unauthorized: No valid API token provided.
Uploads a product image to the server. Requires authentication.
Request: multipart/form-data
product_image: (File) The image file to upload (JPEG, PNG, JPG, max 5MB). Response:
{
"message": "Product Image Uploaded",
"path": "products/example_image.png",
"url": "http://localhost:8000/storage/products/example_image.png"
}Errors:
422 Unprocessable Entity: Validation failed (e.g., invalid file type, file too large).401 Unauthorized: No valid API token provided.
Generates an AI image based on an uploaded product image and a specified shot type. Requires authentication.
Request: multipart/form-data
product_image: (File) The product image to use as input.shot_type: (String) The desired shot type (lifestyle,hero,falt_lay,context,white_background).product_description: (String, optional) A description of the product for the AI prompt (max 400 characters). Response:
{
"message": "Image generated successfully",
"data": {
"user_id": 1,
"product_image_path": "products/uploaded_product.jpg",
"user_intent": "A sleek smartphone",
"structured_prompt": {
"style": "professional",
"shot_type": "lifestyle",
"subject": "A sleek smartphone",
"camera_angle": "4 degree angle",
"lighting": "soft natural light",
"composition": "rule of thirds",
"mood": "casual, authentic, relatable"
},
"generated_image_url": "https://bria-ai.com/generated/image_url.jpg",
"shot_type": "lifestyle",
"angle": "4 degree angle",
"style": "professional",
"bria_request_id": "bria-request-uuid",
"metadata": { /* Bria API full response metadata */ },
"updated_at": "2023-10-27T10:00:00.000000Z",
"created_at": "2023-10-27T10:00:00.000000Z",
"id": 1
},
"image_url": "https://bria-ai.com/generated/image_url.jpg"
}Errors:
422 Unprocessable Entity: Validation failed (e.g., missing fields, invalid shot type).401 Unauthorized: No valid API token provided.500 Internal Server Error: Failed to generate image, or Bria API returned an error.
Retrieves all generated images for the authenticated user. Requires authentication. Request: (No body) Response:
[
{
"id": 1,
"user_id": 1,
"brand_preset_id": null,
"product_image_path": "products/uploaded_product.jpg",
"user_intent": "A sleek smartphone",
"structured_prompt": { /* ... */ },
"generated_image_url": "https://bria-ai.com/generated/image_url.jpg",
"shot_type": "lifestyle",
"angle": "4 degree angle",
"style": "professional",
"bria_request_id": "bria-request-uuid",
"metadata": { /* ... */ },
"created_at": "2023-10-27T10:00:00.000000Z",
"updated_at": "2023-10-27T10:00:00.000000Z"
},
// ... more generated image objects
]Errors:
401 Unauthorized: No valid API token provided.
Retrieves a single generated image by its ID for the authenticated user. Requires authentication. Request: (No body) Response:
{
"id": 1,
"user_id": 1,
"brand_preset_id": null,
"product_image_path": "products/uploaded_product.jpg",
"user_intent": "A sleek smartphone",
"structured_prompt": { /* ... */ },
"generated_image_url": "https://bria-ai.com/generated/image_url.jpg",
"shot_type": "lifestyle",
"angle": "4 degree angle",
"style": "professional",
"bria_request_id": "bria-request-uuid",
"metadata": { /* ... */ },
"created_at": "2023-10-27T10:00:00.000000Z",
"updated_at": "2023-10-27T10:00:00.000000Z"
}Errors:
401 Unauthorized: No valid API token provided.404 Not Found: Generated image with the specified ID not found for the user.
Deletes a generated image by its ID for the authenticated user. Requires authentication. Request: (No body) Response:
{
"message": "Image successfully deleted"
}Errors:
401 Unauthorized: No valid API token provided.404 Not Found: Generated image with the specified ID not found for the user.
Retrieves all brand presets for the authenticated user. Requires authentication. Request: (No body) Response:
[
{
"id": 1,
"user_id": 1,
"name": "Luxury Product Shot",
"structured_prompt": {
"style": "premium",
"angle": "close-up",
"lighting": "studio",
"composition": "centered"
},
"description": "High-end look for jewelry.",
"shot_type": "hero",
"created_at": "2023-10-27T10:00:00.000000Z",
"updated_at": "2023-10-27T10:00:00.000000Z"
},
// ... more preset objects
]Errors:
401 Unauthorized: No valid API token provided.
Creates a new brand preset for the authenticated user. Requires authentication. Request:
{
"name": "E-commerce White Background",
"description": "Standard white background for online stores.",
"shot_type": "white_background",
"structured_prompt": {
"style": "clean",
"lighting": "even studio lighting",
"composition": "centered product fill frame",
"mood": "clean, simple, professional"
}
}Response:
{
"message": "Brand Preset Created Successfully",
"data": {
"name": "E-commerce White Background",
"description": "Standard white background for online stores.",
"structured_prompt": { /* ... */ },
"shot_type": "white_background",
"user_id": 1,
"updated_at": "2023-10-27T10:00:00.000000Z",
"created_at": "2023-10-27T10:00:00.000000Z",
"id": 1
}
}Errors:
422 Unprocessable Entity: Validation failed (e.g., missing name, invalid shot type).401 Unauthorized: No valid API token provided.500 Internal Server Error: Failed to store preset.
Retrieves a single brand preset by its ID for the authenticated user. Requires authentication. Request: (No body) Response:
{
"id": 1,
"user_id": 1,
"name": "Luxury Product Shot",
"structured_prompt": { /* ... */ },
"description": "High-end look for jewelry.",
"shot_type": "hero",
"created_at": "2023-10-27T10:00:00.000000Z",
"updated_at": "2023-10-27T10:00:00.000000Z"
}Errors:
401 Unauthorized: No valid API token provided.404 Not Found: Brand preset with the specified ID not found for the user.
Updates an existing brand preset by its ID for the authenticated user. Requires authentication. Request:
{
"name": "Updated Luxury Product Shot",
"description": "Revised high-end look for watches.",
"structured_prompt": {
"style": "minimalist",
"angle": "top-down",
"lighting": "softbox",
"composition": "rule of thirds",
"mood": "elegant, sophisticated"
}
}Response:
{
"message": "Brand Preset Updated successfully",
"data": {
"id": 1,
"user_id": 1,
"name": "Updated Luxury Product Shot",
"structured_prompt": { /* ... updated fields */ },
"description": "Revised high-end look for watches.",
"shot_type": "hero",
"created_at": "2023-10-27T10:00:00.000000Z",
"updated_at": "2023-10-27T10:30:00.000000Z"
}
}Errors:
422 Unprocessable Entity: Validation failed (e.g., invalid structured prompt).401 Unauthorized: No valid API token provided.404 Not Found: Brand preset with the specified ID not found for the user.
Deletes a brand preset by its ID for the authenticated user. Requires authentication. Request: (No body) Response:
{
"message": "Preset successfully deleted"
}Errors:
401 Unauthorized: No valid API token provided.404 Not Found: Brand preset with the specified ID not found for the user.
Applies a specific brand preset to an uploaded product image to generate a new AI image. Requires authentication.
Request: multipart/form-data
preset_id: (Integer) The ID of the brand preset to apply.product_image: (File) The product image to process.product_description: (String, optional) A description of the product for the AI prompt. Response:
{
"message": "Image generated successfully with preset",
"data": {
"user_id": 1,
"brand_preset_id": 1,
"product_image_path": "products/product_for_preset.jpg",
"user_intent": "Vintage camera",
"structured_prompt": { /* ... */ },
"generated_image_url": "https://bria-ai.com/generated/preset_image.jpg",
"shot_type": "hero",
"angle": "close-up",
"style": "premium",
"bria_request_id": "bria-request-uuid-preset",
"metadata": { /* Bria API full response metadata */ },
"updated_at": "2023-10-27T10:00:00.000000Z",
"created_at": "2023-10-27T10:00:00.000000Z",
"id": 2
},
"image_url": "https://bria-ai.com/generated/preset_image.jpg"
}Errors:
422 Unprocessable Entity: Validation failed (e.g., missing fields, invalid image).401 Unauthorized: No valid API token provided.404 Not Found: Preset with the specified ID not found for the user.500 Internal Server Error: Failed to generate image, or Bria API returned an error.
Initiates a batch generation process for multiple product images using a single brand preset. This process is handled asynchronously via a job queue. Requires authentication.
Request: multipart/form-data
preset_id: (Integer) The ID of the brand preset to apply to all images.product_images[]: (Array of Files) An array of product image files.product_descriptions[]: (Array of Strings, optional) An array of descriptions corresponding to each product image. Response:
{
"message": "Batch Generation Started! Processing Batch In Background",
"total_images": 3,
"status": "processing"
}Errors:
422 Unprocessable Entity: Validation failed (e.g., missing preset ID, invalid image files).401 Unauthorized: No valid API token provided.404 Not Found: Preset with the specified ID not found for the user.
| Technology | Description |
|---|---|
| PHP | Server-side scripting language |
| Laravel | Web application framework for PHP |
| Laravel Sanctum | API token authentication for SPAs and mobile applications |
| MariaDB | Relational database management system |
| Bria AI | External AI image generation API |
| Composer | PHP dependency manager |
| Vite | Frontend build tool |
| TailwindCSS | Utility-first CSS framework |
| Alpine.js | Lightweight JavaScript framework for dynamic UI |
| Flowbite | Tailwind CSS components library |
| Redis | In-memory data store for caching and queuing (optional for queues) |
We welcome contributions to BrandFrame AI! To contribute, please follow these guidelines:
- Fork the Repository: Start by forking the project repository.
- Create a New Branch: Create a feature or bugfix branch from
main(e.g.,feature/add-new-endpoint,bugfix/fix-auth-issue). - Implement Changes: Write your code, ensuring it adheres to the project's coding standards.
- Write Tests: Add appropriate tests for your new features or bug fixes.
- Run Tests: Ensure all existing tests pass with your changes.
php artisan test - Commit Changes: Commit your changes with clear and concise messages.
- Push to Your Fork: Push your branch to your forked repository.
- Open a Pull Request: Submit a pull request to the
mainbranch of the original repository. Provide a detailed description of your changes and why they are necessary.
This project is licensed under the MIT License.
- Victor Ajibua
- LinkedIn: https://linkedin.com/in/victorajibua (Placeholder - please replace with actual link)
- Portfolio: https://victorajibua.dev (Placeholder - please replace with actual link)