Bug573-PanBinjie #169
12
app/main.py
12
app/main.py
|
@ -2,7 +2,7 @@
|
||||||
# Copyright 2019 (C) Hui Lan <hui.lan@cantab.net>
|
# Copyright 2019 (C) Hui Lan <hui.lan@cantab.net>
|
||||||
# Written permission must be obtained from the author for commercial uses.
|
# Written permission must be obtained from the author for commercial uses.
|
||||||
###########################################################################
|
###########################################################################
|
||||||
from flask import abort
|
from flask import abort, jsonify
|
||||||
from markupsafe import escape
|
from markupsafe import escape
|
||||||
from Login import *
|
from Login import *
|
||||||
from Article import *
|
from Article import *
|
||||||
|
@ -11,6 +11,7 @@ from user_service import userService
|
||||||
from account_service import accountService
|
from account_service import accountService
|
||||||
from admin_service import adminService, ADMIN_NAME
|
from admin_service import adminService, ADMIN_NAME
|
||||||
import os
|
import os
|
||||||
|
from translate import *
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = os.urandom(32)
|
app.secret_key = os.urandom(32)
|
||||||
|
@ -118,6 +119,15 @@ def mainpage():
|
||||||
number_of_essays=number_of_essays,
|
number_of_essays=number_of_essays,
|
||||||
ratio = ratio)
|
ratio = ratio)
|
||||||
|
|
||||||
|
@app.route("/translate", methods=['POST'])
|
||||||
|
def translate_word():
|
||||||
|
data = request.get_json()
|
||||||
|
word = data.get('word', '')
|
||||||
|
from_lang = data.get('from_lang', 'en') # 假设默认源语言是英语
|
||||||
|
to_lang = data.get('to_lang', 'zh') # 假设默认目标语言是中文
|
||||||
|
result = translate(word, from_lang, to_lang)
|
||||||
|
return jsonify({'translation': result})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -17,21 +17,20 @@ function showBtnHandler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWord() {
|
function getWord() {
|
||||||
return window.getSelection ? window.getSelection() : document.selection.createRange().text;
|
return window.getSelection ? window.getSelection().toString() : document.selection.createRange().text;
|
||||||
}
|
}
|
||||||
|
|
||||||
function highLight() {
|
function highLight() {
|
||||||
if (!isHighlight) return;
|
if (!isHighlight) return;
|
||||||
let word = (getWord() + "").trim();
|
let word = (getWord() + "").trim().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "");
|
||||||
let articleContent = document.getElementById("article").innerHTML; // innerHTML保留HTML标签来保持部分格式,且适配不同的浏览器
|
let articleContent = document.getElementById("article").innerHTML; // innerHTML保留HTML标签来保持部分格式,且适配不同的浏览器
|
||||||
let pickedWords = document.getElementById("selected-words"); // words picked to the text area
|
let pickedWords = document.getElementById("selected-words"); // words picked to the text area
|
||||||
let dictionaryWords = document.getElementById("selected-words2"); // words appearing in the user's new words list
|
let dictionaryWords = document.getElementById("selected-words2"); // words appearing in the user's new words list
|
||||||
let allWords = dictionaryWords === null ? pickedWords.value + " " : pickedWords.value + " " + dictionaryWords.value;
|
let allWords = dictionaryWords === null ? pickedWords.value + " " : pickedWords.value + " " + dictionaryWords.value;
|
||||||
highlightWords = document.getElementById("selected-words3");
|
let highlightWords = document.getElementById("selected-words3");
|
||||||
allWords = highlightWords == null ? allWords : allWords + " " + highlightWords.value;
|
allWords = highlightWords == null ? allWords : allWords + " " + highlightWords.value;
|
||||||
const list = allWords.split(" "); // 将所有的生词放入一个list中
|
const list = allWords.split(" "); // 将所有的生词放入一个list中
|
||||||
if(word !== null && word !== "" && word !== " "){
|
if(word !== null && word !== "" && word !== " "){
|
||||||
let articleContent_fb2 = articleContent;
|
|
||||||
if(localStorage.getItem("nowWords").indexOf(word) !== -1 || localStorage.getItem("nowWords").indexOf(word.toLowerCase()) !== -1){
|
if(localStorage.getItem("nowWords").indexOf(word) !== -1 || localStorage.getItem("nowWords").indexOf(word.toLowerCase()) !== -1){
|
||||||
articleContent = articleContent.replace(new RegExp('<span class="highlighted">' + word + '</span>', "gi"), word);
|
articleContent = articleContent.replace(new RegExp('<span class="highlighted">' + word + '</span>', "gi"), word);
|
||||||
pickedWords.value = localStorage.getItem("nowWords").replace(word,"");
|
pickedWords.value = localStorage.getItem("nowWords").replace(word,"");
|
||||||
|
@ -58,6 +57,7 @@ function highLight() {
|
||||||
articleContent = articleContent.replace(new RegExp("\\b" + word + "\\b", "g"), "<span class='highlighted'>" + word + "</span>");
|
articleContent = articleContent.replace(new RegExp("\\b" + word + "\\b", "g"), "<span class='highlighted'>" + word + "</span>");
|
||||||
}
|
}
|
||||||
document.getElementById("article").innerHTML = articleContent;
|
document.getElementById("article").innerHTML = articleContent;
|
||||||
|
addClickEventToHighlightedWords();
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelHighlighting() {
|
function cancelHighlighting() {
|
||||||
|
@ -86,4 +86,59 @@ function toggleHighlighting() {
|
||||||
localStorage.setItem('highlightChecked', isHighlight);
|
localStorage.setItem('highlightChecked', isHighlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showWordMeaning(event) {
|
||||||
|
const word = event.target.innerText.trim().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "").toLowerCase();
|
||||||
|
const apiUrl = '/translate';
|
||||||
|
const rect = event.target.getBoundingClientRect();
|
||||||
|
const tooltipX = rect.left + window.scrollX;
|
||||||
|
const tooltipY = rect.top + window.scrollY + rect.height;
|
||||||
|
// 发送POST请求
|
||||||
|
fetch(apiUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ word: word }), // 发送的JSON数据
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
return response.json(); // 解析JSON响应
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
// 假设data.translation是翻译结果
|
||||||
|
const tooltip = document.getElementById('tooltip');
|
||||||
|
if (!tooltip) {
|
||||||
|
console.error('Tooltip element not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip.textContent = data.translation || '没有找到该单词的中文意思';
|
||||||
|
tooltip.style.left = `${tooltipX}px`;
|
||||||
|
tooltip.style.top = `${tooltipY}px`;
|
||||||
|
tooltip.style.display = 'block';
|
||||||
|
tooltip.style.position = 'absolute';
|
||||||
|
tooltip.style.background = 'yellow';
|
||||||
|
|
||||||
|
// 可以在这里添加点击事件监听器来隐藏tooltip,但注意避免内存泄漏
|
||||||
|
document.addEventListener('click', function handler(e) {
|
||||||
|
if (!tooltip.contains(e.target)) {
|
||||||
|
tooltip.style.display = 'none';
|
||||||
|
document.removeEventListener('click', handler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('There was a problem with your fetch operation:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addClickEventToHighlightedWords() {
|
||||||
|
const highlightedWords = document.querySelectorAll('.highlighted');
|
||||||
|
highlightedWords.forEach(word => {
|
||||||
|
word.addEventListener('click', showWordMeaning);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
showBtnHandler();
|
showBtnHandler();
|
|
@ -107,6 +107,7 @@
|
||||||
<button onclick="toggle_visibility('answer');">ANSWER</button>
|
<button onclick="toggle_visibility('answer');">ANSWER</button>
|
||||||
<div id="answer" style="display:none;">{{ today_article['answer'] }}</div><br/>
|
<div id="answer" style="display:none;">{{ today_article['answer'] }}</div><br/>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="tooltip"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-success" role="alert" id="not_found" style="display:none;">
|
<div class="alert alert-success" role="alert" id="not_found" style="display:none;">
|
||||||
<p class="text-muted"><span class="badge bg-success">Notes:</span><br>No article is currently available for you. You can try again a few times or mark new words in the passage to improve your level.</p>
|
<p class="text-muted"><span class="badge bg-success">Notes:</span><br>No article is currently available for you. You can try again a few times or mark new words in the passage to improve your level.</p>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import requests
|
||||||
|
import hashlib
|
||||||
|
import time
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
# 假设这是从某个配置文件中读取的
|
||||||
|
class BaiduContent:
|
||||||
|
APPID = '20240702002090356'
|
||||||
|
SECRET = '3CcqcMAJdIIpgG0uMS_f'
|
||||||
|
|
||||||
|
def generate_sign(q, salt):
|
||||||
|
"""生成百度翻译API所需的签名"""
|
||||||
|
appid = BaiduContent.APPID
|
||||||
|
secret = BaiduContent.SECRET
|
||||||
|
appid_with_data = appid + q + salt + secret
|
||||||
|
md5_obj = hashlib.md5(appid_with_data.encode('utf-8'))
|
||||||
|
return md5_obj.hexdigest()
|
||||||
|
|
||||||
|
def translate(q, from_lang, to_lang):
|
||||||
|
"""调用百度翻译API进行翻译"""
|
||||||
|
salt = str(int(time.time())) # 生成一个时间戳作为salt
|
||||||
|
sign = generate_sign(q, salt)
|
||||||
|
|
||||||
|
# 封装请求参数
|
||||||
|
params = {
|
||||||
|
'q': q,
|
||||||
|
'from': from_lang,
|
||||||
|
'to': to_lang,
|
||||||
|
'appid': BaiduContent.APPID,
|
||||||
|
'salt': salt,
|
||||||
|
'sign': sign
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构造请求URL(百度翻译API使用POST请求,并将参数放在请求体中)
|
||||||
|
url = "http://api.fanyi.baidu.com/api/trans/vip/translate"
|
||||||
|
|
||||||
|
# 发送POST请求
|
||||||
|
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
|
||||||
|
data = urlencode(params).encode('utf-8') # 注意:需要编码为bytes
|
||||||
|
|
||||||
|
response = requests.post(url, data=data, headers=headers)
|
||||||
|
|
||||||
|
# 检查响应状态码
|
||||||
|
if response.status_code == 200:
|
||||||
|
# 解析并返回JSON响应体中的翻译结果
|
||||||
|
try:
|
||||||
|
return response.json()['trans_result'][0]['dst']
|
||||||
|
except (KeyError, IndexError):
|
||||||
|
return "Invalid response from API"
|
||||||
|
else:
|
||||||
|
# 返回错误信息或状态码
|
||||||
|
return {"error": f"Failed with status code {response.status_code}"}
|
|
@ -4,5 +4,5 @@ PyYAML~=6.0
|
||||||
pony==0.7.16
|
pony==0.7.16
|
||||||
snowballstemmer==2.2.0
|
snowballstemmer==2.2.0
|
||||||
Werkzeug==2.2.2
|
Werkzeug==2.2.2
|
||||||
|
requests
|
||||||
pytest~=8.1.1
|
pytest~=8.1.1
|
Loading…
Reference in New Issue