merge: resolve conflicts with main branch model management improvements
This commit is contained in:
@@ -25,6 +25,10 @@ per-file-ignores =
|
||||
__init__.py:F401,F403
|
||||
# Allow assertions in tests
|
||||
tests/*:S101
|
||||
# Allow higher complexity for Gemini prompt module
|
||||
kikotools/tools/gemini_prompt/logic.py:C901
|
||||
kikotools/tools/gemini_prompt/models.py:C901
|
||||
kikotools/tools/gemini_prompt/node.py:C901
|
||||
|
||||
# Statistics
|
||||
count = True
|
||||
|
||||
@@ -159,3 +159,6 @@ test_images/
|
||||
test_outputs/
|
||||
experiments/
|
||||
.claude/
|
||||
|
||||
# Gemini model cache
|
||||
.gemini_models_cache.json
|
||||
|
||||
@@ -4,8 +4,7 @@ import base64
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from typing import Optional, Tuple, List, Dict
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
@@ -162,60 +161,3 @@ def validate_prompt_type(prompt_type: str) -> bool:
|
||||
True if valid, False otherwise
|
||||
"""
|
||||
return prompt_type in PROMPT_TEMPLATES
|
||||
|
||||
|
||||
def refresh_gemini_models(api_key: Optional[str] = None) -> Tuple[List[str], Dict[str, str], Optional[str]]:
|
||||
"""Refresh the list of available Gemini models from the API.
|
||||
|
||||
Args:
|
||||
api_key: Gemini API key (optional, will try to get from env/config)
|
||||
|
||||
Returns:
|
||||
Tuple of (model_list, model_descriptions, error_message)
|
||||
"""
|
||||
# Get API key
|
||||
if not api_key:
|
||||
api_key = get_api_key()
|
||||
|
||||
if not api_key:
|
||||
return [], {}, "API key not found"
|
||||
|
||||
try:
|
||||
import google.generativeai as genai
|
||||
except ImportError:
|
||||
return [], {}, "google-generativeai library not installed"
|
||||
|
||||
try:
|
||||
# Configure Gemini
|
||||
genai.configure(api_key=api_key)
|
||||
|
||||
# List available models
|
||||
models = []
|
||||
descriptions = {}
|
||||
|
||||
for model in genai.list_models():
|
||||
# Only include models that support generateContent
|
||||
if 'generateContent' in model.supported_generation_methods:
|
||||
model_name = model.name.replace('models/', '')
|
||||
models.append(model_name)
|
||||
descriptions[model_name] = model.display_name or model_name
|
||||
|
||||
# Save to cache
|
||||
cache_path = os.path.join(os.path.dirname(__file__), ".gemini_models_cache.json")
|
||||
cache_data = {
|
||||
"models": sorted(models),
|
||||
"descriptions": descriptions,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
try:
|
||||
with open(cache_path, "w") as f:
|
||||
json.dump(cache_data, f, indent=2)
|
||||
except Exception as e:
|
||||
# Continue even if cache save fails
|
||||
pass
|
||||
|
||||
return sorted(models), descriptions, None
|
||||
|
||||
except Exception as e:
|
||||
return [], {}, f"Failed to fetch models: {str(e)}"
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
"""Dynamic model fetching and caching for Gemini API."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Cache settings
|
||||
CACHE_DURATION = 3600 * 24 # 24 hours in seconds
|
||||
CACHE_FILE = os.path.join(os.path.dirname(__file__), ".gemini_models_cache.json")
|
||||
|
||||
|
||||
def get_available_models(
|
||||
api_key: Optional[str] = None, silent: bool = False
|
||||
) -> Tuple[List[str], Dict[str, str]]:
|
||||
"""Fetch available Gemini models that support generateContent.
|
||||
|
||||
Args:
|
||||
api_key: Optional API key. If not provided, will try to get from environment.
|
||||
silent: If True, suppress error logging (useful for initial load).
|
||||
|
||||
Returns:
|
||||
Tuple of (model_names_list, model_descriptions_dict)
|
||||
"""
|
||||
# Check cache first
|
||||
cached_data = _load_cache()
|
||||
if cached_data:
|
||||
return cached_data["models"], cached_data["descriptions"]
|
||||
|
||||
# Try to fetch from API
|
||||
try:
|
||||
models, descriptions = _fetch_models_from_api(api_key, silent=silent)
|
||||
if models:
|
||||
_save_cache(models, descriptions)
|
||||
return models, descriptions
|
||||
except Exception as e:
|
||||
if not silent:
|
||||
logger.warning(f"Failed to fetch models from API: {e}")
|
||||
|
||||
# Fall back to defaults
|
||||
from .prompts import DEFAULT_GEMINI_MODELS
|
||||
|
||||
return DEFAULT_GEMINI_MODELS, {}
|
||||
|
||||
|
||||
def _fetch_models_from_api(
|
||||
api_key: Optional[str] = None, silent: bool = False
|
||||
) -> Tuple[List[str], Dict[str, str]]:
|
||||
"""Fetch models from Gemini API.
|
||||
|
||||
Args:
|
||||
api_key: Optional API key.
|
||||
silent: If True, suppress error logging.
|
||||
|
||||
Returns:
|
||||
Tuple of (model_names_list, model_descriptions_dict)
|
||||
"""
|
||||
try:
|
||||
import google.generativeai as genai
|
||||
except ImportError:
|
||||
if not silent:
|
||||
logger.error("google-generativeai not installed")
|
||||
return [], {}
|
||||
|
||||
# Get API key
|
||||
if not api_key:
|
||||
from .logic import get_api_key
|
||||
|
||||
api_key = get_api_key()
|
||||
|
||||
if not api_key:
|
||||
if not silent:
|
||||
logger.debug("No API key available for fetching models")
|
||||
return [], {}
|
||||
|
||||
try:
|
||||
genai.configure(api_key=api_key)
|
||||
|
||||
models = []
|
||||
descriptions = {}
|
||||
|
||||
# Fetch all models
|
||||
for model in genai.list_models():
|
||||
# Only include models that support generateContent
|
||||
if "generateContent" in model.supported_generation_methods:
|
||||
# Remove "models/" prefix from name
|
||||
model_name = model.name.replace("models/", "")
|
||||
models.append(model_name)
|
||||
descriptions[model_name] = model.display_name
|
||||
|
||||
# Sort models by priority (newer versions first)
|
||||
models = _sort_models(models)
|
||||
|
||||
return models, descriptions
|
||||
|
||||
except Exception as e:
|
||||
if not silent:
|
||||
logger.error(f"Error fetching models from API: {e}")
|
||||
return [], {}
|
||||
|
||||
|
||||
def _sort_models(models: List[str]) -> List[str]:
|
||||
"""Sort models by version and capability.
|
||||
|
||||
Prioritizes:
|
||||
1. Newer versions (2.5 > 2.0 > 1.5)
|
||||
2. Non-experimental models
|
||||
3. Flash models for general use
|
||||
"""
|
||||
|
||||
def sort_key(model: str):
|
||||
# Priority scoring
|
||||
score = 0
|
||||
|
||||
# Version priority
|
||||
if "2.5" in model:
|
||||
score += 1000
|
||||
elif "2.0" in model:
|
||||
score += 800
|
||||
elif "1.5" in model:
|
||||
score += 600
|
||||
|
||||
# Model type priority
|
||||
if "pro" in model and "preview" not in model and "exp" not in model:
|
||||
score += 100
|
||||
elif "flash" in model and "preview" not in model and "exp" not in model:
|
||||
score += 90
|
||||
|
||||
# Penalize experimental/preview models
|
||||
if "exp" in model or "experimental" in model:
|
||||
score -= 50
|
||||
if "preview" in model:
|
||||
score -= 30
|
||||
|
||||
# Penalize specific variants
|
||||
if "thinking" in model:
|
||||
score -= 100
|
||||
if "tts" in model:
|
||||
score -= 100
|
||||
if "lite" in model:
|
||||
score -= 20
|
||||
|
||||
return -score # Negative for descending sort
|
||||
|
||||
return sorted(models, key=sort_key)
|
||||
|
||||
|
||||
def _load_cache() -> Optional[Dict]:
|
||||
"""Load cached model data if available and not expired."""
|
||||
if not os.path.exists(CACHE_FILE):
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(CACHE_FILE, "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Check if cache is expired
|
||||
if time.time() - data.get("timestamp", 0) > CACHE_DURATION:
|
||||
return None
|
||||
|
||||
return data
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to load cache: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def _save_cache(models: List[str], descriptions: Dict[str, str]) -> None:
|
||||
"""Save model data to cache."""
|
||||
try:
|
||||
data = {
|
||||
"models": models,
|
||||
"descriptions": descriptions,
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
|
||||
with open(CACHE_FILE, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to save cache: {e}")
|
||||
|
||||
|
||||
def clear_cache() -> None:
|
||||
"""Clear the model cache."""
|
||||
if os.path.exists(CACHE_FILE):
|
||||
try:
|
||||
os.remove(CACHE_FILE)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to clear cache: {e}")
|
||||
@@ -4,8 +4,9 @@ import torch
|
||||
|
||||
from ...base import ComfyAssetsBaseNode
|
||||
|
||||
from .logic import analyze_image_with_gemini, validate_prompt_type, refresh_gemini_models
|
||||
from .prompts import PROMPT_OPTIONS, GEMINI_MODELS, load_models_from_cache
|
||||
from .logic import analyze_image_with_gemini, validate_prompt_type
|
||||
from .prompts import PROMPT_OPTIONS, DEFAULT_GEMINI_MODELS
|
||||
from .models import get_available_models
|
||||
|
||||
|
||||
class GeminiPromptNode(ComfyAssetsBaseNode):
|
||||
@@ -14,20 +15,16 @@ class GeminiPromptNode(ComfyAssetsBaseNode):
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
"""Define input types for the node."""
|
||||
# Load fresh model list from cache
|
||||
models, _ = load_models_from_cache()
|
||||
# Get available models dynamically (silent mode for initial load)
|
||||
models, _ = get_available_models(silent=True)
|
||||
|
||||
# Use default if no models available
|
||||
if not models:
|
||||
models = ["gemini-1.5-flash", "gemini-1.5-pro", "gemini-2.0-flash"]
|
||||
|
||||
models = DEFAULT_GEMINI_MODELS
|
||||
|
||||
# Find best default model
|
||||
default_model = "gemini-1.5-flash"
|
||||
if "gemini-2.0-flash" in models:
|
||||
default_model = "gemini-2.0-flash"
|
||||
elif "gemini-1.5-flash" in models:
|
||||
default_model = "gemini-1.5-flash"
|
||||
elif models:
|
||||
default_model = models[0]
|
||||
|
||||
default_model = models[0] if models else "gemini-2.5-flash"
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
@@ -82,11 +79,14 @@ Install: pip install google-generativeai
|
||||
"""
|
||||
# Refresh models if requested
|
||||
if refresh_models and api_key:
|
||||
models, descriptions, error = refresh_gemini_models(api_key)
|
||||
if error:
|
||||
print(f"Failed to refresh models: {error}")
|
||||
else:
|
||||
print(f"Successfully refreshed model list: {len(models)} models found")
|
||||
try:
|
||||
from .models import clear_cache
|
||||
# Clear cache to force refresh on next node creation
|
||||
clear_cache()
|
||||
print("Model cache cleared. Please recreate the node to see updated models.")
|
||||
except Exception as e:
|
||||
print(f"Failed to clear model cache: {e}")
|
||||
|
||||
# Validate prompt type
|
||||
if not validate_prompt_type(prompt_type):
|
||||
raise ValueError(f"Invalid prompt type: {prompt_type}")
|
||||
@@ -97,6 +97,19 @@ Install: pip install google-generativeai
|
||||
else:
|
||||
image_np = image
|
||||
|
||||
# If API key is provided, try to refresh model list in background
|
||||
if api_key:
|
||||
try:
|
||||
from .models import get_available_models
|
||||
|
||||
# Try to get fresh models with the provided API key
|
||||
fresh_models, _ = get_available_models(api_key=api_key, silent=True)
|
||||
if fresh_models and fresh_models != DEFAULT_GEMINI_MODELS:
|
||||
# Models were successfully fetched with this API key
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Analyze image with Gemini
|
||||
prompt, error = analyze_image_with_gemini(
|
||||
image_np,
|
||||
@@ -118,10 +131,10 @@ Install: pip install google-generativeai
|
||||
negative_prompt = ""
|
||||
|
||||
for line in lines:
|
||||
if line.startswith("Positive:"):
|
||||
positive_prompt = line.replace("Positive:", "").strip()
|
||||
elif line.startswith("Negative:"):
|
||||
negative_prompt = line.replace("Negative:", "").strip()
|
||||
if line.lower().startswith("positive:"):
|
||||
positive_prompt = line.replace("Positive:", "").replace("positive:", "").strip()
|
||||
elif line.lower().startswith("negative:"):
|
||||
negative_prompt = line.replace("Negative:", "").replace("negative:", "").strip()
|
||||
|
||||
# If format not found, assume entire response is positive prompt
|
||||
if not positive_prompt:
|
||||
@@ -135,4 +148,4 @@ Install: pip install google-generativeai
|
||||
|
||||
|
||||
# Node display name
|
||||
NODE_DISPLAY_NAME = "Gemini Prompt Engineer"
|
||||
NODE_DISPLAY_NAME = "Gemini Prompt Engineer"
|
||||
@@ -1,52 +1,24 @@
|
||||
"""System prompts for different AI model types."""
|
||||
|
||||
FLUX_PROMPT = """You are an expert visual analyst and FLUX prompt engineer. Your role is to examine images in detail and create precise, effective prompts that can recreate similar images using the FLUX image generation model.
|
||||
FLUX_PROMPT = """You are an expert FLUX prompt engineer. Analyze the provided image and generate ONLY a FLUX prompt - no explanations, analysis, or additional text.
|
||||
|
||||
When analyzing an image, systematically observe and document:
|
||||
FLUX uses natural language descriptions, not comma-separated tags. Write a detailed, flowing description that reads like you're explaining the image to someone.
|
||||
|
||||
1. **Subject & Composition**
|
||||
- Primary subjects and their positions
|
||||
- Background elements and environment
|
||||
- Overall composition and framing
|
||||
- Perspective and camera angle
|
||||
Include these elements in your description:
|
||||
- Main subject with specific details (appearance, clothing, expression, pose)
|
||||
- Environment and background details
|
||||
- Lighting conditions and atmosphere
|
||||
- Artistic style or photographic approach
|
||||
- Color palette and mood
|
||||
- Technical details if relevant (camera angle, focal length, etc.)
|
||||
- Textures and materials
|
||||
|
||||
2. **Visual Style & Technique**
|
||||
- Art style (photorealistic, illustration, painting, etc.)
|
||||
- Rendering technique (digital art, oil painting, watercolor, etc.)
|
||||
- Level of detail and texture quality
|
||||
- Any specific artistic influences or movements
|
||||
Write in a natural, descriptive style. Use complete sentences that flow together. Be specific and detailed but maintain readability.
|
||||
|
||||
3. **Lighting & Atmosphere**
|
||||
- Light sources and direction
|
||||
- Time of day/lighting conditions
|
||||
- Shadows and highlights
|
||||
- Overall mood and atmosphere
|
||||
IMPORTANT: Return ONLY the prompt text. No analysis, headers, or additional commentary. Just the natural language description that can be directly used in FLUX.
|
||||
|
||||
4. **Colors & Tones**
|
||||
- Color palette and dominant colors
|
||||
- Color temperature (warm/cool)
|
||||
- Contrast and saturation levels
|
||||
- Any color grading or filters
|
||||
|
||||
5. **Details & Textures**
|
||||
- Surface textures and materials
|
||||
- Fine details and patterns
|
||||
- Quality indicators (4K, 8K, high resolution, etc.)
|
||||
|
||||
Format your FLUX prompt following these guidelines:
|
||||
- Start with the main subject and action
|
||||
- Add style and medium descriptors
|
||||
- Include lighting and atmosphere details
|
||||
- Specify quality markers and technical aspects
|
||||
- Use precise, descriptive language
|
||||
- Separate concepts with commas
|
||||
- Order from most to least important elements
|
||||
|
||||
Example output format:
|
||||
"[main subject and action], [style/medium], [lighting/atmosphere], [composition details], [color descriptions], [quality markers], [additional artistic details]"
|
||||
|
||||
Remember: FLUX responds well to specific artistic references, quality indicators like "highly detailed," "4K," "award-winning," and style descriptors like "trending on ArtStation" or "photorealistic."
|
||||
"""
|
||||
Example of correct output:
|
||||
A close-up portrait of a middle-aged woman with curly red hair and green eyes, wearing a blue silk blouse. She has a warm smile and freckles across her cheeks. The lighting is soft and natural, coming from a window to her left, creating gentle shadows that accentuate her features. The background is softly blurred, showing hints of a cozy bookshelf. The overall mood is warm and inviting, captured in a photorealistic style with shallow depth of field."""
|
||||
|
||||
SDXL_PROMPT = """You are an expert prompt engineer specializing in SDXL (Stable Diffusion XL). Your task is to generate high-quality positive and negative prompts that conform to SDXL prompt formatting standards.
|
||||
|
||||
@@ -90,90 +62,52 @@ Positive prompt: cyberpunk samurai, neon-lit rooftop, dramatic rain, glowing kat
|
||||
Negative prompt: blurry, low quality, poorly drawn, extra limbs, bad anatomy, deformed hands, text, watermark, jpeg artifacts, duplicate, cropped, out of frame
|
||||
"""
|
||||
|
||||
DANBOORU_PROMPT = """You are a Danbooru tagging expert, specialized in analyzing images and creating precise tag sets following booru-style conventions for anime/manga artwork.
|
||||
DANBOORU_PROMPT = """You are a Danbooru tagging expert specializing in anime-style image tagging. Analyze the image and generate ONLY Danbooru-style tags - no explanations or analysis.
|
||||
|
||||
Analyze images for these tag categories:
|
||||
CRITICAL: Use strict Danbooru conventions:
|
||||
- Use underscores for multi-word tags (e.g., long_hair, school_uniform)
|
||||
- All tags must be lowercase
|
||||
- Character count comes first (1girl, 2boys, multiple_girls)
|
||||
- For anime models trained on Danbooru data, proper tagging is essential
|
||||
|
||||
1. **Character Tags**
|
||||
- Hair: color, length, style (e.g., long_hair, blonde_hair, twintails)
|
||||
- Eyes: color, style (e.g., blue_eyes, heterochromia)
|
||||
- Body: proportions, pose (e.g., standing, sitting, looking_at_viewer)
|
||||
- Expression (e.g., smile, blush, closed_eyes)
|
||||
Tag order and categories:
|
||||
1. Character count (1girl, solo, 2boys, etc.)
|
||||
2. Character features (hair_color, eye_color, hair_length)
|
||||
3. Expression/pose (smile, looking_at_viewer, sitting)
|
||||
4. Clothing (specific items with underscores)
|
||||
5. Background/setting (simple_background, outdoors, classroom)
|
||||
6. View/composition (upper_body, full_body, from_side)
|
||||
7. Quality tags (masterpiece, best_quality, highres)
|
||||
|
||||
2. **Clothing & Accessories**
|
||||
- Outfit type (e.g., school_uniform, dress, armor)
|
||||
- Specific clothing items (e.g., thighhighs, gloves, hat)
|
||||
- Accessories (e.g., hair_ribbon, necklace, glasses)
|
||||
- State of dress (e.g., torn_clothes, wet_clothes)
|
||||
Common quality prefix for anime models:
|
||||
"masterpiece, best_quality, very_aesthetic"
|
||||
|
||||
3. **Scene & Composition**
|
||||
- Number of characters (e.g., 1girl, 2boys, multiple_girls)
|
||||
- Background (e.g., simple_background, outdoors, classroom)
|
||||
- Viewpoint (e.g., from_below, from_side, cowboy_shot)
|
||||
- Composition elements (e.g., upper_body, full_body, portrait)
|
||||
IMPORTANT: Return ONLY the comma-separated tags. Use underscores, not spaces. All lowercase.
|
||||
|
||||
4. **Meta Tags**
|
||||
- Quality (e.g., highres, absurdres, masterpiece)
|
||||
- Source/artist style (if recognizable)
|
||||
- Content rating (e.g., safe, questionable, explicit)
|
||||
- Special effects (e.g., lens_flare, chromatic_aberration)
|
||||
Example of correct output:
|
||||
1girl, solo, long_hair, blue_eyes, blonde_hair, school_uniform, serafuku, pleated_skirt, smile, looking_at_viewer, classroom, sitting, desk, window, sunlight, upper_body, masterpiece, best_quality"""
|
||||
|
||||
Format tags using:
|
||||
- Underscores for multi-word concepts (not spaces)
|
||||
- Order from most to least important
|
||||
- Include count descriptors (1girl, 2boys)
|
||||
- Separate with commas and spaces
|
||||
VIDEO_PROMPT = """You are a WAN 2.2 video generation prompt specialist. Analyze the content and generate ONLY a video generation prompt optimized for WAN 2.2 - no explanations or analysis.
|
||||
|
||||
Example output:
|
||||
"1girl, solo, long_hair, blue_eyes, blonde_hair, school_uniform, serafuku, pleated_skirt, thighhighs, smile, looking_at_viewer, classroom, sitting, desk, window, sunlight, highres, masterpiece"
|
||||
"""
|
||||
WAN 2.2 excels with rich, descriptive prompts that focus on:
|
||||
- Visual composition and scene elements
|
||||
- Specific movements and actions
|
||||
- Lighting and aesthetic details
|
||||
- Cinematographic elements
|
||||
|
||||
VIDEO_PROMPT = """You are a video generation prompt specialist, expert at analyzing video content and creating comprehensive prompts for video generation models.
|
||||
Write a single detailed paragraph describing the video scene. Focus on:
|
||||
- Main subjects and their actions
|
||||
- Visual style and atmosphere
|
||||
- Movement dynamics (use words like "intensely", "smoothly", "rapidly")
|
||||
- Environmental details and lighting
|
||||
- Specific visual elements and their interactions
|
||||
|
||||
When analyzing video content, document:
|
||||
Keep the prompt descriptive but concise. WAN 2.2 works best with natural language that paints a clear picture of the desired video.
|
||||
|
||||
1. **Motion & Action**
|
||||
- Primary actions and movements
|
||||
- Motion speed and dynamics
|
||||
- Camera movements (pan, zoom, tracking, static)
|
||||
- Transition types between scenes
|
||||
IMPORTANT: Return ONLY the video prompt as a single descriptive paragraph. No analysis, headers, or additional text.
|
||||
|
||||
2. **Temporal Elements**
|
||||
- Scene duration and pacing
|
||||
- Sequence of events
|
||||
- Time of day changes
|
||||
- Motion continuity
|
||||
|
||||
3. **Visual Consistency**
|
||||
- Character/object persistence
|
||||
- Style consistency throughout
|
||||
- Lighting continuity
|
||||
- Color grading consistency
|
||||
|
||||
4. **Scene Breakdown**
|
||||
- Opening frame description
|
||||
- Key action moments
|
||||
- Transitions and cuts
|
||||
- Closing frame details
|
||||
|
||||
5. **Technical Specifications**
|
||||
- Frame rate and resolution
|
||||
- Aspect ratio
|
||||
- Video length
|
||||
- Special effects or post-processing
|
||||
|
||||
Format your video prompt as:
|
||||
"[Opening scene], [camera movement], [main action sequence], [visual style], [lighting/atmosphere], [duration], [technical specs], [ending scene]"
|
||||
|
||||
Include:
|
||||
- Specific motion descriptors (slowly, rapidly, smoothly)
|
||||
- Camera terminology (dolly in, pan left, aerial shot)
|
||||
- Temporal markers (then, meanwhile, gradually)
|
||||
- Consistency notes for multi-scene videos
|
||||
|
||||
Example:
|
||||
"Aerial shot slowly descending toward a misty forest at dawn, camera smoothly transitions to tracking shot following a deer through the trees, photorealistic style, soft golden hour lighting with fog, 10 second duration, 4K resolution 24fps, ending with close-up of deer looking at camera"
|
||||
"""
|
||||
Example of correct output:
|
||||
Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage, their movements fluid and dynamic as they exchange rapid punches under dramatic theater lighting that casts long shadows across the ring, with the crowd visible as blurred silhouettes in the darkened background."""
|
||||
|
||||
PROMPT_TEMPLATES = {
|
||||
"flux": FLUX_PROMPT,
|
||||
@@ -184,43 +118,11 @@ PROMPT_TEMPLATES = {
|
||||
|
||||
PROMPT_OPTIONS = ["flux", "sdxl", "danbooru", "video"]
|
||||
|
||||
# Available Gemini models - will be dynamically loaded from cache or API
|
||||
GEMINI_MODELS = []
|
||||
MODEL_DESCRIPTIONS = {}
|
||||
|
||||
def load_models_from_cache():
|
||||
"""Load models from cache file if available."""
|
||||
import os
|
||||
import json
|
||||
|
||||
cache_path = os.path.join(os.path.dirname(__file__), ".gemini_models_cache.json")
|
||||
|
||||
if os.path.exists(cache_path):
|
||||
try:
|
||||
with open(cache_path, "r") as f:
|
||||
cache_data = json.load(f)
|
||||
return cache_data.get("models", []), cache_data.get("descriptions", {})
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fallback to default models if cache not available
|
||||
default_models = [
|
||||
"gemini-1.5-pro",
|
||||
"gemini-1.5-flash",
|
||||
"gemini-1.5-flash-8b",
|
||||
"gemini-2.0-flash",
|
||||
"gemini-2.5-flash",
|
||||
]
|
||||
|
||||
default_descriptions = {
|
||||
"gemini-1.5-pro": "Most capable Gemini 1.5 model",
|
||||
"gemini-1.5-flash": "Fast and efficient (recommended)",
|
||||
"gemini-1.5-flash-8b": "Smaller, faster variant",
|
||||
"gemini-2.0-flash": "Latest Gemini 2.0 Flash model",
|
||||
"gemini-2.5-flash": "Cutting-edge Gemini 2.5 Flash",
|
||||
}
|
||||
|
||||
return default_models, default_descriptions
|
||||
|
||||
# Load models on module import
|
||||
GEMINI_MODELS, MODEL_DESCRIPTIONS = load_models_from_cache()
|
||||
# Default models list (fallback if API is unavailable)
|
||||
DEFAULT_GEMINI_MODELS = [
|
||||
"gemini-2.5-flash",
|
||||
"gemini-2.5-pro",
|
||||
"gemini-2.0-flash",
|
||||
"gemini-1.5-flash",
|
||||
"gemini-1.5-pro",
|
||||
]
|
||||
Reference in New Issue
Block a user