refactor ai lookup

This commit is contained in:
an-lee
2024-05-15 17:06:10 +08:00
parent 8c18f2458d
commit 89faf35483
5 changed files with 91 additions and 52 deletions

View File

@@ -12,6 +12,7 @@ import {
import { useAiCommand, useCamdict } from "@renderer/hooks";
import { LoaderIcon, Volume2Icon } from "lucide-react";
import { t } from "i18next";
import { md5 } from "js-md5";
export const LookupWidget = () => {
const { EnjoyApp } = useContext(AppSettingsProviderContext);
@@ -104,15 +105,16 @@ export const AiLookupResult = (props: {
sourceId?: string;
}) => {
const { word, context = "", sourceType, sourceId } = props;
const { webApi } = useContext(AppSettingsProviderContext);
const { webApi, EnjoyApp } = useContext(AppSettingsProviderContext);
const [lookingUp, setLookingUp] = useState<boolean>(false);
const [result, setResult] = useState<LookupType>();
const { lookupWord } = useAiCommand();
const handleLookup = async () => {
const handleLookup = async (options?: { force: boolean }) => {
if (lookingUp) return;
if (!word) return;
const { force = false } = options;
setLookingUp(true);
lookupWord({
@@ -120,6 +122,8 @@ export const AiLookupResult = (props: {
context,
sourceId,
sourceType,
cacheKey: `lookup-${md5(`${word}-${context}`)}`,
force,
})
.then((lookup) => {
if (lookup?.meaning) {
@@ -134,26 +138,36 @@ export const AiLookupResult = (props: {
});
};
const fetchCachedLookup = async () => {
const remoteLookup = await webApi.lookup({
word,
context,
sourceId,
sourceType,
});
if (remoteLookup?.meaning) {
setResult(remoteLookup);
return;
}
const cached = await EnjoyApp.cacheObjects.get(
`lookup-${md5(`${word}-${context}`)}`
);
if (cached?.meaning) {
setResult(cached);
return;
}
setResult(undefined);
};
/*
* Fetch cached lookup result.
*/
useEffect(() => {
if (!word) return;
webApi
.lookup({
word,
context,
sourceId,
sourceType,
})
.then((res) => {
if (res?.meaning) {
setResult(res);
} else {
setResult(null);
}
});
fetchCachedLookup();
}, [word, context]);
if (!word) return null;
@@ -164,34 +178,53 @@ export const AiLookupResult = (props: {
{t("aiDictionary")}
</div>
{result ? (
<div className="mb-4 select-text">
<div className="mb-2 font-semibord font-serif">{word}</div>
<div className="mb-2">
{result.meaning?.pos && (
<span className="italic text-sm text-muted-foreground mr-2">
{result.meaning.pos}
</span>
)}
{result.meaning?.pronunciation && (
<span className="text-sm font-code mr-2">
/{result.meaning.pronunciation.replaceAll("/", "")}/
</span>
)}
{result.meaning?.lemma &&
result.meaning.lemma !== result.meaning.word && (
<span className="text-sm">({result.meaning.lemma})</span>
<>
<div className="mb-4 select-text">
<div className="mb-2 font-semibord font-serif">{word}</div>
<div className="mb-2">
{result.meaning?.pos && (
<span className="italic text-sm text-muted-foreground mr-2">
{result.meaning.pos}
</span>
)}
{result.meaning?.pronunciation && (
<span className="text-sm font-code mr-2">
/{result.meaning.pronunciation.replaceAll("/", "")}/
</span>
)}
{result.meaning?.lemma &&
result.meaning.lemma !== result.meaning.word && (
<span className="text-sm">({result.meaning.lemma})</span>
)}
</div>
<div className="text-serif">{result.meaning.translation}</div>
<div className="text-serif">{result.meaning.definition}</div>
</div>
<div className="text-serif">{result.meaning.translation}</div>
<div className="text-serif">{result.meaning.definition}</div>
</div>
<div className="flex items-center">
<Button
className="cursor-pointer"
variant="secondary"
size="sm"
disabled={lookingUp}
onClick={() => handleLookup({ force: true })}
asChild
>
<a>
{lookingUp && (
<LoaderIcon className="animate-spin w-4 h-4 mr-2" />
)}
{t("reLookup")}
</a>
</Button>
</div>
</>
) : (
<div className="flex items-center space-x-2 py-2">
<Button
className="cursor-pointer"
size="sm"
asChild
onClick={handleLookup}
onClick={() => handleLookup()}
>
<a>
{lookingUp && (

View File

@@ -21,8 +21,10 @@ export const useAiCommand = () => {
context: string;
sourceId?: string;
sourceType?: string;
cacheKey?: string;
force?: boolean;
}) => {
const { context, sourceId, sourceType } = params;
const { context, sourceId, sourceType, cacheKey, force = false } = params;
let { word } = params;
word = word.trim();
if (!word) return;
@@ -34,7 +36,7 @@ export const useAiCommand = () => {
sourceType,
});
if (lookup.meaning) {
if (lookup.meaning && !force) {
return lookup;
}
@@ -54,18 +56,21 @@ export const useAiCommand = () => {
}
);
// Accept result from gpt-3/4 models
if (modelName.match(/^gpt-(3|4)\S*/i) && res.context_translation?.trim()) {
return webApi.updateLookup(lookup.id, {
meaning: res,
sourceId,
sourceType,
});
} else {
return Object.assign(lookup, {
meaning: res,
});
webApi.updateLookup(lookup.id, {
meaning: res,
sourceId,
sourceType,
});
const result = Object.assign(lookup, {
meaning: res,
});
if (cacheKey) {
EnjoyApp.cacheObjects.set(cacheKey, result);
}
return result;
};
const extractStory = async (story: StoryType) => {