Ver código fonte

menu deroulants dans le navmenu

debut gerstion des audit
WebUI
maela 4 dias atrás
pai
commit
f405c8927c
5 arquivos alterados com 253 adições e 84 exclusões
  1. +1
    -1
      WebUI/ReAct_PME.Api/Controllers/custom/ChatRoomController.cs
  2. +220
    -77
      WebUI/ReAct_PME.WebUI/Layout/NavMenu.razor
  3. +5
    -5
      WebUI/ReAct_PME.WebUI/Pages/ChatRoom/ChatRoom_base.razor
  4. +1
    -1
      WebUI/ReAct_PME.WebUI/Pages/ChatRoom/ChatRoom_base.razor.cs
  5. +26
    -0
      WebUI/ReAct_PME.WebUI/wwwroot/css/app.css

+ 1
- 1
WebUI/ReAct_PME.Api/Controllers/custom/ChatRoomController.cs Ver arquivo

@@ -65,7 +65,7 @@ namespace ReAct_PME_API.Controllers
}
else if (typeLLM == 3)
{
lst = lst.Where(c => c.TypeConv.ToUpper() == "CODE").ToList();
lst = lst.Where(c => c.TypeConv.ToUpper() == "AUDIT").ToList();
}
else if (typeLLM == 4)
{

+ 220
- 77
WebUI/ReAct_PME.WebUI/Layout/NavMenu.razor Ver arquivo

@@ -28,53 +28,63 @@
<div class="sidebar-section">
@if (!IsCollapsed)
{
<button class="new-chat-button" @onclick="OnNewChat" aria-label="Nouvelle discussion">
<button class="new-chat-button" @onclick="OnNewChat" aria-label="Nouvelle activité">
<span class="icon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-dots" viewBox="0 0 16 16">
<path d="M5 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2" />
<path d="m2.165 15.803.02-.004c1.83-.363 2.948-.842 3.468-1.105A9 9 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.4 10.4 0 0 1-.524 2.318l-.003.011a11 11 0 0 1-.244.637c-.079.186.074.394.273.362a22 22 0 0 0 .693-.125m.8-3.108a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6-3.004 6-7 6a8 8 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a11 11 0 0 0 .398-2" />
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
<path d="M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5M3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.6 26.6 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.93.93 0 0 1-.765.935c-.845.147-2.34.346-4.235.346s-3.39-.2-4.235-.346A.93.93 0 0 1 3 9.219zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a25 25 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25 25 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135" />
<path d="M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2zM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5" />
</svg>

</span>
<span>Nouvelle discussion</span>
<span>Nouvelle activité</span>
</button>


<h3 class="section-title"> Conversations</h3>

<div class="conversations-section">


@if (IsLoadingChat)
{
<div class="loading">Chargement...</div>
}
else if (ChatConversations.Any())
{
<div class="conversations-list">
@foreach (var conversation in ChatConversations)
{
<div class="conversation-item @(CurrentConversationId == conversation.Id ? "active" : "")"
@onclick="() => OnSelectConversation(conversation.Id, 1)">
<span class="conversation-title">
@if (!string.IsNullOrEmpty(conversation.Title))
{
@conversation.Title
}
else
{
@($"Conversation du {conversation.Date:dd/MM/yyyy}")
}
</span>
</div>
}
</div>
}
else
{
<div class="empty-state">Aucune conversation</div>
}
</div>
<button class="section-title-button" @onclick="ToggleChatSection">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-dots" viewBox="0 0 16 16">
<path d="M5 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2" />
<path d="m2.165 15.803.02-.004c1.83-.363 2.948-.842 3.468-1.105A9 9 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.4 10.4 0 0 1-.524 2.318l-.003.011a11 11 0 0 1-.244.637c-.079.186.074.394.273.362a22 22 0 0 0 .693-.125m.8-3.108a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6-3.004 6-7 6a8 8 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a11 11 0 0 0 .398-2" />
</svg>
<span>Conversations</span>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor"
class="chevron @(IsChatSectionOpen ? "open" : "")" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" />
</svg>
</button>

@if (IsChatSectionOpen)
{
<div class="conversations-section">
@if (IsLoadingChat)
{
<div class="loading">Chargement...</div>
}
else if (ChatConversations.Any())
{
<div class="conversations-list">
@foreach (var conversation in ChatConversations)
{
<div class="conversation-item @(CurrentConversationId == conversation.Id ? "active" : "")"
@onclick="() => OnSelectConversation(conversation.Id, 1)">
<span class="conversation-title">
@if (!string.IsNullOrEmpty(conversation.Title))
{
@conversation.Title
}
else
{
@($"Conversation du {conversation.Date:dd/MM/yyyy}")
}
</span>
</div>
}
</div>
}
else
{
<div class="empty-state">Aucune conversation</div>
}
</div>
}
}
else
{
@@ -93,45 +103,51 @@
<div class="sidebar-section">
@if (!IsCollapsed)
{
<h3 class="section-title">
<button class="section-title-button" @onclick="ToggleRagSection">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-folder" viewBox="0 0 16 16">
<path d="M.54 3.87.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a2 2 0 0 1 .342-1.31zM2.19 4a1 1 0 0 0-.996 1.09l.637 7a1 1 0 0 0 .995.91h10.348a1 1 0 0 0 .995-.91l.637-7A1 1 0 0 0 13.81 4zm4.69-1.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981l.006.139q.323-.119.684-.12h5.396z" />
</svg>
RAG
</h3>

<div class="conversations-section">

@if (IsLoadingRag)
{
<div class="loading">Chargement...</div>
}
else if (RagConversations.Any())
{
<div class="conversations-list">
@foreach (var conversation in RagConversations)
{
<div class="conversation-item @(CurrentConversationId == conversation.Id ? "active" : "")"
@onclick="() => OnSelectConversation(conversation.Id, 2)">
<span class="conversation-title">
@if (!string.IsNullOrEmpty(conversation.Title))
{
@conversation.Title
}
else
{
@($"RAG du {conversation.Date:dd/MM/yyyy}")
}
</span>
</div>
}
</div>
}
else
{
<div class="empty-state">Aucune conversation RAG</div>
}
</div>
<span>RAG</span>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor"
class="chevron @(IsRagSectionOpen ? "open" : "")" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" />
</svg>
</button>

@if (IsRagSectionOpen)
{
<div class="conversations-section">
@if (IsLoadingRag)
{
<div class="loading">Chargement...</div>
}
else if (RagConversations.Any())
{
<div class="conversations-list">
@foreach (var conversation in RagConversations)
{
<div class="conversation-item @(CurrentConversationId == conversation.Id ? "active" : "")"
@onclick="() => OnSelectConversation(conversation.Id, 2)">
<span class="conversation-title">
@if (!string.IsNullOrEmpty(conversation.Title))
{
@conversation.Title
}
else
{
@($"RAG du {conversation.Date:dd/MM/yyyy}")
}
</span>
</div>
}
</div>
}
else
{
<div class="empty-state">Aucune conversation RAG</div>
}
</div>
}
}
else
{
@@ -146,6 +162,72 @@
}
</div>



<div class="sidebar-section">
@if (!IsCollapsed)
{
<button class="section-title-button" @onclick="ToggleAuditSection">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-folder" viewBox="0 0 16 16">
<path d="M.54 3.87.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a2 2 0 0 1 .342-1.31zM2.19 4a1 1 0 0 0-.996 1.09l.637 7a1 1 0 0 0 .995.91h10.348a1 1 0 0 0 .995-.91l.637-7A1 1 0 0 0 13.81 4zm4.69-1.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981l.006.139q.323-.119.684-.12h5.396z" />
</svg>
<span>AUDIT</span>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor"
class="chevron @(IsAuditSectionOpen ? "open" : "")" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" />
</svg>
</button>

@if (IsAuditSectionOpen)
{
<div class="conversations-section">
@if (IsLoadingAudit)
{
<div class="loading">Chargement...</div>
}
else if (AuditConversations.Any())
{
<div class="conversations-list">
@foreach (var conversation in AuditConversations)
{
<div class="conversation-item @(CurrentConversationId == conversation.Id ? "active" : "")"
@onclick="() => OnSelectConversation(conversation.Id, 3)">
<span class="conversation-title">
@if (!string.IsNullOrEmpty(conversation.Title))
{
@conversation.Title
}
else
{
@($"AUDIT du {conversation.Date:dd/MM/yyyy}")
}
</span>
</div>
}
</div>
}
else
{
<div class="empty-state">Aucune conversation AUDIT</div>
}
</div>
}
}
else
{
<button class="sidebar-icon-button" aria-label="AUDIT">
<span class="icon">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-folder" viewBox="0 0 16 16">
<path d="M.54 3.87.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a2 2 0 0 1 .342-1.31zM2.19 4a1 1 0 0 0-.996 1.09l.637 7a1 1 0 0 0 .995.91h10.348a1 1 0 0 0 .995-.91l.637-7A1 1 0 0 0 13.81 4zm4.69-1.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981l.006.139q.323-.119.684-.12h5.396z" />
</svg>

</span>
</button>
}
</div>



</div>

<script>
@@ -158,11 +240,17 @@
private bool IsCollapsed = false;
private string CurrentConversationId = "";

private bool IsChatSectionOpen = true;
private bool IsRagSectionOpen = true;
private bool IsAuditSectionOpen = true;

private List<ConversationDto> ChatConversations { get; set; } = new();
private List<ConversationDto> RagConversations { get; set; } = new();
private List<ConversationDto> AuditConversations { get; set; } = new();

private bool IsLoadingChat = false;
private bool IsLoadingRag = false;
private bool IsLoadingAudit = false;

protected override async Task OnInitializedAsync()
{
@@ -179,6 +267,8 @@

await LoadChatConversations();
await LoadRagConversations();
await LoadAuditConversations();

}

protected override async Task OnAfterRenderAsync(bool firstRender)
@@ -207,6 +297,21 @@
IsCollapsed = !IsCollapsed;
}

private void ToggleChatSection()
{
IsChatSectionOpen = !IsChatSectionOpen;
}

private void ToggleRagSection()
{
IsRagSectionOpen = !IsRagSectionOpen;
}

private void ToggleAuditSection()
{
IsAuditSectionOpen = !IsAuditSectionOpen;
}

private void UpdateCurrentConversationFromUrl()
{
var uri = new Uri(Navigation.Uri);
@@ -309,6 +414,44 @@
}
}

