This commit is contained in:
Saifeddine ALOUI 2024-07-19 00:38:03 +02:00
parent a631f73da1
commit 70291fcd8e
13 changed files with 4181 additions and 4152 deletions

@ -1 +1 @@
Subproject commit 1437b2c40d28e40b2e9965fac399e30f46f1e1a2
Subproject commit 205ec5b01536b3c1647f15fbd3220d55b809e2bb

File diff suppressed because one or more lines are too long

8
web/dist/assets/index-16450776.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3906
web/dist/assets/index-cafbd2e3.js vendored Normal file

File diff suppressed because one or more lines are too long

6
web/dist/index.html vendored
View File

@ -3,11 +3,11 @@
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI</title>
<script type="module" crossorigin src="/assets/index-156a33f2.js"></script>
<link rel="stylesheet" href="/assets/index-4cfc40d0.css">
<script type="module" crossorigin src="/assets/index-cafbd2e3.js"></script>
<link rel="stylesheet" href="/assets/index-16450776.css">
</head>
<body>
<div id="app"></div>

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI</title>
</head>

42
web/package-lock.json generated
View File

@ -21,7 +21,9 @@
"markdown-it-emoji": "^2.0.2",
"markdown-it-implicit-figures": "^0.11.0",
"markdown-it-math": "^4.1.1",
"markdown-it-mathjax": "^2.0.0",
"markdown-it-multimd-table": "^4.2.3",
"mathjax": "^3.2.2",
"mermaid": "^9.0.0",
"papaparse": "^5.4.1",
"prismjs": "^1.29.0",
@ -1123,11 +1125,11 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@ -1866,14 +1868,14 @@
"integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ=="
},
"node_modules/engine.io-client": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz",
"integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==",
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.11.0",
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.0.0"
}
},
@ -2234,9 +2236,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -2815,11 +2817,21 @@
"ascii2mathml": "^0.6.2"
}
},
"node_modules/markdown-it-mathjax": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-mathjax/-/markdown-it-mathjax-2.0.0.tgz",
"integrity": "sha512-Fafv7TnMENccWYTNjMZzV4BzONPxpK9Mknr1iMEK6m7PI5a5UTCOFctPzx7Nhv81fFzYEY8WHDkSu9n43fTV9g=="
},
"node_modules/markdown-it-multimd-table": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.2.3.tgz",
"integrity": "sha512-KepCr2OMJqm7IT6sOIbuqHGe+NERhgy66XMrc5lo6dHW7oaPzMDtYwR1EGwK16/blb6mCSg4jqityOe0o/H7HA=="
},
"node_modules/mathjax": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/mathjax/-/mathjax-3.2.2.tgz",
"integrity": "sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw=="
},
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
@ -3986,15 +3998,15 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {

View File

@ -23,7 +23,9 @@
"markdown-it-emoji": "^2.0.2",
"markdown-it-implicit-figures": "^0.11.0",
"markdown-it-math": "^4.1.1",
"markdown-it-mathjax": "^2.0.0",
"markdown-it-multimd-table": "^4.2.3",
"mathjax": "^3.2.2",
"mermaid": "^9.0.0",
"papaparse": "^5.4.1",
"prismjs": "^1.29.0",

View File

@ -1,35 +1,5 @@
<template>
<div class="bg-bg-light-tone-panel dark:bg-bg-dark-tone-panel p-2 rounded-lg shadow-sm">
<div class="flex flex-row bg-bg-light-tone-panel dark:bg-bg-dark-tone-panel p-2 rounded-lg shadow-sm">
<span class="text-2xl">{{ language }}</span>
<button @click="copyCode" title="copy"
:class="isCopied ? 'bg-green-500' : 'bg-bg-dark-tone-panel dark:bg-bg-dark-tone'"
class="px-2 py-1 ml-2 text-left p-2 text-sm font-medium rounded-lg hover:bg-primary dark:hover:bg-primary text-white text-xs transition-colors duration-200">
<i data-feather="copy"></i>
</button>
<button v-if="['function', 'python', 'sh', 'shell', 'bash', 'cmd', 'powershell', 'latex', 'mermaid', 'graphviz', 'dot', 'javascript', 'html', 'html5', 'svg'].includes(language)" ref="btn_code_exec" @click="executeCode" title="execute"
class="px-2 py-1 ml-2 text-left p-2 text-sm font-medium bg-bg-dark-tone-panel dark:bg-bg-dark-tone rounded-lg hover:bg-primary dark:hover:bg-primary text-white text-xs transition-colors duration-200"
:class="isExecuting?'bg-green-500':''">
<i data-feather="play-circle"></i>
</button>
<button v-if="['airplay', 'mermaid', 'graphviz', 'dot', 'javascript', 'html', 'html5', 'svg', 'css'].includes(language)" ref="btn_code_exec_in_new_tab" @click="executeCode_in_new_tab" title="execute"
class="px-2 py-1 ml-2 text-left p-2 text-sm font-medium bg-bg-dark-tone-panel dark:bg-bg-dark-tone rounded-lg hover:bg-primary dark:hover:bg-primary text-white text-xs transition-colors duration-200"
:class="isExecuting?'bg-green-500':''">
<i data-feather="airplay"></i>
</button>
<button v-if="['python', 'latex', 'html'].includes(language)" @click="openFolder" title="open code project folder"
class="px-2 py-1 ml-2 text-left p-2 text-sm font-medium bg-bg-dark-tone-panel dark:bg-bg-dark-tone rounded-lg hover:bg-primary dark:hover:bg-primary text-white text-xs transition-colors duration-200">
<i data-feather="folder"></i>
</button>
<button v-if="['python', 'latex', 'html'].includes(language)" @click="openFolderVsCode" title="open code project folder in vscode"
class="px-2 py-1 ml-2 text-left p-2 text-sm font-medium bg-bg-dark-tone-panel dark:bg-bg-dark-tone rounded-lg hover:bg-primary dark:hover:bg-primary text-white text-xs transition-colors duration-200">
<img src="@/assets/vscode_black.svg" width="25" height="25">
</button>
<button v-if="['python', 'latex', 'html'].includes(language)" @click="openVsCode" title="open code in vscode"
class="px-2 py-1 ml-2 text-left p-2 text-sm font-medium bg-bg-dark-tone-panel dark:bg-bg-dark-tone rounded-lg hover:bg-primary dark:hover:bg-primary text-white text-xs transition-colors duration-200">
<img src="@/assets/vscode.svg" width="25" height="25">
</button>
</div>
<pre class="hljs p-1 rounded-md break-all grid grid-cols-1">
<div class="code-container">
<div
@ -41,6 +11,41 @@
</div>
</pre>
<div class="flex flex-row bg-bg-light-tone-panel dark:bg-bg-dark-tone-panel p-2 rounded-lg shadow-sm">
<span class="text-2xl mr-2">{{ language }}</span>
<button @click="copyCode"
:title="isCopied ? 'Copied!' : 'Copy code'"
:class="isCopied ? 'bg-green-500' : ''"
class="px-2 py-1 mr-2 mb-2 text-left text-sm font-medium rounded-lg hover:bg-primary dark:hover:bg-primary text-white transition-colors duration-200"
>
<i data-feather="copy"></i>
</button>
<button v-if="['function', 'python', 'sh', 'shell', 'bash', 'cmd', 'powershell', 'latex', 'mermaid', 'graphviz', 'dot', 'javascript', 'html', 'html5', 'svg'].includes(language)" ref="btn_code_exec" @click="executeCode" title="execute"
class="px-2 py-1 mr-2 mb-2 text-left text-sm font-medium rounded-lg hover:bg-primary dark:hover:bg-primary text-white transition-colors duration-200"
:class="isExecuting?'bg-green-500':''">
<i data-feather="play-circle"></i>
</button>
<button v-if="['airplay', 'mermaid', 'graphviz', 'dot', 'javascript', 'html', 'html5', 'svg', 'css'].includes(language)" ref="btn_code_exec_in_new_tab" @click="executeCode_in_new_tab" title="execute"
class="px-2 py-1 mr-2 mb-2 text-left text-sm font-medium rounded-lg hover:bg-primary dark:hover:bg-primary text-white transition-colors duration-200"
:class="isExecuting?'bg-green-500':''">
<i data-feather="airplay"></i>
</button>
<button v-if="['python', 'latex', 'html'].includes(language)" @click="openFolder" title="open code project folder"
class="px-2 py-1 mr-2 mb-2 text-left text-sm font-medium rounded-lg hover:bg-primary dark:hover:bg-primary text-white transition-colors duration-200"
>
<i data-feather="folder"></i>
</button>
<button v-if="['python', 'latex', 'html'].includes(language)" @click="openFolderVsCode" title="open code project folder in vscode"
class="px-2 py-1 mr-2 mb-2 text-left text-sm font-medium rounded-lg hover:bg-primary dark:hover:bg-primary text-white transition-colors duration-200"
>
<img src="@/assets/vscode_black.svg" width="25" height="25">
</button>
<button v-if="['python', 'latex', 'html'].includes(language)" @click="openVsCode" title="open code in vscode"
class="px-2 py-1 mr-2 mb-2 text-left text-sm font-medium rounded-lg hover:bg-primary dark:hover:bg-primary text-white transition-colors duration-200"
>
<img src="@/assets/vscode.svg" width="25" height="25">
</button>
</div>
<span v-if="executionOutput" class="text-2xl">Execution output</span>
<pre class="hljs mt-0 p-1 rounded-md break-all grid grid-cols-1" v-if="executionOutput">
<div class="container h-[200px] overflow-x-auto break-all scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary">

View File

@ -1,5 +1,5 @@
<template>
<div class="break-all container w-full" >
<div class="break-all container w-full">
<div ref="mdRender" class="markdown-content">
<div v-for="(item, index) in markdownItems" :key="index">
<code-block
@ -10,6 +10,7 @@
:discussion_id="discussion_id"
:message_id="message_id"
:client_id="client_id"
@update-code="updateCode(index, $event)"
></code-block>
<div v-else v-html="item.html"></div>
</div>
@ -18,12 +19,11 @@
</template>
<script>
import {nextTick, ref, onMounted, watch } from 'vue';
import { nextTick, ref, onMounted, watch } from 'vue';
import feather from 'feather-icons';
import MarkdownIt from 'markdown-it';
import emoji from 'markdown-it-emoji';
import anchor from 'markdown-it-anchor';
import MarkdownItMath from 'markdown-it-math';
import MarkdownItMultimdTable from 'markdown-it-multimd-table';
import implicitFigures from 'markdown-it-implicit-figures';
import 'highlight.js/styles/tomorrow-night-blue.css';
@ -31,8 +31,7 @@ import 'highlight.js/styles/tokyo-night-dark.css';
import attrs from 'markdown-it-attrs';
import CodeBlock from './CodeBlock.vue';
import hljs from 'highlight.js';
import DOMPurify from 'dompurify';
import mathjax from 'markdown-it-mathjax';
function escapeHtml(unsafe) {
return unsafe
@ -42,6 +41,7 @@ function escapeHtml(unsafe) {
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
export default {
name: 'MarkdownRenderer',
props: {
@ -49,11 +49,11 @@ export default {
type: String,
required: false,
default: "http://localhost:9600",
},
},
client_id: {
type: String,
required: true,
},
},
markdownText: {
type: String,
required: true,
@ -88,13 +88,7 @@ export default {
figcaption: true,
})
.use(attrs)
.use(MarkdownItMath, {
inlineOpen: '$',
inlineClose: '$',
blockOpen: '$$',
blockClose: '$$',
})
.use(MarkdownItMultimdTable,{
.use(MarkdownItMultimdTable, {
enableRowspan: true,
enableColspan: true,
enableGridTables: true,
@ -106,44 +100,43 @@ export default {
multilineCellEndMarker: '<|',
multilineCellPadding: ' ',
multilineCellJoiner: '\n',
});
})
.use(mathjax({
inlineMath: [['$', '$'], ['\\(', '\\)']],
blockMath: [['$$', '$$'], ['\\[', '\\]']]
}));
const markdownItems = ref([]);
const updateMarkdown = () => {
if (props.markdownText) {
let tokens = md.parse(props.markdownText, {});
let cumulated = [];
markdownItems.value = []
markdownItems.value = [];
for (let i = 0; i < tokens.length; i++) {
if (tokens[i].type !== 'fence') {
cumulated.push(tokens[i]);
}
else{
if(cumulated.length>0){
markdownItems.value.push(
{
} else {
if (cumulated.length > 0) {
markdownItems.value.push({
type: 'html',
html: md.renderer.render(cumulated, md.options, {}),
});
cumulated = []
cumulated = [];
}
markdownItems.value.push(
{
type: 'code',
language: escapeHtml(tokens[i].info),
code: tokens[i].content,
}
)
markdownItems.value.push({
type: 'code',
language: escapeHtml(tokens[i].info),
code: tokens[i].content,
});
}
}
if(cumulated.length>0){
markdownItems.value.push(
{
if (cumulated.length > 0) {
markdownItems.value.push({
type: 'html',
html: md.renderer.render(cumulated, md.options, {}),
});
cumulated = []
cumulated = [];
}
} else {
markdownItems.value = [];
}
@ -151,14 +144,25 @@ export default {
feather.replace();
});
};
watch(() => props.markdownText, updateMarkdown);
onMounted(updateMarkdown);
return { markdownItems };
},
const updateCode = (index, newCode) => {
markdownItems.value[index].code = newCode;
};
watch(() => props.markdownText, updateMarkdown);
onMounted(() => {
updateMarkdown();
nextTick(() => {
if (window.MathJax) {
window.MathJax.typesetPromise();
}
});
});
return { markdownItems, updateCode };
},
};
</script>
<style>
/* Your existing styles */
</style>

View File

@ -31,141 +31,7 @@
<div class="flex-grow ">
</div>
<!-- MESSAGE CONTROLS -->
<div class="flex-row justify-end mx-2">
<div class="invisible group-hover:visible flex flex-row ">
<!-- MESSAGE CONTROLS -->
<!-- EDIT CONFIRMATION -->
<div v-if="editMsgMode" class="flex items-center duration-75">
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2"
title="Cancel edit" type="button" @click.stop="editMsgMode = false">
<i data-feather="x"></i>
</button>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2"
title="Update message" type="button" @click.stop="updateMessage">
<i data-feather="check"></i>
</button>
</div>
<div v-if="!editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Edit message" @click.stop="editMsgMode = true">
<i data-feather="edit"></i>
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer hover:border-2"
title="Add generic block" @click.stop="addBlock('')">
<img :src="code_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer hover:border-2"
title="Add python block" @click.stop="addBlock('python')">
<img :src="python_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add javascript block" @click.stop="addBlock('javascript')">
<img :src="javascript_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add json block" @click.stop="addBlock('json')">
<img :src="json_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add c++ block" @click.stop="addBlock('c++')">
<img :src="cpp_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add html block" @click.stop="addBlock('html')">
<img :src="html5_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add LaTex block" @click.stop="addBlock('latex')">
<img :src="LaTeX_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add bash block" @click.stop="addBlock('bash')">
<img :src="bash_block" width="25" height="25">
</div>
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Copy message to clipboard" @click.stop="copyContentToClipboard()">
<i data-feather="copy"></i>
</div>
<div v-if="!editMsgMode && message.sender!=this.$store.state.mountedPers.name" class="text-lg text-red-500 hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message with full context"
@click.stop="resendMessage('full_context')"
:class="{ 'text-5xl': editMsgMode }">
<i data-feather="send"></i>
</div>
<div v-if="!editMsgMode && message.sender!=this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message without the full context"
@click.stop="resendMessage('full_context_with_internet')"
:class="{ 'text-5xl': editMsgMode }">
<img :src="sendGlobe" width="25" height="25">
</div>
<div v-if="!editMsgMode && message.sender!=this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message without the full context"
@click.stop="resendMessage('simple_question')"
:class="{ 'text-5xl': editMsgMode }">
<i data-feather="send"></i>
</div>
<div v-if="!editMsgMode && message.sender==this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message"
@click.stop="continueMessage()"
>
<i data-feather="fast-forward"></i>
</div>
<!-- DELETE CONFIRMATION -->
<div v-if="deleteMsgMode" class="flex items-center duration-75">
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="Cancel removal" type="button" @click.stop="deleteMsgMode = false">
<i data-feather="x"></i>
</button>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Confirm removal" type="button" @click.stop="deleteMsg()">
<i data-feather="check"></i>
</button>
</div>
<div v-if="!editMsgMode && !deleteMsgMode" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="Remove message" @click="deleteMsgMode = true">
<i data-feather="trash"></i>
</div>
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer" title="Upvote"
@click.stop="rankUp()">
<i data-feather="thumbs-up"></i>
</div>
<div class="flex flex-row items-center">
<div class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer" title="Downvote"
@click.stop="rankDown()">
<i data-feather="thumbs-down"></i>
</div>
<div v-if="message.rank != 0"
class="rounded-full px-2 text-sm flex items-center justify-center font-bold cursor-pointer"
:class="message.rank > 0 ? 'bg-secondary' : 'bg-red-600'" title="Rank">{{
message.rank }}
</div>
</div>
<div class="flex flex-row items-center">
<div class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="speak"
v-if ="this.$store.state.config.active_tts_service!='None'"
@click.stop="speak()"
:class="{ 'text-red-500': isTalking }">
<i data-feather="volume-2"></i>
</div>
</div>
<div v-if="this.$store.state.config.xtts_enable && !this.$store.state.config.xtts_use_streaming_mode" class="flex flex-row items-center">
<div v-if="!isSynthesizingVoice" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="generate_audio"
@click.stop="read()"
>
<i data-feather="voicemail"></i>
</div>
<img v-else :src="loading_svg">
</div>
</div>
</div>
</div>
<div class="overflow-x-auto w-full overflow-y-auto scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary">
@ -202,7 +68,7 @@
</MarkdownRenderer>
<div >
<textarea v-if="message.open" ref="mdTextarea" @keydown.tab.prevent="insertTab"
class="block min-h-[900px] p-2.5 w-full text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 overflow-y-scroll flex flex-col shadow-lg p-10 pt-0 overflow-y-scroll dark:bg-bg-dark scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary"
class="block min-h-[500px] p-2.5 w-full text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 overflow-y-scroll flex flex-col shadow-lg p-10 pt-0 overflow-y-scroll dark:bg-bg-dark scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary"
:rows="4"
placeholder="Enter message here..."
v-model="message.content">
@ -223,6 +89,141 @@
</audio>
</div>
<!-- MESSAGE CONTROLS -->
<div class="flex-row justify-end mx-2">
<div class="invisible group-hover:visible flex flex-row ">
<!-- MESSAGE CONTROLS -->
<!-- EDIT CONFIRMATION -->
<div v-if="editMsgMode" class="flex items-center duration-75">
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2"
title="Cancel edit" type="button" @click.stop="editMsgMode = false">
<i data-feather="x"></i>
</button>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2"
title="Update message" type="button" @click.stop="updateMessage">
<i data-feather="check"></i>
</button>
</div>
<div v-if="!editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Edit message" @click.stop="editMsgMode = true">
<i data-feather="edit"></i>
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer hover:border-2"
title="Add generic block" @click.stop="addBlock('')">
<img :src="code_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer hover:border-2"
title="Add python block" @click.stop="addBlock('python')">
<img :src="python_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add javascript block" @click.stop="addBlock('javascript')">
<img :src="javascript_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add json block" @click.stop="addBlock('json')">
<img :src="json_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add c++ block" @click.stop="addBlock('c++')">
<img :src="cpp_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add html block" @click.stop="addBlock('html')">
<img :src="html5_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add LaTex block" @click.stop="addBlock('latex')">
<img :src="LaTeX_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add bash block" @click.stop="addBlock('bash')">
<img :src="bash_block" width="25" height="25">
</div>
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Copy message to clipboard" @click.stop="copyContentToClipboard()">
<i data-feather="copy"></i>
</div>
<div v-if="!editMsgMode && message.sender!=this.$store.state.mountedPers.name" class="text-lg text-red-500 hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message with full context"
@click.stop="resendMessage('full_context')"
:class="{ 'text-5xl': editMsgMode }">
<i data-feather="send"></i>
</div>
<div v-if="!editMsgMode && message.sender!=this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message without the full context"
@click.stop="resendMessage('full_context_with_internet')"
:class="{ 'text-5xl': editMsgMode }">
<img :src="sendGlobe" width="25" height="25">
</div>
<div v-if="!editMsgMode && message.sender!=this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message without the full context"
@click.stop="resendMessage('simple_question')"
:class="{ 'text-5xl': editMsgMode }">
<i data-feather="send"></i>
</div>
<div v-if="!editMsgMode && message.sender==this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Resend message"
@click.stop="continueMessage()"
>
<i data-feather="fast-forward"></i>
</div>
<!-- DELETE CONFIRMATION -->
<div v-if="deleteMsgMode" class="flex items-center duration-75">
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="Cancel removal" type="button" @click.stop="deleteMsgMode = false">
<i data-feather="x"></i>
</button>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Confirm removal" type="button" @click.stop="deleteMsg()">
<i data-feather="check"></i>
</button>
</div>
<div v-if="!editMsgMode && !deleteMsgMode" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="Remove message" @click="deleteMsgMode = true">
<i data-feather="trash"></i>
</div>
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer" title="Upvote"
@click.stop="rankUp()">
<i data-feather="thumbs-up"></i>
</div>
<div class="flex flex-row items-center">
<div class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer" title="Downvote"
@click.stop="rankDown()">
<i data-feather="thumbs-down"></i>
</div>
<div v-if="message.rank != 0"
class="rounded-full px-2 text-sm flex items-center justify-center font-bold cursor-pointer"
:class="message.rank > 0 ? 'bg-secondary' : 'bg-red-600'" title="Rank">{{
message.rank }}
</div>
</div>
<div class="flex flex-row items-center">
<div class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="speak"
v-if ="this.$store.state.config.active_tts_service!='None'"
@click.stop="speak()"
:class="{ 'text-red-500': isTalking }">
<i data-feather="volume-2"></i>
</div>
</div>
<div v-if="this.$store.state.config.xtts_enable && !this.$store.state.config.xtts_use_streaming_mode" class="flex flex-row items-center">
<div v-if="!isSynthesizingVoice" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="generate_audio"
@click.stop="read()"
>
<i data-feather="voicemail"></i>
</div>
<img v-else :src="loading_svg">
</div>
</div>
</div>
<!-- FOOTER -->
<div class="text-sm text-gray-400 mt-2">
<div class="flex flex-row items-center gap-2">
@ -525,15 +526,25 @@ export default {
});
}
},
speak() {
async speak() {
if(this.$store.state.config.active_tts_service!="browser" && this.$store.state.config.active_tts_service!="None"){
this.isSpeaking = true;
axios.post("./text2Audio",{text:this.message.content}).then(response => {
this.isSpeaking = false;
}).catch(ex=>{
this.$store.state.toast.showToast(`Error: ${ex}`,4,false)
this.isSpeaking = false;
});
if(!this.isSpeaking){
this.isSpeaking = true;
axios.post("./text2Audio",{client_id:this.$store.state.client_id, text:this.message.content}).then(response => {
}).catch(ex=>{
this.$store.state.toast.showToast(`Error: ${ex}`,4,false)
this.isSpeaking = false;
});
}
else{
this.isSpeaking = true;
axios.post("./stop",{text:this.message.content}).then(response => {
this.isSpeaking = false;
}).catch(ex=>{
this.$store.state.toast.showToast(`Error: ${ex}`,4,false)
this.isSpeaking = false;
});
}
}
else{
if (this.msg) {

@ -1 +1 @@
Subproject commit babf95044dc34e46d74843ae17bc87e06f5cecd8
Subproject commit 518371c281c619bdae757f310194e7693f0083a1