Skip to content

Commit

Permalink
refactor ai lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
an-lee committed May 15, 2024
1 parent 8c18f24 commit 89faf35
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 52 deletions.
3 changes: 1 addition & 2 deletions enjoy/src/commands/lookup.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ const DICITIONARY_PROMPT = `You are an {learning_language}-{native_language} dic
I will provide "word(it also maybe a phrase)" and "context" as input, you should return the "word", "lemma", "pronunciation", "pos", "definition", "translation" and "context_translation" as output.
If no context is provided, return the most common definition.
If you do not know the appropriate definition, return an empty string for "definition" and "translation".
Always return output in JSON format.
Always return the output in JSON format as following:
The output format:
{{
"word": "the original word or phrase",
"lemma": "lemma",
Expand Down
3 changes: 2 additions & 1 deletion enjoy/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,8 @@
"extracting": "Extracting",
"extractionFailed": "Extraction failed",
"extractedSuccessfully": "Extracted successfully",
"lookup": "Look up",
"lookup": "Lookup",
"reLookup": "Re-Lookup",
"lookupAll": "Look up all",
"lookingUp": "Looking up",
"pending": "Pending",
Expand Down
1 change: 1 addition & 0 deletions enjoy/src/i18n/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@
"extractionFailed": "提取失败",
"extractedSuccessfully": "提取成功",
"lookup": "查询",
"reLookup": "重新查询",
"lookupAll": "全部查询",
"lookingUp": "正在查询",
"pending": "等待中",
Expand Down
105 changes: 69 additions & 36 deletions enjoy/src/renderer/components/widgets/lookup-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -104,22 +105,25 @@ 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({
word,
context,
sourceId,
sourceType,
cacheKey: `lookup-${md5(`${word}-${context}`)}`,
force,
})
.then((lookup) => {
if (lookup?.meaning) {
Expand All @@ -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;
Expand All @@ -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 && (
Expand Down
31 changes: 18 additions & 13 deletions enjoy/src/renderer/hooks/use-ai-command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,7 +36,7 @@ export const useAiCommand = () => {
sourceType,
});

if (lookup.meaning) {
if (lookup.meaning && !force) {
return lookup;
}

Expand All @@ -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) => {
Expand Down

0 comments on commit 89faf35

Please sign in to comment.