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

Test assistant prompt monorepo #5193

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion label_studio/frontend/dist/lsf/css/main.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion label_studio/frontend/dist/lsf/css/main.css.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion label_studio/frontend/dist/lsf/js/main.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion label_studio/frontend/dist/lsf/js/main.js.map

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions label_studio/frontend/dist/lsf/version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"message": "fix: OPTIC-341: Incorrect icon width causing layout issues with TabPanels in monorepo",
"commit": "2f5b6e1f3aac6aacf23b66ac64f1d6a8f34d4036",
"branch": "master",
"date": "2023-12-08T16:36:04Z"
"message": "Test assistant prompt",
"commit": "d3b5fd37ecbbf9a0ca6012db5a85b351854ed57d",
"branch": "fb-hackathon-assistant",
"date": "2023-12-18T16:09:13Z"
}
123 changes: 123 additions & 0 deletions web/libs/editor/src/components/Assistant/Assistant.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
.assistant
display flex
flex-wrap wrap
padding 16px

&__history
display flex
flex-wrap wrap
width 100%
cursor pointer
margin-top 10px

&-item
width 100%
margin 2px 0
padding 1px 5px
display: flex;
justify-content: space-between;
align-items center

&-delete
width 8px
height 8px
display flex
opacity .5

&:hover
opacity 1

&:hover
background-color #F5F5F5


.assist-form
--primary-action-color #00A8FF
--primary-action-padding 4px
--primary-action-border-radius 4px
--primary-action-surface-color-hover rgba(9, 109, 217, 0.12)
--text-input-min-height 40px
--tooltip-text-color #F5222D

display grid
grid-template-columns: auto var(--text-input-min-height);
align-items center
gap 4px
width 100%

&_disabled
opacity .5 !important
pointer-events none

&_loading
--borderWidth: 3px;
background: #FFF;
position: relative;
border-radius 4px
pointer-events: none;

&:after
content: '';
position: absolute;
top: calc(-1 * var(--borderWidth));
left: calc(-1 * var(--borderWidth));
height: calc(100% + var(--borderWidth) * 2);
width: calc(100% + var(--borderWidth) * 2);
background: linear-gradient(60deg, #9254DE, #9254DE, #13C2C2, #13C2C2);
border-radius: calc(2 * var(--borderWidth));
z-index: -1;
animation: animatedgradient 3s ease alternate infinite;
background-size: 300% 300%;

&__primary-action
height 100%
width 100%
display flex
justify-content center
align-items flex-start
flex-shrink 0
flex-grow 0
grid-row 1 / 2
grid-column 2 / -1

&_loading
filter grayscale(1)
opacity .6

button
margin-top 4px
display flex
justify-content center
align-items center
flex-shrink 0
flex-grow 0
appearance none
border none
background-color transparent
color var(--primary-action-color)
border-radius var(--primary-action-border-radius)
padding 0
height calc(var(--text-input-min-height) - 8px);
width calc(var(--text-input-min-height) - 8px);

&:hover
background-color var(--primary-action-surface-color-hover)

&__tooltipMessage
color var(--tooltip-text-color)
font-size 0.9em


@keyframes animatedgradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}


117 changes: 117 additions & 0 deletions web/libs/editor/src/components/Assistant/Assistant.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { observer } from 'mobx-react';
import { Block, Elem } from '../../utils/bem';
import { ReactComponent as IconSend } from '../../assets/icons/send.svg';
import { IconCross } from '../../assets/icons';
import { SpinnerCircle } from '../SpinnerCircle/SpinnerCircle';

import './Assistant.styl';
import { TextArea } from '../../common/TextArea/TextArea';

const MAX_NUMBER_OF_HISTORY_ITEMS = 10;

