Skip to content
Open
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
21 changes: 21 additions & 0 deletions samples/AIChat.AOAI/AIChat.AOAI.Api/AIChat.AOAI.Api.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<LangVersion>preview</LangVersion>
<NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;SKEXP0050;OPENAI001;SKEXP0010</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Azure.AI.OpenAI" Version="9.1.0-preview.1.25121.10" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.2.0" />
<PackageReference Include="CoreEx.AspNetCore" Version="3.30.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.41.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.11" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AIChat.AOAI.Business\AIChat.AOAI.Business.csproj" />
<ProjectReference Include="..\AIChat.AOAI.Common\AIChat.AOAI.Common.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* This file is automatically generated; any changes will be lost.
*/

namespace AIChat.AOAI.Api.Controllers;

/// <summary>
/// Provides the <see cref="Chat"/> Web API functionality.
/// </summary>
[Consumes(System.Net.Mime.MediaTypeNames.Application.Json)]
[Produces(System.Net.Mime.MediaTypeNames.Application.Json)]
public partial class ChatController : ControllerBase
{
private readonly WebApi _webApi;
private readonly IChatManager _manager;

/// <summary>
/// Initializes a new instance of the <see cref="ChatController"/> class.
/// </summary>
/// <param name="webApi">The <see cref="WebApi"/>.</param>
/// <param name="manager">The <see cref="IChatManager"/>.</param>
public ChatController(WebApi webApi, IChatManager manager)
{ _webApi = webApi.ThrowIfNull(); _manager = manager.ThrowIfNull(); ChatControllerCtor(); }

partial void ChatControllerCtor(); // Enables additional functionality to be added to the constructor.

/// <summary>
/// Creates a new <c>Chat</c>.
/// </summary>
/// <returns>The created <c>Chat</c>.</returns>
[HttpPost("chats", Name="Chat_Create")]
[AcceptsBody(typeof(Common.Entities.Chat))]
[ProducesResponseType(typeof(Common.Entities.Chat), (int)HttpStatusCode.Created)]
public Task<IActionResult> Create()
=> _webApi.PostWithResultAsync<Chat, Chat>(Request, p => _manager.CreateAsync(p.Value!), statusCode: HttpStatusCode.Created);

/// <summary>
/// Chat Completion.
/// </summary>
/// <param name="message">The Message.</param>
/// <returns>A resultant <c>ChatCompletionResponse</c>.</returns>
[HttpPost("chats/completion", Name="Chat_ChatCompletion")]
[ProducesResponseType(typeof(Common.Entities.ChatCompletionResponse), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
public Task<IActionResult> ChatCompletion(string? message)
=> _webApi.PostWithResultAsync<ChatCompletionResponse>(Request, p => _manager.ChatCompletionAsync(message), alternateStatusCode: HttpStatusCode.NoContent, operationType: CoreEx.OperationType.Unspecified);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* This file is automatically generated; any changes will be lost.
*/

using CommonRefDataNamespace = AIChat.AOAI.Common.Entities;

namespace AIChat.AOAI.Api.Controllers;

/// <summary>
/// Provides the <b>ReferenceData</b> Web API functionality.
/// </summary>
[Consumes(System.Net.Mime.MediaTypeNames.Application.Json)]
[Produces(System.Net.Mime.MediaTypeNames.Application.Json)]
public partial class ReferenceDataController : ControllerBase
{
private readonly ReferenceDataContentWebApi _webApi;
private readonly ReferenceDataOrchestrator _orchestrator;

/// <summary>
/// Initializes a new instance of the <see cref="ReferenceDataController"/> class.
/// </summary>
/// <param name="webApi">The <see cref="ReferenceDataContentWebApi"/>.</param>
/// <param name="orchestrator">The <see cref="ReferenceDataOrchestrator"/>.</param>
public ReferenceDataController(ReferenceDataContentWebApi webApi, ReferenceDataOrchestrator orchestrator)
{ _webApi = webApi.ThrowIfNull(); _orchestrator = orchestrator.ThrowIfNull(); }

/// <summary>
/// Gets all of the 'Role' reference data items that match the specified criteria.
/// </summary>
/// <param name="codes">The reference data code list.</param>
/// <param name="text">The reference data text (including wildcards).</param>
/// <returns>The 'Role' array.</returns>
[HttpGet("ref/roles", Name="ReferenceData_RoleGetAll")]
[ProducesResponseType(typeof(IEnumerable<CommonRefDataNamespace.Role>), (int)HttpStatusCode.OK)]
public Task<IActionResult> RoleGetAll([FromQuery] IEnumerable<string>? codes = default, string? text = default)
=> _webApi.GetAsync(Request, p => _orchestrator.GetWithFilterAsync<RefDataNamespace.Role>(codes, text, p.RequestOptions.IncludeInactive));

/// <summary>
/// Gets the reference data entries for the specified entities and codes from the query string; e.g: ref?entity=codeX,codeY&amp;entity2=codeZ&amp;entity3
/// </summary>
/// <returns>The 'ReferenceDataMultiDictionary'.</returns>
[HttpGet("ref", Name="ReferenceData_GetNamed")]
[ProducesResponseType(typeof(CoreEx.RefData.ReferenceDataMultiDictionary), (int)HttpStatusCode.OK)]
public Task<IActionResult> GetNamed() => _webApi.GetAsync(Request, p => _orchestrator.GetNamedAsync(p.RequestOptions));
}
23 changes: 23 additions & 0 deletions samples/AIChat.AOAI/AIChat.AOAI.Api/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
global using Azure.Monitor.OpenTelemetry.AspNetCore;
global using CoreEx;
global using CoreEx.AspNetCore.WebApis;
global using CoreEx.AspNetCore.HealthChecks;
global using CoreEx.Entities;
global using CoreEx.Events;
global using CoreEx.Http;
global using CoreEx.RefData;
global using CoreEx.Validation;
global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.Extensions.Caching.Memory;
global using Microsoft.OpenApi.Models;
global using OpenTelemetry.Trace;
global using System.Net;
global using System.Reflection;
global using AIChat.AOAI.Api;
global using AIChat.AOAI.Business;
global using AIChat.AOAI.Business.Data;
global using AIChat.AOAI.Business.Entities;
//global using AIChat.AOAI.Business.Validation;
global using RefDataNamespace = AIChat.AOAI.Business.Entities;
global using AzCosmos = Microsoft.Azure.Cosmos;
27 changes: 27 additions & 0 deletions samples/AIChat.AOAI/AIChat.AOAI.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.SemanticKernel;

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddEnvironmentVariables("AOAI_");

var startup = new Startup();
startup.ConfigureServices(builder.Services, builder.Environment);

// Add the semantic kernel
builder.Services.AddKernel()
.AddAzureOpenAIChatCompletion(
builder.Configuration["AzureOpenAI::ModelName"] ?? string.Empty,
builder.Configuration["AzureOpenAI::Endpoint"] ?? string.Empty,
builder.Configuration["AzureOpenAI::APIKey"] ?? string.Empty
);

builder.Services.AddTransient((serviceProvider) => {
return new Kernel(serviceProvider);
});

if (!builder.Environment.IsDevelopment())
builder.Services.AddOpenTelemetry().UseAzureMonitor().WithTracing(b => b.AddSource("CoreEx.*", "AIChat.AOAI.*"));

var app = builder.Build();
startup.Configure(app);

app.Run();
110 changes: 110 additions & 0 deletions samples/AIChat.AOAI/AIChat.AOAI.Api/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using Microsoft.SemanticKernel;

namespace AIChat.AOAI.Api;

/// <summary>
/// Represents the <b>startup</b> class.
/// </summary>
public class Startup
{
/// <summary>
/// The configure services method called by the runtime; use this method to add services to the container.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
public void ConfigureServices(IServiceCollection services, IWebHostEnvironment env)
{
// Add the core services.
services.AddSettings<AOAISettings>()
.AddExecutionContext()
.AddJsonSerializer()
.AddReferenceDataOrchestrator()
.AddReferenceDataContentWebApi()
.AddWebApi()
.AddJsonMergePatch()
.AddRequestCache()
.AddValidationTextProvider()
.AddValidators<AOAISettings>()
.AddMappers<AOAISettings>()
.AddSingleton<IIdentifierGenerator, IdentifierGenerator>();

// Add the cosmos database.
services.AddSingleton(sp =>
{
var settings = sp.GetRequiredService<AOAISettings>();
var cco = new AzCosmos.CosmosClientOptions { SerializerOptions = new AzCosmos.CosmosSerializationOptions { PropertyNamingPolicy = AzCosmos.CosmosPropertyNamingPolicy.CamelCase, IgnoreNullValues = true } };
return new AzCosmos.CosmosClient(settings.CosmosConnectionString, cco);
}).AddCosmosDb(sp =>
{
var settings = sp.GetRequiredService<AOAISettings>();
return new AOAICosmosDb(sp.GetRequiredService<AzCosmos.CosmosClient>().GetDatabase(settings.CosmosDatabaseId), sp.GetRequiredService<CoreEx.Mapping.IMapper>());
});

// Add the generated reference data services.
services.AddGeneratedReferenceDataManagerServices()
.AddGeneratedReferenceDataDataSvcServices()
.AddGeneratedReferenceDataDataServices();

// Add the generated entity services.
services.AddGeneratedManagerServices()
.AddGeneratedDataSvcServices()
.AddGeneratedDataServices();

// Add the event publishing; this will need to be updated from the null publisher to the actual as appropriate.
services.AddEventDataFormatter()
.AddCloudEventSerializer()
.AddNullEventPublisher();

// Add controllers.
services.AddControllers();

// Add health checks.
services.AddHealthChecks();

// Add Azure monitor open telemetry.
if (!env.IsDevelopment())
services.AddOpenTelemetry().UseAzureMonitor().WithTracing(b => b.AddSource("CoreEx.*", "AIChat.AOAI.*", "Microsoft.EntityFrameworkCore.*", "EntityFrameworkCore.*"));

// Add the swagger capabilities.
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "AIChat.AOAI API", Version = "v1" });
options.OperationFilter<AcceptsBodyOperationFilter>(); // Needed to support AcceptsBodyAttribute where body parameter not explicitly defined.
options.OperationFilter<PagingOperationFilter>(); // Needed to support PagingAttribute where PagingArgs parameter not explicitly defined.
options.OperationFilter<QueryOperationFilter>(); // Needed to support QueryAttribute where QueryArgs parameter not explicitly defined.
});
}

