Skip to content

Commit c91af1c

Browse files
committed
(#271) Semantic/Vector Search (#271)
1 parent 498c772 commit c91af1c

File tree

2 files changed

+105
-5
lines changed

2 files changed

+105
-5
lines changed

src/Monolith/ClassifiedAds.Background/ClassifiedAds.Background.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
</PackageReference>
1717
</ItemGroup>
1818

19+
<ItemGroup>
20+
<PackageReference Include="Azure.AI.Vision.ImageAnalysis" Version="1.0.0" />
21+
</ItemGroup>
22+
1923
<ItemGroup>
2024
<ProjectReference Include="..\ClassifiedAds.Application\ClassifiedAds.Application.csproj" />
2125
<ProjectReference Include="..\ClassifiedAds.Infrastructure\ClassifiedAds.Infrastructure.csproj" />

src/Monolith/ClassifiedAds.Background/MessageBusConsumers/FileEmbeddingConsumer.cs

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using ClassifiedAds.Application.FileEntries.MessageBusEvents;
1+
using Azure;
2+
using Azure.AI.Vision.ImageAnalysis;
3+
using ClassifiedAds.Application.FileEntries.MessageBusEvents;
24
using ClassifiedAds.Domain.Entities;
35
using ClassifiedAds.Domain.Infrastructure.Messaging;
46
using ClassifiedAds.Domain.Infrastructure.Storages;
@@ -9,9 +11,11 @@
911
using Microsoft.Extensions.Logging;
1012
using System;
1113
using System.IO;
14+
using System.Linq;
1215
using System.Net.Http;
1316
using System.Net.Http.Headers;
1417
using System.Security.Cryptography;
18+
using System.Text.Json;
1519
using System.Threading;
1620
using System.Threading.Tasks;
1721

@@ -77,9 +81,9 @@ private async Task ProcessFileAsync(FileEntry fileEntry, CancellationToken cance
7781
// TODO: xxx
7882
return;
7983
}
80-
81-
if (fileExtension == ".pdf" ||
82-
fileExtension == ".docx")
84+
else if (fileExtension == ".pdf" ||
85+
fileExtension == ".docx" ||
86+
fileExtension == ".pptx")
8387
{
8488
_logger.LogInformation("Converting file to markdown for FileEntry Id: {FileEntryId}", fileEntry?.Id);
8589

@@ -98,9 +102,30 @@ private async Task ProcessFileAsync(FileEntry fileEntry, CancellationToken cance
98102
await File.WriteAllTextAsync(markdownFile, markdown, cancellationToken);
99103
}
100104
}
105+
else if (fileExtension == ".jpg" ||
106+
fileExtension == ".png")
107+
{
108+
_logger.LogInformation("Processing image file for FileEntry Id: {FileEntryId}", fileEntry?.Id);
109+
110+
var imageAnalysisFolder = Path.Combine(_configuration["Storage:TempFolderPath"], "ImageAnalysis");
111+
112+
if (!Directory.Exists(imageAnalysisFolder))
113+
{
114+
Directory.CreateDirectory(imageAnalysisFolder);
115+
}
116+
117+
var imageAnalysisFile = Path.Combine(imageAnalysisFolder, fileEntry.Id + ".json");
118+
119+
if (!File.Exists(imageAnalysisFile))
120+
{
121+
var imageAnalysisResult = await AnalyzeImageAsync(fileStorageManager, fileEntry, cancellationToken);
122+
123+
await File.WriteAllTextAsync(imageAnalysisFile, JsonSerializer.Serialize(imageAnalysisResult), cancellationToken);
124+
}
125+
}
101126
}
102127

103-
private async Task<string> ConvertToMarkdownAsync(IFileStorageManager fileStorageManager, FileEntry fileEntry, CancellationToken cancellationToken = default)
128+
private async Task<byte[]> GetBytesAsync(IFileStorageManager fileStorageManager, FileEntry fileEntry, CancellationToken cancellationToken)
104129
{
105130
var content = await fileStorageManager.ReadAsync(fileEntry, cancellationToken);
106131

@@ -124,6 +149,13 @@ private async Task<string> ConvertToMarkdownAsync(IFileStorageManager fileStorag
124149
: content;
125150
}
126151

152+
return content;
153+
}
154+
155+
private async Task<string> ConvertToMarkdownAsync(IFileStorageManager fileStorageManager, FileEntry fileEntry, CancellationToken cancellationToken = default)
156+
{
157+
var content = await GetBytesAsync(fileStorageManager, fileEntry, cancellationToken);
158+
127159
using var form = new MultipartFormDataContent();
128160
using var fileContent = new ByteArrayContent(content);
129161
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
@@ -137,4 +169,68 @@ private async Task<string> ConvertToMarkdownAsync(IFileStorageManager fileStorag
137169

138170
return markdown;
139171
}
172+
173+
private ImageAnalysisClient CreateImageAnalysisClient(string endpoint, string key)
174+
{
175+
var client = new ImageAnalysisClient(new Uri(endpoint), new AzureKeyCredential(key));
176+
return client;
177+
}
178+
179+
private async Task<ImageAnalysisResult> AnalyzeImageAsync(IFileStorageManager fileStorageManager, FileEntry fileEntry, CancellationToken cancellationToken = default)
180+
{
181+
string key = _configuration["ImageAnalysis:AzureAIVision:ApiKey"]!;
182+
string endpoint = _configuration["ImageAnalysis:AzureAIVision:Endpoint"]!;
183+
184+
// Create a client
185+
var client = CreateImageAnalysisClient(endpoint, key);
186+
var bytes = await GetBytesAsync(fileStorageManager, fileEntry, cancellationToken);
187+
188+
// Creating a list that defines the features to be extracted from the image.
189+
VisualFeatures features = VisualFeatures.Caption | VisualFeatures.DenseCaptions | VisualFeatures.Tags;
190+
191+
// Analyze the image
192+
var result = await client.AnalyzeAsync(new BinaryData(bytes), visualFeatures: features, cancellationToken: cancellationToken);
193+
194+
return new ImageAnalysisResult
195+
{
196+
Tags = result.Value.Tags.Values.Select(x => new Tag
197+
{
198+
Name = x.Name,
199+
Confidence = x.Confidence
200+
}).ToArray(),
201+
Caption = new Caption
202+
{
203+
Text = result.Value.Caption.Text,
204+
Confidence = result.Value.Caption.Confidence
205+
},
206+
DenseCaptions = result.Value.DenseCaptions.Values.Select(x => new Caption
207+
{
208+
Text = x.Text,
209+
Confidence = x.Confidence
210+
}).ToArray()
211+
};
212+
}
213+
214+
class ImageAnalysisResult
215+
{
216+
public Tag[] Tags { get; set; }
217+
218+
public Caption Caption { get; set; }
219+
220+
public Caption[] DenseCaptions { get; set; }
221+
}
222+
223+
class Tag
224+
{
225+
public string Name { get; set; }
226+
227+
public float Confidence { get; set; }
228+
}
229+
230+
class Caption
231+
{
232+
public string Text { get; set; }
233+
234+
public float Confidence { get; set; }
235+
}
140236
}

0 commit comments

Comments
 (0)