@polymorphism-tech/morph-spec 8.33.0 → 8.34.2
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/CLAUDE.md +3 -0
- package/README.md +2 -2
- package/bin/morph-spec.js +25 -1
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -2
- package/framework/MORPH.md +4 -5
- package/framework/agents.json +1 -0
- package/framework/docs/CLI.md +5 -2
- package/framework/hooks/README.md +11 -1
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
- package/framework/hooks/claude-code/core/chain.js +27 -7
- package/framework/hooks/claude-code/core/worktree-context.js +83 -14
- package/framework/hooks/claude-code/core/worktree-create.js +206 -0
- package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
- package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
- package/framework/hooks/git/pre-commit/agents.sh +25 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
- package/framework/hooks/git/pre-commit/specs.sh +50 -50
- package/framework/hooks/git/pre-push/run-tests.sh +44 -44
- package/framework/hooks/shared/command-tokens.js +23 -0
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/git-paths.js +25 -0
- package/framework/hooks/shared/hook-response.js +17 -0
- package/framework/hooks/shared/morph-cli.js +134 -0
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/rules/infrastructure-standards.md +3 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +3 -3
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +3 -1
- package/framework/skills/core/morph-plan/SKILL.md +6 -3
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +30 -0
- package/framework/standards/ai-agents/agent-session.md +160 -160
- package/framework/standards/ai-agents/batching.md +193 -193
- package/framework/standards/ai-agents/context-providers.md +188 -188
- package/framework/standards/ai-agents/mcp-server.md +250 -250
- package/framework/standards/ai-agents/mcp-tools.md +197 -197
- package/framework/standards/ai-agents/middleware-patterns.md +207 -207
- package/framework/standards/ai-agents/modalities-image-gen.md +173 -173
- package/framework/standards/ai-agents/modalities-speech-to-text.md +171 -171
- package/framework/standards/ai-agents/modalities-text-to-speech.md +181 -181
- package/framework/standards/ai-agents/modalities-vision.md +201 -201
- package/framework/standards/ai-agents/multi-agent-patterns.md +155 -155
- package/framework/standards/ai-agents/production.md +231 -231
- package/framework/standards/ai-agents/prompts-in-db.md +214 -214
- package/framework/standards/ai-agents/providers/model-registry.md +158 -158
- package/framework/standards/ai-agents/service-tier-flex.md +135 -135
- package/framework/standards/ai-agents/structured-output.md +249 -249
- package/framework/standards/ai-agents/sweet-spot.md +109 -109
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +88 -0
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/REGISTRY.json +1 -1
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
- package/framework/templates/code/dotnet/database/migration.cs +83 -83
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/code/typescript/contracts.ts +167 -167
- package/framework/templates/docs/clarifications.md +253 -253
- package/framework/templates/docs/schema-analysis.md +119 -119
- package/framework/templates/docs/ui-components.md +52 -52
- package/framework/templates/docs/ui-design-system.md +76 -76
- package/framework/templates/docs/ui-flows.md +167 -167
- package/framework/templates/docs/ui-mockups.md +98 -98
- package/framework/templates/feature/decisions.md +122 -122
- package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +24 -14
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/README.md +56 -56
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/integrations/asaas-client.cs +387 -387
- package/framework/templates/integrations/asaas-webhook.cs +351 -351
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
- package/framework/templates/project/validate.js +120 -120
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/dashboard/dashboard.js +53 -53
- package/src/commands/e2e/e2e.js +77 -39
- package/src/commands/index.js +13 -13
- package/src/commands/project/checkpoint.js +209 -209
- package/src/commands/project/doctor.js +8 -6
- package/src/commands/project/env.js +95 -0
- package/src/commands/project/worktree.js +266 -52
- package/src/commands/state/delete.js +8 -0
- package/src/commands/state/finish.js +29 -34
- package/src/core/state/phase-state-machine.js +197 -197
- package/src/core/templates/template-renderer.js +477 -477
- package/src/dashboard/app/components/DetailPanel.jsx +11 -11
- package/src/dashboard/app/components/FlowGraph.jsx +17 -17
- package/src/dashboard/app/components/SearchFilter.jsx +22 -22
- package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/AgentMap.jsx +370 -370
- package/src/dashboard/app/pages/HookInspector.jsx +430 -418
- package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
- package/src/dashboard/app/pages/RulesMap.jsx +273 -273
- package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
- package/src/dashboard/app/pages/Standards.jsx +332 -332
- package/src/dashboard/app/styles/index.css +47 -47
- package/src/dashboard/index.html +12 -12
- package/src/dashboard/package.json +24 -24
- package/src/dashboard/scanner/hooks-scanner.js +5 -1
- package/src/dashboard/scanner/phases-scanner.js +15 -15
- package/src/dashboard/scanner/rubrics-scanner.js +12 -12
- package/src/dashboard/scanner/rules-scanner.js +37 -37
- package/src/dashboard/scanner/skills-scanner.js +43 -43
- package/src/dashboard/scanner/squads-scanner.js +13 -13
- package/src/dashboard/vite-plugin-morph-data.js +17 -17
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/detectors/index.js +217 -217
- package/src/lib/e2e/compose-env.js +6 -11
- package/src/lib/e2e/stack-teardown.js +115 -0
- package/src/lib/generators/architecture-scanner.js +2 -1
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/settings-generator.js +209 -209
- package/src/lib/graph/graphifyignore.js +2 -1
- package/src/lib/hooks/hook-executor.js +167 -167
- package/src/lib/installers/mcp-installer.js +719 -719
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/test-runner.js +21 -4
- package/src/lib/validators/checkpoint-persistence.js +39 -39
- package/src/lib/validators/css/css-validator.js +340 -340
- package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
- package/src/lib/validators/shared/issue-counter.js +14 -14
- package/src/lib/validators/verify-runner.js +7 -0
- package/src/lib/worktree/dirs.js +32 -0
- package/src/lib/worktree/env-allocator.js +45 -11
- package/src/lib/worktree/worktree-audit.js +40 -2
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/file-copier.js +18 -13
- package/src/utils/hooks-installer.js +46 -3
- package/src/utils/skills-installer.js +187 -187
- package/framework/templates/.idea/morph-templates.xml +0 -92
- package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
# Modalities — Image Generation (Text to Image)
|
|
2
|
-
|
|
3
|
-
> **Scope:** stacks=["dotnet"]
|
|
4
|
-
> **Layer:** 2 (on-keyword)
|
|
5
|
-
> **Keywords:** image generation, text to image, dall-e, gpt-image, mockup generation, image synthesis
|
|
6
|
-
> **Read by Claude in:** implement (quando o projeto precisa gerar imagens a partir de texto)
|
|
7
|
-
|
|
8
|
-
**Verified against:** MAF 1.0 GA + OpenAI .NET SDK 2.x. Last-verified: 2026-05-19.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Quando usar geração de imagem
|
|
13
|
-
|
|
14
|
-
Use quando o produto precisa criar imagens em runtime a partir de um prompt textual:
|
|
15
|
-
|
|
16
|
-
- **Mockups e protótipos visuais:** gerar capa de produto, banner de campanha, layout de tela
|
|
17
|
-
- **Conteúdo para social media:** imagens para posts geradas a partir de briefing do usuário
|
|
18
|
-
- **Visualizações:** diagramas, ilustrações ou thumbnails dinâmicos
|
|
19
|
-
|
|
20
|
-
**Nota importante:** geração de imagem é uma **chamada de serviço ao provider**, não um agente conversacional. Não crie um `AIAgent` para isso — use `ImageClient` diretamente via DI.
|
|
21
|
-
|
|
22
|
-
**Não use** quando um asset estático resolve o problema. Geração de imagem tem custo por chamada e latência de vários segundos. Se a imagem não muda por usuário/contexto, sirva de CDN.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## A API
|
|
27
|
-
|
|
28
|
-
O projeto resolve o `ImageClient` para o provider configurado. No OpenAI SDK (.NET 2.x), o caminho é:
|
|
29
|
-
|
|
30
|
-
```csharp
|
|
31
|
-
using OpenAI.Images;
|
|
32
|
-
|
|
33
|
-
ImageClient client = new("dall-e-3", apiKey);
|
|
34
|
-
GeneratedImage image = await client.GenerateImageAsync(prompt, options);
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
O projeto injeta `ImageClient` via DI (ver §Exemplo). A resolução pode ser feita via factory ou diretamente por configuração — não há um `GetImageClient("alias")` no `ModelRegistry` padrão; registre o `ImageClient` como serviço nomeado ou use uma factory simples que lê `model-registry.json`.
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Exemplo C# completo
|
|
42
|
-
|
|
43
|
-
```csharp
|
|
44
|
-
using OpenAI.Images;
|
|
45
|
-
using Microsoft.Extensions.Configuration;
|
|
46
|
-
|
|
47
|
-
public sealed class ImageGenerationService
|
|
48
|
-
{
|
|
49
|
-
private readonly ImageClient _client;
|
|
50
|
-
|
|
51
|
-
public ImageGenerationService(IConfiguration config)
|
|
52
|
-
{
|
|
53
|
-
// O projeto configura o modelo e a chave via config/model-registry.json ou appsettings
|
|
54
|
-
var model = config["ImageGen:Model"] ?? "dall-e-3";
|
|
55
|
-
var apiKey = config["OpenAI:ApiKey"]!;
|
|
56
|
-
_client = new ImageClient(model, apiKey);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/// <summary>
|
|
60
|
-
/// Gera uma imagem a partir de um prompt e retorna os bytes PNG.
|
|
61
|
-
/// Prefira armazenar os bytes; URLs retornadas pelo provider são efêmeras (expiram em ~1h).
|
|
62
|
-
/// </summary>
|
|
63
|
-
public async Task<BinaryData> GenerateImageBytesAsync(
|
|
64
|
-
string prompt,
|
|
65
|
-
GeneratedImageSize? size = null,
|
|
66
|
-
GeneratedImageQuality? quality = null,
|
|
67
|
-
CancellationToken ct = default)
|
|
68
|
-
{
|
|
69
|
-
var resolvedSize = size ?? GeneratedImageSize.W1024xH1024;
|
|
70
|
-
var resolvedQuality = quality ?? GeneratedImageQuality.Standard;
|
|
71
|
-
|
|
72
|
-
var options = new ImageGenerationOptions
|
|
73
|
-
{
|
|
74
|
-
Size = resolvedSize,
|
|
75
|
-
Quality = resolvedQuality,
|
|
76
|
-
ResponseFormat = GeneratedImageFormat.Bytes
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
GeneratedImage image = await _client.GenerateImageAsync(prompt, options, ct);
|
|
80
|
-
return image.ImageBytes;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/// <summary>
|
|
84
|
-
/// Gera uma imagem e retorna a URI. Use apenas quando precisar da URL diretamente
|
|
85
|
-
/// e souber que o downstream vai consumir a URL antes de ela expirar (~1h no OpenAI).
|
|
86
|
-
/// </summary>
|
|
87
|
-
public async Task<Uri> GenerateImageUriAsync(string prompt, CancellationToken ct = default)
|
|
88
|
-
{
|
|
89
|
-
var options = new ImageGenerationOptions
|
|
90
|
-
{
|
|
91
|
-
Size = GeneratedImageSize.W1024xH1024,
|
|
92
|
-
Quality = GeneratedImageQuality.Standard,
|
|
93
|
-
ResponseFormat = GeneratedImageFormat.Uri
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
GeneratedImage image = await _client.GenerateImageAsync(prompt, options, ct);
|
|
97
|
-
return image.ImageUri!;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**Registro DI:**
|
|
103
|
-
|
|
104
|
-
```csharp
|
|
105
|
-
// Program.cs
|
|
106
|
-
builder.Services.AddSingleton<ImageGenerationService>();
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**Consumo:**
|
|
110
|
-
|
|
111
|
-
```csharp
|
|
112
|
-
public class CampaignController(ImageGenerationService imageGen, IBlobStorage storage) : ControllerBase
|
|
113
|
-
{
|
|
114
|
-
[HttpPost("generate-banner")]
|
|
115
|
-
public async Task<IActionResult> GenerateBanner([FromBody] BannerRequest req)
|
|
116
|
-
{
|
|
117
|
-
BinaryData bytes = await imageGen.GenerateImageBytesAsync(
|
|
118
|
-
prompt: req.Briefing,
|
|
119
|
-
size: GeneratedImageSize.W1792xH1024,
|
|
120
|
-
quality: GeneratedImageQuality.High);
|
|
121
|
-
|
|
122
|
-
// Persista no storage do projeto antes de retornar
|
|
123
|
-
string storedUrl = await storage.UploadAsync(bytes, "image/png");
|
|
124
|
-
return Ok(new { url = storedUrl });
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Parâmetros
|
|
132
|
-
|
|
133
|
-
> Valores verificados contra OpenAI .NET SDK 2.x / DALL-E 3 (2026-05-19). Outros providers podem variar.
|
|
134
|
-
|
|
135
|
-
| Parâmetro | Tipo | Opções | Nota |
|
|
136
|
-
|-----------|------|--------|------|
|
|
137
|
-
| `Size` | `GeneratedImageSize` | `W1024xH1024`, `W1792xH1024`, `W1024xH1792` | DALL-E 3 suporta os três; DALL-E 2 tem conjunto diferente |
|
|
138
|
-
| `Quality` | `GeneratedImageQuality` | `Standard`, `High` | `High` = mais detalhe, mais custo e latência |
|
|
139
|
-
| `Style` | `GeneratedImageStyle` | `Natural`, `Vivid` | `Vivid` = mais saturado/dramático; `Natural` = realista |
|
|
140
|
-
| `ResponseFormat` | `GeneratedImageFormat` | `Bytes`, `Uri` | Prefira `Bytes` — URLs expiram em ~1h |
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
## Anti-patterns
|
|
145
|
-
|
|
146
|
-
| Anti-pattern | Por quê é errado | Jeito certo |
|
|
147
|
-
|--------------|-----------------|-------------|
|
|
148
|
-
| Gerar imagem quando asset estático resolve | Custo por chamada + latência sem ganho | Sirva de CDN; só gere quando o conteúdo é dinâmico por usuário/contexto |
|
|
149
|
-
| Não moderar o prompt antes de enviar | Prompts maliciosos podem gerar conteúdo impróprio; o provider rejeitará e você terá erro 400 sem log útil | Aplique validação/moderação de prompt antes de chamar `GenerateImageAsync`; veja `ai-agents-middleware-patterns` |
|
|
150
|
-
| Armazenar a URI retornada sem baixar | URLs do provider são efêmeras (~1h no OpenAI); links quebram depois | Use `ResponseFormat = Bytes`, persista no storage do projeto e sirva sua própria URL |
|
|
151
|
-
| Criar `AIAgent` para geração de imagem | `ImageClient` não é `IChatClient`; não há sentido em wrappear como agente | Injete `ImageGenerationService` diretamente — é um serviço, não um agente |
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## Checklist (verifiable by morph-eval)
|
|
156
|
-
|
|
157
|
-
- [ ] `ImageClient` injetado via DI — não instanciado inline nos controllers
|
|
158
|
-
- [ ] `ResponseFormat = GeneratedImageFormat.Bytes` na maioria dos casos; URLs armazenadas no storage do projeto
|
|
159
|
-
- [ ] Prompt passa por validação/moderação antes de ir ao provider
|
|
160
|
-
- [ ] Não usa `AIAgent`/`AsAIAgent` para geração de imagem — é um `ImageGenerationService`
|
|
161
|
-
- [ ] Model e API key vêm de config, não hardcoded
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## References
|
|
166
|
-
|
|
167
|
-
- `ai-agents-setup` — packages, DI, e providers disponíveis
|
|
168
|
-
- `ai-agents-providers-model-registry` — padrão de alias; adapte para resolver `ImageClient` por provider
|
|
169
|
-
- OpenAI .NET SDK — `ImageClient`: https://github.com/openai/openai-dotnet
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/modalities-image-gen.md v1.0 (2026-05-19)*
|
|
1
|
+
# Modalities — Image Generation (Text to Image)
|
|
2
|
+
|
|
3
|
+
> **Scope:** stacks=["dotnet"]
|
|
4
|
+
> **Layer:** 2 (on-keyword)
|
|
5
|
+
> **Keywords:** image generation, text to image, dall-e, gpt-image, mockup generation, image synthesis
|
|
6
|
+
> **Read by Claude in:** implement (quando o projeto precisa gerar imagens a partir de texto)
|
|
7
|
+
|
|
8
|
+
**Verified against:** MAF 1.0 GA + OpenAI .NET SDK 2.x. Last-verified: 2026-05-19.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Quando usar geração de imagem
|
|
13
|
+
|
|
14
|
+
Use quando o produto precisa criar imagens em runtime a partir de um prompt textual:
|
|
15
|
+
|
|
16
|
+
- **Mockups e protótipos visuais:** gerar capa de produto, banner de campanha, layout de tela
|
|
17
|
+
- **Conteúdo para social media:** imagens para posts geradas a partir de briefing do usuário
|
|
18
|
+
- **Visualizações:** diagramas, ilustrações ou thumbnails dinâmicos
|
|
19
|
+
|
|
20
|
+
**Nota importante:** geração de imagem é uma **chamada de serviço ao provider**, não um agente conversacional. Não crie um `AIAgent` para isso — use `ImageClient` diretamente via DI.
|
|
21
|
+
|
|
22
|
+
**Não use** quando um asset estático resolve o problema. Geração de imagem tem custo por chamada e latência de vários segundos. Se a imagem não muda por usuário/contexto, sirva de CDN.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## A API
|
|
27
|
+
|
|
28
|
+
O projeto resolve o `ImageClient` para o provider configurado. No OpenAI SDK (.NET 2.x), o caminho é:
|
|
29
|
+
|
|
30
|
+
```csharp
|
|
31
|
+
using OpenAI.Images;
|
|
32
|
+
|
|
33
|
+
ImageClient client = new("dall-e-3", apiKey);
|
|
34
|
+
GeneratedImage image = await client.GenerateImageAsync(prompt, options);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
O projeto injeta `ImageClient` via DI (ver §Exemplo). A resolução pode ser feita via factory ou diretamente por configuração — não há um `GetImageClient("alias")` no `ModelRegistry` padrão; registre o `ImageClient` como serviço nomeado ou use uma factory simples que lê `model-registry.json`.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Exemplo C# completo
|
|
42
|
+
|
|
43
|
+
```csharp
|
|
44
|
+
using OpenAI.Images;
|
|
45
|
+
using Microsoft.Extensions.Configuration;
|
|
46
|
+
|
|
47
|
+
public sealed class ImageGenerationService
|
|
48
|
+
{
|
|
49
|
+
private readonly ImageClient _client;
|
|
50
|
+
|
|
51
|
+
public ImageGenerationService(IConfiguration config)
|
|
52
|
+
{
|
|
53
|
+
// O projeto configura o modelo e a chave via config/model-registry.json ou appsettings
|
|
54
|
+
var model = config["ImageGen:Model"] ?? "dall-e-3";
|
|
55
|
+
var apiKey = config["OpenAI:ApiKey"]!;
|
|
56
|
+
_client = new ImageClient(model, apiKey);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// <summary>
|
|
60
|
+
/// Gera uma imagem a partir de um prompt e retorna os bytes PNG.
|
|
61
|
+
/// Prefira armazenar os bytes; URLs retornadas pelo provider são efêmeras (expiram em ~1h).
|
|
62
|
+
/// </summary>
|
|
63
|
+
public async Task<BinaryData> GenerateImageBytesAsync(
|
|
64
|
+
string prompt,
|
|
65
|
+
GeneratedImageSize? size = null,
|
|
66
|
+
GeneratedImageQuality? quality = null,
|
|
67
|
+
CancellationToken ct = default)
|
|
68
|
+
{
|
|
69
|
+
var resolvedSize = size ?? GeneratedImageSize.W1024xH1024;
|
|
70
|
+
var resolvedQuality = quality ?? GeneratedImageQuality.Standard;
|
|
71
|
+
|
|
72
|
+
var options = new ImageGenerationOptions
|
|
73
|
+
{
|
|
74
|
+
Size = resolvedSize,
|
|
75
|
+
Quality = resolvedQuality,
|
|
76
|
+
ResponseFormat = GeneratedImageFormat.Bytes
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
GeneratedImage image = await _client.GenerateImageAsync(prompt, options, ct);
|
|
80
|
+
return image.ImageBytes;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// <summary>
|
|
84
|
+
/// Gera uma imagem e retorna a URI. Use apenas quando precisar da URL diretamente
|
|
85
|
+
/// e souber que o downstream vai consumir a URL antes de ela expirar (~1h no OpenAI).
|
|
86
|
+
/// </summary>
|
|
87
|
+
public async Task<Uri> GenerateImageUriAsync(string prompt, CancellationToken ct = default)
|
|
88
|
+
{
|
|
89
|
+
var options = new ImageGenerationOptions
|
|
90
|
+
{
|
|
91
|
+
Size = GeneratedImageSize.W1024xH1024,
|
|
92
|
+
Quality = GeneratedImageQuality.Standard,
|
|
93
|
+
ResponseFormat = GeneratedImageFormat.Uri
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
GeneratedImage image = await _client.GenerateImageAsync(prompt, options, ct);
|
|
97
|
+
return image.ImageUri!;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Registro DI:**
|
|
103
|
+
|
|
104
|
+
```csharp
|
|
105
|
+
// Program.cs
|
|
106
|
+
builder.Services.AddSingleton<ImageGenerationService>();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Consumo:**
|
|
110
|
+
|
|
111
|
+
```csharp
|
|
112
|
+
public class CampaignController(ImageGenerationService imageGen, IBlobStorage storage) : ControllerBase
|
|
113
|
+
{
|
|
114
|
+
[HttpPost("generate-banner")]
|
|
115
|
+
public async Task<IActionResult> GenerateBanner([FromBody] BannerRequest req)
|
|
116
|
+
{
|
|
117
|
+
BinaryData bytes = await imageGen.GenerateImageBytesAsync(
|
|
118
|
+
prompt: req.Briefing,
|
|
119
|
+
size: GeneratedImageSize.W1792xH1024,
|
|
120
|
+
quality: GeneratedImageQuality.High);
|
|
121
|
+
|
|
122
|
+
// Persista no storage do projeto antes de retornar
|
|
123
|
+
string storedUrl = await storage.UploadAsync(bytes, "image/png");
|
|
124
|
+
return Ok(new { url = storedUrl });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Parâmetros
|
|
132
|
+
|
|
133
|
+
> Valores verificados contra OpenAI .NET SDK 2.x / DALL-E 3 (2026-05-19). Outros providers podem variar.
|
|
134
|
+
|
|
135
|
+
| Parâmetro | Tipo | Opções | Nota |
|
|
136
|
+
|-----------|------|--------|------|
|
|
137
|
+
| `Size` | `GeneratedImageSize` | `W1024xH1024`, `W1792xH1024`, `W1024xH1792` | DALL-E 3 suporta os três; DALL-E 2 tem conjunto diferente |
|
|
138
|
+
| `Quality` | `GeneratedImageQuality` | `Standard`, `High` | `High` = mais detalhe, mais custo e latência |
|
|
139
|
+
| `Style` | `GeneratedImageStyle` | `Natural`, `Vivid` | `Vivid` = mais saturado/dramático; `Natural` = realista |
|
|
140
|
+
| `ResponseFormat` | `GeneratedImageFormat` | `Bytes`, `Uri` | Prefira `Bytes` — URLs expiram em ~1h |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Anti-patterns
|
|
145
|
+
|
|
146
|
+
| Anti-pattern | Por quê é errado | Jeito certo |
|
|
147
|
+
|--------------|-----------------|-------------|
|
|
148
|
+
| Gerar imagem quando asset estático resolve | Custo por chamada + latência sem ganho | Sirva de CDN; só gere quando o conteúdo é dinâmico por usuário/contexto |
|
|
149
|
+
| Não moderar o prompt antes de enviar | Prompts maliciosos podem gerar conteúdo impróprio; o provider rejeitará e você terá erro 400 sem log útil | Aplique validação/moderação de prompt antes de chamar `GenerateImageAsync`; veja `ai-agents-middleware-patterns` |
|
|
150
|
+
| Armazenar a URI retornada sem baixar | URLs do provider são efêmeras (~1h no OpenAI); links quebram depois | Use `ResponseFormat = Bytes`, persista no storage do projeto e sirva sua própria URL |
|
|
151
|
+
| Criar `AIAgent` para geração de imagem | `ImageClient` não é `IChatClient`; não há sentido em wrappear como agente | Injete `ImageGenerationService` diretamente — é um serviço, não um agente |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Checklist (verifiable by morph-eval)
|
|
156
|
+
|
|
157
|
+
- [ ] `ImageClient` injetado via DI — não instanciado inline nos controllers
|
|
158
|
+
- [ ] `ResponseFormat = GeneratedImageFormat.Bytes` na maioria dos casos; URLs armazenadas no storage do projeto
|
|
159
|
+
- [ ] Prompt passa por validação/moderação antes de ir ao provider
|
|
160
|
+
- [ ] Não usa `AIAgent`/`AsAIAgent` para geração de imagem — é um `ImageGenerationService`
|
|
161
|
+
- [ ] Model e API key vêm de config, não hardcoded
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## References
|
|
166
|
+
|
|
167
|
+
- `ai-agents-setup` — packages, DI, e providers disponíveis
|
|
168
|
+
- `ai-agents-providers-model-registry` — padrão de alias; adapte para resolver `ImageClient` por provider
|
|
169
|
+
- OpenAI .NET SDK — `ImageClient`: https://github.com/openai/openai-dotnet
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/modalities-image-gen.md v1.0 (2026-05-19)*
|