Skip to content

Commit

Permalink
transliteration added
Browse files Browse the repository at this point in the history
  • Loading branch information
prtkjakhar committed Dec 12, 2023
1 parent f3394c7 commit 438349d
Show file tree
Hide file tree
Showing 13 changed files with 950 additions and 34 deletions.
1 change: 1 addition & 0 deletions apps/amakrushi/src/components/ChatWindow/ChatUiWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ const ChatUiWindow: React.FC = () => {
background="var(--bg-color)"
disableSend={context?.loading}
translation={t}
showTransliteration={!(localStorage.getItem('locale') === 'en')}
//@ts-ignore
messages={msgToRender}
voiceToText={RenderVoiceRecorder}
Expand Down
21 changes: 21 additions & 0 deletions apps/amakrushi/src/components/HomePage/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,27 @@
font-size: 18px;
}

.suggestions{
position: absolute;
display: flex;
min-width: 50px;
width: auto;
bottom: 50px;
left: 10px;
background-color: white;
box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
}

.suggestion{
padding: 0 10px;
cursor: pointer;
}

.active{
background-color: #65c3d7;
color: white;
}

.inputBox {
min-height: 40px;
/* height: 40px; */
Expand Down
230 changes: 223 additions & 7 deletions apps/amakrushi/src/components/HomePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,136 @@ const HomePage: NextPage = () => {
const voiceRecorderRef = useRef(null);
const exampleMessagesRef = useRef(null);
const chatBoxButton = useRef(null);
const [suggestions, setSuggestions] = useState([]);
const [suggestionClicked, setSuggestionClicked] = useState(false);
const [activeSuggestion, setActiveSuggestion] = useState<number>(0);
const [transliterationConfig, setTransliterationConfig] = useState({
auth: '',
serviceId: '',
});
const [cursorPosition, setCursorPosition] = useState(0);

const suggestionHandler = (e: any, index: number) => {
setActiveSuggestion(index);
};

// Show chatbox when audio recorder sends input message
useEffect(() => {
if (inputMsg.length > 0) {
setShowChatBox(true);
if (inputMsg.length > 0 && !(localStorage.getItem('locale') === 'en')) {
if (suggestionClicked) {
setSuggestionClicked(false);
return;
}
if (!sessionStorage.getItem('computeFetched')) {
sessionStorage.setItem('computeFetched', 'true');
let data = JSON.stringify({
pipelineTasks: [
{
taskType: 'transliteration',
config: {
language: {
sourceLanguage: 'en',
targetLanguage: 'or',
},
},
},
],
pipelineRequestConfig: {
pipelineId: '64392f96daac500b55c543cd',
},
});

let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://meity-auth.ulcacontrib.org/ulca/apis/v0/model/getModelsPipeline',
headers: {
ulcaApiKey: '13900b794f-49de-4b42-8ee5-6e0289fe8833',
userID: '737078729ae04552822e4e7e3093575c',
'Content-Type': 'application/json',
},
data: data,
};

axios
.request(config)
.then((response) => {
setTransliterationConfig({
serviceId:
response?.data?.pipelineResponseConfig?.[0]?.config?.[0]
?.serviceId,
auth: response?.data?.pipelineInferenceAPIEndPoint
?.inferenceApiKey?.value,
});
})
.catch((error) => {
console.log(error);
});
}
setSuggestions([]);

const words = inputMsg.split(' ');
const wordUnderCursor = words.find(
(word, index) =>
cursorPosition >= inputMsg.indexOf(word) && cursorPosition <= inputMsg.indexOf(word) + word.length
);

if (!wordUnderCursor) return;
let data = JSON.stringify({
pipelineTasks: [
{
taskType: 'transliteration',
config: {
language: {
sourceLanguage: 'en',
targetLanguage: 'or',
},
serviceId:
transliterationConfig.serviceId ||
'ai4bharat/indicxlit--cpu-fsv2',
isSentence: false,
numSuggestions: 5,
},
},
],
inputData: {
input: [
{
source: wordUnderCursor,
},
],
},
});

let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://dhruva-api.bhashini.gov.in/services/inference/pipeline',
headers: {
Accept: ' */*',
'User-Agent': ' Thunder Client (https://www.thunderclient.com)',
Authorization:
transliterationConfig.auth ||
'L6zgUQ59QzincUafIoc1pZ8m54-UfxRdDKTNb0bVUDjm6z6HbXi6Nv7zxIJ-UyQN',
'Content-Type': 'application/json',
},
data: data,
};

axios
.request(config)
.then((res: any) => {
// console.log("hurray", res?.data?.output?.[0]?.target);
setSuggestions(res?.data?.pipelineResponse?.[0]?.output?.[0]?.target);
})
.catch((err) => {
console.log(err);
toast.error('Bhashini transliteration failed');
});
} else {
setSuggestions([]);
}
}, [inputMsg]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputMsg, cursorPosition]);

