Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features/add content log #8

Merged
merged 4 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/lib/helpers/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ IRichContent.prototype.text;
* @param {string} text
*/

/**
* Content log
*
* @callback ContentLog
* @param {string} message
*/

// having to export an empty object here is annoying,
// but required for vscode to pass on your types.
export default {};
45 changes: 45 additions & 0 deletions src/lib/scss/custom/pages/_chat.scss
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,48 @@
min-width: auto;
}
}

.user-chat {
flex: 1;
}

.chat-with-log {
flex: 0.7;
}

.chat-log {
flex: 0.3;

.padding-side {
padding-left: 10px;
padding-right: 20px;
}

.log-background {
background-color: black;

.log-close-btn {
margin-top: 1.5rem;
margin-bottom: 10px;
position: sticky;
display: flex;
justify-content: flex-end;
}

.log-list {
height: 90vh;
.log-element {
margin-top: 15px;
margin-bottom: 15px;

.log-content {
font-size: 15px;
color: white;
}
}
}
}
}



9 changes: 8 additions & 1 deletion src/lib/services/signalr-service.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HubConnection, HubConnectionBuilder, LogLevel, HubConnectionState } from '@microsoft/signalr';
import { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
import { endpoints } from '$lib/services/api-endpoints.js';
import { getUserStore } from '$lib/helpers/store.js';

Expand All @@ -21,6 +21,9 @@ export const signalr = {
/** @type {import('$types').OnMessageReceived} */
onMessageReceivedFromAssistant: () => {},

/** @type {import('$types').ContentLog} */
onContentLogGenerated: () => {},

// start the connection
/** @param {string} conversationId */
async start(conversationId) {
Expand Down Expand Up @@ -74,6 +77,10 @@ export const signalr = {
this.onMessageReceivedFromAssistant(message);
}
});

connection.on('onContentLogGenerated', (log) => {
this.onContentLogGenerated(log);
});
},

// stop the connection
Expand Down
52 changes: 40 additions & 12 deletions src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,21 @@
DropdownToggle,
DropdownMenu,
DropdownItem,
Input,
Button
} from '@sveltestrap/sveltestrap';

import 'overlayscrollbars/overlayscrollbars.css';
import { OverlayScrollbars } from 'overlayscrollbars';
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { onMount, tick } from 'svelte';
import Link from 'svelte-link';
import { signalr } from '$lib/services/signalr-service.js';
import { webSpeech } from '$lib/services/web-speech.js';
import { sendMessageToHub, GetDialogs } from '$lib/services/conversation-service.js';
import { getFullLog } from '$lib/services/logging-service';
import { format } from '$lib/helpers/datetime';
import RcText from './rc-text.svelte';
import RcQuickReply from './rc-quick-reply.svelte';
import { PUBLIC_LIVECHAT_ENTRY_ICON } from '$env/static/public';
import ContentLog from './content-log.svelte';

