Browse Source

Merge pull request #2210 from visuddhinanda/agile

add ai translate
visuddhinanda 1 year ago
parent
commit
8ab9b55f82

+ 61 - 0
dashboard/src/components/ai/AiTranslate.tsx

@@ -0,0 +1,61 @@
+import { Button, Typography } from "antd";
+import { useState } from "react";
+import { LoadingOutlined } from "@ant-design/icons";
+
+import Marked from "../general/Marked";
+import { post } from "../../request";
+import { IAiTranslateRequest, IAiTranslateResponse } from "../api/ai";
+
+const { Text } = Typography;
+
+interface IAiTranslateWidget {
+  origin?: string;
+}
+
+const AiTranslate = ({ origin }: IAiTranslateWidget) => {
+  const [loading, setLoading] = useState(false);
+  const [translation, setTranslation] = useState<string>();
+  const [error, setError] = useState<string>();
+  const onTranslate = (origin?: string) => {
+    if (typeof origin === "undefined") {
+      return;
+    }
+    const url = "/v2/ai-translate";
+    const data = { origin: origin };
+    console.info("api request", url, data);
+    setLoading(true);
+    post<IAiTranslateRequest, IAiTranslateResponse>(url, data)
+      .then((json) => {
+        console.debug("api response", json);
+        if (json.ok) {
+          setTranslation(json.data.choices[0].message.content);
+        } else {
+          setError(json.message);
+        }
+      })
+      .finally(() => setLoading(false));
+  };
+
+  if (translation) {
+    return <Marked text={translation} />;
+  } else if (loading) {
+    return <LoadingOutlined />;
+  } else if (error) {
+    return (
+      <div>
+        <Text type="danger">{error}</Text>
+        <Button type="link" onClick={() => onTranslate(origin)}>
+          再试一次
+        </Button>
+      </div>
+    );
+  } else {
+    return (
+      <Button type="link" onClick={() => onTranslate(origin)}>
+        AI 翻译
+      </Button>
+    );
+  }
+};
+
+export default AiTranslate;

+ 35 - 0
dashboard/src/components/api/ai.ts

@@ -0,0 +1,35 @@
+export interface IKimiResponse {
+  id: string;
+  object: string;
+  created: number;
+  model: string;
+  choices: AiChoice[];
+  usage: AiUsage;
+}
+
+export interface AiUsage {
+  prompt_tokens: number;
+  completion_tokens: number;
+  total_tokens: number;
+}
+
+export interface AiChoice {
+  index: number;
+  message: AiMessage;
+  finish_reason: string;
+}
+
+export interface AiMessage {
+  role: string;
+  content: string;
+}
+
+export interface IAiTranslateRequest {
+  origin: string;
+}
+
+export interface IAiTranslateResponse {
+  ok: boolean;
+  message: string;
+  data: IKimiResponse;
+}

+ 5 - 1
dashboard/src/components/fts/FullTextSearchResult.tsx

@@ -1,4 +1,4 @@
-import { List, Skeleton, Space, Tag, Typography } from "antd";
+import { Button, List, Skeleton, Space, Tag, Typography } from "antd";
 import { useEffect, useState } from "react";
 import { Link } from "react-router-dom";
 
@@ -8,6 +8,7 @@ import { TContentType } from "../discussion/DiscussionCreate";
 import Marked from "../general/Marked";
 import PaliText from "../template/Wbw/PaliText";
 import "./search.css";
+import AiTranslate from "../ai/AiTranslate";
 
 const { Title, Text } = Typography;
 
@@ -236,6 +237,9 @@ const FullTxtSearchResultWidget = ({
                 <div>
                   <Marked className="search_content" text={item.content} />
                 </div>
+                <div>
+                  <AiTranslate origin={item.content} />
+                </div>
               </div>
             )}
           </List.Item>