Skip to content

Commit

Permalink
Refactoring by putting LLM translations into a context
Browse files Browse the repository at this point in the history
  • Loading branch information
ayanaar committed Apr 22, 2024
1 parent f4efd51 commit 496ca2b
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 112 deletions.
97 changes: 97 additions & 0 deletions translate/src/context/TranslationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, {
createContext,
useContext,
useState,
Dispatch,
SetStateAction,
} from 'react';
import { fetchGPTTransform } from '~/api/machinery';

interface LLMTranslationContextType {
llmTranslation: string;
setLlmTranslation: Dispatch<SetStateAction<string>>;

selectedOption: string;
setSelectedOption: Dispatch<SetStateAction<string>>;
transformLLMTranslation: (
original: string,
current: string,
characteristic: string,
localeName: string,
) => Promise<void>;
}

const LLMTranslationContext = createContext<LLMTranslationContextType>({
llmTranslation: '',
setLlmTranslation: () => {},

selectedOption: '',
setSelectedOption: () => {},
transformLLMTranslation: async () => {},
});

export const LLMTranslationProvider: React.FC = ({ children }) => {
const [llmTranslation, setLlmTranslation] = useState<string>('');

const [selectedOption, setSelectedOption] = useState<string>('');

const handleSetSelectedOption = (option: string) => {
let displayText = '';

switch (option) {
case 'alternative':
displayText = 'REPHRASED';
break;
case 'formal':
displayText = 'FORMAL';
break;
case 'informal':
displayText = 'INFORMAL';
break;
case 'original':
displayText = '';
break;
}

setSelectedOption(displayText);
};

const transformLLMTranslation = async (
original: string,
current: string,
characteristic: string,
localeName: string,
) => {
if (characteristic !== 'original') {
const machineryTranslations = await fetchGPTTransform(
original,
current,
characteristic,
localeName,
);
if (machineryTranslations.length > 0) {
setLlmTranslation(machineryTranslations[0].translation);
handleSetSelectedOption(characteristic);
}
} else {
setLlmTranslation('');
handleSetSelectedOption('');
}
};

return (
<LLMTranslationContext.Provider
value={{
llmTranslation,
setLlmTranslation,
selectedOption,
setSelectedOption,
transformLLMTranslation,
}}
>
{children}
</LLMTranslationContext.Provider>
);
};

export const useLLMTranslation = () => useContext(LLMTranslationContext);
29 changes: 17 additions & 12 deletions translate/src/modules/machinery/components/Machinery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { SkeletonLoader } from '~/modules/loaders';

import './Machinery.css';
import { MachineryTranslationComponent } from './MachineryTranslation';
import { LLMTranslationProvider } from '~/context/TranslationContext';