const options = {
scrollbars: {
Expand Down Expand Up @@ -50,12 +48,19 @@
/** @type {import('$types').ChatResponseModel[]} */
let dialogs = [];

/** @type {string[]} */
let contentLogs = [];

/** @type {boolean} */
let isLoadLog = false;

onMount(async () => {
dialogs = await GetDialogs(params.conversationId);

signalr.onMessageReceivedFromClient = onMessageReceivedFromClient;
signalr.onMessageReceivedFromCsr = onMessageReceivedFromCsr;
signalr.onMessageReceivedFromAssistant = onMessageReceivedFromAssistant;
signalr.onContentLogGenerated = onContentLogGenerated;
await signalr.start(params.conversationId);

const scrollElements = document.querySelectorAll('.scrollbar');
Expand Down Expand Up @@ -91,10 +96,16 @@

dialogs.push(message);
refresh();
}
}

async function viewFullLogHandler() {
await getFullLog();
/** @param {string} log */
function onContentLogGenerated(log) {
contentLogs.push(log);
contentLogs = contentLogs;
}

function viewFullLogHandler() {
isLoadLog = true;
}

async function sendTextMessage() {
Expand All @@ -111,23 +122,34 @@
webSpeech.start();
}

function refresh() {
async function refresh() {
// trigger UI render
dialogs = dialogs;
await tick();

setTimeout(() => {
const { viewport } = scrollbar.elements();
viewport.scrollTo({ top: viewport.scrollHeight, behavior: 'smooth' }); // set scroll offset
}, 200);
}

/** @param {any} e */
async function onSendMessage(e) {
if (e.key !== 'Enter') return;
await sendMessageToHub(params.agentId, params.conversationId, text);
}

function close() {
window.parent.postMessage({ action: "close" }, "*");
}

function closeLog() {
isLoadLog = false;
}
</script>

<div class="d-lg-flex">
<div class="w-100 user-chat">
<div class="user-chat" class:chat-with-log={isLoadLog}>
<div class="card mb-0">
<div class="p-4 border-bottom" style="height: 12vh">
<div class="row">
Expand All @@ -140,6 +162,7 @@

<div class="col-md-8 col-5">
<ul class="list-inline user-chat-nav text-end mb-0">
{#if !isLoadLog}
<li class="list-inline-item">
<Dropdown>
<DropdownToggle tag="button" class="nav-btn dropdown-toggle" color="">
Expand All @@ -150,6 +173,7 @@
</DropdownMenu>
</Dropdown>
</li>
{/if}
<li class="list-inline-item d-sm-inline-block">
<button type="submit" class="btn btn-primary btn-rounded chat-send waves-effect waves-light"
on:click={close}
Expand Down Expand Up @@ -180,7 +204,7 @@
<i class="bx bx-dots-vertical-rounded" />
</DropdownToggle>
<DropdownMenu class="dropdown-menu-end">
<DropdownItem href="#">Eidt</DropdownItem>
<DropdownItem href="#">Edit</DropdownItem>
<DropdownItem href="#">Copy</DropdownItem>
<DropdownItem href="#">Delete</DropdownItem>
</DropdownMenu>
Expand All @@ -202,7 +226,7 @@
<i class="bx bx-time-five align-middle me-1" />
{format(message.created_at, 'short-time')}
</p>
</div>
</div>
{:else}
<div class="ctext-wrap float-start">
<div class="flex-shrink-0 align-self-center">
Expand Down Expand Up @@ -239,7 +263,7 @@
</div>
<div class="col">
<div class="position-relative">
<input type="text" class="form-control chat-input" bind:value={text} placeholder="Enter Message..." />
<input type="text" class="form-control chat-input" bind:value={text} on:keydown={e => { onSendMessage(e); }} placeholder="Enter Message..." />
<div class="chat-input-links" id="tooltip-container">
<ul class="list-inline mb-0">
<li class="list-inline-item">
Expand All @@ -262,4 +286,8 @@
</div>
</div>
</div>

{#if isLoadLog}
<ContentLog logs={contentLogs} closeLog={closeLog} />
{/if}
</div>
78 changes: 78 additions & 0 deletions src/routes/chat/[agentId]/[conversationId]/content-log.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script>
import 'overlayscrollbars/overlayscrollbars.css';
import { OverlayScrollbars } from 'overlayscrollbars';
import { afterUpdate, onMount, tick } from 'svelte';
import { replaceNewLine } from '$lib/helpers/http';

/** @type {any[]} */
export let logs = [];

/** @type {() => void} */
export let closeLog;

// @ts-ignore
let scrollbar;

const options = {
scrollbars: {
visibility: 'auto',
autoHide: 'move',
autoHideDelay: 100,
dragScroll: true,
clickScroll: false,
theme: 'os-theme-dark',
pointers: ['mouse', 'touch', 'pen']
}
};

onMount(async () => {
const scrollElements = document.querySelectorAll('.log-scrollbar');
scrollElements.forEach((item) => {
scrollbar = OverlayScrollbars(item, options);
});

refreshLog();
});

afterUpdate(() => {
refreshLog();
});


async function refreshLog() {
// trigger UI render
logs = logs;
await tick();

setTimeout(() => {
const { viewport } = scrollbar.elements();
viewport.scrollTo({ top: viewport.scrollHeight, behavior: 'smooth' }); // set scroll offset
}, 200);
}

</script>

<div class="chat-log">
<div class="card mb-0 log-background" style="height: 100%;">
<div class="log-close-btn padding-side ">
<button
type="button"
class="btn btn-danger btn-rounded chat-send waves-effect waves-light"
on:click={() => closeLog()}
>
<span class="d-none d-sm-inline-block me-2" >Close</span><i class="mdi mdi-window-close"></i>
</button>
</div>
<div class="log-scrollbar log-list padding-side">
<ul>
{#each logs as log}
<div class="log-element">
<div class="log-content">
{@html replaceNewLine(log)}
</div>
</div>
{/each}
</ul>
</div>
</div>
</div>