Erwin Jacimino 8 месяцев назад
Родитель
Сommit
31983fed20
5 измененных файлов с 75 добавлено и 22 удалено
  1. 7 2
      public/main/index.html
  2. 17 2
      public/main/js/app.js
  3. 26 2
      public/main/js/service/chat.js
  4. 9 1
      routes/chat.py
  5. 16 15
      services/openai_service/openai_service.py

+ 7 - 2
public/main/index.html

@@ -49,7 +49,7 @@
   <!-- ---------- MAIN  ---------- -->
   <!-- ---------- MAIN  ---------- -->
   <main class="relative flex-1 flex flex-col min-h-0 overflow-x-hidden">  
   <main class="relative flex-1 flex flex-col min-h-0 overflow-x-hidden">  
     <!-- ===== MENÚ tab ===== -->
     <!-- ===== MENÚ tab ===== -->
-    <section id="menuTab" data-index="0" class="min-h-0 overflow-y-auto h-full" data-tab>
+    <section id="menuTab" data-index="0" class="min-h-0 hidden overflow-y-auto h-full" data-tab>
         <div class="pt-4 pb-3">
         <div class="pt-4 pb-3">
             <!-- Barra de progreso para cerveza gratis -->
             <!-- Barra de progreso para cerveza gratis -->
             <div class="mx-4 mb-6 p-4 bg-gradient-to-r from-amber-50 to-orange-50 rounded-xl border border-amber-200">
             <div class="mx-4 mb-6 p-4 bg-gradient-to-r from-amber-50 to-orange-50 rounded-xl border border-amber-200">
@@ -113,9 +113,14 @@
     </section>
     </section>
 
 
     <!-- ===== CHAT ===== -->
     <!-- ===== CHAT ===== -->
-    <section id="chatTab" data-index="2" data-tab class="flex hidden flex-col h-full flex-1 min-h-0">
+    <section id="chatTab" data-index="2" data-tab class="flex flex-col h-full flex-1 min-h-0">
         <!-- Contenedor de mensajes que puede crecer y hacer scroll -->
         <!-- Contenedor de mensajes que puede crecer y hacer scroll -->
         <div id="chatContainer" class="flex flex-col h-full flex-1 bg-white border border-gray-200 rounded-xl shadow-sm m-4 overflow-hidden">
         <div id="chatContainer" class="flex flex-col h-full flex-1 bg-white border border-gray-200 rounded-xl shadow-sm m-4 overflow-hidden">
+          <header>
+            <div class="flex items-center justify-between px-4 py-3 border-b border-gray-200 bg-gray-50">
+              <div id="onlineUsers" class="flex items-center gap-3"><span class="rounded-full bg-lime-500 w-2 h-2 inline-block shadow-md shadow-lime-300"></span><h4>4 Usuarios en linea</h4></div>
+            </div>
+          </header>
           <!-- Mensajes -->
           <!-- Mensajes -->
           <div id="chatMessages" class="flex-1 overflow-y-auto px-4 py-3 space-y-1 bg-gray-50 font-mono text-sm">
           <div id="chatMessages" class="flex-1 overflow-y-auto px-4 py-3 space-y-1 bg-gray-50 font-mono text-sm">
             <!-- Mensajes de ejemplo estilo IRC -->
             <!-- Mensajes de ejemplo estilo IRC -->

+ 17 - 2
public/main/js/app.js

@@ -80,6 +80,7 @@ const chatMessagesElement = document.getElementById("chatMessages");
 const chatInputElement = document.getElementById("chatInput");
 const chatInputElement = document.getElementById("chatInput");
 const chatForm = document.getElementById("chatForm");
 const chatForm = document.getElementById("chatForm");
 const userList = document.getElementById("userList")
 const userList = document.getElementById("userList")
+const onlineUsersElement = document.querySelector("#onlineUsers h4");
 // --- Reward Elements ---
 // --- Reward Elements ---
 const rewardBtn = document.getElementById('rewardBtn');
 const rewardBtn = document.getElementById('rewardBtn');
 const rewardModal = document.getElementById('rewardModal');
 const rewardModal = document.getElementById('rewardModal');
@@ -189,6 +190,9 @@ function initializeWebSocket() {
                 username: chatUserName
                 username: chatUserName
             }));
             }));
         }
         }
