chat for admin
This commit is contained in:
391
src/components/ChatClient.vue
Normal file
391
src/components/ChatClient.vue
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="chat-wrapper p-p-3">
|
||||||
|
<div class="p-d-flex p-flex-column" style="height: 100%;">
|
||||||
|
<div class="chat-messages" ref="messagesContainer">
|
||||||
|
<div v-for="(msg, index) in messages" :key="index" :class="['chat-message', msg.sender]">
|
||||||
|
<div class="message-bubble">
|
||||||
|
<div v-if="msg.sender === 'bot'">
|
||||||
|
|
||||||
|
<MdPreview class="editor" theme="light" previewTheme="github" v-model="msg.text" language="en-US" :key="index" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<p v-else>{{ msg.text }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p-inputGroup class="p-mt-2" style="width: 100%;">
|
||||||
|
<p-inputText
|
||||||
|
v-model="message"
|
||||||
|
placeholder="Ask anything..."
|
||||||
|
@keyup.enter="sendMessage"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p-button
|
||||||
|
label="Send"
|
||||||
|
icon="pi pi-send"
|
||||||
|
class="p-button-primary"
|
||||||
|
@click="sendMessage"
|
||||||
|
/>
|
||||||
|
<p-button
|
||||||
|
label="Reset"
|
||||||
|
icon="pi pi-trash"
|
||||||
|
@click="clearHistory"
|
||||||
|
class=" p-button-danger"
|
||||||
|
/>
|
||||||
|
<p-button
|
||||||
|
icon="pi pi-cog"
|
||||||
|
@click="showSettings = !showSettings"
|
||||||
|
class=" p-button-normal"
|
||||||
|
/>
|
||||||
|
</p-inputGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- CARD DELLE IMPOSTAZIONI -->
|
||||||
|
<p-card v-if="showSettings" class="chat-settings-card p-p-2 p-mt-3">
|
||||||
|
<template #title>
|
||||||
|
<div class="p-d-flex p-ai-center">
|
||||||
|
<i class="pi pi-cog p-mr-2"></i>
|
||||||
|
<span>Chat Settings</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Checkboxes e campi di testo -->
|
||||||
|
<template #content>
|
||||||
|
<p-inputGroup class="p-mt-2" style="width: 100%;">
|
||||||
|
<div class="p-field-checkbox p-mr-3">
|
||||||
|
<p-checkbox v-model="useDocumentation" inputId="documentation" binary="true" />
|
||||||
|
<label for="documentation">Documentation</label>
|
||||||
|
</div>
|
||||||
|
<div class="p-field-checkbox p-mr-3">
|
||||||
|
<p-checkbox v-model="useSource" inputId="source" binary="true" />
|
||||||
|
<label for="source">Source</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p-inputText
|
||||||
|
v-model="scenarioExecutionId"
|
||||||
|
placeholder="Enter executionId..."
|
||||||
|
class="p-mr-2"
|
||||||
|
/>
|
||||||
|
<p-button
|
||||||
|
label="Load Context"
|
||||||
|
icon="pi pi-upload"
|
||||||
|
@click="loadContext"
|
||||||
|
class="p-button-outlined p-button-sm"
|
||||||
|
/>
|
||||||
|
<p-inputText disabled
|
||||||
|
v-model="conversationId"
|
||||||
|
placeholder="Enter conversation ID..."
|
||||||
|
class="p-mr-2"
|
||||||
|
/>
|
||||||
|
<p-inputText disabled
|
||||||
|
v-model="project"
|
||||||
|
placeholder="Project"
|
||||||
|
class="p-mr-2"
|
||||||
|
/>
|
||||||
|
<p-inputText disabled
|
||||||
|
v-model="application"
|
||||||
|
placeholder="Application"
|
||||||
|
class="p-mr-2"
|
||||||
|
/>
|
||||||
|
</p-inputGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</p-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { marked } from "marked";
|
||||||
|
import { MdPreview } from 'md-editor-v3';
|
||||||
|
import 'md-editor-v3/lib/style.css';
|
||||||
|
import Button from 'primevue/button';
|
||||||
|
import Card from 'primevue/card';
|
||||||
|
import Checkbox from 'primevue/checkbox';
|
||||||
|
import InputGroup from 'primevue/inputgroup';
|
||||||
|
import InputGroupAddon from 'primevue/inputgroupaddon';
|
||||||
|
import InputText from 'primevue/inputtext';
|
||||||
|
import ScrollPanel from 'primevue/scrollpanel';
|
||||||
|
|
||||||
|
import { UserPrefStore } from '../stores/UserPrefStore.js';
|
||||||
|
const userPrefStore = UserPrefStore();
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ChatGPTInterface",
|
||||||
|
components: {
|
||||||
|
"p-scrollPanel": ScrollPanel,
|
||||||
|
"p-inputText": InputText,
|
||||||
|
"p-button": Button,
|
||||||
|
"p-checkbox": Checkbox,
|
||||||
|
"p-card": Card,
|
||||||
|
"p-inputGroup": InputGroup,
|
||||||
|
"p-inputGroupAddon": InputGroupAddon,
|
||||||
|
MdPreview
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
conversationId: userPrefStore.user.id, // Default conversation ID
|
||||||
|
message: "",
|
||||||
|
messages: [],
|
||||||
|
useDocumentation: true,
|
||||||
|
useSource: true,
|
||||||
|
project: userPrefStore.user.selectedProject.internal_name,
|
||||||
|
application: userPrefStore.getSelApp ? userPrefStore.getSelApp.internal_name : "",
|
||||||
|
scenarioExecutionId:"",
|
||||||
|
showSettings: false,
|
||||||
|
authorization:"Bearer " + this.$auth.token(),
|
||||||
|
waitingData: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
console.log("mounted");
|
||||||
|
console.log("userPrefStore", userPrefStore);
|
||||||
|
this.fetchChatHistory();
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchChatHistory() {
|
||||||
|
if (!this.conversationId.trim()) {
|
||||||
|
console.warn("No conversation ID set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`http://olympus-api-gateway-aks.olympusai.live/chatservice/get-history?conversationId=${this.conversationId}&lastN=100`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: { "Content-Type": "application/json",
|
||||||
|
"authorization": "Bearer " + this.$auth.token()}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!response.ok) throw new Error("Failed to fetch chat history");
|
||||||
|
|
||||||
|
const history = await response.json();
|
||||||
|
|
||||||
|
// Convert API format to frontend format
|
||||||
|
this.messages = [];
|
||||||
|
|
||||||
|
history.forEach(msg => {
|
||||||
|
console.log("msg", msg);
|
||||||
|
if (msg.messageType != "SYSTEM") {
|
||||||
|
this.messages.push ({
|
||||||
|
sender : msg.messageType === "USER" ? "user" : 'bot',
|
||||||
|
text : msg.text
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
console.log("messages", this.messages);
|
||||||
|
|
||||||
|
|
||||||
|
this.scrollToBottom();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading chat history:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async sendMessage() {
|
||||||
|
if (this.message.trim() === "" || !this.conversationId.trim()) return;
|
||||||
|
|
||||||
|
this.messages.push({ sender: "user", text: this.message });
|
||||||
|
const botMessage = { sender: "bot", text: "" };
|
||||||
|
this.messages.push(botMessage);
|
||||||
|
this.scrollToBottom();
|
||||||
|
const payload = {
|
||||||
|
message: this.message,
|
||||||
|
conversationId: this.conversationId,
|
||||||
|
useDocumentation: this.useDocumentation,
|
||||||
|
useSource: this.useSource,
|
||||||
|
project: this.project,
|
||||||
|
application: this.application
|
||||||
|
};
|
||||||
|
|
||||||
|
this.message = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.waitingData = true;
|
||||||
|
const response = await fetch("http://olympus-api-gateway-aks.olympusai.live/chatservice/chat", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json",
|
||||||
|
"authorization": this.authorization},
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
this.waitingData = false;
|
||||||
|
if (!response.body) throw new Error("Streaming not supported");
|
||||||
|
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
let buffer = "";
|
||||||
|
|
||||||
|
const processStream = async ({ done, value }) => {
|
||||||
|
if (done) return;
|
||||||
|
buffer += decoder.decode(value, { stream: true });
|
||||||
|
|
||||||
|
const parts = buffer.split("\n");
|
||||||
|
buffer = parts.pop();
|
||||||
|
|
||||||
|
parts.forEach((line) => {
|
||||||
|
if (line.startsWith("data:")) {
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(line.slice(5).trim());
|
||||||
|
if (jsonData.result?.output?.text) {
|
||||||
|
botMessage.text += jsonData.result.output.text;
|
||||||
|
}
|
||||||
|
this.$forceUpdate();
|
||||||
|
this.scrollToBottom();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error parsing JSON:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return reader.read().then(processStream);
|
||||||
|
};
|
||||||
|
|
||||||
|
await reader.read().then(processStream);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching response:", error);
|
||||||
|
botMessage.text += "\n[Error fetching response]";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
formatMessage(text) {
|
||||||
|
return marked.parse(text); // Converts Markdown to HTML
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollToBottom() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const container = this.$refs.messagesContainer;
|
||||||
|
container.scrollTop = container.scrollHeight;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetChat() {
|
||||||
|
this.messages = []; // Clear chat messages
|
||||||
|
this.fetchChatHistory(); // Reload history for new conversation ID
|
||||||
|
},
|
||||||
|
async clearHistory() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`http://olympus-api-gateway-aks.olympusai.live/chatservice/delete-history?conversationId=${this.conversationId}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: { "Content-Type": "application/json",
|
||||||
|
"authorization": this.authorization}
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to clear chat history');
|
||||||
|
}
|
||||||
|
this.messages = [];
|
||||||
|
console.log('Chat history deleted successfully!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error clearing chat history:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
async loadContext() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`http://olympus-api-gateway-aks.olympusai.live/chatservice/load-context-to-conversation?conversationId=${this.conversationId}&scenarioExecutionId=${this.scenarioExecutionId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: { "Content-Type": "application/json",
|
||||||
|
"authorization": this.authorization}
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to clear chat history');
|
||||||
|
}
|
||||||
|
this.messages = [];
|
||||||
|
this.resetChat();
|
||||||
|
console.log('Chat history deleted successfully!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error clearing chat history:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap');
|
||||||
|
@import 'md-editor-v3/lib/style.css';
|
||||||
|
|
||||||
|
.md-editor {
|
||||||
|
background-color: inherit;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-card {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
height: 82vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card delle impostazioni */
|
||||||
|
.chat-settings-card {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Area messaggi */
|
||||||
|
.chat-messages {
|
||||||
|
background: #f4f4f4;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 70vh;
|
||||||
|
min-height: 70vh;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Singolo messaggio */
|
||||||
|
.chat-message {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messaggi dell'utente a destra */
|
||||||
|
.chat-message.user {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bolla del messaggio */
|
||||||
|
.message-bubble {
|
||||||
|
max-width: 70%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 15px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stile messaggi del bot */
|
||||||
|
.chat-message.bot .message-bubble {
|
||||||
|
background: #e1e1e1;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stile messaggi dell'utente */
|
||||||
|
.chat-message.user .message-bubble {
|
||||||
|
background: #6f3ff5; /* Sostituisci con il colore desiderato */
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Esempio di pulsanti "outlined" personalizzati */
|
||||||
|
.p-button-outlined {
|
||||||
|
border: 1px solid #6f3ff5; /* Adatta al tuo tema */
|
||||||
|
color: #6f3ff5;
|
||||||
|
}
|
||||||
|
.p-button-outlined.p-button-danger {
|
||||||
|
border: 1px solid #f44336; /* Rosso */
|
||||||
|
color: #f44336;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { UserPrefStore } from '../stores/UserPrefStore.js';
|
import { UserPrefStore } from '../stores/UserPrefStore.js';
|
||||||
@@ -25,10 +25,19 @@ const model = ref([
|
|||||||
{
|
{
|
||||||
label: 'Canvas',
|
label: 'Canvas',
|
||||||
items: [{ label: 'New Canvas', icon: 'pi pi-fw pi-pencil', to: '/mdcanvas' }]
|
items: [{ label: 'New Canvas', icon: 'pi pi-fw pi-pencil', to: '/mdcanvas' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if(userPrefStore.user.role == 'ADMIN'){
|
||||||
|
model.value.push({
|
||||||
|
label: 'Chat',
|
||||||
|
items: [{ label: 'Chat', icon: 'pi pi-fw pi-comments', to: '/chat' }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Funzione per aggiornare la sezione "Your Applications" in base a selectedApp
|
// Funzione per aggiornare la sezione "Your Applications" in base a selectedApp
|
||||||
function updateApplicationsMenu() {
|
function updateApplicationsMenu() {
|
||||||
const selectedApp = userPrefStore.getSelApp;
|
const selectedApp = userPrefStore.getSelApp;
|
||||||
@@ -95,28 +104,10 @@ function updateApplicationsMenu() {
|
|||||||
model.value[1].label = '';
|
model.value[1].label = '';
|
||||||
model.value[1].items = [];
|
model.value[1].items = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Funzione per creare un item scenario con Execution List
|
|
||||||
/*function createScenarioItem(app) {
|
|
||||||
return {
|
|
||||||
label: app.label,
|
|
||||||
icon: 'pi pi-fw pi-wrench',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: 'Execution List',
|
|
||||||
icon: 'pi pi-fw pi-list',
|
|
||||||
to: '/executions/filter',
|
|
||||||
command: () => {
|
|
||||||
userPrefStore.setSelectedScenario(app.label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
command: () => {
|
|
||||||
route.push({ path: `/scenario/exec/${app.scenario_id}` });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}*/
|
|
||||||
|
|
||||||
function createScenarioItem(app) {
|
function createScenarioItem(app) {
|
||||||
|
|
||||||
@@ -148,6 +139,8 @@ function createScenarioItem(app) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -156,7 +149,6 @@ function createScenarioItem(app) {
|
|||||||
|
|
||||||
// Monitora i cambiamenti in selectedApp dallo store
|
// Monitora i cambiamenti in selectedApp dallo store
|
||||||
watch(() => userPrefStore.getSelApp, updateApplicationsMenu, { immediate: true });
|
watch(() => userPrefStore.getSelApp, updateApplicationsMenu, { immediate: true });
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ const router = createRouter({
|
|||||||
path: '/mdcanvas',
|
path: '/mdcanvas',
|
||||||
name: 'mdcanvas',
|
name: 'mdcanvas',
|
||||||
component: () => import('@/views/pages/canvas/MdCanvas.vue')
|
component: () => import('@/views/pages/canvas/MdCanvas.vue')
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/chat',
|
||||||
|
name: 'chat',
|
||||||
|
component: () => import('@/views/pages/chat/ChatPage.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/views/pages/chat/ChatPage.vue
Normal file
22
src/views/pages/chat/ChatPage.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex items-center justify-between p-1">
|
||||||
|
<h1>
|
||||||
|
<i class="pi pi-comments p-mr-2"></i>
|
||||||
|
<span>Chat with WizardAI</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div className="card">
|
||||||
|
<ChatClient />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import ChatClient from '@/components/ChatClient.vue';
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style >
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user