From 035463395100f20b536a6bba5b83fc86520eeb21 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Sun, 21 Jan 2024 17:31:12 +0800 Subject: [PATCH] [Web] Support more fields and infomation --- web/src/components/SubtitleCard.jsx | 10 +- web/src/components/TranslatorApplication.jsx | 123 ++++++++++++++++--- 2 files changed, 107 insertions(+), 26 deletions(-) diff --git a/web/src/components/SubtitleCard.jsx b/web/src/components/SubtitleCard.jsx index 663fd37..0191c6f 100644 --- a/web/src/components/SubtitleCard.jsx +++ b/web/src/components/SubtitleCard.jsx @@ -1,14 +1,12 @@ -export function SubtitleCard({ children, text }) { +export function SubtitleCard({ children, label, }) { return ( <> -
-
-

{text}

-
+
+

{label}

+
{children}
-
diff --git a/web/src/components/TranslatorApplication.jsx b/web/src/components/TranslatorApplication.jsx index 94d463d..1badc0d 100644 --- a/web/src/components/TranslatorApplication.jsx +++ b/web/src/components/TranslatorApplication.jsx @@ -1,42 +1,57 @@ "use client" import React, { useEffect, useRef, useState } from 'react' -import { Accordion, AccordionItem, Button, Input } from "@nextui-org/react"; +import { Accordion, AccordionItem, Button, Input, Card, Textarea, Slider, Switch } from "@nextui-org/react"; import { EyeSlashFilledIcon } from './EyeSlashFilledIcon'; import { EyeFilledIcon } from './EyeFilledIcon'; import { FileUploadButton } from '@/components/FileUploadButton'; import { SubtitleCard } from '@/components/SubtitleCard'; +import { downloadString } from '@/utils/download'; import { sampleSrt } from '@/data/sample'; import { Translator } from "chatgpt-subtitle-translator" import { parser } from 'chatgpt-subtitle-translator/src/subtitle.mjs'; import { createOpenAIClient } from 'chatgpt-subtitle-translator/src/openai.mjs' -import { downloadString } from '@/utils/download'; +import { CooldownContext } from 'chatgpt-subtitle-translator/src/cooldown.mjs'; const OPENAI_API_KEY = "OPENAI_API_KEY" +const coolerChatGPTAPI = new CooldownContext(60, 60000, "ChatGPTAPI") +const coolerOpenAIModerator = new CooldownContext(60, 60000, "OpenAIModerator") export function TranslatorApplication() { - const [APIvalue, setAPIValue] = useState(""); - const [isAPIInputVisible, setIsAPIInputVisible] = useState(false); + // Translator Configuration + const [APIvalue, setAPIValue] = useState("") const [fromLanguage, setFromLanguage] = useState("") const [toLanguage, setToLanguage] = useState("English") + const [systemInstruction, setSystemInstruction] = useState("") + const [model, setModel] = useState("gpt-3.5-turbo") + const [temperature, setTemperature] = useState(0) + const [useModerator, setUseModerator] = useState(true) + /** @type {React.MutableRefObject} */ + const configSection = useRef() + const [isAPIInputVisible, setIsAPIInputVisible] = useState(false) + const toggleAPIInputVisibility = () => setIsAPIInputVisible(!isAPIInputVisible) + + // Translator State const [srtInputText, setSrtInputText] = useState(sampleSrt) const [srtOutputText, setSrtOutputText] = useState(sampleSrt) const [inputs, setInputs] = useState(parser.fromSrt(sampleSrt).map(x => x.text)) const [outputs, setOutput] = useState([]) const [streamOutput, setStreamOutput] = useState("") const [translatorRunningState, setTranslatorRunningState] = useState(false) - - /** @type {React.MutableRefObject} */ - const configSection = useRef() - /** @type {React.MutableRefObject} */ const translatorRef = useRef(null) - const translatorRunningRef = useRef(false) + + // Translator Stats + const [usageInformation, setUsageInformation] = useState(/** @type {typeof Translator.prototype.usage}*/(null)) + const [RPMInfomation, setRPMInformation] = useState(0) - const toggleAPIInputVisibility = () => setIsAPIInputVisible(!isAPIInputVisible); + // Persistent Data Restoration + useEffect(() => { + setAPIValue(localStorage.getItem(OPENAI_API_KEY) ?? "") + }, []) function setAPIKey(value) { localStorage.setItem(OPENAI_API_KEY, value) @@ -49,12 +64,14 @@ export function TranslatorApplication() { console.log("[User Interface]", "Begin Generation") translatorRunningRef.current = true setOutput([]) + setUsageInformation(null) let currentStream = "" const outputWorkingProgress = parser.fromSrt(srtInputText) const currentOutputs = [] const openai = createOpenAIClient(APIvalue, true) translatorRef.current = new Translator({ from: fromLanguage, to: toLanguage }, { openai, + cooler: coolerChatGPTAPI, onStreamChunk: (data) => { currentStream += data setStreamOutput(currentStream) @@ -62,13 +79,24 @@ export function TranslatorApplication() { onStreamEnd: () => { currentStream = "" setStreamOutput("") + }, + moderationService: { + openai, + cooler: coolerOpenAIModerator } }, { + useModerator: useModerator, createChatCompletionRequest: { - temperature: 0, + model: model, + temperature: temperature, stream: true }, }) + + if (systemInstruction) { + translatorRef.current.systemInstruction = systemInstruction + } + try { for await (const output of translatorRef.current.translateLines(inputs)) { if (!translatorRunningRef.current) { @@ -80,6 +108,8 @@ export function TranslatorApplication() { const srtEntry = outputWorkingProgress[output.index - 1] srtEntry.text = output.finalTransform setOutput([...currentOutputs]) + setUsageInformation(translatorRef.current.usage) + setRPMInformation(translatorRef.current.services.cooler?.rate) } console.log({ sourceInputWorkingCopy: outputWorkingProgress }) setSrtOutputText(parser.toSrt(outputWorkingProgress)) @@ -100,22 +130,17 @@ export function TranslatorApplication() { } } - useEffect(() => { - setAPIValue(localStorage.getItem(OPENAI_API_KEY) ?? "") - }, []) - return ( <>
generate(e)}>
- + -
+
setAPIKey(value)} @@ -142,6 +167,7 @@ export function TranslatorApplication() { type="text" label="From Language" placeholder="Auto" + autoComplete='on' value={fromLanguage} onValueChange={setFromLanguage} /> @@ -150,10 +176,55 @@ export function TranslatorApplication() { size='sm' type="text" label="To Language" + autoComplete='on' value={toLanguage} onValueChange={setToLanguage} />
+ +
+