feat: minio integration
This commit is contained in:
parent
2c7eb7c090
commit
5c8bc90bcc
|
|
@ -72,6 +72,7 @@ jspm_packages/
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# Generated images and uploads
|
# Generated images and uploads
|
||||||
|
data/storage/
|
||||||
results/
|
results/
|
||||||
uploads/
|
uploads/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ Banatie is a REST API service for AI-powered image generation using the Gemini F
|
||||||
|
|
||||||
## Development Commands
|
## Development Commands
|
||||||
|
|
||||||
|
use `docker compose` command for using docker-compose service (v3 version)
|
||||||
|
|
||||||
### Core Development
|
### Core Development
|
||||||
- `pnpm dev` - Start development server with auto-reload using tsx
|
- `pnpm dev` - Start development server with auto-reload using tsx
|
||||||
- `pnpm start` - Start production server (runs build first)
|
- `pnpm start` - Start production server (runs build first)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
-- Banatie Database Initialization Script
|
||||||
|
-- This script creates the initial database schema for the Banatie image generation service
|
||||||
|
|
||||||
|
-- Enable UUID extension
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
-- Organizations table
|
||||||
|
CREATE TABLE IF NOT EXISTS organizations (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
slug VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
settings JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Projects table (within organizations)
|
||||||
|
CREATE TABLE IF NOT EXISTS projects (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
slug VARCHAR(100) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
settings JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
UNIQUE(organization_id, slug)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Users table
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
username VARCHAR(100) NOT NULL,
|
||||||
|
email VARCHAR(255),
|
||||||
|
role VARCHAR(50) DEFAULT 'user',
|
||||||
|
settings JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
UNIQUE(organization_id, username)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Image metadata table
|
||||||
|
CREATE TABLE IF NOT EXISTS images (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
filename VARCHAR(255) NOT NULL,
|
||||||
|
original_filename VARCHAR(255),
|
||||||
|
file_path VARCHAR(500) NOT NULL, -- Path in MinIO
|
||||||
|
category VARCHAR(50) NOT NULL CHECK (category IN ('uploads', 'generated', 'references')),
|
||||||
|
original_prompt TEXT,
|
||||||
|
enhanced_prompt TEXT,
|
||||||
|
model_used VARCHAR(100),
|
||||||
|
file_size BIGINT,
|
||||||
|
content_type VARCHAR(100),
|
||||||
|
metadata JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Upload sessions table (for tracking multi-part uploads)
|
||||||
|
CREATE TABLE IF NOT EXISTS upload_sessions (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
session_data JSONB NOT NULL,
|
||||||
|
expires_at TIMESTAMP WITH TIME ZONE,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create indexes for better performance
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_organizations_slug ON organizations(slug);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_projects_org_id ON projects(organization_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_projects_org_slug ON projects(organization_id, slug);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_org_id ON users(organization_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_users_org_username ON users(organization_id, username);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_images_org_id ON images(organization_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_images_project_id ON images(project_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_images_user_id ON images(user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_images_category ON images(category);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_images_created_at ON images(created_at);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_upload_sessions_user_id ON upload_sessions(user_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_upload_sessions_expires_at ON upload_sessions(expires_at);
|
||||||
|
|
||||||
|
-- Function to update the updated_at timestamp
|
||||||
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = NOW();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ language 'plpgsql';
|
||||||
|
|
||||||
|
-- Create triggers to automatically update updated_at
|
||||||
|
CREATE TRIGGER update_organizations_updated_at BEFORE UPDATE ON organizations FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
CREATE TRIGGER update_projects_updated_at BEFORE UPDATE ON projects FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
CREATE TRIGGER update_images_updated_at BEFORE UPDATE ON images FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
|
||||||
|
-- Insert default organization and project
|
||||||
|
INSERT INTO organizations (id, name, slug, description) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000001', 'Default Organization', 'default', 'Default organization for development and testing')
|
||||||
|
ON CONFLICT (slug) DO NOTHING;
|
||||||
|
|
||||||
|
INSERT INTO projects (id, organization_id, name, slug, description) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000001', 'Main Project', 'main', 'Main project for image generation')
|
||||||
|
ON CONFLICT (organization_id, slug) DO NOTHING;
|
||||||
|
|
||||||
|
-- Insert system user
|
||||||
|
INSERT INTO users (id, organization_id, username, role) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000001', 'system', 'admin')
|
||||||
|
ON CONFLICT (organization_id, username) DO NOTHING;
|
||||||
|
|
||||||
|
-- Insert demo organization for development
|
||||||
|
INSERT INTO organizations (id, name, slug, description) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000002', 'Demo Organization', 'demo', 'Demo organization for testing and development')
|
||||||
|
ON CONFLICT (slug) DO NOTHING;
|
||||||
|
|
||||||
|
INSERT INTO projects (id, organization_id, name, slug, description) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000002', '00000000-0000-0000-0000-000000000002', 'Sandbox Project', 'sandbox', 'Sandbox project for testing features')
|
||||||
|
ON CONFLICT (organization_id, slug) DO NOTHING;
|
||||||
|
|
||||||
|
INSERT INTO users (id, organization_id, username, role) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000002', '00000000-0000-0000-0000-000000000002', 'guest', 'user')
|
||||||
|
ON CONFLICT (organization_id, username) DO NOTHING;
|
||||||
|
|
@ -5,6 +5,7 @@ import { Config } from './types/api';
|
||||||
import { generateRouter } from './routes/generate';
|
import { generateRouter } from './routes/generate';
|
||||||
import { enhanceRouter } from './routes/enhance';
|
import { enhanceRouter } from './routes/enhance';
|
||||||
import { textToImageRouter } from './routes/textToImage';
|
import { textToImageRouter } from './routes/textToImage';
|
||||||
|
import { imagesRouter } from './routes/images';
|
||||||
import { errorHandler, notFoundHandler } from './middleware/errorHandler';
|
import { errorHandler, notFoundHandler } from './middleware/errorHandler';
|
||||||
|
|
||||||
// Load environment variables
|
// Load environment variables
|
||||||
|
|
@ -82,6 +83,7 @@ export const createApp = (): Application => {
|
||||||
app.use('/api', generateRouter);
|
app.use('/api', generateRouter);
|
||||||
app.use('/api', enhanceRouter);
|
app.use('/api', enhanceRouter);
|
||||||
app.use('/api', textToImageRouter);
|
app.use('/api', textToImageRouter);
|
||||||
|
app.use('/api', imagesRouter);
|
||||||
|
|
||||||
// Error handling middleware (must be last)
|
// Error handling middleware (must be last)
|
||||||
app.use(notFoundHandler);
|
app.use(notFoundHandler);
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ textToImageRouter.post(
|
||||||
data: {
|
data: {
|
||||||
filename: result.filename!,
|
filename: result.filename!,
|
||||||
filepath: result.filepath!,
|
filepath: result.filepath!,
|
||||||
|
...(result.url && { url: result.url }),
|
||||||
...(result.description && { description: result.description }),
|
...(result.description && { description: result.description }),
|
||||||
model: result.model,
|
model: result.model,
|
||||||
generatedAt: timestamp,
|
generatedAt: timestamp,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { GoogleGenAI } from "@google/genai";
|
import { GoogleGenAI } from "@google/genai";
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const mime = require("mime") as any;
|
const mime = require("mime") as any;
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import {
|
import {
|
||||||
ImageGenerationOptions,
|
ImageGenerationOptions,
|
||||||
ImageGenerationResult,
|
ImageGenerationResult,
|
||||||
ReferenceImage,
|
ReferenceImage,
|
||||||
} from "../types/api";
|
} from "../types/api";
|
||||||
|
import { StorageFactory } from "./StorageFactory";
|
||||||
|
|
||||||
export class ImageGenService {
|
export class ImageGenService {
|
||||||
private ai: GoogleGenAI;
|
private ai: GoogleGenAI;
|
||||||
|
|
@ -27,11 +27,16 @@ export class ImageGenService {
|
||||||
async generateImage(
|
async generateImage(
|
||||||
options: ImageGenerationOptions,
|
options: ImageGenerationOptions,
|
||||||
): Promise<ImageGenerationResult> {
|
): Promise<ImageGenerationResult> {
|
||||||
const { prompt, filename, referenceImages } = options;
|
const { prompt, filename, referenceImages, orgId, projectId, userId } = options;
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = new Date().toISOString();
|
||||||
|
|
||||||
|
// Use default values if not provided
|
||||||
|
const finalOrgId = orgId || process.env['DEFAULT_ORG_ID'] || 'default';
|
||||||
|
const finalProjectId = projectId || process.env['DEFAULT_PROJECT_ID'] || 'main';
|
||||||
|
const finalUserId = userId || process.env['DEFAULT_USER_ID'] || 'system';
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`[${timestamp}] Starting image generation: "${prompt.substring(0, 50)}..."`,
|
`[${timestamp}] Starting image generation: "${prompt.substring(0, 50)}..." for ${finalOrgId}/${finalProjectId}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -41,6 +46,9 @@ export class ImageGenService {
|
||||||
config: { responseModalities: ["IMAGE", "TEXT"] },
|
config: { responseModalities: ["IMAGE", "TEXT"] },
|
||||||
prompt,
|
prompt,
|
||||||
filename,
|
filename,
|
||||||
|
orgId: finalOrgId,
|
||||||
|
projectId: finalProjectId,
|
||||||
|
userId: finalUserId,
|
||||||
...(referenceImages && { referenceImages }),
|
...(referenceImages && { referenceImages }),
|
||||||
modelName: "Nano Banana",
|
modelName: "Nano Banana",
|
||||||
});
|
});
|
||||||
|
|
@ -59,6 +67,9 @@ export class ImageGenService {
|
||||||
config: { responseModalities: ["IMAGE"] },
|
config: { responseModalities: ["IMAGE"] },
|
||||||
prompt,
|
prompt,
|
||||||
filename: `${filename}_fallback`,
|
filename: `${filename}_fallback`,
|
||||||
|
orgId: finalOrgId,
|
||||||
|
projectId: finalProjectId,
|
||||||
|
userId: finalUserId,
|
||||||
...(referenceImages && { referenceImages }),
|
...(referenceImages && { referenceImages }),
|
||||||
modelName: "Imagen 4",
|
modelName: "Imagen 4",
|
||||||
});
|
});
|
||||||
|
|
@ -84,10 +95,13 @@ export class ImageGenService {
|
||||||
config: { responseModalities: string[] };
|
config: { responseModalities: string[] };
|
||||||
prompt: string;
|
prompt: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
|
orgId: string;
|
||||||
|
projectId: string;
|
||||||
|
userId: string;
|
||||||
referenceImages?: ReferenceImage[];
|
referenceImages?: ReferenceImage[];
|
||||||
modelName: string;
|
modelName: string;
|
||||||
}): Promise<ImageGenerationResult> {
|
}): Promise<ImageGenerationResult> {
|
||||||
const { model, config, prompt, filename, referenceImages, modelName } =
|
const { model, config, prompt, filename, orgId, projectId, userId, referenceImages, modelName } =
|
||||||
params;
|
params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -143,7 +157,7 @@ export class ImageGenService {
|
||||||
) {
|
) {
|
||||||
const content = response.candidates[0].content;
|
const content = response.candidates[0].content;
|
||||||
let generatedDescription = "";
|
let generatedDescription = "";
|
||||||
let savedImagePath = "";
|
let uploadResult = null;
|
||||||
|
|
||||||
for (let index = 0; index < (content.parts?.length || 0); index++) {
|
for (let index = 0; index < (content.parts?.length || 0); index++) {
|
||||||
const part = content.parts?.[index];
|
const part = content.parts?.[index];
|
||||||
|
|
@ -154,16 +168,28 @@ export class ImageGenService {
|
||||||
part.inlineData.mimeType || "",
|
part.inlineData.mimeType || "",
|
||||||
);
|
);
|
||||||
const finalFilename = `${filename}.${fileExtension}`;
|
const finalFilename = `${filename}.${fileExtension}`;
|
||||||
const filepath = path.join("./results", finalFilename);
|
const contentType = part.inlineData.mimeType || `image/${fileExtension}`;
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`[${new Date().toISOString()}] Saving image: ${finalFilename}`,
|
`[${new Date().toISOString()}] Uploading image to MinIO: ${finalFilename}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const buffer = Buffer.from(part.inlineData.data || "", "base64");
|
const buffer = Buffer.from(part.inlineData.data || "", "base64");
|
||||||
await this.saveImageFile(filepath, buffer);
|
|
||||||
|
|
||||||
savedImagePath = filepath;
|
// Upload to MinIO storage
|
||||||
|
const storageService = StorageFactory.getInstance();
|
||||||
|
uploadResult = await storageService.uploadFile(
|
||||||
|
orgId,
|
||||||
|
projectId,
|
||||||
|
'generated',
|
||||||
|
finalFilename,
|
||||||
|
buffer,
|
||||||
|
contentType
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`[${new Date().toISOString()}] Image uploaded successfully: ${uploadResult.path}`,
|
||||||
|
);
|
||||||
} else if (part.text) {
|
} else if (part.text) {
|
||||||
generatedDescription = part.text;
|
generatedDescription = part.text;
|
||||||
console.log(
|
console.log(
|
||||||
|
|
@ -172,11 +198,12 @@ export class ImageGenService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedImagePath) {
|
if (uploadResult && uploadResult.success) {
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
filename: path.basename(savedImagePath),
|
filename: uploadResult.filename,
|
||||||
filepath: savedImagePath,
|
filepath: uploadResult.path,
|
||||||
|
url: uploadResult.url,
|
||||||
description: generatedDescription,
|
description: generatedDescription,
|
||||||
model: modelName,
|
model: modelName,
|
||||||
};
|
};
|
||||||
|
|
@ -201,33 +228,6 @@ export class ImageGenService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Save image buffer to file system
|
|
||||||
*/
|
|
||||||
private async saveImageFile(filepath: string, buffer: Buffer): Promise<void> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// Ensure the results directory exists
|
|
||||||
const dir = path.dirname(filepath);
|
|
||||||
if (!fs.existsSync(dir)) {
|
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFile(filepath, buffer, (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(
|
|
||||||
`[${new Date().toISOString()}] Error saving file ${filepath}:`,
|
|
||||||
err,
|
|
||||||
);
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
`[${new Date().toISOString()}] File saved successfully: ${filepath}`,
|
|
||||||
);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate reference images
|
* Validate reference images
|
||||||
|
|
|
||||||
|
|
@ -109,17 +109,17 @@ export class MinioStorageService implements StorageService {
|
||||||
metadata
|
metadata
|
||||||
);
|
);
|
||||||
|
|
||||||
const key = `${this.bucketName}/${filePath}`;
|
|
||||||
const url = this.getPublicUrl(orgId, projectId, category, uniqueFilename);
|
const url = this.getPublicUrl(orgId, projectId, category, uniqueFilename);
|
||||||
|
|
||||||
console.log(`Generated API URL: ${url}`);
|
console.log(`Generated API URL: ${url}`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key,
|
success: true,
|
||||||
filename: uniqueFilename,
|
filename: uniqueFilename,
|
||||||
|
path: filePath,
|
||||||
url,
|
url,
|
||||||
etag: result.etag,
|
size: buffer.length,
|
||||||
size: buffer.length
|
contentType
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
export interface FileMetadata {
|
||||||
|
filename: string;
|
||||||
|
size: number;
|
||||||
|
contentType: string;
|
||||||
|
lastModified: Date;
|
||||||
|
etag?: string;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UploadResult {
|
||||||
|
success: boolean;
|
||||||
|
filename: string;
|
||||||
|
path: string;
|
||||||
|
url: string; // API URL for accessing the file
|
||||||
|
size: number;
|
||||||
|
contentType: string;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StorageService {
|
||||||
|
/**
|
||||||
|
* Create the main bucket if it doesn't exist
|
||||||
|
*/
|
||||||
|
createBucket(): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the main bucket exists
|
||||||
|
*/
|
||||||
|
bucketExists(): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload a file to storage
|
||||||
|
* @param orgId Organization ID
|
||||||
|
* @param projectId Project ID
|
||||||
|
* @param category File category (uploads, generated, references)
|
||||||
|
* @param filename Original filename
|
||||||
|
* @param buffer File buffer
|
||||||
|
* @param contentType MIME type
|
||||||
|
*/
|
||||||
|
uploadFile(
|
||||||
|
orgId: string,
|
||||||
|
projectId: string,
|
||||||
|
category: 'uploads' | 'generated' | 'references',
|
||||||
|
filename: string,
|
||||||
|
buffer: Buffer,
|
||||||
|
contentType: string
|
||||||
|
): Promise<UploadResult>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download a file from storage
|
||||||
|
* @param orgId Organization ID
|
||||||
|
* @param projectId Project ID
|
||||||
|
* @param category File category
|
||||||
|
* @param filename Filename to download
|
||||||
|
*/
|
||||||
|
downloadFile(
|
||||||
|
orgId: string,
|
||||||
|
projectId: string,
|
||||||
|
category: 'uploads' | 'generated' | 'references',
|
||||||
|
filename: string
|
||||||
|
): Promise<Buffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a presigned URL for downloading a file
|
||||||
|
* @param orgId Organization ID
|
||||||
|
* @param projectId Project ID
|
||||||
|
* @param category File category
|
||||||
|
* @param filename Filename
|
||||||
|
* @param expirySeconds URL expiry time in seconds
|
||||||
|
*/
|
||||||
|
getPresignedDownloadUrl(
|
||||||
|
orgId: string,
|
||||||
|
projectId: string,
|
||||||
|
category: 'uploads' | 'generated' | 'references',
|
||||||
|
filename: string,
|
||||||
|
expirySeconds: number
|
||||||
|
): Promise<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a presigned URL for uploading a file
|
||||||
|
* @param orgId Organization ID
|
||||||
|
* @param projectId Project ID
|
||||||
|
* @param category File category
|
||||||
|
* @param filename Filename
|
||||||
|
* @param expirySeconds URL expiry time in seconds
|
||||||
|
* @param contentType MIME type
|
||||||
|
*/
|
||||||
|
getPresignedUploadUrl(
|
||||||
|
orgId: string,
|
||||||
|
projectId: string,
|
||||||
|
category: 'uploads' | 'generated' | 'references',
|
||||||
|
filename: string,
|
||||||
|
expirySeconds: number,
|
||||||
|
contentType: string
|
||||||
|
): Promise<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List files in a specific path
|
||||||
|
* @param orgId Organization ID
|
||||||
|
* @param projectId Project ID
|
||||||
|
* @param category File category
|
||||||
|
* @param prefix Optional prefix to filter files
|
||||||
|
*/
|
||||||
|
listFiles(
|
||||||
|
orgId: string,
|
||||||
|
projectId: string,
|
||||||
|
category: 'uploads' | 'generated' | 'references',
|
||||||
|
prefix?: string
|
||||||
|
): Promise<FileMetadata[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a file from storage
|
||||||
|
* @param orgId Organization ID
|
||||||
|
* @param projectId Project ID
|
||||||
|
* @param category File category
|
||||||
|
* @param filename Filename to delete
|
||||||
|
*/
|
||||||
|
deleteFile(
|
||||||
|
orgId: string,
|
||||||
|
projectId: string,
|
||||||
|
category: 'uploads' | 'generated' | 'references',
|
||||||
|
filename: string
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a file exists
|
||||||
|
* @param orgId Organization ID
|
||||||
|
* @param projectId Project ID
|
||||||
|
* @param category File category
|
||||||
|
* @param filename Filename to check
|
||||||
|
*/
|
||||||
|
fileExists(
|
||||||
|
orgId: string,
|
||||||
|
projectId: string,
|
||||||
|
category: 'uploads' | 'generated' | 'references',
|
||||||
|
filename: string
|
||||||
|
): Promise<boolean>;
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,7 @@ export interface GenerateImageResponse {
|
||||||
data?: {
|
data?: {
|
||||||
filename: string;
|
filename: string;
|
||||||
filepath: string;
|
filepath: string;
|
||||||
|
url?: string; // API URL for accessing the image
|
||||||
description?: string;
|
description?: string;
|
||||||
model: string;
|
model: string;
|
||||||
generatedAt: string;
|
generatedAt: string;
|
||||||
|
|
@ -57,6 +58,9 @@ export interface ImageGenerationOptions {
|
||||||
prompt: string;
|
prompt: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
referenceImages?: ReferenceImage[];
|
referenceImages?: ReferenceImage[];
|
||||||
|
orgId?: string;
|
||||||
|
projectId?: string;
|
||||||
|
userId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReferenceImage {
|
export interface ReferenceImage {
|
||||||
|
|
@ -69,6 +73,7 @@ export interface ImageGenerationResult {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
filename?: string;
|
filename?: string;
|
||||||
filepath?: string;
|
filepath?: string;
|
||||||
|
url?: string; // API URL for accessing the image
|
||||||
description?: string;
|
description?: string;
|
||||||
model: string;
|
model: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue