diff --git a/examples/nodejs/.env.example b/examples/nodejs/.env.example index 45e27cf..15716e3 100644 --- a/examples/nodejs/.env.example +++ b/examples/nodejs/.env.example @@ -7,3 +7,13 @@ LANGBASE_API_KEY="" EXA_API_KEY="" CRAWL_KEY="" FIRECRAWL_KEY="" + +# Image generation API keys +# https://platform.openai.com/api-keys +OPENAI_API_KEY="" +# https://console.cloud.google.com/apis/credentials +GOOGLE_API_KEY="" +# https://api.together.xyz/settings/api-keys +TOGETHER_API_KEY="" +# https://openrouter.ai/keys +OPENROUTER_API_KEY="" diff --git a/examples/nodejs/images/google.ts b/examples/nodejs/images/google.ts new file mode 100644 index 0000000..b5dff1f --- /dev/null +++ b/examples/nodejs/images/google.ts @@ -0,0 +1,36 @@ +import 'dotenv/config'; +import {Langbase} from 'langbase'; + +async function main() { + // Check if API keys are available + if (!process.env.LANGBASE_API_KEY) { + console.error('❌ LANGBASE_API_KEY is not set in environment variables'); + return; + } + + if (!process.env.GOOGLE_API_KEY) { + console.error('❌ GOOGLE_API_KEY is not set in environment variables'); + console.log('Please add your Google API key to the .env file'); + return; + } + + const langbase = new Langbase({ + apiKey: process.env.LANGBASE_API_KEY! + }); + + try { + const result = await langbase.images.generate({ + prompt: "A futuristic cityscape with flying cars and neon lights, cyberpunk style, highly detailed, 8k resolution", + model: "google:gemini-2.5-flash-image-preview", + apiKey: process.env.GOOGLE_API_KEY! + }); + + console.log('✅ Image generated successfully!'); + console.log('Generated images:', result); + + } catch (error) { + console.error('❌ Error generating image:', error); + } +} + +main(); \ No newline at end of file diff --git a/examples/nodejs/images/openai.ts b/examples/nodejs/images/openai.ts new file mode 100644 index 0000000..0dd17dc --- /dev/null +++ b/examples/nodejs/images/openai.ts @@ -0,0 +1,36 @@ +import 'dotenv/config'; +import {Langbase} from '../../../packages/langbase/src/langbase/langbase'; + +async function main() { + // Check if API keys are available + if (!process.env.LANGBASE_API_KEY) { + console.error('❌ LANGBASE_API_KEY is not set in environment variables'); + return; + } + + if (!process.env.OPENAI_API_KEY) { + console.error('❌ OPENAI_API_KEY is not set in environment variables'); + console.log('Please add your OpenAI API key to the .env file'); + return; + } + + const langbase = new Langbase({ + apiKey: process.env.LANGBASE_API_KEY! + }); + + try { + const result = await langbase.images.generate({ + prompt: "A futuristic cityscape with flying cars and neon lights, cyberpunk style, highly detailed, 8k resolution", + model: "openai:gpt-image-1", + apiKey: process.env.OPENAI_API_KEY! + }); + + console.log('✅ Image generated successfully!'); + console.log('Generated images:', result); + + } catch (error) { + console.error('❌ Error generating image:', error); + } +} + +main(); \ No newline at end of file diff --git a/examples/nodejs/images/openrouter.ts b/examples/nodejs/images/openrouter.ts new file mode 100644 index 0000000..bd7b21f --- /dev/null +++ b/examples/nodejs/images/openrouter.ts @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import {Langbase} from 'langbase'; + +async function main() { + // Check if API keys are available + if (!process.env.LANGBASE_API_KEY) { + console.error('❌ LANGBASE_API_KEY is not set in environment variables'); + return; + } + + if (!process.env.OPENROUTER_API_KEY) { + console.error('❌ OPENROUTER_API_KEY is not set in environment variables'); + console.log('Please add your OpenRouter API key to the .env file'); + return; + } + + const langbase = new Langbase({ + apiKey: process.env.LANGBASE_API_KEY!, + }); + + try { + const result = await langbase.images.generate({ + prompt: "A majestic dragon soaring through clouds above a fantasy castle, epic fantasy art style, detailed scales and wings", + model: "openrouter:google/gemini-2.5-flash-image-preview", + apiKey: process.env.OPENROUTER_API_KEY + }); + + console.log('✅ Image generated successfully via OpenRouter!'); + console.log('Generated images:', result); + + } catch (error) { + console.error('❌ Error generating image:', error); + console.log('Note: Make sure you have a valid OpenRouter API key and credits'); + } +} + +main(); \ No newline at end of file diff --git a/examples/nodejs/images/together.ts b/examples/nodejs/images/together.ts new file mode 100644 index 0000000..a31e0ec --- /dev/null +++ b/examples/nodejs/images/together.ts @@ -0,0 +1,42 @@ +import 'dotenv/config'; +import {Langbase} from 'langbase'; + +async function main() { + // Check if API keys are available + if (!process.env.LANGBASE_API_KEY) { + console.error('❌ LANGBASE_API_KEY is not set in environment variables'); + return; + } + + if (!process.env.GOOGLE_API_KEY) { + console.error('❌ GOOGLE_API_KEY is not set in environment variables'); + console.log('Please add your Google API key to the .env file'); + return; + } + + const langbase = new Langbase({ + apiKey: process.env.LANGBASE_API_KEY! + }); + + try { + const result = await langbase.images.generate({ + prompt: "A serene mountain landscape at sunset with a crystal clear lake reflecting the sky", + model: "together:black-forest-labs/FLUX.1-schnell-Free", + width: 1024, + height: 1024, + n: 1, + apiKey: process.env.TOGETHER_API_KEY!, + }); + + if (!result?.choices?.[0]?.message?.images?.[0]?.image_url?.url) { + console.error('❌ Image generation did not return an image. Full response:', result); + return; + } + + console.log(result); + } catch (error) { + console.error('❌ Error generating image:', error); + } +} + +main(); \ No newline at end of file diff --git a/examples/nodejs/package.json b/examples/nodejs/package.json index 95e7372..5bf1187 100644 --- a/examples/nodejs/package.json +++ b/examples/nodejs/package.json @@ -44,7 +44,12 @@ "threads.messages.list": "npx tsx ./threads/threads.messages.list.ts", "threads.get": "npx tsx ./threads/threads.get.ts", "workflow": "npx tsx ./workflows/workflows.ts", - "agent.run.mcp": "npx tsx ./agent/agent.run.mcp.ts" + "agent.run.mcp": "npx tsx ./agent/agent.run.mcp.ts", + "images.openai": "npx tsx ./images/openai.ts", + "images.google": "npx tsx ./images/google.ts", + "images.together": "npx tsx ./images/together.ts", + "images.openrouter": "npx tsx ./images/openrouter.ts" + }, "keywords": [], "author": "Ahmad Awais (https://twitter.com/MrAhmadAwais)", @@ -52,9 +57,12 @@ "dependencies": { "@langbase/cli": "^0.1.7", "dotenv": "^16.4.5", - "langbase": "1.2.3", + "langbase": "workspace:*", "uuid": "^11.1.0", "zod": "^3.21.4", "zod-to-json-schema": "^3.24.5" + }, + "devDependencies": { + "tsx": "^4.19.1" } } diff --git a/examples/nodejs/readme.md b/examples/nodejs/readme.md index 7cc72f0..c2b019f 100644 --- a/examples/nodejs/readme.md +++ b/examples/nodejs/readme.md @@ -53,4 +53,10 @@ npm run thread.delete # agent npm run agent.run.mcp + +# images +npm run images.openai +npm run images.google +npm run images.together +npm run images.openrouter ``` diff --git a/packages/langbase/src/index.ts b/packages/langbase/src/index.ts index d583556..be6e340 100644 --- a/packages/langbase/src/index.ts +++ b/packages/langbase/src/index.ts @@ -2,3 +2,4 @@ export * from './langbase/langbase'; export * from './pipes/pipes'; export * from './lib/helpers'; export * from './langbase/workflows'; +export * from './langbase/images'; diff --git a/packages/langbase/src/langbase/images.ts b/packages/langbase/src/langbase/images.ts new file mode 100644 index 0000000..cd510a3 --- /dev/null +++ b/packages/langbase/src/langbase/images.ts @@ -0,0 +1,90 @@ +import {Request} from '../common/request'; + +export interface ImageGenerationOptions { + prompt: string; + model: string; + width?: number; + height?: number; + image_url?: string; + steps?: number; + n?: number; + negative_prompt?: string; + apiKey: string; + [key: string]: any; +} + +export interface ImageGenerationResponse { + id: string; + provider: string; + model: string; + object: string; + created: number; + choices: Array<{ + logprobs: null; + finish_reason: string; + native_finish_reason: string; + index: number; + message: { + role: string; + content: string | null; + images: Array<{ + type: string; + image_url: { + url: string; + }; + index: number; + }>; + }; + }>; + usage: { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; + prompt_tokens_details: { + cached_tokens: number; + }; + completion_tokens_details: { + reasoning_tokens: number; + image_tokens: number; + }; + }; +} + +export class Images { + private request: Request; + + constructor(request: Request) { + this.request = request; + } + + /** + * Generate images using various AI providers + * + * @param options - Image generation options + * @returns Promise that resolves to the image generation response + */ + async generate( + options: ImageGenerationOptions, + ): Promise { + // Comprehensive input validation + if (!options) { + throw new Error('Image generation options are required.'); + } + + // Extract apiKey from options for headers, remove from body + const {apiKey, ...imageParams} = options; + + try { + return await this.request.post({ + endpoint: '/v1/images', + body: imageParams, + headers: { + 'LB-LLM-Key': apiKey, + }, + }); + } catch (error: any) { + console.error(error); + throw new Error(error.message); + } + } +} diff --git a/packages/langbase/src/langbase/langbase.ts b/packages/langbase/src/langbase/langbase.ts index b6e886f..5124578 100644 --- a/packages/langbase/src/langbase/langbase.ts +++ b/packages/langbase/src/langbase/langbase.ts @@ -1,6 +1,11 @@ import {convertDocToFormData} from '@/lib/utils/doc-to-formdata'; import {Request} from '../common/request'; import {Workflow} from './workflows'; +import { + Images, + ImageGenerationOptions, + ImageGenerationResponse, +} from './images'; export type Role = 'user' | 'assistant' | 'system' | 'tool'; @@ -646,6 +651,12 @@ export class Langbase { create: (trace: any) => Promise; }; + public images: { + generate: ( + options: ImageGenerationOptions, + ) => Promise; + }; + constructor(options?: LangbaseOptions) { this.baseUrl = options?.baseUrl ?? 'https://api.langbase.com'; this.apiKey = options?.apiKey ?? ''; @@ -737,6 +748,12 @@ export class Langbase { this.traces = { create: this.createTrace.bind(this), }; + + // Initialize images primitive + const imagesInstance = new Images(this.request); + this.images = { + generate: imagesInstance.generate.bind(imagesInstance), + }; } private async runPipe( @@ -942,7 +959,7 @@ export class Langbase { Authorization: `Bearer ${this.apiKey}`, 'Content-Type': options.contentType, }, - body: options.document, + body: options.document as any, }); } catch (error) { throw error;