+        const userNumber = getUserList().then(users => {
+            onlineUsersElement.innerText = `${users.length} Usuario${users.length !== 1 ? 's' : ''} en línea`;
+        });
         chatWebsocket.onmessage = (event) => {
         chatWebsocket.onmessage = (event) => {
             const data = JSON.parse(event.data);
             const data = JSON.parse(event.data);
             if (data.type === "message") {
             if (data.type === "message") {
@@ -196,9 +200,15 @@ function initializeWebSocket() {
             }
             }
             else if (data.type === "join") {
             else if (data.type === "join") {
                 newUserInChat(data.username);
                 newUserInChat(data.username);
+                const userNumber = getUserList().then(users => {
+                    onlineUsersElement.innerText = `${users.length} Usuario${users.length !== 1 ? 's' : ''} en línea`;
+                });
             }
             }
             else if (data.type === "leave") {
             else if (data.type === "leave") {
                 userLeftChat(data.username);
                 userLeftChat(data.username);
+                const userNumber = getUserList().then(users => {
+                    onlineUsersElement.innerText = `${users.length} Usuario${users.length !== 1 ? 's' : ''} en línea`;
+                });
             }
             }
             else if (data.type === "mentioned") {
             else if (data.type === "mentioned") {
                 if (data.username && data.username !== chatUserName) return; // not for me
                 if (data.username && data.username !== chatUserName) return; // not for me
@@ -277,7 +287,12 @@ function initializeChat() {
                     const userItem = document.createElement("button");
                     const userItem = document.createElement("button");
                     userItem.type = "button";
                     userItem.type = "button";
                     userItem.onclick = () => {
                     userItem.onclick = () => {
-                        chatInputElement.value = chatInputElement.value.replace(lastWord, `@${user}`);
+                        // Replace the last occurrence of lastWord with @user
+                        const inputValue = chatInputElement.value;
+                        const lastWordIndex = inputValue.lastIndexOf(lastWord);
+                        if (lastWordIndex !== -1) {
+                            chatInputElement.value = inputValue.slice(0, lastWordIndex) + `@${user}` + inputValue.slice(lastWordIndex + lastWord.length);
+                        }
                         userList.classList.add("hidden");
                         userList.classList.add("hidden");
                         chatInputElement.focus();
                         chatInputElement.focus();
                     };
                     };
@@ -1009,7 +1024,7 @@ document.addEventListener("DOMContentLoaded", async () => {
     
     
     createGlobalLoader();
     createGlobalLoader();
     // Uncomment these lines when ready to initialize the full app:
     // Uncomment these lines when ready to initialize the full app:
-    initializeLoginModal();
+    // initializeLoginModal();
     // hideGUI();
     // hideGUI();
     // initializeApp();
     // initializeApp();
 });
 });

+ 26 - 2
public/main/js/service/chat.js

@@ -3,7 +3,11 @@ async function getUserList(q, token) {
   if (!token) {
   if (!token) {
     return "not_init";
     return "not_init";
   }
   }
-  const response = await fetch(`/api/chat/users?q=${encodeURIComponent(q)}`, {
+
+
+
+
+  const response = await fetch(`/api/chat/users` + (q ? `?q=${encodeURIComponent(q)}` : ""), {
     method: "GET",
     method: "GET",
     headers: {
     headers: {
       "Authorization": `Bearer ${token}`
       "Authorization": `Bearer ${token}`
@@ -17,4 +21,24 @@ async function getUserList(q, token) {
   return data.users || [];
   return data.users || [];
 }
 }
 
 
-export { getUserList };
+async function getOnlineUserCount(token) {
+  if (!token) {
+    return "not_init";
+  }
+
+  const response = await fetch(`/api/chat/onlines`, {
+    method: "GET",
+    headers: {
+      "Authorization": `Bearer ${token}`
+    }
+  });
+
+  if (!response.ok) {
+    const errorData = await response.json().catch(() => ({ message: "Respuesta no válida del servidor." }));
+    throw new Error(errorData.message || `Error del servidor: ${response.status}`);
+  }
+  const data = await response.json();
+  return data.count || 0;
+}
+
+export { getUserList, getOnlineUserCount };

+ 9 - 1
routes/chat.py

@@ -1,6 +1,7 @@
 import asyncio
 import asyncio
 import json
 import json
 import logging
 import logging
+from typing import Optional
 from fastapi import Query, Request, HTTPException, Depends, APIRouter, WebSocket, WebSocketDisconnect
 from fastapi import Query, Request, HTTPException, Depends, APIRouter, WebSocket, WebSocketDisconnect
 from fastapi.responses import JSONResponse
 from fastapi.responses import JSONResponse
 from fastapi.security import HTTPAuthorizationCredentials
 from fastapi.security import HTTPAuthorizationCredentials
@@ -140,11 +141,18 @@ async def chat_irc_endpoint(websocket: WebSocket):
 
 
 
 
 @chat_router.get("/users")
 @chat_router.get("/users")
-async def get_connected_users(q: str = Query(...), _: User = Depends(get_current_user)):
+async def get_connected_users(q: str = Optional[Query(...)], _: User = Depends(get_current_user)):
     """Get a list of connected users (solo local al worker)"""
     """Get a list of connected users (solo local al worker)"""
     # return {"users": [user.username for user in connected_users if q.lower() in user.username.lower()]}
     # return {"users": [user.username for user in connected_users if q.lower() in user.username.lower()]}
     all_users = redis_client.smembers("connected_users")
     all_users = redis_client.smembers("connected_users")
     all_users = [json.loads(user)["username"] for user in all_users]
     all_users = [json.loads(user)["username"] for user in all_users]
+    if q is None or q.strip() == "":
+        return {"users": all_users}
     filtered_users = [user for user in all_users if q.lower() in user.lower()]
     filtered_users = [user for user in all_users if q.lower() in user.lower()]
     return {"users": filtered_users}
     return {"users": filtered_users}
 
 
+@chat_router.get("/onlines")
+async def get_online_user_count(_: User = Depends(get_current_user)):
+    """Get the count of online users (solo local al worker)"""
+    all_users = redis_client.smembers("connected_users")
+    return {"count": len(all_users)}

+ 16 - 15
services/openai_service/openai_service.py

@@ -28,21 +28,22 @@ async def generate_completion(messages_array: List[dict], user: User) -> str:
     data_string = "\n".join(data_for_prompt)
     data_string = "\n".join(data_for_prompt)
 
 
     preprompt = f"""
     preprompt = f"""
-Eres un asistente de el bar klein, tu nombre es camilo klein, usas emojis para responder.
-y ser carismatico con los cliente.
-tus responsabilidades son:
-- Responder preguntas sobre el menu de el bar klein
-- bromear con los usuarios sobre distintos temas pero siempre redirigir la conversacion al bar klein
-- Proporcionar información sobre el menú de el bar klein
-- Proporcionar recomendaciones sobre el menú de el bar klein
-- Proporcionar información sobre la comida de el bar klein
-- No puedes tomar pedidos de clientes, solo informar
-- puedes recibir feedback de los clientes, y usar la herramienta feedback para enviar el feedback
-- respuestas cortas estilo app de mensajeria
-- si el usuario te pregunta por tu nombre, di que eres camilo klein
-para esto usaras los siguientes datos:
-{data_string}
-    """
+Sos IAKlein, el asistente oficial del bar Klein 🍻.
+Hablas en estilo de chat corto (como en mensajería o IRC), usando emojis y mucho carisma.
+Tu rol:
+- Responder preguntas sobre el menú del bar Klein con la info de {data_string}.
+- Hacer bromas y charlar, pero siempre llevás la conversación de vuelta al bar Klein.
+- Dar recomendaciones de comidas y tragos.
+- Aceptar feedback y mandarlo con la herramienta 'feedback'.
+Reglas:
+- No tomás pedidos, solo informás.
+- Si te preguntan tu nombre, siempre respondés "Soy IAKlein".
+- Aunque uses el chat como contexto, siempre priorizás lo que diga @IAKlein.
+- No resolvés tareas, cálculos, ni programación: sos un amigo simpático del bar, no un esclavo LLM 🕺.
+Estilo:
+- Todo divertido, breve, con buena onda 😉.
+"""
+
 
 
     processed_messages: List[dict] = [{"role": "system", "content": preprompt}]
     processed_messages: List[dict] = [{"role": "system", "content": preprompt}]
     processed_messages.append(
     processed_messages.append(