/// <summary>
/// The configure method called by the runtime; use this method to configure the HTTP request pipeline.
/// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
public void Configure(IApplicationBuilder app)
{
// Handle any unhandled exceptions.
app.UseWebApiExceptionHandler();

// Authenticate the user.
//app.UseAuthentication();

// Add Swagger as an endpoint and to serve the swagger-ui to the pipeline.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.RoutePrefix = ""; // Default as the root/home page.
c.SwaggerEndpoint("/swagger/v1/swagger.json", "AIChat.AOAI");
});

// Add execution context set up to the pipeline.
app.UseExecutionContext();
app.UseReferenceDataOrchestrator();

// Add health checks.
app.UseHealthChecks("/health");
app.UseHealthChecks("/health/detailed", new HealthCheckOptions { ResponseWriter = HealthReportStatusWriter.WriteJsonResults }); // Secure with permissions / or remove given data returned.

// Use controllers.
app.UseRouting();
//app.UseAuthorization();
app.UseEndpoints(endpoints => endpoints.MapControllers());
}
}
27 changes: 27 additions & 0 deletions samples/AIChat.AOAI/AIChat.AOAI.Api/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"AllowedHosts": "*",
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
// Set using environment variables: 'AOAI_CosmosConnectionString' and 'AOAI_CosmosDatabaseId'.
"CosmosConnectionString": "AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;AccountEndpoint=https://localhost:8081",
"CosmosDatabaseId": "Chats",
"Invokers": {
"Default": {
"TracingEnabled": true,
"LoggingEnabled": true
},
"CoreEx.Validation.ValidationInvoker": {
"TracingEnabled": false,
"LoggingEnabled": false
}
},
"AzureOpenAI:": {
"ModelName": "<your-model-name>",
"Endpoint": "https://<your-ai-resource-name>.openai.azure.com/",
"APIKey": "<your-api-key>"
},
"IncludeExceptionInResult": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>preview</LangVersion>
<NoWarn>$(NoWarn);CA2007;IDE1006;SKEXP0001;SKEXP0110;SKEXP0050;OPENAI001;SKEXP0010</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CoreEx" Version="3.30.0" />
<PackageReference Include="CoreEx.Cosmos" Version="3.30.0" />
<PackageReference Include="CoreEx.Validation" Version="3.30.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.41.0" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureOpenAI" Version="1.41.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Validation\" />
</ItemGroup>
</Project>
19 changes: 19 additions & 0 deletions samples/AIChat.AOAI/AIChat.AOAI.Business/AOAISettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace AIChat.AOAI.Business;

