'use client';
import React, { useState, useEffect, useRef } from 'react';
import type { Meta, StoryObj } from "@storybook/react";
import { getPublicClient } from "../api";
const client = getPublicClient('f5d86791-d513-48de-8fd2-b6dbdd4abe9b');
const DEFAULT_PROMPT = `Your job is to predict the next 5-10 words after the current text. Current text: {{inputText}}`;
export const AutocompleteTextField = ({
prompt = DEFAULT_PROMPT,
placeholder = "",
}: any) => {
const [text, setText] = React.useState('');
const [dirtyCount, setDirtyCount] = React.useState(0);
const [prediction, setPrediction] = React.useState('');
const inputRef = React.useRef(null) as any;
const [isFocused, setIsFocused] = useState(false);
const timeoutRef = useRef(null) as any;
// Event handler for focus
const handleFocus = () => {
setIsFocused(true);
};
// Event handler for blur
const handleBlur = () => {
setIsFocused(false);
};
useEffect(() => {
if (!inputRef.current) {
return;
}
const currentElement = inputRef.current as HTMLElement;
// Attach the event listeners
currentElement.addEventListener('focus', handleFocus);
currentElement.addEventListener('blur', handleBlur);
// Cleanup function to remove event listeners
return () => {
currentElement.removeEventListener('focus', handleFocus);
currentElement.removeEventListener('blur', handleBlur);
};
}, []); // Empty dependency array ensures this effect runs only once
React.useEffect(() => {
if (dirtyCount > 0) {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
if (text !== '') {
timeoutRef.current = setTimeout(() => {
getPredictions(text);
setDirtyCount(0);
}, 500);
}
}
}, [dirtyCount, text]);
const handleInput = (e: any) => {
e.preventDefault();
console.log(e.target.innerHTML);
setText(() => {
let newText = e.target.innerHTML;
newText = newText.replace(/(
){2,}/gi, '
');
newText = newText.replace(/
/gi, '\n');
newText = newText.replace(/ /gi, ' ');
const lastChar = newText[newText.length - 1] === ' ' ? ' ' : newText[newText.length - 1];
if (lastChar === prediction[0]) {
setPrediction((prevPrediction) => {
const newPrediction = prevPrediction.slice(1);
return newPrediction;
});
} else {
setDirtyCount((prevCount) => prevCount + 1);
setPrediction('');
}
return newText;
});
};
const handleKeyDown = (e: any) => {
if (e.key === 'Tab' && prediction) {
e.preventDefault();
// Append prediction and reset prediction state
const newText = text + prediction;
setText(newText);
setPrediction('');
const html = newText.split('\n').join('
');
inputRef.current.innerHTML = html; // Update contentEditable text
const range = document.createRange();
const sel = window.getSelection() as any;
range.selectNodeContents(inputRef.current); // Select the entire content of the div
range.collapse(false); // false collapses the range to the end, true to the start
sel.removeAllRanges(); // Remove any existing selections
sel.addRange(range); // Add the new range
} else if (e.key === 'Escape') {
setPrediction('');
}
};
const getPredictions = async (inputText: any) => {
if (!client) {
console.error("OpenAI client is not defined.");
return;
}
try {
const response = await client.getCompletion({
model: 'gpt-3.5-turbo',
messages: [{
role: 'system',
content: prompt.replace("{{inputText}}", inputText),
}],
});
if (response && response.choices && response.choices.length > 0) {
const predictedText = response.choices[0].message.content;
console.log("Predicted text:", predictedText);
setPrediction(predictedText);
}
} catch (error) {
console.error("Failed to fetch predictions:", error);
}
};
return (