refactor ai lookup
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -437,6 +437,7 @@
|
||||
"extractionFailed": "提取失败",
|
||||
"extractedSuccessfully": "提取成功",
|
||||
"lookup": "查询",
|
||||
"reLookup": "重新查询",
|
||||
"lookupAll": "全部查询",
|
||||
"lookingUp": "正在查询",
|
||||
"pending": "等待中",
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user