Skip to content

Commit b6adf96

Browse files
committed
Fix image generation env vars and add post-deploy improvements
- Fix AZURE_DALLE_MODEL -> AZURE_OPENAI_IMAGE_MODEL in Bicep - Add AZURE_OPENAI_GPT_IMAGE_ENDPOINT to App Service and Container Instance configs - Update post_deploy.py with requirements file - Add backend API module - Update README and architecture diagram
1 parent cec45a6 commit b6adf96

11 files changed

Lines changed: 931 additions & 484 deletions

File tree

README.md

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Content generation solution accelerator
22

3-
This solution accelerator is an internal chatbot that can interpret and
4-
understand context and direction from a creative brief to create multi-modal text and image content for a marketing ad campaign.​
3+
This solution accelerator is an internal chatbot that interprets and understands context and direction from creative briefs to create multi-modal text and image content for marketing ad campaigns. Built on the Microsoft Agent Framework with HandoffBuilder orchestration, it uses specialized AI agents to parse briefs, research product data, generate content, and validate brand compliance.
54
<br/>
65

76
<div align="center">
@@ -18,12 +17,12 @@ understand context and direction from a creative brief to create multi-modal tex
1817
Solution overview
1918
</h2>
2019

21-
It leverages Azure OpenAI Service and Azure AI Search, to identify relevant documents, summarize unstructured information, and generate document templates.
20+
This solution leverages Azure OpenAI Service (GPT and DALL-E 3), Azure Cosmos DB, and Azure Blob Storage to interpret creative briefs, retrieve product information, generate marketing content, and validate brand compliance.
2221

23-
The sample data is sourced from generic AI-generated promissory notes. The documents are intended for use as sample data only.
22+
The sample data includes synthetic product catalogs and brand guidelines. The data is intended for use as sample data only.
2423

2524
### Solution architecture
26-
|TBD|
25+
|![image](./docs/images/readme/solution_architecture.png)|
2726
|---|
2827

2928

@@ -33,7 +32,9 @@ The sample data is sourced from generic AI-generated promissory notes. The docum
3332

