feat: Connect chat interface to conversation layer router
Integrates the chat UI with the conversation layer router.
Key changes:
- Added new environment variables (`CONVERSATION_LAYER_ROUTER_URL` for the API and `VITE_CONVERSATION_LAYER_ROUTER_URL` for the UI) to specify the router's URL. These have been configured in `docker-compose.yml`, `api/.env.example`, and `ui/runtime-env.sh`.
- Modified `ui/src/stores/useChat.js`:
- Introduced a `sendMessage` action that constructs a message object (as per the specified format with `id`, `from`, `to`, `ts`, `type`, `text`, `meta`) and sends it to the conversation router.
- Implemented optimistic local display of your message.
- Handles the `Conversation` object returned by the router, iterating through its `messages` array and adding them to the chat display.
- Determines message ownership ('user' for UI messages, 'bot' for Nucleo messages) for appropriate rendering.
- Includes basic error handling for API requests, logging errors and showing system messages in the chat.
- Updated `ui/src/components/chat/CanvasChat.vue`:
- Modified the message sending mechanism to use the new `chat.sendMessage()` action.
- Adjusted message rendering to correctly differentiate between messages from 'user' and 'bot' based on the `owner` field from the chat store.
This allows the UI to send messages to the conversation router and display the resulting conversation, focusing on rendering messages from both the UI ('planilla-UI') and the bot ('Nucleo').
This commit is contained in:
@@ -5,4 +5,5 @@
|
|||||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||||
|
|
||||||
DATABASE_URL=postgresql://planilla:planilla@localhost:5434/planilla_db?schema=public
|
DATABASE_URL=postgresql://planilla:planilla@localhost:5434/planilla_db?schema=public
|
||||||
|
CONVERSATION_LAYER_ROUTER_URL='http://your-router-url:port'
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: "postgresql://planilla:secret@db:5432/planilla_db?schema=public"
|
DATABASE_URL: "postgresql://planilla:secret@db:5432/planilla_db?schema=public"
|
||||||
|
CONVERSATION_LAYER_ROUTER_URL: 'http://your-router-url:port'
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
ports:
|
ports:
|
||||||
@@ -34,6 +35,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
VITE_API_EVENTS_URL: https://planilla.interno.com/events
|
VITE_API_EVENTS_URL: https://planilla.interno.com/events
|
||||||
VITE_API_DB_URL: https://planilla.interno.com
|
VITE_API_DB_URL: https://planilla.interno.com
|
||||||
|
VITE_CONVERSATION_LAYER_ROUTER_URL: 'http://your-router-url:port'
|
||||||
ports:
|
ports:
|
||||||
- "3008:80"
|
- "3008:80"
|
||||||
networks: [planilla, principal]
|
networks: [planilla, principal]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
echo "window.RUNTIME_CONFIG = {" > /usr/share/nginx/html/config.js
|
echo "window.RUNTIME_CONFIG = {" > /usr/share/nginx/html/config.js
|
||||||
echo " VITE_API_EVENTS_URL: '${VITE_API_EVENTS_URL}'," >> /usr/share/nginx/html/config.js
|
echo " VITE_API_EVENTS_URL: '${VITE_API_EVENTS_URL}'," >> /usr/share/nginx/html/config.js
|
||||||
echo " VITE_API_DB_URL: '${VITE_API_DB_URL}'" >> /usr/share/nginx/html/config.js
|
echo " VITE_API_DB_URL: '${VITE_API_DB_URL}'," >> /usr/share/nginx/html/config.js
|
||||||
|
echo " VITE_CONVERSATION_LAYER_ROUTER_URL: '${VITE_CONVERSATION_LAYER_ROUTER_URL}'," >> /usr/share/nginx/html/config.js
|
||||||
echo "};" >> /usr/share/nginx/html/config.js
|
echo "};" >> /usr/share/nginx/html/config.js
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function send () {
|
|||||||
if (!t) return
|
if (!t) return
|
||||||
|
|
||||||
if (t.startsWith('/')) chat.run(t.slice(1))
|
if (t.startsWith('/')) chat.run(t.slice(1))
|
||||||
else chat.add({ type: 'text', owner: 'yo', text: t })
|
else chat.sendMessage(t)
|
||||||
|
|
||||||
msg.value = ''
|
msg.value = ''
|
||||||
scrollBottom()
|
scrollBottom()
|
||||||
@@ -58,12 +58,12 @@ watch(() => chat.items.length, scrollBottom)
|
|||||||
<div ref="list" class="flex-1 min-h-0 overflow-auto p-6 space-y-4 custom-scroll">
|
<div ref="list" class="flex-1 min-h-0 overflow-auto p-6 space-y-4 custom-scroll">
|
||||||
<template v-for="(m,i) in chat.items" :key="i">
|
<template v-for="(m,i) in chat.items" :key="i">
|
||||||
<!-- mensaje de texto -->
|
<!-- mensaje de texto -->
|
||||||
<div :class="m.owner==='yo' ? 'flex justify-end' : 'flex justify-start'" v-if="m.type==='text'">
|
<div :class="m.owner==='user' ? 'flex justify-end' : 'flex justify-start'" v-if="m.type==='text'">
|
||||||
<div
|
<div
|
||||||
class="max-w-lg rounded-lg px-4 py-2 shadow break-words"
|
class="max-w-lg rounded-lg px-4 py-2 shadow break-words"
|
||||||
:class="m.owner === 'yo' ? '' : ''"
|
:class="m.owner === 'user' ? '' : ''"
|
||||||
:style="{
|
:style="{
|
||||||
backgroundColor: m.owner === 'yo' ? 'var(--chat-own-message-color)' : 'var(--chat-agent-message-color)',
|
backgroundColor: m.owner === 'user' ? 'var(--chat-own-message-color)' : 'var(--chat-agent-message-color)',
|
||||||
color: 'var(--chat-font-color)',
|
color: 'var(--chat-font-color)',
|
||||||
fontFamily: 'var(--chat-font-family)',
|
fontFamily: 'var(--chat-font-family)',
|
||||||
fontSize: 'var(--chat-font-size)'
|
fontSize: 'var(--chat-font-size)'
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,5 +37,87 @@ export const useChat = defineStore('chat', {
|
|||||||
this.add({ type: 'text', owner: 'bot', text: `❓ No reconozco /${cmd}` })
|
this.add({ type: 'text', owner: 'bot', text: `❓ No reconozco /${cmd}` })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async sendMessage (text) {
|
||||||
|
const routerUrl = window.RUNTIME_CONFIG?.VITE_CONVERSATION_LAYER_ROUTER_URL || 'http://localhost:8080/fallback-router'; // Fallback or error
|
||||||
|
if (!window.RUNTIME_CONFIG?.VITE_CONVERSATION_LAYER_ROUTER_URL) {
|
||||||
|
console.error('VITE_CONVERSATION_LAYER_ROUTER_URL is not defined in window.RUNTIME_CONFIG. Using fallback or please check your configuration.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const messagePayload = {
|
||||||
|
id: `planilla-UI-${Date.now()}`, // Simple unique ID for now
|
||||||
|
from: 'planilla-UI',
|
||||||
|
to: 'Nucleo',
|
||||||
|
ts: Math.floor(Date.now() / 1000), // Timestamp in seconds
|
||||||
|
type: 'chat',
|
||||||
|
text: text, // User's message text
|
||||||
|
mediaUrl: null, // Assuming no media for now
|
||||||
|
mentions: null, // Assuming no mentions for now
|
||||||
|
meta: {
|
||||||
|
ack: 1, // Or 0 if acknowledgement is handled by the router
|
||||||
|
hasReaction: false,
|
||||||
|
isQuoted: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Optimistically add message to chat
|
||||||
|
this.add({
|
||||||
|
id: messagePayload.id, // Use the same ID
|
||||||
|
type: 'chat',
|
||||||
|
owner: 'user', // Or a more specific identifier if available
|
||||||
|
text: text,
|
||||||
|
ts: messagePayload.ts
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post(routerUrl, messagePayload);
|
||||||
|
console.log('Message sent, raw response:', response.data); // Log raw response
|
||||||
|
|
||||||
|
const conversation = response.data;
|
||||||
|
|
||||||
|
if (conversation && Array.isArray(conversation.messages)) {
|
||||||
|
conversation.messages.forEach(msg => {
|
||||||
|
let owner = 'bot'; // Default to bot
|
||||||
|
if (msg.from === 'planilla-UI') {
|
||||||
|
owner = 'user';
|
||||||
|
// NOTE: This might add a duplicate if the optimistic message's ID
|
||||||
|
// is different from the ID assigned by the router for the echoed message.
|
||||||
|
// The current instructions are to render all messages from the router.
|
||||||
|
// Refinement for deduplication can be done later if needed.
|
||||||
|
} else if (msg.from === 'Nucleo') {
|
||||||
|
owner = 'bot';
|
||||||
|
}
|
||||||
|
// else, it could be from another participant
|
||||||
|
|
||||||
|
this.add({
|
||||||
|
id: msg.id,
|
||||||
|
type: msg.type || 'chat', // Default to 'chat' if type is not present
|
||||||
|
owner: owner,
|
||||||
|
text: msg.text,
|
||||||
|
ts: msg.ts,
|
||||||
|
// mediaUrl: msg.mediaUrl, // Uncomment if mediaUrl is expected
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('Invalid conversation response format:', conversation);
|
||||||
|
this.add({
|
||||||
|
id: `error-${Date.now()}`,
|
||||||
|
type: 'error',
|
||||||
|
owner: 'system',
|
||||||
|
text: 'Error processing server response. Invalid format.',
|
||||||
|
ts: Math.floor(Date.now() / 1000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error sending message:', error);
|
||||||
|
this.add({
|
||||||
|
id: `error-send-${Date.now()}`,
|
||||||
|
type: 'error',
|
||||||
|
owner: 'system',
|
||||||
|
text: `Error sending message: ${error.message}`,
|
||||||
|
ts: Math.floor(Date.now() / 1000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user