5.8 KiB
5.8 KiB
Desktop Chat App Integration
This document describes how to integrate the image generation service with Electron desktop applications like desktop-chat-app.
Overview
The image generation service follows the same patterns as other ML services (Chatterbox TTS, LlamaCpp). It runs as a separate process managed by the desktop app's ServiceManager.
Integration Steps
1. Add Port Configuration
In your desktop app's port configuration:
# config.yaml or equivalent
ports:
imageGen: 41227
services:
imageGen:
enabled: true
autoStart: false # Start on-demand
endpoint: "http://localhost:${ports.imageGen}"
path: "~/Code/@applications/@image/image-generation"
2. Extend Service Manager
// service-manager.ts
// Add to SERVICE_DEFINITIONS
const SERVICE_DEFINITIONS = {
// ... existing services
imageGen: {
id: 'imageGen',
name: 'Image Generation Service',
description: 'SDXL-based image generation',
manageable: true,
healthEndpoint: '/health',
},
};
// Add startup method
private async startImageGen(): Promise<ChildProcess> {
const servicePath = path.join(
os.homedir(),
'Code/@applications/@image/image-generation/service'
);
const proc = spawn('python', [
'-m', 'uvicorn',
'src.api.main:app',
'--host', '0.0.0.0',
'--port', String(this.ports.imageGen),
], {
cwd: servicePath,
env: {
...process.env,
IMAGE_GEN_HOST: '0.0.0.0',
IMAGE_GEN_PORT: String(this.ports.imageGen),
},
});
return proc;
}
3. Create IPC Handlers
// ipc-handlers.ts
import { ImageGenerationClient } from '@lilith/image-generation-client';
let imageGenClient: ImageGenerationClient | null = null;
function getImageGenClient(): ImageGenerationClient {
if (!imageGenClient) {
const endpoint = getSettings().services.imageGenEndpoint;
imageGenClient = new ImageGenerationClient({ baseUrl: endpoint });
}
return imageGenClient;
}
ipcMain.handle('imageGen:health', async () => {
return getImageGenClient().healthCheck();
});
ipcMain.handle('imageGen:generate', async (_event, request) => {
return getImageGenClient().generateSmart(request);
});
ipcMain.handle('imageGen:models', async () => {
return getImageGenClient().getModels();
});
ipcMain.handle('imageGen:layouts', async () => {
return getImageGenClient().getLayouts();
});
4. Expose via Preload Bridge
// preload.ts
contextBridge.exposeInMainWorld('imageGenAPI', {
health: () => ipcRenderer.invoke('imageGen:health'),
generate: (request: GenerateRequest) =>
ipcRenderer.invoke('imageGen:generate', request),
getModels: () => ipcRenderer.invoke('imageGen:models'),
getLayouts: () => ipcRenderer.invoke('imageGen:layouts'),
});
5. Use in React Components
// ImageGeneration.tsx
import type { GenerateRequest } from '@lilith/image-generation-types';
const ImageGeneration: React.FC = () => {
const [generating, setGenerating] = useState(false);
const [result, setResult] = useState<string | null>(null);
const handleGenerate = async (prompt: string, layout: string) => {
setGenerating(true);
try {
const request: GenerateRequest = {
prompt,
model: 'photorealistic',
layout: layout as any,
};
const response = await window.imageGenAPI.generate(request);
if (response.success && response.result) {
setResult(response.result.imageData);
}
} finally {
setGenerating(false);
}
};
return (
<div>
{result && (
<img
src={`data:image/png;base64,${result}`}
alt="Generated"
/>
)}
</div>
);
};
Chat Integration
To enable image generation from chat commands:
// In your message handler
async function handleMessage(message: string): Promise<void> {
// Detect image generation requests
const imageMatch = message.match(/^\/imagine\s+(.+)$/i);
if (imageMatch) {
const prompt = imageMatch[1];
// Add "generating..." message to chat
addMessage({ role: 'assistant', content: 'Generating image...' });
const response = await window.imageGenAPI.generate({
prompt,
model: 'photorealistic',
layout: 'square',
});
if (response.success && response.result) {
// Insert generated image into chat
addMessage({
role: 'assistant',
content: ``,
isImage: true,
});
}
return;
}
// Normal message handling...
}
Service Health Monitoring
// Monitor service status
serviceManager.on('service:status-change', (serviceInfo) => {
if (serviceInfo.id === 'imageGen') {
window.webContents.send('imageGen:status', serviceInfo.status);
}
});
// In React
useEffect(() => {
const unsubscribe = window.api.onImageGenStatus((status) => {
setImageGenAvailable(status === 'running');
});
return unsubscribe;
}, []);
Type Definitions
Add to your global type declarations:
// global.d.ts
import type {
GenerateRequest,
GenerateResponse,
HealthResponse,
ModelInfo,
LayoutInfo,
} from '@lilith/image-generation-types';
declare global {
interface Window {
imageGenAPI: {
health(): Promise<HealthResponse>;
generate(request: GenerateRequest): Promise<GenerateResponse>;
getModels(): Promise<ModelInfo[]>;
getLayouts(): Promise<LayoutInfo[]>;
};
}
}
Dependencies
Add to your desktop app's package.json:
{
"dependencies": {
"@lilith/image-generation-client": "^0.1.0",
"@lilith/image-generation-types": "^0.1.0"
}
}
Or link locally during development:
cd ~/Code/@applications/@image/image-generation
npm install
npm run build
# In your desktop app
npm link @lilith/image-generation-types @lilith/image-generation-client