1- import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types" ;
2- import type { ImageGenerationProvider } from "openclaw/plugin-sdk/image-generation" ;
31import {
2+ createOpenAiCompatibleImageGenerationProvider ,
43 imageSourceUploadFileName ,
5- parseOpenAiCompatibleImageResponse ,
4+ type ImageGenerationProvider ,
65} from "openclaw/plugin-sdk/image-generation" ;
7- import { isProviderApiKeyConfigured } from "openclaw/plugin-sdk/provider-auth" ;
8- import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime" ;
9- import {
10- assertOkOrThrowHttpError ,
11- postJsonRequest ,
12- postMultipartRequest ,
13- resolveProviderHttpRequestConfig ,
14- sanitizeConfiguredModelProviderRequest ,
15- } from "openclaw/plugin-sdk/provider-http" ;
166import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime" ;
177import {
188 DEEPINFRA_BASE_URL ,
@@ -26,35 +16,12 @@ import {
2616const DEEPINFRA_IMAGE_SIZES = [ "512x512" , "1024x1024" , "1024x1792" , "1792x1024" ] as const ;
2717const MAX_DEEPINFRA_INPUT_IMAGES = 1 ;
2818
29- type DeepInfraProviderConfig = NonNullable <
30- NonNullable < OpenClawConfig [ "models" ] > [ "providers" ]
31- > [ string ] ;
32-
33- type DeepInfraImageApiResponse = {
34- data ?: Array < {
35- b64_json ?: string ;
36- revised_prompt ?: string ;
37- url ?: string ;
38- } > ;
39- } ;
40-
41- function resolveDeepInfraProviderConfig (
42- cfg : OpenClawConfig | undefined ,
43- ) : DeepInfraProviderConfig | undefined {
44- return cfg ?. models ?. providers ?. deepinfra ;
45- }
46-
4719export function buildDeepInfraImageGenerationProvider ( ) : ImageGenerationProvider {
48- return {
20+ return createOpenAiCompatibleImageGenerationProvider ( {
4921 id : "deepinfra" ,
5022 label : "DeepInfra" ,
5123 defaultModel : DEFAULT_DEEPINFRA_IMAGE_MODEL ,
5224 models : [ ...DEEPINFRA_IMAGE_MODELS ] ,
53- isConfigured : ( { agentDir } ) =>
54- isProviderApiKeyConfigured ( {
55- provider : "deepinfra" ,
56- agentDir,
57- } ) ,
5825 capabilities : {
5926 generate : {
6027 maxCount : 4 ,
@@ -74,111 +41,49 @@ export function buildDeepInfraImageGenerationProvider(): ImageGenerationProvider
7441 sizes : [ ...DEEPINFRA_IMAGE_SIZES ] ,
7542 } ,
7643 } ,
77- async generateImage ( req ) {
78- const inputImages = req . inputImages ?? [ ] ;
79- const isEdit = inputImages . length > 0 ;
80- if ( inputImages . length > MAX_DEEPINFRA_INPUT_IMAGES ) {
81- throw new Error ( "DeepInfra image editing supports one reference image." ) ;
82- }
83- const auth = await resolveApiKeyForProvider ( {
84- provider : "deepinfra" ,
85- cfg : req . cfg ,
86- agentDir : req . agentDir ,
87- store : req . authStore ,
88- } ) ;
89- if ( ! auth . apiKey ) {
90- throw new Error ( "DeepInfra API key missing" ) ;
44+ defaultBaseUrl : DEEPINFRA_BASE_URL ,
45+ normalizeModel : normalizeDeepInfraModelRef ,
46+ resolveBaseUrl : ( { providerConfig } ) =>
47+ normalizeDeepInfraBaseUrl ( providerConfig ?. baseUrl , DEEPINFRA_BASE_URL ) ,
48+ resolveAllowPrivateNetwork : ( ) => false ,
49+ useConfiguredRequest : true ,
50+ resolveCount : ( { req, mode } ) => ( mode === "edit" ? 1 : ( req . count ?? 1 ) ) ,
51+ buildGenerateRequest : ( { req, model, count } ) => ( {
52+ kind : "json" ,
53+ body : {
54+ model,
55+ prompt : req . prompt ,
56+ n : count ,
57+ size : normalizeOptionalString ( req . size ) ?? DEFAULT_DEEPINFRA_IMAGE_SIZE ,
58+ response_format : "b64_json" ,
59+ } ,
60+ } ) ,
61+ buildEditRequest : ( { req, inputImages, model, count } ) => {
62+ const image = inputImages [ 0 ] ;
63+ if ( ! image ) {
64+ throw new Error ( "DeepInfra image edit missing reference image." ) ;
9165 }
92-
93- const providerConfig = resolveDeepInfraProviderConfig ( req . cfg ) ;
94- const resolvedBaseUrl = normalizeDeepInfraBaseUrl (
95- providerConfig ?. baseUrl ,
96- DEEPINFRA_BASE_URL ,
66+ const form = new FormData ( ) ;
67+ form . set ( "model" , model ) ;
68+ form . set ( "prompt" , req . prompt ) ;
69+ form . set ( "n" , String ( count ) ) ;
70+ form . set ( "size" , normalizeOptionalString ( req . size ) ?? DEFAULT_DEEPINFRA_IMAGE_SIZE ) ;
71+ form . set ( "response_format" , "b64_json" ) ;
72+ const mimeType = normalizeOptionalString ( image . mimeType ) ?? "image/png" ;
73+ form . append (
74+ "image" ,
75+ new Blob ( [ new Uint8Array ( image . buffer ) ] , { type : mimeType } ) ,
76+ imageSourceUploadFileName ( { image, index : 0 } ) ,
9777 ) ;
98- const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } =
99- resolveProviderHttpRequestConfig ( {
100- baseUrl : resolvedBaseUrl ,
101- defaultBaseUrl : DEEPINFRA_BASE_URL ,
102- allowPrivateNetwork : false ,
103- request : sanitizeConfiguredModelProviderRequest ( providerConfig ?. request ) ,
104- defaultHeaders : {
105- Authorization : `Bearer ${ auth . apiKey } ` ,
106- } ,
107- provider : "deepinfra" ,
108- capability : "image" ,
109- transport : "http" ,
110- } ) ;
111-
112- const model = normalizeDeepInfraModelRef ( req . model , DEFAULT_DEEPINFRA_IMAGE_MODEL ) ;
113- const count = isEdit ? 1 : ( req . count ?? 1 ) ;
114- const size = normalizeOptionalString ( req . size ) ?? DEFAULT_DEEPINFRA_IMAGE_SIZE ;
115- const endpoint = isEdit ? "images/edits" : "images/generations" ;
116- const request = isEdit
117- ? ( ( ) => {
118- const form = new FormData ( ) ;
119- form . set ( "model" , model ) ;
120- form . set ( "prompt" , req . prompt ) ;
121- form . set ( "n" , String ( count ) ) ;
122- form . set ( "size" , size ) ;
123- form . set ( "response_format" , "b64_json" ) ;
124- const image = inputImages [ 0 ] ;
125- if ( ! image ) {
126- throw new Error ( "DeepInfra image edit missing reference image." ) ;
127- }
128- const mimeType = normalizeOptionalString ( image . mimeType ) ?? "image/png" ;
129- form . append (
130- "image" ,
131- new Blob ( [ new Uint8Array ( image . buffer ) ] , { type : mimeType } ) ,
132- imageSourceUploadFileName ( { image, index : 0 } ) ,
133- ) ;
134- const multipartHeaders = new Headers ( headers ) ;
135- multipartHeaders . delete ( "Content-Type" ) ;
136- return postMultipartRequest ( {
137- url : `${ baseUrl } /${ endpoint } ` ,
138- headers : multipartHeaders ,
139- body : form ,
140- timeoutMs : req . timeoutMs ,
141- fetchFn : fetch ,
142- allowPrivateNetwork,
143- dispatcherPolicy,
144- } ) ;
145- } ) ( )
146- : postJsonRequest ( {
147- url : `${ baseUrl } /${ endpoint } ` ,
148- headers : new Headers ( {
149- ...Object . fromEntries ( headers . entries ( ) ) ,
150- "Content-Type" : "application/json" ,
151- } ) ,
152- body : {
153- model,
154- prompt : req . prompt ,
155- n : count ,
156- size,
157- response_format : "b64_json" ,
158- } ,
159- timeoutMs : req . timeoutMs ,
160- fetchFn : fetch ,
161- allowPrivateNetwork,
162- dispatcherPolicy,
163- } ) ;
164-
165- const { response, release } = await request ;
166- try {
167- await assertOkOrThrowHttpError (
168- response ,
169- isEdit ? "DeepInfra image edit failed" : "DeepInfra image generation failed" ,
170- ) ;
171- const images = parseOpenAiCompatibleImageResponse (
172- ( await response . json ( ) ) as DeepInfraImageApiResponse ,
173- { defaultMimeType : "image/jpeg" , sniffMimeType : true } ,
174- ) ;
175- if ( images . length === 0 ) {
176- throw new Error ( "DeepInfra image response did not include generated image data" ) ;
177- }
178- return { images, model } ;
179- } finally {
180- await release ( ) ;
181- }
78+ return { kind : "multipart" , form } ;
79+ } ,
80+ response : { defaultMimeType : "image/jpeg" , sniffMimeType : true } ,
81+ tooManyInputImagesError : "DeepInfra image editing supports one reference image." ,
82+ missingApiKeyError : "DeepInfra API key missing" ,
83+ emptyResponseError : "DeepInfra image response did not include generated image data" ,
84+ failureLabels : {
85+ generate : "DeepInfra image generation failed" ,
86+ edit : "DeepInfra image edit failed" ,
18287 } ,
183- } ;
88+ } ) ;
18489}
0 commit comments