Yash Worlikar commited on
Commit
94e843c
Β·
1 Parent(s): 70235b2

Images Changes

Browse files
Files changed (26) hide show
  1. .gitignore +2 -1
  2. {FoodHealthChecker/Components β†’ Components}/App.razor +0 -0
  3. {FoodHealthChecker/Components β†’ Components}/Layout/MainLayout.razor +0 -0
  4. {FoodHealthChecker/Components β†’ Components}/Layout/MainLayout.razor.css +0 -0
  5. {FoodHealthChecker/Components β†’ Components}/Pages/Error.razor +0 -0
  6. {FoodHealthChecker/Components β†’ Components}/Pages/Home.razor +49 -8
  7. {FoodHealthChecker/Components β†’ Components}/Routes.razor +0 -0
  8. {FoodHealthChecker/Components β†’ Components}/_Imports.razor +0 -0
  9. Dockerfile +3 -3
  10. FoodHealthChecker/FoodCheckerService.cs β†’ FoodCheckerService.cs +53 -1
  11. FoodHealthChecker/FoodHealthChecker.csproj β†’ FoodHealthChecker.csproj +1 -0
  12. FoodHealthChecker.sln +5 -5
  13. {FoodHealthChecker/Options β†’ Options}/AzureOpenAIOptions.cs +0 -0
  14. {FoodHealthChecker/Options β†’ Options}/OpenAIOptions.cs +0 -0
  15. FoodHealthChecker/Program.cs β†’ Program.cs +1 -1
  16. {FoodHealthChecker/Properties β†’ Properties}/launchSettings.json +0 -0
  17. README.md +3 -2
  18. {FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Filters/FoodCheckFunctionFilter.cs +0 -0
  19. {FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Filters/FoodCheckPromptRenderFilter.cs +0 -0
  20. {FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Plugins/FoodCheckerFilterPlugin.cs +0 -0
  21. {FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Plugins/FoodCheckerPlugin.cs +3 -2
  22. FoodHealthChecker/appsettings.json β†’ appsettings.json +0 -0
  23. {FoodHealthChecker/wwwroot β†’ wwwroot}/app.css +6 -0
  24. {FoodHealthChecker/wwwroot β†’ wwwroot}/bootstrap/bootstrap.min.css +0 -0
  25. {FoodHealthChecker/wwwroot β†’ wwwroot}/bootstrap/bootstrap.min.css.map +0 -0
  26. {FoodHealthChecker/wwwroot β†’ wwwroot}/favicon.png +0 -0
.gitignore CHANGED
@@ -361,4 +361,5 @@ MigrationBackup/
361
 
362
  # Fody - auto-generated XML schema
363
  FodyWeavers.xsd
364
- /FoodHealthChecker/appsettings.Development.json
 
 
361
 
362
  # Fody - auto-generated XML schema
363
  FodyWeavers.xsd
364
+ /appsettings.Development.json
365
+ /wwwroot/TempImages
{FoodHealthChecker/Components β†’ Components}/App.razor RENAMED
File without changes
{FoodHealthChecker/Components β†’ Components}/Layout/MainLayout.razor RENAMED
File without changes
{FoodHealthChecker/Components β†’ Components}/Layout/MainLayout.razor.css RENAMED
File without changes
{FoodHealthChecker/Components β†’ Components}/Pages/Error.razor RENAMED
File without changes
{FoodHealthChecker/Components β†’ Components}/Pages/Home.razor RENAMED
@@ -5,7 +5,6 @@
5
  @using Microsoft.AspNetCore.Components
6
  @using System.Runtime.CompilerServices
7
  @implements IDisposable
8
-
9
  <PageTitle> Food Health Checker</PageTitle>
10
 
11
  <div class="container mt-2">
@@ -20,12 +19,16 @@
20
  <div class="col-xl-4">
21
  <div class="card common-card-height">
22
  <div class="card-body">
23
- <h4 class="card-title fw-bold required text-start">Image URL</h4>
24
  <div class="form-group mb-3">
25
- <InputText class="form-control" @bind-Value="ImageUrl" id="imageUrl" placeholder="Enter the food package image URL" />
 
 
 
 
26
  </div>
27
  <div class="form-group mb-3">
28
- <button class="btn btn-primary w-100" @onclick="CheckHealth" disabled="@(isProcessingResponse || isProcessingIngredients)">Check Health</button>
29
  </div>
30
 
31
  @if (!string.IsNullOrWhiteSpace(ImageUrl))
@@ -87,22 +90,60 @@
87
 
88
  @code {
89
  public string ImageUrl { get; set; } = string.Empty;
 
 
 
90
  public string Ingredients { get; set; } = string.Empty;
91
  public string Result { get; set; } = string.Empty;
92
-
93
  [Inject]
94
- public MarkdownPipeline pipeline { get; set; }
95
  [Inject]
96
- public FoodCheckerService _foodCheckerService { get; set; }
 
 
97
 
98
  private bool isProcessingIngredients = false;
99
  private bool isProcessingResponse = false;
100
  private string errorMessage = string.Empty;
101
  private CancellationTokenSource _cts = new CancellationTokenSource();
102
 
103
- private async Task CheckHealth()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  {
 
 
 
 
105
 
 
 
106
  isProcessingIngredients = true;
107
  errorMessage = string.Empty;
108
  Result = string.Empty;
 
5
  @using Microsoft.AspNetCore.Components
6
  @using System.Runtime.CompilerServices
7
  @implements IDisposable
 
8
  <PageTitle> Food Health Checker</PageTitle>
9
 
10
  <div class="container mt-2">
 
19
  <div class="col-xl-4">
20
  <div class="card common-card-height">
21
  <div class="card-body">
22
+ <h4 class="card-title fw-bold required text-start">Image</h4>
23
  <div class="form-group mb-3">
24
+ <!-- HTML -->
25
+ <label for="upload-image" class="custom-upload-button btn btn-primary">
26
+ Upload Image
27
+ </label>
28
+ <InputFile OnChange="HandleSelectedFiles" class="btn btn-primary" id="upload-image" aria-describedby="fileHelp" multiple></InputFile>
29
  </div>
30
  <div class="form-group mb-3">
31
+ <button class="btn btn-primary w-100" @onclick="CheckHealth" disabled="@(isProcessingResponse && isProcessingIngredients)">Check Health</button>
32
  </div>
33
 
34
  @if (!string.IsNullOrWhiteSpace(ImageUrl))
 
90
 
91
  @code {
92
  public string ImageUrl { get; set; } = string.Empty;
93
+ public ReadOnlyMemory<byte> ImageData { get; set; }
94
+ public string ImageName { get; set; } = string.Empty;
95
+
96
  public string Ingredients { get; set; } = string.Empty;
97
  public string Result { get; set; } = string.Empty;
98
+
99
  [Inject]
100
+ public MarkdownPipeline pipeline { get; set; } = default!;
101
  [Inject]
102
+ public FoodCheckerService _foodCheckerService { get; set; } = default!;
103
+ [Inject]
104
+ private NavigationManager Navigation { get; set; } = default!;
105
 
106
  private bool isProcessingIngredients = false;
107
  private bool isProcessingResponse = false;
108
  private string errorMessage = string.Empty;
109
  private CancellationTokenSource _cts = new CancellationTokenSource();
110
 
111
+
112
+ private async Task HandleSelectedFiles(InputFileChangeEventArgs e)
113
+ {
114
+ var imageFile = e.File;
115
+ if (imageFile != null)
116
+ {
117
+ // Ensure the TempImages folder exists
118
+ var folderPath = Path.Combine("wwwroot", "TempImages");
119
+ if (!Directory.Exists(folderPath))
120
+ {
121
+ Directory.CreateDirectory(folderPath);
122
+ }
123
+
124
+ // Save the file to the server
125
+ var filePath = Path.Combine(folderPath, imageFile.Name);
126
+ using var stream = new FileStream(filePath, FileMode.Create);
127
+ await imageFile.OpenReadStream().CopyToAsync(stream);
128
+
129
+ // Read the file into a byte array
130
+ ImageData = await ReadFileBytes(imageFile);
131
+ ImageName = imageFile.Name;
132
+ // Update the ImageUrl property with the complete URL
133
+ var relativePath = Path.Combine("TempImages", imageFile.Name);
134
+ ImageUrl = Navigation.ToAbsoluteUri(relativePath).ToString();
135
+ }
136
+ }
137
+
138
+ private async Task<ReadOnlyMemory<byte>> ReadFileBytes(IBrowserFile imageFile)
139
  {
140
+ using var memoryStream = new MemoryStream();
141
+ await imageFile.OpenReadStream().CopyToAsync(memoryStream);
142
+ return memoryStream.ToArray();
143
+ }
144
 
145
+ private async Task CheckHealth()
146
+ {
147
  isProcessingIngredients = true;
148
  errorMessage = string.Empty;
149
  Result = string.Empty;
{FoodHealthChecker/Components β†’ Components}/Routes.razor RENAMED
File without changes
{FoodHealthChecker/Components β†’ Components}/_Imports.razor RENAMED
File without changes
Dockerfile CHANGED
@@ -9,10 +9,10 @@ EXPOSE 8081
9
  FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
10
  ARG BUILD_CONFIGURATION=Release
11
  WORKDIR /src
12
- COPY ["FoodHealthChecker/FoodHealthChecker.csproj", "FoodHealthChecker/"]
13
- RUN dotnet restore "./FoodHealthChecker/FoodHealthChecker.csproj"
14
  COPY . .
15
- WORKDIR "/src/FoodHealthChecker"
16
  RUN dotnet build "./FoodHealthChecker.csproj" -c $BUILD_CONFIGURATION -o /app/build
17
 
18
  FROM build AS publish
 
9
  FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
10
  ARG BUILD_CONFIGURATION=Release
11
  WORKDIR /src
12
+ COPY ["FoodHealthChecker.csproj", "."]
13
+ RUN dotnet restore "./FoodHealthChecker.csproj"
14
  COPY . .
15
+ WORKDIR "/src/."
16
  RUN dotnet build "./FoodHealthChecker.csproj" -c $BUILD_CONFIGURATION -o /app/build
17
 
18
  FROM build AS publish
FoodHealthChecker/FoodCheckerService.cs β†’ FoodCheckerService.cs RENAMED
@@ -36,14 +36,66 @@ namespace FoodHealthChecker
36
  kernel.Plugins.AddFromObject(foodCheckerPlugin);
37
  _kernel = kernel;
38
  }
 
 
 
 
 
 
 
39
  public IAsyncEnumerable<string> CheckFoodHealthAsync(string ingredientResponse, CancellationToken cancellationToken = default)
40
  {
41
  return _foodCheckerPlugin.CheckFoodHealthAsync(ingredientResponse, _kernel, cancellationToken);
42
  }
43
 
44
- public IAsyncEnumerable<string> GetIngredirentsAsync(string imageDataUrl, CancellationToken cancellationToken = default)
 
 
 
 
 
 
 
 
 
 
45
  {
 
 
 
46
  return _foodCheckerPlugin.GetIngredientsAsync(imageDataUrl, _kernel, cancellationToken);
47
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
  }
 
36
  kernel.Plugins.AddFromObject(foodCheckerPlugin);
37
  _kernel = kernel;
38
  }
39
+
40
+ /// <summary>
41
+ ///
42
+ /// </summary>
43
+ /// <param name="ingredientResponse"></param>
44
+ /// <param name="cancellationToken"></param>
45
+ /// <returns></returns>
46
  public IAsyncEnumerable<string> CheckFoodHealthAsync(string ingredientResponse, CancellationToken cancellationToken = default)
47
  {
48
  return _foodCheckerPlugin.CheckFoodHealthAsync(ingredientResponse, _kernel, cancellationToken);
49
  }
50
 
51
+
52
+ /// <summary>
53
+ ///
54
+ /// </summary>
55
+ /// <param name="imageData"></param>
56
+ /// <param name="fileName"></param>
57
+ /// <param name="cancellationToken"></param>
58
+ /// <returns></returns>
59
+ /// Inconsistant behaviour https://github.com/microsoft/semantic-kernel/pull/6319
60
+ /// Related to https://github.com/dotnet/runtime/issues/96544
61
+ public IAsyncEnumerable<string> GetIngredirentsAsync(ReadOnlyMemory<byte> imageData,string fileName, CancellationToken cancellationToken = default)
62
  {
63
+
64
+ var imageDataUrl = new ImageContent(imageData) { MimeType = GetMimeType(fileName) }.ToString();
65
+
66
  return _foodCheckerPlugin.GetIngredientsAsync(imageDataUrl, _kernel, cancellationToken);
67
  }
68
+
69
+ /// <summary>
70
+ ///
71
+ /// </summary>
72
+ /// <param name="imageUrl"></param>
73
+ /// <param name="cancellationToken"></param>
74
+ /// <returns></returns>
75
+ public IAsyncEnumerable<string> GetIngredirentsAsync(string imageUrl,CancellationToken cancellationToken = default)
76
+ {
77
+ return _foodCheckerPlugin.GetIngredientsAsync(imageUrl, _kernel, cancellationToken);
78
+ }
79
+
80
+ /// <summary>
81
+ ///
82
+ /// </summary>
83
+ /// <param name="fileName"></param>
84
+ /// <returns></returns>
85
+ /// <exception cref="NotSupportedException"></exception>
86
+ private static string GetMimeType(string fileName)
87
+ {
88
+ return Path.GetExtension(fileName) switch
89
+ {
90
+ ".jpg" or ".jpeg" => "image/jpeg",
91
+ ".png" => "image/png",
92
+ ".gif" => "image/gif",
93
+ ".bmp" => "image/bmp",
94
+ ".tiff" => "image/tiff",
95
+ ".ico" => "image/x-icon",
96
+ ".svg" => "image/svg+xml",
97
+ _ => throw new NotSupportedException("Unsupported image format.")
98
+ };
99
+ }
100
  }
101
  }
FoodHealthChecker/FoodHealthChecker.csproj β†’ FoodHealthChecker.csproj RENAMED
@@ -7,6 +7,7 @@
7
  <NoWarn>SKEXP0001</NoWarn>
8
  <UserSecretsId>34c9f77b-3416-42fc-90bc-2e0503b55215</UserSecretsId>
9
  <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
 
10
  </PropertyGroup>
11
  <ItemGroup>
12
  <PackageReference Include="Markdig" Version="0.37.0" />
 
7
  <NoWarn>SKEXP0001</NoWarn>
8
  <UserSecretsId>34c9f77b-3416-42fc-90bc-2e0503b55215</UserSecretsId>
9
  <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
10
+ <DockerfileContext>.</DockerfileContext>
11
  </PropertyGroup>
12
  <ItemGroup>
13
  <PackageReference Include="Markdig" Version="0.37.0" />
FoodHealthChecker.sln CHANGED
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
3
  # Visual Studio Version 17
4
  VisualStudioVersion = 17.9.34902.65
5
  MinimumVisualStudioVersion = 10.0.40219.1
6
- Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FoodHealthChecker", "FoodHealthChecker\FoodHealthChecker.csproj", "{E2623B67-5F1F-4D9F-AADD-E23C493DA5EB}"
7
  EndProject
8
  Global
9
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,10 +11,10 @@ Global
11
  Release|Any CPU = Release|Any CPU
12
  EndGlobalSection
13
  GlobalSection(ProjectConfigurationPlatforms) = postSolution
14
- {E2623B67-5F1F-4D9F-AADD-E23C493DA5EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15
- {E2623B67-5F1F-4D9F-AADD-E23C493DA5EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
16
- {E2623B67-5F1F-4D9F-AADD-E23C493DA5EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
17
- {E2623B67-5F1F-4D9F-AADD-E23C493DA5EB}.Release|Any CPU.Build.0 = Release|Any CPU
18
  EndGlobalSection
19
  GlobalSection(SolutionProperties) = preSolution
20
  HideSolutionNode = FALSE
 
3
  # Visual Studio Version 17
4
  VisualStudioVersion = 17.9.34902.65
5
  MinimumVisualStudioVersion = 10.0.40219.1
6
+ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FoodHealthChecker", "FoodHealthChecker.csproj", "{7BEAFE91-5A63-4430-8D43-D2D241FE19AB}"
7
  EndProject
8
  Global
9
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
 
11
  Release|Any CPU = Release|Any CPU
12
  EndGlobalSection
13
  GlobalSection(ProjectConfigurationPlatforms) = postSolution
14
+ {7BEAFE91-5A63-4430-8D43-D2D241FE19AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15
+ {7BEAFE91-5A63-4430-8D43-D2D241FE19AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
16
+ {7BEAFE91-5A63-4430-8D43-D2D241FE19AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
17
+ {7BEAFE91-5A63-4430-8D43-D2D241FE19AB}.Release|Any CPU.Build.0 = Release|Any CPU
18
  EndGlobalSection
19
  GlobalSection(SolutionProperties) = preSolution
20
  HideSolutionNode = FALSE
{FoodHealthChecker/Options β†’ Options}/AzureOpenAIOptions.cs RENAMED
File without changes
{FoodHealthChecker/Options β†’ Options}/OpenAIOptions.cs RENAMED
File without changes
FoodHealthChecker/Program.cs β†’ Program.cs RENAMED
@@ -19,7 +19,7 @@ namespace FoodHealthChecker
19
  });
20
  builder.Services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true);
21
  builder.Services.AddSingleton<FoodCheckerPlugin>();
22
- builder.Services.AddSingleton<FoodCheckerService>();
23
 
24
  var app = builder.Build();
25
 
 
19
  });
20
  builder.Services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true);
21
  builder.Services.AddSingleton<FoodCheckerPlugin>();
22
+ builder.Services.AddTransient<FoodCheckerService>();
23
 
24
  var app = builder.Build();
25
 
{FoodHealthChecker/Properties β†’ Properties}/launchSettings.json RENAMED
File without changes
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: Food health Check
3
  emoji: πŸƒ
4
  colorFrom: blue
5
  colorTo: yellow
@@ -12,9 +12,10 @@ app_port: 8080
12
  ## FoodHealthChecker
13
 
14
  An app that lists all the ingredients and nutritional info present in the images and predicts whether it is healthy or not.
 
15
  Build using .Net Semantic Kernel and Azure OpenAI/OpenAI Gpt-4-vision model.
16
 
17
- **NOTE Copying this space requires either an Azure OpenAI endpoint or an OpenAI APIKey to function properly**
18
 
19
 
20
 
 
1
  ---
2
+ title: FoodHealthChecker
3
  emoji: πŸƒ
4
  colorFrom: blue
5
  colorTo: yellow
 
12
  ## FoodHealthChecker
13
 
14
  An app that lists all the ingredients and nutritional info present in the images and predicts whether it is healthy or not.
15
+
16
  Build using .Net Semantic Kernel and Azure OpenAI/OpenAI Gpt-4-vision model.
17
 
18
+ **NOTE Running this Repo locally requires either an Azure OpenAI endpoint or an OpenAI APIKey present in the app settings to function properly**
19
 
20
 
21
 
{FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Filters/FoodCheckFunctionFilter.cs RENAMED
File without changes
{FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Filters/FoodCheckPromptRenderFilter.cs RENAMED
File without changes
{FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Plugins/FoodCheckerFilterPlugin.cs RENAMED
File without changes
{FoodHealthChecker/SemanticKernel β†’ SemanticKernel}/Plugins/FoodCheckerPlugin.cs RENAMED
@@ -47,7 +47,7 @@ namespace FoodHealthChecker.SemanticKernel.Plugins
47
  {
48
  new TextContent(FoodCheckerTemplates.GetIngredients),
49
  new ImageContent(new Uri(input))
50
- });
51
  await foreach (var result in chatService.GetStreamingChatMessageContentsAsync(chat, s_settings, kernel, cancellationToken))
52
  {
53
  var generatedText = result?.ToString() ?? string.Empty;
@@ -63,7 +63,8 @@ namespace FoodHealthChecker.SemanticKernel.Plugins
63
  public const string CheckFoodHealth =
64
  @"
65
  [Instruction]
66
- Given the list of ingredients for a food product give it a Rating from Very Unhealthy to very Healthy. Also give the reasoning in ELI5 format using less than 3 sentences in the below response format
 
67
  [Ingredients]
68
  {{$input}}
69
  [RESPONSE]
 
47
  {
48
  new TextContent(FoodCheckerTemplates.GetIngredients),
49
  new ImageContent(new Uri(input))
50
+ });
51
  await foreach (var result in chatService.GetStreamingChatMessageContentsAsync(chat, s_settings, kernel, cancellationToken))
52
  {
53
  var generatedText = result?.ToString() ?? string.Empty;
 
63
  public const string CheckFoodHealth =
64
  @"
65
  [Instruction]
66
+ Given the list of ingredients for a food product give it a Rating from Very Unhealthy to very Healthy. Also give the reasoning in ELI5 format using less than 3 sentences in the below response format.
67
+ Also list any cancer causing or harmful substances if present.
68
  [Ingredients]
69
  {{$input}}
70
  [RESPONSE]
FoodHealthChecker/appsettings.json β†’ appsettings.json RENAMED
File without changes
{FoodHealthChecker/wwwroot β†’ wwwroot}/app.css RENAMED
@@ -184,3 +184,9 @@ h1, h2, h3, h4, h5, h6 {
184
  .ai-ingredients-response::-webkit-scrollbar-thumb {
185
  background-color: rgba(0,0,0,0.5);
186
  }
 
 
 
 
 
 
 
184
  .ai-ingredients-response::-webkit-scrollbar-thumb {
185
  background-color: rgba(0,0,0,0.5);
186
  }
187
+
188
+ #upload-image {
189
+ opacity: 0;
190
+ position: absolute;
191
+ z-index: -1;
192
+ }
{FoodHealthChecker/wwwroot β†’ wwwroot}/bootstrap/bootstrap.min.css RENAMED
File without changes
{FoodHealthChecker/wwwroot β†’ wwwroot}/bootstrap/bootstrap.min.css.map RENAMED
File without changes
{FoodHealthChecker/wwwroot β†’ wwwroot}/favicon.png RENAMED
File without changes