private async Task LoadAuditConversations()
{

if (string.IsNullOrEmpty(AuthService.ID))
{
return;
}

IsLoadingAudit = true;
StateHasChanged();

try
{
var url = $"/api/ChatRoom/conversations/{AuthService.ID}/3";

var allConversations = await Http.GetFromJsonAsync<List<ConversationDto>>(url) ?? new();


// Filtrer uniquement celles avec TypeConv = "AUDIT"
AuditConversations = allConversations
.Where(c => c.TypeConv == "AUDIT")
.OrderByDescending(c => c.Messages.Any()
? c.Messages.Max(m => m.CreatedAt)
: c.Date)
.ToList();

}
catch (Exception ex)
{
AuditConversations = new();
}
finally
{
IsLoadingAudit = false;
StateHasChanged();
}
}

private void OnNewChat()
{
Navigation.NavigateTo("chatroom_base/0");

+ 5
- 5
WebUI/ReAct_PME.WebUI/Pages/ChatRoom/ChatRoom_base.razor Ver arquivo

@@ -123,9 +123,9 @@
</svg>
</div>
<div class="agent-content">
<h3 class="agent-name">Par défaut</h3>
<h3 class="agent-name">conversation</h3>
<p class="agent-description">
Discutez avec un agent IA ayant une base de données importante dans votre domaine
Discutez avec un agent IA ayant une bonne connaissance de votre secteur d'activité
</p>
</div>
<div class="agent-check">
@@ -150,8 +150,8 @@
<div class="agent-content">
<h3 class="agent-name">Agent RAG</h3>
<p class="agent-description">
Un agent IA entraîné dans la création de bilan comptable sur la base de vos comptes-rendus
</p>
un agent possédant une excellente connaissance de votre base documentaire
</p>
</div>
<div class="agent-check">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
@@ -202,7 +202,7 @@
<div class="agent-content">
<h3 class="agent-name">L'agent mail spécialisé</h3>
<p class="agent-description">
Un agent IA spécialisé dans la rédaction de mail professionnel avec une approche humaine et experte
un agent IA spécialisé dans le traitement de vos mails avec une approche humaine et experte
</p>
</div>
<div class="agent-check">

+ 1
- 1
WebUI/ReAct_PME.WebUI/Pages/ChatRoom/ChatRoom_base.razor.cs Ver arquivo

@@ -226,7 +226,7 @@ namespace ReAct_PME.WebUI.Pages.ChatRoom
{
1 => "LLM",
2 => "RAG",
3 => "CODE",
3 => "AUDIT",
4 => "IMAGE",
_ => "LLM"
};

+ 26
- 0
WebUI/ReAct_PME.WebUI/wwwroot/css/app.css Ver arquivo

@@ -3025,3 +3025,29 @@ color:white;
}


.section-title-button {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 8px;
background: transparent;
border: none;
cursor: pointer;
transition: background-color 0.2s;
color:white;
}

.section-title-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}

.chevron {
margin-left: auto;
transition: transform 0.2s;
transform: rotate(270deg);
}

.chevron.open {
transform: rotate(360deg);
}

Carregando…
Cancelar
Salvar