From d82af4efad7f7acfc66e5b7b7052351a4c2e2275 Mon Sep 17 00:00:00 2001 From: zyronon Date: Mon, 11 Sep 2023 18:52:21 +0800 Subject: [PATCH] feat(typearticle): add useNetworkTranslate hook --- src/components/Practice/TypeArticle.vue | 33 ++++-- src/hooks/translate.ts | 135 +++++++++++++++++++----- src/types.ts | 9 +- 3 files changed, 143 insertions(+), 34 deletions(-) diff --git a/src/components/Practice/TypeArticle.vue b/src/components/Practice/TypeArticle.vue index a280041f..5ea19772 100644 --- a/src/components/Practice/TypeArticle.vue +++ b/src/components/Practice/TypeArticle.vue @@ -16,7 +16,17 @@ import correct from '../..//assets/sound/correct.wav' import {useSound} from "@/hooks/useSound.ts" import {CnKeyboardMap, useSplitArticle, useSplitCNArticle} from "@/hooks/useSplitArticle"; import {$computed, $ref} from "vue/macros"; -import {Article, ArticleWord, DefaultWord, DictType, SaveKey, Sentence, ShortKeyMap, Word} from "@/types"; +import { + Article, + ArticleWord, + DefaultWord, + DictType, + SaveKey, + Sentence, + ShortKeyMap, + TranslateEngine, + Word +} from "@/types"; import {useBaseStore} from "@/stores/base"; import Footer from "@/components/Practice/Footer.vue" import {usePracticeStore} from "@/components/Practice/usePracticeStore.ts"; @@ -27,6 +37,7 @@ import Baidu from "@opentranslate/baidu"; import {axiosInstance} from "@/utils/http"; import {translate} from "element-plus"; import useSleep from "@/hooks/useSleep.ts"; +import {useNetworkTranslate} from "@/hooks/translate.ts"; let article1 = `How does the older investor differ in his approach to investment from the younger investor? There is no shortage of tipsters around offering 'get-rich-quick' opportunities. But if you are a serious private investor, leave the Las Vegas mentality to those with money to fritter. The serious investor needs a proper 'portfolio' -- a well-planned selection of investments, with a definite structure and a clear aim. But exactly how does a newcomer to the stock market go about achieving that? @@ -37,9 +48,10 @@ If you are younger, and in a solid financial position, you may decide to take an *'Periwigs' is the name of a fictitious company. INVESTOR'S CHRONICLE, March 23 1990` -// article1 = `How does the older investor differ in his approach to investment from the younger investor?How does the older investor differ in his approach to investment from the younger investor?` +article1 = `How does the older investor differ in his approach to investment from the younger investor?` article1 = `Last week I went to the theatre. I had a very good seat. The play was very interesting. I did not enjoy it. A young man and a young woman were sitting behind me. They were talking loudly. I got very angry. I could not hear the actors. I turned round. I looked at the man and the woman angrily. They did not pay any attention. In the end, I could not bear it. I turned round again. ‘I can't hear a word!’ I said angrily. ‘It's none of your business, ’ the young man said rudely. ‘This is a private conversation!’` +// article1 = `Last week I went to the theatre. I had a very good seat. The play was very interesting. I did not enjoy it.` let article2 = `What is one of the features of modern camping where nationality is concerned? Economy is one powerful motive for camping, since after the initial outlay upon equipment, or through hiring it, the total expense can be far less than the cost of hotels. But, contrary to a popular assumption, it is far from being the only one, or even the greatest. The man who manoeuvres carelessly into his twenty pounds' worth of space at one of Europe's myriad permanent sites may find himself bumping a Bentley. More likely, Ford Escort will be hub to hub with Renault or Mercedes, but rarely with bicycles made for two. @@ -88,16 +100,19 @@ let wordData = $ref({ let article = reactive
({ article: article1, - translate: `上星期我去看戏。我的座位很好,戏很有意思,但我却无法欣赏。一青年男子与一青年女子坐在我的身后,大声地说着话。我非常生气,因为我听不见演员在说什么。我回过头去,怒视着那一男一女,他们却毫不理会。最后,我忍不住了,又一次回过头去,生气地说,“我一个字也听不见了!” + customTranslate: `上星期我去看戏。我的座位很好,戏很有意思,但我却无法欣赏。一青年男子与一青年女子坐在我的身后,大声地说着话。我非常生气,因为我听不见演员在说什么。我回过头去,怒视着那一男一女,他们却毫不理会。最后,我忍不住了,又一次回过头去,生气地说,“我一个字也听不见了!” “不关你的事,”那男的毫不客气地说,“这是私人间的谈话!”`, + networkTranslate: '', newWords: [], articleAllWords: [], sections: [], - isTranslate: false, + isTranslated: false, }) -onMounted(() => { - article.sections = useSplitArticle(article.article) +onMounted(async () => { + if (!article.sections.length) { + article.sections = useSplitArticle(article.article) + } practiceStore.total = 0 article.sections.map((v, i) => { @@ -110,8 +125,12 @@ onMounted(() => { }) }) practiceStore.startDate = Date.now() - console.log(cloneDeep(article)) calcTranslateLocation() + + console.time() + await useNetworkTranslate(article, TranslateEngine.Baidu, false) + console.timeEnd() + // console.log(cloneDeep(article)) }) function calcTranslateLocation() { diff --git a/src/hooks/translate.ts b/src/hooks/translate.ts index dd7064b5..63fbdc3d 100644 --- a/src/hooks/translate.ts +++ b/src/hooks/translate.ts @@ -1,36 +1,121 @@ -import {Article} from "@/types.ts"; +import {Article, Sentence, TranslateEngine} from "@/types.ts"; import Baidu from "@opentranslate/baidu"; import {axiosInstance} from "@/utils/http.ts"; import useSleep from "@/hooks/useSleep.ts"; import {CnKeyboardMap, useSplitCNArticle} from "@/hooks/useSplitArticle.ts"; +import {Translator} from "@opentranslate/translator/src/translator.ts"; -export async function useArticleTranslate(article: Article) { - const baidu = new Baidu({ - axios: axiosInstance, - config: { - appid: "20230910001811857", - key: "Xxe_yftQR3K3Ue43NQMC" - } - }) +export function useLocalTranslate(article: Article, translate: string) { + if (translate) { + let articleTranslate = useSplitCNArticle(translate, 'cn', CnKeyboardMap) - let articleTranslate - // if (article.translate) { - if (false) { - articleTranslate = useSplitCNArticle(article.translate, 'cn', CnKeyboardMap) - } - - for (let i = 0; i < article.sections.length; i++) { - let v = article.sections[i] - for (let j = 0; j < v.length; j++) { - let sentence = v[j] - if (articleTranslate) { + for (let i = 0; i < article.sections.length; i++) { + let v = article.sections[i] + for (let j = 0; j < v.length; j++) { + let sentence = v[j] sentence.translate = articleTranslate[i][j].sentence - } else { - await useSleep(500) - let r = await baidu.translate(sentence.sentence, 'en', 'zh-CN') - console.log('r', r) - sentence.translate = r.trans.paragraphs[0] } } } +} + +/*** + * @desc + * @param article 文章实体 + * @param translateEngine 翻译引擎 + * @param allShow 是否翻译完所有之后才显示 + * */ +export async function useNetworkTranslate(article: Article, translateEngine: TranslateEngine, allShow: boolean = false) { + if (article.networkTranslate) { + useLocalTranslate(article, article.networkTranslate) + } else { + let translator: Translator + if (translateEngine === TranslateEngine.Baidu) { + translator = new Baidu({ + axios: axiosInstance as any, + config: { + appid: "20230910001811857", + key: "Xxe_yftQR3K3Ue43NQMC" + } + }) as any + } + + if (translator) { + let promiseList = [] + let retryCount = 0 + let retryCountMap = new Map() + + const translate = async (sentence: Sentence) => { + try { + let r = await translator.translate(sentence.sentence, 'en', 'zh-CN') + if (r) { + const cb = () => { + sentence.translate = r.trans.paragraphs[0] + article.networkTranslate += sentence.translate + } + return Promise.resolve(cb) + } else { + return Promise.reject(() => translate(sentence)) + } + } catch (e) { + return Promise.reject(() => translate(sentence)) + } + } + + let total = 0 + let index = 0 + article.sections.map(v => total += v.length) + + for (let i = 0; i < article.sections.length; i++) { + let v = article.sections[i] + for (let j = 0; j < v.length; j++) { + let sentence = v[j] + let promise = translate(sentence) + if (allShow) { + promiseList.push(promise) + } else { + retryCountMap.set(sentence.sentence, 0) + let errResult: any + let cb = await promise.catch(err => { + errResult = err + }) + + while (errResult) { + let count = retryCountMap.get(sentence.sentence) + if (count > 2) break + cb = await errResult().catch(err => { + errResult = err + }) + retryCountMap.set(sentence.sentence, count + 1) + } + if (cb) cb() + index++ + console.log(index, total) + } + } + } + if (!promiseList.length) return + + return new Promise(async resolve => { + let cbs = [] + do { + if (retryCount > 2) { + return resolve(true) + } + let results = await Promise.allSettled(promiseList) + promiseList = [] + results.map(results => { + if (results.status === 'fulfilled') { + cbs.push(results.value) + } else { + promiseList.push(results.reason()) + } + }) + retryCount++ + } while (promiseList.length) + cbs.map(v => v()) + resolve(true) + }) + } + } } \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 912787f5..529b1bba 100644 --- a/src/types.ts +++ b/src/types.ts @@ -114,8 +114,9 @@ export interface Sentence { export interface Article { article: string, - translate: string, - isTranslate: boolean, + customTranslate: string, + networkTranslate: string, + isTranslated: boolean, newWords: Word[], articleAllWords: string[], sections: Sentence[][], @@ -195,4 +196,8 @@ export const ShortKeyMap = { Ignore: 'Tab', Remove: '`', Collect: 'Enter', +} + +export enum TranslateEngine { + Baidu = 0, } \ No newline at end of file