Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ jobs:
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://0.0.0.0:5000
ConnectionStrings__DefaultConnection="Server=${{ secrets.RDS_HOST }};Port=3306;Database=${{ secrets.RDS_DB_NAME }};Uid=${{ secrets.RDS_DB_USER }};Pwd=${{ secrets.RDS_DB_PASSWORD }};SslMode=Required;"
GOOGLE_API_KEY=${{ secrets.GOOGLE_API_KEY }}
EOF
sudo chown ${{ secrets.LIGHTSAIL_USER }}:${{ secrets.LIGHTSAIL_USER }} /var/www/culinarycommand/.env
sudo chmod 640 /var/www/culinarycommand/.env
Expand All @@ -135,6 +136,7 @@ jobs:
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://0.0.0.0:5000
export ConnectionStrings__DefaultConnection="Server=${{ secrets.RDS_HOST }};Port=3306;Database=${{ secrets.RDS_DB_NAME }};Uid=${{ secrets.RDS_DB_USER }};Pwd=${{ secrets.RDS_DB_PASSWORD }};SslMode=Required;"
export GOOGLE_API_KEY="${{ secrets.GOOGLE_API_KEY }}"
EOF
sudo chown ${{ secrets.LIGHTSAIL_USER }}:${{ secrets.LIGHTSAIL_USER }} /var/www/culinarycommand/.env.export
sudo chmod 640 /var/www/culinarycommand/.env.export
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,4 @@ jobs:

- name: Run Culinary Command xUnit tests
run: |
dotnet test CulinaryCommandApp/CulinaryCommand.sln

