Skip to content

Commit

Permalink
Merge pull request #306 from Roaryyyy/roary-features/chat-window
Browse files Browse the repository at this point in the history
AII-449
  • Loading branch information
iceljc authored Feb 11, 2025
2 parents 4a1481d + b1abede commit e322aa7
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 148 deletions.
149 changes: 75 additions & 74 deletions src/lib/common/RemoteSearchInput.svelte
Original file line number Diff line number Diff line change
@@ -1,84 +1,85 @@
<script>
import { Input, Dropdown, DropdownMenu, DropdownItem, Spinner, DropdownToggle } from '@sveltestrap/sveltestrap';
import { debounce } from 'lodash';
/** @type {{id: string, name: string} | null} */
export let selectedValue;
export let disabled = false;
export let placeholder = '';
/**
import {
Input,
Dropdown,
DropdownMenu,
DropdownItem,
Spinner,
DropdownToggle
} from '@sveltestrap/sveltestrap';
import { debounce } from 'lodash';
* @type {(arg0: any) => any[] | PromiseLike<any[]>}
*/
export let onSearch;
export let loading = false;
/** @type {string} */
export let value;
export let disabled = false;
export let placeholder = '';
/**
* @type {(query: string) => Promise<({id: string; name: string} | string)[]>}
*/
export let onSearch;
export let loading = false;
/** @type {any[]} */
let searchResults = [];
let isOpen = false;
/** @type {({id: string; name: string} | string)[]} */
let searchResults = [];
let isOpen = false;
// @ts-ignore
const debouncedSearch = debounce(async (query) => {
if (query.length) {
loading = true;
searchResults = await onSearch(query);
loading = false;
isOpen = true;
} else {
searchResults = [];
isOpen = false;
}
}, 500);
// @ts-ignore
const debouncedSearch = debounce(async (query) => {
if (query.length) {
loading = true;
searchResults = await onSearch(query);
loading = false;
} else {
searchResults = [];
isOpen = false;
}
}, 500);
/**
* @param {any} e
*/
async function handleInput(e) {
const query = e.target.value;
selectedValue = { id: query, name: query };
await debouncedSearch(query);
}
/**
* @param {any} e
*/
async function handleInput(e) {
const query = e.target.value;
isOpen = true;
value = query;
await debouncedSearch(query);
}
/**
* @param {{ id: string; name: string; }} result
*/
function selectResult(result) {
selectedValue = result;
}
export function clearSearchResults() {
searchResults = [];
}
/**
* @param { {id: string; name: string} | string } result
*/
function selectResult(result) {
value = typeof result === 'string' ? result : result?.id;
}
export function clearSearchResults() {
searchResults = [];
}
</script>
<div class="position-relative">
<Dropdown class="scrollable-dropdown" isOpen={isOpen && (searchResults.length > 0 || loading)} toggle={() => isOpen = !isOpen}>
<DropdownToggle tag="div">
<Input
type="text"
value={selectedValue?.name}
on:input={handleInput}
{disabled}
{placeholder}
/>
</DropdownToggle>
<DropdownMenu class="w-100">
{#if loading}
<DropdownItem>
<Spinner size="sm" />
</DropdownItem>
{:else}
{#each searchResults as result, index}
<DropdownItem
active={selectedValue?.id === result.id}
on:click={() => selectResult(result)}
title={result.name}
>
{result.name}
</DropdownItem>
{/each}
{/if}
</DropdownMenu>
</Dropdown>
</div>
<Dropdown
class="scrollable-dropdown"
isOpen={isOpen && (searchResults.length > 0 || loading)}
toggle={() => (isOpen = !isOpen)}
>
<DropdownToggle tag="div">
<Input type="text" {value} on:input={handleInput} {disabled} {placeholder} />
</DropdownToggle>
<DropdownMenu class="w-100">
{#if loading}
<li class="text-center"><Spinner size="sm" /></li>
{:else}
{#each searchResults as result, index}
<DropdownItem
active={value === (typeof result === 'string' ? result : result?.id)}
on:click={() => selectResult(result)}
title={typeof result === 'string' ? result : result?.name}
>
{typeof result === 'string' ? result : result?.name}
</DropdownItem>
{/each}
{/if}
</DropdownMenu>
</Dropdown>
</div>
2 changes: 1 addition & 1 deletion src/lib/helpers/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function skipLoader(config) {
new RegExp('http(s*)://(.*?)/role/(.*?)/details', 'g'),
new RegExp('http(s*)://(.*?)/user/(.*?)/details', 'g'),
new RegExp('http(s*)://(.*?)/agent/labels', 'g'),
new RegExp('http(s*)://(.*?)/conversation/state-search', 'g'),
new RegExp('http(s*)://(.*?)/conversation/state-key', 'g'),
];

if (config.method === 'post' && postRegexes.some(regex => regex.test(config.url || ''))) {
Expand Down
1 change: 0 additions & 1 deletion src/lib/services/api-endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export const endpoints = {
conversationTagsUpdateUrl: `${host}/conversation/{conversationId}/update-tags`,
fileUploadUrl: `${host}/agent/{agentId}/conversation/{conversationId}/upload`,
pinConversationUrl: `${host}/agent/{agentId}/conversation/{conversationId}/dashboard`,
conversationStateValueUrl: `${host}/conversation/state-search`,
conversationStateKeyListUrl: `${host}/conversation/state-key`,

// LLM provider
Expand Down
28 changes: 8 additions & 20 deletions src/lib/services/conversation-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -290,36 +290,24 @@ export async function getAddressOptions(text) {
return response.data;
}

/**
* get conversation state key list
* @returns {Promise<{id: string, name: string, description: string}[]>}
*/
export async function getConversationStateKey() {
let url = endpoints.conversationStateKeyListUrl;
const response = await axios.get(url);
return response.data;
}

/** @type {import('axios').CancelTokenSource | null} */
let getConversationStateValueCancelToken = null;
let getConversationStatKeyCancelToken = null;
/**
* get conversation state value
* @param {string} key
* get conversation state key list
* @param {string} query
* @returns {Promise<{id: string, name: string}[]>}
*/
export async function getConversationStateValue(key, query) {
let url = endpoints.conversationStateValueUrl;
if (getConversationStateValueCancelToken) {
getConversationStateValueCancelToken.cancel();
export async function getConversationStateKey(query) {
let url = endpoints.conversationStateKeyListUrl;
if (getConversationStatKeyCancelToken) {
getConversationStatKeyCancelToken.cancel();
}
getConversationStateValueCancelToken = axios.CancelToken.source();
getConversationStatKeyCancelToken = axios.CancelToken.source();
const response = await axios.get(url, {
params: {
conversatinFilterType: key,
searchKey: query
},
cancelToken: getConversationStateValueCancelToken.token
cancelToken: getConversationStatKeyCancelToken.token
});
return response.data;
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
class="form-check-input"
type="checkbox"
bind:checked={agent.is_public}
on:input={handleAgentChange}
on:change={handleAgentChange}
id="is_public"
/>
<label class="form-check-label" for="is_public"> Public </label>
Expand All @@ -151,7 +151,7 @@
class="form-check-input"
type="checkbox"
bind:checked={agent.allow_routing}
on:input={handleAgentChange}
on:change={handleAgentChange}
id="allow_routing"
/>
<label class="form-check-label" for="allow_routing">Allow</label>
Expand Down Expand Up @@ -244,7 +244,7 @@
class="form-check-input"
type="checkbox"
bind:checked={agent.disabled}
on:input={handleAgentChange}
on:change={handleAgentChange}
id="disabled"
/>
<label class="form-check-label" for="disabled">Disabled</label>
Expand Down
70 changes: 21 additions & 49 deletions src/routes/page/conversation/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import LoadingToComplete from '$lib/common/LoadingToComplete.svelte';
import { onMount } from 'svelte';
import { getAgents } from '$lib/services/agent-service';
import { getConversations, deleteConversation, getConversationStateKey, getConversationStateValue } from '$lib/services/conversation-service.js';
import { getConversations, deleteConversation, getConversationStateKey } from '$lib/services/conversation-service.js';
import { utcToLocal } from '$lib/helpers/datetime';
import Swal from 'sweetalert2';
import lodash from "lodash";
Expand Down Expand Up @@ -70,27 +70,17 @@
tags: []
};
/** @type {any[]} */
let stateOptions = [];
/** @type {string} */
let stateKey = "";
/** @type {string | null} */
let selectedStateKey = null;
/** @type {{id: string, name: string} | null} */
let selectedStateValue;
/** @type {boolean} */
let isValueEditable = false;
/** @type {RemoteSearchInput} */
let remoteSearchInput;
let stateValue = null;
onMount(async () => {
isLoading = true;
Promise.all([
loadAgentOptions(),
loadSearchOption(),
loadStates(),
loadConversations()])
.finally(() => {
isLoading = false
Expand Down Expand Up @@ -229,12 +219,12 @@
* @param {any} e
*/
function handleConfirmStateModal(e) {
if (selectedStateKey && selectedStateValue?.id) {
if (stateKey && stateValue) {
searchOption.states = [
{
key: { data: stateOptions.find(x => Number(x.id) === Number(selectedStateKey))?.description, isValid: true },
value: {data: selectedStateValue.id, isValid: true },
active_rounds: {data: 0, isValid: true},
key: { data: stateKey, isValid: true },
value: {data: stateValue, isValid: true },
active_rounds: {data: -1, isValid: true},
}
];
} else {
Expand Down Expand Up @@ -348,28 +338,12 @@
}
}
async function loadStates() {
const response = await getConversationStateKey();
stateOptions = response;
}
/**
* @param { any } e
*/
function handleStateChange(e) {
selectedStateKey = e.target.value;
isValueEditable = !!selectedStateKey;
selectedStateValue = null;
remoteSearchInput?.clearSearchResults();
}
/**
* @param {any} query
*/
async function handleValueSearch(query) {
if (!selectedStateKey) return [];
const response = await getConversationStateValue(selectedStateKey, query);
return response;
async function handleStateSearch(query) {
const response = await getConversationStateKey(query);
return response || [];
}
</script>
Expand All @@ -386,20 +360,18 @@
<div style="width: 100%;">
<div class="state-search-container">
<div>
<select class="form-select" on:change={handleStateChange}>
<option value={null}>Select State</option>
{#each stateOptions as state}
<option value={state.id}>{state.name}</option>
{/each}
</select>
<RemoteSearchInput
bind:value={stateKey}
onSearch={handleStateSearch}
placeholder="Search States"
/>
</div>
<div>
<RemoteSearchInput
bind:selectedValue={selectedStateValue}
disabled={!isValueEditable}
onSearch={handleValueSearch}
placeholder="Enter a value"
bind:this={remoteSearchInput}
<Input
type="text"
bind:value={stateValue}
disabled={!stateKey}
placeholder="Enter a value"
/>
</div>
<div>
Expand Down

0 comments on commit e322aa7

Please sign in to comment.