useEffect(() => {
setMessages([getInitialMsgs(t, flags, context?.locale)]);
Expand Down Expand Up @@ -98,8 +221,10 @@ const HomePage: NextPage = () => {
const handleInputChange = (e: any) => {
const inputValue = e.target.value;
setInputMsg(inputValue);
setShowExampleMessages(inputValue.length === 0);

// Store the cursor position
const cursorPosition = e.target.selectionStart;
setCursorPosition(cursorPosition);
// setShowExampleMessages(inputValue.length === 0);
// Adjust textarea height dynamically based on content
if (inputRef.current) {
//@ts-ignore
Expand All @@ -121,7 +246,8 @@ const HomePage: NextPage = () => {
//@ts-ignore
!exampleMessagesRef.current?.contains(target)
) {
setShowExampleMessages(false);
// setShowExampleMessages(false);
setSuggestions([]);
// setShowChatBox(false);
}
}, []);
Expand All @@ -134,6 +260,81 @@ const HomePage: NextPage = () => {
};
}, [handleDocumentClick]);

const suggestionClickHandler = useCallback(
(e: any) => {
const words = inputMsg.split(' ');

// Find the word at the cursor position
//@ts-ignore
const cursorPosition = inputRef.current.selectionStart;
let currentIndex = 0;
let selectedWord = '';

for (let i = 0; i < words.length; i++) {
const word = words[i];
if (currentIndex <= cursorPosition && cursorPosition <= currentIndex + word.length) {
selectedWord = word;
break;
}
currentIndex += word.length + 1; // +1 to account for the space between words
}

// Replace the selected word with the transliterated suggestion
if (selectedWord !== '') {
const newInputMsg = inputMsg.replace(selectedWord, e);

setSuggestions([]);
setSuggestionClicked(true);
setActiveSuggestion(0);

//@ts-ignore
setInputMsg(newInputMsg, () => {
//@ts-ignore
inputRef.current.focus(); // Ensure input is focused
});
}
},
[inputMsg]
);

const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (suggestions.length > 0) {
if (e.key === 'ArrowUp') {
e.preventDefault();
setActiveSuggestion((prevActiveSuggestion) =>
prevActiveSuggestion > 0
? prevActiveSuggestion - 1
: prevActiveSuggestion
);
} else if (e.key === 'ArrowDown') {
e.preventDefault();
setActiveSuggestion((prevActiveSuggestion) =>
prevActiveSuggestion < suggestions.length - 1
? prevActiveSuggestion + 1
: prevActiveSuggestion
);
} else if (e.key === ' ') {
e.preventDefault();
if (activeSuggestion >= 0 && activeSuggestion < suggestions?.length) {
suggestionClickHandler(suggestions[activeSuggestion]);
} else {
setInputMsg((prevInputMsg) => prevInputMsg + ' ');
}
}
}
},
[activeSuggestion, suggestionClickHandler, suggestions]
);

useEffect(() => {
document.addEventListener('keydown', handleKeyDown);

return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [handleKeyDown]);

if (context?.isDown) {
return <DownTimePage />;
} else
Expand Down Expand Up @@ -194,6 +395,21 @@ const HomePage: NextPage = () => {
</div>
) : (
<>
<div className={styles.suggestions}>
{suggestions.map((elem, index) => {
return (
<div
key={index}
onClick={() => suggestionClickHandler(elem)}
className={`${styles.suggestion} ${
activeSuggestion === index ? styles.active : ''
}`}
onMouseEnter={(e) => suggestionHandler(e, index)}>
{elem}
</div>
);
})}
</div>
<textarea
ref={inputRef}
rows={1}
Expand Down
2 changes: 1 addition & 1 deletion packages/chat-ui/dist/index.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/chat-ui/dist/index.js

Large diffs are not rendered by default.

Loading

0 comments on commit 438349d

Please sign in to comment.