refactor(chatbot): change appearance and function of chatbot window, send context on chat message instead of with each page change
This commit is contained in:
parent
e44e2c1e20
commit
7cf23a6a55
|
|
@ -3,14 +3,8 @@
|
||||||
setup
|
setup
|
||||||
>
|
>
|
||||||
import { useUiStore } from 'src/stores/ui-store';
|
import { useUiStore } from 'src/stores/ui-store';
|
||||||
import { useAuthStore } from 'src/stores/auth-store';
|
|
||||||
import { useChatbotStore } from 'src/stores/chatbot-store';
|
|
||||||
|
|
||||||
// import HeaderBarNotification from './main-layout-header-bar-notification.vue';
|
|
||||||
|
|
||||||
const uiStore = useUiStore();
|
const uiStore = useUiStore();
|
||||||
const chatbot_store = useChatbotStore();
|
|
||||||
const auth_store = useAuthStore();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -37,19 +31,6 @@
|
||||||
/>
|
/>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
|
|
||||||
<q-item class="q-pa-none">
|
|
||||||
<!-- <HeaderBarNotification /> -->
|
|
||||||
<q-btn
|
|
||||||
v-if="auth_store.user?.user_module_access.includes('chatbot')"
|
|
||||||
flat
|
|
||||||
color="transparant"
|
|
||||||
icon="las la-robot"
|
|
||||||
size="lg"
|
|
||||||
@click="chatbot_store.is_showing_chatbot = !chatbot_store.is_showing_chatbot"
|
|
||||||
style="--q-icon-size: 28px; min-width: auto;"
|
|
||||||
/>
|
|
||||||
</q-item>
|
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,13 @@
|
||||||
const chatbot_store = useChatbotStore();
|
const chatbot_store = useChatbotStore();
|
||||||
|
|
||||||
const text = ref('');
|
const text = ref('');
|
||||||
|
const is_showing_right_drawer = ref(true);
|
||||||
|
const drawer_width = ref(85);
|
||||||
|
|
||||||
const handleSend = async () => {
|
const handleSend = async () => {
|
||||||
const message = text.value.trim();
|
const message = text.value.trim();
|
||||||
text.value = '';
|
text.value = '';
|
||||||
|
console.log('message: ', message, ', length: ', message.length);
|
||||||
await chatbot_api.sendMessage(message);
|
await chatbot_api.sendMessage(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -26,53 +29,79 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-drawer
|
<q-drawer
|
||||||
v-model="chatbot_store.is_showing_chatbot"
|
v-model="is_showing_right_drawer"
|
||||||
overlay
|
overlay
|
||||||
elevated
|
persistent
|
||||||
|
:width="drawer_width"
|
||||||
side="right"
|
side="right"
|
||||||
class="column justify-end no-wrap"
|
class="column justify-end no-wrap relative-position no-scroll"
|
||||||
>
|
>
|
||||||
<div class="col q-px-md relative-position">
|
<transition
|
||||||
<DialogueContent class="absolute-full" />
|
enter-active-class="animated fadeInRight"
|
||||||
</div>
|
leave-active-class="animated fadeOutRight"
|
||||||
|
mode="out-in"
|
||||||
<q-form
|
@after-leave="chatbot_store.is_showing_chatbot ? drawer_width = 500 : drawer_width = 85"
|
||||||
submit="handleSend"
|
|
||||||
class="col-auto row"
|
|
||||||
>
|
>
|
||||||
<q-input
|
<div
|
||||||
v-model="text"
|
v-if="chatbot_store.is_showing_chatbot"
|
||||||
borderless
|
class="col column"
|
||||||
:label="$t('chatbot.chat_placeholder')"
|
style="background: rgba(0, 0, 0, 0.7); overflow: hidden;"
|
||||||
:autogrow="false"
|
>
|
||||||
dark
|
<q-btn
|
||||||
label-color="white"
|
dense
|
||||||
class="col q-px-md"
|
icon="las la-chevron-right"
|
||||||
style="background: rgba(0, 0, 0, 0.3);"
|
text-color="white"
|
||||||
@keyup.enter="handleSend"
|
color="accent"
|
||||||
/>
|
align="left"
|
||||||
|
size="2em"
|
||||||
|
class="q-mb-sm"
|
||||||
|
@click="chatbot_store.is_showing_chatbot = false"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- <q-input
|
<div class="col q-px-md relative-position">
|
||||||
v-model="custId"
|
<DialogueContent class="absolute-full" />
|
||||||
:label="'Customer Id'"
|
</div>
|
||||||
:autogrow="false"
|
|
||||||
class="col"
|
|
||||||
style="margin-left: 8px;"
|
|
||||||
@keyup.enter="handleCustomerId"
|
|
||||||
/> -->
|
|
||||||
</q-form>
|
|
||||||
|
|
||||||
<!-- <div
|
<q-form
|
||||||
class="drag-handle"
|
submit="handleSend"
|
||||||
@mousedown.prevent="startDrag"
|
class="col-auto row"
|
||||||
></div> -->
|
>
|
||||||
|
<q-input
|
||||||
|
v-model="text"
|
||||||
|
borderless
|
||||||
|
:label="$t('chatbot.chat_placeholder')"
|
||||||
|
:autogrow="false"
|
||||||
|
dark
|
||||||
|
label-color="white"
|
||||||
|
class="col q-px-md"
|
||||||
|
style="background: rgba(0, 0, 0, 0.3);"
|
||||||
|
@keydown.enter="handleSend"
|
||||||
|
/>
|
||||||
|
</q-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="row col-auto q-pa-sm self-end"
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
round
|
||||||
|
icon="las la-robot"
|
||||||
|
color="accent"
|
||||||
|
size="2em"
|
||||||
|
class="shadow-5"
|
||||||
|
@click="chatbot_store.is_showing_chatbot = true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
:deep(.q-drawer--right) {
|
:deep(.q-drawer) {
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0);
|
||||||
width: 50vw !important;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -20,11 +20,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-scroll-area ref="scroll_area">
|
<q-scroll-area ref="scroll_area" class="no-wrap">
|
||||||
<div
|
<div
|
||||||
v-for="(msg, index) in chatbot_store.messages"
|
v-for="(msg, index) in chatbot_store.messages"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="column q-px-md no-wrap"
|
class="col-auto q-px-md no-wrap"
|
||||||
>
|
>
|
||||||
<DialoguePhrase
|
<DialoguePhrase
|
||||||
v-if="!msg.isThinking"
|
v-if="!msg.isThinking"
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@
|
||||||
|
|
||||||
const message_text = computed(() => message.text.includes('chatbot.') ? t(message.text) : message.text)
|
const message_text = computed(() => message.text.includes('chatbot.') ? t(message.text) : message.text)
|
||||||
|
|
||||||
const is_error = computed(() => message.text.includes('NO_REPLY_RECEIVED') || message.text.includes('NO_REPLY_RECEIVED'));
|
const is_error = computed(() => message.text.includes('NO_REPLY_RECEIVED') || message.text.includes('SEND_MESSAGE_FAILED'));
|
||||||
|
|
||||||
// Initialize Markdown parser
|
// Initialize Markdown parser
|
||||||
// const md = new MarkdownIt({
|
// const md = new MarkdownIt({
|
||||||
// // breaks: false, // Support line breaks
|
// // breaks: false, // Support line breaks
|
||||||
|
|
@ -48,6 +49,24 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-chat-message
|
<q-chat-message
|
||||||
|
v-if="is_error"
|
||||||
|
name="SystemBot"
|
||||||
|
bg-color="negative"
|
||||||
|
text-color="white"
|
||||||
|
>
|
||||||
|
<div class="row flex-center">
|
||||||
|
<q-icon
|
||||||
|
name="las la-exclamation-triangle"
|
||||||
|
class="col-auto q-pr-xs"
|
||||||
|
size="2em"
|
||||||
|
color="white"
|
||||||
|
/>
|
||||||
|
<span>{{ message_text }}</span>
|
||||||
|
</div>
|
||||||
|
</q-chat-message>
|
||||||
|
|
||||||
|
<q-chat-message
|
||||||
|
v-else
|
||||||
:sent="message.sent"
|
:sent="message.sent"
|
||||||
:name="message.sent ? auth_store.user?.first_name : 'TargoBot'"
|
:name="message.sent ? auth_store.user?.first_name : 'TargoBot'"
|
||||||
:bg-color="message.sent ? 'accent' : 'info'"
|
:bg-color="message.sent ? 'accent' : 'info'"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { RouteNames } from "src/router/router-constants";
|
import { RouteNames } from "src/router/router-constants";
|
||||||
|
|
||||||
export interface chatbotPageContext {
|
export interface ChatbotPageContext {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
features: string[];
|
features: string[];
|
||||||
path: RouteNames | null;
|
path: RouteNames | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dashboardContext: chatbotPageContext = {
|
export const dashboardContext: ChatbotPageContext = {
|
||||||
name: "Dashboard",
|
name: "Dashboard",
|
||||||
description: "Landing page containing useful links and a carousel showcasing recent news, as well as a local weather widget in the top right corner",
|
description: "Landing page containing useful links and a carousel showcasing recent news, as well as a local weather widget in the top right corner",
|
||||||
features: [
|
features: [
|
||||||
|
|
@ -18,7 +18,7 @@ export const dashboardContext: chatbotPageContext = {
|
||||||
path: RouteNames.DASHBOARD,
|
path: RouteNames.DASHBOARD,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const leftDrawerContext: chatbotPageContext = {
|
export const leftDrawerContext: ChatbotPageContext = {
|
||||||
name: "Left Drawer",
|
name: "Left Drawer",
|
||||||
description: "A drawer that acts as a navigation bar, routes to different parts of the website. Some icons will be hidden according to user access",
|
description: "A drawer that acts as a navigation bar, routes to different parts of the website. Some icons will be hidden according to user access",
|
||||||
features: [
|
features: [
|
||||||
|
|
@ -33,7 +33,7 @@ export const leftDrawerContext: chatbotPageContext = {
|
||||||
path: null,
|
path: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const profileContext: chatbotPageContext = {
|
export const profileContext: ChatbotPageContext = {
|
||||||
name: "Profile",
|
name: "Profile",
|
||||||
description: "Display and edit user information",
|
description: "Display and edit user information",
|
||||||
features: [
|
features: [
|
||||||
|
|
@ -44,7 +44,7 @@ export const profileContext: chatbotPageContext = {
|
||||||
path: RouteNames.PROFILE,
|
path: RouteNames.PROFILE,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const employeeListContext: chatbotPageContext = {
|
export const employeeListContext: ChatbotPageContext = {
|
||||||
name: "Employee List",
|
name: "Employee List",
|
||||||
description: "View all the hired and currently active Staff",
|
description: "View all the hired and currently active Staff",
|
||||||
features: [
|
features: [
|
||||||
|
|
@ -57,7 +57,7 @@ export const employeeListContext: chatbotPageContext = {
|
||||||
path: RouteNames.EMPLOYEE_LIST,
|
path: RouteNames.EMPLOYEE_LIST,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const timesheetApprovalContext: chatbotPageContext = {
|
export const timesheetApprovalContext: ChatbotPageContext = {
|
||||||
name: "Timesheet Approval",
|
name: "Timesheet Approval",
|
||||||
description: "Page where employee hours and shifts are approved for accounting purposes. Requires timesheet_approval module access.",
|
description: "Page where employee hours and shifts are approved for accounting purposes. Requires timesheet_approval module access.",
|
||||||
features: [
|
features: [
|
||||||
|
|
@ -71,7 +71,7 @@ export const timesheetApprovalContext: chatbotPageContext = {
|
||||||
path: RouteNames.TIMESHEET_APPROVALS,
|
path: RouteNames.TIMESHEET_APPROVALS,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const timesheetContext: chatbotPageContext = {
|
export const timesheetContext: ChatbotPageContext = {
|
||||||
name: "Timesheet",
|
name: "Timesheet",
|
||||||
description:
|
description:
|
||||||
"Page where an employee can enter their hours for their day and week. Display in 2-week pay periods.",
|
"Page where an employee can enter their hours for their day and week. Display in 2-week pay periods.",
|
||||||
|
|
@ -86,7 +86,7 @@ export const timesheetContext: chatbotPageContext = {
|
||||||
path: RouteNames.TIMESHEET,
|
path: RouteNames.TIMESHEET,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const helpContext: chatbotPageContext = {
|
export const helpContext: ChatbotPageContext = {
|
||||||
name: "Help",
|
name: "Help",
|
||||||
description: "page containing common Q&A segments regarding website functionalities",
|
description: "page containing common Q&A segments regarding website functionalities",
|
||||||
features: [
|
features: [
|
||||||
|
|
@ -98,7 +98,7 @@ export const helpContext: chatbotPageContext = {
|
||||||
path: RouteNames.HELP,
|
path: RouteNames.HELP,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PageContexts: Record<RouteNames, chatbotPageContext | null> = {
|
export const PageContexts: Record<RouteNames, ChatbotPageContext | null> = {
|
||||||
"login": null,
|
"login": null,
|
||||||
"login-success": null,
|
"login-success": null,
|
||||||
"error": null,
|
"error": null,
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
import type { chatbotPageContext } from "src/modules/chatbot/models/page-context.model";
|
import type { ChatbotPageContext } from "src/modules/chatbot/models/page-context.model";
|
||||||
import type { Message } from "src/modules/chatbot/models/dialogue-message.model";
|
import type { Message } from "src/modules/chatbot/models/dialogue-message.model";
|
||||||
import { api } from "src/boot/axios";
|
import { api } from "src/boot/axios";
|
||||||
|
|
||||||
export const chatbotService = {
|
export const chatbotService = {
|
||||||
// Function to send the message to the backend
|
// Function to send the message to the backend
|
||||||
sendChatMessage: async (userInput: string): Promise<Message> => {
|
sendChatMessage: async (userInput: string, pageContext: ChatbotPageContext | undefined): Promise<Message> => {
|
||||||
const response = await api.post("/chatbot", { userInput });
|
const response = await api.post("/chatbot", { userInput, pageContext });
|
||||||
return response.data as Message;
|
return response.data as Message;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Function to send context to backend
|
// // Function to send context to backend
|
||||||
sendPageContext: async (context: chatbotPageContext): Promise<string> => {
|
// sendPageContext: async (context: chatbotPageContext): Promise<string> => {
|
||||||
const response = await api.post("/chatbot/context", context);
|
// const response = await api.post("/chatbot/context", context);
|
||||||
return response.data;
|
// return response.data;
|
||||||
},
|
// },
|
||||||
|
|
||||||
// Function to send user credentials to the backend to communicate with n8n.
|
// // Function to send user credentials to the backend to communicate with n8n.
|
||||||
sendUserCredentials: async (email: string, role: string): Promise<boolean> => {
|
// sendUserCredentials: async (email: string, role: string): Promise<boolean> => {
|
||||||
const response = await api.post("/chatbot/user", { email, role });
|
// const response = await api.post("/chatbot/user", { email, role });
|
||||||
return response.data;
|
// return response.data;
|
||||||
},
|
// },
|
||||||
|
|
||||||
retrieveCustomerDiagnostics: async (id: string): Promise<string> => {
|
// retrieveCustomerDiagnostics: async (id: string): Promise<string> => {
|
||||||
const response = await api.get(`/chat/customer/${id}`);
|
// const response = await api.get(`/chat/customer/${id}`);
|
||||||
return response.data;
|
// return response.data;
|
||||||
},
|
// },
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
Object.values(overview_column_names).map(column => column_options.value.push({ label: `timesheet_approvals.table.${column}`, value: column as OverviewColumns }))
|
Object.values(overview_column_names).map(column => column_options.value.push({ label: `timesheet_approvals.table.${column}`, value: column as OverviewColumns }))
|
||||||
column_options.value = column_options.value.filter(column => !EXCLUDED_COLUMNS.includes(column.value));
|
column_options.value = column_options.value.filter(column => !EXCLUDED_COLUMNS.includes(column.value));
|
||||||
console.log('filter column values: ', column_options.value )
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
const is_timesheets_approved = computed(() => timesheet_store.timesheets.every(timesheet => timesheet.is_approved))
|
const is_timesheets_approved = computed(() => timesheet_store.timesheets.every(timesheet => timesheet.is_approved))
|
||||||
|
|
||||||
const total_hours = computed(() => timesheet_store.timesheets.reduce((sum, timesheet) =>
|
const total_hours = computed(() => timesheet_store.timesheets.reduce((sum, timesheet) =>
|
||||||
sum + timesheet.weekly_hours.regular
|
sum += timesheet.weekly_hours.regular
|
||||||
+ timesheet.weekly_hours.evening
|
+ timesheet.weekly_hours.evening
|
||||||
+ timesheet.weekly_hours.emergency
|
+ timesheet.weekly_hours.emergency
|
||||||
+ timesheet.weekly_hours.overtime,
|
+ timesheet.weekly_hours.overtime,
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,20 @@ import { ref } from "vue";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { chatbotService } from "src/modules/chatbot/services/chatbot.service";
|
import { chatbotService } from "src/modules/chatbot/services/chatbot.service";
|
||||||
import type { Message } from "src/modules/chatbot/models/dialogue-message.model";
|
import type { Message } from "src/modules/chatbot/models/dialogue-message.model";
|
||||||
|
import { type ChatbotPageContext, PageContexts } from "src/modules/chatbot/models/page-context.model";
|
||||||
import type { RouteNames } from "src/router/router-constants";
|
import type { RouteNames } from "src/router/router-constants";
|
||||||
import { PageContexts } from "src/modules/chatbot/models/page-context.model";
|
|
||||||
|
|
||||||
export const useChatbotStore = defineStore("chatbot", () => {
|
export const useChatbotStore = defineStore("chatbot", () => {
|
||||||
const messages = ref<Message[]>([]);
|
const messages = ref<Message[]>([]);
|
||||||
const has_shown_instructions = ref(false);
|
const has_shown_instructions = ref(false);
|
||||||
const is_showing_chatbot = ref(false);
|
const is_showing_chatbot = ref(false);
|
||||||
|
const current_page_context = ref<ChatbotPageContext | undefined>(undefined);
|
||||||
|
|
||||||
const sendChatMessage = async (user_message: string) => {
|
const sendChatMessage = async (user_message: string) => {
|
||||||
const last_chatbot_message = messages.value.at(messages.value.length - 1)!;
|
const last_chatbot_message = messages.value.at(messages.value.length - 1)!;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const chatbot_response = await chatbotService.sendChatMessage(user_message);
|
const chatbot_response = await chatbotService.sendChatMessage(user_message, current_page_context.value);
|
||||||
if (chatbot_response) {
|
if (chatbot_response) {
|
||||||
last_chatbot_message.text = chatbot_response.text;
|
last_chatbot_message.text = chatbot_response.text;
|
||||||
last_chatbot_message.isThinking = false;
|
last_chatbot_message.isThinking = false;
|
||||||
|
|
@ -30,11 +31,9 @@ export const useChatbotStore = defineStore("chatbot", () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updatePageContext = async (page_name: RouteNames) => {
|
const updatePageContext = (page_name: RouteNames) => {
|
||||||
const chatbot_page_context = PageContexts[page_name];
|
current_page_context.value = PageContexts[page_name] ?? undefined;
|
||||||
|
|
||||||
if (chatbot_page_context)
|
|
||||||
await chatbotService.sendPageContext(chatbot_page_context);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const showInstructionsOnce = () => {
|
const showInstructionsOnce = () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user