ag-cortex 0.1.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/.agent/commands/test-browser.md +339 -0
- package/.agent/rules/00-constitution.md +46 -0
- package/.agent/rules/project-rules.md +49 -0
- package/.agent/skills/agent-browser/SKILL.md +223 -0
- package/.agent/skills/agent-native-architecture/SKILL.md +435 -0
- package/.agent/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
- package/.agent/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
- package/.agent/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
- package/.agent/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
- package/.agent/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
- package/.agent/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
- package/.agent/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
- package/.agent/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
- package/.agent/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
- package/.agent/skills/agent-native-architecture/references/product-implications.md +443 -0
- package/.agent/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
- package/.agent/skills/agent-native-architecture/references/self-modification.md +269 -0
- package/.agent/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
- package/.agent/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
- package/.agent/skills/agent-native-reviewer/SKILL.md +246 -0
- package/.agent/skills/andrew-kane-gem-writer/SKILL.md +184 -0
- package/.agent/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/.agent/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/.agent/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/.agent/skills/andrew-kane-gem-writer/references/resources.md +119 -0
- package/.agent/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/.agent/skills/ankane-readme-writer/SKILL.md +50 -0
- package/.agent/skills/architecture-strategist/SKILL.md +52 -0
- package/.agent/skills/best-practices-researcher/SKILL.md +100 -0
- package/.agent/skills/bug-reproduction-validator/SKILL.md +67 -0
- package/.agent/skills/code-simplicity-reviewer/SKILL.md +85 -0
- package/.agent/skills/coding-tutor/.claude-plugin/plugin.json +9 -0
- package/.agent/skills/coding-tutor/README.md +37 -0
- package/.agent/skills/coding-tutor/commands/quiz-me.md +1 -0
- package/.agent/skills/coding-tutor/commands/sync-tutorials.md +25 -0
- package/.agent/skills/coding-tutor/commands/teach-me.md +1 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/SKILL.md +214 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py +202 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py +203 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py +190 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py +132 -0
- package/.agent/skills/compound-docs/SKILL.md +510 -0
- package/.agent/skills/compound-docs/assets/critical-pattern-template.md +34 -0
- package/.agent/skills/compound-docs/assets/resolution-template.md +93 -0
- package/.agent/skills/compound-docs/references/yaml-schema.md +65 -0
- package/.agent/skills/compound-docs/schema.yaml +176 -0
- package/.agent/skills/create-agent-skills/SKILL.md +299 -0
- package/.agent/skills/create-agent-skills/references/api-security.md +226 -0
- package/.agent/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
- package/.agent/skills/create-agent-skills/references/best-practices.md +404 -0
- package/.agent/skills/create-agent-skills/references/common-patterns.md +595 -0
- package/.agent/skills/create-agent-skills/references/core-principles.md +437 -0
- package/.agent/skills/create-agent-skills/references/executable-code.md +175 -0
- package/.agent/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
- package/.agent/skills/create-agent-skills/references/official-spec.md +185 -0
- package/.agent/skills/create-agent-skills/references/recommended-structure.md +168 -0
- package/.agent/skills/create-agent-skills/references/skill-structure.md +372 -0
- package/.agent/skills/create-agent-skills/references/using-scripts.md +113 -0
- package/.agent/skills/create-agent-skills/references/using-templates.md +112 -0
- package/.agent/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
- package/.agent/skills/create-agent-skills/templates/router-skill.md +73 -0
- package/.agent/skills/create-agent-skills/templates/simple-skill.md +33 -0
- package/.agent/skills/create-agent-skills/workflows/add-reference.md +96 -0
- package/.agent/skills/create-agent-skills/workflows/add-script.md +93 -0
- package/.agent/skills/create-agent-skills/workflows/add-template.md +74 -0
- package/.agent/skills/create-agent-skills/workflows/add-workflow.md +120 -0
- package/.agent/skills/create-agent-skills/workflows/audit-skill.md +138 -0
- package/.agent/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
- package/.agent/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
- package/.agent/skills/create-agent-skills/workflows/get-guidance.md +121 -0
- package/.agent/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
- package/.agent/skills/create-agent-skills/workflows/verify-skill.md +204 -0
- package/.agent/skills/data-integrity-guardian/SKILL.md +70 -0
- package/.agent/skills/data-migration-expert/SKILL.md +97 -0
- package/.agent/skills/deployment-verification-agent/SKILL.md +159 -0
- package/.agent/skills/design-implementation-reviewer/SKILL.md +85 -0
- package/.agent/skills/design-iterator/SKILL.md +197 -0
- package/.agent/skills/dhh-rails-reviewer/SKILL.md +45 -0
- package/.agent/skills/dhh-rails-style/SKILL.md +184 -0
- package/.agent/skills/dhh-rails-style/references/architecture.md +653 -0
- package/.agent/skills/dhh-rails-style/references/controllers.md +303 -0
- package/.agent/skills/dhh-rails-style/references/frontend.md +510 -0
- package/.agent/skills/dhh-rails-style/references/gems.md +266 -0
- package/.agent/skills/dhh-rails-style/references/models.md +359 -0
- package/.agent/skills/dhh-rails-style/references/testing.md +338 -0
- package/.agent/skills/dspy-ruby/SKILL.md +594 -0
- package/.agent/skills/dspy-ruby/assets/config-template.rb +359 -0
- package/.agent/skills/dspy-ruby/assets/module-template.rb +326 -0
- package/.agent/skills/dspy-ruby/assets/signature-template.rb +143 -0
- package/.agent/skills/dspy-ruby/references/core-concepts.md +265 -0
- package/.agent/skills/dspy-ruby/references/optimization.md +623 -0
- package/.agent/skills/dspy-ruby/references/providers.md +305 -0
- package/.agent/skills/every-style-editor/SKILL.md +134 -0
- package/.agent/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/.agent/skills/figma-design-sync/SKILL.md +166 -0
- package/.agent/skills/file-todos/SKILL.md +251 -0
- package/.agent/skills/file-todos/assets/todo-template.md +155 -0
- package/.agent/skills/framework-docs-researcher/SKILL.md +83 -0
- package/.agent/skills/frontend-design/SKILL.md +42 -0
- package/.agent/skills/gemini-imagegen/SKILL.md +237 -0
- package/.agent/skills/gemini-imagegen/requirements.txt +2 -0
- package/.agent/skills/gemini-imagegen/scripts/compose_images.py +168 -0
- package/.agent/skills/gemini-imagegen/scripts/edit_image.py +157 -0
- package/.agent/skills/gemini-imagegen/scripts/gemini_images.py +265 -0
- package/.agent/skills/gemini-imagegen/scripts/generate_image.py +147 -0
- package/.agent/skills/gemini-imagegen/scripts/multi_turn_chat.py +215 -0
- package/.agent/skills/git-history-analyzer/SKILL.md +42 -0
- package/.agent/skills/git-worktree/SKILL.md +302 -0
- package/.agent/skills/git-worktree/scripts/worktree-manager.sh +345 -0
- package/.agent/skills/julik-frontend-races-reviewer/SKILL.md +222 -0
- package/.agent/skills/kieran-python-reviewer/SKILL.md +104 -0
- package/.agent/skills/kieran-rails-reviewer/SKILL.md +86 -0
- package/.agent/skills/kieran-typescript-reviewer/SKILL.md +95 -0
- package/.agent/skills/lint/SKILL.md +16 -0
- package/.agent/skills/pattern-recognition-specialist/SKILL.md +57 -0
- package/.agent/skills/performance-oracle/SKILL.md +110 -0
- package/.agent/skills/pr-comment-resolver/SKILL.md +69 -0
- package/.agent/skills/rclone/SKILL.md +150 -0
- package/.agent/skills/rclone/scripts/check_setup.sh +60 -0
- package/.agent/skills/repo-research-analyst/SKILL.md +113 -0
- package/.agent/skills/security-sentinel/SKILL.md +93 -0
- package/.agent/skills/skill-creator/SKILL.md +209 -0
- package/.agent/skills/skill-creator/scripts/init_skill.py +304 -0
- package/.agent/skills/skill-creator/scripts/package_skill.py +112 -0
- package/.agent/skills/skill-creator/scripts/quick_validate.py +72 -0
- package/.agent/skills/spec-flow-analyzer/SKILL.md +113 -0
- package/.agent/skills/test-agent/SKILL.md +4 -0
- package/.agent/workflows/agent-native-audit.md +277 -0
- package/.agent/workflows/ask-user-question.md +21 -0
- package/.agent/workflows/changelog.md +137 -0
- package/.agent/workflows/compound.md +202 -0
- package/.agent/workflows/create-agent-skill.md +8 -0
- package/.agent/workflows/deepen-plan-research.md +334 -0
- package/.agent/workflows/deepen-plan-synthesis.md +182 -0
- package/.agent/workflows/deepen-plan.md +79 -0
- package/.agent/workflows/feature-video.md +342 -0
- package/.agent/workflows/generate-command.md +162 -0
- package/.agent/workflows/heal-skill.md +142 -0
- package/.agent/workflows/lfg.md +20 -0
- package/.agent/workflows/plan-analysis.md +67 -0
- package/.agent/workflows/plan-next-steps.md +63 -0
- package/.agent/workflows/plan-review.md +33 -0
- package/.agent/workflows/plan-synthesis.md +106 -0
- package/.agent/workflows/plan.md +49 -0
- package/.agent/workflows/report-bug.md +150 -0
- package/.agent/workflows/reproduce-bug.md +99 -0
- package/.agent/workflows/resolve-parallel.md +34 -0
- package/.agent/workflows/resolve-pr-parallel.md +49 -0
- package/.agent/workflows/resolve-todo-parallel.md +35 -0
- package/.agent/workflows/review-analysis.md +145 -0
- package/.agent/workflows/review-synthesis.md +262 -0
- package/.agent/workflows/review.md +64 -0
- package/.agent/workflows/ship.md +90 -0
- package/.agent/workflows/test-command.md +3 -0
- package/.agent/workflows/triage.md +310 -0
- package/.agent/workflows/work.md +157 -0
- package/.agent/workflows/xcode-test.md +332 -0
- package/LICENSE +22 -0
- package/README.md +49 -0
- package/bin/ag-cortex.js +54 -0
- package/lib/core.js +165 -0
- package/package.json +31 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Gemini Image Generation Library
|
|
3
|
+
|
|
4
|
+
A simple Python library for generating and editing images with the Gemini API.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from gemini_images import GeminiImageGenerator
|
|
8
|
+
|
|
9
|
+
gen = GeminiImageGenerator()
|
|
10
|
+
gen.generate("A sunset over mountains", "sunset.png")
|
|
11
|
+
gen.edit("input.png", "Add clouds", "output.png")
|
|
12
|
+
|
|
13
|
+
Environment:
|
|
14
|
+
GEMINI_API_KEY - Required API key
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Literal
|
|
20
|
+
|
|
21
|
+
from PIL import Image
|
|
22
|
+
from google import genai
|
|
23
|
+
from google.genai import types
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
AspectRatio = Literal[
|
|
27
|
+
"1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"
|
|
28
|
+
]
|
|
29
|
+
ImageSize = Literal["1K", "2K", "4K"]
|
|
30
|
+
Model = Literal["gemini-2.5-flash-image", "gemini-3-pro-image-preview"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class GeminiImageGenerator:
|
|
34
|
+
"""High-level interface for Gemini image generation."""
|
|
35
|
+
|
|
36
|
+
FLASH = "gemini-2.5-flash-image"
|
|
37
|
+
PRO = "gemini-3-pro-image-preview"
|
|
38
|
+
|
|
39
|
+
def __init__(self, api_key: str | None = None, model: Model = FLASH):
|
|
40
|
+
"""Initialize the generator.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
api_key: Gemini API key (defaults to GEMINI_API_KEY env var)
|
|
44
|
+
model: Default model to use
|
|
45
|
+
"""
|
|
46
|
+
self.api_key = api_key or os.environ.get("GEMINI_API_KEY")
|
|
47
|
+
if not self.api_key:
|
|
48
|
+
raise EnvironmentError("GEMINI_API_KEY not set")
|
|
49
|
+
|
|
50
|
+
self.client = genai.Client(api_key=self.api_key)
|
|
51
|
+
self.model = model
|
|
52
|
+
|
|
53
|
+
def _build_config(
|
|
54
|
+
self,
|
|
55
|
+
aspect_ratio: AspectRatio | None = None,
|
|
56
|
+
image_size: ImageSize | None = None,
|
|
57
|
+
google_search: bool = False,
|
|
58
|
+
) -> types.GenerateContentConfig:
|
|
59
|
+
"""Build generation config."""
|
|
60
|
+
kwargs = {"response_modalities": ["TEXT", "IMAGE"]}
|
|
61
|
+
|
|
62
|
+
img_config = {}
|
|
63
|
+
if aspect_ratio:
|
|
64
|
+
img_config["aspect_ratio"] = aspect_ratio
|
|
65
|
+
if image_size:
|
|
66
|
+
img_config["image_size"] = image_size
|
|
67
|
+
|
|
68
|
+
if img_config:
|
|
69
|
+
kwargs["image_config"] = types.ImageConfig(**img_config)
|
|
70
|
+
|
|
71
|
+
if google_search:
|
|
72
|
+
kwargs["tools"] = [{"google_search": {}}]
|
|
73
|
+
|
|
74
|
+
return types.GenerateContentConfig(**kwargs)
|
|
75
|
+
|
|
76
|
+
def generate(
|
|
77
|
+
self,
|
|
78
|
+
prompt: str,
|
|
79
|
+
output: str | Path,
|
|
80
|
+
*,
|
|
81
|
+
model: Model | None = None,
|
|
82
|
+
aspect_ratio: AspectRatio | None = None,
|
|
83
|
+
image_size: ImageSize | None = None,
|
|
84
|
+
google_search: bool = False,
|
|
85
|
+
) -> tuple[Path, str | None]:
|
|
86
|
+
"""Generate an image from a text prompt.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
prompt: Text description
|
|
90
|
+
output: Output file path
|
|
91
|
+
model: Override default model
|
|
92
|
+
aspect_ratio: Output aspect ratio
|
|
93
|
+
image_size: Output resolution
|
|
94
|
+
google_search: Enable Google Search grounding (Pro only)
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Tuple of (output path, optional text response)
|
|
98
|
+
"""
|
|
99
|
+
output = Path(output)
|
|
100
|
+
config = self._build_config(aspect_ratio, image_size, google_search)
|
|
101
|
+
|
|
102
|
+
response = self.client.models.generate_content(
|
|
103
|
+
model=model or self.model,
|
|
104
|
+
contents=[prompt],
|
|
105
|
+
config=config,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
text = None
|
|
109
|
+
for part in response.parts:
|
|
110
|
+
if part.text:
|
|
111
|
+
text = part.text
|
|
112
|
+
elif part.inline_data:
|
|
113
|
+
part.as_image().save(output)
|
|
114
|
+
|
|
115
|
+
return output, text
|
|
116
|
+
|
|
117
|
+
def edit(
|
|
118
|
+
self,
|
|
119
|
+
input_image: str | Path | Image.Image,
|
|
120
|
+
instruction: str,
|
|
121
|
+
output: str | Path,
|
|
122
|
+
*,
|
|
123
|
+
model: Model | None = None,
|
|
124
|
+
aspect_ratio: AspectRatio | None = None,
|
|
125
|
+
image_size: ImageSize | None = None,
|
|
126
|
+
) -> tuple[Path, str | None]:
|
|
127
|
+
"""Edit an existing image.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
input_image: Input image (path or PIL Image)
|
|
131
|
+
instruction: Edit instruction
|
|
132
|
+
output: Output file path
|
|
133
|
+
model: Override default model
|
|
134
|
+
aspect_ratio: Output aspect ratio
|
|
135
|
+
image_size: Output resolution
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Tuple of (output path, optional text response)
|
|
139
|
+
"""
|
|
140
|
+
output = Path(output)
|
|
141
|
+
|
|
142
|
+
if isinstance(input_image, (str, Path)):
|
|
143
|
+
input_image = Image.open(input_image)
|
|
144
|
+
|
|
145
|
+
config = self._build_config(aspect_ratio, image_size)
|
|
146
|
+
|
|
147
|
+
response = self.client.models.generate_content(
|
|
148
|
+
model=model or self.model,
|
|
149
|
+
contents=[instruction, input_image],
|
|
150
|
+
config=config,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
text = None
|
|
154
|
+
for part in response.parts:
|
|
155
|
+
if part.text:
|
|
156
|
+
text = part.text
|
|
157
|
+
elif part.inline_data:
|
|
158
|
+
part.as_image().save(output)
|
|
159
|
+
|
|
160
|
+
return output, text
|
|
161
|
+
|
|
162
|
+
def compose(
|
|
163
|
+
self,
|
|
164
|
+
instruction: str,
|
|
165
|
+
images: list[str | Path | Image.Image],
|
|
166
|
+
output: str | Path,
|
|
167
|
+
*,
|
|
168
|
+
model: Model | None = None,
|
|
169
|
+
aspect_ratio: AspectRatio | None = None,
|
|
170
|
+
image_size: ImageSize | None = None,
|
|
171
|
+
) -> tuple[Path, str | None]:
|
|
172
|
+
"""Compose multiple images into one.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
instruction: Composition instruction
|
|
176
|
+
images: List of input images (up to 14)
|
|
177
|
+
output: Output file path
|
|
178
|
+
model: Override default model (Pro recommended)
|
|
179
|
+
aspect_ratio: Output aspect ratio
|
|
180
|
+
image_size: Output resolution
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Tuple of (output path, optional text response)
|
|
184
|
+
"""
|
|
185
|
+
output = Path(output)
|
|
186
|
+
|
|
187
|
+
# Load images
|
|
188
|
+
loaded = []
|
|
189
|
+
for img in images:
|
|
190
|
+
if isinstance(img, (str, Path)):
|
|
191
|
+
loaded.append(Image.open(img))
|
|
192
|
+
else:
|
|
193
|
+
loaded.append(img)
|
|
194
|
+
|
|
195
|
+
config = self._build_config(aspect_ratio, image_size)
|
|
196
|
+
contents = [instruction] + loaded
|
|
197
|
+
|
|
198
|
+
response = self.client.models.generate_content(
|
|
199
|
+
model=model or self.PRO, # Pro recommended for composition
|
|
200
|
+
contents=contents,
|
|
201
|
+
config=config,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
text = None
|
|
205
|
+
for part in response.parts:
|
|
206
|
+
if part.text:
|
|
207
|
+
text = part.text
|
|
208
|
+
elif part.inline_data:
|
|
209
|
+
part.as_image().save(output)
|
|
210
|
+
|
|
211
|
+
return output, text
|
|
212
|
+
|
|
213
|
+
def chat(self) -> "ImageChat":
|
|
214
|
+
"""Start an interactive chat session for iterative refinement."""
|
|
215
|
+
return ImageChat(self.client, self.model)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class ImageChat:
|
|
219
|
+
"""Multi-turn chat session for iterative image generation."""
|
|
220
|
+
|
|
221
|
+
def __init__(self, client: genai.Client, model: Model):
|
|
222
|
+
self.client = client
|
|
223
|
+
self.model = model
|
|
224
|
+
self._chat = client.chats.create(
|
|
225
|
+
model=model,
|
|
226
|
+
config=types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]),
|
|
227
|
+
)
|
|
228
|
+
self.current_image: Image.Image | None = None
|
|
229
|
+
|
|
230
|
+
def send(
|
|
231
|
+
self,
|
|
232
|
+
message: str,
|
|
233
|
+
image: Image.Image | str | Path | None = None,
|
|
234
|
+
) -> tuple[Image.Image | None, str | None]:
|
|
235
|
+
"""Send a message and optionally an image.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Tuple of (generated image or None, text response or None)
|
|
239
|
+
"""
|
|
240
|
+
contents = [message]
|
|
241
|
+
if image:
|
|
242
|
+
if isinstance(image, (str, Path)):
|
|
243
|
+
image = Image.open(image)
|
|
244
|
+
contents.append(image)
|
|
245
|
+
|
|
246
|
+
response = self._chat.send_message(contents)
|
|
247
|
+
|
|
248
|
+
text = None
|
|
249
|
+
img = None
|
|
250
|
+
for part in response.parts:
|
|
251
|
+
if part.text:
|
|
252
|
+
text = part.text
|
|
253
|
+
elif part.inline_data:
|
|
254
|
+
img = part.as_image()
|
|
255
|
+
self.current_image = img
|
|
256
|
+
|
|
257
|
+
return img, text
|
|
258
|
+
|
|
259
|
+
def reset(self):
|
|
260
|
+
"""Reset the chat session."""
|
|
261
|
+
self._chat = self.client.chats.create(
|
|
262
|
+
model=self.model,
|
|
263
|
+
config=types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]),
|
|
264
|
+
)
|
|
265
|
+
self.current_image = None
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Generate images from text prompts using Gemini API.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python generate_image.py "prompt" output.png [--model MODEL] [--aspect RATIO] [--size SIZE]
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
python generate_image.py "A cat in space" cat.png
|
|
10
|
+
python generate_image.py "A logo for Acme Corp" logo.png --model gemini-3-pro-image-preview --aspect 1:1
|
|
11
|
+
python generate_image.py "Epic landscape" landscape.png --aspect 16:9 --size 2K
|
|
12
|
+
|
|
13
|
+
Environment:
|
|
14
|
+
GEMINI_API_KEY - Required API key
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
from google import genai
|
|
22
|
+
from google.genai import types
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def generate_image(
|
|
26
|
+
prompt: str,
|
|
27
|
+
output_path: str,
|
|
28
|
+
model: str = "gemini-2.5-flash-image",
|
|
29
|
+
aspect_ratio: str | None = None,
|
|
30
|
+
image_size: str | None = None,
|
|
31
|
+
) -> str | None:
|
|
32
|
+
"""Generate an image from a text prompt.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
prompt: Text description of the image to generate
|
|
36
|
+
output_path: Path to save the generated image
|
|
37
|
+
model: Gemini model to use
|
|
38
|
+
aspect_ratio: Aspect ratio (1:1, 16:9, 9:16, etc.)
|
|
39
|
+
image_size: Resolution (1K, 2K, 4K - 4K only for pro model)
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Any text response from the model, or None
|
|
43
|
+
"""
|
|
44
|
+
api_key = os.environ.get("GEMINI_API_KEY")
|
|
45
|
+
if not api_key:
|
|
46
|
+
raise EnvironmentError("GEMINI_API_KEY environment variable not set")
|
|
47
|
+
|
|
48
|
+
client = genai.Client(api_key=api_key)
|
|
49
|
+
|
|
50
|
+
# Build config
|
|
51
|
+
config_kwargs = {"response_modalities": ["TEXT", "IMAGE"]}
|
|
52
|
+
|
|
53
|
+
image_config_kwargs = {}
|
|
54
|
+
if aspect_ratio:
|
|
55
|
+
image_config_kwargs["aspect_ratio"] = aspect_ratio
|
|
56
|
+
if image_size:
|
|
57
|
+
image_config_kwargs["image_size"] = image_size
|
|
58
|
+
|
|
59
|
+
if image_config_kwargs:
|
|
60
|
+
config_kwargs["image_config"] = types.ImageConfig(**image_config_kwargs)
|
|
61
|
+
|
|
62
|
+
config = types.GenerateContentConfig(**config_kwargs)
|
|
63
|
+
|
|
64
|
+
response = client.models.generate_content(
|
|
65
|
+
model=model,
|
|
66
|
+
contents=[prompt],
|
|
67
|
+
config=config,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
text_response = None
|
|
71
|
+
image_saved = False
|
|
72
|
+
|
|
73
|
+
for part in response.parts:
|
|
74
|
+
if part.text is not None:
|
|
75
|
+
text_response = part.text
|
|
76
|
+
elif part.inline_data is not None:
|
|
77
|
+
image = part.as_image()
|
|
78
|
+
image.save(output_path)
|
|
79
|
+
image_saved = True
|
|
80
|
+
|
|
81
|
+
if not image_saved:
|
|
82
|
+
raise RuntimeError("No image was generated. Check your prompt and try again.")
|
|
83
|
+
|
|
84
|
+
return text_response
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def main():
|
|
88
|
+
parser = argparse.ArgumentParser(
|
|
89
|
+
description="Generate images from text prompts using Gemini API",
|
|
90
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
91
|
+
epilog=__doc__,
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument("prompt", help="Text prompt describing the image")
|
|
94
|
+
parser.add_argument("output", help="Output file path (e.g., output.png)")
|
|
95
|
+
parser.add_argument(
|
|
96
|
+
"--model",
|
|
97
|
+
"-m",
|
|
98
|
+
default="gemini-2.5-flash-image",
|
|
99
|
+
choices=["gemini-2.5-flash-image", "gemini-3-pro-image-preview"],
|
|
100
|
+
help="Model to use (default: gemini-2.5-flash-image)",
|
|
101
|
+
)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"--aspect",
|
|
104
|
+
"-a",
|
|
105
|
+
choices=[
|
|
106
|
+
"1:1",
|
|
107
|
+
"2:3",
|
|
108
|
+
"3:2",
|
|
109
|
+
"3:4",
|
|
110
|
+
"4:3",
|
|
111
|
+
"4:5",
|
|
112
|
+
"5:4",
|
|
113
|
+
"9:16",
|
|
114
|
+
"16:9",
|
|
115
|
+
"21:9",
|
|
116
|
+
],
|
|
117
|
+
help="Aspect ratio",
|
|
118
|
+
)
|
|
119
|
+
parser.add_argument(
|
|
120
|
+
"--size",
|
|
121
|
+
"-s",
|
|
122
|
+
choices=["1K", "2K", "4K"],
|
|
123
|
+
help="Image resolution (4K only available with pro model)",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
args = parser.parse_args()
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
text = generate_image(
|
|
130
|
+
prompt=args.prompt,
|
|
131
|
+
output_path=args.output,
|
|
132
|
+
model=args.model,
|
|
133
|
+
aspect_ratio=args.aspect,
|
|
134
|
+
image_size=args.size,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
print(f"Image saved to: {args.output}")
|
|
138
|
+
if text:
|
|
139
|
+
print(f"Model response: {text}")
|
|
140
|
+
|
|
141
|
+
except Exception as e:
|
|
142
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
143
|
+
sys.exit(1)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if __name__ == "__main__":
|
|
147
|
+
main()
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Interactive multi-turn image generation and refinement using Gemini API.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python multi_turn_chat.py [--model MODEL] [--output-dir DIR]
|
|
7
|
+
|
|
8
|
+
This starts an interactive session where you can:
|
|
9
|
+
- Generate images from prompts
|
|
10
|
+
- Iteratively refine images through conversation
|
|
11
|
+
- Load existing images for editing
|
|
12
|
+
- Save images at any point
|
|
13
|
+
|
|
14
|
+
Commands:
|
|
15
|
+
/save [filename] - Save current image
|
|
16
|
+
/load <path> - Load an image into the conversation
|
|
17
|
+
/clear - Start fresh conversation
|
|
18
|
+
/quit - Exit
|
|
19
|
+
|
|
20
|
+
Environment:
|
|
21
|
+
GEMINI_API_KEY - Required API key
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import os
|
|
26
|
+
import sys
|
|
27
|
+
from datetime import datetime
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
from PIL import Image
|
|
31
|
+
from google import genai
|
|
32
|
+
from google.genai import types
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ImageChat:
|
|
36
|
+
"""Interactive chat session for image generation and refinement."""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
model: str = "gemini-2.5-flash-image",
|
|
41
|
+
output_dir: str = ".",
|
|
42
|
+
):
|
|
43
|
+
api_key = os.environ.get("GEMINI_API_KEY")
|
|
44
|
+
if not api_key:
|
|
45
|
+
raise EnvironmentError("GEMINI_API_KEY environment variable not set")
|
|
46
|
+
|
|
47
|
+
self.client = genai.Client(api_key=api_key)
|
|
48
|
+
self.model = model
|
|
49
|
+
self.output_dir = Path(output_dir)
|
|
50
|
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
51
|
+
|
|
52
|
+
self.chat = None
|
|
53
|
+
self.current_image = None
|
|
54
|
+
self.image_count = 0
|
|
55
|
+
|
|
56
|
+
self._init_chat()
|
|
57
|
+
|
|
58
|
+
def _init_chat(self):
|
|
59
|
+
"""Initialize or reset the chat session."""
|
|
60
|
+
config = types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"])
|
|
61
|
+
self.chat = self.client.chats.create(
|
|
62
|
+
model=self.model,
|
|
63
|
+
config=config,
|
|
64
|
+
)
|
|
65
|
+
self.current_image = None
|
|
66
|
+
|
|
67
|
+
def send_message(
|
|
68
|
+
self, message: str, image: Image.Image | None = None
|
|
69
|
+
) -> tuple[str | None, Image.Image | None]:
|
|
70
|
+
"""Send a message and optionally an image, return response text and image."""
|
|
71
|
+
contents = []
|
|
72
|
+
if message:
|
|
73
|
+
contents.append(message)
|
|
74
|
+
if image:
|
|
75
|
+
contents.append(image)
|
|
76
|
+
|
|
77
|
+
if not contents:
|
|
78
|
+
return None, None
|
|
79
|
+
|
|
80
|
+
response = self.chat.send_message(contents)
|
|
81
|
+
|
|
82
|
+
text_response = None
|
|
83
|
+
image_response = None
|
|
84
|
+
|
|
85
|
+
for part in response.parts:
|
|
86
|
+
if part.text is not None:
|
|
87
|
+
text_response = part.text
|
|
88
|
+
elif part.inline_data is not None:
|
|
89
|
+
image_response = part.as_image()
|
|
90
|
+
self.current_image = image_response
|
|
91
|
+
|
|
92
|
+
return text_response, image_response
|
|
93
|
+
|
|
94
|
+
def save_image(self, filename: str | None = None) -> str | None:
|
|
95
|
+
"""Save the current image to a file."""
|
|
96
|
+
if self.current_image is None:
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
if filename is None:
|
|
100
|
+
self.image_count += 1
|
|
101
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
102
|
+
filename = f"image_{timestamp}_{self.image_count}.png"
|
|
103
|
+
|
|
104
|
+
filepath = self.output_dir / filename
|
|
105
|
+
self.current_image.save(filepath)
|
|
106
|
+
return str(filepath)
|
|
107
|
+
|
|
108
|
+
def load_image(self, path: str) -> Image.Image:
|
|
109
|
+
"""Load an image from disk."""
|
|
110
|
+
img = Image.open(path)
|
|
111
|
+
self.current_image = img
|
|
112
|
+
return img
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def main():
|
|
116
|
+
parser = argparse.ArgumentParser(
|
|
117
|
+
description="Interactive multi-turn image generation",
|
|
118
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
119
|
+
epilog=__doc__,
|
|
120
|
+
)
|
|
121
|
+
parser.add_argument(
|
|
122
|
+
"--model",
|
|
123
|
+
"-m",
|
|
124
|
+
default="gemini-2.5-flash-image",
|
|
125
|
+
choices=["gemini-2.5-flash-image", "gemini-3-pro-image-preview"],
|
|
126
|
+
help="Model to use",
|
|
127
|
+
)
|
|
128
|
+
parser.add_argument(
|
|
129
|
+
"--output-dir", "-o", default=".", help="Directory to save images"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
args = parser.parse_args()
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
chat = ImageChat(model=args.model, output_dir=args.output_dir)
|
|
136
|
+
except Exception as e:
|
|
137
|
+
print(f"Error initializing: {e}", file=sys.stderr)
|
|
138
|
+
sys.exit(1)
|
|
139
|
+
|
|
140
|
+
print(f"Gemini Image Chat ({args.model})")
|
|
141
|
+
print("Commands: /save [name], /load <path>, /clear, /quit")
|
|
142
|
+
print("-" * 50)
|
|
143
|
+
|
|
144
|
+
while True:
|
|
145
|
+
try:
|
|
146
|
+
user_input = input("\nYou: ").strip()
|
|
147
|
+
except (EOFError, KeyboardInterrupt):
|
|
148
|
+
print("\nGoodbye!")
|
|
149
|
+
break
|
|
150
|
+
|
|
151
|
+
if not user_input:
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
# Handle commands
|
|
155
|
+
if user_input.startswith("/"):
|
|
156
|
+
parts = user_input.split(maxsplit=1)
|
|
157
|
+
cmd = parts[0].lower()
|
|
158
|
+
arg = parts[1] if len(parts) > 1 else None
|
|
159
|
+
|
|
160
|
+
if cmd == "/quit":
|
|
161
|
+
print("Goodbye!")
|
|
162
|
+
break
|
|
163
|
+
|
|
164
|
+
elif cmd == "/clear":
|
|
165
|
+
chat._init_chat()
|
|
166
|
+
print("Conversation cleared.")
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
elif cmd == "/save":
|
|
170
|
+
path = chat.save_image(arg)
|
|
171
|
+
if path:
|
|
172
|
+
print(f"Image saved to: {path}")
|
|
173
|
+
else:
|
|
174
|
+
print("No image to save.")
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
elif cmd == "/load":
|
|
178
|
+
if not arg:
|
|
179
|
+
print("Usage: /load <path>")
|
|
180
|
+
continue
|
|
181
|
+
try:
|
|
182
|
+
chat.load_image(arg)
|
|
183
|
+
print(f"Loaded: {arg}")
|
|
184
|
+
print("You can now describe edits to make.")
|
|
185
|
+
except Exception as e:
|
|
186
|
+
print(f"Error loading image: {e}")
|
|
187
|
+
continue
|
|
188
|
+
|
|
189
|
+
else:
|
|
190
|
+
print(f"Unknown command: {cmd}")
|
|
191
|
+
continue
|
|
192
|
+
|
|
193
|
+
# Send message to model
|
|
194
|
+
try:
|
|
195
|
+
# If we have a loaded image and this is first message, include it
|
|
196
|
+
image_to_send = None
|
|
197
|
+
if chat.current_image and not chat.chat.history:
|
|
198
|
+
image_to_send = chat.current_image
|
|
199
|
+
|
|
200
|
+
text, image = chat.send_message(user_input, image_to_send)
|
|
201
|
+
|
|
202
|
+
if text:
|
|
203
|
+
print(f"\nGemini: {text}")
|
|
204
|
+
|
|
205
|
+
if image:
|
|
206
|
+
# Auto-save
|
|
207
|
+
path = chat.save_image()
|
|
208
|
+
print(f"\n[Image generated: {path}]")
|
|
209
|
+
|
|
210
|
+
except Exception as e:
|
|
211
|
+
print(f"\nError: {e}")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if __name__ == "__main__":
|
|
215
|
+
main()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-history-analyzer
|
|
3
|
+
description: "Use this agent when you need to understand the historical context and evolution of code changes, trace the origins of specific code patterns, identify key contributors and their expertise areas, or analyze patterns in commit history. This agent excels at archaeological analysis of git repositories to provide insights about code evolution and development patterns. <example>Context: The user wants to understand the history and evolution of recently modified files.\\nuser: \"I've just refactored the authentication module. Can you analyze the historical context?\"\\nassistant: \"I'll use the git-history-analyzer agent to examine the evolution of the authentication module files.\"\\n<commentary>Since the user wants historical context about code changes, use the git-history-analyzer agent to trace file evolution, identify contributors, and extract patterns from the git history.</commentary></example> <example>Context: The user needs to understand why certain code patterns exist.\\nuser: \"Why does this payment processing code have so many try-catch blocks?\"\\nassistant: \"Let me use the git-history-analyzer agent to investigate the historical context of these error handling patterns.\"\\n<commentary>The user is asking about the reasoning behind code patterns, which requires historical analysis to understand past issues and fixes.</commentary></example>"
|
|
4
|
+
model: inherit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Note: The current year is 2025.** Use this when interpreting commit dates and recent changes.
|
|
8
|
+
|
|
9
|
+
You are a Git History Analyzer, an expert in archaeological analysis of code repositories. Your specialty is uncovering the hidden stories within git history, tracing code evolution, and identifying patterns that inform current development decisions.
|
|
10
|
+
|
|
11
|
+
Your core responsibilities:
|
|
12
|
+
|
|
13
|
+
1. **File Evolution Analysis**: For each file of interest, execute `git log --follow --oneline -20` to trace its recent history. Identify major refactorings, renames, and significant changes.
|
|
14
|
+
|
|
15
|
+
2. **Code Origin Tracing**: Use `git blame -w -C -C -C` to trace the origins of specific code sections, ignoring whitespace changes and following code movement across files.
|
|
16
|
+
|
|
17
|
+
3. **Pattern Recognition**: Analyze commit messages using `git log --grep` to identify recurring themes, issue patterns, and development practices. Look for keywords like 'fix', 'bug', 'refactor', 'performance', etc.
|
|
18
|
+
|
|
19
|
+
4. **Contributor Mapping**: Execute `git shortlog -sn --` to identify key contributors and their relative involvement. Cross-reference with specific file changes to map expertise domains.
|
|
20
|
+
|
|
21
|
+
5. **Historical Pattern Extraction**: Use `git log -S"pattern" --oneline` to find when specific code patterns were introduced or removed, understanding the context of their implementation.
|
|
22
|
+
|
|
23
|
+
Your analysis methodology:
|
|
24
|
+
- Start with a broad view of file history before diving into specifics
|
|
25
|
+
- Look for patterns in both code changes and commit messages
|
|
26
|
+
- Identify turning points or significant refactorings in the codebase
|
|
27
|
+
- Connect contributors to their areas of expertise based on commit patterns
|
|
28
|
+
- Extract lessons from past issues and their resolutions
|
|
29
|
+
|
|
30
|
+
Deliver your findings as:
|
|
31
|
+
- **Timeline of File Evolution**: Chronological summary of major changes with dates and purposes
|
|
32
|
+
- **Key Contributors and Domains**: List of primary contributors with their apparent areas of expertise
|
|
33
|
+
- **Historical Issues and Fixes**: Patterns of problems encountered and how they were resolved
|
|
34
|
+
- **Pattern of Changes**: Recurring themes in development, refactoring cycles, and architectural evolution
|
|
35
|
+
|
|
36
|
+
When analyzing, consider:
|
|
37
|
+
- The context of changes (feature additions vs bug fixes vs refactoring)
|
|
38
|
+
- The frequency and clustering of changes (rapid iteration vs stable periods)
|
|
39
|
+
- The relationship between different files changed together
|
|
40
|
+
- The evolution of coding patterns and practices over time
|
|
41
|
+
|
|
42
|
+
Your insights should help developers understand not just what the code does, but why it evolved to its current state, informing better decisions for future changes.
|