Created
June 9, 2026 06:20
-
-
Save agrancini-sc/ee0b4bfa5f66c4327a4bcddbb37cbd70 to your computer and use it in GitHub Desktop.
ImageGenerator.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Specs Inc. 2026 | |
| * Image Generator component for the AI Playground Spectacles lens. | |
| */ | |
| import {Gemini} from "RemoteServiceGateway.lspkg/HostedExternal/Gemini" | |
| import {GeminiTypes} from "RemoteServiceGateway.lspkg/HostedExternal/GeminiTypes" | |
| import {OpenAI} from "RemoteServiceGateway.lspkg/HostedExternal/OpenAI" | |
| import {OpenAITypes} from "RemoteServiceGateway.lspkg/HostedExternal/OpenAITypes" | |
| import {Promisfy} from "RemoteServiceGateway.lspkg/Utils/Promisfy" | |
| import {Logger} from "Utilities.lspkg/Scripts/Utils/Logger" | |
| export class ImageGenerator { | |
| private rmm = require("LensStudio:RemoteMediaModule") as RemoteMediaModule | |
| private model: string | |
| private logger: Logger | |
| constructor(model: string, logger?: Logger) { | |
| this.model = model | |
| this.logger = logger | |
| } | |
| generateImage(prompt: string): Promise<Texture> { | |
| if (this.model === "OpenAI") { | |
| return this.generateWithOpenAI(prompt) | |
| } else { | |
| return this.generateWithGemini(prompt) | |
| } | |
| } | |
| private generateWithGemini(prompt: string): Promise<Texture> { | |
| return new Promise((resolve, reject) => { | |
| const request: GeminiTypes.Models.GenerateContentRequest = { | |
| model: "gemini-2.5-flash-image", | |
| type: "generateContent", | |
| body: { | |
| contents: [ | |
| { | |
| parts: [ | |
| { | |
| text: prompt | |
| } | |
| ], | |
| role: "user" | |
| } | |
| ], | |
| generationConfig: { | |
| responseModalities: ["TEXT", "IMAGE"] | |
| } | |
| } | |
| } | |
| Gemini.models(request) | |
| .then((response) => { | |
| if (!response.candidates || response.candidates.length === 0) { | |
| reject("No image generated in response") | |
| return | |
| } | |
| let foundImage = false | |
| for (const part of response.candidates[0].content.parts) { | |
| if (part?.inlineData) { | |
| foundImage = true | |
| const b64Data = part.inlineData.data | |
| Base64.decodeTextureAsync( | |
| b64Data, | |
| (texture) => { | |
| resolve(texture) | |
| }, | |
| () => { | |
| reject("Failed to decode texture from base64 data.") | |
| } | |
| ) | |
| break | |
| } | |
| } | |
| if (!foundImage) { | |
| reject("No image data found in response") | |
| } | |
| }) | |
| .catch((error) => { | |
| reject("Error while generating image: " + error) | |
| }) | |
| }) | |
| } | |
| private generateWithOpenAI(prompt: string): Promise<Texture> { | |
| return new Promise((resolve, reject) => { | |
| const req = { | |
| prompt: prompt, | |
| n: 1, | |
| model: "dall-e-3" | |
| } as OpenAITypes.ImageGenerate.Request | |
| OpenAI.imagesGenerate(req) | |
| .then((result) => { | |
| result.data.forEach((datum) => { | |
| const b64 = datum.b64_json | |
| const url = datum.url | |
| if (url) { | |
| if (this.logger) this.logger.info("Texture loaded as image URL") | |
| const internetModule = require("LensStudio:InternetModule") as InternetModule | |
| const request = RemoteServiceHttpRequest.create() | |
| request.url = url | |
| Promisfy.InternetModule.performHttpRequest(internetModule, request).then((response) => { | |
| const resource = response.asResource() | |
| this.rmm.loadResourceAsImageTexture( | |
| resource, | |
| (texture) => { | |
| resolve(texture) | |
| }, | |
| () => { | |
| reject("Failure to download texture from URL") | |
| } | |
| ) | |
| }) | |
| } else if (b64) { | |
| if (this.logger) this.logger.debug("Decoding texture from base64") | |
| Base64.decodeTextureAsync( | |
| b64, | |
| (texture) => { | |
| resolve(texture) | |
| }, | |
| () => { | |
| reject("Failure to download texture from base64") | |
| } | |
| ) | |
| } | |
| }) | |
| }) | |
| .catch((error) => reject(error)) | |
| }) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment