Skip to content

Commit

Permalink
♻️ Move Graph client to DI (#65)
Browse files Browse the repository at this point in the history
* DI the Graph client
Remove a bunch of comments
Work on teams call data

* Thanks rider

* Remove logs
  • Loading branch information
bradystroud authored Oct 10, 2023
1 parent b3a207a commit 6b6c584
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 72 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"dotnet.defaultSolution": "TimesheetGPT.sln"
}
48 changes: 28 additions & 20 deletions src/TimesheetGPT.Core/Services/GraphService.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
using Microsoft.Graph;
using Microsoft.Graph.Models;
using Microsoft.Graph.Models.ODataErrors;
using TimesheetGPT.Core.Interfaces;
using TimesheetGPT.Core.Models;

namespace TimesheetGPT.Core.Services;

public class GraphService : IGraphService
{
private GraphServiceClient _client;
private readonly GraphServiceClient _client;

public GraphService(GraphServiceClient client)
{
if (client == null)
throw new ArgumentNullException(nameof(client));
ArgumentNullException.ThrowIfNull(client);

_client = client ?? throw new ArgumentNullException(nameof(client));
}
Expand All @@ -24,7 +24,6 @@ public async Task<List<string>> GetEmailSubjects(DateTime date)
var dateUtc = date.ToUniversalTime();
var nextDayUtc = nextDay.ToUniversalTime();

// GET https://graph.microsoft.com/v1.0/me/mailFolders('sentitems')/messages
var messages = await _client.Me.MailFolders["sentitems"].Messages
.GetAsync(rc =>
{
Expand Down Expand Up @@ -52,7 +51,7 @@ public async Task<List<Meeting>> GetMeetings(DateTime date)
var nextDay = date.AddDays(1);
var dateUtc = date.ToUniversalTime();
var nextDayUtc = nextDay.ToUniversalTime();

var meetings = await _client.Me.CalendarView.GetAsync(rc =>
{
rc.QueryParameters.Top = 999;
Expand All @@ -61,7 +60,7 @@ public async Task<List<Meeting>> GetMeetings(DateTime date)
rc.QueryParameters.Orderby = new[] { "start/dateTime" };
rc.QueryParameters.Select = new[] { "subject", "start", "end", "occurrenceId" };
});

if (meetings is { Value.Count: > 1 })
{
return meetings.Value.Select(m => new Meeting
Expand All @@ -72,28 +71,37 @@ public async Task<List<Meeting>> GetMeetings(DateTime date)
// Sender = m.EmailAddress.Address TODO: Why is Organizer and attendees null? permissions?
}).ToList();
}

return new List<Meeting>(); //slack
}
public async Task<List<TeamsCall>> GetTeamsCalls(DateTime date) {
public async Task<List<TeamsCall>> GetTeamsCalls(DateTime date)
{
var nextDay = date.AddDays(1);
var dateUtc = date.ToUniversalTime();
var nextDayUtc = nextDay.ToUniversalTime();

var calls = await _client.Communications.CallRecords.GetAsync(rc =>
{
rc.QueryParameters.Top = 999;
rc.QueryParameters.Orderby = new[] { "start/dateTime" };
rc.QueryParameters.Select = new[] { "subject", "start", "end", "occurrenceId" };
});

if (calls is { Value.Count: > 1 })
try
{
return calls.Value.Select(m => new TeamsCall
var calls = await _client.Communications.CallRecords.GetAsync(rc =>
{
Attendees = m.Participants.Select(p => p.User.DisplayName).ToList(),
Length = m.EndDateTime - m.StartDateTime ?? TimeSpan.Zero,
}).ToList();
rc.QueryParameters.Top = 999;
rc.QueryParameters.Orderby = new[] { "startDateTime" };
rc.QueryParameters.Select = new[] { "startDateTime", "endDateTime", "participants" };
rc.QueryParameters.Filter = $"startDateTime ge {dateUtc:o} and endDateTime lt {nextDayUtc:o}";
});

if (calls is { Value.Count: > 1 })
{
return calls.Value.Select(m => new TeamsCall
{
Attendees = m.Participants.Select(p => p.User.DisplayName).ToList(),
Length = m.EndDateTime - m.StartDateTime ?? TimeSpan.Zero,
}).ToList();
}
}
catch (ODataError e)
{
throw new Exception("Need CallRecords.Read.All scopes", e);
}

return new List<TeamsCall>();
Expand Down
8 changes: 2 additions & 6 deletions src/TimesheetGPT.Core/Services/SemKerAiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ public class SemKerAiService : IAiService
private readonly string _apiKey;
public SemKerAiService(IConfiguration configuration)
{
if (configuration == null)
throw new ArgumentNullException(nameof(configuration));

ArgumentNullException.ThrowIfNull(configuration);

_apiKey = configuration["OpenAI:ApiKey"] ?? "";
}

public async Task<string> GetSummary(string text, string extraPrompts, string additionalNotes = "")
{
Console.WriteLine(text);
var builder = new KernelBuilder();

// builder.WithAzureChatCompletionService(
Expand All @@ -43,8 +41,6 @@ public async Task<string> GetSummary(string text, string extraPrompts, string ad

var summary = await summarizeFunction.InvokeAsync(context);

Console.WriteLine(summary.ModelResults);

return summary.Result;
}
}
20 changes: 8 additions & 12 deletions src/TimesheetGPT.Core/Services/TimesheetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,18 @@

namespace TimesheetGPT.Core.Services;

public class TimesheetService
public class TimesheetService(IAiService aiService, GraphServiceClient graphServiceClient)
{
private readonly IAiService _aiService;

public TimesheetService(IAiService aiService)
public async Task<SummaryWithRaw> GenerateSummary(DateTime date, string extraPrompts = "", string additionalNotes = "")
{
_aiService = aiService;
}

public async Task<SummaryWithRaw> GenerateSummary(DateTime date, GraphServiceClient client, string extraPrompts = "", string additionalNotes = "")
{
IGraphService graphService = new GraphService(client);
var graphService = new GraphService(graphServiceClient);

var emailSubjects = await graphService.GetEmailSubjects(date);
var meetings = await graphService.GetMeetings(date);
// var calls = await graphService.GetTeamsCalls(date);
// TODO: SSW needs to allow the CallRecords.Read.All scope for this to work

var summary = await _aiService.GetSummary(StringifyData(emailSubjects, meetings), extraPrompts, additionalNotes);
var summary = await aiService.GetSummary(StringifyData(emailSubjects, meetings), extraPrompts, additionalNotes);

return new SummaryWithRaw
{
Expand All @@ -32,14 +27,15 @@ public async Task<SummaryWithRaw> GenerateSummary(DateTime date, GraphServiceCli
};
}

private string StringifyData(List<string> emails, List<Meeting> meetings)
private string StringifyData(IEnumerable<string> emails, IList<Meeting> meetings)
{
var result = "Sent emails (subject) \n";
foreach (var email in emails)
{
result += email + "\n";
}
result += "\n Calendar Events (name - length) \n";

foreach (var meeting in meetings)
{
result += $"{meeting.Name} - {meeting.Length} \n";
Expand Down
5 changes: 1 addition & 4 deletions src/TimesheetGPT.Gateway/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@
builder.Configuration.AddUserSecrets(typeof(Program).Assembly);

builder.Services.AddTimesheetGptUi(builder.Configuration);
/*
builder.Services.AddTimesheetGptApi(builder.Configuration);
*/

var app = builder.Build();

/*
app.UseTimesheetGptApi();
*/

app.UseTimesheetGptUi();

app.Run();
34 changes: 6 additions & 28 deletions src/TimesheetGPT.WebAPI/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;

using TimesheetGPT.WebAPI.Endpoints;

namespace TimesheetGPT.WebAPI;
Expand All @@ -11,44 +11,22 @@ public static class DependencyInjection
{
public static IServiceCollection AddTimesheetGptApi(this IServiceCollection services, IConfiguration config)
{
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();

services.AddMicrosoftIdentityWebApiAuthentication(config, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();

// Get tenantId, clientId and clientSecret from appsettings.json
// and pass them to GraphService
//
// var tenantId = configuration["AzureAd:TenantId"];
// var clientId = configuration["AzureAd:ClientId"];
// var clientSecret = configuration["AzureAd:ClientSecret"];
//
// // ensure the above values are set
// if (string.IsNullOrEmpty(tenantId) ||
// string.IsNullOrEmpty(clientId) ||
// string.IsNullOrEmpty(clientSecret))
// {
// throw new Exception("TenantId, ClientId and ClientSecret must be set in appsettings.json");
// }


return services;
}

public static WebApplication UseTimesheetGptApi(this WebApplication app)
{
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.MapGetSubjects();

app.MapGetSubjects();

return app;
}
}
}
2 changes: 1 addition & 1 deletion src/TimesheetGPT.WebUI/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
return;
}
var dateTime = _date ?? DateTime.Today;
var summary = await TimesheetService.GenerateSummary(dateTime, GraphServiceClient, _extraPrompt ?? "", _additionalNotes);
var summary = await TimesheetService.GenerateSummary(dateTime, _extraPrompt ?? "", _additionalNotes);

_emailSubjects = summary.Emails;
_meetings = summary.Meetings;
Expand Down
1 change: 0 additions & 1 deletion src/TimesheetGPT.WebUI/Shared/ResultCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
catch (Exception e)
{
Snackbar.Add("Failed to copy summary to clipboard", Severity.Warning);
Console.WriteLine(e.Message);
}
}
}

0 comments on commit 6b6c584

Please sign in to comment.