160 lines
7.2 KiB
Plaintext
160 lines
7.2 KiB
Plaintext
/**
|
|
* API Provider Selector Node - Simple model list updates
|
|
* Updates model dropdown when provider changes using hardcoded lists
|
|
*/
|
|
|
|
import { app } from "../../../scripts/app.js";
|
|
|
|
// Hardcoded model lists (must match Python node exactly)
|
|
const PROVIDER_MODELS = {
|
|
"openai": [
|
|
"gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo",
|
|
"dall-e-3", "dall-e-2", "o1-preview", "o1-mini",
|
|
// Add more OpenAI models as needed
|
|
],
|
|
"gemini": [
|
|
"gemini-2.5-flash", "gemini-2.5-pro", "gemini-2.0-flash", "gemini-2.0-pro",
|
|
"gemini-2.5-flash-image-preview", "gemini-2.0-flash-preview-image-generation",
|
|
"imagen-4.0-generate-001", "imagen-4.0-ultra-generate-001", "imagen-3.0-generate-002",
|
|
"gemini-pro", "gemini-pro-vision",
|
|
// Add more Gemini models as needed
|
|
],
|
|
"groq": [
|
|
"llama-3.3-70b-versatile", "llama-3.2-90b-vision-preview", "llama-3.2-11b-vision-preview",
|
|
"llama-3.2-3b-preview", "llama-3.2-1b-preview", "llama3-groq-70b-8192-tool-use-preview",
|
|
"llama3-groq-8b-8192-tool-use-preview", "llama-3.1-70b-versatile", "llama-3.1-8b-instant",
|
|
"mixtral-8x7b-32768", "gemma2-9b-it",
|
|
// Add more Groq models as needed
|
|
],
|
|
"anthropic": [
|
|
"claude-3-5-sonnet-20241022", "claude-3-5-haiku-20241022",
|
|
"claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307",
|
|
],
|
|
"mistral": [
|
|
"mistral-large-latest", "mistral-medium-latest", "mistral-small-latest",
|
|
"mistral-tiny-latest", "codestral-latest", "pixtral-12b-latest",
|
|
"open-mixtral-8x22b", "open-mixtral-8x7b", "open-mistral-7b",
|
|
],
|
|
"bfl": ["flux-kontext-max"],
|
|
"suno": ["V3_5", "V4", "V4_5"],
|
|
"wavespeed": [
|
|
"wavespeed-ai/flux-kontext-dev-ultra-fast", "wavespeed-ai/flux-kontext-dev/multi-ultra-fast", "wavespeed-ai/hunyuan-image-3", "wavespeed-ai/qwen-image/edit-plus",
|
|
"bytedance/portrait", "bytedance/seededit-v3", "google/imagen4", "google/imagen4-fast", "google/imagen4-ultra",
|
|
"google/nano-banana/edit", "bytedance/dreamina-v3.1/text-to-image",
|
|
"minimax/hailuo-02/t2v-standard", "minimax/hailuo-02/t2v-pro",
|
|
"minimax/hailuo-02/i2v-pro", "minimax/hailuo-02/i2v-standard",
|
|
"kwaivgi/kling-v2.1-i2v-standard", "kwaivgi/kling-v2.1-i2v-pro", "kwaivgi/kling-v2.1-i2v-master",
|
|
"kwaivgi/kling-v2.5-turbo-pro/image-to-video", "kwaivgi/kling-v2.5-turbo-pro/text-to-video",
|
|
"kwaivgi/kling-lipsync/audio-to-video", "kwaivgi/kling-lipsync/text-to-video",
|
|
"kwaivgi/kling-v1-ai-avatar-pro", "kwaivgi/kling-effects",
|
|
"google/veo3-fast/image-to-video", "google/veo3/image-to-video",
|
|
"google/veo3-fast", "wavespeed-ai/veo2-t2v", "wavespeed-ai/veo2-i2v",
|
|
"alibaba/wan-2.5/text-to-video", "alibaba/wan-2.5/text-to-video-fast",
|
|
"alibaba/wan-2.5/image-to-video", "alibaba/wan-2.5/image-to-video-fast"
|
|
]
|
|
};
|
|
|
|
app.registerExtension({
|
|
name: "ComfyLLMToolkit.APIProviderSelector",
|
|
|
|
async nodeCreated(node) {
|
|
if (node.comfyClass !== "APIProviderSelectorNode") return;
|
|
|
|
// Find the widgets
|
|
const providerWidget = node.widgets?.find(w => w.name === "provider");
|
|
const modelWidget = node.widgets?.find(w => w.name === "llm_model");
|
|
|
|
if (!providerWidget || !modelWidget) {
|
|
console.warn("APIProviderSelectorNode: Required widgets not found");
|
|
return;
|
|
}
|
|
|
|
// Function to update model list based on provider
|
|
const updateModelList = (provider) => {
|
|
// Get models from local list or fetch from server
|
|
const models = PROVIDER_MODELS[provider] || ["No models available"];
|
|
|
|
// Update the widget options
|
|
modelWidget.options.values = models;
|
|
|
|
// Set to first model if current selection is invalid
|
|
if (!models.includes(modelWidget.value)) {
|
|
modelWidget.value = models[0];
|
|
}
|
|
|
|
// Mark node as dirty to trigger re-render
|
|
node.setDirtyCanvas(true);
|
|
|
|
console.log(`APIProviderSelector: Updated models for ${provider}: ${models.length} models`);
|
|
};
|
|
|
|
// Store original callback
|
|
const originalProviderCallback = providerWidget.callback;
|
|
|
|
// Override provider widget callback
|
|
providerWidget.callback = function() {
|
|
// Call original callback if it exists
|
|
if (originalProviderCallback) {
|
|
originalProviderCallback.apply(this, arguments);
|
|
}
|
|
|
|
// Update model list when provider changes
|
|
updateModelList(providerWidget.value);
|
|
};
|
|
|
|
// Initial model list update
|
|
updateModelList(providerWidget.value);
|
|
|
|
// Try to fetch latest models from server on creation
|
|
const fetchLatestModels = async (provider) => {
|
|
try {
|
|
// Add timeout to prevent hanging
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), 3000); // 3 second timeout
|
|
|
|
const response = await fetch(`/ComfyLLMToolkit/get_provider_models?provider=${provider}`, {
|
|
signal: controller.signal
|
|
});
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
if (data.models && data.models.length > 0) {
|
|
// Update local cache with server data
|
|
PROVIDER_MODELS[provider] = data.models;
|
|
updateModelList(provider);
|
|
console.log(`APIProviderSelector: Fetched ${data.models.length} models for ${provider} from server`);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
// Silently fail - use hardcoded list
|
|
console.debug(`APIProviderSelector: Using hardcoded models for ${provider}`);
|
|
}
|
|
};
|
|
|
|
// Fetch models for current provider
|
|
fetchLatestModels(providerWidget.value);
|
|
},
|
|
|
|
async loadedGraphNode(node) {
|
|
if (node.comfyClass !== "APIProviderSelectorNode") return;
|
|
|
|
// Re-initialize model list when loading a saved workflow
|
|
const providerWidget = node.widgets?.find(w => w.name === "provider");
|
|
const modelWidget = node.widgets?.find(w => w.name === "llm_model");
|
|
|
|
if (providerWidget && modelWidget) {
|
|
const models = PROVIDER_MODELS[providerWidget.value] || ["No models available"];
|
|
modelWidget.options.values = models;
|
|
|
|
// Ensure saved model is still valid
|
|
if (!models.includes(modelWidget.value)) {
|
|
modelWidget.value = models[0];
|
|
}
|
|
|
|
console.log(`APIProviderSelector: Restored ${providerWidget.value} with model ${modelWidget.value}`);
|
|
}
|
|
}
|
|
});
|