Auto-Sync: Quad-Modal Update (2026-03-01)
This commit is contained in:
@@ -26,61 +26,61 @@ Whether you are running on an 8GB laptop or a cloud server, this node suite offl
|
||||
### 1. 🌸 Pollinations Image Gen (BYOP)
|
||||
Generates high-fidelity images directly to a ComfyUI `IMAGE` tensor.
|
||||
* **Supported Models:**
|
||||
* `flux`
|
||||
* `gptimage`
|
||||
* `gptimage-large 💎`
|
||||
* `grok-imagine`
|
||||
* `imagen-4`
|
||||
* `klein`
|
||||
* `klein-large`
|
||||
* `kontext 💎`
|
||||
* `nanobanana 💎`
|
||||
* `nanobanana-pro 💎`
|
||||
* `seedream 💎`
|
||||
* `seedream-pro 💎`
|
||||
* `gptimage`
|
||||
* `gptimage-large 💎`
|
||||
* `flux`
|
||||
* `zimage`
|
||||
* `klein`
|
||||
* `klein-large`
|
||||
* `imagen-4`
|
||||
* `grok-imagine`
|
||||
* **Parameters:** `prompt`, `model`, `width`, `height`, `seed`, `api_key`, `negative_prompt`
|
||||
|
||||
### 2. 🌸 Pollinations Video Gen (BYOP)
|
||||
Generates high-quality AI video.
|
||||
* **Supported Models:**
|
||||
* `veo 💎`
|
||||
* `seedance`
|
||||
* `seedance-pro 💎`
|
||||
* `wan 💎`
|
||||
* `grok-video`
|
||||
* `ltx-2 💎`
|
||||
* `seedance`
|
||||
* `seedance-pro 💎`
|
||||
* `veo 💎`
|
||||
* `wan 💎`
|
||||
* **Parameters:** `prompt`, `model`, `seed`, `api_key`
|
||||
|
||||
### 3. 🌸 Pollinations Text Gen (BYOP)
|
||||
Leverage top-tier LLMs for prompt expansion, dynamic tagging, or scriptwriting inside your workflow.
|
||||
* **Supported Models:**
|
||||
* `openai`
|
||||
* `openai-fast`
|
||||
* `openai-large`
|
||||
* `qwen-coder`
|
||||
* `mistral`
|
||||
* `openai-audio`
|
||||
* `claude 💎`
|
||||
* `claude-fast`
|
||||
* `claude-large 💎`
|
||||
* `deepseek`
|
||||
* `gemini 💎`
|
||||
* `gemini-fast`
|
||||
* `deepseek`
|
||||
* `grok 💎`
|
||||
* `gemini-large 💎`
|
||||
* `gemini-search`
|
||||
* `glm`
|
||||
* `grok 💎`
|
||||
* `kimi`
|
||||
* `midijourney`
|
||||
* `claude-fast`
|
||||
* `claude 💎`
|
||||
* `claude-large 💎`
|
||||
* `minimax`
|
||||
* `mistral`
|
||||
* `nomnom`
|
||||
* `nova-fast`
|
||||
* `openai`
|
||||
* `openai-audio`
|
||||
* `openai-fast`
|
||||
* `openai-large`
|
||||
* `perplexity-fast`
|
||||
* `perplexity-reasoning`
|
||||
* `kimi`
|
||||
* `gemini-large 💎`
|
||||
* `nova-fast`
|
||||
* `glm`
|
||||
* `minimax`
|
||||
* `nomnom`
|
||||
* `polly`
|
||||
* `qwen-safety`
|
||||
* `qwen-character`
|
||||
* `qwen-coder`
|
||||
* `qwen-safety`
|
||||
* **Parameters:** `prompt`, `system_instruction`, `model`, `temperature`, `seed`, `api_key`
|
||||
|
||||
---
|
||||
|
||||
+4
-2
@@ -3,13 +3,15 @@ from .pollinations_nodes import PollinationsImageGen, PollinationsTextGen, Polli
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"PollinationsImageGen": PollinationsImageGen,
|
||||
"PollinationsTextGen": PollinationsTextGen,
|
||||
"PollinationsVideoGen": PollinationsVideoGen
|
||||
"PollinationsVideoGen": PollinationsVideoGen,
|
||||
"PollinationsAudioGen": PollinationsAudioGen
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"PollinationsImageGen": "🌸🖼️ Pollinations Image Gen (BYOP)",
|
||||
"PollinationsTextGen": "🌸🤖 Pollinations Text Gen (BYOP)",
|
||||
"PollinationsVideoGen": "🌸🎞️ Pollinations Video Gen URL (BYOP)"
|
||||
"PollinationsVideoGen": "🌸🎞️ Pollinations Video Gen URL (BYOP)",
|
||||
"PollinationsAudioGen": "🌸🔊 Pollinations Audio Gen (BYOP)"
|
||||
}
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
+37
-31
@@ -1,53 +1,59 @@
|
||||
{
|
||||
"image": [
|
||||
"flux",
|
||||
"gptimage",
|
||||
"gptimage-large \ud83d\udc8e",
|
||||
"grok-imagine",
|
||||
"imagen-4",
|
||||
"klein",
|
||||
"klein-large",
|
||||
"kontext \ud83d\udc8e",
|
||||
"nanobanana \ud83d\udc8e",
|
||||
"nanobanana-pro \ud83d\udc8e",
|
||||
"seedream \ud83d\udc8e",
|
||||
"seedream-pro \ud83d\udc8e",
|
||||
"gptimage",
|
||||
"gptimage-large \ud83d\udc8e",
|
||||
"flux",
|
||||
"zimage",
|
||||
"klein",
|
||||
"klein-large",
|
||||
"imagen-4",
|
||||
"grok-imagine"
|
||||
"zimage"
|
||||
],
|
||||
"video": [
|
||||
"veo \ud83d\udc8e",
|
||||
"grok-video",
|
||||
"ltx-2 \ud83d\udc8e",
|
||||
"seedance",
|
||||
"seedance-pro \ud83d\udc8e",
|
||||
"wan \ud83d\udc8e",
|
||||
"grok-video",
|
||||
"ltx-2 \ud83d\udc8e"
|
||||
"veo \ud83d\udc8e",
|
||||
"wan \ud83d\udc8e"
|
||||
],
|
||||
"text": [
|
||||
"openai",
|
||||
"openai-fast",
|
||||
"openai-large",
|
||||
"qwen-coder",
|
||||
"mistral",
|
||||
"openai-audio",
|
||||
"claude \ud83d\udc8e",
|
||||
"claude-fast",
|
||||
"claude-large \ud83d\udc8e",
|
||||
"deepseek",
|
||||
"gemini \ud83d\udc8e",
|
||||
"gemini-fast",
|
||||
"deepseek",
|
||||
"grok \ud83d\udc8e",
|
||||
"gemini-large \ud83d\udc8e",
|
||||
"gemini-search",
|
||||
"glm",
|
||||
"grok \ud83d\udc8e",
|
||||
"kimi",
|
||||
"midijourney",
|
||||
"claude-fast",
|
||||
"claude \ud83d\udc8e",
|
||||
"claude-large \ud83d\udc8e",
|
||||
"minimax",
|
||||
"mistral",
|
||||
"nomnom",
|
||||
"nova-fast",
|
||||
"openai",
|
||||
"openai-audio",
|
||||
"openai-fast",
|
||||
"openai-large",
|
||||
"perplexity-fast",
|
||||
"perplexity-reasoning",
|
||||
"kimi",
|
||||
"gemini-large \ud83d\udc8e",
|
||||
"nova-fast",
|
||||
"glm",
|
||||
"minimax",
|
||||
"nomnom",
|
||||
"polly",
|
||||
"qwen-safety",
|
||||
"qwen-character"
|
||||
"qwen-character",
|
||||
"qwen-coder",
|
||||
"qwen-safety"
|
||||
],
|
||||
"audio": [
|
||||
"elevenlabs",
|
||||
"elevenmusic",
|
||||
"scribe",
|
||||
"whisper"
|
||||
]
|
||||
}
|
||||
@@ -11,57 +11,53 @@ JSON_FILE = os.path.join(REPO_DIR, "models.json")
|
||||
README_FILE = os.path.join(REPO_DIR, "README.md")
|
||||
|
||||
def fetch_api_models():
|
||||
print("🛰️ Scouting Pollinations API for new models (Premium Aware)...")
|
||||
print("🛰️ Scouting Pollinations Official API (Quad-Modal Pass)...")
|
||||
try:
|
||||
# 1. Fetch Text Models
|
||||
# 1. Text Models
|
||||
text_resp = requests.get("https://gen.pollinations.ai/text/models", timeout=10).json()
|
||||
# We append 💎 if paid_only is True
|
||||
text_models = [
|
||||
f"{m['name']} 💎" if m.get("paid_only") else m["name"]
|
||||
for m in text_resp if "name" in m
|
||||
]
|
||||
text_models = [f"{m['name']} 💎" if m.get("paid_only") else m["name"] for m in text_resp if "name" in m]
|
||||
|
||||
# 2. Fetch Image & Video Models
|
||||
# 2. Image & Video Models
|
||||
img_vid_resp = requests.get("https://gen.pollinations.ai/image/models", timeout=10).json()
|
||||
|
||||
image_models = []
|
||||
video_models = []
|
||||
|
||||
image_models, video_models = [], []
|
||||
for m in img_vid_resp:
|
||||
model_id = m.get("name")
|
||||
if not model_id: continue
|
||||
|
||||
# Append diamond for paid models
|
||||
display_name = f"{model_id} 💎" if m.get("paid_only") else model_id
|
||||
|
||||
# Detect video models via output_modalities array
|
||||
out_modalities = m.get("output_modalities", [])
|
||||
if "video" in out_modalities:
|
||||
video_models.append(display_name)
|
||||
name = m.get("name")
|
||||
if not name: continue
|
||||
display = f"{name} 💎" if m.get("paid_only") else name
|
||||
if "video" in m.get("output_modalities", []):
|
||||
video_models.append(display)
|
||||
else:
|
||||
image_models.append(display_name)
|
||||
|
||||
# Safety defaults (Clean IDs - 💎 logic handled later in script if missing)
|
||||
return {"image": image_models, "video": video_models, "text": text_models}
|
||||
image_models.append(display)
|
||||
|
||||
# 3. Audio Models (NEW)
|
||||
audio_resp = requests.get("https://gen.pollinations.ai/audio/models", timeout=10).json()
|
||||
audio_models = [f"{m['name']} 💎" if m.get("paid_only") else m["name"] for m in audio_resp if "name" in m]
|
||||
|
||||
# Safety Fallbacks
|
||||
if not text_models: text_models = ["openai"]
|
||||
if not image_models: image_models = ["flux"]
|
||||
if not video_models: video_models = ["wan"]
|
||||
if not audio_models: audio_models = ["elevenlabs"]
|
||||
|
||||
return {
|
||||
"image": sorted(image_models),
|
||||
"video": sorted(video_models),
|
||||
"text": sorted(text_models),
|
||||
"audio": sorted(audio_models)
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"❌ API Fetch Failed: {e}")
|
||||
return None
|
||||
|
||||
def update_json_file(models):
|
||||
print("💾 Updating models.json...")
|
||||
with open(JSON_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(models, f, indent=4)
|
||||
|
||||
def update_readme(models):
|
||||
print("📝 Updating README.md...")
|
||||
if not os.path.exists(README_FILE):
|
||||
return
|
||||
|
||||
if not os.path.exists(README_FILE): return
|
||||
with open(README_FILE, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
def replace_md_list(section_id, new_list, text):
|
||||
escaped_id = re.escape(section_id)
|
||||
# Regex looks for the section header down to the next parameter or section break
|
||||
pattern = rf"(###.*?{escaped_id}.*?\n\* \*\*Supported Models:\*\*.*?\n)(.*?)(\n\* \*\*Parameters|\n---|\n##)"
|
||||
formatted_list = "\n".join([f" * `{m}`" for m in new_list])
|
||||
return re.sub(pattern, f"\\1{formatted_list}\\3", text, flags=re.DOTALL | re.IGNORECASE)
|
||||
@@ -69,42 +65,33 @@ def update_readme(models):
|
||||
content = replace_md_list("Image Gen", models["image"], content)
|
||||
content = replace_md_list("Video Gen", models["video"], content)
|
||||
content = replace_md_list("Text Gen", models["text"], content)
|
||||
content = replace_md_list("Audio Gen", models["audio"], content)
|
||||
|
||||
with open(README_FILE, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
def git_sync_everything():
|
||||
print("🚀 Synchronizing local machine to GitHub and HuggingFace...")
|
||||
print("🚀 Synchronizing local machine to Cloud...")
|
||||
try:
|
||||
subprocess.run(["git", "add", "."], cwd=REPO_DIR)
|
||||
|
||||
status = subprocess.run(["git", "status", "--porcelain"], capture_output=True, text=True, cwd=REPO_DIR)
|
||||
if not status.stdout.strip():
|
||||
print(" ✅ Local state matches previous commit.")
|
||||
return
|
||||
|
||||
date_str = datetime.now().strftime("%Y-%m-%d")
|
||||
subprocess.run(["git", "commit", "-m", f"Auto-Sync: Premium Labels & Models ({date_str})"], cwd=REPO_DIR)
|
||||
|
||||
print(" Merging cloud changes...")
|
||||
subprocess.run(["git", "commit", "-m", f"Auto-Sync: Quad-Modal Update ({date_str})"], cwd=REPO_DIR)
|
||||
subprocess.run(["git", "pull", "origin", "main", "-X", "ours", "--no-edit"], cwd=REPO_DIR)
|
||||
|
||||
print(" Pushing to GitHub (origin)...")
|
||||
subprocess.run(["git", "push", "origin", "main"], cwd=REPO_DIR)
|
||||
|
||||
print(" Pushing to HuggingFace...")
|
||||
subprocess.run(["git", "push", "huggingface", "main", "--force"], cwd=REPO_DIR)
|
||||
|
||||
print("🎉 Full sync complete!")
|
||||
except Exception as e:
|
||||
print(f"❌ Git Sync Failed: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"=== Pollinations Engine Updater: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===")
|
||||
os.chdir(REPO_DIR)
|
||||
|
||||
live_models = fetch_api_models()
|
||||
if live_models:
|
||||
update_json_file(live_models)
|
||||
with open(JSON_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(live_models, f, indent=4)
|
||||
update_readme(live_models)
|
||||
git_sync_everything()
|
||||
+100
-107
@@ -8,172 +8,165 @@ import json
|
||||
import os
|
||||
import logging
|
||||
|
||||
# SILENCE LOGGERS to prevent any console/pipe conflicts
|
||||
# SILENCE LOGGERS
|
||||
logging.getLogger("requests").setLevel(logging.CRITICAL)
|
||||
logging.getLogger("urllib3").setLevel(logging.CRITICAL)
|
||||
|
||||
def load_model_list(category, default_list):
|
||||
def get_models():
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
json_path = os.path.join(current_dir, "models.json")
|
||||
try:
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
json_path = os.path.join(current_dir, "models.json")
|
||||
if os.path.exists(json_path):
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
return data.get(category, default_list)
|
||||
except Exception:
|
||||
pass
|
||||
return default_list
|
||||
return json.load(f)
|
||||
except: pass
|
||||
return {"image": ["flux"], "video": ["wan"], "text": ["openai"], "audio": ["elevenlabs"]}
|
||||
|
||||
def upload_to_pollinations(image_tensor):
|
||||
try:
|
||||
i = 255. * image_tensor.cpu().numpy().squeeze()
|
||||
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
||||
buffered = io.BytesIO()
|
||||
img.save(buffered, format="PNG")
|
||||
resp = requests.post("https://media.pollinations.ai/upload", files={"file": ("image.png", buffered.getvalue(), "image/png")})
|
||||
if resp.status_code == 200: return resp.json().get("url")
|
||||
except: pass
|
||||
return None
|
||||
|
||||
class PollinationsImageGen:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
model_list = load_model_list("image", ["flux", "zimage", "klein-large"])
|
||||
model_data = get_models()
|
||||
return {
|
||||
"required": {
|
||||
"prompt": ("STRING", {"multiline": True, "default": "a cat in space"}),
|
||||
"model": (model_list, {"default": "flux"}),
|
||||
"model": (model_data["image"], {"default": "flux"}),
|
||||
"width": ("INT", {"default": 1024, "min": 256, "max": 4096, "step": 8}),
|
||||
"height": ("INT", {"default": 1024, "min": 256, "max": 4096, "step": 8}),
|
||||
"seed": ("INT", {"default": 42, "min": -1, "max": 2147483647}),
|
||||
},
|
||||
"optional": {
|
||||
"api_key": ("STRING", {"default": "", "multiline": False}),
|
||||
"image_input": ("IMAGE",),
|
||||
"negative_prompt": ("STRING", {"multiline": True, "default": ""})
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("image",)
|
||||
RETURN_TYPES = ("IMAGE", "STRING")
|
||||
RETURN_NAMES = ("image", "url")
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = "Pollinations"
|
||||
CATEGORY = "Pollinations/Image"
|
||||
|
||||
def generate(self, prompt, model, width, height, seed, api_key, negative_prompt=""):
|
||||
# Clean the model name by removing the diamond emoji and extra spaces
|
||||
model = model.replace("💎", "").strip()
|
||||
# 1. Official Path Construction
|
||||
def generate(self, prompt, model, width, height, seed, api_key="", image_input=None, negative_prompt=""):
|
||||
clean_model = model.replace("💎", "").strip()
|
||||
encoded_prompt = urllib.parse.quote(prompt.replace("\n", " ").strip())
|
||||
url = f"https://gen.pollinations.ai/image/{encoded_prompt}?model={clean_model}&width={width}&height={height}&seed={seed}&nologo=true"
|
||||
if image_input is not None:
|
||||
img_url = upload_to_pollinations(image_input)
|
||||
if img_url: url += f"&image={urllib.parse.quote(img_url)}"
|
||||
if negative_prompt.strip(): url += f"&negative_prompt={urllib.parse.quote(negative_prompt.strip())}"
|
||||
|
||||
# Base URL from official api.json
|
||||
base_url = f"https://gen.pollinations.ai/image/{encoded_prompt}"
|
||||
|
||||
# 2. Query Parameters (Official Spec)
|
||||
params = {
|
||||
"model": model,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"seed": seed,
|
||||
"nologo": "true"
|
||||
}
|
||||
|
||||
if negative_prompt and negative_prompt.strip() != "":
|
||||
params["negative_prompt"] = negative_prompt.strip()
|
||||
|
||||
# 3. Headers (Crucial for WAF bypass and BYOP)
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
}
|
||||
|
||||
if api_key and api_key.strip() != "":
|
||||
headers["Authorization"] = f"Bearer {api_key.strip()}"
|
||||
|
||||
headers = {"User-Agent": "Mozilla/5.0"}
|
||||
if api_key.strip(): headers["Authorization"] = f"Bearer {api_key.strip()}"
|
||||
try:
|
||||
response = requests.get(base_url, params=params, headers=headers, timeout=120)
|
||||
|
||||
if response.status_code == 200:
|
||||
image = Image.open(io.BytesIO(response.content)).convert("RGB")
|
||||
image_np = np.array(image).astype(np.float32) / 255.0
|
||||
return (torch.from_numpy(image_np)[None,],)
|
||||
else:
|
||||
# Return Black square with Red pixel in corner on error
|
||||
err_img = np.zeros((width, height, 3), dtype=np.float32)
|
||||
err_img[0,0] = [1.0, 0, 0]
|
||||
return (torch.from_numpy(err_img)[None,],)
|
||||
|
||||
except Exception:
|
||||
return (torch.zeros((1, 512, 512, 3)),)
|
||||
r = requests.get(url, headers=headers, timeout=120)
|
||||
if r.status_code == 200:
|
||||
img = Image.open(io.BytesIO(r.content)).convert("RGB")
|
||||
img_np = np.array(img).astype(np.float32) / 255.0
|
||||
return (torch.from_numpy(img_np)[None,], url)
|
||||
except: pass
|
||||
return (torch.zeros((1, 512, 512, 3)), url)
|
||||
|
||||
class PollinationsTextGen:
|
||||
class PollinationsAudioGen:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
model_list = load_model_list("text", ["openai", "deepseek", "gemini"])
|
||||
model_data = get_models()
|
||||
return {
|
||||
"required": {
|
||||
"prompt": ("STRING", {"multiline": True, "default": "Hello!"}),
|
||||
"model": (model_list, {"default": "openai"}),
|
||||
"system_instruction": ("STRING", {"multiline": True, "default": "You are a helpful assistant."}),
|
||||
"seed": ("INT", {"default": 42, "min": -1, "max": 9007199254740991}),
|
||||
"text": ("STRING", {"multiline": True, "default": "Hello world"}),
|
||||
"model": (model_data["audio"], {"default": "elevenlabs"}),
|
||||
"voice": (["alloy", "echo", "fable", "onyx", "nova", "shimmer", "sarah", "rachel", "charlie"], {"default": "sarah"}),
|
||||
},
|
||||
"optional": {
|
||||
"api_key": ("STRING", {"default": "", "multiline": False})
|
||||
}
|
||||
"optional": {"api_key": ("STRING", {"default": ""})}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("text",)
|
||||
RETURN_NAMES = ("audio_url",)
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = "Pollinations"
|
||||
CATEGORY = "Pollinations/Audio"
|
||||
|
||||
def generate(self, prompt, model, system_instruction, seed, api_key):
|
||||
# Clean the model name by removing the diamond emoji and extra spaces
|
||||
model = model.replace("💎", "").strip()
|
||||
url = "https://gen.pollinations.ai/v1/chat/completions"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
if api_key and api_key.strip() != "":
|
||||
headers["Authorization"] = f"Bearer {api_key.strip()}"
|
||||
|
||||
payload = {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{"role": "system", "content": system_instruction},
|
||||
{"role": "user", "content": prompt}
|
||||
],
|
||||
"seed": seed
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=payload, timeout=60)
|
||||
if response.status_code == 200:
|
||||
return (response.json()["choices"][0]["message"]["content"],)
|
||||
return (f"Error: {response.status_code}",)
|
||||
except Exception as e:
|
||||
return (str(e),)
|
||||
def generate(self, text, model, voice, api_key=""):
|
||||
clean_model = model.replace("💎", "").strip()
|
||||
encoded_text = urllib.parse.quote(text.strip())
|
||||
url = f"https://gen.pollinations.ai/audio/{encoded_text}?model={clean_model}&voice={voice}"
|
||||
if api_key.strip(): url += f"&key={api_key.strip()}"
|
||||
return (url,)
|
||||
|
||||
class PollinationsVideoGen:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
model_list = load_model_list("video", ["wan", "seedance", "veo"])
|
||||
model_data = get_models()
|
||||
return {
|
||||
"required": {
|
||||
"prompt": ("STRING", {"multiline": True, "default": "a sunset timelapse"}),
|
||||
"model": (model_list, {"default": "wan"}),
|
||||
"prompt": ("STRING", {"multiline": True, "default": "cinematic sunset"}),
|
||||
"model": (model_data["video"], {"default": "wan"}),
|
||||
},
|
||||
"optional": {
|
||||
"api_key": ("STRING", {"default": "", "multiline": False})
|
||||
"api_key": ("STRING", {"default": ""}),
|
||||
"image_input": ("IMAGE",),
|
||||
"duration": ("INT", {"default": 5, "min": 2, "max": 15}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("video_url",)
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = "Pollinations"
|
||||
CATEGORY = "Pollinations/Video"
|
||||
|
||||
def generate(self, prompt, model, api_key):
|
||||
# Clean the model name by removing the diamond emoji and extra spaces
|
||||
model = model.replace("💎", "").strip()
|
||||
def generate(self, prompt, model, api_key="", image_input=None, duration=5):
|
||||
clean_model = model.replace("💎", "").strip()
|
||||
encoded_prompt = urllib.parse.quote(prompt.strip())
|
||||
url = f"https://gen.pollinations.ai/video/{encoded_prompt}?model={model}"
|
||||
if api_key and api_key.strip() != "":
|
||||
url += f"&key={api_key.strip()}"
|
||||
url = f"https://gen.pollinations.ai/video/{encoded_prompt}?model={clean_model}&duration={duration}"
|
||||
if image_input is not None:
|
||||
img_url = upload_to_pollinations(image_input)
|
||||
if img_url: url += f"&image={urllib.parse.quote(img_url)}"
|
||||
if api_key.strip(): url += f"&key={api_key.strip()}"
|
||||
return (url,)
|
||||
|
||||
class PollinationsTextGen:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
model_data = get_models()
|
||||
return {
|
||||
"required": {
|
||||
"prompt": ("STRING", {"multiline": True, "default": "Hi!"}),
|
||||
"model": (model_data["text"], {"default": "openai"}),
|
||||
"system_instruction": ("STRING", {"multiline": True, "default": "You are helpful assistant."}),
|
||||
},
|
||||
"optional": {"api_key": ("STRING", {"default": ""})}
|
||||
}
|
||||
RETURN_TYPES = ("STRING",)
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = "Pollinations/Text"
|
||||
|
||||
def generate(self, prompt, model, system_instruction, api_key=""):
|
||||
clean_model = model.replace("💎", "").strip()
|
||||
url = "https://gen.pollinations.ai/v1/chat/completions"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
if api_key.strip(): headers["Authorization"] = f"Bearer {api_key.strip()}"
|
||||
payload = {"model": clean_model, "messages": [{"role": "system", "content": system_instruction}, {"role": "user", "content": prompt}]}
|
||||
try:
|
||||
r = requests.post(url, json=payload, headers=headers)
|
||||
return (r.json()["choices"][0]["message"]["content"],)
|
||||
except: return ("Error connecting to Text API",)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"PollinationsImageGen": PollinationsImageGen,
|
||||
"PollinationsTextGen": PollinationsTextGen,
|
||||
"PollinationsVideoGen": PollinationsVideoGen
|
||||
"PollinationsVideoGen": PollinationsVideoGen,
|
||||
"PollinationsAudioGen": PollinationsAudioGen
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"PollinationsImageGen": "🌸🖼️ Pollinations Image Gen (BYOP)",
|
||||
"PollinationsTextGen": "🌸🤖 Pollinations Text Gen (BYOP)",
|
||||
"PollinationsVideoGen": "🌸🎞️ Pollinations Video Gen URL (BYOP)"
|
||||
"PollinationsVideoGen": "🌸🎞️ Pollinations Video Gen URL (BYOP)",
|
||||
"PollinationsAudioGen": "🌸🔊 Pollinations Audio Gen (BYOP)"
|
||||
}
|
||||
Reference in New Issue
Block a user