libre-webui 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/dist/db.d.ts.map +1 -1
- package/backend/dist/db.js +63 -0
- package/backend/dist/db.js.map +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +4 -4
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/routes/chat.d.ts.map +1 -1
- package/backend/dist/routes/chat.js +93 -10
- package/backend/dist/routes/chat.js.map +1 -1
- package/backend/dist/routes/imageGen.d.ts.map +1 -1
- package/backend/dist/routes/imageGen.js +52 -29
- package/backend/dist/routes/imageGen.js.map +1 -1
- package/backend/dist/routes/plugins.d.ts.map +1 -1
- package/backend/dist/routes/plugins.js +218 -41
- package/backend/dist/routes/plugins.js.map +1 -1
- package/backend/dist/routes/preferences.d.ts.map +1 -1
- package/backend/dist/routes/preferences.js +5 -4
- package/backend/dist/routes/preferences.js.map +1 -1
- package/backend/dist/routes/tts.js +2 -2
- package/backend/dist/routes/tts.js.map +1 -1
- package/backend/dist/services/assistantCompletionService.d.ts +2 -1
- package/backend/dist/services/assistantCompletionService.d.ts.map +1 -1
- package/backend/dist/services/assistantCompletionService.js +3 -1
- package/backend/dist/services/assistantCompletionService.js.map +1 -1
- package/backend/dist/services/chatGenerationService.d.ts +5 -3
- package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
- package/backend/dist/services/chatGenerationService.js +18 -6
- package/backend/dist/services/chatGenerationService.js.map +1 -1
- package/backend/dist/services/chatRequestService.d.ts +6 -4
- package/backend/dist/services/chatRequestService.d.ts.map +1 -1
- package/backend/dist/services/chatRequestService.js +10 -2
- package/backend/dist/services/chatRequestService.js.map +1 -1
- package/backend/dist/services/chatService.d.ts +2 -2
- package/backend/dist/services/chatService.d.ts.map +1 -1
- package/backend/dist/services/chatService.js +29 -17
- package/backend/dist/services/chatService.js.map +1 -1
- package/backend/dist/services/embeddingService.js +1 -1
- package/backend/dist/services/embeddingService.js.map +1 -1
- package/backend/dist/services/pluginActivationService.d.ts +11 -0
- package/backend/dist/services/pluginActivationService.d.ts.map +1 -0
- package/backend/dist/services/pluginActivationService.js +163 -0
- package/backend/dist/services/pluginActivationService.js.map +1 -0
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.js +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
- package/backend/dist/services/pluginCredentialsService.d.ts +16 -8
- package/backend/dist/services/pluginCredentialsService.d.ts.map +1 -1
- package/backend/dist/services/pluginCredentialsService.js +47 -14
- package/backend/dist/services/pluginCredentialsService.js.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.d.ts +2 -2
- package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.js +33 -13
- package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.d.ts +11 -7
- package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.js +265 -81
- package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
- package/backend/dist/services/pluginService.d.ts +55 -25
- package/backend/dist/services/pluginService.d.ts.map +1 -1
- package/backend/dist/services/pluginService.js +658 -170
- package/backend/dist/services/pluginService.js.map +1 -1
- package/backend/dist/services/pluginTTSService.d.ts +4 -4
- package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
- package/backend/dist/services/pluginTTSService.js +24 -28
- package/backend/dist/services/pluginTTSService.js.map +1 -1
- package/backend/dist/services/pluginVariablesService.d.ts +6 -1
- package/backend/dist/services/pluginVariablesService.d.ts.map +1 -1
- package/backend/dist/services/pluginVariablesService.js +59 -1
- package/backend/dist/services/pluginVariablesService.js.map +1 -1
- package/backend/dist/services/preferencesService.d.ts +2 -2
- package/backend/dist/services/preferencesService.d.ts.map +1 -1
- package/backend/dist/services/preferencesService.js +78 -10
- package/backend/dist/services/preferencesService.js.map +1 -1
- package/backend/dist/services/titleGenerationService.d.ts +6 -4
- package/backend/dist/services/titleGenerationService.d.ts.map +1 -1
- package/backend/dist/services/titleGenerationService.js +9 -5
- package/backend/dist/services/titleGenerationService.js.map +1 -1
- package/backend/dist/services/workAgentService.d.ts +5 -2
- package/backend/dist/services/workAgentService.d.ts.map +1 -1
- package/backend/dist/services/workAgentService.js +315 -44
- package/backend/dist/services/workAgentService.js.map +1 -1
- package/backend/dist/services/workModelProviderService.d.ts +6 -3
- package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
- package/backend/dist/services/workModelProviderService.js +243 -19
- package/backend/dist/services/workModelProviderService.js.map +1 -1
- package/backend/dist/services/workTaskService.d.ts +2 -0
- package/backend/dist/services/workTaskService.d.ts.map +1 -1
- package/backend/dist/services/workTaskService.js +89 -14
- package/backend/dist/services/workTaskService.js.map +1 -1
- package/backend/dist/storage.d.ts.map +1 -1
- package/backend/dist/storage.js +9 -6
- package/backend/dist/storage.js.map +1 -1
- package/backend/dist/storageMappers.d.ts +3 -0
- package/backend/dist/storageMappers.d.ts.map +1 -1
- package/backend/dist/storageMappers.js +3 -0
- package/backend/dist/storageMappers.js.map +1 -1
- package/backend/dist/types/index.d.ts +54 -1
- package/backend/dist/types/index.d.ts.map +1 -1
- package/backend/dist/types/index.js.map +1 -1
- package/backend/dist/types/work.d.ts +1 -1
- package/backend/dist/types/work.d.ts.map +1 -1
- package/backend/dist/utils/chatContext.d.ts +13 -1
- package/backend/dist/utils/chatContext.d.ts.map +1 -1
- package/backend/dist/utils/chatContext.js +52 -0
- package/backend/dist/utils/chatContext.js.map +1 -1
- package/backend/dist/utils/chatProviderSelection.d.ts +15 -0
- package/backend/dist/utils/chatProviderSelection.d.ts.map +1 -0
- package/backend/dist/utils/chatProviderSelection.js +59 -0
- package/backend/dist/utils/chatProviderSelection.js.map +1 -0
- package/backend/dist/utils/imageGenerationValidation.d.ts +3 -0
- package/backend/dist/utils/imageGenerationValidation.d.ts.map +1 -0
- package/backend/dist/utils/imageGenerationValidation.js +55 -0
- package/backend/dist/utils/imageGenerationValidation.js.map +1 -0
- package/backend/dist/utils/openAIResponsesAdapter.d.ts +88 -0
- package/backend/dist/utils/openAIResponsesAdapter.d.ts.map +1 -0
- package/backend/dist/utils/openAIResponsesAdapter.js +521 -0
- package/backend/dist/utils/openAIResponsesAdapter.js.map +1 -0
- package/backend/dist/utils/pluginChatAdapter.d.ts +7 -4
- package/backend/dist/utils/pluginChatAdapter.d.ts.map +1 -1
- package/backend/dist/utils/pluginChatAdapter.js +33 -5
- package/backend/dist/utils/pluginChatAdapter.js.map +1 -1
- package/backend/dist/utils/pluginChatContext.d.ts.map +1 -1
- package/backend/dist/utils/pluginChatContext.js +5 -1
- package/backend/dist/utils/pluginChatContext.js.map +1 -1
- package/backend/dist/utils/pluginConnectionVariables.d.ts +6 -0
- package/backend/dist/utils/pluginConnectionVariables.d.ts.map +1 -0
- package/backend/dist/utils/pluginConnectionVariables.js +52 -0
- package/backend/dist/utils/pluginConnectionVariables.js.map +1 -0
- package/backend/dist/utils/pluginDefinitionTrust.d.ts +9 -0
- package/backend/dist/utils/pluginDefinitionTrust.d.ts.map +1 -0
- package/backend/dist/utils/pluginDefinitionTrust.js +71 -0
- package/backend/dist/utils/pluginDefinitionTrust.js.map +1 -0
- package/backend/dist/utils/pluginStreamAdapter.d.ts +3 -0
- package/backend/dist/utils/pluginStreamAdapter.d.ts.map +1 -1
- package/backend/dist/utils/pluginStreamAdapter.js +410 -0
- package/backend/dist/utils/pluginStreamAdapter.js.map +1 -1
- package/backend/dist/utils/pluginStreaming.d.ts +7 -1
- package/backend/dist/utils/pluginStreaming.d.ts.map +1 -1
- package/backend/dist/utils/pluginStreaming.js +12 -1
- package/backend/dist/utils/pluginStreaming.js.map +1 -1
- package/backend/dist/utils/pluginValidation.d.ts +20 -2
- package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
- package/backend/dist/utils/pluginValidation.js +187 -17
- package/backend/dist/utils/pluginValidation.js.map +1 -1
- package/backend/dist/utils/pluginVariableValidation.d.ts +7 -0
- package/backend/dist/utils/pluginVariableValidation.d.ts.map +1 -1
- package/backend/dist/utils/pluginVariableValidation.js +79 -4
- package/backend/dist/utils/pluginVariableValidation.js.map +1 -1
- package/backend/dist/websocketServer.d.ts.map +1 -1
- package/backend/dist/websocketServer.js +16 -3
- package/backend/dist/websocketServer.js.map +1 -1
- package/backend/package.json +1 -1
- package/frontend/dist/assets/index-CKV9Lnj8.js +5 -0
- package/frontend/dist/assets/index-Dme2Ozol.css +1 -0
- package/frontend/dist/index.html +3 -3
- package/frontend/dist/js/{ArtifactContainer-BHSBrlQB.js → ArtifactContainer-B0uVR8Z9.js} +1 -1
- package/frontend/dist/js/{ArtifactDemoPage-BHGJmJAT.js → ArtifactDemoPage-DBVPHFxk.js} +1 -1
- package/frontend/dist/js/{ArtifactSlideOutPanel-s8vcE5Ea.js → ArtifactSlideOutPanel-Cg5kAwv9.js} +1 -1
- package/frontend/dist/js/ChatPage-CPHlIZqU.js +16 -0
- package/frontend/dist/js/{FirstTimeSetup-BYWAVAdE.js → FirstTimeSetup-DksL5arK.js} +1 -1
- package/frontend/dist/js/GalleryPage-1mdUGo_N.js +1 -0
- package/frontend/dist/js/LibreClawPage-qGr1Jy8p.js +1 -0
- package/frontend/dist/js/ModelSelector-CUnwRmNU.js +1 -0
- package/frontend/dist/js/ModelsPage-DMYVg3LT.js +2 -0
- package/frontend/dist/js/PersonasPage-Ct-KKW-j.js +13 -0
- package/frontend/dist/js/{RichMessageContent-BdU5vXz9.js → RichMessageContent-CGBAcUES.js} +1 -1
- package/frontend/dist/js/SettingsModal-BVj3gFCS.js +1 -0
- package/frontend/dist/js/UserManagementPage-D3tLGtTu.js +1 -0
- package/frontend/dist/js/WorkPage-DhTjy-kf.js +2 -0
- package/frontend/dist/js/api-YWoSobKv.js +19 -0
- package/frontend/dist/js/{estree-Bu_-Wi6O.js → estree-PDLT672k.js} +1 -1
- package/frontend/dist/js/{html-Ca764Rus.js → html-CkhF9wDQ.js} +1 -1
- package/frontend/dist/js/{markdown-DaiQGPEs.js → markdown-B1iNUbse.js} +1 -1
- package/frontend/dist/js/{standalone-DWWnsbIr.js → standalone-CCd6rkf-.js} +1 -1
- package/frontend/dist/js/{typescript-CatjJeHm.js → typescript-DKJ1uM5L.js} +1 -1
- package/frontend/dist/js/useBaseQuery-MuQj7vA5.js +1 -0
- package/frontend/dist/js/useQuery-CYGPkxWR.js +1 -0
- package/package.json +2 -2
- package/plugins/github.json +1 -2
- package/plugins/huggingface.json +30 -30
- package/plugins/openai.json +53 -22
- package/frontend/dist/assets/index-DkShhNBf.js +0 -5
- package/frontend/dist/assets/index-bdSWBsAM.css +0 -1
- package/frontend/dist/js/ChatPage-B6Hm_pdu.js +0 -16
- package/frontend/dist/js/GalleryPage-CH4f65q8.js +0 -1
- package/frontend/dist/js/LibreClawPage-CcH7M3mJ.js +0 -1
- package/frontend/dist/js/ModelSelector-T1KZtIde.js +0 -1
- package/frontend/dist/js/ModelsPage-C1bM_Yoc.js +0 -2
- package/frontend/dist/js/PersonasPage-T_PrhnPG.js +0 -13
- package/frontend/dist/js/SettingsModal-BVj-D1L4.js +0 -1
- package/frontend/dist/js/UserManagementPage-Pix71oRW.js +0 -1
- package/frontend/dist/js/WorkPage-DdOVGyj_.js +0 -2
- package/frontend/dist/js/api-Do6u0tMM.js +0 -19
- package/frontend/dist/js/useBaseQuery-CVNuhuID.js +0 -1
- package/frontend/dist/js/useQuery-CYhC_da4.js +0 -1
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import axios from 'axios';
|
|
18
|
-
import { validatePluginModel } from '../utils/pluginValidation.js';
|
|
18
|
+
import { assertSafePluginEndpoint, applyModelEndpointTemplate, resolvePluginOperationEndpoint, validatePluginModel, } from '../utils/pluginValidation.js';
|
|
19
19
|
export class PluginEmbeddingService {
|
|
20
20
|
constructor(deps) {
|
|
21
21
|
this.deps = deps;
|
|
22
22
|
}
|
|
23
23
|
getPluginForEmbedding(model, pluginId, userId) {
|
|
24
|
-
const allPlugins = this.deps.getAllPlugins();
|
|
24
|
+
const allPlugins = this.deps.getAllPlugins(userId);
|
|
25
25
|
for (const plugin of allPlugins) {
|
|
26
26
|
if (pluginId && plugin.id !== pluginId) {
|
|
27
27
|
continue;
|
|
@@ -46,7 +46,7 @@ export class PluginEmbeddingService {
|
|
|
46
46
|
}
|
|
47
47
|
getAvailableEmbeddingModels(userId) {
|
|
48
48
|
const models = [];
|
|
49
|
-
const allPlugins = this.deps.getAllPlugins();
|
|
49
|
+
const allPlugins = this.deps.getAllPlugins(userId);
|
|
50
50
|
for (const plugin of allPlugins) {
|
|
51
51
|
const embeddingCapability = this.getEmbeddingCapability(plugin);
|
|
52
52
|
const noAuthRequired = embeddingCapability?.config
|
|
@@ -87,15 +87,28 @@ export class PluginEmbeddingService {
|
|
|
87
87
|
const embeddingCapability = this.getEmbeddingCapability(plugin);
|
|
88
88
|
const noAuthRequired = embeddingCapability?.config
|
|
89
89
|
?.no_auth_required === true;
|
|
90
|
+
const pluginVars = this.deps.getPluginVariables(plugin, userId);
|
|
91
|
+
const endpointVariable = embeddingCapability?.config?.endpoint_variable ||
|
|
92
|
+
(embeddingCapability && plugin.type !== 'embedding'
|
|
93
|
+
? 'embedding_endpoint'
|
|
94
|
+
: 'endpoint');
|
|
95
|
+
const endpointOverride = pluginVars[endpointVariable];
|
|
96
|
+
let effectiveEndpoint = embeddingCapability?.endpoint || plugin.endpoint;
|
|
97
|
+
if (endpointVariable === 'endpoint') {
|
|
98
|
+
effectiveEndpoint = resolvePluginOperationEndpoint(effectiveEndpoint, pluginVars);
|
|
99
|
+
}
|
|
100
|
+
else if (typeof endpointOverride === 'string' &&
|
|
101
|
+
endpointOverride.trim().length > 0) {
|
|
102
|
+
effectiveEndpoint = this.deps.validateEndpointUrl(endpointOverride.trim());
|
|
103
|
+
}
|
|
104
|
+
const processedEndpoint = plugin.id === 'huggingface'
|
|
105
|
+
? applyModelEndpointTemplate(effectiveEndpoint, model)
|
|
106
|
+
: getEmbeddingEndpoint(effectiveEndpoint);
|
|
107
|
+
assertSafePluginEndpoint(processedEndpoint, 'embedding endpoint');
|
|
90
108
|
const apiKey = this.deps.getApiKey(plugin, userId);
|
|
91
109
|
if (!apiKey && !noAuthRequired) {
|
|
92
|
-
throw new Error(`API key not found for plugin ${plugin.id} (
|
|
110
|
+
throw new Error(`API key not found for plugin ${plugin.id} (save a provider credential in Settings)`);
|
|
93
111
|
}
|
|
94
|
-
const pluginVars = this.deps.getPluginVariables(plugin, userId);
|
|
95
|
-
const endpointOverride = pluginVars.endpoint;
|
|
96
|
-
const effectiveEndpoint = (endpointOverride && this.deps.validateEndpointUrl(endpointOverride)) ||
|
|
97
|
-
embeddingCapability?.endpoint ||
|
|
98
|
-
plugin.endpoint;
|
|
99
112
|
const headers = {
|
|
100
113
|
'Content-Type': 'application/json',
|
|
101
114
|
};
|
|
@@ -105,13 +118,20 @@ export class PluginEmbeddingService {
|
|
|
105
118
|
: apiKey;
|
|
106
119
|
headers[plugin.auth.header] = authValue;
|
|
107
120
|
}
|
|
108
|
-
const response = await axios.post(
|
|
109
|
-
model,
|
|
110
|
-
input,
|
|
111
|
-
}, {
|
|
121
|
+
const response = await axios.post(processedEndpoint, plugin.id === 'huggingface' ? { inputs: input } : { model, input }, {
|
|
112
122
|
headers,
|
|
113
123
|
timeout: 60000,
|
|
124
|
+
maxRedirects: 0,
|
|
114
125
|
});
|
|
126
|
+
if (Array.isArray(response.data) &&
|
|
127
|
+
response.data.every(value => typeof value === 'number')) {
|
|
128
|
+
return { embeddings: [response.data] };
|
|
129
|
+
}
|
|
130
|
+
if (Array.isArray(response.data) &&
|
|
131
|
+
response.data.every(value => Array.isArray(value) &&
|
|
132
|
+
value.every(component => typeof component === 'number'))) {
|
|
133
|
+
return { embeddings: response.data };
|
|
134
|
+
}
|
|
115
135
|
if (Array.isArray(response.data?.embeddings)) {
|
|
116
136
|
return {
|
|
117
137
|
embeddings: response.data.embeddings,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pluginEmbeddingService.js","sourceRoot":"","sources":["../../src/services/pluginEmbeddingService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"pluginEmbeddingService.js","sourceRoot":"","sources":["../../src/services/pluginEmbeddingService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
import { ImageGenConfig, ImageGenResponse, Plugin } from '../types/index.js';
|
|
2
2
|
type PluginVariables = Record<string, string | number | boolean>;
|
|
3
|
+
type ImageGenImage = ImageGenResponse['images'][number];
|
|
3
4
|
export interface PluginImageGenerationServiceDependencies {
|
|
4
|
-
getAllPlugins(): Plugin[];
|
|
5
|
-
getPlugin(id: string): Plugin | null;
|
|
5
|
+
getAllPlugins(userId?: string): Plugin[];
|
|
6
|
+
getPlugin(id: string, userId?: string): Plugin | null;
|
|
6
7
|
getApiKey(plugin: Plugin, userId?: string): string | null;
|
|
7
8
|
getPluginVariables(plugin: Plugin, userId?: string): PluginVariables;
|
|
8
|
-
validateEndpointUrl(endpoint: string): string
|
|
9
|
+
validateEndpointUrl(endpoint: string): string;
|
|
9
10
|
}
|
|
10
11
|
export declare class PluginImageGenerationService {
|
|
11
12
|
private readonly deps;
|
|
12
13
|
constructor(deps: PluginImageGenerationServiceDependencies);
|
|
13
|
-
getPluginForImageGen(model: string): Plugin | null;
|
|
14
|
-
getAvailableImageGenModels(): {
|
|
14
|
+
getPluginForImageGen(model: string, pluginId: string, userId?: string): Plugin | null;
|
|
15
|
+
getAvailableImageGenModels(userId?: string): {
|
|
15
16
|
model: string;
|
|
16
17
|
plugin: string;
|
|
17
18
|
config?: ImageGenConfig;
|
|
18
19
|
}[];
|
|
19
|
-
executeImageGenRequest(model: string, prompt: string, options
|
|
20
|
+
executeImageGenRequest(model: string, prompt: string, options: {
|
|
20
21
|
size?: string;
|
|
21
22
|
quality?: string;
|
|
22
23
|
style?: string;
|
|
23
24
|
n?: number;
|
|
24
25
|
response_format?: 'url' | 'b64_json';
|
|
26
|
+
pluginId: string;
|
|
27
|
+
userId?: string;
|
|
25
28
|
}): Promise<ImageGenResponse>;
|
|
26
|
-
getImageGenConfig(pluginId: string): ImageGenConfig | null;
|
|
29
|
+
getImageGenConfig(pluginId: string, userId?: string): ImageGenConfig | null;
|
|
27
30
|
}
|
|
31
|
+
export declare function normalizeImageGenerationResponse(responseData: unknown): ImageGenImage[];
|
|
28
32
|
export {};
|
|
29
33
|
//# sourceMappingURL=pluginImageGenerationService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pluginImageGenerationService.d.ts","sourceRoot":"","sources":["../../src/services/pluginImageGenerationService.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"pluginImageGenerationService.d.ts","sourceRoot":"","sources":["../../src/services/pluginImageGenerationService.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAY7E,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AACjE,KAAK,aAAa,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,WAAW,wCAAwC;IACvD,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACtD,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC1D,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IACrE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/C;AAED,qBAAa,4BAA4B;IAErC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,wCAAwC;IAGjE,oBAAoB,CAClB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,GAAG,IAAI;IAchB,0BAA0B,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG;QAC3C,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,cAAc,CAAC;KACzB,EAAE;IAiCG,sBAAsB,CAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,CAAC,CAAC,EAAE,MAAM,CAAC;QACX,eAAe,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;QACrC,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC,gBAAgB,CAAC;IA8L5B,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;CAU5E;AAED,wBAAgB,gCAAgC,CAC9C,YAAY,EAAE,OAAO,GACpB,aAAa,EAAE,CAYjB"}
|
|
@@ -15,67 +15,58 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import axios from 'axios';
|
|
18
|
-
import {
|
|
18
|
+
import { normalizeImageGenerationCount, normalizeImageMediaType, } from '../utils/imageGenerationValidation.js';
|
|
19
|
+
import { assertSafePluginEndpoint, applyModelEndpointTemplate, resolvePluginOperationEndpoint, validatePluginModel, } from '../utils/pluginValidation.js';
|
|
19
20
|
export class PluginImageGenerationService {
|
|
20
21
|
constructor(deps) {
|
|
21
22
|
this.deps = deps;
|
|
22
23
|
}
|
|
23
|
-
getPluginForImageGen(model) {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
if (plugin.type === 'image' && plugin.model_map.includes(model)) {
|
|
33
|
-
return plugin;
|
|
34
|
-
}
|
|
24
|
+
getPluginForImageGen(model, pluginId, userId) {
|
|
25
|
+
const plugin = this.deps.getPlugin(pluginId, userId);
|
|
26
|
+
if (!plugin?.active)
|
|
27
|
+
return null;
|
|
28
|
+
const supportedModels = plugin.capabilities?.image?.model_map ??
|
|
29
|
+
(plugin.type === 'image' ? plugin.model_map : []);
|
|
30
|
+
if (supportedModels.includes(model)) {
|
|
31
|
+
return plugin;
|
|
35
32
|
}
|
|
36
33
|
return null;
|
|
37
34
|
}
|
|
38
|
-
getAvailableImageGenModels() {
|
|
35
|
+
getAvailableImageGenModels(userId) {
|
|
39
36
|
const models = [];
|
|
40
|
-
const allPlugins = this.deps.getAllPlugins();
|
|
37
|
+
const allPlugins = this.deps.getAllPlugins(userId);
|
|
41
38
|
for (const plugin of allPlugins) {
|
|
42
|
-
if (plugin.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
models.push({
|
|
50
|
-
model,
|
|
51
|
-
plugin: plugin.id,
|
|
52
|
-
config: imageCapability.config,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
39
|
+
if (!plugin.active)
|
|
40
|
+
continue;
|
|
41
|
+
const imageCapability = plugin.capabilities?.image;
|
|
42
|
+
const supportedModels = imageCapability?.model_map ??
|
|
43
|
+
(plugin.type === 'image' ? plugin.model_map : []);
|
|
44
|
+
if (supportedModels.length === 0) {
|
|
45
|
+
continue;
|
|
56
46
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
47
|
+
const noAuthRequired = imageCapability?.config
|
|
48
|
+
?.no_auth_required === true;
|
|
49
|
+
const apiKey = this.deps.getApiKey(plugin, userId);
|
|
50
|
+
if (apiKey || noAuthRequired) {
|
|
51
|
+
for (const model of supportedModels) {
|
|
52
|
+
models.push({
|
|
53
|
+
model,
|
|
54
|
+
plugin: plugin.id,
|
|
55
|
+
config: imageCapability?.config,
|
|
56
|
+
});
|
|
66
57
|
}
|
|
67
58
|
}
|
|
68
59
|
}
|
|
69
60
|
return models;
|
|
70
61
|
}
|
|
71
|
-
async executeImageGenRequest(model, prompt, options
|
|
62
|
+
async executeImageGenRequest(model, prompt, options) {
|
|
72
63
|
validatePluginModel(model);
|
|
73
64
|
if (!prompt || typeof prompt !== 'string') {
|
|
74
65
|
throw new Error('Invalid prompt: must be a non-empty string');
|
|
75
66
|
}
|
|
76
|
-
const plugin = this.getPluginForImageGen(model);
|
|
67
|
+
const plugin = this.getPluginForImageGen(model, options.pluginId, options.userId);
|
|
77
68
|
if (!plugin) {
|
|
78
|
-
throw new Error(`No image generation plugin found for model: ${model}`);
|
|
69
|
+
throw new Error(`No image generation plugin found for model: ${model} in plugin ${options.pluginId}`);
|
|
79
70
|
}
|
|
80
71
|
let endpoint;
|
|
81
72
|
let imageConfig;
|
|
@@ -86,22 +77,45 @@ export class PluginImageGenerationService {
|
|
|
86
77
|
else {
|
|
87
78
|
endpoint = plugin.endpoint;
|
|
88
79
|
}
|
|
89
|
-
const imageVars = this.deps.getPluginVariables(plugin);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
const imageVars = this.deps.getPluginVariables(plugin, options.userId);
|
|
81
|
+
const imageCount = normalizeImageGenerationCount(options.n);
|
|
82
|
+
const endpointVariable = imageConfig?.endpoint_variable ||
|
|
83
|
+
(plugin.type === 'image' ? 'endpoint' : 'image_endpoint');
|
|
84
|
+
const endpointOverride = imageVars[endpointVariable];
|
|
85
|
+
if (endpointVariable === 'endpoint') {
|
|
86
|
+
endpoint = resolvePluginOperationEndpoint(endpoint, imageVars);
|
|
87
|
+
}
|
|
88
|
+
else if (typeof endpointOverride === 'string' &&
|
|
89
|
+
endpointOverride.trim().length > 0) {
|
|
90
|
+
const validatedEndpoint = this.deps.validateEndpointUrl(endpointOverride.trim());
|
|
91
|
+
if (!validatedEndpoint) {
|
|
92
|
+
throw new Error(`Invalid image endpoint override configured for plugin ${plugin.id}`);
|
|
93
|
+
}
|
|
94
|
+
endpoint = validatedEndpoint;
|
|
94
95
|
}
|
|
96
|
+
endpoint =
|
|
97
|
+
plugin.id === 'huggingface'
|
|
98
|
+
? applyModelEndpointTemplate(endpoint, model)
|
|
99
|
+
: endpoint;
|
|
100
|
+
const baseUrl = parseImageEndpoint(endpoint);
|
|
95
101
|
const noAuthRequired = imageConfig?.no_auth_required ===
|
|
96
102
|
true;
|
|
97
|
-
const apiKey = this.deps.getApiKey(plugin);
|
|
103
|
+
const apiKey = this.deps.getApiKey(plugin, options.userId);
|
|
98
104
|
if (!apiKey && !noAuthRequired) {
|
|
99
|
-
throw new Error(`API key not found for plugin ${plugin.id} (
|
|
105
|
+
throw new Error(`API key not found for plugin ${plugin.id} (save a provider credential in Settings)`);
|
|
100
106
|
}
|
|
101
107
|
if (imageConfig?.max_prompt_length &&
|
|
102
108
|
prompt.length > imageConfig.max_prompt_length) {
|
|
103
109
|
throw new Error(`Prompt exceeds maximum length of ${imageConfig.max_prompt_length} characters`);
|
|
104
110
|
}
|
|
111
|
+
if (imageCount !== undefined) {
|
|
112
|
+
if (imageConfig?.supports_n === false && imageCount !== 1) {
|
|
113
|
+
throw new Error(`Plugin ${plugin.id} supports only one image per request`);
|
|
114
|
+
}
|
|
115
|
+
if (imageConfig?.max_n && imageCount > imageConfig.max_n) {
|
|
116
|
+
throw new Error(`Image count exceeds maximum of ${imageConfig.max_n} for plugin ${plugin.id}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
105
119
|
const headers = {
|
|
106
120
|
'Content-Type': 'application/json',
|
|
107
121
|
};
|
|
@@ -118,38 +132,65 @@ export class PluginImageGenerationService {
|
|
|
118
132
|
prompt,
|
|
119
133
|
size: options.size || imageConfig?.default_size || '1024x1024',
|
|
120
134
|
quality: options.quality || imageConfig?.default_quality || 'standard',
|
|
121
|
-
n: options.n || 1,
|
|
122
|
-
response_format: options.response_format || 'url',
|
|
123
135
|
};
|
|
136
|
+
if (imageConfig?.supports_n !== false) {
|
|
137
|
+
payload.n = imageCount ?? 1;
|
|
138
|
+
}
|
|
139
|
+
if (imageConfig?.supports_response_format !== false) {
|
|
140
|
+
payload.response_format =
|
|
141
|
+
options.response_format ||
|
|
142
|
+
imageConfig?.default_response_format ||
|
|
143
|
+
'url';
|
|
144
|
+
}
|
|
124
145
|
if (options.style || imageConfig?.default_style) {
|
|
125
146
|
payload.style = options.style || imageConfig?.default_style;
|
|
126
147
|
}
|
|
127
|
-
|
|
128
|
-
if (plugin.id === 'comfyui' || endpoint.includes('/prompt')) {
|
|
148
|
+
if (plugin.id === 'comfyui') {
|
|
129
149
|
return executeComfyUIRequest(baseUrl, prompt, {
|
|
130
150
|
...options,
|
|
151
|
+
headers,
|
|
131
152
|
model,
|
|
132
|
-
|
|
153
|
+
pluginId: plugin.id,
|
|
154
|
+
pluginVars: imageVars,
|
|
133
155
|
});
|
|
134
156
|
}
|
|
135
157
|
try {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
158
|
+
if (plugin.id === 'huggingface') {
|
|
159
|
+
const [width, height] = String(payload.size)
|
|
160
|
+
.split('x')
|
|
161
|
+
.map(value => Number.parseInt(value, 10));
|
|
162
|
+
const response = await axios.post(endpoint, {
|
|
163
|
+
inputs: prompt,
|
|
164
|
+
...(Number.isInteger(width) && Number.isInteger(height)
|
|
165
|
+
? { parameters: { width, height } }
|
|
166
|
+
: {}),
|
|
167
|
+
}, {
|
|
168
|
+
headers,
|
|
169
|
+
timeout: 120000,
|
|
170
|
+
responseType: 'arraybuffer',
|
|
171
|
+
maxRedirects: 0,
|
|
172
|
+
});
|
|
173
|
+
const mimeType = normalizeImageMediaType(response.headers['content-type']);
|
|
141
174
|
return {
|
|
142
|
-
images:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
175
|
+
images: [
|
|
176
|
+
{
|
|
177
|
+
b64_json: Buffer.from(response.data).toString('base64'),
|
|
178
|
+
...(mimeType ? { mime_type: mimeType } : {}),
|
|
179
|
+
},
|
|
180
|
+
],
|
|
147
181
|
model,
|
|
182
|
+
pluginId: plugin.id,
|
|
148
183
|
};
|
|
149
184
|
}
|
|
185
|
+
const response = await axios.post(endpoint, payload, {
|
|
186
|
+
headers,
|
|
187
|
+
timeout: 120000,
|
|
188
|
+
maxRedirects: 0,
|
|
189
|
+
});
|
|
150
190
|
return {
|
|
151
|
-
images:
|
|
191
|
+
images: normalizeImageGenerationResponse(response.data),
|
|
152
192
|
model,
|
|
193
|
+
pluginId: plugin.id,
|
|
153
194
|
};
|
|
154
195
|
}
|
|
155
196
|
catch (error) {
|
|
@@ -162,9 +203,9 @@ export class PluginImageGenerationService {
|
|
|
162
203
|
throw error;
|
|
163
204
|
}
|
|
164
205
|
}
|
|
165
|
-
getImageGenConfig(pluginId) {
|
|
166
|
-
const plugin = this.deps.getPlugin(pluginId);
|
|
167
|
-
if (!plugin)
|
|
206
|
+
getImageGenConfig(pluginId, userId) {
|
|
207
|
+
const plugin = this.deps.getPlugin(pluginId, userId);
|
|
208
|
+
if (!plugin?.active)
|
|
168
209
|
return null;
|
|
169
210
|
if (plugin.capabilities?.image?.config) {
|
|
170
211
|
return plugin.capabilities.image.config;
|
|
@@ -172,20 +213,134 @@ export class PluginImageGenerationService {
|
|
|
172
213
|
return null;
|
|
173
214
|
}
|
|
174
215
|
}
|
|
175
|
-
function
|
|
216
|
+
export function normalizeImageGenerationResponse(responseData) {
|
|
217
|
+
const candidates = getImageCandidates(responseData);
|
|
218
|
+
const images = candidates.flatMap(candidate => {
|
|
219
|
+
const image = normalizeImageCandidate(candidate);
|
|
220
|
+
return image ? [image] : [];
|
|
221
|
+
});
|
|
222
|
+
if (images.length === 0) {
|
|
223
|
+
throw new Error('Image provider returned no usable image data');
|
|
224
|
+
}
|
|
225
|
+
return images;
|
|
226
|
+
}
|
|
227
|
+
function getImageCandidates(responseData) {
|
|
228
|
+
if (Array.isArray(responseData)) {
|
|
229
|
+
return responseData;
|
|
230
|
+
}
|
|
231
|
+
if (!isRecord(responseData)) {
|
|
232
|
+
return [responseData];
|
|
233
|
+
}
|
|
234
|
+
if ('data' in responseData) {
|
|
235
|
+
return Array.isArray(responseData.data)
|
|
236
|
+
? responseData.data
|
|
237
|
+
: [responseData.data];
|
|
238
|
+
}
|
|
239
|
+
if ('images' in responseData) {
|
|
240
|
+
return Array.isArray(responseData.images)
|
|
241
|
+
? responseData.images
|
|
242
|
+
: [responseData.images];
|
|
243
|
+
}
|
|
244
|
+
return [responseData];
|
|
245
|
+
}
|
|
246
|
+
function normalizeImageCandidate(candidate) {
|
|
247
|
+
if (typeof candidate === 'string') {
|
|
248
|
+
const dataUrl = normalizeImageDataUrl(candidate);
|
|
249
|
+
if (dataUrl) {
|
|
250
|
+
return {
|
|
251
|
+
b64_json: dataUrl.b64Json,
|
|
252
|
+
mime_type: dataUrl.mimeType,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
const url = normalizeHttpImageUrl(candidate);
|
|
256
|
+
if (url) {
|
|
257
|
+
return { url };
|
|
258
|
+
}
|
|
259
|
+
const b64Json = normalizeCanonicalBase64(candidate);
|
|
260
|
+
return b64Json ? { b64_json: b64Json } : null;
|
|
261
|
+
}
|
|
262
|
+
if (!isRecord(candidate)) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
const normalized = {};
|
|
266
|
+
const b64DataUrl = normalizeImageDataUrl(candidate.b64_json);
|
|
267
|
+
const b64Json = b64DataUrl?.b64Json || normalizeCanonicalBase64(candidate.b64_json);
|
|
268
|
+
if (b64Json) {
|
|
269
|
+
normalized.b64_json = b64Json;
|
|
270
|
+
const mimeType = b64DataUrl?.mimeType || normalizeImageMediaType(candidate.mime_type);
|
|
271
|
+
if (mimeType) {
|
|
272
|
+
normalized.mime_type = mimeType;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const urlData = normalizeImageDataUrl(candidate.url);
|
|
276
|
+
if (urlData && !normalized.b64_json) {
|
|
277
|
+
normalized.b64_json = urlData.b64Json;
|
|
278
|
+
normalized.mime_type = urlData.mimeType;
|
|
279
|
+
}
|
|
280
|
+
else if (!urlData) {
|
|
281
|
+
const url = normalizeHttpImageUrl(candidate.url);
|
|
282
|
+
if (url) {
|
|
283
|
+
normalized.url = url;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (!normalized.url && !normalized.b64_json) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
if (typeof candidate.revised_prompt === 'string') {
|
|
290
|
+
normalized.revised_prompt = candidate.revised_prompt;
|
|
291
|
+
}
|
|
292
|
+
return normalized;
|
|
293
|
+
}
|
|
294
|
+
function normalizeImageDataUrl(value) {
|
|
295
|
+
if (typeof value !== 'string') {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
const match = /^data:(image\/[a-z0-9.+-]+)(?:;[a-z0-9!#$&^_.+-]+=[^;,]*)*;base64,([a-z0-9+/]+={0,2})$/i.exec(value.trim());
|
|
299
|
+
if (!match) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
const b64Json = normalizeCanonicalBase64(match[2]);
|
|
303
|
+
const mimeType = normalizeImageMediaType(match[1]);
|
|
304
|
+
return b64Json && mimeType ? { b64Json, mimeType } : null;
|
|
305
|
+
}
|
|
306
|
+
function normalizeCanonicalBase64(value) {
|
|
307
|
+
if (typeof value !== 'string') {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
const normalized = value.trim();
|
|
311
|
+
if (normalized.length === 0 ||
|
|
312
|
+
normalized.length % 4 !== 0 ||
|
|
313
|
+
!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(normalized)) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
const decoded = Buffer.from(normalized, 'base64');
|
|
317
|
+
if (decoded.length === 0 || decoded.toString('base64') !== normalized) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
return normalized;
|
|
321
|
+
}
|
|
322
|
+
function normalizeHttpImageUrl(value) {
|
|
323
|
+
if (typeof value !== 'string') {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
176
326
|
try {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (baseUrl.protocol !== 'https:' && !isLocalhost && !isPrivateNetwork) {
|
|
181
|
-
throw new Error(`Insecure endpoint protocol: ${baseUrl.protocol}. Only HTTPS is allowed for remote endpoints.`);
|
|
327
|
+
const url = new URL(value.trim());
|
|
328
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
329
|
+
return null;
|
|
182
330
|
}
|
|
183
|
-
return
|
|
331
|
+
return url.toString();
|
|
184
332
|
}
|
|
185
333
|
catch (_error) {
|
|
186
|
-
|
|
334
|
+
return null;
|
|
187
335
|
}
|
|
188
336
|
}
|
|
337
|
+
function isRecord(value) {
|
|
338
|
+
return typeof value === 'object' && value !== null;
|
|
339
|
+
}
|
|
340
|
+
function parseImageEndpoint(endpoint) {
|
|
341
|
+
assertSafePluginEndpoint(endpoint, 'image generation endpoint');
|
|
342
|
+
return new URL(endpoint);
|
|
343
|
+
}
|
|
189
344
|
const fluxModelConfigs = {
|
|
190
345
|
'flux1-dev': {
|
|
191
346
|
unetFile: 'flux1-dev.safetensors',
|
|
@@ -210,7 +365,23 @@ const fluxModelConfigs = {
|
|
|
210
365
|
},
|
|
211
366
|
};
|
|
212
367
|
async function executeComfyUIRequest(baseUrl, prompt, options = {}) {
|
|
213
|
-
const
|
|
368
|
+
const promptEndpoint = new URL(baseUrl);
|
|
369
|
+
promptEndpoint.hash = '';
|
|
370
|
+
const configuredPath = promptEndpoint.pathname.replace(/\/+$/, '');
|
|
371
|
+
const apiRootPath = configuredPath.endsWith('/prompt')
|
|
372
|
+
? configuredPath.slice(0, -'/prompt'.length)
|
|
373
|
+
: configuredPath;
|
|
374
|
+
promptEndpoint.pathname = `${apiRootPath}/prompt`;
|
|
375
|
+
const createOperationUrl = (operationPath) => {
|
|
376
|
+
const operationUrl = new URL(promptEndpoint);
|
|
377
|
+
operationUrl.search = '';
|
|
378
|
+
operationUrl.hash = '';
|
|
379
|
+
operationUrl.pathname = `${apiRootPath}/${operationPath}`;
|
|
380
|
+
return operationUrl;
|
|
381
|
+
};
|
|
382
|
+
const requestHeaders = options.headers || {
|
|
383
|
+
'Content-Type': 'application/json',
|
|
384
|
+
};
|
|
214
385
|
const size = options.size || '1024x1024';
|
|
215
386
|
const [width, height] = size.split('x').map(Number);
|
|
216
387
|
const model = options.model || 'flux1-dev';
|
|
@@ -338,12 +509,13 @@ async function executeComfyUIRequest(baseUrl, prompt, options = {}) {
|
|
|
338
509
|
}
|
|
339
510
|
try {
|
|
340
511
|
const clientId = `libre-webui-${Date.now()}`;
|
|
341
|
-
const promptResponse = await axios.post(
|
|
512
|
+
const promptResponse = await axios.post(promptEndpoint.toString(), {
|
|
342
513
|
prompt: workflow,
|
|
343
514
|
client_id: clientId,
|
|
344
515
|
}, {
|
|
345
|
-
headers:
|
|
516
|
+
headers: requestHeaders,
|
|
346
517
|
timeout: 10000,
|
|
518
|
+
maxRedirects: 0,
|
|
347
519
|
});
|
|
348
520
|
const promptId = promptResponse.data.prompt_id;
|
|
349
521
|
if (!promptId) {
|
|
@@ -355,7 +527,11 @@ async function executeComfyUIRequest(baseUrl, prompt, options = {}) {
|
|
|
355
527
|
while (!completed && attempts < maxAttempts) {
|
|
356
528
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
357
529
|
attempts++;
|
|
358
|
-
const historyResponse = await axios.get(
|
|
530
|
+
const historyResponse = await axios.get(createOperationUrl(`history/${encodeURIComponent(String(promptId))}`).toString(), {
|
|
531
|
+
headers: requestHeaders,
|
|
532
|
+
timeout: 5000,
|
|
533
|
+
maxRedirects: 0,
|
|
534
|
+
});
|
|
359
535
|
if (historyResponse.data[promptId]) {
|
|
360
536
|
const outputs = historyResponse.data[promptId].outputs;
|
|
361
537
|
if (outputs && Object.keys(outputs).length > 0) {
|
|
@@ -364,20 +540,28 @@ async function executeComfyUIRequest(baseUrl, prompt, options = {}) {
|
|
|
364
540
|
const nodeOutput = outputs[nodeId];
|
|
365
541
|
if (nodeOutput.images && nodeOutput.images.length > 0) {
|
|
366
542
|
const imageInfo = nodeOutput.images[0];
|
|
367
|
-
const imageUrl =
|
|
368
|
-
|
|
543
|
+
const imageUrl = createOperationUrl('view');
|
|
544
|
+
imageUrl.searchParams.set('filename', imageInfo.filename);
|
|
545
|
+
imageUrl.searchParams.set('subfolder', imageInfo.subfolder || '');
|
|
546
|
+
imageUrl.searchParams.set('type', imageInfo.type || 'output');
|
|
547
|
+
const imageResponse = await axios.get(imageUrl.toString(), {
|
|
548
|
+
headers: requestHeaders,
|
|
369
549
|
responseType: 'arraybuffer',
|
|
370
550
|
timeout: 30000,
|
|
551
|
+
maxRedirects: 0,
|
|
371
552
|
});
|
|
372
553
|
const base64Image = Buffer.from(imageResponse.data).toString('base64');
|
|
554
|
+
const mimeType = normalizeImageMediaType(imageResponse.headers['content-type']);
|
|
373
555
|
return {
|
|
374
556
|
images: [
|
|
375
557
|
{
|
|
376
558
|
b64_json: base64Image,
|
|
559
|
+
...(mimeType ? { mime_type: mimeType } : {}),
|
|
377
560
|
revised_prompt: prompt,
|
|
378
561
|
},
|
|
379
562
|
],
|
|
380
563
|
model,
|
|
564
|
+
pluginId: options.pluginId,
|
|
381
565
|
};
|
|
382
566
|
}
|
|
383
567
|
}
|