diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..fe1152b
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,30 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
+!**/.gitignore
+!.git/HEAD
+!.git/config
+!.git/packed-refs
+!.git/refs/heads/**
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..98232e4
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,4 @@
+[*.cs]
+
+# SKEXP0070: Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+dotnet_diagnostic.SKEXP0070.severity = silent
diff --git a/AuthMiddleware.cs b/AuthMiddleware.cs
new file mode 100644
index 0000000..350eb19
--- /dev/null
+++ b/AuthMiddleware.cs
@@ -0,0 +1,11 @@
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+
+namespace ChatApi
+{
+ public class AuthMiddleware
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ }
+ }
+}
diff --git a/ChatApi.csproj b/ChatApi.csproj
new file mode 100644
index 0000000..2d9ea86
--- /dev/null
+++ b/ChatApi.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net8.0
+ enable
+ enable
+ 10e5023f-8f45-46d6-8637-bc2127842068
+ Linux
+ .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ChatApi.csproj.user b/ChatApi.csproj.user
new file mode 100644
index 0000000..983ecfc
--- /dev/null
+++ b/ChatApi.csproj.user
@@ -0,0 +1,9 @@
+
+
+
+ http
+
+
+ ProjectDebugger
+
+
\ No newline at end of file
diff --git a/ChatApi.http b/ChatApi.http
new file mode 100644
index 0000000..b2d56ee
--- /dev/null
+++ b/ChatApi.http
@@ -0,0 +1,6 @@
+@ChatApi_HostAddress = http://localhost:5020
+
+GET {{ChatApi_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/ChatApi.sln b/ChatApi.sln
new file mode 100644
index 0000000..7f588b2
--- /dev/null
+++ b/ChatApi.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.10.35122.118
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatApi", "ChatApi.csproj", "{B5287933-4BFA-4EC1-8522-393864C46B1F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B5287933-4BFA-4EC1-8522-393864C46B1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B5287933-4BFA-4EC1-8522-393864C46B1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B5287933-4BFA-4EC1-8522-393864C46B1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B5287933-4BFA-4EC1-8522-393864C46B1F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {332EC001-9CEA-4261-9DE0-110EEB502728}
+ EndGlobalSection
+EndGlobal
diff --git a/ChatHistoryService.cs b/ChatHistoryService.cs
new file mode 100644
index 0000000..5eee0ea
--- /dev/null
+++ b/ChatHistoryService.cs
@@ -0,0 +1,92 @@
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using System.Text.Json;
+
+namespace ChatApi
+{
+ public class ChatHistoryService
+ {
+ private readonly Dictionary _keyValues = new Dictionary();
+ public ChatHistoryService()
+ {
+ }
+
+ public ChatHistory Get(string sessionId)
+ {
+ //var msg = new List();
+ ////msg.Add(new ChatMessageContent(AuthorRole.System, "Your name is SuperChat. \nYou only generate answers using portuguese.\nYou are friendly and polite.\nYou speak only Brazilian Portuguese.\nYou never create a response in English. Always brazilian portuguese."));
+ //msg.Add(new ChatMessageContent(AuthorRole.System, "Seu nome é SuperChat."));
+ //msg.Add(new ChatMessageContent(AuthorRole.System, "Você só gera respostas usando português do Brasil."));
+ //msg.Add(new ChatMessageContent(AuthorRole.System, "Você fala apenas português brasileiro."));
+ //msg.Add(new ChatMessageContent(AuthorRole.System, "Você nunca cria respostas em inglês, mas sempre em português brasileiro."));
+ //string json = JsonSerializer.Serialize(msg);
+ //var history = new ChatHistory(JsonSerializer.Deserialize>(json));
+
+ //return history;
+
+ if (_keyValues.ContainsKey(sessionId))
+ {
+ var history = _keyValues[sessionId];
+ return history;
+ }
+ else
+ {
+ var msg = new List();
+ TestePrompt(msg);
+ string json = JsonSerializer.Serialize(msg);
+ var history = new ChatHistory(JsonSerializer.Deserialize>(json));
+ _keyValues[sessionId] = history;
+ return _keyValues[sessionId];
+ }
+ }
+
+ public ChatHistory GetSumarizer(string sessionId)
+ {
+ if (_keyValues.ContainsKey(sessionId))
+ {
+ var history = _keyValues[sessionId];
+ return history;
+ }
+ else
+ {
+ var msg = new List();
+ PromptIan(msg);
+ string json = JsonSerializer.Serialize(msg);
+ var history = new ChatHistory(JsonSerializer.Deserialize>(json));
+ _keyValues[sessionId] = history;
+ return _keyValues[sessionId];
+ }
+ }
+
+ public void UpdateHistory(string sessionId, ChatHistory history)
+ {
+ _keyValues[sessionId] = history;
+ }
+
+ public void TestePromptBot(List msg)
+ {
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Seu nome é Rosa, uma vendedora de bolos que está atendendo seus clientes. "));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Você tem apenas os seguintes sabores de bolo: chocolate, baunilha e morango. "));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Excepcionalmente hoje, o sabor morango está fora de estoque. Você não tem mais morangos. "));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Cada fatia de bolo custa 5 reais. \n"));
+ msg.Add(new ChatMessageContent(AuthorRole.User, "Responda sempre em portugues do Brasil as minhas perguntas."));
+ }
+
+ public void PromptIan(List msg)
+ {
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Seu nome é Ian, um assistente ajuda empresas de Consultoria e RH. "));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Você responde sempre em português do Brasil."));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Em breve, você será capaz de consultar o linkedin."));
+ msg.Add(new ChatMessageContent(AuthorRole.User, "Use sempre portugues do Brasil."));
+ }
+
+ public void TestePrompt(List msg)
+ {
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Seu nome é Ian."));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Você só gera respostas usando português do Brasil."));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Você fala apenas português brasileiro."));
+ msg.Add(new ChatMessageContent(AuthorRole.System, "Você nunca cria respostas em inglês, mas sempre em português brasileiro."));
+ msg.Add(new ChatMessageContent(AuthorRole.User, "Responda sempre em portugues do Brasil as minhas perguntas."));
+ }
+ }
+}
diff --git a/ChatHistoryStore.cs b/ChatHistoryStore.cs
new file mode 100644
index 0000000..16f992c
--- /dev/null
+++ b/ChatHistoryStore.cs
@@ -0,0 +1,7 @@
+namespace ChatApi
+{
+ public class ChatHistoryStore
+ {
+
+ }
+}
diff --git a/ChatRequest.cs b/ChatRequest.cs
new file mode 100644
index 0000000..b6dd109
--- /dev/null
+++ b/ChatRequest.cs
@@ -0,0 +1,7 @@
+using System;
+
+public class ChatRequest
+{
+ public string SessionId { get; set; } = string.Empty;
+ public string Message { get; set; } = string.Empty;
+}
diff --git a/Controllers/ChatController.cs b/Controllers/ChatController.cs
new file mode 100644
index 0000000..2a16dfc
--- /dev/null
+++ b/Controllers/ChatController.cs
@@ -0,0 +1,95 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using Microsoft.SemanticKernel.Embeddings;
+using Microsoft.SemanticKernel.Memory;
+using Microsoft.SemanticKernel.Connectors.InMemory;
+using System.Globalization;
+using System.Text;
+using MongoDB.Driver;
+using System.IO;
+using System.Text.RegularExpressions;
+using ChatApi.Services;
+using ChatApi.Services.ResponseService;
+using ChatApi.Services.Classifier;
+using Microsoft.AspNetCore.Authorization;
+using System.Security.Claims;
+using ChatApi.Models;
+
+#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+namespace ChatApi.Controllers
+{
+ [Authorize]
+ [ApiController]
+ [Route("[controller]")]
+ public class ChatController : ControllerBase
+ {
+ private readonly ILogger _logger;
+ private readonly TextFilter _textFilter;
+ private readonly ResponseFactory _responseFactory;
+ private readonly ClassifierPersistence _classifierPersistence;
+
+ public ChatController(
+ ILogger logger,
+ TextFilter textFilter,
+ ResponseFactory responseFactory,
+ ClassifierPersistence classifierPersistence)
+ {
+ _logger = logger;
+ _textFilter = textFilter;
+ _responseFactory = responseFactory;
+ _classifierPersistence = classifierPersistence;
+ }
+
+ [HttpGet(Name = "Response")]
+ public async Task Get([FromQuery] ChatRequest chatRequest)
+ {
+ var userData = UserData.Create(User);
+ var textClassifier = new TextClassifier(_textFilter, _classifierPersistence);
+ var textType = await textClassifier.ClassifyQuestion(chatRequest.SessionId, chatRequest.Message);
+ var responseText = _responseFactory.GetService(textType);
+ var response = await responseText.GetResponse(HttpContext, userData, chatRequest.SessionId, chatRequest.Message);
+ return response;
+ }
+
+ [HttpPost(Name = "LoadDBData")]
+ public async Task SaveData([FromQuery] DBLoadRequest loadRequest)
+ {
+ //string readText = System.IO.File.ReadAllText("C:\\vscode\\ChatApi\\bin\\Debug\\net8.0\\Servicos.txt");
+ string readText = loadRequest.Content;
+ await SalvarTextoComEmbeddingNoMongoDB(readText);
+ }
+
+
+ async Task SalvarTextoComEmbeddingNoMongoDB(string textoCompleto)
+ {
+ var textoArray = new List();
+ string[] textolinhas = textoCompleto.Split(
+ new string[] { "\n" },
+ StringSplitOptions.None
+ );
+
+ var title = textolinhas[0];
+
+ var builder = new StringBuilder();
+ foreach (string line in textolinhas)
+ {
+ if (line.StartsWith("**") || line.StartsWith("\r**"))
+ {
+ if (builder.Length > 0)
+ {
+ textoArray.Add(title.Replace("**", "").Replace("\r", "") + ": " + Environment.NewLine + builder.ToString());
+ builder = new StringBuilder();
+ title = line;
+ }
+ }
+ else
+ {
+ builder.AppendLine(line);
+ }
+ }
+ }
+ }
+}
+#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
diff --git a/Controllers/ChatController.cs~RF39ccb1.TMP b/Controllers/ChatController.cs~RF39ccb1.TMP
new file mode 100644
index 0000000..f682375
--- /dev/null
+++ b/Controllers/ChatController.cs~RF39ccb1.TMP
@@ -0,0 +1,68 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using Microsoft.SemanticKernel.Embeddings;
+using Microsoft.SemanticKernel.Memory;
+using Microsoft.SemanticKernel.Connectors.InMemory;
+
+#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+namespace ChatApi.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class ChatController : ControllerBase
+ {
+ private readonly ILogger _logger;
+ private readonly ChatHistoryService _chatHistoryService;
+ private readonly IChatCompletionService _chatCompletionService;
+ private readonly Kernel _kernel;
+
+ public ChatController(ILogger logger, ChatHistoryService chatHistoryService, IChatCompletionService chatCompletionService, Kernel kernel)
+ {
+ _logger = logger;
+ _chatHistoryService = chatHistoryService;
+ _chatCompletionService = chatCompletionService;
+ _kernel = kernel;
+ }
+
+ [HttpGet(Name = "Response")]
+ public async Task Get([FromQuery] ChatRequest chatRequest)
+ {
+ var stopWatch = new System.Diagnostics.Stopwatch();
+
+ stopWatch.Start();
+ SessionIdStore sessionIdStore = new SessionIdStore(HttpContext);
+ var sessionId = sessionIdStore.GetSessionId();
+ var history = _chatHistoryService.Get(sessionId);
+
+ history.AddUserMessage(chatRequest.Message);
+
+ var embeddingGenerator = _kernel.GetRequiredService();
+ // Setup a memory store and create a memory out of it
+#pragma warning disable SKEXP0020 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ var memoryStore = new InMemoryVectorStore();
+#pragma warning restore SKEXP0020 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+ var memory = new SemanticTextMemory(memoryStore, embeddingGenerator);
+ // Loading it for Save, Recall and other methods
+ _kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
+ string MemoryCollectionName = "MyCustomDataCollection";
+
+ var option = new PromptExecutionSettings
+ {
+
+ Memory = memory,
+ MemoryCollectionName = MemoryCollectionName
+ };
+
+ var response = await _chatCompletionService.GetChatMessageContentAsync(history);
+ history.AddMessage(response.Role, response.Content ?? "");
+
+ _chatHistoryService.UpdateHistory(sessionId, history);
+
+ stopWatch.Stop();
+ return $"{response.Content ?? ""}\n\nTempo: {stopWatch.ElapsedMilliseconds/1000}s";
+ }
+ }
+}
+#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
diff --git a/DBLoadRequest.cs b/DBLoadRequest.cs
new file mode 100644
index 0000000..8be824e
--- /dev/null
+++ b/DBLoadRequest.cs
@@ -0,0 +1,7 @@
+namespace ChatApi
+{
+ public class DBLoadRequest
+ {
+ public string Content { get; set; } = string.Empty;
+ }
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..f4b0d66
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,25 @@
+#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
+USER app
+WORKDIR /app
+EXPOSE 8080
+EXPOSE 8081
+
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+COPY ["ChatApi.csproj", "."]
+RUN dotnet restore "./ChatApi.csproj"
+COPY . .
+WORKDIR "/src/."
+RUN dotnet build "./ChatApi.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "./ChatApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "ChatApi.dll"]
\ No newline at end of file
diff --git a/DomvsDatabaseSettings.cs b/DomvsDatabaseSettings.cs
new file mode 100644
index 0000000..eeb97bd
--- /dev/null
+++ b/DomvsDatabaseSettings.cs
@@ -0,0 +1,15 @@
+namespace ChatApi
+{
+ public class DomvsDatabaseSettings
+ {
+ public string ConnectionString { get; set; } = null!;
+
+ public string DatabaseName { get; set; } = null!;
+
+ public string SharepointCollectionName { get; set; } = null!;
+
+ public string ChatBotRHCollectionName { get; set; } = null!;
+
+ public string ClassifierCollectionName { get; set; } = null!;
+ }
+}
diff --git a/Infra/Result.cs b/Infra/Result.cs
new file mode 100644
index 0000000..0c9055a
--- /dev/null
+++ b/Infra/Result.cs
@@ -0,0 +1,56 @@
+namespace ChatApi.Infra
+{
+ public class Result
+ {
+ protected Result(bool success, string error)
+ {
+ if (success && error != string.Empty)
+ throw new InvalidOperationException();
+ if (!success && error == string.Empty)
+ throw new InvalidOperationException();
+ Success = success;
+ Error = error;
+ }
+
+ public bool Success { get; }
+ public string Error { get; }
+ public bool IsFailure => !Success;
+
+ public static Result Fail(string message)
+ {
+ return new Result(false, message);
+ }
+
+ public static Result Fail(string message)
+ {
+ return new Result(default, false, message);
+ }
+
+ public static Result Ok()
+ {
+ return new Result(true, string.Empty);
+ }
+
+ public static Result Ok(T value)
+ {
+ return new Result(value, true, string.Empty);
+ }
+ }
+
+ public class Result : Result
+ {
+ protected internal Result(T value, bool success, string error)
+ : base(success, error)
+ {
+ Value = value;
+ }
+
+ protected internal Result(T value)
+ : base(true, "")
+ {
+ Value = value;
+ }
+
+ public T Value { get; set; }
+ }
+}
diff --git a/Models/UserData.cs b/Models/UserData.cs
new file mode 100644
index 0000000..a1e9052
--- /dev/null
+++ b/Models/UserData.cs
@@ -0,0 +1,30 @@
+using System.Security.Claims;
+
+namespace ChatApi.Models
+{
+ public class UserData
+ {
+ private UserData()
+ {
+ }
+
+ public string Email { get; set; }
+ public string Name { get; set; }
+
+ public static UserData Create(ClaimsPrincipal user)
+ {
+ var email = user.FindFirst(ClaimTypes.Email)?.Value
+ ?? user.FindFirst("email")?.Value;
+
+ var name = user.FindFirst(ClaimTypes.Name)?.Value
+ ?? user.FindFirst("name")?.Value;
+
+
+ return new UserData
+ {
+ Email = email,
+ Name = name
+ };
+ }
+ }
+}
diff --git a/Models/UserData.cs~RF3dab6a.TMP b/Models/UserData.cs~RF3dab6a.TMP
new file mode 100644
index 0000000..c6f962b
--- /dev/null
+++ b/Models/UserData.cs~RF3dab6a.TMP
@@ -0,0 +1,30 @@
+using System.Security.Claims;
+
+namespace ChatApi.Models
+{
+ public class UserData
+ {
+ private UserData()
+ {
+ }
+
+ public int Email { get; set; }
+ public int Name { get; set; }
+
+ public static UserData Create(ClaimsPrincipal user)
+ {
+ var email = user.FindFirst(ClaimTypes.Email)?.Value
+ ?? user.FindFirst("email")?.Value;
+
+ var name = user.FindFirst(ClaimTypes.Name)?.Value
+ ?? user.FindFirst("name")?.Value;
+
+
+ return new UserData
+ {
+ Email = email,
+ Name = name
+ };
+ }
+ }
+}
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..52e4030
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,157 @@
+using ChatApi;
+using ChatApi.Services;
+using ChatApi.Services.Bot;
+using ChatApi.Services.Bot.Structs;
+using ChatApi.Services.Classifier;
+using ChatApi.Services.ResponseService;
+using ChatApi.Settings;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.IdentityModel.Tokens;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using OllamaSharp;
+
+#pragma warning disable SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+
+builder.Services.AddControllers();
+// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+
+builder.Services.Configure(
+builder.Configuration.GetSection("DomvsDatabase"));
+
+builder.Services.Configure(
+builder.Configuration.GetSection("ChatRHSettings"));
+
+builder.Services.AddScoped();
+builder.Services.AddSingleton();
+builder.Services.AddScoped();
+builder.Services.AddSingleton();
+builder.Services.AddScoped();
+
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+
+
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinydolphin", new Uri("http://localhost:11435"));
+//var apiClient = new OllamaApiClient(new Uri("http://localhost:11435"), "tinydolphin");
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinydolphin", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinyllama", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("starling-lm", new Uri("http://localhost:11435"));
+
+//ServerSpace - GPT Service
+builder.Services.AddOpenAIChatCompletion("openchat-3.5-0106", new Uri("https://gpt.serverspace.com.br/v1/chat/completions"), "tIAXVf3AkCkkpSX+PjFvktfEeSPyA1ZYam50UO3ye/qmxVZX6PIXstmJsLZXkQ39C33onFD/81mdxvhbGHm7tQ==");
+
+builder.Services.AddOllamaTextEmbeddingGeneration("all-minilm", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOpenAIChatCompletion("gpt-4o-mini", "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");
+//builder.Services.AddGoogleAIGeminiChatCompletion("gemini-1.5-flash-latest", "AIzaSyDKBMX5yW77vxJFVJVE-5VLxlQRxCepck8");
+
+//Anthropic / Claude
+//builder.Services.AddAnthropicChatCompletion(
+// modelId: "claude-3-5-sonnet-latest", // ou outro modelo Claude desejado
+// apiKey: "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"
+//);
+
+builder.Services.AddKernel();
+//builder.Services.AddKernel()
+// .AddOllamaChatCompletion("phi3", new Uri("http://localhost:11435"))
+// .AddOllamaTextEmbeddingGeneration()
+// .Build();
+
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://192.168.0.150:11436"));
+
+builder.Services.AddHttpClient();
+
+var tenantId = builder.Configuration.GetSection("AppTenantId");
+var clientId = builder.Configuration.GetSection("AppClientID");
+builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(options =>
+ {
+ options.Authority = $"https://login.microsoftonline.com/{tenantId}/v2.0";
+ options.Audience = "api://" + clientId; // Client ID da sua API
+
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidateAudience = true,
+ ValidateLifetime = true,
+ ValidateIssuerSigningKey = true,
+ ValidIssuer = $"https://login.microsoftonline.com/{tenantId}/v2.0",
+ ValidAudience = "api://" + clientId
+ };
+ });
+
+builder.Services.AddControllers();
+
+//builder.Services.AddAuthentication(options =>
+// {
+// options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
+// options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
+// })
+// .AddJwtBearer(options =>
+// {
+// // Configurações anteriores...
+
+// // Eventos para log e tratamento de erros
+// options.Events = new JwtBearerEvents
+// {
+// OnAuthenticationFailed = context =>
+// {
+// // Log de erros de autenticação
+// Console.WriteLine($"Erro de autenticação: {context.Exception.Message}");
+// return Task.CompletedTask;
+// },
+// OnTokenValidated = context =>
+// {
+// // Validações adicionais se necessário
+// return Task.CompletedTask;
+// }
+// };
+// });
+
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseSwagger();
+ app.UseSwaggerUI();
+}
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.MapControllers();
+
+app.Use(async (context, next) =>
+{
+ var cookieOpt = new CookieOptions()
+ {
+ Path = "/",
+ Expires = DateTimeOffset.UtcNow.AddDays(1),
+ IsEssential = true,
+ HttpOnly = false,
+ Secure = false,
+ };
+
+ await next();
+});
+
+app.UseAuthentication();
+app.UseAuthorization();
+
+app.Run();
+
+#pragma warning restore SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
diff --git a/Program.cs~RF419917.TMP b/Program.cs~RF419917.TMP
new file mode 100644
index 0000000..b9099d9
--- /dev/null
+++ b/Program.cs~RF419917.TMP
@@ -0,0 +1,61 @@
+using ChatApi;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using OllamaSharp;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+
+builder.Services.AddControllers();
+// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+
+builder.Services.AddSingleton();
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinydolphin", new Uri("http://localhost:11435"));
+//var apiClient = new OllamaApiClient(new Uri("http://localhost:11435"), "tinydolphin");
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinydolphin", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinyllama", new Uri("http://localhost:11435"));
+builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+builder.Services.AddOllamaTextEmbeddingGeneration("all-minilm", new Uri("http://localhost:11435"));
+builder.Services.AddKernel();
+//builder.Services.AddKernel()
+// .AddOllamaChatCompletion("phi3", new Uri("http://localhost:11435"))
+// .AddOllamaTextEmbeddingGeneration()
+// .Build();
+
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://192.168.0.150:11436"));
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseSwagger();
+ app.UseSwaggerUI();
+}
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.MapControllers();
+
+app.Use(async (context, next) =>
+{
+ var cookieOpt = new CookieOptions()
+ {
+ Path = "/",
+ Expires = DateTimeOffset.UtcNow.AddDays(1),
+ IsEssential = true,
+ HttpOnly = false,
+ Secure = false,
+ };
+
+ await next();
+});
+
+app.Run();
diff --git a/Program.cs~RF68750a0.TMP b/Program.cs~RF68750a0.TMP
new file mode 100644
index 0000000..e76aa24
--- /dev/null
+++ b/Program.cs~RF68750a0.TMP
@@ -0,0 +1,98 @@
+using ChatApi;
+using ChatApi.Services;
+using ChatApi.Services.Bot;
+using ChatApi.Services.Bot.Structs;
+using ChatApi.Services.Classifier;
+using ChatApi.Services.ResponseService;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using OllamaSharp;
+
+#pragma warning disable SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+
+builder.Services.AddControllers();
+// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+
+builder.Services.Configure(
+builder.Configuration.GetSection("DomvsDatabase"));
+
+builder.Services.AddScoped();
+builder.Services.AddSingleton();
+builder.Services.AddScoped();
+builder.Services.AddSingleton();
+builder.Services.AddScoped();
+
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+
+
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinydolphin", new Uri("http://localhost:11435"));
+//var apiClient = new OllamaApiClient(new Uri("http://localhost:11435"), "tinydolphin");
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinydolphin", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("tinyllama", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("starling-lm", new Uri("http://localhost:11435"));
+
+//ServerSpace - GPT Service
+builder.Services.AddOpenAIChatCompletion("openchat-3.5-0106", new Uri("https://gpt.serverspace.com.br/v1/chat/completions"), "tIAXVf3AkCkkpSX+PjFvktfEeSPyA1ZYam50UO3ye/qmxVZX6PIXstmJsLZXkQ39C33onFD/81mdxvhbGHm7tQ==");
+
+builder.Services.AddOllamaTextEmbeddingGeneration("all-minilm", new Uri("http://localhost:11435"));
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435"));
+//builder.Services.AddOpenAIChatCompletion("gpt-4o-mini", "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");
+//builder.Services.AddGoogleAIGeminiChatCompletion("gemini-1.5-flash-latest", "AIzaSyDKBMX5yW77vxJFVJVE-5VLxlQRxCepck8");
+
+//Anthropic / Claude
+//builder.Services.AddAnthropicChatCompletion(
+// modelId: "claude-3-5-sonnet-latest", // ou outro modelo Claude desejado
+// apiKey: "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"
+//);
+
+builder.Services.AddKernel();
+//builder.Services.AddKernel()
+// .AddOllamaChatCompletion("phi3", new Uri("http://localhost:11435"))
+// .AddOllamaTextEmbeddingGeneration()
+// .Build();
+
+//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://192.168.0.150:11436"));
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseSwagger();
+ app.UseSwaggerUI();
+}
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.MapControllers();
+
+app.Use(async (context, next) =>
+{
+ var cookieOpt = new CookieOptions()
+ {
+ Path = "/",
+ Expires = DateTimeOffset.UtcNow.AddDays(1),
+ IsEssential = true,
+ HttpOnly = false,
+ Secure = false,
+ };
+
+ await next();
+});
+
+app.Run();
+
+#pragma warning restore SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json
new file mode 100644
index 0000000..ed836dc
--- /dev/null
+++ b/Properties/launchSettings.json
@@ -0,0 +1,52 @@
+{
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "dotnetRunMessages": true,
+ "applicationUrl": "http://localhost:5020"
+ },
+ "https": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "dotnetRunMessages": true,
+ "applicationUrl": "https://localhost:7163;http://localhost:5020"
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Container (Dockerfile)": {
+ "commandName": "Docker",
+ "launchBrowser": true,
+ "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
+ "environmentVariables": {
+ "ASPNETCORE_HTTPS_PORTS": "8081",
+ "ASPNETCORE_HTTP_PORTS": "8080"
+ },
+ "publishAllPorts": true,
+ "useSSL": true
+ }
+ },
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:61198",
+ "sslPort": 44305
+ }
+ }
+}
\ No newline at end of file
diff --git a/Services/Bot/5vb0vxog.ejb~ b/Services/Bot/5vb0vxog.ejb~
new file mode 100644
index 0000000..bcd8fd4
--- /dev/null
+++ b/Services/Bot/5vb0vxog.ejb~
@@ -0,0 +1,64 @@
+using ChatApi.Services.Bot.Structs;
+
+namespace ChatApi.Services.Bot
+{
+ public class ChatBotRHCall
+ {
+ private readonly ChatBot _chatbot;
+
+ Dictionary _opcoesSolicitação =
+ new Dictionary {
+ { "Inclusão/Exclusão Alura", "Inclusão/Exclusão Alura"},
+ { "Inclusão/Exclusão AuxÃlio Idioma", "Inclusão/Exclusão AuxÃlio Idioma"},
+ { "Inclusão/Exclusão Plano Odonto", "Inclusão/Exclusão Plano Odonto"},
+ //{ "Envio de Atestado", "Envio de Atestado"},
+ //{ "Envio de Reembolso Idioma", "Envio de Reembolso Idioma"},
+ //{ "Afastamento e Licenças", "Afastamento e Licenças"},
+ { "Dúvidas Plano de Saúde", "Dúvidas Plano de Saúde"},
+ { "Dúvidas Folha de Pagamento", "Dúvidas Folha de Pagamento"},
+ { "Ajuste Cargo/Salário", "Ajuste Cargo/Salário"},
+ { "Feedbacks, reclamações", "1 - Feedbacks, reclamações"},
+ { "Feedz - Dúvida 1:1", "Feedz - Dúvida 1:1"},
+ { "Feedz - Dúvida Feedback", "Feedz - Dúvida Feedback"},
+ { "Feedz - Cadastro de Objetivo", "Feedz - Cadastro de Objetivo"},
+ { "Feedz - Erro Cadastro", "Feedz - Erro Cadastro"},
+ { "Feedz - Outros", "Feedz - Outros"},
+ { "Ciclo de Performance", "Ciclo de Performance"},
+ { "Declaração Bolsa Faculdade", "Declaração Bolsa Faculdade"},
+ { "Inclusão/Exclusão Programa de Especialização", "Inclusão/Exclusão Programa de Especialização"},
+ //{ "Envio de Reembolso Especialização", "Envio de Reembolso Especialização"},
+ { "DayOff", "DayOff"}
+ };
+
+ public ChatBotRHCall(ChatBot chatbot)
+ {
+ _chatbot = chatbot;
+ AddNumbersBeforShow(_opcoesSolicitação);
+
+ _chatbot.AddQuestion(new Question(
+ "Qual seu número de celular (com WhatsApp)?",
+ resposta => !string.IsNullOrEmpty(resposta) && resposta.Length >= 10));
+
+ _chatbot.AddQuestion(new Question(
+ "Qual o tipo de solicitação (1 para Reembolso de Idioma, 2 para Reembolso Alura, 3 para Dúvidas)?",
+ resposta => resposta == "1" || resposta == "2" || resposta == "3"));
+
+ _chatbot.AddQuestion(new Question(
+ "Texto/Descrição da solicitação (em caso de dúvidas)",
+ resposta => !string.IsNullOrEmpty(resposta)));
+
+ _chatbot.AddQuestion(new Question(
+ "Tudo bem? Posso enviar sua solicitação? Ou prefere que eu tente fazer algum ajuste no texto da descrição?",
+ resposta => !string.IsNullOrEmpty(resposta)));
+ }
+
+ private void AddNumbersBeforShow(Dictionary dict)
+ {
+ int optionNumber = 1;
+ foreach (var key in dict.Keys)
+ {
+ dict[key] = $"{optionNumber} - {dict[key]}";
+ }
+ }
+ }
+}
diff --git a/Services/Bot/ActionCreateCall.cs b/Services/Bot/ActionCreateCall.cs
new file mode 100644
index 0000000..001287f
--- /dev/null
+++ b/Services/Bot/ActionCreateCall.cs
@@ -0,0 +1,63 @@
+using ChatApi.Infra;
+using ChatApi.Services.Bot.Structs;
+using ChatApi.Settings;
+using System.Text;
+
+namespace ChatApi.Services.Bot
+{
+ public class ActionCreateCall : IActionCall
+ {
+ private readonly IHttpClientFactory _httpClientFactory;
+ private readonly ChatRHSettings _configuration;
+ private dynamic _callRH;
+
+ public ActionCreateCall(IHttpClientFactory httpClientFactory, ChatRHSettings configuration)
+ {
+ _httpClientFactory = httpClientFactory;
+ _configuration = configuration;
+ }
+
+ public Task> Call()
+ {
+ var httpClient =_httpClientFactory.CreateClient();
+ var url = new Uri(new Uri(_configuration.Url), _configuration.Create);
+ var request = new HttpRequestMessage(HttpMethod.Post, url);
+ request.Content = new StringContent(System.Text.Json.JsonSerializer.Serialize(_callRH), Encoding.UTF8, "application/json");
+ var response = httpClient.SendAsync(request).Result;
+
+ if (response.IsSuccessStatusCode)
+ {
+ var content = response.Content.ReadAsStringAsync().Result;
+ return Task.FromResult(Result.Ok(content));
+ }
+
+ var errorContent = "";
+ try
+ {
+ errorContent = response.Content.ReadAsStringAsync().Result;
+ }
+ catch (Exception ex)
+ {
+ errorContent = "Náo foi possivel criar sua solicitação. Reinicie.";
+ }
+
+ return Task.FromResult(Result.Fail(errorContent));
+ }
+
+ public Task Populate(Dictionary? knowParameters, Dictionary answers)
+ {
+ if (knowParameters == null) return Task.FromResult(Result.Fail("Nome e/ou email não foram informados."));
+
+ _callRH = new
+ {
+ Nome = knowParameters["Nome"],
+ Email = knowParameters["Email"],
+ WhatsApp = answers[0],
+ TipoSolicitacao = answers[1],
+ Descricao = answers[2],
+ };
+
+ return Task.FromResult(Result.Ok());
+ }
+ }
+}
diff --git a/Services/Bot/ChatBotRHCall.cs b/Services/Bot/ChatBotRHCall.cs
new file mode 100644
index 0000000..b4adb1a
--- /dev/null
+++ b/Services/Bot/ChatBotRHCall.cs
@@ -0,0 +1,120 @@
+using ChatApi.Models;
+using ChatApi.Services.Bot.Structs;
+using ChatApi.Settings;
+using Microsoft.Extensions.Options;
+using Microsoft.SemanticKernel.ChatCompletion;
+using System.Text;
+
+namespace ChatApi.Services.Bot
+{
+ public class ChatBotRHCall
+ {
+ private ChatBot _chatbot;
+ private readonly IChatCompletionService _chatCompletionService;
+ private readonly IHttpClientFactory _httpClientFactory;
+ private readonly IOptions _chatRHApiConfig;
+ public UserData UserData { get; set; }
+
+ Dictionary _opcoesSolicitação =
+ new Dictionary {
+ { "Inclusão/Exclusão Alura", "Inclusão/Exclusão Alura"},
+ { "Inclusão/Exclusão AuxÃlio Idioma", "Inclusão/Exclusão AuxÃlio Idioma"},
+ { "Inclusão/Exclusão Plano Odonto", "Inclusão/Exclusão Plano Odonto"},
+ //{ "Envio de Atestado", "Envio de Atestado"},
+ //{ "Envio de Reembolso Idioma", "Envio de Reembolso Idioma"},
+ //{ "Afastamento e Licenças", "Afastamento e Licenças"},
+ { "Dúvidas Plano de Saúde", "Dúvidas Plano de Saúde"},
+ { "Dúvidas Folha de Pagamento", "Dúvidas Folha de Pagamento"},
+ { "Ajuste Cargo/Salário", "Ajuste Cargo/Salário"},
+ { "Feedbacks, reclamações", "Feedbacks, reclamações"},
+ { "Feedz - Dúvida 1:1", "Feedz - Dúvida 1:1"},
+ { "Feedz - Dúvida Feedback", "Feedz - Dúvida Feedback"},
+ { "Feedz - Cadastro de Objetivo", "Feedz - Cadastro de Objetivo"},
+ { "Feedz - Erro Cadastro", "Feedz - Erro Cadastro"},
+ { "Feedz - Outros", "Feedz - Outros"},
+ { "Ciclo de Performance", "Ciclo de Performance"},
+ { "Declaração Bolsa Faculdade", "Declaração Bolsa Faculdade"},
+ { "Inclusão/Exclusão Programa de Especialização", "Inclusão/Exclusão Programa de Especialização"},
+ //{ "Envio de Reembolso Especialização", "Envio de Reembolso Especialização"},
+ { "DayOff", "DayOff"}
+ };
+ private readonly IOptions _config;
+
+ public ChatBotRHCall(
+ IOptions config,
+ IChatCompletionService chatCompletionService,
+ IHttpClientFactory httpClientFactory,
+ IOptions chatRHApiConfig)
+ {
+ _chatCompletionService = chatCompletionService;
+ _httpClientFactory = httpClientFactory;
+ _chatRHApiConfig = chatRHApiConfig;
+ _config = config;
+ }
+ public string SetAnswer(string sessionId, string resposta)
+ {
+ if (_chatbot==null)
+ {
+ this.Init(sessionId);
+ }
+
+ return _chatbot.SetAnswer(resposta);
+ }
+
+ public async Task GetNextQuestion()
+ {
+ return await _chatbot.GetNextQuestion();
+ }
+
+ public string GetCurrentQuestion()
+ {
+ return _chatbot.GetCurrentQuestion();
+ }
+
+ public bool HasNextQuestion()
+ {
+ return _chatbot.HasNextQuestion();
+ }
+
+ public void Init(string sessionId)
+ {
+ var persist = ChatPersistence.Create(_config.Value).SetBotName("RHCall");
+ var actionOnEnd = new ActionCreateCall(_httpClientFactory, _chatRHApiConfig.Value);
+ _chatbot = new ChatBot(persist, sessionId, this.UserData, _chatCompletionService, actionOnEnd);
+
+ AddNumbersBeforShow(_opcoesSolicitação);
+
+ _chatbot.AddQuestion(new Question(
+ "Você quer fazer uma solicitação ao RH, certo??",
+ resposta => !string.IsNullOrEmpty(resposta)));
+
+ _chatbot.AddQuestion(new Question(
+ "Qual seu número de celular (com WhatsApp)?",
+ resposta => !string.IsNullOrEmpty(resposta) && resposta.Length >= 10));
+
+ var builder = new StringBuilder();
+ _opcoesSolicitação.Select(s => s.Value).ToList().ForEach(s => builder.AppendLine(s));
+
+ _chatbot.AddQuestion(new Question(
+ $"Indique o tipo de solicitação: \n {builder}",
+ resposta => resposta == "1" || resposta == "2" || resposta == "3"));
+
+ _chatbot.AddQuestion(new Question(
+ "Texto/Descrição da solicitação (em caso de dúvidas)",
+ resposta => !string.IsNullOrEmpty(resposta)));
+
+ _chatbot.AddQuestion(new Question(
+ "Tudo bem? Posso enviar sua solicitação? Ou prefere que eu tente fazer algum ajuste no texto da descrição?",
+ resposta => !string.IsNullOrEmpty(resposta)));
+ }
+ private void AddNumbersBeforShow(Dictionary dict)
+ {
+ int optionNumber = 1;
+ foreach (var key in dict.Keys)
+ {
+ dict[key] = $"{optionNumber} - {dict[key]}";
+ optionNumber++;
+ }
+ }
+ }
+}
diff --git a/Services/Bot/Structs/ChatBot.cs b/Services/Bot/Structs/ChatBot.cs
new file mode 100644
index 0000000..7885d1f
--- /dev/null
+++ b/Services/Bot/Structs/ChatBot.cs
@@ -0,0 +1,148 @@
+using Amazon.Auth.AccessControlPolicy;
+using ChatApi.Models;
+using Microsoft.SemanticKernel.ChatCompletion;
+
+namespace ChatApi.Services.Bot.Structs
+{
+ public class ChatBot
+ {
+ private readonly List _questions;
+ private readonly ChatPersistence _persistence;
+ private readonly Dictionary _answers;
+ private readonly IChatCompletionService _chatCompletionService;
+ private readonly IActionCall _actionCall;
+ private readonly string _usuarioId;
+ private readonly UserData _userData;
+ private Dictionary _knowParameters;
+ private int _indiceAtual;
+
+ public ChatBot(ChatPersistence persistence, string usuarioId, UserData userData, IChatCompletionService chatCompletionService, IActionCall actionCall)
+ {
+ _chatCompletionService = chatCompletionService;
+ _actionCall = actionCall;
+ _questions = new List();
+ _answers = new Dictionary();
+ _knowParameters = new Dictionary();
+ _indiceAtual = 0;
+ _persistence = persistence;
+ _usuarioId = usuarioId;
+ _userData = userData;
+ var estado = _persistence.GetState(_usuarioId);
+ if (estado != null)
+ {
+ _indiceAtual = estado.IndicePerguntaAtual;
+ _answers = estado.Respostas;
+ }
+ else
+ {
+ _indiceAtual = 0;
+ }
+ }
+
+ public void SetParameter(string key, string value)
+ {
+ _knowParameters[key] = value;
+ }
+
+ public void AddQuestion(Question Question)
+ {
+ _questions.Add(Question);
+ }
+
+ public string SetAnswer(string resposta)
+ {
+ if (!this.HasNextQuestion()) return "";
+
+ var state = _persistence.GetState(_usuarioId);
+ if (state != null)
+ {
+ _questions[_indiceAtual].CountTry = state.TentativasPerguntaAtual;
+ }
+ else
+ {
+ _knowParameters = new Dictionary()
+ {
+ { "Nome", _userData.Name },
+ { "Email", _userData.Email }
+ };
+ }
+
+ var perguntaAtual = _questions[_indiceAtual];
+ var testByChat = TestAnswerByChat(resposta);
+ var abort = TestIfWantToAbort(resposta);
+ var validResp = perguntaAtual.TryToAnswer(resposta);
+
+ if (string.IsNullOrEmpty(validResp) && !abort.Contains("ABORTAR") && perguntaAtual.Validator(resposta) && testByChat.Contains("SIM"))
+ {
+ _answers[_indiceAtual] = resposta;
+ _indiceAtual++;
+ _persistence.SaveState(new ChatState
+ {
+ Id = _usuarioId,
+ UsuarioId = _usuarioId,
+ IndicePerguntaAtual = _indiceAtual,
+ TentativasPerguntaAtual = _questions[_indiceAtual].CountTry,
+ Respostas = new Dictionary(_answers)
+ });
+
+ return "";
+ }
+ else if (validResp.Contains("reiniciar") || abort.Contains("ABORTAR"))
+ {
+ _persistence.DeleteState(_usuarioId);
+ return "REINICIAR";
+ }
+
+ _persistence.SaveState(new ChatState
+ {
+ Id = _usuarioId,
+ UsuarioId = _usuarioId,
+ IndicePerguntaAtual = _indiceAtual,
+ TentativasPerguntaAtual = _questions[_indiceAtual].CountTry,
+ DadosConhecidos = _knowParameters,
+ Respostas = new Dictionary(_answers)
+ });
+
+ return $"Resposta inválida. Tente novamente. {(testByChat.Contains("NÃO") ? "Motivo: " + testByChat.Replace("NÂO", "") : "")} \n\n {perguntaAtual.Text}";
+ }
+
+ public string GetCurrentQuestion() => _questions[_indiceAtual].Text;
+ public async Task GetNextQuestion()
+ {
+ while (_indiceAtual < _questions.Count)
+ {
+ var perguntaAtual = _questions[_indiceAtual];
+ if (perguntaAtual.MustShow(_answers))
+ {
+ return perguntaAtual.Text;
+ }
+ _indiceAtual++;
+ }
+
+ var resp = await _actionCall.Populate(_knowParameters, _answers);
+ if (!resp.Success) return "Obrigado por responder a nossas perguntas!";
+
+ var result = await _actionCall.Call();
+
+ return result.Success ? result.Value : "Obrigado por responder a nossas perguntas!";
+ }
+
+ public string TestAnswerByChat(string resposta)
+ {
+ var resp = _chatCompletionService.GetChatMessageContentAsync($"Por favor, responda com SIM/NÂO e o motivo para eu saber se a pergunta: ({this.GetCurrentQuestion()}) foi respondida pelo usuário quando ele digitou: ({resposta})? É um chatbot, por isso preciso saber apenas se a resposta faz sentido e/ou tem o formato certo.").Result;
+ return resp.Content;
+ }
+
+ public string TestIfWantToAbort(string resposta)
+ {
+ if (_indiceAtual==0) return "";
+ var resp = _chatCompletionService.GetChatMessageContentAsync($"Este é um chatbot. Foi feita a pergunta para o usuario: ({this.GetCurrentQuestion()}) e ele digitou: ({resposta})? Ele respondeu a pergunta com a informação solicitada, ou ele está pedindo para sair do chat? Responda com (SIM = Ele quer sair ou não quer responder) ou (NÃO = Ele responde a pergunta de maneira coerente) e indique o motivo.").Result;
+ return resp.Content.Contains("SIM") ? "ABORTAR" : "";
+ }
+
+ public bool HasNextQuestion()
+ {
+ return _indiceAtual < _questions.Count;
+ }
+ }
+}
diff --git a/Services/Bot/Structs/ChatBot.cs~RFf86c93a.TMP b/Services/Bot/Structs/ChatBot.cs~RFf86c93a.TMP
new file mode 100644
index 0000000..0957797
--- /dev/null
+++ b/Services/Bot/Structs/ChatBot.cs~RFf86c93a.TMP
@@ -0,0 +1,54 @@
+namespace ChatApi.Services.Bot.Structs
+{
+ public class ChatBot
+ {
+ private readonly List _Questions;
+ private readonly ChatPersistence _persistence;
+ private readonly Dictionary _answers;
+ private readonly Guid _usuarioId;
+ private int _indiceAtual;
+
+ public ChatBot(ChatPersistence persistence, Guid usuarioId)
+ {
+ _Questions = new List();
+ _answers = new Dictionary();
+ _indiceAtual = 0;
+ _persistence = persistence;
+ _usuarioId = usuarioId;
+
+ var estado = _persistence.GetState(_usuarioId);
+ if (estado != null)
+ {
+ _indiceAtual = estado.IndicePerguntaAtual;
+ _answers = estado.Respostas;
+ }
+ else
+ {
+ _indiceAtual = 0;
+ }
+ }
+
+ public void AddQuestion(Question Question)
+ {
+ _Questions.Add(Question);
+ }
+
+ public void Iniciar()
+ {
+ while (_indiceAtual < _Questions.Count)
+ {
+ var QuestionAtual = _Questions[_indiceAtual];
+ if (QuestionAtual.TryToAnswer(out _))
+ {
+ _indiceAtual++;
+ }
+ else
+ {
+ _indiceAtual = 0; // Reinicia o fluxo
+ }
+ }
+
+ Console.WriteLine("Obrigado por responder a todas as perguntas!");
+ }
+ }
+}
diff --git a/Services/Bot/Structs/ChatBot.cs~RFf89467e.TMP b/Services/Bot/Structs/ChatBot.cs~RFf89467e.TMP
new file mode 100644
index 0000000..6c4eb52
--- /dev/null
+++ b/Services/Bot/Structs/ChatBot.cs~RFf89467e.TMP
@@ -0,0 +1,75 @@
+namespace ChatApi.Services.Bot.Structs
+{
+ public class ChatBot
+ {
+ private readonly List _questions;
+ private readonly ChatPersistence _persistence;
+ private readonly Dictionary _answers;
+ private readonly Guid _usuarioId;
+ private int _indiceAtual;
+
+ public ChatBot(ChatPersistence persistence, Guid usuarioId)
+ {
+ _questions = new List();
+ _answers = new Dictionary();
+ _indiceAtual = 0;
+ _persistence = persistence;
+ _usuarioId = usuarioId;
+
+ var estado = _persistence.GetState(_usuarioId);
+ if (estado != null)
+ {
+ _indiceAtual = estado.IndicePerguntaAtual;
+ _answers = estado.Respostas;
+ }
+ else
+ {
+ _indiceAtual = 0;
+ }
+ }
+
+ public void AddQuestion(Question Question)
+ {
+ _questions.Add(Question);
+ }
+
+ public bool InformarResposta(string resposta)
+ {
+ var perguntaAtual = _questions[_indiceAtual];
+ if (perguntaAtual.Validator(resposta))
+ {
+ _answers[_indiceAtual] = resposta;
+ _indiceAtual++;
+
+ _persistence.SaveState(new ChatState
+ {
+ UsuarioId = _usuarioId,
+ IndicePerguntaAtual = _indiceAtual,
+ Respostas = new Dictionary(_answers)
+ });
+
+ return true;
+ }
+
+ Console.WriteLine("Resposta inválida. Tente novamente.");
+ return false;
+ }
+ public void Iniciar()
+ {
+ while (_indiceAtual < _questions.Count)
+ {
+ var QuestionAtual = _questions[_indiceAtual];
+ if (QuestionAtual.TryToAnswer(out _))
+ {
+ _indiceAtual++;
+ }
+ else
+ {
+ _indiceAtual = 0; // Reinicia o fluxo
+ }
+ }
+
+ Console.WriteLine("Obrigado por responder a todas as perguntas!");
+ }
+ }
+}
diff --git a/Services/Bot/Structs/ChatPersistence.cs b/Services/Bot/Structs/ChatPersistence.cs
new file mode 100644
index 0000000..ee7d554
--- /dev/null
+++ b/Services/Bot/Structs/ChatPersistence.cs
@@ -0,0 +1,45 @@
+using ChatApi.Services.Classifier;
+using MongoDB.Driver;
+
+namespace ChatApi.Services.Bot.Structs
+{
+ public class ChatPersistence
+ {
+ private readonly IMongoCollection _collection;
+ private string _botName;
+
+ private ChatPersistence(DomvsDatabaseSettings config)
+ {
+ var client = new MongoClient(config.ConnectionString);
+ var database = client.GetDatabase(config.DatabaseName);
+ _collection = database.GetCollection(config.ChatBotRHCollectionName);
+ }
+
+ public static ChatPersistence Create(DomvsDatabaseSettings config)
+ {
+ return new ChatPersistence(config);
+ }
+
+ public ChatPersistence SetBotName(string botName)
+ {
+ _botName = botName;
+ return this;
+ }
+
+ public ChatState GetState(string usuarioId)
+ {
+ return _collection.Find(x => x.UsuarioId == usuarioId).FirstOrDefault();
+ }
+
+ public void DeleteState(string usuarioId)
+ {
+ _collection.DeleteOne(x => x.UsuarioId == usuarioId);
+ }
+
+ public void SaveState(ChatState estado)
+ {
+ var filtro = Builders.Filter.Eq(x => x.UsuarioId, estado.UsuarioId);
+ _collection.ReplaceOne(filtro, estado, new ReplaceOptions { IsUpsert = true });
+ }
+ }
+}
diff --git a/Services/Bot/Structs/ChatState.cs b/Services/Bot/Structs/ChatState.cs
new file mode 100644
index 0000000..919b983
--- /dev/null
+++ b/Services/Bot/Structs/ChatState.cs
@@ -0,0 +1,20 @@
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Options;
+
+namespace ChatApi.Services.Bot.Structs
+{
+ public class ChatState
+ {
+ [BsonId]
+ [BsonElement("_id")]
+ public string Id { get; set; }
+ public string UsuarioId { get; set; }
+ public int IndicePerguntaAtual { get; set; }
+ public int TentativasPerguntaAtual { get; set; }
+
+ [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
+ public Dictionary Respostas { get; set; }
+ public Dictionary DadosConhecidos { get; set; }
+ }
+}
diff --git a/Services/Bot/Structs/IActionCall.cs b/Services/Bot/Structs/IActionCall.cs
new file mode 100644
index 0000000..bef2fc3
--- /dev/null
+++ b/Services/Bot/Structs/IActionCall.cs
@@ -0,0 +1,10 @@
+using ChatApi.Infra;
+
+namespace ChatApi.Services.Bot.Structs
+{
+ public interface IActionCall
+ {
+ Task Populate(Dictionary? knowParameters, Dictionary answers);
+ Task> Call();
+ }
+}
diff --git a/Services/Bot/Structs/Question.cs b/Services/Bot/Structs/Question.cs
new file mode 100644
index 0000000..4156464
--- /dev/null
+++ b/Services/Bot/Structs/Question.cs
@@ -0,0 +1,42 @@
+namespace ChatApi.Services.Bot.Structs
+{
+ public class Question
+ {
+ public string Text { get; }
+ public Func Validator { get; }
+ public int CountTry { get; set; }
+ public Func, bool> Condition { get; }
+
+ private const int MaxTentativas = 2;
+
+ public Question(string texto, Func validador, Func, bool> condition=null)
+ {
+ Text = texto;
+ Validator = validador;
+ CountTry = 0;
+ Condition = condition;
+ }
+
+ public bool MustShow(Dictionary respostasAnteriores)
+ {
+ return Condition == null || Condition(respostasAnteriores);
+ }
+
+ public string TryToAnswer(string resposta)
+ {
+ if (Validator(resposta))
+ {
+ return "";
+ }
+
+ CountTry++;
+ if (CountTry >= MaxTentativas)
+ {
+ CountTry = 0;
+ return "Não entendi sua resposta. Vamos reiniciar.";
+ }
+
+ return "Resposta inválida. Tente novamente.";
+ }
+ }
+}
diff --git a/Services/Bot/Structs/e4zbjmgl.vwg~ b/Services/Bot/Structs/e4zbjmgl.vwg~
new file mode 100644
index 0000000..dd7b2a6
--- /dev/null
+++ b/Services/Bot/Structs/e4zbjmgl.vwg~
@@ -0,0 +1,137 @@
+using Amazon.Auth.AccessControlPolicy;
+using Microsoft.SemanticKernel.ChatCompletion;
+
+namespace ChatApi.Services.Bot.Structs
+{
+ public class ChatBot
+ {
+ private readonly List _questions;
+ private readonly ChatPersistence _persistence;
+ private readonly Dictionary _knowParameters;
+ private readonly Dictionary _answers;
+ private readonly IChatCompletionService _chatCompletionService;
+ private readonly IActionCall _actionCall;
+ private readonly string _usuarioId;
+ private int _indiceAtual;
+
+ public ChatBot(ChatPersistence persistence, string usuarioId, IChatCompletionService chatCompletionService, IActionCall actionCall)
+ {
+ _chatCompletionService = chatCompletionService;
+ _actionCall = actionCall;
+ _questions = new List();
+ _answers = new Dictionary();
+ _knowParameters = new Dictionary();
+ _indiceAtual = 0;
+ _persistence = persistence;
+ _usuarioId = usuarioId;
+
+ var estado = _persistence.GetState(_usuarioId);
+ if (estado != null)
+ {
+ _indiceAtual = estado.IndicePerguntaAtual;
+ _answers = estado.Respostas;
+ }
+ else
+ {
+ _indiceAtual = 0;
+ }
+ }
+
+ public void SetParameter(string key, string value)
+ {
+ _knowParameters[key] = value;
+ }
+
+ public void AddQuestion(Question Question)
+ {
+ _questions.Add(Question);
+ }
+
+ public string SetAnswer(string resposta)
+ {
+ if (!this.HasNextQuestion()) return "";
+
+ var state = _persistence.GetState(_usuarioId);
+ if (state != null)
+ {
+ _questions[_indiceAtual].CountTry = state.TentativasPerguntaAtual;
+ }
+
+ var perguntaAtual = _questions[_indiceAtual];
+ var testByChat = TestAnswerByChat(resposta);
+ var abort = TestIfWantToAbort(resposta);
+ var validResp = perguntaAtual.TryToAnswer(resposta);
+
+ if (string.IsNullOrEmpty(validResp) && !abort.Contains("ABORTAR") && perguntaAtual.Validator(resposta) && testByChat.Contains("SIM"))
+ {
+ _answers[_indiceAtual] = resposta;
+ _indiceAtual++;
+ _persistence.SaveState(new ChatState
+ {
+ Id = _usuarioId,
+ UsuarioId = _usuarioId,
+ IndicePerguntaAtual = _indiceAtual,
+ TentativasPerguntaAtual = _questions[_indiceAtual].CountTry,
+ Respostas = new Dictionary(_answers)
+ });
+
+ return "";
+ }
+ else if (validResp.Contains("reiniciar") || abort.Contains("ABORTAR"))
+ {
+ _persistence.DeleteState(_usuarioId);
+ return "REINICIAR";
+ }
+
+ _persistence.SaveState(new ChatState
+ {
+ Id = _usuarioId,
+ UsuarioId = _usuarioId,
+ IndicePerguntaAtual = _indiceAtual,
+ TentativasPerguntaAtual = _questions[_indiceAtual].CountTry,
+ Respostas = new Dictionary(_answers)
+ });
+
+ return $"Resposta inválida. Tente novamente. {(testByChat.Contains("NÃO") ? "Motivo: " + testByChat.Replace("NÂO", "") : "")} \n\n {perguntaAtual.Text}";
+ }
+
+ public string GetCurrentQuestion() => _questions[_indiceAtual].Text;
+ public async Task GetNextQuestion()
+ {
+ while (_indiceAtual < _questions.Count)
+ {
+ var perguntaAtual = _questions[_indiceAtual];
+ if (perguntaAtual.MustShow(_answers))
+ {
+ return perguntaAtual.Text;
+ }
+ _indiceAtual++;
+ }
+
+ var resp = await _actionCall.Populate(_knowParameters, _answers);
+ if (!resp.Success) return "Obrigado por responder a nossas perguntas!";
+
+ var result = await _actionCall.Call();
+
+ return result.Success ? result.Value : "Obrigado por responder a nossas perguntas!";
+ }
+
+ public string TestAnswerByChat(string resposta)
+ {
+ var resp = _chatCompletionService.GetChatMessageContentAsync($"Por favor, responda com SIM/NÂO e o motivo para eu saber se a pergunta: ({this.GetCurrentQuestion()}) foi respondida pelo usuário quando ele digitou: ({resposta})? É um chatbot, por isso preciso saber apenas se a resposta faz sentido e/ou tem o formato certo.").Result;
+ return resp.Content;
+ }
+
+ public string TestIfWantToAbort(string resposta)
+ {
+ if (_indiceAtual==0) return "";
+ var resp = _chatCompletionService.GetChatMessageContentAsync($"Este é um chatbot. Foi feita a pergunta para o usuario: ({this.GetCurrentQuestion()}) e ele digitou: ({resposta})? Ele respondeu a pergunta com a informação solicitada, ou ele está pedindo para sair do chat? Responda com (SIM = Ele quer sair ou não quer responder) ou (NÃO = Ele responde a pergunta de maneira coerente) e indique o motivo.").Result;
+ return resp.Content.Contains("SIM") ? "ABORTAR" : "";
+ }
+
+ public bool HasNextQuestion()
+ {
+ return _indiceAtual < _questions.Count;
+ }
+ }
+}
diff --git a/Services/Bot/Structs/v0pubwmg.zkp~ b/Services/Bot/Structs/v0pubwmg.zkp~
new file mode 100644
index 0000000..31225ba
--- /dev/null
+++ b/Services/Bot/Structs/v0pubwmg.zkp~
@@ -0,0 +1,148 @@
+using Amazon.Auth.AccessControlPolicy;
+using ChatApi.Models;
+using Microsoft.SemanticKernel.ChatCompletion;
+
+namespace ChatApi.Services.Bot.Structs
+{
+ public class ChatBot
+ {
+ private readonly List _questions;
+ private readonly ChatPersistence _persistence;
+ private readonly Dictionary _answers;
+ private readonly IChatCompletionService _chatCompletionService;
+ private readonly IActionCall _actionCall;
+ private readonly string _usuarioId;
+ private readonly UserData _userData;
+ private Dictionary _knowParameters;
+ private int _indiceAtual;
+
+ public ChatBot(ChatPersistence persistence, string usuarioId, UserData userData, IChatCompletionService chatCompletionService, IActionCall actionCall)
+ {
+ _chatCompletionService = chatCompletionService;
+ _actionCall = actionCall;
+ _questions = new List();
+ _answers = new Dictionary();
+ _knowParameters = new Dictionary();
+ _indiceAtual = 0;
+ _persistence = persistence;
+ _usuarioId = usuarioId;
+ _userData = userData;
+ var estado = _persistence.GetState(_usuarioId);
+ if (estado != null)
+ {
+ _indiceAtual = estado.IndicePerguntaAtual;
+ _answers = estado.Respostas;
+ }
+ else
+ {
+ _indiceAtual = 0;
+ }
+ }
+
+ public void SetParameter(string key, string value)
+ {
+ _knowParameters[key] = value;
+ }
+
+ public void AddQuestion(Question Question)
+ {
+ _questions.Add(Question);
+ }
+
+ public string SetAnswer(string resposta)
+ {
+ if (!this.HasNextQuestion()) return "";
+
+ var state = _persistence.GetState(_usuarioId);
+ if (state != null)
+ {
+ _questions[_indiceAtual].CountTry = state.TentativasPerguntaAtual;
+ }
+ else
+ {
+ _knowParameters = new Dictionary()
+ {
+ { "Nome", _userData.Name },
+ { "Email", _userData.Email }
+ };
+ }
+
+ var perguntaAtual = _questions[_indiceAtual];
+ var testByChat = TestAnswerByChat(resposta);
+ var abort = TestIfWantToAbort(resposta);
+ var validResp = perguntaAtual.TryToAnswer(resposta);
+
+ if (string.IsNullOrEmpty(validResp) && !abort.Contains("ABORTAR") && perguntaAtual.Validator(resposta) && testByChat.Contains("SIM"))
+ {
+ _answers[_indiceAtual] = resposta;
+ _indiceAtual++;
+ _persistence.SaveState(new ChatState
+ {
+ Id = _usuarioId,
+ UsuarioId = _usuarioId,
+ IndicePerguntaAtual = _indiceAtual,
+ TentativasPerguntaAtual = _questions[_indiceAtual].CountTry,
+ Respostas = new Dictionary(_answers)
+ });
+
+ return "";
+ }
+ else if (validResp.Contains("reiniciar") || abort.Contains("ABORTAR"))
+ {
+ _persistence.DeleteState(_usuarioId);
+ return "REINICIAR";
+ }
+
+ _persistence.SaveState(new ChatState
+ {
+ Id = _usuarioId,
+ UsuarioId = _usuarioId,
+ IndicePerguntaAtual = _indiceAtual,
+ TentativasPerguntaAtual = _questions[_indiceAtual].CountTry,
+ DadosConhecidos = _knowParameters,
+ Respostas = new Dictionary(_answers)
+ });
+
+ return $"Resposta inválida. Tente novamente. {(testByChat.Contains("NÃO") ? "Motivo: " + testByChat.Replace("NÂO", "") : "")} \n\n {perguntaAtual.Text}";
+ }
+
+ public string GetCurrentQuestion() => _questions[_indiceAtual].Text;
+ public async Task GetNextQuestion()
+ {
+ while (_indiceAtual < _questions.Count)
+ {
+ var perguntaAtual = _questions[_indiceAtual];
+ if (perguntaAtual.MustShow(_answers))
+ {
+ return perguntaAtual.Text;
+ }
+ _indiceAtual++;
+ }
+
+ var resp = await _actionCall.Populate(_knowParameters, _answers);
+ if (!resp.Success) return "Obrigado por responder a nossas perguntas!";
+
+ var result = await _actionCall.Call();
+
+ return result.Success ? result. : "Obrigado por responder a nossas perguntas!";
+ }
+
+ public string TestAnswerByChat(string resposta)
+ {
+ var resp = _chatCompletionService.GetChatMessageContentAsync($"Por favor, responda com SIM/NÂO e o motivo para eu saber se a pergunta: ({this.GetCurrentQuestion()}) foi respondida pelo usuário quando ele digitou: ({resposta})? É um chatbot, por isso preciso saber apenas se a resposta faz sentido e/ou tem o formato certo.").Result;
+ return resp.Content;
+ }
+
+ public string TestIfWantToAbort(string resposta)
+ {
+ if (_indiceAtual==0) return "";
+ var resp = _chatCompletionService.GetChatMessageContentAsync($"Este é um chatbot. Foi feita a pergunta para o usuario: ({this.GetCurrentQuestion()}) e ele digitou: ({resposta})? Ele respondeu a pergunta com a informação solicitada, ou ele está pedindo para sair do chat? Responda com (SIM = Ele quer sair ou não quer responder) ou (NÃO = Ele responde a pergunta de maneira coerente) e indique o motivo.").Result;
+ return resp.Content.Contains("SIM") ? "ABORTAR" : "";
+ }
+
+ public bool HasNextQuestion()
+ {
+ return _indiceAtual < _questions.Count;
+ }
+ }
+}
diff --git a/Services/Bot/tdpgs1ms.1ky~ b/Services/Bot/tdpgs1ms.1ky~
new file mode 100644
index 0000000..a4875ed
--- /dev/null
+++ b/Services/Bot/tdpgs1ms.1ky~
@@ -0,0 +1,64 @@
+using ChatApi.Services.Bot.Structs;
+
+namespace ChatApi.Services.Bot
+{
+ public class ChatBotRHCall
+ {
+ private readonly ChatBot _chatbot;
+
+ Dictionary _opcoesSolicitação =
+ new Dictionary {
+ { "Inclusão/Exclusão Alura", "Inclusão/Exclusão Alura"},
+ { "Inclusão/Exclusão AuxÃlio Idioma", "Inclusão/Exclusão AuxÃlio Idioma"},
+ { "Inclusão/Exclusão Plano Odonto", "Inclusão/Exclusão Plano Odonto"},
+ //{ "Envio de Atestado", "Envio de Atestado"},
+ //{ "Envio de Reembolso Idioma", "Envio de Reembolso Idioma"},
+ //{ "Afastamento e Licenças", "Afastamento e Licenças"},
+ { "Dúvidas Plano de Saúde", "Dúvidas Plano de Saúde"},
+ { "Dúvidas Folha de Pagamento", "Dúvidas Folha de Pagamento"},
+ { "Ajuste Cargo/Salário", "Ajuste Cargo/Salário"},
+ { "Feedbacks, reclamações", "1 - Feedbacks, reclamações"},
+ { "Feedz - Dúvida 1:1", "Feedz - Dúvida 1:1"},
+ { "Feedz - Dúvida Feedback", "Feedz - Dúvida Feedback"},
+ { "Feedz - Cadastro de Objetivo", "Feedz - Cadastro de Objetivo"},
+ { "Feedz - Erro Cadastro", "Feedz - Erro Cadastro"},
+ { "Feedz - Outros", "Feedz - Outros"},
+ { "Ciclo de Performance", "Ciclo de Performance"},
+ { "Declaração Bolsa Faculdade", "Declaração Bolsa Faculdade"},
+ { "Inclusão/Exclusão Programa de Especialização", "Inclusão/Exclusão Programa de Especialização"},
+ //{ "Envio de Reembolso Especialização", "Envio de Reembolso Especialização"},
+ { "DayOff", "DayOff"}
+ };
+
+ public ChatBotRHCall(ChatBot chatbot)
+ {
+ _chatbot = chatbot;
+ AddNumbersBeforShow(_opcoesSolicitação);
+
+ _chatbot.AddQuestion(new Question(
+ "Qual seu número de celular (com WhatsApp)?",
+ resposta => !string.IsNullOrEmpty(resposta) && resposta.Length >= 10));
+
+ _chatbot.AddQuestion(new Question(
+ "Qual o tipo de solicitação (1 para Reembolso de Idioma, 2 para Reembolso Alura, 3 para Dúvidas)?",
+ resposta => resposta == "1" || resposta == "2" || resposta == "3"));
+
+ _chatbot.AddQuestion(new Question(
+ "Texto/Descrição da solicitação (em caso de dúvidas)",
+ resposta => !string.IsNullOrEmpty(resposta)));
+
+ _chatbot.AddQuestion(new Question(
+ "Tudo bem? Posso enviar sua solicitação?",
+ resposta => !string.IsNullOrEmpty(resposta)));
+ }
+
+ private void AddNumbersBeforShow(Dictionary dict)
+ {
+ int optionNumber = 1;
+ foreach (var key in dict.Keys)
+ {
+ dict[key] = $"{optionNumber} - {dict[key]}";
+ }
+ }
+ }
+}
diff --git a/Services/Classifier/ClassifierPersistence.cs b/Services/Classifier/ClassifierPersistence.cs
new file mode 100644
index 0000000..631e0b3
--- /dev/null
+++ b/Services/Classifier/ClassifierPersistence.cs
@@ -0,0 +1,35 @@
+using ChatApi.Services.Bot.Structs;
+using Microsoft.Extensions.Options;
+using MongoDB.Driver;
+
+namespace ChatApi.Services.Classifier
+{
+ public class ClassifierPersistence
+ {
+ private readonly IMongoCollection _collection;
+
+ public ClassifierPersistence(IOptions config)
+ {
+ var client = new MongoClient(config.Value.ConnectionString);
+ var database = client.GetDatabase(config.Value.DatabaseName);
+ _collection = database.GetCollection(config.Value.ClassifierCollectionName);
+ }
+
+ public ClassifierSate GetState(string usuarioId)
+ {
+ return _collection.Find(x => x.Id == usuarioId).FirstOrDefault();
+ }
+
+ public void DeleteState(string usuarioId)
+ {
+ _collection.DeleteOne(x => x.UsuarioId == usuarioId);
+ }
+
+ public void SaveState(ClassifierSate estado)
+ {
+ estado.Id = estado.UsuarioId;
+ var filtro = Builders.Filter.Eq(x => x.Id, estado.UsuarioId);
+ _collection.ReplaceOne(filtro, estado, new ReplaceOptions { IsUpsert = true });
+ }
+ }
+}
diff --git a/Services/Classifier/ClassifierSate.cs b/Services/Classifier/ClassifierSate.cs
new file mode 100644
index 0000000..1968dda
--- /dev/null
+++ b/Services/Classifier/ClassifierSate.cs
@@ -0,0 +1,17 @@
+using ChatApi.Services.ClassifyHandlers;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace ChatApi.Services.Classifier
+{
+ public class ClassifierSate
+ {
+ [BsonId]
+ [BsonElement("_id")]
+ public string Id { get; set; }
+ public string UsuarioId { get; set; }
+ public EnumClassification Classification { get; set; }
+ public DateTime DhInicio { get; set; }
+ public EnumClassificationType ClassificationType { get; set; }
+ }
+}
diff --git a/Services/Classifier/ClassifierSate.cs~RF14991194.TMP b/Services/Classifier/ClassifierSate.cs~RF14991194.TMP
new file mode 100644
index 0000000..cfdf7c0
--- /dev/null
+++ b/Services/Classifier/ClassifierSate.cs~RF14991194.TMP
@@ -0,0 +1,6 @@
+namespace ChatApi.Services.Classifier
+{
+ public class ClassifierSate
+ {
+ }
+}
diff --git a/Services/ClassifyHandlers/AClassifyHandler.cs b/Services/ClassifyHandlers/AClassifyHandler.cs
new file mode 100644
index 0000000..1ea3d7a
--- /dev/null
+++ b/Services/ClassifyHandlers/AClassifyHandler.cs
@@ -0,0 +1,50 @@
+namespace ChatApi.Services.ClassifyHandlers
+{
+ public enum EnumClassificationType
+ {
+ Stay,
+ Free
+ }
+
+ public class AHandlerClassify : IHandlerClassify
+ {
+ private IHandlerClassify _nextHandlerClassify;
+ protected TextFilter _textFilter;
+ private EnumClassificationType _type = EnumClassificationType.Free;
+
+ public EnumClassificationType Type
+ {
+ get
+ {
+ return _type;
+ }
+ protected set
+ {
+ _type = EnumClassificationType.Stay;
+ }
+ }
+
+ public int StayInMinutes { get; set; }
+ public EnumClassification MyClassification { get; set; }
+
+ public AHandlerClassify()
+ {
+ _textFilter = new TextFilter();
+ }
+
+ public IHandlerClassify SetNext(IHandlerClassify handler)
+ {
+ _nextHandlerClassify = handler;
+ return handler;
+ }
+
+ public virtual EnumClassification Handle(string request)
+ {
+ if (_nextHandlerClassify != null)
+ {
+ return _nextHandlerClassify.Handle(request);
+ }
+ return EnumClassification.CantDetect;
+ }
+ }
+}
diff --git a/Services/ClassifyHandlers/ClassifyBotRHCall.cs b/Services/ClassifyHandlers/ClassifyBotRHCall.cs
new file mode 100644
index 0000000..6111335
--- /dev/null
+++ b/Services/ClassifyHandlers/ClassifyBotRHCall.cs
@@ -0,0 +1,30 @@
+namespace ChatApi.Services.ClassifyHandlers
+{
+ public class ClassifyBotRHCall : AHandlerClassify
+ {
+ public ClassifyBotRHCall()
+ {
+ this.MyClassification = EnumClassification.BotRHCall;
+ this.Type = EnumClassificationType.Stay;
+ this.StayInMinutes = 240;
+ }
+
+ public override EnumClassification Handle(string request)
+ {
+ var companyKeywords = new List { "solicitação", "solicitações", "pedido", "dúvida", "dúvidas", "alura", "auxilio idioma", "plano odonto", "envio atestado", "reembolso idioma", "afastamento", "Agility as a Service", "agilidade",
+ "plano de saúde", "folha de pagamento", "feedbacks", "reclamações", "1:1", "feedback", "Erro de cadsatro", "performance",
+ "bolsa faculdade", "especialização", "reembolso de especialização", "dayoff", "aws", "cadastro", "dúvidas"
+ };
+
+ var questionLower = base._textFilter.ToLowerAndWithoutAccents(request);
+
+ if (questionLower.Contains(_textFilter.ToLowerAndWithoutAccents(" rh")) &&
+ companyKeywords.Any(keyword => questionLower.Contains(_textFilter.ToLowerAndWithoutAccents(keyword))))
+ {
+ return this.MyClassification;
+ }
+
+ return base.Handle(request);
+ }
+ }
+}
diff --git a/Services/ClassifyHandlers/ClassifyChat.cs b/Services/ClassifyHandlers/ClassifyChat.cs
new file mode 100644
index 0000000..1692a9d
--- /dev/null
+++ b/Services/ClassifyHandlers/ClassifyChat.cs
@@ -0,0 +1,10 @@
+namespace ChatApi.Services.ClassifyHandlers
+{
+ public class ClassifyChat : AHandlerClassify
+ {
+ public override EnumClassification Handle(string request)
+ {
+ return EnumClassification.Chat;
+ }
+ }
+}
diff --git a/Services/ClassifyHandlers/ClassifyCompany.cs b/Services/ClassifyHandlers/ClassifyCompany.cs
new file mode 100644
index 0000000..b6ad4a7
--- /dev/null
+++ b/Services/ClassifyHandlers/ClassifyCompany.cs
@@ -0,0 +1,25 @@
+namespace ChatApi.Services.ClassifyHandlers
+{
+ public class ClassifyCompany : AHandlerClassify
+ {
+ public ClassifyCompany()
+ {
+ this.MyClassification = EnumClassification.Company;
+ }
+
+ public override EnumClassification Handle(string request)
+ {
+ var companyKeywords = new List { "Domvs", "DomvsiT", "squad gerenciada", "squad hÃbrida", "alocação", "Professional Service", "solução", "Soluções", "Agility as a Service", "agilidade",
+ "DDC", "Design Diamond Conception", "Bussiness Process Optmization", "Otimização de processos", "Soluções em Cloud", "Delphix", "UX", "Squad" };
+
+ var questionLower = base._textFilter.ToLowerAndWithoutAccents(request);
+
+ if (companyKeywords.Any(keyword => questionLower.Contains(_textFilter.ToLowerAndWithoutAccents(keyword))))
+ {
+ return this.MyClassification;
+ }
+
+ return base.Handle(request);
+ }
+ }
+}
diff --git a/Services/ClassifyHandlers/ClassifyEstimate.cs b/Services/ClassifyHandlers/ClassifyEstimate.cs
new file mode 100644
index 0000000..d5fc054
--- /dev/null
+++ b/Services/ClassifyHandlers/ClassifyEstimate.cs
@@ -0,0 +1,20 @@
+namespace ChatApi.Services.ClassifyHandlers
+{
+ public class ClassifyEstimate : AHandlerClassify
+ {
+ public override EnumClassification Handle(string request)
+ {
+ var companyKeywords = new List { "Domvs", "DomvsiT", "squad gerenciada", "squad hÃbrida", "alocação", "Professional Service", "solução", "Soluções", "Agility as a Service", "agilidade",
+ "DDC", "Design Diamond Conception", "Bussiness Process Optmization", "Otimização de processos", "Soluções em Cloud", "Delphix", "UX", "Squad" };
+
+ var questionLower = base._textFilter.ToLowerAndWithoutAccents(request);
+
+ if (companyKeywords.Any(keyword => questionLower.Contains(_textFilter.ToLowerAndWithoutAccents(keyword))))
+ {
+ return EnumClassification.Company;
+ }
+
+ return base.Handle(request);
+ }
+ }
+}
diff --git a/Services/ClassifyHandlers/IHandlerClassify.cs b/Services/ClassifyHandlers/IHandlerClassify.cs
new file mode 100644
index 0000000..ba2f104
--- /dev/null
+++ b/Services/ClassifyHandlers/IHandlerClassify.cs
@@ -0,0 +1,11 @@
+using System.Reflection.Metadata;
+
+namespace ChatApi.Services.ClassifyHandlers
+{
+ public interface IHandlerClassify
+ {
+ IHandlerClassify SetNext(IHandlerClassify handler);
+
+ EnumClassification Handle(string request);
+ }
+}
diff --git a/Services/ResponseService/IResponseService.cs b/Services/ResponseService/IResponseService.cs
new file mode 100644
index 0000000..bbc4fcd
--- /dev/null
+++ b/Services/ResponseService/IResponseService.cs
@@ -0,0 +1,10 @@
+using ChatApi.Models;
+
+namespace ChatApi.Services.ResponseService
+{
+ public interface IResponseService
+ {
+ EnumClassification Classification { get; }
+ Task GetResponse(HttpContext context, UserData userData, string sessionId, string question);
+ }
+}
diff --git a/Services/ResponseService/ResponseBotRHService.cs b/Services/ResponseService/ResponseBotRHService.cs
new file mode 100644
index 0000000..fbaeb24
--- /dev/null
+++ b/Services/ResponseService/ResponseBotRHService.cs
@@ -0,0 +1,76 @@
+
+using ChatApi.Models;
+using ChatApi.Services.Bot;
+using ChatApi.Services.Bot.Structs;
+using ChatApi.Services.Classifier;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using Microsoft.SemanticKernel.Embeddings;
+using OllamaSharp.Models.Chat;
+
+#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+namespace ChatApi.Services.ResponseService
+{
+ public class ResponseBotRHService : IResponseService
+ {
+ private readonly ChatHistoryService _chatHistoryService;
+ private readonly TextFilter _textFilter;
+ private readonly ChatBotRHCall _chatBotCall;
+ private readonly ClassifierPersistence _classifierPersistence;
+
+ public ResponseBotRHService(
+ ChatHistoryService chatHistoryService,
+ TextFilter textFilter,
+ ChatBotRHCall chatBotCall,
+ ClassifierPersistence classifierPersistence)
+ {
+ _chatHistoryService = chatHistoryService;
+ _textFilter = textFilter;
+ _chatBotCall = chatBotCall;
+ _classifierPersistence = classifierPersistence;
+ }
+ public EnumClassification Classification => EnumClassification.BotRHCall;
+
+ public async Task GetResponse(HttpContext context, UserData userData, string sessionId, string question)
+ {
+ var stopWatch = new System.Diagnostics.Stopwatch();
+ stopWatch.Start();
+
+ SessionIdStore sessionIdStore = new SessionIdStore(context);
+ ChatHistory history = _chatHistoryService.GetSumarizer(sessionId);
+ _chatBotCall.UserData = userData;
+ var resp = _chatBotCall.SetAnswer(sessionId, question);
+ var resposta = "";
+ if (string.IsNullOrEmpty(resp) && resp!="REINICIAR")
+ {
+ resposta = await _chatBotCall.GetNextQuestion();
+ history.AddUserMessage(question);
+
+ history.AddMessage(AuthorRole.Assistant, resposta ?? "");
+
+ _chatHistoryService.UpdateHistory(sessionId, history);
+
+ if (!_chatBotCall.HasNextQuestion())
+ {
+ _classifierPersistence.DeleteState(sessionId);
+ }
+ }
+ else
+ {
+ if (resp == "REINICIAR")
+ {
+ _classifierPersistence.DeleteState(sessionId);
+ resp = "Ok! Parece que você não quer continuar e/ou eu não entendi sua resposta. Tudo bem! Se quiser, tente novamente depois...";
+ }
+
+ resposta = resp;
+ }
+
+ stopWatch.Stop();
+ return $"{resposta ?? ""}\n\nTempo: {stopWatch.ElapsedMilliseconds / 1000}s";
+ }
+ }
+}
+
+#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
diff --git a/Services/ResponseService/ResponseChatService.cs b/Services/ResponseService/ResponseChatService.cs
new file mode 100644
index 0000000..59f9b27
--- /dev/null
+++ b/Services/ResponseService/ResponseChatService.cs
@@ -0,0 +1,42 @@
+
+using ChatApi.Models;
+using Microsoft.SemanticKernel.ChatCompletion;
+using OllamaSharp.Models.Chat;
+using System.Diagnostics;
+
+namespace ChatApi.Services.ResponseService
+{
+ public class ResponseChatService : IResponseService
+ {
+ private readonly ChatHistoryService _chatHistoryService;
+ private readonly IChatCompletionService _chatCompletionService;
+
+ public ResponseChatService(
+ ChatHistoryService chatHistoryService,
+ IChatCompletionService chatCompletionService)
+ {
+ this._chatHistoryService = chatHistoryService;
+ this._chatCompletionService = chatCompletionService;
+ }
+ public EnumClassification Classification => EnumClassification.Chat;
+
+ public async Task GetResponse(HttpContext context, UserData userData, string sessionId, string question)
+ {
+ var stopWatch = new System.Diagnostics.Stopwatch();
+
+ stopWatch.Start();
+
+ SessionIdStore sessionIdStore = new SessionIdStore(context);
+ ChatHistory history = _chatHistoryService.Get(sessionId);
+
+ history.AddUserMessage(question);
+ var response = await _chatCompletionService.GetChatMessageContentAsync(history);
+ history.AddMessage(response.Role, response.Content ?? "");
+
+ _chatHistoryService.UpdateHistory(sessionId, history);
+
+ stopWatch.Stop();
+ return $"{response.Content ?? ""}\n\nTempo: {stopWatch.ElapsedMilliseconds / 1000}s";
+ }
+ }
+}
diff --git a/Services/ResponseService/ResponseCompanyService.cs b/Services/ResponseService/ResponseCompanyService.cs
new file mode 100644
index 0000000..db166ab
--- /dev/null
+++ b/Services/ResponseService/ResponseCompanyService.cs
@@ -0,0 +1,99 @@
+
+using ChatApi.Models;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using Microsoft.SemanticKernel.Embeddings;
+using OllamaSharp.Models.Chat;
+
+#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
+
+namespace ChatApi.Services.ResponseService
+{
+ public class ResponseCompanyService : IResponseService
+ {
+ private readonly ChatHistoryService _chatHistoryService;
+ private readonly Kernel _kernel;
+ private readonly TextFilter _textFilter;
+ private readonly SharepointDomvsService _sharepointDomvsService;
+ private readonly IChatCompletionService _chatCompletionService;
+
+ public ResponseCompanyService(
+ ChatHistoryService chatHistoryService,
+ Kernel kernel,
+ TextFilter textFilter,
+ SharepointDomvsService sharepointDomvsService,
+ IChatCompletionService chatCompletionService)
+ {
+ this._chatHistoryService = chatHistoryService;
+ this._kernel = kernel;
+ this._textFilter = textFilter;
+ this._sharepointDomvsService = sharepointDomvsService;
+ this._chatCompletionService = chatCompletionService;
+ }
+ public EnumClassification Classification => EnumClassification.Company;
+
+ public async Task GetResponse(HttpContext context, UserData userData, string sessionId, string question)
+ {
+ var stopWatch = new System.Diagnostics.Stopwatch();
+ stopWatch.Start();
+
+ SessionIdStore sessionIdStore = new SessionIdStore(context);
+
+ var resposta = await BuscarTextoRelacionado(question);
+ question = "Para responder à pergunta: \"" + question + "\" por favor, gere um resumo com 3 linhas baseado exclusivamente no texto: \"" + resposta + "\"";
+ ChatHistory history = _chatHistoryService.GetSumarizer(sessionId);
+
+ history.AddUserMessage(question);
+
+ var response = await _chatCompletionService.GetChatMessageContentAsync(history);
+ history.AddMessage(response.Role, response.Content ?? "");
+
+ _chatHistoryService.UpdateHistory(sessionId, history);
+
+ stopWatch.Stop();
+ return $"{response.Content ?? ""}\n\nTempo: {stopWatch.ElapsedMilliseconds / 1000}s";
+
+ }
+
+ async Task BuscarTextoRelacionado(string pergunta)
+ {
+ var embeddingService = _kernel.GetRequiredService();
+ var embeddingPergunta = await embeddingService.GenerateEmbeddingAsync(_textFilter.ToLowerAndWithoutAccents(pergunta));
+ var embeddingArrayPergunta = embeddingPergunta.ToArray().Select(e => (double)e).ToArray();
+
+ var textos = await _sharepointDomvsService.GetAsync();
+
+ TextoComEmbedding melhorTexto = null;
+ double melhorSimilaridade = -1.0;
+
+ foreach (var texto in textos)
+ {
+ double similaridade = CalcularSimilaridadeCoseno(embeddingArrayPergunta, texto.Embedding);
+ if (similaridade > melhorSimilaridade)
+ {
+ melhorSimilaridade = similaridade;
+ melhorTexto = texto;
+ }
+ }
+
+ // 4. Retornar o conteúdo mais similar, ou uma mensagem padrão
+ return melhorTexto != null ? melhorTexto.Conteudo : "Não encontrei uma resposta adequada.";
+ }
+
+ double CalcularSimilaridadeCoseno(double[] embedding1, double[] embedding2)
+ {
+ double dotProduct = 0.0;
+ double normA = 0.0;
+ double normB = 0.0;
+ for (int i = 0; i < embedding1.Length; i++)
+ {
+ dotProduct += embedding1[i] * embedding2[i];
+ normA += Math.Pow(embedding1[i], 2);
+ normB += Math.Pow(embedding2[i], 2);
+ }
+ return dotProduct / (Math.Sqrt(normA) * Math.Sqrt(normB));
+ }
+ }
+}
+
+#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
diff --git a/Services/ResponseService/ResponseFactory.cs b/Services/ResponseService/ResponseFactory.cs
new file mode 100644
index 0000000..f1fd60a
--- /dev/null
+++ b/Services/ResponseService/ResponseFactory.cs
@@ -0,0 +1,18 @@
+using System.Net.NetworkInformation;
+
+namespace ChatApi.Services.ResponseService
+{
+ public class ResponseFactory
+ {
+ private readonly IEnumerable _responseServices;
+ public ResponseFactory(IEnumerable responseService)
+ {
+ _responseServices = responseService;
+ }
+
+ public IResponseService? GetService(EnumClassification classification)
+ {
+ return _responseServices.FirstOrDefault(w => w.Classification == classification);
+ }
+ }
+}
diff --git a/Services/TextClassifier.cs b/Services/TextClassifier.cs
new file mode 100644
index 0000000..0f7a925
--- /dev/null
+++ b/Services/TextClassifier.cs
@@ -0,0 +1,60 @@
+using ChatApi.Services.Classifier;
+using ChatApi.Services.ClassifyHandlers;
+
+namespace ChatApi.Services
+{
+ public enum EnumClassification
+ {
+ Company=0,
+ Estimate=1,
+ BotRHCall = 2,
+ Chat = 3,
+ CantDetect=4
+ }
+
+ ///
+ /// enum
+ ///
+ public class TextClassifier
+ {
+ private readonly TextFilter _textFilter;
+ private readonly ClassifierPersistence _classifierPersistence;
+
+ public TextClassifier(TextFilter textFilter, ClassifierPersistence classifierPersistence)
+ {
+ _textFilter = textFilter;
+ _classifierPersistence = classifierPersistence;
+ }
+ public async Task ClassifyQuestion(string sessionId, string question)
+ {
+ var state = _classifierPersistence.GetState(sessionId);
+
+ if (state!=null && (state.ClassificationType == EnumClassificationType.Stay))
+ {
+ return state.Classification;
+ }
+ else
+ {
+ var classifyCompany = new ClassifyCompany();
+ var classifyChat = new ClassifyChat();
+ var botChat = new ClassifyBotRHCall();
+
+ classifyCompany
+ .SetNext(botChat)
+ .SetNext(classifyChat);
+
+ var classify = classifyCompany.Handle(question);
+
+ _classifierPersistence.SaveState(new ClassifierSate
+ {
+ Id = sessionId,
+ UsuarioId = sessionId,
+ Classification = classify,
+ DhInicio = DateTime.Now,
+ ClassificationType = botChat.MyClassification == classify ? EnumClassificationType.Stay : EnumClassificationType.Free
+ });
+ return classify;
+ }
+ }
+ }
+}
diff --git a/Services/TextFilter.cs b/Services/TextFilter.cs
new file mode 100644
index 0000000..15a0594
--- /dev/null
+++ b/Services/TextFilter.cs
@@ -0,0 +1,33 @@
+using System.Globalization;
+using System.Text;
+
+namespace ChatApi.Services
+{
+ public class TextFilter
+ {
+ public string ToLowerAndWithoutAccents(string text)
+ {
+ return RemoveDiacritics(text.ToLower());
+ }
+
+ public string RemoveDiacritics(string text)
+ {
+ var normalizedString = text.Normalize(NormalizationForm.FormD);
+ var stringBuilder = new StringBuilder(capacity: normalizedString.Length);
+
+ for (int i = 0; i < normalizedString.Length; i++)
+ {
+ char c = normalizedString[i];
+ var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
+ if (unicodeCategory != UnicodeCategory.NonSpacingMark)
+ {
+ stringBuilder.Append(c);
+ }
+ }
+
+ return stringBuilder
+ .ToString()
+ .Normalize(NormalizationForm.FormC);
+ }
+ }
+}
diff --git a/SessionIdStore.cs b/SessionIdStore.cs
new file mode 100644
index 0000000..fbd1b3a
--- /dev/null
+++ b/SessionIdStore.cs
@@ -0,0 +1,32 @@
+namespace ChatApi
+{
+ public class SessionIdStore
+ {
+ HttpContext _context;
+
+ public SessionIdStore(HttpContext httpContext)
+ {
+ _context = httpContext;
+ }
+
+ public string GetSessionId()
+ {
+ var sessionId = _context.Request.Cookies["ChatSessionId"];
+
+ if (sessionId == null)
+ {
+ sessionId = Guid.NewGuid().ToString("N");
+ _context.Response.Cookies.Append("ChatSessionId", sessionId, new CookieOptions
+ {
+ Expires = DateTimeOffset.Now.AddMonths(12),
+ HttpOnly = true,
+ SameSite = SameSiteMode.None,
+ Secure = true
+ });
+ }
+
+
+ return sessionId;
+ }
+ }
+}
diff --git a/Settings/ChatRHSettings.cs b/Settings/ChatRHSettings.cs
new file mode 100644
index 0000000..ca37ab1
--- /dev/null
+++ b/Settings/ChatRHSettings.cs
@@ -0,0 +1,8 @@
+namespace ChatApi.Settings
+{
+ public class ChatRHSettings
+ {
+ public string Url { get; set; }
+ public string Create { get; set; }
+ }
+}
diff --git a/SharepointDomvsService.cs b/SharepointDomvsService.cs
new file mode 100644
index 0000000..e4956ca
--- /dev/null
+++ b/SharepointDomvsService.cs
@@ -0,0 +1,38 @@
+using Microsoft.Extensions.Options;
+using MongoDB.Driver;
+
+namespace ChatApi
+{
+ public class SharepointDomvsService
+ {
+ private readonly IMongoCollection _booksCollection;
+
+ public SharepointDomvsService(
+ IOptions bookStoreDatabaseSettings)
+ {
+ var mongoClient = new MongoClient(
+ bookStoreDatabaseSettings.Value.ConnectionString);
+
+ var mongoDatabase = mongoClient.GetDatabase(
+ bookStoreDatabaseSettings.Value.DatabaseName);
+
+ _booksCollection = mongoDatabase.GetCollection(
+ bookStoreDatabaseSettings.Value.SharepointCollectionName);
+ }
+
+ public async Task> GetAsync() =>
+ await _booksCollection.Find(_ => true).ToListAsync();
+
+ public async Task GetAsync(string id) =>
+ await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync();
+
+ public async Task CreateAsync(TextoComEmbedding newBook) =>
+ await _booksCollection.InsertOneAsync(newBook);
+
+ public async Task UpdateAsync(string id, TextoComEmbedding updatedBook) =>
+ await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook);
+
+ public async Task RemoveAsync(string id) =>
+ await _booksCollection.DeleteOneAsync(x => x.Id == id);
+ }
+}
diff --git a/TextoComEmbedding.cs b/TextoComEmbedding.cs
new file mode 100644
index 0000000..62c5091
--- /dev/null
+++ b/TextoComEmbedding.cs
@@ -0,0 +1,16 @@
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson;
+
+namespace ChatApi
+{
+ public class TextoComEmbedding
+ {
+ [BsonId]
+ [BsonElement("_id")]
+ [BsonRepresentation(BsonType.ObjectId)]
+ public string Id { get; set; }
+
+ public string Conteudo { get; set; }
+ public double[] Embedding { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/appsettings.Development.json b/appsettings.Development.json
new file mode 100644
index 0000000..0f2755a
--- /dev/null
+++ b/appsettings.Development.json
@@ -0,0 +1,19 @@
+{
+ "DomvsDatabase": {
+ "ConnectionString": "mongodb://localhost:27017",
+ "DatabaseName": "DomvsSites",
+ "SharepointCollectionName": "SharepointSite",
+ "ChatBotRHCollectionName": "ChatBotRHData",
+ "ClassifierCollectionName": "ClassifierData"
+ },
+ "ChatRHSettings": {
+ "Url": "https://localhost:7070/",
+ "Create": "/CallRH"
+ },
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/appsettings.json b/appsettings.json
new file mode 100644
index 0000000..4c39c1b
--- /dev/null
+++ b/appsettings.json
@@ -0,0 +1,22 @@
+{
+ "DomvsDatabase": {
+ "ConnectionString": "mongodb://localhost:27017",
+ "DatabaseName": "DomvsSites",
+ "SharepointCollectionName": "SharepointSite",
+ "ChatBotRHCollectionName": "ChatBotRHData",
+ "ClassifierCollectionName": "ClassifierData"
+ },
+ "ChatRHSettings": {
+ "Url": "mongodb://localhost:27017",
+ "Create": "DomvsSites"
+ },
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*",
+ "AppTenantId": "20190830-5fd4-4a72-b8fd-1c1cb35b25bc",
+ "AppClientID": "8f4248fc-ee30-4f54-8793-66edcca3fd20"
+}