export const Assistant: FC<{ onPrompt: (prompt: string) => void, awaitingSuggestions: boolean }> = observer(({ onPrompt, awaitingSuggestions }) => {
const [historyValue, setHistoryValue] = useState<string[]>([]);
const [value, setValue] = useState('');

useEffect(() => {
const _history = JSON.parse(window.localStorage.getItem('llm_assistant') || '[]');

if (_history.length) {
setHistoryValue(_history);
setValue(historyValue[0]);
}
}, []);

useEffect(() => {
window.localStorage.setItem('llm_assistant', JSON.stringify(historyValue));
}, [historyValue]);

const setHistory = useCallback((text: string) => {
const _history = [...historyValue];

_history.forEach((item: string, index: number) => {
if (item === text) {
_history.splice(index, 1);
}
});

_history.unshift(text);

if (_history.length > MAX_NUMBER_OF_HISTORY_ITEMS) {
_history.pop();
}

setHistoryValue(_history);
}, [historyValue]);


const onSubmit = useCallback((e) => {
e?.preventDefault?.();

if (!value.trim()) return;

onPrompt(value);

setHistory(value);
}, [value]);

const setValueFromHistory = useCallback((item: string) => {
setValue(item);
onPrompt(item);
setHistory(item);
}, [historyValue]);

const deleteValueFromHistory = useCallback((deleteItem: string) => {
const _history = [...historyValue];

_history.forEach((item: string, index: number) => {
if (item === deleteItem) {
_history.splice(index, 1);
}
});

setHistoryValue(_history);
}, [historyValue]);

const renderHistory = () => {
return historyValue.map((item: string, index: number) => {
return (
<Elem tag="div" name="history-item" key={index} onClick={() => setValueFromHistory(item)}>
{item}
<Elem tag="div" name="history-item-delete" onClick={(e:MouseEvent) => {
e.stopPropagation();
deleteValueFromHistory(item);
}}>
<IconCross />
</Elem>
</Elem>
);
});
};

return (
<Block name="assistant">
<Block tag="form" name="assist-form" mod={{ inline: true, loading: awaitingSuggestions }} onSubmit={onSubmit}>
<TextArea
className={awaitingSuggestions ? 'lsf-assist-form_disabled' : ''}
name="assist-text"
placeholder="Type your message here"
value={value}
onChange={setValue}
onSubmit={onSubmit}
/>
<Elem tag="div" name="primary-action"
mod={{ loading: awaitingSuggestions }}
>
<button type="submit">
<Elem name='icon' tag={awaitingSuggestions ? SpinnerCircle : IconSend} width={24} height={24}/>
</button>
</Elem>
</Block>
<Elem tag="div" name="history">
{historyValue.length > 0 && renderHistory()}
</Elem>
</Block>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { Relations as RelationsComponent } from './Relations';
// eslint-disable-next-line
// @ts-ignore
import { DraftPanel } from '../../DraftPanel/DraftPanel';
import { Assistant } from '../../Assistant/Assistant';

interface DetailsPanelProps extends PanelProps {
regions: any;
selection: any;
Expand Down Expand Up @@ -70,6 +72,18 @@ const CommentsTab: FC<any> = inject('store')(observer(({ store }) => {
);
}));

const AssistTab: FC<any> = inject('store')(observer(({ store }) => {
return (
<Block name={'assistant-panel'}>
<Elem name="section-tab">
<Elem name="section-content">
<Assistant onPrompt={store.onAssistantPrompt} awaitingSuggestions={store.awaitingSuggestions} />
</Elem>
</Elem>
</Block>
);
}));

const RelationsTab: FC<any> = inject('store')(observer(({ currentEntity }) => {
const { relationStore } = currentEntity;

Expand Down Expand Up @@ -207,6 +221,7 @@ const SelectedRegion: FC<{region: any}> = observer(({
);
});

export const Assist = observer(AssistTab);
export const Comments = observer(CommentsTab);
export const History = observer(HistoryTab);
export const Relations = observer(RelationsTab);
Expand Down
36 changes: 25 additions & 11 deletions web/libs/editor/src/components/SidePanels/TabPanels/utils.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import { FC, MutableRefObject, ReactNode } from 'react';
import { clamp } from '../../../utils/utilities';
import { DEFAULT_PANEL_HEIGHT, DEFAULT_PANEL_MAX_HEIGHT, DEFAULT_PANEL_MAX_WIDTH, DEFAULT_PANEL_MIN_HEIGHT, DEFAULT_PANEL_WIDTH, PANEL_HEADER_HEIGHT } from '../constants';
import { Comments, History, Info, Relations } from '../DetailsPanel/DetailsPanel';
import {
DEFAULT_PANEL_HEIGHT,
DEFAULT_PANEL_MAX_HEIGHT,
DEFAULT_PANEL_MAX_WIDTH,
DEFAULT_PANEL_MIN_HEIGHT,
DEFAULT_PANEL_WIDTH,
PANEL_HEADER_HEIGHT
} from '../constants';
import { Assist, Comments, History, Info, Relations } from '../DetailsPanel/DetailsPanel';
import { OutlinerComponent } from '../OutlinerPanel/OutlinerPanel';
import { PanelProps } from '../PanelBase';
import { emptyPanel, JoinOrder, PanelBBox, PanelView, Side, ViewportSize } from './types';

export const determineLeftOrRight = (event: any, droppableElement?: ReactNode) => {
const element = droppableElement || event.target as HTMLElement;
const element = droppableElement || event.target as HTMLElement;
const dropWidth = (element as HTMLElement).clientWidth as number;
const x = event.pageX as number - (element as HTMLElement).getBoundingClientRect().left;
const half = dropWidth / 2;

return x > half ? Side.right : Side.left;
};

export const determineDroppableArea = (droppingElement: HTMLElement) => droppingElement?.id?.includes('droppable');

export const stateRemovedTab = (state: Record<string, PanelBBox>, movingPanel: string, movingTab: number) => {
Expand Down Expand Up @@ -49,7 +56,7 @@ export const setActiveDefaults = (state: Record<string, PanelBBox>) => {

Object.keys(state).forEach((panelKey: string) => {
const firstActiveTab = newState[panelKey].panelViews.findIndex((view) => view.active) ;

newState[panelKey].panelViews[firstActiveTab > 0 ? firstActiveTab : 0].active = true;
});

Expand Down Expand Up @@ -80,15 +87,15 @@ export const stateAddedTab = (
) => {
const newState = { ...state };
const panel = newState[receivingPanel];

panel.panelViews = newState[receivingPanel].panelViews.map((view) => {
view.active = false;
return view;
});

let index = receivingTab + (dropSide === Side.right ? 1 : 0);

if (movingPanel === receivingPanel && index > 0) index -= 1;
if (movingPanel === receivingPanel && index > 0) index -= 1;
panel.panelViews.splice(index, 0, movingTabData);
return newState;
};
Expand All @@ -107,6 +114,7 @@ export const panelComponents: {[key:string]: FC<PanelProps>} = {
'history': History as FC<PanelProps>,
'relations': Relations as FC<PanelProps>,
'comments': Comments as FC<PanelProps>,
'assist': Assist as FC<PanelProps>,
'info': Info as FC<PanelProps>,
};

Expand Down Expand Up @@ -142,6 +150,12 @@ const panelViews = [
component: panelComponents['comments'] as FC<PanelProps>,
active: false,
},
{
name: 'assist',
title: 'Assistant',
component: panelComponents['assist'] as FC<PanelProps>,
active: false,
},
];

export const enterprisePanelDefault: Record<string, PanelBBox> = {
Expand Down Expand Up @@ -173,7 +187,7 @@ export const enterprisePanelDefault: Record<string, PanelBBox> = {
detached: false,
alignment: Side.right,
maxHeight: DEFAULT_PANEL_MAX_HEIGHT,
panelViews: [panelViews[0], panelViews[2]],
panelViews: [panelViews[0], panelViews[2], panelViews[5]],
},
};

Expand All @@ -191,7 +205,7 @@ export const openSourcePanelDefault: Record<string, PanelBBox> = {
detached: false,
alignment: Side.right,
maxHeight: DEFAULT_PANEL_MAX_HEIGHT,
panelViews: [panelViews[3], panelViews[1]],
panelViews: [panelViews[3], panelViews[4], panelViews[1]],
},
'regions-relations': {
order: 2,
Expand Down
Loading