dotnet test CulinaryCommandApp/CulinaryCommand.sln
63 changes: 63 additions & 0 deletions CulinaryCommandApp/AIDashboard/DTOs/AIAnalysisResultDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace CulinaryCommandApp.AIDashboard.Services.DTOs
{
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

public class AIAnalysisResultDTO
{
[JsonPropertyName("title")]
public string? Title { get; set; }

[JsonPropertyName("summary")]
public string? Summary { get; set; }

[JsonPropertyName("metrics")]
public List<Metric>? Metrics { get; set; }

[JsonPropertyName("sections")]
public List<Section>? Sections { get; set; }

[JsonPropertyName("anomalies")]
public List<Anomaly>? Anomalies { get; set; }

[JsonPropertyName("recommendations")]
public List<string>? Recommendations { get; set; }

[JsonPropertyName("generatedAt")]
public DateTimeOffset? GeneratedAt { get; set; }

[JsonPropertyName("confidence")]
public double? Confidence { get; set; }
}

public class Metric
{
[JsonPropertyName("label")]
public string? Label { get; set; }

[JsonPropertyName("value")]
public string? Value { get; set; }

[JsonPropertyName("unit")]
public string? Unit { get; set; }
}
public class Section
{
[JsonPropertyName("heading")]
public string? Heading { get; set; }

[JsonPropertyName("body")]
public string? Body { get; set; }
}

public class Anomaly
{
[JsonPropertyName("row")]
public string? Row { get; set; }

[JsonPropertyName("reason")]
public string? Reason { get; set; }

}
}
Comment thread
kevbang marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
namespace CulinaryCommandApp.AIDashboard.Services.Reporting
{
using Google.GenAI;
using Google.GenAI.Types;
using System;
using System.Threading.Tasks;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Text.Json.Serialization;
using System.Text.Json;
using CulinaryCommandApp.AIDashboard.Services.DTOs;


public class AIReportingService
{
private readonly Client _client;

public AIReportingService(Client client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
}

public async Task<string> AnalyzeCsvAsync(string? csvPath = null)
{
const string PayloadSchema = @" You are an expert restaurant data analyst.
Analyze the CSV I give you and return ONLY a JSON object
that exactly follows this SCHEMA:
{
""title"": string,
""summary"": string,
""metrics"": [ { ""label"": string, ""value"": string, ""unit"": string|null } ],
""sections"": [ { ""heading"": string, ""body"": string } ],
""anomalies"": [ { ""row"": string, ""reason"": string } ],
""recommendations"": [ string ],
""generatedAt"": ""ISO-8601 datetime string"",
""confidence"": ""number"" (0.0 to 1.0)
}
Constraints:
- Return only JSON (no surrounding text, no markdown fences).
- For long text blocks, try to be concise in the ""body"" fields.
- Use ISO-8601 for generatedAt.
- Provide a numeric confidence between 0 and 1.

Analysis requirements:
- Use business/user friendly tone.
- If there are anomalies, prompt the user to investigate.
- Include top seller focus analysis.
- Provide quick action items if appropriate.
Now analyze the CSV content below and return the JSON.
";


if (string.IsNullOrWhiteSpace(csvPath))
{
Console.WriteLine("CSV path not provided.");
return "CSV path not provided.";
}

if (!System.IO.File.Exists(csvPath))
{
Console.WriteLine($"CSV not found at: {csvPath}");
return $"CSV not found at: {csvPath}";
}

var lines = System.IO.File.ReadAllLines(csvPath).ToList();
Comment thread
kevbang marked this conversation as resolved.

if (lines.Count <= 1)
{
Console.WriteLine("CSV empty or only header.");
return "CSV empty or only header.";
}

var header = lines[0];
var rows = lines.Skip(1).ToList();

/**** Build payload to send to Gemini model****/
var geminiPayload = new StringBuilder();

geminiPayload.AppendLine(PayloadSchema);
geminiPayload.AppendLine(header);
foreach (var r in rows) geminiPayload.AppendLine(r);
Comment thread
kevbang marked this conversation as resolved.

Console.WriteLine(geminiPayload);

/***** Make API call to Gemini with payload ******/
var response = await _client.Models.GenerateContentAsync(
model: "gemini-3-flash-preview",
Comment thread
kevbang marked this conversation as resolved.
contents: geminiPayload.ToString()
);

Console.WriteLine(response.Candidates[0].Content.Parts[0].Text);
Comment thread
kevbang marked this conversation as resolved.

var AIAnalysisResponse = response?.Candidates?.FirstOrDefault()?.Content?.Parts?.FirstOrDefault()?.Text;
Comment thread
kevbang marked this conversation as resolved.

/*** Deserialize ***/

if (!string.IsNullOrWhiteSpace(AIAnalysisResponse))
{
try
{
var options = new System.Text.Json.JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
};

var result = System.Text.Json.JsonSerializer.Deserialize<AIAnalysisResultDTO>(AIAnalysisResponse, options);

if (result != null)
{
return System.Text.Json.JsonSerializer.Serialize(result, new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
}
}
catch (JsonException)
{
// just catch the exception and move on
}
Comment thread
kevbang marked this conversation as resolved.
}

return AIAnalysisResponse ?? "(no analysis returned)";
}

}
}
101 changes: 101 additions & 0 deletions CulinaryCommandApp/AIDashboard/Services/Reporting/test_data.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
date,dish_ordered,dish_price
2025-08-09,Beef Tacos,9.75
2025-08-21,Beef Tacos,9.75
2025-12-26,Grilled Chicken Salad,10.49
2025-01-12,Spaghetti Bolognese,12.99
2025-09-08,Beef Tacos,9.75
2025-01-25,Grilled Chicken Salad,10.49
2025-02-14,Fish and Chips,11.99
2025-05-29,Sushi Platter,15.99
2025-11-26,Fish and Chips,11.99
2025-05-26,Fish and Chips,11.99
2025-02-27,Chicken Alfredo,13.5
2025-09-29,Spaghetti Bolognese,12.99
2025-08-05,Sushi Platter,15.99
2025-12-11,Spaghetti Bolognese,12.99
2025-04-22,Beef Tacos,9.75
2025-04-28,Fish and Chips,11.99
2025-08-31,Spaghetti Bolognese,12.99
2025-11-02,Grilled Chicken Salad,10.49
2025-09-18,Margherita Pizza,11.25
2025-12-24,Margherita Pizza,11.25
2025-11-09,Margherita Pizza,11.25
2025-03-10,Sushi Platter,15.99
2025-12-31,Margherita Pizza,11.25
2025-06-27,Chicken Alfredo,13.5
2025-02-28,Chicken Alfredo,13.5
2025-09-16,Chicken Alfredo,13.5
2025-12-28,Beef Tacos,9.75
2025-11-27,Chicken Alfredo,13.5
2025-07-18,Spaghetti Bolognese,12.99
2025-05-29,Chicken Alfredo,13.5
2025-11-03,Veggie Burger,8.95
2025-05-09,Fish and Chips,11.99
2025-05-20,Spaghetti Bolognese,12.99
2025-04-23,Sushi Platter,15.99
2025-07-08,Sushi Platter,15.99
2025-08-06,Spaghetti Bolognese,12.99
2025-07-12,Grilled Chicken Salad,10.49
2025-04-13,Grilled Chicken Salad,10.49
2025-04-22,Fish and Chips,11.99
2025-03-09,Beef Tacos,9.75
2025-06-17,Spaghetti Bolognese,12.99
2025-02-26,Spaghetti Bolognese,12.99
2025-06-19,Fish and Chips,11.99
2025-06-16,Beef Tacos,9.75
2025-07-10,Spaghetti Bolognese,12.99
2025-02-03,Spaghetti Bolognese,12.99
2025-07-22,Chicken Alfredo,13.5
2025-03-17,Grilled Chicken Salad,10.49
2025-07-24,Fish and Chips,11.99
2025-01-29,Veggie Burger,8.95
2025-08-21,Veggie Burger,8.95
2025-12-30,Fish and Chips,11.99
2025-09-04,Fish and Chips,11.99
2025-05-04,Spaghetti Bolognese,12.99
2025-11-06,Sushi Platter,15.99
2035-05-15,Spaghetti Bolognese,999.99
2025-12-12,Chicken Alfredo,13.5
2025-11-15,Sushi Platter,15.99
2025-05-19,Chicken Alfredo,13.5
2025-04-01,Grilled Chicken Salad,10.49
2025-01-03,Beef Tacos,9.75
2025-08-22,Spaghetti Bolognese,12.99
2025-12-29,Grilled Chicken Salad,10.49
2025-03-22,Margherita Pizza,11.25
2025-04-29,Veggie Burger,8.95
2025-05-31,Grilled Chicken Salad,10.49
2025-02-07,Beef Tacos,9.75
2025-09-11,Veggie Burger,8.95
2025-12-22,Veggie Burger,8.95
2025-05-29,Margherita Pizza,11.25
2025-01-19,Beef Tacos,9.75
2025-07-12,Beef Tacos,9.75
2025-02-09,Sushi Platter,15.99
2025-10-05,Beef Tacos,9.75
2025-06-06,Beef Tacos,9.75
2025-08-29,Margherita Pizza,11.25
2025-09-08,Chicken Alfredo,13.5
2025-11-06,Beef Tacos,9.75
2025-03-27,Margherita Pizza,11.25
2025-03-08,Veggie Burger,8.95
2025-07-18,Margherita Pizza,11.25
2025-08-29,Beef Tacos,9.75
2025-03-02,Grilled Chicken Salad,10.49
2025-03-06,Margherita Pizza,11.25
2025-11-28,Beef Tacos,9.75
2025-11-15,Spaghetti Bolognese,12.99
2025-11-12,Grilled Chicken Salad,10.49
2025-08-05,Veggie Burger,8.95
2025-07-31,Sushi Platter,15.99
2025-01-14,Margherita Pizza,11.25
2025-04-01,Sushi Platter,15.99
2025-11-09,Spaghetti Bolognese,12.99
2025-12-23,Veggie Burger,8.95
2025-12-22,Veggie Burger,8.95
2025-05-25,Chicken Alfredo,13.5
2025-11-04,Grilled Chicken Salad,10.49
2025-04-13,Sushi Platter,15.99
2025-09-27,Fish and Chips,11.99
2025-09-29,Chicken Alfredo,13.5
2025-09-01,Chicken Alfredo,13.5
Loading
Loading