Skip to content

Commit cd8991e

Browse files
authored
chore: tf-azure-ai-foundry (#43)
* chore: tf-azure-ai-foundry * fmt: tf * fix: fmt * chore: update * chore: error handling safety * fix: tf * fix: ctor * fix: fmt * fix: fmt * fix: fmt * fix: fmt * fix: fmt * fix: fmt
1 parent 37f3351 commit cd8991e

File tree

8 files changed

+53
-46
lines changed

8 files changed

+53
-46
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Azure AI Foundry Content Safety resource
2+
resource "azurerm_cognitive_account" "content_safety" {
3+
name = "cs-evently-dev-sea"
4+
location = azurerm_resource_group.rg.location
5+
resource_group_name = azurerm_resource_group.rg.name
6+
kind = "ContentSafety"
7+
sku_name = "F0"
8+
}

deploy/Terraform/container-app.tf

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -168,26 +168,26 @@ resource "azurerm_container_app" "app" {
168168
value = "Warning"
169169
}
170170

171-
# General Settings
172171
env {
173-
name = "AllowedHosts"
174-
value = "*"
172+
name = "AzureAIFoundry__ContentSafetyKey"
173+
value = azurerm_cognitive_account.content_safety.primary_access_key
175174
}
176175

177-
# Environment indicator
178176
env {
179-
name = "ASPNETCORE_ENVIRONMENT"
180-
value = "Production"
177+
name = "AzureAIFoundry__ContentSafetyEndpoint"
178+
value = azurerm_cognitive_account.content_safety.endpoint
181179
}
182180

181+
# General Settings
183182
env {
184-
name = "AzureAIFoundry__ContentSafetyKey"
185-
secret_name = "content-safety-key"
183+
name = "AllowedHosts"
184+
value = "*"
186185
}
187186

187+
# Environment indicator
188188
env {
189-
name = "AzureAIFoundry__ContentSafetyEndpoint"
190-
value = var.content_safety_api
189+
name = "ASPNETCORE_ENVIRONMENT"
190+
value = "Production"
191191
}
192192
}
193193
}
@@ -226,9 +226,4 @@ resource "azurerm_container_app" "app" {
226226
value = var.smtp_password
227227
}
228228

229-
secret {
230-
name = "content-safety-key"
231-
value = var.content_safety_key
232-
}
233-
234229
}

deploy/Terraform/variables.tf

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,4 @@ variable "smtp_password" {
3434
description = "SMTP password for email sending"
3535
type = string
3636
sensitive = true
37-
}
38-
39-
variable "content_safety_key" {
40-
description = "Azure AI foundry content safety key"
41-
type = string
42-
sensitive = true
43-
}
44-
45-
variable "content_safety_api" {
46-
description = "Azure AI foundry content safety api endpoint"
47-
type = string
4837
}

src/Evently.Server/Common/Domains/Models/Settings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public sealed class EmailSettings {
3535
public string SmtpPassword { get; init; } = string.Empty;
3636
}
3737

38+
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")]
39+
// ReSharper disable once InconsistentNaming
3840
public sealed class AzureAIFoundry {
3941
public string ContentSafetyKey { get; init; } = string.Empty;
4042
public string ContentSafetyEndpoint { get; init; } = string.Empty;

src/Evently.Server/Common/Extensions/LoggerExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static partial void LogSuccessEmail(
2828
Message = "Error occurred at {context}: {errorMsg}")]
2929
public static partial void LogErrorContext(
3030
this ILogger logger, string context, string errorMsg);
31-
31+
3232
[LoggerMessage(
3333
EventId = 5,
3434
Level = LogLevel.Error,

src/Evently.Server/Features/Bookings/Services/BookingService.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,4 @@ public async Task<string> RenderTicket(string bookingId) {
126126

127127
return await mediaRenderer.RenderComponentHtml<Ticket>(props);
128128
}
129-
130-
public async Task<bool> Exists(string bookingId) {
131-
return await db.Bookings.AnyAsync(b => b.BookingId == bookingId);
132-
}
133129
}

src/Evently.Server/Features/Emails/Services/EmailBackgroundService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Evently.Server.Common.Domains.Entities;
22
using Evently.Server.Common.Domains.Interfaces;
3+
using Evently.Server.Common.Extensions;
34
using System.Threading.Channels;
4-
using LoggerExtension=Evently.Server.Common.Extensions.LoggerExtension;
55

66
namespace Evently.Server.Features.Emails.Services;
77

@@ -26,7 +26,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
2626

2727
string html = await bookingService.RenderTicket(bookingId);
2828
await emailerAdapter.SendEmailAsync("noreply@evently", account.Email, "Test QR ticket", html);
29-
LoggerExtension.LogSuccessEmail(logger, account.Email);
29+
logger.LogSuccessEmail(account.Email);
3030
} catch (Exception ex) {
3131
logger.LogError("email error: {}", ex.Message);
3232
}

