Develop scenario/scenario executions chat
This commit is contained in:
@@ -1,107 +1,59 @@
|
||||
<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 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>
|
||||
</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>
|
||||
<p-inputGroup class="p-mt-2" style="width: 100%">
|
||||
<p-inputText v-model="message" placeholder="Ask anything..." @keyup.enter="sendMessage" />
|
||||
|
||||
|
||||
<!-- 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>
|
||||
<p-button label="Ask" icon="pi pi-send" class="p-button-primary" @click="sendMessage" />
|
||||
<p-button label="Clear" 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>
|
||||
</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>
|
||||
<!-- 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>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
</p-card>
|
||||
</div>
|
||||
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 { marked } from 'marked';
|
||||
import { MdPreview } from 'md-editor-v3';
|
||||
import 'md-editor-v3/lib/style.css';
|
||||
import Button from 'primevue/button';
|
||||
@@ -115,277 +67,281 @@ import ScrollPanel from 'primevue/scrollpanel';
|
||||
import { UserPrefStore } from '../stores/UserPrefStore.js';
|
||||
const userPrefStore = UserPrefStore();
|
||||
|
||||
export default {
|
||||
name: "ChatGPTInterface",
|
||||
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
|
||||
'p-scrollPanel': ScrollPanel,
|
||||
'p-inputText': InputText,
|
||||
'p-button': Button,
|
||||
'p-checkbox': Checkbox,
|
||||
'p-card': Card,
|
||||
'p-inputGroup': InputGroup,
|
||||
'p-inputGroupAddon': InputGroupAddon,
|
||||
MdPreview
|
||||
},
|
||||
props: {
|
||||
scenarioExecutionId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
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
|
||||
};
|
||||
return {
|
||||
conversationId: `${userPrefStore.user.id}-${userPrefStore.user.selectedProject.internal_name}`,
|
||||
message: '',
|
||||
messages: [],
|
||||
useDocumentation: true,
|
||||
useSource: true,
|
||||
project: userPrefStore.user.selectedProject.internal_name,
|
||||
application: userPrefStore.getSelApp ? userPrefStore.getSelApp.internal_name : '',
|
||||
scenarioExecutionId: this.scenarioExecutionId,
|
||||
showSettings: false,
|
||||
authorization: 'Bearer ' + this.$auth.token(),
|
||||
waitingData: false,
|
||||
previousMessagesLength: 0
|
||||
};
|
||||
},
|
||||
//
|
||||
|
||||
|
||||
mounted() {
|
||||
console.log("mounted");
|
||||
console.log("userPrefStore", userPrefStore);
|
||||
this.fetchChatHistory();
|
||||
|
||||
console.log('userPrefStore', userPrefStore);
|
||||
this.updateConversationId();
|
||||
},
|
||||
|
||||
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
|
||||
})
|
||||
async updateConversationId() {
|
||||
this.conversationId = this.scenarioExecutionId
|
||||
? `${userPrefStore.user.id}-${this.scenarioExecutionId}`
|
||||
: `${userPrefStore.user.id}-${userPrefStore.user.selectedProject.internal_name}`;
|
||||
await this.fetchChatHistory();
|
||||
if (this.scenarioExecutionId && this.messages.length === 0) {
|
||||
this.loadContext();
|
||||
}
|
||||
|
||||
});
|
||||
console.log("messages", this.messages);
|
||||
},
|
||||
|
||||
|
||||
this.scrollToBottom();
|
||||
} catch (error) {
|
||||
console.error("Error loading chat history:", error);
|
||||
}
|
||||
},
|
||||
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');
|
||||
|
||||
async sendMessage() {
|
||||
if (this.message.trim() === "" || !this.conversationId.trim()) return;
|
||||
const history = await response.json();
|
||||
|
||||
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
|
||||
};
|
||||
// Convert API format to frontend format
|
||||
this.messages = [];
|
||||
|
||||
this.message = "";
|
||||
history.forEach((msg) => {
|
||||
if (msg.messageType != 'SYSTEM') {
|
||||
this.messages.push({
|
||||
sender: msg.messageType === 'USER' ? 'user' : 'bot',
|
||||
text: msg.text
|
||||
});
|
||||
}
|
||||
});
|
||||
this.scrollToBottom();
|
||||
} catch (error) {
|
||||
console.error('Error loading chat history:', error);
|
||||
}
|
||||
},
|
||||
|
||||
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");
|
||||
async sendMessage() {
|
||||
if (this.message.trim() === '' || !this.conversationId.trim()) return;
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = "";
|
||||
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
|
||||
};
|
||||
|
||||
const processStream = async ({ done, value }) => {
|
||||
if (done) return;
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
this.message = '';
|
||||
|
||||
const parts = buffer.split("\n");
|
||||
buffer = parts.pop();
|
||||
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');
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
});
|
||||
},
|
||||
|
||||
return reader.read().then(processStream);
|
||||
};
|
||||
resetChat() {
|
||||
this.messages = []; // Clear chat messages
|
||||
this.fetchChatHistory(); // Reload history for new conversation ID
|
||||
},
|
||||
|
||||
await reader.read().then(processStream);
|
||||
} catch (error) {
|
||||
console.error("Error fetching response:", error);
|
||||
botMessage.text += "\n[Error fetching response]";
|
||||
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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
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';
|
||||
};
|
||||
</script>
|
||||
|
||||
.md-editor {
|
||||
<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;
|
||||
.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;
|
||||
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;
|
||||
|
||||
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;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* Messaggi dell'utente a destra */
|
||||
.chat-message.user {
|
||||
justify-content: flex-end;
|
||||
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;
|
||||
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;
|
||||
background: #e1e1e1;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Stile messaggi dell'utente */
|
||||
.chat-message.user .message-bubble {
|
||||
background: #6f3ff5; /* Sostituisci con il colore desiderato */
|
||||
color: #fff;
|
||||
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;
|
||||
border: 1px solid #6f3ff5; /* Adatta al tuo tema */
|
||||
color: #6f3ff5;
|
||||
}
|
||||
.p-button-outlined.p-button-danger {
|
||||
border: 1px solid #f44336; /* Rosso */
|
||||
color: #f44336;
|
||||
border: 1px solid #f44336; /* Rosso */
|
||||
color: #f44336;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -25,18 +25,22 @@ const model = ref([
|
||||
{
|
||||
label: 'Canvas',
|
||||
items: [{ label: 'New Canvas', icon: 'pi pi-fw pi-pencil', to: '/mdcanvas' }]
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Chat',
|
||||
items: [{ label: 'Chat', icon: 'pi pi-fw pi-comments', to: '/chat' }]
|
||||
}
|
||||
|
||||
]);
|
||||
|
||||
onMounted(() => {
|
||||
if(userPrefStore.user.role == 'ADMIN'){
|
||||
model.value.push({
|
||||
label: 'Chat',
|
||||
items: [{ label: 'Chat', icon: 'pi pi-fw pi-comments', to: '/chat' }]
|
||||
});
|
||||
}
|
||||
});
|
||||
// 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
|
||||
function updateApplicationsMenu() {
|
||||
|
||||
@@ -108,6 +108,10 @@ watch(() => userPrefStore.getSelApp, appUpdated, { immediate: true });
|
||||
|
||||
|
||||
</div>
|
||||
<div class="layout-topbar-theme">
|
||||
<span class="flex items-center mt-2">Project:</span>
|
||||
</div>
|
||||
|
||||
<div class="topbar-project">
|
||||
<button v-if="userPrefStore.user.selectedProject" @click="redirectProject()" class="p-button p-button-outlined" v-tooltip="'Click to change the project'">{{ userPrefStore.user.selectedProject.fe_name }}</button>
|
||||
<button v-else @click="redirectProject()" class="p-button p-button-outlined" v-tooltip="'Click to change the project'">Project</button>
|
||||
@@ -115,7 +119,11 @@ watch(() => userPrefStore.getSelApp, appUpdated, { immediate: true });
|
||||
<!-- <span v-if="userPrefStore.user.selectedProject">
|
||||
<small>PROJECT:</small> {{ userPrefStore.user.selectedProject.fe_name }}
|
||||
</span> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-topbar-theme">
|
||||
<span class="flex items-center mt-2">Application:</span>
|
||||
</div>
|
||||
<Dropdown
|
||||
v-model="selectedApp"
|
||||
:options="userPrefStore.availableApp"
|
||||
@@ -155,7 +163,7 @@ watch(() => userPrefStore.getSelApp, appUpdated, { immediate: true });
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.2rem;
|
||||
min-width: 100px;
|
||||
|
||||
|
||||
@@ -1,167 +1,147 @@
|
||||
<template>
|
||||
<div v-if="loading" class="flex justify-center">
|
||||
<ProgressSpinner style="width: 50px; height: 50px; margin-top: 50px" strokeWidth="3" fill="transparent"/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="flex items-center justify-between p-2">
|
||||
|
||||
<!-- <Button
|
||||
<div v-if="loading" class="flex justify-center">
|
||||
<ProgressSpinner style="width: 50px; height: 50px; margin-top: 50px" strokeWidth="3" fill="transparent" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="flex items-center justify-between p-2">
|
||||
<!-- <Button
|
||||
@click="back()"
|
||||
label="Load"
|
||||
class="flex items-center text-sm">
|
||||
<ChevronLeftIcon name="chevron-left" class="w-4 h-5 text-white"/>
|
||||
<span>Back to Scenarios</span>
|
||||
</Button> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="loading_data" class="flex justify-center">
|
||||
<ProgressSpinner style="width: 30px; height: 30px; margin: 30px" strokeWidth="6" fill="transparent"/>
|
||||
</div>
|
||||
<div v-if="data_loaded">
|
||||
<!-- <div class="box p-4 border rounded-md shadow-sm" style="background-color: #f3f3f3;">
|
||||
<div v-for="(input, index) in inputs" :key="index" class="input-container">
|
||||
<div class="input-wrapper">
|
||||
<span class="font-bold">{{ index.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase()) }}:</span>
|
||||
<span>{{ input }}</span>
|
||||
</div>
|
||||
<div v-if="loading_data" class="flex justify-center">
|
||||
<ProgressSpinner style="width: 30px; height: 30px; margin: 30px" strokeWidth="6" fill="transparent" />
|
||||
</div>
|
||||
<div v-if="data_loaded">
|
||||
<Panel class="mt-6">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-bold">Execution Input for ID {{ execution_id }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #icons>
|
||||
<div v-if="updateLoading" class="flex justify-end">
|
||||
<Rating :modelValue="rating" :stars="5" @change="updateRating($event)" />
|
||||
</div>
|
||||
<div v-else class="flex justify-end">
|
||||
<Rating :modelValue="rating" :stars="5" :readonly="true" @change="updateRating($event)" />
|
||||
</div>
|
||||
</template>
|
||||
<div class="box p-4 border rounded-md shadow-sm" style="background-color: white">
|
||||
<table class="table-auto w-full border-collapse border border-gray-300">
|
||||
<tbody>
|
||||
<tr v-for="(input, index) in inputs" :key="index">
|
||||
<th v-if="index === 'MultiFileUpload'" class="border border-gray-300 px-4 py-2">Files Uploaded</th>
|
||||
<th v-else-if="index === 'SingleFileUpload'" class="border border-gray-300 px-4 py-2 bg-gray-500 text-white">Parameter</th>
|
||||
<th v-else class="border border-gray-300 px-4 py-2">
|
||||
{{ index.replace(/_/g, ' ').replace(/\b\w/g, (char) => char.toUpperCase()) }}
|
||||
</th>
|
||||
<td class="border border-gray-300 px-4 py-2">
|
||||
<div v-if="index === 'MultiFileUpload'">
|
||||
<div v-if="fileNames.length">
|
||||
<ul>
|
||||
<li v-for="(file, idx) in fileNames" :key="idx" class="file-item">
|
||||
{{ file.substring(file.lastIndexOf('/') + 1) }}
|
||||
<Button icon="pi pi-download" class="p-button-text p-button-sm" label="Download" @click="downloadFileInput(file)" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>No files found in the zip.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="index !== 'SingleFileUpload'">{{ input }}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-if="data_loaded && scenario.chatEnabled" class="flex justify-center">
|
||||
<div v-if="!chat_enabled" class="flex gap-4 mt-4">
|
||||
<Button label="Open Chat" @click="chatEnabled" size="large" iconPos="right" icon="pi pi-comments"></Button>
|
||||
</div>
|
||||
</div> -->
|
||||
<div v-else class="flex gap-4 mt-4">
|
||||
<Button label="Return to scenario" @click="chatDisabled" size="large" iconPos="right" icon="pi pi-backward"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
|
||||
<div v-if="!chat_enabled" class="mt-4">
|
||||
<Panel class="mt-6">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-bold">Execution Input for ID {{execution_id}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #icons>
|
||||
<div v-if="updateLoading" class="flex justify-end">
|
||||
<Rating
|
||||
:modelValue="rating"
|
||||
:stars="5"
|
||||
@change="updateRating($event)"
|
||||
|
||||
/>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-bold">Workflow response</span>
|
||||
</div>
|
||||
<div v-else class="flex justify-end">
|
||||
<Rating
|
||||
|
||||
:modelValue="rating"
|
||||
:stars="5"
|
||||
:readonly="true"
|
||||
@change="updateRating($event)"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<div class="box p-4 border rounded-md shadow-sm" style="background-color: white;">
|
||||
<table class="table-auto w-full border-collapse border border-gray-300">
|
||||
<tbody>
|
||||
<tr v-for="(input, index) in inputs" :key="index">
|
||||
<th v-if="index === 'MultiFileUpload'" class="border border-gray-300 px-4 py-2">
|
||||
Files Uploaded
|
||||
</th>
|
||||
<th v-else-if="index === 'SingleFileUpload'" class="border border-gray-300 px-4 py-2 bg-gray-500 text-white">
|
||||
Parameter
|
||||
</th>
|
||||
<th v-else class="border border-gray-300 px-4 py-2">
|
||||
{{ index.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase()) }}
|
||||
</th>
|
||||
<td class="border border-gray-300 px-4 py-2">
|
||||
<div v-if="index === 'MultiFileUpload'">
|
||||
<div v-if="fileNames.length">
|
||||
<ul>
|
||||
<li v-for="(file, idx) in fileNames" :key="idx" class="file-item">
|
||||
{{ file.substring(file.lastIndexOf('/') + 1) }}
|
||||
<Button
|
||||
icon="pi pi-download"
|
||||
class="p-button-text p-button-sm"
|
||||
label="Download"
|
||||
@click="downloadFileInput(file)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>No files found in the zip.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="index !== 'SingleFileUpload'">{{ input }}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<Panel class="mt-6">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-bold">Workflow response</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #icons>
|
||||
<div class="flex justify-end">
|
||||
<Button severity="secondary" rounded @click="openDebug" v-tooltip.left="'View code'">
|
||||
<i class="pi pi-code"></i>
|
||||
</Button>
|
||||
<Button severity="secondary" rounded @click="openDebug" v-tooltip.left="'View code'">
|
||||
<i class="pi pi-code"></i>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<div class="card flex flex-col gap-4 w-full">
|
||||
<div v-if="scenario.outputType == 'ciaOutput'">
|
||||
<ChangeImpactOutputViewer :scenario_output="scenario_output" />
|
||||
<ChangeImpactOutputViewer :scenario_output="scenario_output" />
|
||||
</div>
|
||||
<div v-else-if="loadingStore.exectuion_loading && loadingStore.getExecIdLoading===execution_id">
|
||||
<div class="flex justify-center mt-4">
|
||||
<jellyfish-loader :loading="loadingStore.exectuion_loading" scale="1" color="#A100FF" />
|
||||
</div>
|
||||
<div v-else-if="loadingStore.exectuion_loading && loadingStore.getExecIdLoading === execution_id">
|
||||
<div class="flex justify-center mt-4">
|
||||
<jellyfish-loader :loading="loadingStore.exectuion_loading" scale="1" color="#A100FF" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="fileType == 'FILE' && exec_scenario.execSharedMap.status!=null && exec_scenario.execSharedMap.status==='DONE'">
|
||||
<ul class="file-list">
|
||||
<li class="file-item">
|
||||
sf_document-{{execution_id}}
|
||||
<Button
|
||||
icon="pi pi-download"
|
||||
class="p-button-text p-button-sm"
|
||||
label="Download"
|
||||
@click="downloadFile(scenario_output)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div v-else-if="fileType == 'MARKDOWN'">
|
||||
<div v-html="fileContent" class="markdown-content"></div>
|
||||
</div>
|
||||
<div v-else-if="fileType == 'JSON'">
|
||||
<pre>{{ fileContent }}</pre>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MdPreview class="editor" v-model="scenario_output" language="en-US" />
|
||||
</div>
|
||||
<div v-if="fileType == 'FILE' && exec_scenario.execSharedMap.status != null && exec_scenario.execSharedMap.status === 'DONE'">
|
||||
<ul class="file-list">
|
||||
<li class="file-item">
|
||||
sf_document-{{ execution_id }}
|
||||
<Button icon="pi pi-download" class="p-button-text p-button-sm" label="Download" @click="downloadFile(scenario_output)" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-else-if="fileType == 'MARKDOWN'">
|
||||
<div v-html="fileContent" class="markdown-content"></div>
|
||||
</div>
|
||||
<div v-else-if="fileType == 'JSON'">
|
||||
<pre>{{ fileContent }}</pre>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MdPreview class="editor" v-model="scenario_output" language="en-US" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<Dialog v-model:visible="debug_modal" maximizable modal :header="scenario.name" :style="{ width: '75%' }" :breakpoints="{ '1199px': '75vw', '575px': '90vw' }">
|
||||
|
||||
<div class="flex">
|
||||
<div class="card flex flex-col gap-4 w-full">
|
||||
<JsonEditorVue
|
||||
v-model="exec_scenario"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card flex flex-col gap-4 w-full">
|
||||
<JsonEditorVue v-model="exec_scenario" />
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
<div v-else="chat_enabled" class="mt-4">
|
||||
<Panel class="mt-6">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2 mt-2">
|
||||
<span class="font-bold">Chat with WizardAI</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="card flex flex-col gap-4 w-full">
|
||||
<ChatClient :scenarioExecutionId="execution_id" />
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue';
|
||||
import { LoadingStore } from '@/stores/LoadingStore.js';
|
||||
import axios from 'axios';
|
||||
@@ -174,10 +154,11 @@ import ProgressSpinner from 'primevue/progressspinner';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { JellyfishLoader } from "vue3-spinner";
|
||||
import { JellyfishLoader } from 'vue3-spinner';
|
||||
import { ScenarioService } from '../../service/ScenarioService.js';
|
||||
import { ScenarioExecutionStore } from '../../stores/ScenarioExecutionStore.js';
|
||||
import { UserPrefStore } from '../../stores/UserPrefStore.js';
|
||||
import ChatClient from '@/components/ChatClient.vue';
|
||||
|
||||
const loadingStore = LoadingStore();
|
||||
const router = useRouter();
|
||||
@@ -195,111 +176,100 @@ const debug_modal = ref(false);
|
||||
const rating = ref(null);
|
||||
const scenario_execution_store = ScenarioExecutionStore();
|
||||
const execution = scenario_execution_store.getSelectedExecScenario;
|
||||
const execution_id = ref(null)
|
||||
const execution_id = ref(null);
|
||||
const inputs = ref(null);
|
||||
const steps = ref(null);
|
||||
const toast = useToast();
|
||||
const toast = useToast();
|
||||
const fileNames = ref([]); // Memorizza i nomi dei file nello zip
|
||||
const fileNamesOutput = ref([]); // Memorizza i nomi dei file nello zip
|
||||
const zipInput = ref(null); // Contenitore per il file zip
|
||||
const zipOutput = ref(null); // Contenitore per il file zip
|
||||
const userPrefStore = UserPrefStore();
|
||||
const updateLoading = ref(false);
|
||||
const fileContent = ref('');
|
||||
const fileContent = ref('');
|
||||
const fileType = ref('');
|
||||
|
||||
const chat_enabled = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
if (execution){
|
||||
console.log("scenario id: ", execution);
|
||||
execution_id.value = execution.id
|
||||
console.log("execution_id: ",execution_id)
|
||||
}else{
|
||||
if (execution) {
|
||||
execution_id.value = execution.id;
|
||||
} else {
|
||||
const url = window.location.href;
|
||||
execution_id.value = (new URL(url)).searchParams.get('id')
|
||||
console.log(execution_id.value)
|
||||
execution_id.value = new URL(url).searchParams.get('id');
|
||||
}
|
||||
retrieveScenarioExec(execution_id.value)
|
||||
|
||||
retrieveScenarioExec(execution_id.value);
|
||||
});
|
||||
|
||||
const retrieveScenarioExec = (id) => {
|
||||
//const id = execution_id.value.id;
|
||||
loading.value = true
|
||||
loading.value = true;
|
||||
|
||||
axios.get('/execution?id=' + id )
|
||||
.then(response => {
|
||||
loading.value = false
|
||||
scenario.value = response.data.scenario
|
||||
exec_scenario.value = response.data
|
||||
data_loaded.value = true;
|
||||
rating.value = response.data.rating
|
||||
scenario_output.value = response.data.execSharedMap.scenario_output;
|
||||
exec_id.value = response.data.scenarioExecution_id
|
||||
inputs.value = response.data.scenarioExecutionInput.inputs
|
||||
steps.value = response.data.scenario.steps
|
||||
if(inputs.value['MultiFileUpload']){
|
||||
extractFiles(inputs.value['MultiFileUpload'], 'input', zipInput)
|
||||
if(steps.value[0].attributes['codegenie_output_type']){
|
||||
if(steps.value[0].attributes['codegenie_output_type'] == 'FILE'){
|
||||
//console.log('base64 ', scenario_output.value)
|
||||
//extractFiles(scenario_output.value, 'output', zipOutput)
|
||||
fileType.value = 'FILE'
|
||||
|
||||
}
|
||||
else if(steps.value[0].attributes['codegenie_output_type'] == 'MARKDOWN'){
|
||||
fileType.value = 'MARKDOWN'
|
||||
showFileContent(scenario_output.value, 'MARKDOWN')
|
||||
}
|
||||
else if(steps.value[0].attributes['codegenie_output_type'] == 'JSON'){
|
||||
fileType.value = 'JSON'
|
||||
showFileContent(scenario_output.value, 'JSON')
|
||||
}
|
||||
axios.get('/execution?id=' + id).then((response) => {
|
||||
loading.value = false;
|
||||
scenario.value = response.data.scenario;
|
||||
exec_scenario.value = response.data;
|
||||
data_loaded.value = true;
|
||||
rating.value = response.data.rating;
|
||||
scenario_output.value = response.data.execSharedMap.scenario_output;
|
||||
exec_id.value = response.data.scenarioExecution_id;
|
||||
inputs.value = response.data.scenarioExecutionInput.inputs;
|
||||
steps.value = response.data.scenario.steps;
|
||||
if (inputs.value['MultiFileUpload']) {
|
||||
extractFiles(inputs.value['MultiFileUpload'], 'input', zipInput);
|
||||
if (steps.value[0].attributes['codegenie_output_type']) {
|
||||
if (steps.value[0].attributes['codegenie_output_type'] == 'FILE') {
|
||||
fileType.value = 'FILE';
|
||||
} else if (steps.value[0].attributes['codegenie_output_type'] == 'MARKDOWN') {
|
||||
fileType.value = 'MARKDOWN';
|
||||
showFileContent(scenario_output.value, 'MARKDOWN');
|
||||
} else if (steps.value[0].attributes['codegenie_output_type'] == 'JSON') {
|
||||
fileType.value = 'JSON';
|
||||
showFileContent(scenario_output.value, 'JSON');
|
||||
}
|
||||
}
|
||||
if(exec_scenario.value.executedByUsername===userPrefStore.getUser.username){
|
||||
updateLoading.value = true
|
||||
}
|
||||
});
|
||||
}
|
||||
if (exec_scenario.value.executedByUsername === userPrefStore.getUser.username) {
|
||||
updateLoading.value = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const extractFiles = async (base64String, type, zip) => {
|
||||
try {
|
||||
// Decodifica la base64 in un array di byte
|
||||
const byteCharacters = atob(base64String);
|
||||
const byteNumbers = Array.from(byteCharacters, char => char.charCodeAt(0));
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
try {
|
||||
// Decodifica la base64 in un array di byte
|
||||
const byteCharacters = atob(base64String);
|
||||
const byteNumbers = Array.from(byteCharacters, (char) => char.charCodeAt(0));
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
|
||||
// Carica il file zip con JSZip
|
||||
const zipData = await JSZip.loadAsync(byteArray);
|
||||
zip.value = zipData;
|
||||
// Carica il file zip con JSZip
|
||||
const zipData = await JSZip.loadAsync(byteArray);
|
||||
zip.value = zipData;
|
||||
|
||||
// Ottieni tutti i file (compresi quelli nelle sottocartelle)
|
||||
if(type == 'input'){
|
||||
fileNames.value = getFileNamesInput(zipData);
|
||||
}else{
|
||||
fileNamesOutput.value = getFileNames(zipData);
|
||||
// Ottieni tutti i file (compresi quelli nelle sottocartelle)
|
||||
if (type == 'input') {
|
||||
fileNames.value = getFileNamesInput(zipData);
|
||||
} else {
|
||||
fileNamesOutput.value = getFileNames(zipData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error extracting zip:', error);
|
||||
if (type == 'input') {
|
||||
fileNames.value = [];
|
||||
} else {
|
||||
fileNamesOutput.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error extracting zip:', error);
|
||||
if(type == 'input'){
|
||||
fileNames.value = [];
|
||||
}else{
|
||||
fileNamesOutput.value = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const showFileContent = (base64String, type) => {
|
||||
try {
|
||||
try {
|
||||
// Decodifica la stringa Base64
|
||||
const binaryString = atob(base64String);
|
||||
const binaryLength = binaryString.length;
|
||||
const bytes = new Uint8Array(binaryLength);
|
||||
|
||||
for (let i = 0; i < binaryLength; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
// Converti i byte in una stringa leggibile
|
||||
@@ -307,257 +277,257 @@ const showFileContent = (base64String, type) => {
|
||||
|
||||
// Gestione del tipo di file
|
||||
if (type === 'MARKDOWN') {
|
||||
//fileType.value = 'markdown';
|
||||
fileContent.value = marked(textContent); // Converte Markdown in HTML
|
||||
//fileType.value = 'markdown';
|
||||
fileContent.value = marked(textContent); // Converte Markdown in HTML
|
||||
} else if (type === 'JSON') {
|
||||
//fileType.value = 'json';
|
||||
const jsonObject = JSON.parse(textContent); // Parse JSON
|
||||
fileContent.value = JSON.stringify(jsonObject, null, 2); // Formatta JSON
|
||||
//fileType.value = 'json';
|
||||
const jsonObject = JSON.parse(textContent); // Parse JSON
|
||||
fileContent.value = JSON.stringify(jsonObject, null, 2); // Formatta JSON
|
||||
} else {
|
||||
fileContent.value = 'Tipo di file non supportato.';
|
||||
fileContent.value = 'Tipo di file non supportato.';
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
fileContent.value = 'Errore durante la decodifica o il parsing del file.';
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Funzione ricorsiva per ottenere tutti i file (anche quelli dentro le cartelle)
|
||||
const getFileNames = (zipData) => {
|
||||
const files = [];
|
||||
|
||||
// Esplora tutti i file nel file zip, considerando anche le sottocartelle
|
||||
zipData.forEach((relativePath, file) => {
|
||||
if (!file.dir) { // Escludiamo le cartelle
|
||||
const fileName = relativePath.split('/').pop(); // Estrai solo il nome del file
|
||||
files.push(fileName); // Aggiungiamo solo il nome del file
|
||||
}
|
||||
});
|
||||
// Esplora tutti i file nel file zip, considerando anche le sottocartelle
|
||||
zipData.forEach((relativePath, file) => {
|
||||
if (!file.dir) {
|
||||
// Escludiamo le cartelle
|
||||
const fileName = relativePath.split('/').pop(); // Estrai solo il nome del file
|
||||
files.push(fileName); // Aggiungiamo solo il nome del file
|
||||
}
|
||||
});
|
||||
|
||||
return files;
|
||||
return files;
|
||||
};
|
||||
|
||||
const getFileNamesInput = (zipData) => {
|
||||
const files = [];
|
||||
const getFileNamesInput = (zipData) => {
|
||||
const files = [];
|
||||
|
||||
// Esplora tutti i file nel file zip, considerando anche le sottocartelle
|
||||
zipData.forEach((relativePath, file) => {
|
||||
if (!file.dir) { // Escludiamo le cartelle
|
||||
files.push(relativePath); // Aggiungiamo il percorso relativo del file
|
||||
}
|
||||
});
|
||||
// Esplora tutti i file nel file zip, considerando anche le sottocartelle
|
||||
zipData.forEach((relativePath, file) => {
|
||||
if (!file.dir) {
|
||||
// Escludiamo le cartelle
|
||||
files.push(relativePath); // Aggiungiamo il percorso relativo del file
|
||||
}
|
||||
});
|
||||
|
||||
return files;
|
||||
};
|
||||
return files;
|
||||
};
|
||||
|
||||
// Funzione per scaricare il file
|
||||
const downloadFileInput = async (fileName) => {
|
||||
if (!zipInput.value) return;
|
||||
if (!zipInput.value) return;
|
||||
|
||||
try {
|
||||
// Estrai il file dallo zip
|
||||
const fileContent = await zipInput.value.file(fileName).async('blob');
|
||||
const url = URL.createObjectURL(fileContent);
|
||||
try {
|
||||
// Estrai il file dallo zip
|
||||
const fileContent = await zipInput.value.file(fileName).async('blob');
|
||||
const url = URL.createObjectURL(fileContent);
|
||||
|
||||
// Crea un link per scaricare il file
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
// Crea un link per scaricare il file
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error(`Error downloading file "${fileName}":`, error);
|
||||
}
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error(`Error downloading file "${fileName}":`, error);
|
||||
}
|
||||
};
|
||||
|
||||
const downloadFileOutput = async (fileName) => {
|
||||
if (!zipOutput.value) return;
|
||||
if (!zipOutput.value) return;
|
||||
|
||||
try {
|
||||
// Estrai il file dallo zip
|
||||
const fileContent = await zipOutput.value.file(fileName).async('blob');
|
||||
const url = URL.createObjectURL(fileContent);
|
||||
try {
|
||||
// Estrai il file dallo zip
|
||||
const fileContent = await zipOutput.value.file(fileName).async('blob');
|
||||
const url = URL.createObjectURL(fileContent);
|
||||
|
||||
// Crea un link per scaricare il file
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
// Crea un link per scaricare il file
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error(`Error downloading file "${fileName}":`, error);
|
||||
}
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error(`Error downloading file "${fileName}":`, error);
|
||||
}
|
||||
};
|
||||
|
||||
const downloadFile = (base64String) => {
|
||||
// Decodifica la stringa Base64
|
||||
const binaryString = atob(base64String);
|
||||
const binaryLength = binaryString.length;
|
||||
const bytes = new Uint8Array(binaryLength);
|
||||
// Decodifica la stringa Base64
|
||||
const binaryString = atob(base64String);
|
||||
const binaryLength = binaryString.length;
|
||||
const bytes = new Uint8Array(binaryLength);
|
||||
|
||||
for (let i = 0; i < binaryLength; i++) {
|
||||
for (let i = 0; i < binaryLength; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
// Creazione di un Blob dal file binario
|
||||
const blob = new Blob([bytes], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
|
||||
|
||||
// Creazione di un URL per il Blob
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Creazione di un elemento anchor per il download
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = 'sf_document-'+execution_id.value+'.docx';
|
||||
|
||||
// Simulazione di un click per scaricare il file
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// Pulizia del DOM
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
const downloadFolderFromBase64 = async (base64String) => {
|
||||
try {
|
||||
// Decodifica la stringa base64 in un array di byte
|
||||
const binaryString = atob(base64String); // Decodifica base64 in una stringa binaria
|
||||
const byteArray = new Uint8Array(binaryString.length); // Crea un array di byte
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
byteArray[i] = binaryString.charCodeAt(i); // Popola l'array di byte
|
||||
}
|
||||
|
||||
// Crea un oggetto JSZip per lavorare con il contenuto ZIP
|
||||
const zip = await JSZip.loadAsync(byteArray); // Carica direttamente l'array di byte
|
||||
// Creazione di un Blob dal file binario
|
||||
const blob = new Blob([bytes], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
|
||||
|
||||
// Estrai il primo nome della cartella presente nello ZIP
|
||||
let folderName = Object.keys(zip.files).find(file => zip.files[file].dir); // Trova il primo file che è una cartella
|
||||
|
||||
// Se non è stata trovata alcuna cartella, creiamo una cartella chiamata "folderToDownload"
|
||||
if (!folderName) {
|
||||
folderName = 'docOutput-' + execution_id.value;
|
||||
console.log(`Non è stata trovata alcuna cartella nello ZIP. Verrà creata una cartella chiamata "${folderName}".`);
|
||||
}
|
||||
// Creazione di un URL per il Blob
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Crea un nuovo archivio ZIP in cui mettere i file della cartella
|
||||
const newZip = new JSZip();
|
||||
// Creazione di un elemento anchor per il download
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = 'sf_document-' + execution_id.value + '.docx';
|
||||
|
||||
// Se una cartella esiste nello ZIP, estrai i file da essa, altrimenti crea una nuova cartella
|
||||
const folder = zip.folder(folderName);
|
||||
if (folder) {
|
||||
// Aggiungi ogni file della cartella al nuovo archivio ZIP
|
||||
const files = folder.files;
|
||||
for (const fileName in files) {
|
||||
const file = files[fileName];
|
||||
|
||||
// Controlla se il file è valido (non nullo)
|
||||
if (file && file.async) {
|
||||
try {
|
||||
const fileContent = await file.async('blob'); // Estrai il contenuto del file
|
||||
newZip.file(fileName, fileContent);
|
||||
} catch (fileError) {
|
||||
console.error(`Errore durante l'estrazione del file "${fileName}":`, fileError);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Il file "${fileName}" non è valido o non può essere elaborato.`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Se la cartella non esiste, crea una cartella vuota con nome "folderToDownload"
|
||||
newZip.folder(folderName);
|
||||
}
|
||||
|
||||
// Crea il nuovo file ZIP da scaricare
|
||||
const newZipContent = await newZip.generateAsync({ type: 'blob' });
|
||||
const url = URL.createObjectURL(newZipContent);
|
||||
|
||||
// Crea un link per scaricare il file ZIP
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${folderName}.zip`; // Nome del file ZIP che contiene la cartella
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
// Simulazione di un click per scaricare il file
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// Pulizia del DOM
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error('Errore durante il download della cartella:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const downloadFolderFromBase64 = async (base64String) => {
|
||||
try {
|
||||
// Decodifica la stringa base64 in un array di byte
|
||||
const binaryString = atob(base64String); // Decodifica base64 in una stringa binaria
|
||||
const byteArray = new Uint8Array(binaryString.length); // Crea un array di byte
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
byteArray[i] = binaryString.charCodeAt(i); // Popola l'array di byte
|
||||
}
|
||||
|
||||
// Crea un oggetto JSZip per lavorare con il contenuto ZIP
|
||||
const zip = await JSZip.loadAsync(byteArray); // Carica direttamente l'array di byte
|
||||
|
||||
// Estrai il primo nome della cartella presente nello ZIP
|
||||
let folderName = Object.keys(zip.files).find((file) => zip.files[file].dir); // Trova il primo file che è una cartella
|
||||
|
||||
// Se non è stata trovata alcuna cartella, creiamo una cartella chiamata "folderToDownload"
|
||||
if (!folderName) {
|
||||
folderName = 'docOutput-' + execution_id.value;
|
||||
console.log(`No folders founded in the ZIP. Creating a new folder: "${folderName}".`);
|
||||
}
|
||||
|
||||
// Crea un nuovo archivio ZIP in cui mettere i file della cartella
|
||||
const newZip = new JSZip();
|
||||
|
||||
// Se una cartella esiste nello ZIP, estrai i file da essa, altrimenti crea una nuova cartella
|
||||
const folder = zip.folder(folderName);
|
||||
if (folder) {
|
||||
// Aggiungi ogni file della cartella al nuovo archivio ZIP
|
||||
const files = folder.files;
|
||||
for (const fileName in files) {
|
||||
const file = files[fileName];
|
||||
|
||||
// Controlla se il file è valido (non nullo)
|
||||
if (file && file.async) {
|
||||
try {
|
||||
const fileContent = await file.async('blob'); // Estrai il contenuto del file
|
||||
newZip.file(fileName, fileContent);
|
||||
} catch (fileError) {
|
||||
console.error(`Error while extracting "${fileName}":`, fileError);
|
||||
}
|
||||
} else {
|
||||
console.warn(`"${fileName}" is invalid or cannot be elaborated`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Se la cartella non esiste, crea una cartella vuota con nome "folderToDownload"
|
||||
newZip.folder(folderName);
|
||||
}
|
||||
|
||||
// Crea il nuovo file ZIP da scaricare
|
||||
const newZipContent = await newZip.generateAsync({ type: 'blob' });
|
||||
const url = URL.createObjectURL(newZipContent);
|
||||
|
||||
// Crea un link per scaricare il file ZIP
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${folderName}.zip`; // Nome del file ZIP che contiene la cartella
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error('Error while downloading folder:', error);
|
||||
}
|
||||
};
|
||||
|
||||
async function updateRating(newRating) {
|
||||
|
||||
loading_data.value = true;
|
||||
ScenarioService.updateScenarioExecRating(execution_id.value,newRating.value).then((response) => {
|
||||
|
||||
console.log('response:', response);
|
||||
if (response.data === "OK") {
|
||||
rating.value = newRating.value;
|
||||
console.log('Rating aggiornato con successo:', response.data);
|
||||
toast.add({
|
||||
severity: 'success', // Tipo di notifica (successo)
|
||||
summary: 'Success', // Titolo della notifica
|
||||
detail: 'Rating updated with success.', // Messaggio dettagliato
|
||||
life: 3000 // Durata della notifica in millisecondi
|
||||
});
|
||||
} else {
|
||||
console.error('Errore nell\'aggiornamento del rating', response.data);
|
||||
toast.add({
|
||||
severity: 'error', // Tipo di notifica (errore)
|
||||
summary: 'Error', // Titolo della notifica
|
||||
detail: 'Error updating rating. Try later.', // Messaggio dettagliato
|
||||
life: 3000 // Durata della notifica in millisecondi
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('Errore durante la chiamata al backend:', error);
|
||||
}).finally(() => {
|
||||
loading_data.value = false;
|
||||
});
|
||||
|
||||
|
||||
ScenarioService.updateScenarioExecRating(execution_id.value, newRating.value)
|
||||
.then((response) => {
|
||||
console.log('response:', response);
|
||||
if (response.data === 'OK') {
|
||||
rating.value = newRating.value;
|
||||
console.log('Rating successfully updated:', response.data);
|
||||
toast.add({
|
||||
severity: 'success', // Tipo di notifica (successo)
|
||||
summary: 'Success', // Titolo della notifica
|
||||
detail: 'Rating updated with success.', // Messaggio dettagliato
|
||||
life: 3000 // Durata della notifica in millisecondi
|
||||
});
|
||||
} else {
|
||||
console.error("Error while updating rating", response.data);
|
||||
toast.add({
|
||||
severity: 'error', // Tipo di notifica (errore)
|
||||
summary: 'Error', // Titolo della notifica
|
||||
detail: 'Error updating rating. Try later.', // Messaggio dettagliato
|
||||
life: 3000 // Durata della notifica in millisecondi
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error while calling backend:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
loading_data.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const back = () => {
|
||||
router.push({ name: 'scenario-list'});
|
||||
}
|
||||
router.push({ name: 'scenario-list' });
|
||||
};
|
||||
|
||||
const openDebug = () => {
|
||||
debug_modal.value = true
|
||||
}
|
||||
debug_modal.value = true;
|
||||
};
|
||||
|
||||
const chatEnabled = () => {
|
||||
chat_enabled.value = true;
|
||||
};
|
||||
|
||||
const chatDisabled = () => {
|
||||
chat_enabled.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.input-container {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.input-container {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.full-width-input {
|
||||
width: 100%;
|
||||
}
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.full-width-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.editor ol {
|
||||
list-style-type: decimal !important;
|
||||
@@ -568,31 +538,29 @@ const openDebug = () => {
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap; /* Fa andare a capo il contenuto automaticamente */
|
||||
word-wrap: break-word; /* Interrompe le parole troppo lunghe */
|
||||
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
||||
max-width: 100%; /* Imposta una larghezza massima pari al contenitore genitore */
|
||||
overflow-x: auto; /* Aggiunge uno scorrimento orizzontale solo se necessario */
|
||||
background-color: #f5f5f5; /* Colore di sfondo opzionale per migliorare leggibilità */
|
||||
padding: 10px; /* Spaziatura interna */
|
||||
border-radius: 5px; /* Bordo arrotondato opzionale */
|
||||
font-family: monospace; /* Font specifico per codice */
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Ombra per migliorare estetica */
|
||||
white-space: pre-wrap; /* Fa andare a capo il contenuto automaticamente */
|
||||
word-wrap: break-word; /* Interrompe le parole troppo lunghe */
|
||||
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
||||
max-width: 100%; /* Imposta una larghezza massima pari al contenitore genitore */
|
||||
overflow-x: auto; /* Aggiunge uno scorrimento orizzontale solo se necessario */
|
||||
background-color: #f5f5f5; /* Colore di sfondo opzionale per migliorare leggibilità */
|
||||
padding: 10px; /* Spaziatura interna */
|
||||
border-radius: 5px; /* Bordo arrotondato opzionale */
|
||||
font-family: monospace; /* Font specifico per codice */
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Ombra per migliorare estetica */
|
||||
}
|
||||
|
||||
.markdown-content {
|
||||
white-space: pre-wrap; /* Gestisce correttamente gli spazi e i ritorni a capo */
|
||||
word-wrap: break-word; /* Spezza le parole lunghe */
|
||||
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
||||
max-width: 100%; /* Adatta il contenuto alla larghezza del contenitore */
|
||||
overflow-x: auto; /* Aggiunge scorrimento orizzontale solo se necessario */
|
||||
background-color: #f5f5f5; /* Sfondo per distinguere il contenuto */
|
||||
padding: 10px; /* Margini interni */
|
||||
border-radius: 5px; /* Bordo arrotondato */
|
||||
font-family: Arial, sans-serif; /* Puoi scegliere un font leggibile */
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Effetto estetico di ombra */
|
||||
line-height: 1.5; /* Aumenta la leggibilità */
|
||||
white-space: pre-wrap; /* Gestisce correttamente gli spazi e i ritorni a capo */
|
||||
word-wrap: break-word; /* Spezza le parole lunghe */
|
||||
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
||||
max-width: 100%; /* Adatta il contenuto alla larghezza del contenitore */
|
||||
overflow-x: auto; /* Aggiunge scorrimento orizzontale solo se necessario */
|
||||
background-color: #f5f5f5; /* Sfondo per distinguere il contenuto */
|
||||
padding: 10px; /* Margini interni */
|
||||
border-radius: 5px; /* Bordo arrotondato */
|
||||
font-family: Arial, sans-serif; /* Puoi scegliere un font leggibile */
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Effetto estetico di ombra */
|
||||
line-height: 1.5; /* Aumenta la leggibilità */
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
{{ scenario.description }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="flex mt-6">
|
||||
<div v-if="data_loaded && chat_enabled" class="flex mt-6 justify-center">
|
||||
<div class="card flex flex-col gap-4 w-full items-center">
|
||||
<Button label="Return to scenario" @click="chatDisabled" size="large" iconPos="right" icon="pi pi-backward" class="w-auto"></Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="flex mt-6">
|
||||
<div class="card flex flex-col gap-4 w-full">
|
||||
<MdPreview :class="['markdown-content', 'ml-[-20px]']" v-model="scenario.hint" language="en-US" />
|
||||
|
||||
@@ -143,7 +148,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<div v-if="data_loaded && scenario.chatEnabled" class="flex justify-center">
|
||||
<div v-if ="!chat_enabled" class="flex gap-4">
|
||||
<Button :disabled="loadingStore.exectuion_loading || !isInputFilled" label="Execute" @click="execScenario" size="large" iconPos="right" icon="pi pi-cog"></Button>
|
||||
<Button label="Open Chat" @click="chatEnabled" size="large" iconPos="right" icon="pi pi-comments"></Button>
|
||||
</div>
|
||||
<!-- <div v-else>
|
||||
<Button label="Return to scenario" @click="chatDisabled" size="large" iconPos="right" icon="pi pi-backward"></Button>
|
||||
</div> -->
|
||||
</div>
|
||||
<div v-else class="flex justify-center">
|
||||
<Button :disabled="loadingStore.exectuion_loading || !isInputFilled" label="Execute" @click="execScenario" size="large" iconPos="right" icon="pi pi-cog"></Button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -163,7 +177,7 @@
|
||||
<div id="timer" class="timer">00:00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="data_loaded">
|
||||
<div v-if="data_loaded && !chat_enabled">
|
||||
<Panel class="mt-6">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -234,6 +248,18 @@
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
<div v-if="data_loaded && chat_enabled" class="mt-4">
|
||||
<Panel class="mt-6">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2 mt-2">
|
||||
<span class="font-bold">Chat with WizardAI</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="card flex flex-col gap-4 w-full">
|
||||
<ChatClient :scenarioExecutionId="exec_id"/>
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -256,13 +282,12 @@ import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { JellyfishLoader } from 'vue3-spinner';
|
||||
import { ScenarioService } from '../../service/ScenarioService';
|
||||
import ChatClient from '@/components/ChatClient.vue';
|
||||
|
||||
const loadingStore = LoadingStore();
|
||||
const toast = useToast();
|
||||
const zip = ref(null);
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const value = ref('');
|
||||
const rating = ref(0);
|
||||
const scenario = ref({});
|
||||
const scenario_response = ref(null);
|
||||
@@ -298,6 +323,7 @@ const files = ref([]);
|
||||
const fileContent = ref('');
|
||||
const fileType = ref('');
|
||||
const reqMultiFile = ref(false);
|
||||
const chat_enabled = ref(false);
|
||||
|
||||
let startTime = ref(null);
|
||||
let timerInterval = ref(null);
|
||||
@@ -387,6 +413,14 @@ const getInputComponent = (type) => {
|
||||
}
|
||||
};
|
||||
|
||||
const chatEnabled = () =>{
|
||||
chat_enabled.value = true;
|
||||
}
|
||||
|
||||
const chatDisabled = () =>{
|
||||
chat_enabled.value = false;
|
||||
}
|
||||
|
||||
const execScenario = () => {
|
||||
if (numberPrFiles.value !== 1 && reqMultiFile.value) {
|
||||
toast.add({
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between p-1">
|
||||
<h1>
|
||||
<i class="pi pi-comments p-mr-2"></i>
|
||||
<div class="flex items-center justify-between p-1">
|
||||
<h1 class="flex items-center">
|
||||
<i class="pi pi-comments mr-2"></i>
|
||||
<span>Chat with WizardAI</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex items-center justify-between p-1">
|
||||
<h2>
|
||||
<span>
|
||||
Contextualized on
|
||||
</span><br/>
|
||||
<span>
|
||||
Project: <strong>{{ userPrefStore.user.selectedProject.fe_name }}</strong>
|
||||
</span><br/>
|
||||
<span v-if="userPrefStore.user.selectedApplication">
|
||||
Application: <strong>{{ userPrefStore.user.selectedApplication.fe_name}}</strong>
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div className="card">
|
||||
<ChatClient />
|
||||
@@ -12,6 +25,15 @@
|
||||
|
||||
<script setup>
|
||||
import ChatClient from '@/components/ChatClient.vue';
|
||||
import { UserPrefStore } from '@/stores/UserPrefStore.js';
|
||||
import { onMounted, computed, watch, ref} from 'vue';
|
||||
|
||||
const userPrefStore = UserPrefStore();
|
||||
|
||||
onMounted(() => {
|
||||
console.log('userPrefStore', userPrefStore);
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user