Skip to content
Snippets Groups Projects
Commit 77a3a05b authored by MRdevTagg's avatar MRdevTagg Committed by Christos
Browse files

feat(*): added AskKb config, updated ai tool ui and response handling

parent 768f8559
No related branches found
No related tags found
1 merge request!576feat(*): added AskKb config, updated ai tool ui and response handling
......@@ -41,10 +41,6 @@ import invisibles, {
import CharactersList from './CharactersList';
// const updateTitle = title => {
// console.log(title);
// };
async function DummyPromise(userInput) {
return new Promise((resolve, reject) => {
setTimeout(() => {
......@@ -52,9 +48,15 @@ async function DummyPromise(userInput) {
if (userInput === 'reject') {
reject('Your request could not be processed for now');
} else {
resolve(
'He made significant contributions to theoretical physics, including achievements in quantum mechanics',
);
// JSON response test
const json = JSON.stringify({
content:
'From the documents you have this is the most accurate answer',
citations: ['citation 1', 'citation 2', 'citation 3'],
links: ['https://coko.foundation/', 'https://waxjs.net/about/'],
});
resolve(json);
}
}, 3150);
});
......@@ -313,6 +315,9 @@ export default {
AskAiContentService: {
AskAiContentTransformation: DummyPromise,
AiOn: true,
AskKb: false,
GenerateImages: false,
CustomPromptsOn: true,
FreeTextPromptsOn: true,
CustomPrompts: [],
},
......
......@@ -737,4 +737,178 @@ export default {
<path d="m83.44,72.27l-4.73-2.06c-1.14-.5-2.05-1.41-2.55-2.55l-2.06-4.73c-.16-.37-.68-.37-.84,0l-2.06,4.73c-.5,1.14-1.41,2.05-2.55,2.55l-4.73,2.07c-.37.16-.37.68,0,.84l4.82,2.13c1.14.5,2.05,1.42,2.54,2.57l2,4.64c.16.37.68.37.84,0l2.06-4.72c.5-1.14,1.41-2.05,2.55-2.55l4.73-2.06c.37-.16.37-.68,0-.84Z" />
</Svg>
),
settings: ({ className }) => (
<svg
className={className}
height="28px"
preserveAspectRatio="none"
version="1.1"
viewBox="0 0 28 28"
width="28px"
x="0px"
xmlns="http://www.w3.org/2000/svg"
y="0px"
>
<defs>
<g id="icon-Layer0_0_FILL">
<path
d="
M 21.3 8.8
Q 21.75 8.35 21.25 7.85
L 20.2 6.8
Q 19.7 6.3 19.25 6.8
L 18.05 7.95
Q 16.85 7.15 15.4 6.9
L 15.4 5.15
Q 15.4 4.5 14.75 4.5
L 13.25 4.5
Q 12.55 4.5 12.55 5.15
L 12.55 6.9
Q 11.1 7.15 9.9 8
L 8.65 6.75
Q 8.15 6.3 7.7 6.75
L 6.65 7.8
Q 6.15 8.3 6.6 8.8
L 7.9 10.1
Q 7.1 11.25 6.85 12.65
L 5.05 12.65
Q 4.35 12.65 4.35 13.35
L 4.35 14.8
Q 4.35 15.5 5.05 15.5
L 6.85 15.5
Q 7.1 16.95 7.9 18.1
L 6.65 19.35
Q 6.2 19.85 6.65 20.3
L 7.7 21.35
Q 8.25 21.9 8.7 21.4
L 10 20.15
Q 11.15 20.95 12.55 21.2
L 12.55 22.95
Q 12.55 23.6 13.25 23.6
L 14.75 23.6
Q 15.4 23.6 15.4 22.95
L 15.4 21.2
Q 16.8 20.95 18 20.2
L 19.2 21.35
Q 19.65 21.85 20.15 21.35
L 21.2 20.3
Q 21.7 19.8 21.2 19.35
L 20.05 18.15
Q 20.9 16.95 21.15 15.5
L 22.8 15.5
Q 23.5 15.5 23.5 14.8
L 23.5 13.35
Q 23.5 12.65 22.8 12.65
L 21.2 12.65
Q 20.9 11.25 20.1 10.05
L 21.3 8.8
M 10.45 10.45
Q 11.95 9 14 9 16.05 9 17.5 10.45 19 11.95 19 14 19 16.05 17.5 17.5 16.05 19 14 19 11.95 19 10.45 17.5 9 16.05 9 14 9 11.95 10.45 10.45 Z"
fill="var(--color-blue)"
stroke="var(--color-fill-stroke)"
/>
</g>
<path
d="
M 13.144646453857423 2.0080963134765626
L 15.023285675048829 2.0080963134765626
Q 15.83736267089844 2.0080963134765626 15.83736267089844 2.8253768920898445
L 15.83736267089844 5.025747680664063
Q 17.6533805847168 5.340086364746094 19.156291961669922 6.345970153808594
L 20.659203338623048 4.900012207031249
Q 21.22279510498047 4.271334838867187 21.84900817871094 4.900012207031249
L 23.164055633544923 6.22023468017578
Q 23.79026870727539 6.848912048339843 23.22667694091797 7.414721679687501
L 21.723765563964847 8.986415100097657
Q 22.725706481933592 10.495240783691406 23.101434326171876 12.255537414550782
L 25.105316162109375 12.255537414550782
Q 25.982014465332032 12.255537414550782 25.982014465332032 13.135685729980468
L 25.982014465332032 14.958850097656251
Q 25.982014465332032 15.838998413085937 25.105316162109375 15.838998413085937
L 23.038813018798827 15.838998413085937
Q 22.725706481933592 17.66216278076172 21.661144256591797 19.170988464355467
L 23.101434326171876 20.679814147949223
Q 23.727647399902345 21.245623779296878 23.101434326171876 21.87430114746094
L 21.78638687133789 23.194523620605473
Q 21.16017379760742 23.823200988769536 20.59658203125 23.194523620605473
L 19.093670654296876 21.748565673828125
Q 17.59075927734375 22.69158172607422 15.83736267089844 23.00592041015625
L 15.83736267089844 25.20629119873047
Q 15.83736267089844 26.023571777343754 15.023285675048829 26.023571777343754
L 13.144646453857423 26.023571777343754
Q 12.267948150634766 26.023571777343754 12.267948150634766 25.20629119873047
L 12.267948150634766 23.00592041015625
Q 10.514551544189452 22.69158172607422 9.074261474609376 21.685697937011717
L 7.446107482910155 23.257391357421874
Q 6.882515716552734 23.886068725585936 6.193681335449219 23.194523620605473
L 4.878633880615234 21.87430114746094
Q 4.315042114257812 21.308491516113286 4.878633880615234 20.679814147949223
L 6.444166564941406 19.108120727539067
Q 5.442225646972656 17.66216278076172 5.129119110107422 15.838998413085937
L 2.8747520446777344 15.838998413085937
Q 1.9980537414550774 15.838998413085937 1.9980537414550774 14.958850097656251
L 1.9980537414550774 13.135685729980468
Q 1.9980537414550774 12.255537414550782 2.8747520446777344 12.255537414550782
L 5.129119110107422 12.255537414550782
Q 5.442225646972656 10.495240783691406 6.444166564941406 9.049282836914061
L 4.816012573242188 7.414721679687501
Q 4.252420806884766 6.786044311523439 4.878633880615234 6.157366943359374
L 6.193681335449219 4.837144470214843
Q 6.75727310180664 4.271334838867187 7.383486175537109 4.837144470214843
L 8.94901885986328 6.408837890625
Q 10.451930236816406 5.340086364746094 12.267948150634766 5.025747680664063
L 12.267948150634766 2.8253768920898445
Q 12.267948150634766 2.0080963134765626 13.144646453857423 2.0080963134765626 Z
M 20.346096801757813 13.95296630859375
Q 20.346096801757813 16.53054351806641 18.467457580566407 18.35370788574219 16.651439666748047 20.239739990234376 14.083966064453126 20.239739990234376 11.516492462158201 20.239739990234376 9.637853240966795 18.35370788574219 7.821835327148437 16.53054351806641 7.821835327148437 13.95296630859375 7.821835327148437 11.375389099121092 9.637853240966795 9.489356994628904 11.516492462158201 7.666192626953125 14.083966064453126 7.666192626953125 16.651439666748047 7.666192626953125 18.467457580566407 9.489356994628904 20.346096801757813 11.375389099121092 20.346096801757813 13.95296630859375 Z"
fill="none"
id="iconLayer0_0_1_STROKES"
stroke="var(--color-stroke)"
strokeLinecap="square"
strokeLinejoin="miter"
strokeMiterlimit="3"
strokeWidth="1"
/>
</defs>
<g transform="matrix( 1.2524261474609375, 0, 0, 1.257354736328125, -3.45,-3.65) ">
<use xlinkHref="#icon-Layer0_0_FILL" />
<use
transform="matrix( 0.7984466552734375, 0, 0, 0.795318603515625, 2.75,2.9) "
xlinkHref="#iconLayer0_0_1_STROKES"
/>
</g>
</svg>
),
send: ({ className }) => (
<svg
className={className}
height="18px"
preserveAspectRatio="none"
version="1.1"
viewBox="0 0 18 18"
width="18px"
x="0px"
xmlns="http://www.w3.org/2000/svg"
y="0px"
>
<defs>
<g id="sendicon-Layer0_0_FILL_2">
<path
d="
M 6.65 9.9
L 5.65 14.6 15.4 9.4 5.65 4.2 6.65 8.9 9.25 9.4 6.65 9.9 Z"
fill="var(--ai-tool-icon-color, #777)"
stroke="none"
/>
</g>
</defs>
<g transform="matrix( 1, 0, 0, 1, 0,0) ">
<use xlinkHref="#sendicon-Layer0_0_FILL_2" />
</g>
</svg>
),
};
......@@ -8,6 +8,7 @@ const elementFromString = string => {
};
const replaceSelectedText = (view, responseText, replace = false) => {
if (!responseText) return;
let { state } = view;
let { tr } = state;
const { from, to } = tr.selection;
......
import React, { useContext, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { th } from '@pubsweet/ui-toolkit';
import { WaxContext } from 'wax-prosemirror-core';
import { keys } from 'lodash';
import SwitchComponent from './Switch';
// #region CONSTANTS ---------------------------------------------
const LABEL_POS = 'left';
const SETTINGS = [
{
key: 'AskKb',
label: 'Ask knowledge base',
},
{
key: 'CustomPromptsOn',
label: 'Custom prompts',
},
{
key: 'GenerateImages',
label: 'Generate image',
},
];
// #endregion CONSTANTS ---------------------------------------------
// #region STYLED COMPONENTS ---------------------------------------------
export const ToggleInput = styled(SwitchComponent)`
--width: 20px;
--divisor: 2.1;
--height: calc(var(--width) / var(--divisor));
--padding: 1px;
--border-width: 0px;
--label-font-size: 12px;
align-items: center;
display: flex;
gap: 10px;
padding: 0.5rem 0.2rem;
button {
align-items: center;
border-radius: calc(
var(--height) + (var(--padding) * 2) + var(--border-width)
);
display: flex;
height: fit-content;
padding: var(--padding);
transition: all 0.3s;
width: var(--width);
&:focus {
box-shadow: none;
outline: 1px solid #d5f1fd;
outline-offset: 1px;
}
}
label {
color: var(--ai-tool-switch-label-color, #777);
font-size: var(--label-font-size);
margin: 0;
}
.rc-switch {
border-width: var(--border-width);
&::after {
height: calc(var(--height) - (var(--padding) * 2));
position: unset;
transition: margin 0.2s cubic-bezier(0.35, 0, 0.25, 1);
width: calc(var(--height) - (var(--padding) * 2));
}
}
.rc-switch-checked {
border: var(--border-width) solid ${th('colorPrimary')};
&::after {
border: none;
margin-left: calc(var(--width) - var(--height));
}
}
`;
const SettingsDropdown = styled.ul`
--item-height: var(--ai-settings-menu-height, 30px);
--items-length: ${p => p.$listlng};
--max-height: calc(var(--item-height) * var(--items-length));
background-color: #f8f8f8;
border: ${p => (p.$show ? 'var(--ai-tool-border)' : '0 solid #0000')};
border-radius: 0 0 0.3rem 0.3rem;
border-top: none;
display: flex;
flex-direction: column;
list-style: none;
margin: 0;
max-height: ${p => (p.$show ? 'var(--max-height)' : 0)};
overflow: hidden;
padding: 0 0.5rem;
position: absolute;
right: calc(-1 * var(--ai-tool-border-width));
top: calc(100% + var(--ai-tool-border-width));
transition: all ${p => `${0.15 * p.$listlng}s`};
z-index: 15;
> li {
align-items: center;
display: flex;
height: var(--item-height);
justify-content: ${LABEL_POS === 'right' ? 'flex-start' : 'flex-end'};
padding: 0;
user-select: none;
}
> li:not(:first-child) {
border-top: 1px solid #0001;
}
`;
// #endregion STYLED COMPONENTS ---------------------------------------------
const AiSettingsMenu = ({ show, aiService, optionsState, setOptionsState }) => {
const ctx = useContext(WaxContext);
const onAiService = ({ key }) => keys(aiService).includes(key);
const enabledSettings = SETTINGS.filter(onAiService).map(setting => ({
...setting,
type: typeof aiService[setting.key],
}));
useEffect(() => {
enabledSettings.forEach(({ key }) => setOption(key, aiService[key]));
}, []);
const setOption = (key, state) => {
ctx.setOption({ [key]: state });
setOptionsState(prev => ({
...prev,
[key]: state,
}));
};
const handlers = (key, type, value) => {
const typeBasedHandlers = {
boolean: () => {
setOption(key, !value);
},
};
return typeBasedHandlers[type] ?? (() => {});
};
const renderSettings = ({ key, label, type }) => {
const value = optionsState[key];
const typeBasedSettingUI = {
boolean: (
<li key={key}>
<ToggleInput
checked={optionsState[key]}
label={label}
labelPosition={LABEL_POS}
onChange={handlers(key, type, value)}
/>
</li>
),
};
return typeBasedSettingUI[type] ?? typeBasedSettingUI.boolean;
};
return (
<SettingsDropdown
$listlng={enabledSettings.length}
$show={show}
onClick={e => e.stopPropagation()} // to prevent !showSettings
>
{enabledSettings?.map(renderSettings)}
</SettingsDropdown>
);
};
AiSettingsMenu.propTypes = {
show: PropTypes.bool,
aiService: PropTypes.shape({}),
optionsState: PropTypes.shape({}),
setOptionsState: PropTypes.func,
};
AiSettingsMenu.defaultProps = {
show: false,
aiService: {},
optionsState: {},
setOptionsState: () => {},
};
export default AiSettingsMenu;
......@@ -15,12 +15,13 @@ const Wrapper = styled.span`
}
.rc-switch-checked {
border: 1px solid ${th('colorPrimary')};
background-color: ${th('colorPrimary')};
border: 1px solid ${th('colorPrimary')};
.rc-switch-inner {
left: 6px;
}
:after {
left: 42px;
}
......@@ -28,6 +29,7 @@ const Wrapper = styled.span`
`;
const Label = styled.label`
cursor: pointer;
${props =>
props.labelPosition === 'left' &&
css`
......@@ -43,7 +45,6 @@ const Label = styled.label`
font-size: 14px;
margin-left: ${grid(2)};
`}
cursor: pointer;
`;
const SwitchComponent = props => {
......
export const safeParse = (str, fallbackKey) => {
try {
const parsed = JSON.parse(str);
return parsed;
} catch (e) {
return { [fallbackKey]: str };
}
};
export const resultsToHtml = (key, value) => {
const variations = {
content: value,
citations:
typeof value === 'string'
? value
: value?.map(item => `<blockquote>${item}</blockquote>`).join(''),
links:
typeof value === 'string'
? value
: value
?.map(item => `<a href="${item}" target="_blank">${item}</a></br>`)
.join(''),
};
return variations[key] ?? value;
};
export const getUpdatedPosition = ({ surface, end, overlay }) => {
const top = end.top - surface.top + 20;
let left = end.left - surface.left - overlay.width / 2;
if (end.left - overlay.width / 2 < surface.left) {
left += surface.left - (end.left - overlay.width / 2);
}
// Don't get out of right boundary of the surface
if (end.left + overlay.width / 2 > surface.right) {
left -= end.left + overlay.width / 2 - surface.right;
}
return { left, top };
};
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment