From fdb4fc6996415e2cd210f9305a7b92f5fbf96680 Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro <71648276+ricarneiro@users.noreply.github.com> Date: Tue, 10 Jun 2025 02:22:58 -0300 Subject: [PATCH] feat: RAG por projeto --- ChatHistoryService.cs | 38 +----- ChatRAG.csproj | 1 + Controllers/ChatController.cs | 54 +++++++- Controllers/LoginController.cs | 123 ------------------ Controllers/LoginRequest.cs | 9 -- Data/ProjectDataRepository.cs | 58 +++++++++ Data/TextData.cs | 27 ++-- .../TextDataRepository.cs | 12 +- DomvsDatabaseSettings.cs | 5 +- Models/Project.cs | 19 +++ Program.cs | 41 ++---- Requests/ChatRequest.cs | 1 + Requests/ProjectRequest.cs | 16 +++ Services/ResponseService/IResponseService.cs | 2 +- .../ResponseService/ResponseCompanyService.cs | 30 +++-- ...opment.json => appsettings.Production.json | 0 appsettings.json | 24 +--- 17 files changed, 206 insertions(+), 254 deletions(-) delete mode 100644 Controllers/LoginController.cs delete mode 100644 Controllers/LoginRequest.cs create mode 100644 Data/ProjectDataRepository.cs rename Repositories/TextDataService.cs => Data/TextDataRepository.cs (76%) create mode 100644 Models/Project.cs create mode 100644 Requests/ProjectRequest.cs rename appsettings.Development.json => appsettings.Production.json (100%) diff --git a/ChatHistoryService.cs b/ChatHistoryService.cs index c72abc5..a54c8a8 100644 --- a/ChatHistoryService.cs +++ b/ChatHistoryService.cs @@ -13,17 +13,6 @@ namespace ChatApi 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]; @@ -32,7 +21,7 @@ namespace ChatApi else { var msg = new List(); - TestePrompt(msg); + PromptLiliana(msg); string json = JsonSerializer.Serialize(msg); var history = new ChatHistory(JsonSerializer.Deserialize>(json)); _keyValues[sessionId] = history; @@ -63,32 +52,11 @@ namespace ChatApi _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 PromptLiliana(List msg) { - msg.Add(new ChatMessageContent(AuthorRole.System, "Seu nome é LiliAna, um assistente virtual da Domvs It (Consultoria e RH).")); - msg.Add(new ChatMessageContent(AuthorRole.System, "Você responde sempre em português do Brasil e fala sobre serviços prestados pela Domvs iT.")); - msg.Add(new ChatMessageContent(AuthorRole.System, "Você consegue fazer solicitações no portal do RH da Domvs iT.")); - msg.Add(new ChatMessageContent(AuthorRole.System, "Você responde perguntas voltadas ao mercado de trabalho de tecnologia.")); - msg.Add(new ChatMessageContent(AuthorRole.System, "Em breve, você será capaz de consultar o linkedin.")); + msg.Add(new ChatMessageContent(AuthorRole.System, "Seu nome é LiliAna, uma assistente virtual para projetos.")); + msg.Add(new ChatMessageContent(AuthorRole.System, "Você responde sempre em português do Brasil e fala sobre detalhes de projeto, arquitetura e criação de casos de teste.")); 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/ChatRAG.csproj b/ChatRAG.csproj index dff7904..750d5fe 100644 --- a/ChatRAG.csproj +++ b/ChatRAG.csproj @@ -10,6 +10,7 @@ + diff --git a/Controllers/ChatController.cs b/Controllers/ChatController.cs index 1d9cb3d..87ba158 100644 --- a/Controllers/ChatController.cs +++ b/Controllers/ChatController.cs @@ -3,6 +3,10 @@ using Microsoft.AspNetCore.Authorization; using ChatApi.Data; using ChatRAG.Services.ResponseService; using ChatRAG.Services; +using ChatRAG.Data; +using ChatRAG.Models; +using ChatRAG.Requests; +using BlazMapper; #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. @@ -16,6 +20,7 @@ namespace ChatApi.Controllers private readonly IResponseService _responseService; private readonly TextFilter _textFilter; private readonly UserDataRepository _userDataRepository; + private readonly ProjectDataRepository _projectDataRepository; private readonly TextData _textData; private readonly IHttpClientFactory _httpClientFactory; @@ -24,30 +29,64 @@ namespace ChatApi.Controllers IResponseService responseService, UserDataRepository userDataRepository, TextData textData, + ProjectDataRepository projectDataRepository, IHttpClientFactory httpClientFactory) { _logger = logger; _responseService = responseService; _userDataRepository = userDataRepository; _textData = textData; + _projectDataRepository = projectDataRepository; this._httpClientFactory = httpClientFactory; } [HttpPost] [Route("response")] - [Authorize] - public async Task GetResponse([FromForm] ChatRequest chatRequest) + public async Task GetResponse([FromForm] ChatRequest chatRequest) { - var userData = await _userDataRepository.GeByTokentAsync(AppDomain.CurrentDomain.GetData("Token") as string); - var response = await _responseService.GetResponse(userData, chatRequest.SessionId, chatRequest.Message); - return response; + try + { + var userData = await _userDataRepository.GeByTokentAsync(chatRequest.SessionId); + var response = await _responseService.GetResponse(userData, chatRequest.ProjectId, chatRequest.SessionId, chatRequest.Message); + return Ok(response); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } } + + [HttpPost] + [Route("saveproject")] + public async Task SaveSingleProject([FromBody] ProjectRequest project) + { + var projectSave = project.MapTo(); + await _projectDataRepository.SaveAsync(projectSave); + } + + [HttpGet] + [Route("projects")] + public async Task> GetProjects() + { + var projects = await _projectDataRepository.GetAsync(); + return projects.Select(s => s.MapTo()); + } + + [HttpPost] [Route("savetext")] - public async Task SaveSingleText([FromBody] TextRequest request) + public async Task SaveSingleText([FromBody] TextRequest request) { - await _textData.SalvarNoMongoDB(request.Id, request.Title, request.Content); + try + { + await _textData.SalvarNoMongoDB(request.Id, request.Title, request.Content, request.ProjectId); + return Created(); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } } [HttpGet] @@ -91,6 +130,7 @@ namespace ChatApi.Controllers public class TextRequest { public string? Id { get; set; } + public string ProjectId { get; set; } public string Title { get; set; } public string Content { get; set; } } diff --git a/Controllers/LoginController.cs b/Controllers/LoginController.cs deleted file mode 100644 index 6922a17..0000000 --- a/Controllers/LoginController.cs +++ /dev/null @@ -1,123 +0,0 @@ -using ChatApi.Models; -using ChatApi.Services.Crypt; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Cors; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.IdentityModel.Tokens; -using System.Globalization; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Security.Cryptography; -using System.Text; -using System.Text.Json; - -namespace ChatApi.Controllers -{ - [Route("[controller]")] - [ApiController] - [EnableCors("AllowSpecificOrigin")] - public class LoginController : ControllerBase - { - private readonly IConfigurationManager _configuration; - private readonly UserDataRepository _userDataRepository; - private readonly CryptUtil _cryptUtil; - - public LoginController(IConfigurationManager configuration, UserDataRepository userDataRepository, CryptUtil cryptUtil) - { - _configuration = configuration; - _userDataRepository = userDataRepository; - _cryptUtil = cryptUtil; - } - - [AllowAnonymous] - [HttpPost] - [Route("token")] - public async Task Post([FromBody] LoginRequest loginRequest) - { - if (ModelState.IsValid) - { - try - { - var userDataFrom = await _userDataRepository.GetAsync(loginRequest.ClientName, loginRequest.ClientId, loginRequest.ClientSecret); - if (userDataFrom==null) - { - return Unauthorized(); - } - - var token = ""; - if (userDataFrom.LastToken == null && (userDataFrom.DateTimeToken != null && userDataFrom.DateTimeToken.Value.AddHours(24) > DateTime.Now)) - { - token = userDataFrom.LastToken; - } - else - { - var claims = new[] - { - new Claim("Sub", userDataFrom.CompanyTenant), - new Claim("NameId", userDataFrom.Name), - new Claim(ClaimTypes.NameIdentifier, loginRequest.ClientId), - new Claim("DhCriado", DateTime.Now.ToString(new CultureInfo("pt-BR"))), - new Claim("TenantId", userDataFrom.CompanyTenant), - new Claim(ClaimTypes.Role, "TeamsUser") - }; - - var expires = DateTime.UtcNow.AddMinutes(30); - var tokenGen = new JwtSecurityToken - ( - issuer: _configuration["Issuer"], - audience: _configuration["Audience"], - claims: claims, - expires: expires, - notBefore: DateTime.UtcNow, - signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SigningKey"])), - SecurityAlgorithms.HmacSha256) - ); - - token = new JwtSecurityTokenHandler().WriteToken(tokenGen); - } - userDataFrom.LastToken = token; - userDataFrom.DateTimeToken = DateTime.Now; - await _userDataRepository.UpdateAsync(userDataFrom.Id, userDataFrom); - - return Ok(new { token = token }); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - return BadRequest(); - } - - [AllowAnonymous] - [HttpPost] - [Route("newclient")] - public async Task NewClient([FromBody] UserRequest userDataFrom) - { - if (ModelState.IsValid) - { - try - { - var userData = await _userDataRepository.GetAsync(userDataFrom.Name, userDataFrom.LocalId); - if (userData == null) - { - var secret = _cryptUtil.Encrypt(JsonSerializer.Serialize(userDataFrom)); - userData = UserData.Create(userDataFrom, secret); - await _userDataRepository.CreateAsync(userData); - } - - return Created("newclient", userData); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - return BadRequest(); - } - } -} diff --git a/Controllers/LoginRequest.cs b/Controllers/LoginRequest.cs deleted file mode 100644 index d32158e..0000000 --- a/Controllers/LoginRequest.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChatApi.Controllers -{ - public class LoginRequest - { - public string ClientId { get; set; } - public string ClientName { get; set; } - public string ClientSecret { get; set; } - } -} diff --git a/Data/ProjectDataRepository.cs b/Data/ProjectDataRepository.cs new file mode 100644 index 0000000..185e2ca --- /dev/null +++ b/Data/ProjectDataRepository.cs @@ -0,0 +1,58 @@ +using ChatApi; +using ChatRAG.Models; +using Microsoft.Extensions.Options; +using MongoDB.Driver; + +namespace ChatRAG.Data +{ + public class ProjectDataRepository + { + private readonly IMongoCollection _textsCollection; + + public ProjectDataRepository( + IOptions databaseSettings) + { + var mongoClient = new MongoClient( + databaseSettings.Value.ConnectionString); + + var mongoDatabase = mongoClient.GetDatabase( + databaseSettings.Value.DatabaseName); + + _textsCollection = mongoDatabase.GetCollection( + databaseSettings.Value.ProjectCollectionName); + } + + public async Task> GetAsync() => + await _textsCollection.Find(_ => true).ToListAsync(); + + public async Task GetAsync(string id) => + await _textsCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); + + public async Task CreateAsync(Project newProject) => + await _textsCollection.InsertOneAsync(newProject); + + public async Task UpdateAsync(string id, Project updatedProject) => + await _textsCollection.ReplaceOneAsync(x => x.Id == id, updatedProject); + + public async Task SaveAsync(Project project) + { + Project projectExist = null; + if (project.Id != null) + { + projectExist = await _textsCollection.Find(x => x.Id == project.Id).FirstOrDefaultAsync(); + } + + if (projectExist == null) + { + await _textsCollection.InsertOneAsync(project); + } + else + { + await _textsCollection.ReplaceOneAsync(x => x.Id == project.Id, project); + } + } + + public async Task RemoveAsync(string id) => + await _textsCollection.DeleteOneAsync(x => x.Id == id); + } +} diff --git a/Data/TextData.cs b/Data/TextData.cs index eeb1c92..f816ac2 100644 --- a/Data/TextData.cs +++ b/Data/TextData.cs @@ -1,5 +1,5 @@ -using ChatRAG.Models; -using ChatRAG.Repositories; +using ChatRAG.Data; +using ChatRAG.Models; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Embeddings; using System.Text; @@ -11,15 +11,15 @@ namespace ChatApi.Data public class TextData { private readonly ITextEmbeddingGenerationService _textEmbeddingGenerationService; - private readonly TextDataService _textDataService; + private readonly TextDataRepository _textDataService; - public TextData(ITextEmbeddingGenerationService textEmbeddingGenerationService, TextDataService textDataService) + public TextData(ITextEmbeddingGenerationService textEmbeddingGenerationService, TextDataRepository textDataService) { _textEmbeddingGenerationService = textEmbeddingGenerationService; _textDataService = textDataService; } - public async Task SalvarTextoComEmbeddingNoMongoDB(string textoCompleto) + public async Task SalvarTextoComEmbeddingNoMongoDB(string textoCompleto, string projectId) { var textoArray = new List(); string[] textolinhas = textoCompleto.Split( @@ -49,19 +49,20 @@ namespace ChatApi.Data foreach(var item in textoArray) { - await SalvarNoMongoDB(title, item); + await SalvarNoMongoDB(title, item, projectId); } } - public async Task SalvarNoMongoDB(string titulo, string texto) + public async Task SalvarNoMongoDB(string titulo, string texto, string projectId) { await SalvarNoMongoDB(null, titulo, texto); } - public async Task SalvarNoMongoDB(string? id, string titulo, string texto) + public async Task SalvarNoMongoDB(string? id, string titulo, string texto, string projectId) { + var conteudo = $"**{titulo}** \n\n {texto}"; // Gerar embedding para o texto - var embedding = await _textEmbeddingGenerationService.GenerateEmbeddingAsync(texto); + var embedding = await _textEmbeddingGenerationService.GenerateEmbeddingAsync(conteudo); // Converter embedding para um formato serializável (como um array de floats) var embeddingArray = embedding.ToArray().Select(e => (double)e).ToArray(); @@ -74,6 +75,7 @@ namespace ChatApi.Data { Titulo = titulo, Conteudo = texto, + ProjetoId = projectId, Embedding = embeddingArray }; @@ -86,6 +88,7 @@ namespace ChatApi.Data Id = id, Titulo = titulo, Conteudo = texto, + ProjetoId = projectId, Embedding = embeddingArray }; @@ -97,6 +100,12 @@ namespace ChatApi.Data { return await _textDataService.GetAsync(); } + + public async Task> GetByPorjectId(string porjectId) + { + return await _textDataService.GetByProjectIdAsync(porjectId); + } + public async Task GetById(string id) { return await _textDataService.GetAsync(id); diff --git a/Repositories/TextDataService.cs b/Data/TextDataRepository.cs similarity index 76% rename from Repositories/TextDataService.cs rename to Data/TextDataRepository.cs index f81a3be..536da5a 100644 --- a/Repositories/TextDataService.cs +++ b/Data/TextDataRepository.cs @@ -1,15 +1,16 @@ using ChatApi; using ChatRAG.Models; using Microsoft.Extensions.Options; +using MongoDB.Bson; using MongoDB.Driver; -namespace ChatRAG.Repositories +namespace ChatRAG.Data { - public class TextDataService + public class TextDataRepository { private readonly IMongoCollection _textsCollection; - public TextDataService( + public TextDataRepository( IOptions bookStoreDatabaseSettings) { var mongoClient = new MongoClient( @@ -19,12 +20,15 @@ namespace ChatRAG.Repositories bookStoreDatabaseSettings.Value.DatabaseName); _textsCollection = mongoDatabase.GetCollection( - bookStoreDatabaseSettings.Value.SharepointCollectionName); + bookStoreDatabaseSettings.Value.TextCollectionName); } public async Task> GetAsync() => await _textsCollection.Find(_ => true).ToListAsync(); + public async Task> GetByProjectIdAsync(string projectId) => + await _textsCollection.Find(s => s.ProjetoId == ObjectId.Parse(projectId).ToString()).ToListAsync(); + public async Task GetAsync(string id) => await _textsCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); diff --git a/DomvsDatabaseSettings.cs b/DomvsDatabaseSettings.cs index 5c310e1..16cbcc6 100644 --- a/DomvsDatabaseSettings.cs +++ b/DomvsDatabaseSettings.cs @@ -6,12 +6,11 @@ public string DatabaseName { get; set; } = null!; - public string SharepointCollectionName { get; set; } = null!; + public string TextCollectionName { get; set; } = null!; public string UserDataName { get; set; } = null!; - public string ChatBotRHCollectionName { get; set; } = null!; + public string ProjectCollectionName { get; set; } = null!; - public string ClassifierCollectionName { get; set; } = null!; } } diff --git a/Models/Project.cs b/Models/Project.cs new file mode 100644 index 0000000..2a387c6 --- /dev/null +++ b/Models/Project.cs @@ -0,0 +1,19 @@ +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson; + +namespace ChatRAG.Models +{ + public class Project + { + [BsonId] + [BsonElement("_id")] + [BsonRepresentation(BsonType.ObjectId)] + public string Id { get; set; } + + public string Nome { get; set; } + public string Descricao { get; set; } + public DateTime DataCriacao { get; set; } + public string Status { get; set; } // "ativo", "arquivado", etc. + public string[] Tecnologias { get; set; } + } +} diff --git a/Program.cs b/Program.cs index d52b5c7..39fd3d3 100644 --- a/Program.cs +++ b/Program.cs @@ -3,7 +3,7 @@ using ChatApi.Data; using ChatApi.Middlewares; using ChatApi.Services.Crypt; using ChatApi.Settings; -using ChatRAG.Repositories; +using ChatRAG.Data; using ChatRAG.Services; using ChatRAG.Services.ResponseService; using Microsoft.AspNetCore.Authentication.JwtBearer; @@ -76,7 +76,8 @@ builder.Services.Configure( builder.Configuration.GetSection("ChatRHSettings")); builder.Services.AddSingleton(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddScoped(); @@ -84,25 +85,25 @@ builder.Services.AddTransient(); builder.Services.AddTransient(); 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"); -//Olllama notebook -//builder.Services.AddOllamaChatCompletion("phi3.5", new Uri("http://localhost:11435")); +//Olllama +builder.Services.AddOllamaChatCompletion("llama3.1", new Uri("http://localhost:11434")); //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.AddOpenAIChatCompletion("openchat-3.5-0106", new Uri("https://gpt.serverspace.com.br/v1/chat/completions"), "tIAXVf3AkCkkpSX+PjFvktfEeSPyA1ZYam50UO3ye/qmxVZX6PIXstmJsLZXkQ39C33onFD/81mdxvhbGHm7tQ=="); //Ollama local server (scorpion) //builder.Services.AddOllamaChatCompletion("llama3.1:latest", new Uri("http://192.168.0.150:11434")); -builder.Services.AddOllamaTextEmbeddingGeneration("all-minilm", new Uri("http://192.168.0.150:11434")); +//builder.Services.AddOllamaTextEmbeddingGeneration("all-minilm", new Uri("http://192.168.0.150:11434")); +builder.Services.AddOllamaTextEmbeddingGeneration("all-minilm", new Uri("http://localhost:11434")); //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"); @@ -128,31 +129,6 @@ builder.Services.AddHttpClient(); var tenantId = builder.Configuration.GetSection("AppTenantId"); var clientId = builder.Configuration.GetSection("AppClientID"); -builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) -.AddJwtBearer(jwtBearerOptions => -{ - jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters() - { - ValidateActor = true, - ValidateAudience = true, - ValidateLifetime = true, - ValidateIssuerSigningKey = true, - ValidIssuer = builder.Configuration["Issuer"], - ValidAudience = builder.Configuration["Audience"], - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["SigningKey"])) - }; - jwtBearerOptions.Events = new JwtBearerEvents() - { - OnTokenValidated = async context => - { - var token = context.SecurityToken as JsonWebToken; - context.HttpContext.Items["Token"] = token.EncodedToken; - AppDomain.CurrentDomain.SetData("Token", token.EncodedToken); - } - }; -}) -; - //builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")); @@ -212,6 +188,7 @@ if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); + app.UseDeveloperExceptionPage(); // Isso mostra erros detalhados } //app.UseHttpsRedirection(); diff --git a/Requests/ChatRequest.cs b/Requests/ChatRequest.cs index 9bb4650..99e2e6a 100644 --- a/Requests/ChatRequest.cs +++ b/Requests/ChatRequest.cs @@ -3,6 +3,7 @@ public class ChatRequest { public string SessionId { get; set; } = string.Empty; + public string ProjectId { get; set; } = string.Empty; public string Message { get; set; } = string.Empty; } diff --git a/Requests/ProjectRequest.cs b/Requests/ProjectRequest.cs new file mode 100644 index 0000000..a7dfdeb --- /dev/null +++ b/Requests/ProjectRequest.cs @@ -0,0 +1,16 @@ +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson; + +namespace ChatRAG.Requests +{ + public class ProjectRequest + { + public string? Id { get; set; } + + public string Nome { get; set; } + public string Descricao { get; set; } + public DateTime DataCriacao { get; set; } + public string Status { get; set; } // "ativo", "arquivado", etc. + public string[] Tecnologias { get; set; } + } +} diff --git a/Services/ResponseService/IResponseService.cs b/Services/ResponseService/IResponseService.cs index 9fe2877..f61508e 100644 --- a/Services/ResponseService/IResponseService.cs +++ b/Services/ResponseService/IResponseService.cs @@ -4,6 +4,6 @@ namespace ChatRAG.Services.ResponseService { public interface IResponseService { - Task GetResponse(UserData userData, string sessionId, string question); + Task GetResponse(UserData userData, string projectId, string sessionId, string question); } } diff --git a/Services/ResponseService/ResponseCompanyService.cs b/Services/ResponseService/ResponseCompanyService.cs index 5796d2d..583035c 100644 --- a/Services/ResponseService/ResponseCompanyService.cs +++ b/Services/ResponseService/ResponseCompanyService.cs @@ -1,8 +1,8 @@  using ChatApi; using ChatApi.Models; +using ChatRAG.Data; using ChatRAG.Models; -using ChatRAG.Repositories; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.ChatCompletion; using Microsoft.SemanticKernel.Embeddings; @@ -16,31 +16,39 @@ namespace ChatRAG.Services.ResponseService private readonly ChatHistoryService _chatHistoryService; private readonly Kernel _kernel; private readonly TextFilter _textFilter; - private readonly TextDataService _textDataService; + private readonly TextDataRepository _textDataRepository; + private readonly ProjectDataRepository _projectDataRepository; private readonly IChatCompletionService _chatCompletionService; public ResponseRAGService( ChatHistoryService chatHistoryService, Kernel kernel, TextFilter textFilter, - TextDataService textDataService, + TextDataRepository textDataRepository, + ProjectDataRepository projectDataRepository, IChatCompletionService chatCompletionService) { this._chatHistoryService = chatHistoryService; this._kernel = kernel; this._textFilter = textFilter; - this._textDataService = textDataService; + this._textDataRepository = textDataRepository; + this._projectDataRepository = projectDataRepository; this._chatCompletionService = chatCompletionService; } - public async Task GetResponse(UserData userData, string sessionId, string question) + + public async Task GetResponse(UserData userData, string projectId, string sessionId, string question) { var stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); //var resposta = await BuscarTextoRelacionado(question); - var resposta = await BuscarTopTextosRelacionados(question); - - question = "Para responder à solicitação/pergunta: \"" + question + "\" por favor, considere um resumo com 3 linhas baseado exclusivamente no texto: \"" + resposta + "\""; + var resposta = await BuscarTopTextosRelacionados(question, projectId); + + var projectData = (await _projectDataRepository.GetAsync()).FirstOrDefault(); + + var project = $"Nome: {projectData.Nome} \n\n Descrição:{projectData.Descricao}"; + + question = $"Para responder à solicitação/pergunta: \"{question }\" por favor, considere o projeto: \"{project}\" e os requisitos: \"{resposta}\""; ChatHistory history = _chatHistoryService.GetSumarizer(sessionId); history.AddUserMessage(question); @@ -61,7 +69,7 @@ namespace ChatRAG.Services.ResponseService var embeddingPergunta = await embeddingService.GenerateEmbeddingAsync(_textFilter.ToLowerAndWithoutAccents(pergunta)); var embeddingArrayPergunta = embeddingPergunta.ToArray().Select(e => (double)e).ToArray(); - var textos = await _textDataService.GetAsync(); + var textos = await _textDataRepository.GetAsync(); TextoComEmbedding melhorTexto = null; double melhorSimilaridade = -1.0; @@ -79,13 +87,13 @@ namespace ChatRAG.Services.ResponseService return melhorTexto != null ? melhorTexto.Conteudo : "Não encontrei uma resposta adequada."; } - async Task BuscarTopTextosRelacionados(string pergunta, int size = 3) + async Task BuscarTopTextosRelacionados(string pergunta, string projectId, int size = 3) { var embeddingService = _kernel.GetRequiredService(); var embeddingPergunta = await embeddingService.GenerateEmbeddingAsync(_textFilter.ToLowerAndWithoutAccents(pergunta)); var embeddingArrayPergunta = embeddingPergunta.ToArray().Select(e => (double)e).ToArray(); - var textos = await _textDataService.GetAsync(); + var textos = await _textDataRepository.GetByProjectIdAsync(projectId); var melhoresTextos = textos .Select(texto => new diff --git a/appsettings.Development.json b/appsettings.Production.json similarity index 100% rename from appsettings.Development.json rename to appsettings.Production.json diff --git a/appsettings.json b/appsettings.json index a300e43..933fafa 100644 --- a/appsettings.json +++ b/appsettings.json @@ -1,16 +1,11 @@ { "DomvsDatabase": { - "ConnectionString": "mongodb://192.168.0.82:30017/?directConnection=true", - "DatabaseName": "DomvsSites", - "SharepointCollectionName": "SharepointSite", - "ChatBotRHCollectionName": "ChatBotRHData", - "ClassifierCollectionName": "ClassifierData", + "ConnectionString": "mongodb://admin:c4rn31r0@k3sw2:27017,k3ss1:27017/?authSource=admin", + "DatabaseName": "RAGProjects-dev", + "TextCollectionName": "Texts", + "ProjectCollectionName": "Projects", "UserDataName": "UserData" }, - "ChatRHSettings": { - "Url": "http://apirhcall.lhost.dynu.net", - "Create": "/CallRH" - }, "Logging": { "LogLevel": { "Default": "Information", @@ -21,15 +16,4 @@ "AllowedHosts": "*", "AppTenantId": "20190830-5fd4-4a72-b8fd-1c1cb35b25bc", "AppClientID": "8f4248fc-ee30-4f54-8793-66edcca3fd20", - - "AzureAd": { - "Instance": "https://login.microsoftonline.com/", - "Domain": "domvsitbr.onmicrosoft.com", - "TenantId": "20190830-5fd4-4a72-b8fd-1c1cb35b25bc", - "ClientId": "8f4248fc-ee30-4f54-8793-66edcca3fd20" - }, - "Issuer": "domvsit.com.br", - "Audience": "domvsit.com.br", - "SigningKey": "D57Ls16KxMPdF4P7qTQtV29slWjJqIJZ", - "DataKey": "NOxGacYtZRJTYCPdSQM75HVSNp3qfH05mPalaE/pL4A6FwxWKQiBhLxhu++LrKsI" }