/// <summary>
/// Provides the <see cref="IConfiguration"/> settings.
/// </summary>
/// <param name="configuration">The <see cref="IConfiguration"/>.</param>
public class AOAISettings(IConfiguration configuration) : SettingsBase(configuration, ["AOAI/", "Common/"])
{

/// <summary>
/// Gets the CosmosDB connection string.
/// </summary>
public string CosmosConnectionString => GetRequiredValue<string>();

/// <summary>
/// Gtes the CosmosDB database identifier.
/// </summary>
public string CosmosDatabaseId => GetRequiredValue<string>();
}
33 changes: 33 additions & 0 deletions samples/AIChat.AOAI/AIChat.AOAI.Business/Data/AOAICosmosDb.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.Azure.Cosmos;

namespace AIChat.AOAI.Business.Data;

/// <summary>
/// Provides the <b>AIChat.AOAI</b> CosmosDb client.
/// </summary>
/// <param name="database">The <see cref="Database"/>.</param>
/// <param name="mapper">The <see cref="IMapper"/>.</param>
public class AOAICosmosDb : CosmosDb
{
/// <summary>
/// Gets the <c>Person</c> container identifier.
/// </summary>
public const string ChatContainerId = "Chats";

private readonly Lazy<CosmosDbContainer<Chat, Model.Chat>> _chats;

/// <summary>
/// Initializes a new instance of the <see cref="AOAICosmosDb"/> class.
/// </summary>
/// <param name="database">The CosmosDb <see cref="Database"/>.</param>
/// <param name="mapper">The <see cref="IMapper"/>.</param>
public AOAICosmosDb(Database database, IMapper mapper) : base(database, mapper)
{
_chats = new(() => Container<Chat, Model.Chat>(ChatContainerId));
}

/// <summary>
/// Exposes <see cref="Chat"/> entity from the <see cref="ChatContainerId"/> container.
/// </summary>
public CosmosDbContainer<Chat, Model.Chat> Chats => _chats.Value;
}
Loading
Loading