Browse Source

AI翻译功能

locky 4 months ago
parent
commit
d74951203e
2 changed files with 106 additions and 10 deletions
  1. 88 1
      controller/LangArea.py
  2. 18 9
      web/langTab.html

+ 88 - 1
controller/LangArea.py

@@ -13,6 +13,9 @@
 """
 
 import json
+
+import requests
+from django.db.models import Min, Q
 from django.http import HttpResponse
 
 from django.views.generic import TemplateView
@@ -59,6 +62,8 @@ class LangAreaView(TemplateView):
                 return self.do_query(request_dict, response, userID)
             elif operation == 'export':
                 return self.do_export(request_dict, response, userID)
+            elif operation == 'AITranslation':
+                return self.ai_translation(request_dict, response)
             else:
                 return response.json(414)
         else:
@@ -155,7 +160,6 @@ class LangAreaView(TemplateView):
                 values('word_key', 'langvalmodel__word_val').order_by('addTime')
             res = {}
             for r in res_qs:
-                print(r['langvalmodel__word_val'])
                 if r['langvalmodel__word_val']:
                     res[r['word_key']] = r['langvalmodel__word_val']
                 elif en_kv[r['word_key']]:
@@ -205,6 +209,89 @@ class LangAreaView(TemplateView):
         response['Content-Disposition'] = 'attachment;filename="lang.txt"'
         return response
 
+    @classmethod
+    def ai_translation(cls, request_dict, response):
+        lang_id = request_dict.get('lang_id', None)
+        if not lang_id:
+            return response.json(444)
+        lang_id = int(lang_id)
+        # 英文不翻译
+        if lang_id == 20:
+            return response.json(0)
+        try:
+            # 查询语种
+            lang_area_qs = LangAreaModel.objects.filter(id=lang_id).values('lang')
+            if not lang_area_qs.exists():
+                return response.json(444)
+            lang = lang_area_qs[0]['lang']
+            # 查询英文不为空,并根据lk_id去重
+            lang_val_qs = LangValModel.objects.filter(~Q(word_val=''), Q(la_id=20)).values('lk_id').\
+                annotate(word_val=Min('word_val')).order_by('lk_id')
+            if not lang_val_qs.exists():
+                return response.json(444)
+            bulk = []
+            now_time = int(time.time())
+            # 根据lk_id查询有无对应语种,没有则调用API翻译并保存数据
+            for lang_val in lang_val_qs:
+                lk_id = lang_val['lk_id']
+                lang_qs = LangValModel.objects.filter(la_id=lang_id, lk_id=lk_id).values('word_val')
+                if not lang_qs.exists():
+                    # 翻译内容不存在,进行AI翻译
+                    word_val_en = lang_val['word_val']
+                    word_val = cls.deepseek_translation(lang, word_val_en)
+                    lang_val_model = LangValModel(
+                        lk_id=lk_id, la_id=lang_id, word_val=word_val, addTime=now_time, updTime=now_time, status=1
+                    )
+                    bulk.append(lang_val_model)
+                else:
+                    # 翻译内容为空,进行AI翻译
+                    if lang_qs[0]['word_val'] == '':
+                        word_val_en = lang_val['word_val']
+                        word_val = cls.deepseek_translation(lang, word_val_en)
+                        lang_qs.update(word_val=word_val, addTime=now_time, updTime=now_time, status=1)
+            LangValModel.objects.bulk_create(bulk)
+            return response.json(0)
+        except Exception as e:
+            return response.json(10, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @staticmethod
+    def deepseek_translation(lang, word_val_en):
+        url = "https://maas-cn-southwest-2.modelarts-maas.com/v1/infers/271c9332-4aa6-4ff5-95b3-0cf8bd94c394/v1/chat/completions"  # API地址
+        api_key = "obPL2x_aJKJpm11JLz1GFKTfXcwF_2ra4bdogC1pbFgV7GobDRW3AD6iHPxCvDZqM87buJ3xyT6-bl1xiDV6aQ"  # 把yourApiKey替换成已获取的API Key
+
+        # Send request.
+        headers = {
+            'Content-Type': 'application/json',
+            'Authorization': f'Bearer {api_key}'
+        }
+        content = '请将以下英文内容翻译成{},忽略转义符和占位符,直接返回翻译好的内容即可:{}'.format(lang, word_val_en)
+        data = {
+            "model": "DeepSeek-V3",  # 模型名称
+            "max_tokens": 1024,  # 最大输出token数
+            "messages": [
+                {"role": "system",
+                 "content": "你是一名翻译家"},
+                {"role": "user", "content": content}
+            ],
+            # 是否开启流式推理, 默认为False, 表示不开启流式推理
+            "stream": False,
+            # 在流式输出时是否展示使用的token数目。只有当stream为True时改参数才会生效。
+            # "stream_options": { "include_usage": True },
+            # 控制采样随机性的浮点数,值较低时模型更具确定性,值较高时模型更具创造性。"0"表示贪婪取样。默认为0.6。
+            "temperature": 0.6
+        }
+        # 延迟请求
+        time.sleep(1.1)
+        response = requests.post(url, headers=headers, data=json.dumps(data), verify=False, timeout=10)
+        text = json.loads(response.text)
+        choices = text.get('choices')
+        content = ''
+        if choices is None:
+            print(text)
+        else:
+            content = choices[0]['message']['content']
+        return content
+
     def do_download_avss(self, id):
         content = ''
         en_result = self.get_area_language(20)

+ 18 - 9
web/langTab.html

@@ -20,6 +20,12 @@
     <script src="js/pages.js"></script>
 </head>
 <body>
+<!-- 加载动画 -->
+<div id="loading-overlay" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 1000;">
+    <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-size: 20px;">
+        <i class="fa fa-spinner fa-spin"></i> 正在翻译中,请稍后...
+    </div>
+</div>
 <div class="clear-backend">
     <div class="avatar">
         <div>
@@ -211,7 +217,7 @@
             let new_searchTool_btn = 'New Search Tool:<a href="#" title="new_searchTool" onclick="dlFunc(\'' + obj['id'] + '\',6)"><i class="fa fa-download"></i></a>';
             let old_searchTool_btn = 'Old Search Tool:<a href="#" title="new_searchTool" onclick="dlFunc(\'' + obj['id'] + '\',7)"><i class="fa fa-download"></i></a>';
             let flutter_btn = 'flutter:<a href="#" title="flutter" onclick="dlFunc(\'' + obj['id'] + '\',8)"><i class="fa fa-download"></i></a>';
-            let translate_btn = '一键翻译:<a href="#" title="translate" onclick="translate(\'' + obj['id'] + '\')"><i class="fa fa-language"></i></a>';
+            let translate_btn = '一键翻译:<a href="#" title="translate" onclick="ai_translate(\'' + obj['id'] + '\')"><i class="fa fa-language"></i></a>';
             let np = '&nbsp;&nbsp;&nbsp;'
             body_html += '<tr><td>' + obj['id'] + '</td><td>' + obj['lang'] + '</td><td>' + edit_btn + np + del_btn
                 + np + idw_btn + np + adw_btn + np + avssw_btn + np + link_ios_tbn + np + link_android_btn + np + new_searchTool_btn + np + old_searchTool_btn + np + flutter_btn + np + np + np + translate_btn +'</td></tr>'
@@ -389,21 +395,24 @@
         }
     }
 
-    function translate(lang_id) {
+    function ai_translate(lang_id) {
         console.log('一键翻译')
-        console.log('lang_id')
+        console.log('lang_id:' + lang_id)
         let get_params = {
             'token': $.cookie('access_token'),
             'lang_id': lang_id
         };
 
+        $('#loading-overlay').show();
         $.get(http_ip_prot + 'langArea/AITranslation', get_params, function (data) {
-            if (data['code'] == 0) {
-                alert(data['msg']);
-            } else {
-                alert(data['msg']);
-            }
-        });
+            console.log(data)
+            alert(data)
+            $('#loading-overlay').hide();
+        }).fail(function (jqXHR, textStatus, errorThrown) {
+        // 隐藏加载动画
+        $('#loading-overlay').hide();
+        alert("Request failed: " + textStatus + ", " + errorThrown);
+    });
     }
 </script>
 </body>