src/Evently.Server/Features/Files/Services/ObjectStorageService.cs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,25 @@
1010
namespace Evently.Server.Features.Files.Services;
1111

1212
// Based on https://tinyurl.com/5pam66xn
13-
public sealed class ObjectStorageService(IOptions<Settings> settings, ILogger<ObjectStorageService> logger) : IObjectStorageService {
14-
private readonly BlobServiceClient _blobServiceClient =
15-
new(settings.Value.StorageAccount.AzureStorageConnectionString);
16-
private readonly ContentSafetyClient _contentSafetyClient = new(
17-
endpoint: new Uri(settings.Value.AzureAiFoundry.ContentSafetyEndpoint),
18-
credential: new AzureKeyCredential(settings.Value.AzureAiFoundry.ContentSafetyKey));
13+
public sealed class ObjectStorageService : IObjectStorageService {
14+
private readonly BlobServiceClient _blobServiceClient;
15+
private readonly ContentSafetyClient? _contentSafetyClient;
16+
private readonly ILogger<ObjectStorageService> _logger;
17+
18+
public ObjectStorageService(IOptions<Settings> settings, ILogger<ObjectStorageService> logger) {
19+
_logger = logger;
20+
_blobServiceClient =
21+
new BlobServiceClient(settings.Value.StorageAccount.AzureStorageConnectionString);
22+
23+
try {
24+
_contentSafetyClient = new ContentSafetyClient(
25+
endpoint: new Uri(settings.Value.AzureAiFoundry.ContentSafetyEndpoint),
26+
credential: new AzureKeyCredential(settings.Value.AzureAiFoundry.ContentSafetyKey));
27+
} catch (Exception ex) {
28+
// silence the error
29+
_logger.LogError("error creating content safety client: {message}. Content moderation skipped.", ex.Message);
30+
}
31+
}
1932

2033
public async Task<Uri> UploadFile(string containerName, string fileName, BinaryData binaryData,
2134
string mimeType = "application/octet-stream") {
@@ -63,7 +76,7 @@ public async Task<BinaryData> GetFile(string containerName, string fileName) {
6376
try {
6477
await blobClient.DownloadToAsync(ms);
6578
} catch (Exception ex) {
66-
logger.LogError("error getting file: {}", ex.Message);
79+
_logger.LogError("error getting file: {}", ex.Message);
6780
}
6881

6982
byte[] bytes = ms.ToArray();
@@ -72,21 +85,25 @@ public async Task<BinaryData> GetFile(string containerName, string fileName) {
7285
}
7386

7487
public async Task<bool> PassesContentModeration(BinaryData binaryData) {
88+
if (_contentSafetyClient is null) {
89+
return true;
90+
}
91+
7592
ContentSafetyImageData image = new(binaryData);
7693
AnalyzeImageOptions request = new(image);
7794
Response<AnalyzeImageResult> response;
7895
try {
7996
response = await _contentSafetyClient.AnalyzeImageAsync(request);
8097
} catch (RequestFailedException ex) {
81-
logger.LogContentModerationError(ex.Status.ToString(), ex.ErrorCode ?? "", ex.Message);
98+
_logger.LogContentModerationError(ex.Status.ToString(), ex.ErrorCode ?? "", ex.Message);
8299
throw;
83100
}
84101

85102
AnalyzeImageResult result = response.Value;
86-
int? score = result.CategoriesAnalysis
87-
.Select(v => v.Severity)
88-
.Aggregate((a, b) => a + b)
89-
?? 0;
90-
return score == 0;
103+
int dangerScore = result.CategoriesAnalysis
104+
.Select(v => v.Severity ?? 0)
105+
.DefaultIfEmpty(0)
106+
.Aggregate((a, b) => a + b);
107+
return dangerScore == 0;
91108
}
92109
}

0 commit comments

Comments
 (0)