/**
* Show translations from machines.
Expand Down Expand Up @@ -70,22 +71,26 @@ export function Machinery(): React.ReactElement<'section'> {
<div className='list-wrapper' ref={rootRef}>
<ul>
{translations.map((translation, index) => (
<MachineryTranslationComponent
index={index}
sourceString={source}
translation={translation}
key={index}
/>
<LLMTranslationProvider>
<MachineryTranslationComponent
index={index}
sourceString={source}
translation={translation}
key={index}
/>
</LLMTranslationProvider>
))}
</ul>
<ul>
{results.map((result, index) => (
<MachineryTranslationComponent
index={index + translations.length}
sourceString={query}
translation={result}
key={index + translations.length}
/>
<LLMTranslationProvider>
<MachineryTranslationComponent
index={index + translations.length}
sourceString={query}
translation={result}
key={index + translations.length}
/>
</LLMTranslationProvider>
))}
</ul>
{(fetching || hasMore) && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { Localized } from '@fluent/react';
import classNames from 'classnames';
import React, {
useCallback,
useContext,
useEffect,
useRef,
useState,
} from 'react';
import React, { useCallback, useContext, useEffect, useRef } from 'react';

import type { MachineryTranslation } from '~/api/machinery';
import { logUXAction } from '~/api/uxaction';
Expand All @@ -18,6 +12,7 @@ import { useReadonlyEditor } from '~/hooks/useReadonlyEditor';

import { ConcordanceSearch } from './ConcordanceSearch';
import { MachineryTranslationSource } from './MachineryTranslationSource';
import { useLLMTranslation } from '~/context/TranslationContext';

import './ConcordanceSearch.css';
import './MachineryTranslation.css';
Expand All @@ -44,12 +39,7 @@ export function MachineryTranslationComponent({
const { element, setElement } = useContext(HelperSelection);
const isSelected = element === index;

const [llmTranslation, setLlmTranslation] = useState('');

// Handler to update LLM translation
const handleLLMTranslationChange = useCallback((newTranslation: string) => {
setLlmTranslation(newTranslation);
}, []);
const { llmTranslation } = useLLMTranslation();

const copyRegularTranslationIntoEditor = useCallback(() => {
if (window.getSelection()?.isCollapsed !== false) {
Expand Down Expand Up @@ -90,10 +80,10 @@ export function MachineryTranslationComponent({
<li
className={className}
title='Copy Into Translation (Ctrl + Shift + Down)'
onClick={() =>
onClick={
llmTranslation
? copyLLMTranslationIntoEditor()
: copyRegularTranslationIntoEditor()
? copyLLMTranslationIntoEditor
: copyRegularTranslationIntoEditor
}
ref={translationRef}
>
Expand All @@ -106,9 +96,6 @@ export function MachineryTranslationComponent({
<MachineryTranslationSuggestion
sourceString={sourceString}
translation={translation}
llmTranslation={llmTranslation}
handleLLMTranslationChange={handleLLMTranslationChange}
onLLMClick={copyLLMTranslationIntoEditor}
/>
)}
</li>
Expand All @@ -119,28 +106,21 @@ export function MachineryTranslationComponent({
function MachineryTranslationSuggestion({
sourceString,
translation,
llmTranslation,
handleLLMTranslationChange,
onLLMClick,
}: {
sourceString: string;
translation: MachineryTranslation;
llmTranslation?: string;
handleLLMTranslationChange: (newTranslation: string) => void;
onLLMClick: () => void;
}) {
const { code, direction, script } = useContext(Locale);
const { llmTranslation } = useLLMTranslation();
const contentToDisplay = llmTranslation || translation.translation;
return (
<>
<header>
{translation.quality && (
<span className='quality'>{translation.quality + '%'}</span>
)}
<MachineryTranslationSource
translation={translation}
handleLLMTranslationChange={handleLLMTranslationChange}
/>

<MachineryTranslationSource translation={translation} />
</header>
<p className='original'>
<GenericTranslation
Expand All @@ -157,7 +137,6 @@ function MachineryTranslationSuggestion({
dir={direction}
data-script={script}
lang={code}
onClick={onLLMClick}
>
<GenericTranslation content={contentToDisplay} />
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ import { TranslationMemory } from './source/TranslationMemory';

type Props = {
translation: MachineryTranslation;
handleLLMTranslationChange: (llmTranslation: string) => void;
};

/**
* Shows a list of translation sources.
*/
export function MachineryTranslationSource({
translation,
handleLLMTranslationChange,
}: Props): React.ReactElement<'ul'> {
const sources: React.ReactElement<'li'>[] = [];
const seen: string[] = [];
Expand All @@ -37,11 +35,7 @@ export function MachineryTranslationSource({
break;
case 'google-translate':
sources.push(
<GoogleTranslation
translation={translation}
key={source}
onLLMTranslationChange={handleLLMTranslationChange}
/>,
<GoogleTranslation translation={translation} key={source} />,
);
break;
case 'microsoft-translator':
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React, { useState, useRef, useContext } from 'react';
import { Localized } from '@fluent/react';
import type { MachineryTranslation } from '~/api/machinery';
import { fetchGPTTransform } from '~/api/machinery';
import { Locale } from '~/context/Locale';
import { logUXAction } from '~/api/uxaction';
import { useLLMTranslation } from '~/context/TranslationContext';

type Props = {
translation: MachineryTranslation;
onLLMTranslationChange: (llmTranslation: string) => void;
};

/**
Expand All @@ -16,78 +15,36 @@ type Props = {

export function GoogleTranslation({
translation,
onLLMTranslationChange,
}: Props): React.ReactElement<'li'> {
const [isDropdownOpen, setDropdownOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState('');
const [showOriginalOption, setShowOriginalOption] = useState(false);
const [currentTranslation, setCurrentTranslation] = useState(
translation.translation,
);
const dropdownRef = useRef<HTMLLIElement>(null);
const locale = useContext(Locale);

const { transformLLMTranslation, selectedOption } = useLLMTranslation();

const toggleDropdown = (ev: React.MouseEvent) => {
ev.stopPropagation();
setDropdownOpen((isDropdownOpen) => !isDropdownOpen);
};

const handleTransformation = async (characteristic: string) => {
// Only fetch transformation if not reverting to original
if (characteristic !== 'original') {
const machineryTranslations = await fetchGPTTransform(
translation.original,
currentTranslation,
characteristic,
locale.name,
);

if (machineryTranslations.length > 0) {
setCurrentTranslation(machineryTranslations[0].translation);
onLLMTranslationChange(machineryTranslations[0].translation);
setShowOriginalOption(true);
}
} else {
setCurrentTranslation(translation.translation);
onLLMTranslationChange('');
setSelectedOption('');
setShowOriginalOption(false);
}
};

const handleOptionClick = (ev: React.MouseEvent<HTMLLIElement>) => {
const handleOptionClick = async (ev: React.MouseEvent<HTMLLIElement>) => {
ev.stopPropagation();
const target = ev.currentTarget;
const characteristic = target.dataset['characteristic'];

if (characteristic) {
let displayText = '';

switch (characteristic) {
case 'alternative':
displayText = 'REPHRASED';
break;
case 'formal':
displayText = 'FORMAL';
break;
case 'informal':
displayText = 'INFORMAL';
break;
case 'original':
displayText = '';
break;
default:
break;
}
setSelectedOption(displayText); // TODO: Localize displayText before setting it as selected option.
setDropdownOpen(false);
await transformLLMTranslation(
translation.original,
translation.translation,
characteristic,
locale.name,
);

logUXAction('LLM Dropdown Select', 'LLM Feature Adoption', {
optionSelected: characteristic,
targetLanguage: locale.name,
});

handleTransformation(characteristic);
}
};

Expand Down Expand Up @@ -128,16 +85,12 @@ export function GoogleTranslation({
MAKE INFORMAL
</li>
</Localized>
{showOriginalOption && (
<>
<li className='horizontal-separator'></li>
<Localized id='machinery-GoogleTranslation--option-show-original'>
<li data-characteristic='original' onClick={handleOptionClick}>
SHOW ORIGINAL
</li>
</Localized>
</>
)}
<li className='horizontal-separator'></li>
<Localized id='machinery-GoogleTranslation--option-show-original'>
<li data-characteristic='original' onClick={handleOptionClick}>
SHOW ORIGINAL
</li>
</Localized>
</ul>
)}
</li>
Expand Down

0 comments on commit 496ca2b

Please sign in to comment.