3433
[Azure OpenAI Service](https://learn.microsoft.com/en-us/azure/ai-services/openai/)
3534

36-
[Azure AI Search](https://learn.microsoft.com/en-us/azure/search/)
35+
[Microsoft Agent Framework](https://github.com/microsoft/agent-framework)
36+
37+
[Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/)
3738

3839
[Azure AI Foundry](https://learn.microsoft.com/en-us/azure/ai-studio/)
3940

@@ -44,8 +45,17 @@ The sample data is sourced from generic AI-generated promissory notes. The docum
4445
<details open>
4546
<summary>Click to learn more about the key features this solution enables</summary>
4647

47-
- **TBD** <br/>
48-
Azure...​
48+
- **Creative Brief Interpretation** <br/>
49+
Parse free-text creative briefs into structured fields (overview, objectives, target audience, key message, tone/style, deliverable, timelines, visual guidelines, CTA).
50+
51+
- **Multimodal Content Generation** <br/>
52+
Generate marketing copy and images using GPT models and DALL-E 3 grounded in enterprise product data.
53+
54+
- **Brand Compliance Validation** <br/>
55+
Validate all generated content against brand guidelines with severity-categorized feedback (Error, Warning, Info).
56+
57+
- **Specialized Agent Orchestration** <br/>
58+
Uses Microsoft Agent Framework with HandoffBuilder to coordinate Triage, Planning, Research, Text Content, Image Content, and Compliance agents.
4959

5060
</details>
5161

@@ -59,7 +69,7 @@ Follow the quick deploy steps on the deployment guide to deploy this solution to
5969

6070
> **Note:** This solution accelerator requires **Azure Developer CLI (azd) version 1.18.0 or higher**. Please ensure you have the latest version installed before proceeding with deployment. [Download azd here](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/install-azd).
6171
62-
[Click here to launch the deployment guide](./docs/DeploymentGuide.md)
72+
[Click here to launch the deployment guide](./content-gen/docs/DEPLOYMENT.md)
6373
<br/><br/>
6474

6575
| [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/microsoft/document-generation-solution-accelerator) | [![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/document-generation-solution-accelerator) | [![Open in Visual Studio Code Web](https://img.shields.io/static/v1?style=for-the-badge&label=Visual%20Studio%20Code%20(Web)&message=Open&color=blue&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/azure/?vscode-azure-exp=foundry&agentPayload=eyJiYXNlVXJsIjogImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9taWNyb3NvZnQvZG9jdW1lbnQtZ2VuZXJhdGlvbi1zb2x1dGlvbi1hY2NlbGVyYXRvci9yZWZzL2hlYWRzL21haW4vaW5mcmEvdnNjb2RlX3dlYiIsICJpbmRleFVybCI6ICIvaW5kZXguanNvbiIsICJ2YXJpYWJsZXMiOiB7ImFnZW50SWQiOiAiIiwgImNvbm5lY3Rpb25TdHJpbmciOiAiIiwgInRocmVhZElkIjogIiIsICJ1c2VyTWVzc2FnZSI6ICIiLCAicGxheWdyb3VuZE5hbWUiOiAiIiwgImxvY2F0aW9uIjogIiIsICJzdWJzY3JpcHRpb25JZCI6ICIiLCAicmVzb3VyY2VJZCI6ICIiLCAicHJvamVjdFJlc291cmNlSWQiOiAiIiwgImVuZHBvaW50IjogIiJ9LCAiY29kZVJvdXRlIjogWyJhaS1wcm9qZWN0cy1zZGsiLCAicHl0aG9uIiwgImRlZmF1bHQtYXp1cmUtYXV0aCIsICJlbmRwb2ludCJdfQ==) |
@@ -91,14 +101,14 @@ _Note: This is not meant to outline all costs as selected SKUs, scaled use, cust
91101
| Product | Description | Cost |
92102
|---|---|---|
93103
| [Azure AI Foundry](https://learn.microsoft.com/en-us/azure/ai-foundry/) | Free tier. Build generative AI applications on an enterprise-grade platform. | [Pricing](https://azure.microsoft.com/pricing/details/ai-studio/) |
94-
| [Azure AI Search](https://learn.microsoft.com/en-us/azure/search/) | Standard tier, S1. Pricing is based on the number of documents and operations. Information retrieval at scale for vector and text content in traditional or generative search scenarios. | [Pricing](https://azure.microsoft.com/pricing/details/search/) |
95-
| [Azure Storage Account](https://learn.microsoft.com/en-us/azure/storage/blobs/) | Standard tier, LRS. Pricing is based on storage and operations. Blob storage in the clopud, optimized for storing massive amounts of unstructured data. | [Pricing](https://azure.microsoft.com/pricing/details/storage/blobs/) |
104+
| [Azure Storage Account](https://learn.microsoft.com/en-us/azure/storage/blobs/) | Standard tier, LRS. Pricing is based on storage and operations. Blob storage for product images and generated content. | [Pricing](https://azure.microsoft.com/pricing/details/storage/blobs/) |
96105
| [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/) | Standard tier. Pricing is based on the number of operations. Maintain keys that access and encrypt your cloud resources, apps, and solutions. | [Pricing](https://azure.microsoft.com/pricing/details/key-vault/) |
97-
| [Azure AI Services](https://learn.microsoft.com/en-us/azure/ai-services/) | S0 tier, defaults to gpt-4.1 and text-embedding-ada-002 models. Pricing is based on token count. | [Pricing](https://azure.microsoft.com/pricing/details/cognitive-services/) |
98-
| [Azure Container App](https://learn.microsoft.com/en-us/azure/container-apps/) | Consumption tier with 0.5 CPU, 1GiB memory/storage. Pricing is based on resource allocation, and each month allows for a certain amount of free usage. Allows you to run containerized applications without worrying about orchestration or infrastructure. | [Pricing](https://azure.microsoft.com/pricing/details/container-apps/) |
106+
| [Azure AI Services](https://learn.microsoft.com/en-us/azure/ai-services/) | S0 tier, defaults to gpt-5.1 (GPT) and gpt-image-1 (DALL-E 3) models. Pricing is based on token count. | [Pricing](https://azure.microsoft.com/pricing/details/cognitive-services/) |
107+
| [Azure Container Instance](https://learn.microsoft.com/en-us/azure/container-instances/) | Backend API hosting with private VNet integration. Pricing is based on resource allocation. | [Pricing](https://azure.microsoft.com/pricing/details/container-instances/) |
108+
| [Azure App Service](https://learn.microsoft.com/en-us/azure/app-service/) | B1 tier. Frontend hosting with Node.js proxy server. | [Pricing](https://azure.microsoft.com/pricing/details/app-service/) |
99109
| [Azure Container Registry](https://learn.microsoft.com/en-us/azure/container-registry/) | Basic tier. Build, store, and manage container images and artifacts in a private registry for all types of container deployments | [Pricing](https://azure.microsoft.com/pricing/details/container-registry/) |
100110
| [Log analytics](https://learn.microsoft.com/en-us/azure/azure-monitor/) | Pay-as-you-go tier. Costs based on data ingested. Collect and analyze on telemetry data generated by Azure. | [Pricing](https://azure.microsoft.com/pricing/details/monitor/) |
101-
| [Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/) | Fully managed, distributed NoSQL, relational, and vector database for modern app development. | [Pricing](https://azure.microsoft.com/en-us/pricing/details/cosmos-db/autoscale-provisioned/) |
111+
| [Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/) | Serverless tier. Product catalog and conversation history storage. | [Pricing](https://azure.microsoft.com/en-us/pricing/details/cosmos-db/autoscale-provisioned/) |
102112

103113

104114

@@ -108,7 +118,7 @@ _Note: This is not meant to outline all costs as selected SKUs, scaled use, cust
108118
either by deleting the resource group in the Portal or running `azd down`.
109119

110120
<br /><br />
111-
<h2><img src="./docs/images/readme/business-scenario.png" width="48" />
121+
<h2><img src="./docs/images/readme/business_scenario.png" width="48" />
112122
Business Scenario
113123
</h2>
114124

@@ -118,7 +128,7 @@ Business Scenario
118128

119129
<br/>
120130

121-
Put your data to work by reducing blank page anxiety, speeding up document drafting, improving draft document quality, and reference information quickly - keeping experts in their expertise. Draft document templates for your organization including Invoices, End-user Contracts, Purchase Orders, Investment Proposals, and Grant Submissions.
131+
Accelerate your marketing content creation by leveraging AI to interpret creative briefs and generate on-brand, multimodal content. The solution helps marketing teams reduce time-to-market for campaigns by automating the creation of compliant marketing copy and images grounded in product data.
122132

123133
⚠️ The sample data used in this repository is synthetic and generated using Azure OpenAI Service. The data is intended for use as sample data only.
124134

@@ -127,20 +137,20 @@ Put your data to work by reducing blank page anxiety, speeding up document draft
127137
<details>
128138
<summary>Click to learn more about what value this solution provides</summary>
129139

130-
- **Draft templates quickly** <br/>
131-
Put your data to work to create any kind of document that is supported by a large data library.
140+
- **Interpret creative briefs** <br/>
141+
Parse unstructured creative briefs into structured fields automatically, ensuring all campaign requirements are captured.
132142

133-
- **Share** <br/>
134-
Share with co-authors, contributors and approvers quickly.
143+
- **Generate multimodal content** <br/>
144+
Create marketing copy and images that align with your brand voice and product catalog using GPT and DALL-E 3.
135145

136-
- **Contextualize information** <br/>
137-
Provide context using natural language. Primary and secondary queries allow for access to supplemental detail – reducing cognitive load, increasing efficiency, and enabling focus on higher value work.
146+
- **Ensure brand compliance** <br/>
147+
Validate all generated content against brand guidelines with severity-categorized feedback before publication.
138148

139-
- **Gain confidence in responses** <br/>
140-
Trust responses to queries by customizing how data is referenced and returned to users, reducing the risk of hallucinated responses.<br /><br />Access reference documents in the same chat window to get more detail and confirm accuracy.
149+
- **Ground in enterprise data** <br/>
150+
Leverage product information, images, and brand guidelines stored in Azure to ensure accurate, relevant content.
141151

142-
- **Secure data and responsible AI for innovation** <br/>
143-
Improve data security to minimize breaches, fostering a culture of responsible AI adoption, maximize innovation opportunities, and sustain competitive edge.
152+
- **Secure data and responsible AI** <br/>
153+
Maintain data security with managed identities and private networking while fostering responsible AI adoption.
144154

145155
146156
</details>
@@ -153,16 +163,16 @@ Supporting documentation
153163

154164
### Security guidelines
155165

156-
This template uses Azure Key Vault to store all connections to communicate between resources.
166+
This template uses [Managed Identity](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview) for authentication between Azure services.
157167

158-
This template also uses [Managed Identity](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview) for local development and deployment.
168+
The backend runs in Azure Container Instance within a private VNet subnet, accessible only through the App Service frontend proxy. Private networking can be enabled via the `enablePrivateNetworking` parameter.
159169

160170
To ensure continued best practices in your own repository, we recommend that anyone creating solutions based on our templates ensure that the [Github secret scanning](https://docs.github.com/code-security/secret-scanning/about-secret-scanning) setting is enabled.
161171

162172
You may want to consider additional security measures, such as:
163173

164174
* Enabling Microsoft Defender for Cloud to [secure your Azure resources](https://learn.microsoft.com/azure/defender-for-cloud).
165-
* Protecting the Azure Container Apps instance with a [firewall](https://learn.microsoft.com/azure/container-apps/waf-app-gateway) and/or [Virtual Network](https://learn.microsoft.com/azure/container-apps/networking?tabs=workload-profiles-env%2Cazure-cli).
175+
* Protecting the Azure App Service with [authentication](https://learn.microsoft.com/azure/app-service/overview-authentication-authorization) and/or [Virtual Network integration](https://learn.microsoft.com/azure/app-service/overview-vnet-integration).
166176

167177
<br/>
168178

@@ -186,7 +196,7 @@ Have questions, find a bug, or want to request a feature? [Submit a new issue](h
186196
<br/>
187197

188198
## Responsible AI Transparency FAQ
189-
Please refer to [Transparency FAQ](./docs/TRANSPARENCY_FAQ.md) for responsible AI transparency details of this solution accelerator.
199+
Please refer to [Transparency FAQ](./content-gen/docs/TRANSPARENCY_FAQ.md) for responsible AI transparency details of this solution accelerator.
190200

191201
<br/>
192202

content-gen/azure.yaml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,17 @@ hooks:
196196
Write-Host ""
197197
Write-Host "===== Running Post-Deploy Script =====" -ForegroundColor Yellow
198198
Write-Host "This will upload sample data and create the search index..."
199+
200+
# Ensure post-deploy Python dependencies are installed
201+
$python = "python"
202+
if (Test-Path "./.venv/Scripts/python.exe") { $python = "./.venv/Scripts/python.exe" }
203+
elseif (Test-Path "../.venv/Scripts/python.exe") { $python = "../.venv/Scripts/python.exe" }
204+
elseif (Test-Path "./.venv/bin/python") { $python = "./.venv/bin/python" }
205+
elseif (Test-Path "../.venv/bin/python") { $python = "../.venv/bin/python" }
206+
& $python -m pip install -r ./scripts/requirements-post-deploy.txt
199207
200208
if (Test-Path "./scripts/post_deploy.py") {
201-
python ./scripts/post_deploy.py `
209+
& $python ./scripts/post_deploy.py `
202210
--resource-group $env:RESOURCE_GROUP_NAME `
203211
--app-name $env:APP_SERVICE_NAME `
204212
--skip-tests
@@ -318,7 +326,17 @@ hooks:
318326
echo "This will upload sample data and create the search index..."
319327
320328
if [ -f "./scripts/post_deploy.py" ]; then
321-
python3 ./scripts/post_deploy.py \
329+
# Prefer local venv if present (repo root or content-gen)
330+
if [ -x "./.venv/bin/python" ]; then
331+
PYTHON_BIN="./.venv/bin/python"
332+
elif [ -x "../.venv/bin/python" ]; then
333+
PYTHON_BIN="../.venv/bin/python"
334+
else
335+
PYTHON_BIN="python3"
336+
fi
337+
338+
"$PYTHON_BIN" -m pip install -r ./scripts/requirements-post-deploy.txt \
339+
&& "$PYTHON_BIN" ./scripts/post_deploy.py \
322340
--resource-group "$RESOURCE_GROUP_NAME" \
323341
--app-name "$APP_SERVICE_NAME" \
324342
--skip-tests \

content-gen/infra/main.bicep

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ param acrName string = ''
106106
@description('Optional. Image Tag.')
107107
param imageTag string = 'latest'
108108

109-
@description('Optional. Skip container (ACI) deployment. Use this on first provision, then set to false after image is built.')
110-
param skipContainerDeployment bool = false
109+
@description('Optional. Skip container (ACI) deployment. Default true for first provision - set to false after image is built and pushed to ACR.')
110+
param skipContainerDeployment bool = true
111111

112112
@description('Optional. Enable/Disable usage telemetry.')
113113
param enableTelemetry bool = true
@@ -540,9 +540,6 @@ module aiServicesPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.1
540540
]
541541
}
542542
}
543-
dependsOn: [
544-
aiFoundryAiServices
545-
]
546543
}
547544

548545
module aiFoundryAiServicesProject 'modules/ai-project.bicep' = if (!useExistingAiFoundryAiProject) {
@@ -816,7 +813,12 @@ module webServerFarm 'br/public:avm/res/web/serverfarm:0.5.0' = {
816813
// ========== Web App ========== //
817814
var webSiteResourceName = 'app-${solutionSuffix}'
818815
// ACI private IP is in the 10.0.4.x subnet range (aci subnet)
819-
var aciPrivateIpPlaceholder = '10.0.4.4' // ACI gets this IP from the aci subnet
816+
// Use the deployed ACI private IP when available; otherwise keep a safe fallback for initial provisioning.
817+
var aciPrivateIpFallback = '10.0.4.4'
818+
var aciPrivateIpAddress = (enablePrivateNetworking && !skipContainerDeployment)
819+
? containerInstance!.outputs.privateIpAddress
820+
: aciPrivateIpFallback
821+
var aciBackendUrl = 'http://${aciPrivateIpAddress}:8000'
820822
module webSite 'modules/web-sites.bicep' = {
821823
name: take('module.web-sites.${webSiteResourceName}', 64)
822824
params: {
@@ -848,7 +850,7 @@ module webSite 'modules/web-sites.bicep' = {
848850
properties: {
849851
SCM_DO_BUILD_DURING_DEPLOYMENT: 'true'
850852
// Backend URL points to ACI private IP
851-
BACKEND_URL: 'http://${aciPrivateIpPlaceholder}:8000'
853+
BACKEND_URL: aciBackendUrl
852854
AZURE_CLIENT_ID: userAssignedIdentity.outputs.clientId
853855
}
854856
applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null
@@ -959,6 +961,9 @@ module containerInstance 'modules/container-instance.bicep' = if (enablePrivateN
959961
}
960962

961963
// ========== Outputs ========== //
964+
@description('Contains App Service Name')
965+
output APP_SERVICE_NAME string = webSite.outputs.name
966+
962967
@description('Contains WebApp URL')
963968
output WEB_APP_URL string = 'https://${webSite.outputs.name}.azurewebsites.net'
964969

0 commit comments

Comments
 (0)