ultimate-gemini-mcp 1.0.1__py3-none-any.whl
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.
Potentially problematic release.
This version of ultimate-gemini-mcp might be problematic. Click here for more details.
- src/__init__.py +16 -0
- src/config/__init__.py +32 -0
- src/config/constants.py +77 -0
- src/config/settings.py +143 -0
- src/core/__init__.py +55 -0
- src/core/exceptions.py +60 -0
- src/core/validation.py +161 -0
- src/server.py +166 -0
- src/services/__init__.py +15 -0
- src/services/gemini_client.py +230 -0
- src/services/image_service.py +243 -0
- src/services/imagen_client.py +175 -0
- src/services/prompt_enhancer.py +140 -0
- src/tools/__init__.py +11 -0
- src/tools/batch_generate.py +159 -0
- src/tools/generate_image.py +252 -0
- ultimate_gemini_mcp-1.0.1.dist-info/METADATA +372 -0
- ultimate_gemini_mcp-1.0.1.dist-info/RECORD +21 -0
- ultimate_gemini_mcp-1.0.1.dist-info/WHEEL +4 -0
- ultimate_gemini_mcp-1.0.1.dist-info/entry_points.txt +2 -0
- ultimate_gemini_mcp-1.0.1.dist-info/licenses/LICENSE +31 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Imagen API client for Imagen 3, 4, and 4-Ultra models.
|
|
3
|
+
Uses the predict API endpoint per Google's documentation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
|
|
11
|
+
from ..config.constants import IMAGEN_API_BASE, IMAGEN_MODELS
|
|
12
|
+
from ..core.exceptions import (
|
|
13
|
+
APIError,
|
|
14
|
+
AuthenticationError,
|
|
15
|
+
ContentPolicyError,
|
|
16
|
+
RateLimitError,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ImagenClient:
|
|
23
|
+
"""Client for Imagen 3/4/Ultra API."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, api_key: str, timeout: int = 60):
|
|
26
|
+
"""
|
|
27
|
+
Initialize Imagen client.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
api_key: Gemini/Google API key
|
|
31
|
+
timeout: Request timeout in seconds
|
|
32
|
+
"""
|
|
33
|
+
self.api_key = api_key
|
|
34
|
+
self.timeout = timeout
|
|
35
|
+
self.base_url = IMAGEN_API_BASE
|
|
36
|
+
self.client = httpx.AsyncClient(timeout=timeout)
|
|
37
|
+
|
|
38
|
+
async def generate_image(
|
|
39
|
+
self,
|
|
40
|
+
prompt: str,
|
|
41
|
+
*,
|
|
42
|
+
model: str = "imagen-4-ultra",
|
|
43
|
+
number_of_images: int = 1,
|
|
44
|
+
aspect_ratio: str = "1:1",
|
|
45
|
+
output_format: str = "image/png",
|
|
46
|
+
person_generation: str = "allow_adult",
|
|
47
|
+
negative_prompt: str | None = None,
|
|
48
|
+
seed: int | None = None,
|
|
49
|
+
**kwargs: Any,
|
|
50
|
+
) -> dict[str, Any]:
|
|
51
|
+
"""
|
|
52
|
+
Generate images using Imagen API.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
prompt: Text prompt for image generation
|
|
56
|
+
model: Imagen model to use (imagen-3, imagen-4, imagen-4-ultra)
|
|
57
|
+
number_of_images: Number of images to generate (1-4)
|
|
58
|
+
aspect_ratio: Image aspect ratio
|
|
59
|
+
output_format: Output MIME type (image/jpeg or image/png)
|
|
60
|
+
person_generation: Person generation policy
|
|
61
|
+
negative_prompt: Optional negative prompt
|
|
62
|
+
seed: Optional seed for reproducibility
|
|
63
|
+
**kwargs: Additional parameters
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Dict with 'images' key containing list of base64-encoded images
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
APIError: If the API request fails
|
|
70
|
+
"""
|
|
71
|
+
model_id = IMAGEN_MODELS.get(model, model)
|
|
72
|
+
url = f"{self.base_url}/{model_id}:predict"
|
|
73
|
+
|
|
74
|
+
# Build request body according to Imagen API
|
|
75
|
+
request_body: dict[str, Any] = {
|
|
76
|
+
"instances": [
|
|
77
|
+
{
|
|
78
|
+
"prompt": prompt
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"parameters": {
|
|
82
|
+
"outputMimeType": output_format,
|
|
83
|
+
"sampleCount": number_of_images,
|
|
84
|
+
"personGeneration": person_generation,
|
|
85
|
+
"aspectRatio": aspect_ratio
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Add optional parameters
|
|
90
|
+
if negative_prompt:
|
|
91
|
+
request_body["instances"][0]["negativePrompt"] = negative_prompt
|
|
92
|
+
|
|
93
|
+
if seed is not None:
|
|
94
|
+
request_body["parameters"]["seed"] = seed
|
|
95
|
+
|
|
96
|
+
headers = {
|
|
97
|
+
"Content-Type": "application/json",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
logger.debug(f"Sending request to {url}")
|
|
102
|
+
# Add API key as query parameter
|
|
103
|
+
response = await self.client.post(
|
|
104
|
+
f"{url}?key={self.api_key}",
|
|
105
|
+
json=request_body,
|
|
106
|
+
headers=headers
|
|
107
|
+
)
|
|
108
|
+
response.raise_for_status()
|
|
109
|
+
data = response.json()
|
|
110
|
+
|
|
111
|
+
# Extract images from predictions
|
|
112
|
+
images = self._extract_images(data)
|
|
113
|
+
|
|
114
|
+
if not images:
|
|
115
|
+
raise APIError("No image data found in Imagen API response")
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
"images": images,
|
|
119
|
+
"model": model,
|
|
120
|
+
"response": data
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
except httpx.HTTPStatusError as e:
|
|
124
|
+
self._handle_http_error(e)
|
|
125
|
+
except Exception as e:
|
|
126
|
+
logger.error(f"Imagen API request failed: {e}")
|
|
127
|
+
raise APIError(f"Imagen API request failed: {e}")
|
|
128
|
+
|
|
129
|
+
def _extract_images(self, response_data: dict[str, Any]) -> list[str]:
|
|
130
|
+
"""Extract base64 image data from Imagen API response."""
|
|
131
|
+
images = []
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
predictions = response_data.get("predictions", [])
|
|
135
|
+
for prediction in predictions:
|
|
136
|
+
# Imagen returns base64 data in bytesBase64Encoded field
|
|
137
|
+
image_data = prediction.get("bytesBase64Encoded")
|
|
138
|
+
if image_data:
|
|
139
|
+
images.append(image_data)
|
|
140
|
+
except Exception as e:
|
|
141
|
+
logger.warning(f"Error extracting images from response: {e}")
|
|
142
|
+
|
|
143
|
+
return images
|
|
144
|
+
|
|
145
|
+
def _handle_http_error(self, error: httpx.HTTPStatusError) -> None:
|
|
146
|
+
"""Handle HTTP errors and raise appropriate exceptions."""
|
|
147
|
+
status_code = error.response.status_code
|
|
148
|
+
error_text = error.response.text
|
|
149
|
+
|
|
150
|
+
logger.error(f"API request failed with status {status_code}: {error_text}")
|
|
151
|
+
|
|
152
|
+
if status_code == 401 or status_code == 403:
|
|
153
|
+
raise AuthenticationError(
|
|
154
|
+
"Authentication failed. Please check your API key.",
|
|
155
|
+
status_code=status_code
|
|
156
|
+
)
|
|
157
|
+
elif status_code == 429:
|
|
158
|
+
raise RateLimitError(
|
|
159
|
+
"Rate limit exceeded. Please try again later.",
|
|
160
|
+
status_code=status_code
|
|
161
|
+
)
|
|
162
|
+
elif status_code == 400 and "SAFETY" in error_text.upper():
|
|
163
|
+
raise ContentPolicyError(
|
|
164
|
+
"Content was blocked by safety filters. Please modify your prompt.",
|
|
165
|
+
status_code=status_code
|
|
166
|
+
)
|
|
167
|
+
else:
|
|
168
|
+
raise APIError(
|
|
169
|
+
f"API request failed with status {status_code}: {error_text}",
|
|
170
|
+
status_code=status_code
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
async def close(self) -> None:
|
|
174
|
+
"""Close the HTTP client."""
|
|
175
|
+
await self.client.aclose()
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prompt enhancement service using Gemini Flash.
|
|
3
|
+
Automatically optimizes prompts for better image generation results.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from .gemini_client import GeminiClient
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
PROMPT_ENHANCEMENT_SYSTEM_INSTRUCTION = """You are an expert prompt engineer for AI image generation models. Your task is to enhance user prompts to produce the best possible results.
|
|
15
|
+
|
|
16
|
+
Follow these guidelines:
|
|
17
|
+
1. Preserve the user's core intent and subject matter
|
|
18
|
+
2. Add specific, professional details about:
|
|
19
|
+
- Composition (framing, perspective, angle)
|
|
20
|
+
- Lighting (type, quality, direction, mood)
|
|
21
|
+
- Materials and textures
|
|
22
|
+
- Atmosphere and mood
|
|
23
|
+
- Artistic style (if appropriate)
|
|
24
|
+
3. Use photographic and cinematic terminology when relevant
|
|
25
|
+
4. Be hyper-specific rather than generic
|
|
26
|
+
5. For portraits: describe features, expressions, clothing
|
|
27
|
+
6. For scenes: describe environment, weather, time of day
|
|
28
|
+
7. Keep prompts concise but detailed (aim for 100-300 words)
|
|
29
|
+
8. Output ONLY the enhanced prompt, no explanations"""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class PromptEnhancer:
|
|
33
|
+
"""Service for enhancing image generation prompts."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, gemini_client: GeminiClient):
|
|
36
|
+
"""
|
|
37
|
+
Initialize prompt enhancer.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
gemini_client: Gemini client for text generation
|
|
41
|
+
"""
|
|
42
|
+
self.gemini_client = gemini_client
|
|
43
|
+
|
|
44
|
+
async def enhance_prompt(
|
|
45
|
+
self,
|
|
46
|
+
original_prompt: str,
|
|
47
|
+
*,
|
|
48
|
+
context: dict[str, Any] | None = None,
|
|
49
|
+
) -> dict[str, str]:
|
|
50
|
+
"""
|
|
51
|
+
Enhance a prompt for better image generation.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
original_prompt: Original user prompt
|
|
55
|
+
context: Optional context (features, image type, etc.)
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Dict with 'enhanced_prompt' and 'original_prompt'
|
|
59
|
+
"""
|
|
60
|
+
# Build enhancement instruction
|
|
61
|
+
instruction = self._build_enhancement_instruction(original_prompt, context)
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
enhanced = await self.gemini_client.generate_text(
|
|
65
|
+
prompt=instruction,
|
|
66
|
+
system_instruction=PROMPT_ENHANCEMENT_SYSTEM_INSTRUCTION,
|
|
67
|
+
model="gemini-flash-latest"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Clean up the enhanced prompt
|
|
71
|
+
enhanced = enhanced.strip()
|
|
72
|
+
|
|
73
|
+
logger.info(f"Enhanced prompt: {len(original_prompt)} -> {len(enhanced)} chars")
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
"original_prompt": original_prompt,
|
|
77
|
+
"enhanced_prompt": enhanced,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.warning(f"Prompt enhancement failed, using original: {e}")
|
|
82
|
+
return {
|
|
83
|
+
"original_prompt": original_prompt,
|
|
84
|
+
"enhanced_prompt": original_prompt,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
def _build_enhancement_instruction(
|
|
88
|
+
self,
|
|
89
|
+
prompt: str,
|
|
90
|
+
context: dict[str, Any] | None
|
|
91
|
+
) -> str:
|
|
92
|
+
"""Build the instruction for prompt enhancement."""
|
|
93
|
+
instruction_parts = [f"Enhance this image generation prompt:\n\n{prompt}"]
|
|
94
|
+
|
|
95
|
+
if context:
|
|
96
|
+
# Add context hints
|
|
97
|
+
if context.get("is_editing"):
|
|
98
|
+
instruction_parts.append("\nContext: This is for image editing/modification")
|
|
99
|
+
|
|
100
|
+
if context.get("maintain_character_consistency"):
|
|
101
|
+
instruction_parts.append(
|
|
102
|
+
"\nIMPORTANT: Describe the character with specific, consistent features "
|
|
103
|
+
"for use across multiple generations"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if context.get("blend_images"):
|
|
107
|
+
instruction_parts.append(
|
|
108
|
+
"\nContext: Multiple images will be blended. Describe how elements "
|
|
109
|
+
"should be composed naturally together"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if context.get("use_world_knowledge"):
|
|
113
|
+
instruction_parts.append(
|
|
114
|
+
"\nContext: Include accurate real-world details for historical figures, "
|
|
115
|
+
"landmarks, or factual scenarios"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if context.get("aspect_ratio"):
|
|
119
|
+
ratio = context["aspect_ratio"]
|
|
120
|
+
if ratio in ["16:9", "21:9"]:
|
|
121
|
+
instruction_parts.append("\nFormat: Wide landscape composition")
|
|
122
|
+
elif ratio in ["9:16", "2:3", "3:4"]:
|
|
123
|
+
instruction_parts.append("\nFormat: Vertical/portrait composition")
|
|
124
|
+
|
|
125
|
+
return "\n".join(instruction_parts)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
async def create_prompt_enhancer(api_key: str, timeout: int = 30) -> PromptEnhancer:
|
|
129
|
+
"""
|
|
130
|
+
Factory function to create prompt enhancer.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
api_key: Gemini API key
|
|
134
|
+
timeout: Request timeout
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
PromptEnhancer instance
|
|
138
|
+
"""
|
|
139
|
+
gemini_client = GeminiClient(api_key=api_key, timeout=timeout)
|
|
140
|
+
return PromptEnhancer(gemini_client)
|
src/tools/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Tools module for Ultimate Gemini MCP."""
|
|
2
|
+
|
|
3
|
+
from .batch_generate import batch_generate_images, register_batch_generate_tool
|
|
4
|
+
from .generate_image import generate_image_tool, register_generate_image_tool
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"generate_image_tool",
|
|
8
|
+
"register_generate_image_tool",
|
|
9
|
+
"batch_generate_images",
|
|
10
|
+
"register_batch_generate_tool",
|
|
11
|
+
]
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Batch image generation tool for processing multiple prompts efficiently.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from ..config import MAX_BATCH_SIZE, get_settings
|
|
11
|
+
from ..core import validate_batch_size, validate_prompts_list
|
|
12
|
+
from .generate_image import generate_image_tool
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def batch_generate_images(
|
|
18
|
+
prompts: list[str],
|
|
19
|
+
model: str | None = None,
|
|
20
|
+
enhance_prompt: bool = True,
|
|
21
|
+
aspect_ratio: str = "1:1",
|
|
22
|
+
output_format: str = "png",
|
|
23
|
+
batch_size: int | None = None,
|
|
24
|
+
**shared_params: Any,
|
|
25
|
+
) -> dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Generate multiple images from a list of prompts.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
prompts: List of text prompts
|
|
31
|
+
model: Model to use for all images
|
|
32
|
+
enhance_prompt: Enhance all prompts
|
|
33
|
+
aspect_ratio: Aspect ratio for all images
|
|
34
|
+
output_format: Output format for all images
|
|
35
|
+
batch_size: Number of images to process in parallel (default: from config)
|
|
36
|
+
**shared_params: Additional parameters shared across all generations
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Dict with batch results
|
|
40
|
+
"""
|
|
41
|
+
# Validate inputs
|
|
42
|
+
validate_prompts_list(prompts)
|
|
43
|
+
|
|
44
|
+
settings = get_settings()
|
|
45
|
+
if batch_size is None:
|
|
46
|
+
batch_size = settings.api.max_batch_size
|
|
47
|
+
|
|
48
|
+
validate_batch_size(batch_size, MAX_BATCH_SIZE)
|
|
49
|
+
|
|
50
|
+
# Prepare results
|
|
51
|
+
results = {
|
|
52
|
+
"success": True,
|
|
53
|
+
"total_prompts": len(prompts),
|
|
54
|
+
"batch_size": batch_size,
|
|
55
|
+
"completed": 0,
|
|
56
|
+
"failed": 0,
|
|
57
|
+
"results": []
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Process prompts in batches
|
|
61
|
+
for i in range(0, len(prompts), batch_size):
|
|
62
|
+
batch = prompts[i:i + batch_size]
|
|
63
|
+
logger.info(f"Processing batch {i // batch_size + 1}: {len(batch)} prompts")
|
|
64
|
+
|
|
65
|
+
# Create tasks for parallel processing
|
|
66
|
+
tasks = [
|
|
67
|
+
generate_image_tool(
|
|
68
|
+
prompt=prompt,
|
|
69
|
+
model=model,
|
|
70
|
+
enhance_prompt=enhance_prompt,
|
|
71
|
+
aspect_ratio=aspect_ratio,
|
|
72
|
+
output_format=output_format,
|
|
73
|
+
number_of_images=1,
|
|
74
|
+
**shared_params
|
|
75
|
+
)
|
|
76
|
+
for prompt in batch
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
# Execute batch
|
|
80
|
+
batch_results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
81
|
+
|
|
82
|
+
# Process results
|
|
83
|
+
for j, result in enumerate(batch_results):
|
|
84
|
+
prompt_index = i + j
|
|
85
|
+
|
|
86
|
+
if isinstance(result, Exception):
|
|
87
|
+
logger.error(f"Failed to generate image for prompt {prompt_index}: {result}")
|
|
88
|
+
results["failed"] += 1
|
|
89
|
+
results["results"].append({
|
|
90
|
+
"prompt_index": prompt_index,
|
|
91
|
+
"prompt": batch[j],
|
|
92
|
+
"success": False,
|
|
93
|
+
"error": str(result)
|
|
94
|
+
})
|
|
95
|
+
else:
|
|
96
|
+
results["completed"] += 1
|
|
97
|
+
results["results"].append({
|
|
98
|
+
"prompt_index": prompt_index,
|
|
99
|
+
"prompt": batch[j],
|
|
100
|
+
**result
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
return results
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def register_batch_generate_tool(mcp_server: Any) -> None:
|
|
107
|
+
"""Register batch_generate tool with MCP server."""
|
|
108
|
+
|
|
109
|
+
@mcp_server.tool()
|
|
110
|
+
async def batch_generate(
|
|
111
|
+
prompts: list[str],
|
|
112
|
+
model: str | None = None,
|
|
113
|
+
enhance_prompt: bool = True,
|
|
114
|
+
aspect_ratio: str = "1:1",
|
|
115
|
+
output_format: str = "png",
|
|
116
|
+
batch_size: int | None = None,
|
|
117
|
+
person_generation: str = "allow_adult",
|
|
118
|
+
negative_prompt: str | None = None,
|
|
119
|
+
) -> str:
|
|
120
|
+
"""
|
|
121
|
+
Generate multiple images from a list of prompts efficiently.
|
|
122
|
+
|
|
123
|
+
Processes prompts in parallel batches for optimal performance.
|
|
124
|
+
All images share the same generation settings.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
prompts: List of text descriptions for image generation
|
|
128
|
+
model: Model to use for all images (default: gemini-2.5-flash-image)
|
|
129
|
+
enhance_prompt: Enhance all prompts automatically (default: True)
|
|
130
|
+
aspect_ratio: Aspect ratio for all images (default: 1:1)
|
|
131
|
+
output_format: Image format for all images (default: png)
|
|
132
|
+
batch_size: Parallel batch size (default: from config)
|
|
133
|
+
person_generation: Person policy for Imagen models (default: allow_adult)
|
|
134
|
+
negative_prompt: Negative prompt for Imagen models (optional)
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
JSON string with batch results including individual image paths
|
|
138
|
+
"""
|
|
139
|
+
try:
|
|
140
|
+
result = await batch_generate_images(
|
|
141
|
+
prompts=prompts,
|
|
142
|
+
model=model,
|
|
143
|
+
enhance_prompt=enhance_prompt,
|
|
144
|
+
aspect_ratio=aspect_ratio,
|
|
145
|
+
output_format=output_format,
|
|
146
|
+
batch_size=batch_size,
|
|
147
|
+
person_generation=person_generation,
|
|
148
|
+
negative_prompt=negative_prompt,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return json.dumps(result, indent=2)
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.error(f"Batch generation error: {e}")
|
|
155
|
+
return json.dumps({
|
|
156
|
+
"success": False,
|
|
157
|
+
"error": str(e),
|
|
158
|
+
"error_type": type(e).__name__
|
|
159
|
+
}, indent=2)
|