feat: add separated route for handling batch translations
Browse files- server/app.py +53 -16
- src/Home/index.tsx +1 -1
- test.sh +5 -0
server/app.py
CHANGED
@@ -1,38 +1,56 @@
|
|
1 |
from threading import Thread
|
2 |
-
import redis, time
|
3 |
from flask import Flask, jsonify, send_from_directory, Response, request
|
4 |
from waitress import serve
|
5 |
from flask_cors import CORS, cross_origin
|
6 |
from model import SugoiTranslator
|
7 |
-
|
|
|
|
|
8 |
|
9 |
|
10 |
queue_key = "translation_queue"
|
11 |
translated_key = "translated_temp_store"
|
12 |
redis_client = redis.Redis(host='localhost', port=6379, db=0)
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
def queue_process():
|
15 |
while True:
|
16 |
task_list = []
|
17 |
for _ in range(5):
|
18 |
-
|
19 |
-
if
|
20 |
-
|
|
|
|
|
|
|
|
|
21 |
|
22 |
if len(task_list): task_process(task_list)
|
23 |
time.sleep(0.2)
|
24 |
|
25 |
-
def task_process(
|
|
|
|
|
|
|
|
|
|
|
26 |
sugoiTranslator = SugoiTranslator()
|
27 |
translations = sugoiTranslator.translate(input_text_list)
|
|
|
|
|
28 |
for index, translation in enumerate(translations):
|
29 |
-
redis_client.hset(translated_key,
|
30 |
|
31 |
-
def query_translation(
|
32 |
for _ in range(30):
|
33 |
-
translated_text = redis_client.hget(translated_key,
|
34 |
if translated_text is not None:
|
35 |
-
redis_client.hdel(translated_key,
|
36 |
try: return translated_text.decode('utf-8')
|
37 |
except AttributeError: return translated_text
|
38 |
time.sleep(1)
|
@@ -55,23 +73,42 @@ def download_file(filename):
|
|
55 |
def download_assets(filename):
|
56 |
return send_from_directory('dist/assets', filename)
|
57 |
|
58 |
-
@app.route('/api/translate', methods= [
|
59 |
@cross_origin()
|
60 |
-
def
|
61 |
input_text = request.args.get('text')
|
62 |
if isinstance(input_text, str) and len(input_text) > 0:
|
63 |
-
|
64 |
-
|
|
|
|
|
|
|
|
|
65 |
if result is not None: return jsonify({ "text": result })
|
66 |
else: return Response(status= 529, response= "Error 529: Server overloaded")
|
67 |
return Response(status= 400)
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
if __name__ == '__main__':
|
71 |
Thread(target=queue_process, daemon=True).start()
|
72 |
-
|
73 |
try: serve(app, port= 7860)
|
74 |
except BaseException as e:
|
75 |
-
|
76 |
|
77 |
|
|
|
1 |
from threading import Thread
|
2 |
+
import redis, time, logging, sys, ast
|
3 |
from flask import Flask, jsonify, send_from_directory, Response, request
|
4 |
from waitress import serve
|
5 |
from flask_cors import CORS, cross_origin
|
6 |
from model import SugoiTranslator
|
7 |
+
import uuid, json
|
8 |
+
from typing import List, Dict, Any, Union
|
9 |
+
|
10 |
|
11 |
|
12 |
queue_key = "translation_queue"
|
13 |
translated_key = "translated_temp_store"
|
14 |
redis_client = redis.Redis(host='localhost', port=6379, db=0)
|
15 |
+
logging.basicConfig(
|
16 |
+
level=logging.INFO,
|
17 |
+
format="%(asctime)s [%(levelname)s] %(message)s",
|
18 |
+
stream=sys.stdout
|
19 |
+
)
|
20 |
|
21 |
def queue_process():
|
22 |
while True:
|
23 |
task_list = []
|
24 |
for _ in range(5):
|
25 |
+
json_string = redis_client.rpop(queue_key) # right pop
|
26 |
+
if isinstance(json_string, (bytes, bytearray)):
|
27 |
+
task: Dict[str, Any] = json.loads(json_string.decode("utf-8"))
|
28 |
+
if isinstance(task["input"], list): task_process([ task ])
|
29 |
+
elif isinstance(task["input"], str): task_list.append(task)
|
30 |
+
elif task is not None: logging.info(task)
|
31 |
+
elif json_string is not None: logging.info(json_string)
|
32 |
|
33 |
if len(task_list): task_process(task_list)
|
34 |
time.sleep(0.2)
|
35 |
|
36 |
+
def task_process(task: List[Dict[str, Any]]):
|
37 |
+
logging.info(f"translating: {task}")
|
38 |
+
input_text_list: List[str] = (
|
39 |
+
task[0]["input"] if len(task)==1 and isinstance(task[0]["input"], list)
|
40 |
+
else list(map(lambda item: item["input"], task))
|
41 |
+
)
|
42 |
sugoiTranslator = SugoiTranslator()
|
43 |
translations = sugoiTranslator.translate(input_text_list)
|
44 |
+
if len(task)==1 and isinstance(task[0]["input"], list):
|
45 |
+
return redis_client.hset(translated_key, task[0]["id"], str(translations))
|
46 |
for index, translation in enumerate(translations):
|
47 |
+
redis_client.hset(translated_key, task[index]["id"], translation)
|
48 |
|
49 |
+
def query_translation(key: str) -> Union[str, None]:
|
50 |
for _ in range(30):
|
51 |
+
translated_text = redis_client.hget(translated_key, key)
|
52 |
if translated_text is not None:
|
53 |
+
redis_client.hdel(translated_key, key)
|
54 |
try: return translated_text.decode('utf-8')
|
55 |
except AttributeError: return translated_text
|
56 |
time.sleep(1)
|
|
|
73 |
def download_assets(filename):
|
74 |
return send_from_directory('dist/assets', filename)
|
75 |
|
76 |
+
@app.route('/api/translate', methods= ["GET"])
|
77 |
@cross_origin()
|
78 |
+
def translate_get():
|
79 |
input_text = request.args.get('text')
|
80 |
if isinstance(input_text, str) and len(input_text) > 0:
|
81 |
+
task_id = str(uuid.uuid4())
|
82 |
+
redis_client.lpush(queue_key, json.dumps({
|
83 |
+
"id": task_id,
|
84 |
+
"input": input_text
|
85 |
+
})) # left push
|
86 |
+
result = query_translation(task_id)
|
87 |
if result is not None: return jsonify({ "text": result })
|
88 |
else: return Response(status= 529, response= "Error 529: Server overloaded")
|
89 |
return Response(status= 400)
|
90 |
|
91 |
+
@app.route('/api/translate', methods= ["POST"])
|
92 |
+
@cross_origin()
|
93 |
+
def translate_post():
|
94 |
+
input_texts = request.get_json().get("input_texts")
|
95 |
+
if isinstance(input_texts, list) and len(input_texts):
|
96 |
+
task_id = str(uuid.uuid4())
|
97 |
+
redis_client.lpush(queue_key, json.dumps({
|
98 |
+
"id": task_id,
|
99 |
+
"input": input_texts
|
100 |
+
})) # left push
|
101 |
+
result = query_translation(task_id)
|
102 |
+
if result is not None: return jsonify({ "translations": ast.literal_eval(result) })
|
103 |
+
else: return Response(status= 529, response= "Error 529: Server overloaded")
|
104 |
+
return Response(status= 400)
|
105 |
+
|
106 |
|
107 |
if __name__ == '__main__':
|
108 |
Thread(target=queue_process, daemon=True).start()
|
109 |
+
logging.info("Starting server...")
|
110 |
try: serve(app, port= 7860)
|
111 |
except BaseException as e:
|
112 |
+
logging.info(e)
|
113 |
|
114 |
|
src/Home/index.tsx
CHANGED
@@ -22,7 +22,7 @@ export default function App() {
|
|
22 |
const { text } = input
|
23 |
if (!text || translation.loading) { return null }
|
24 |
if (translation()) { mutate(null) }
|
25 |
-
const response = await fetch(`/api/translate?text=${text}
|
26 |
.then(response => response.status===200? response.json() : response.text())
|
27 |
.then(response => response?.text ?? response)
|
28 |
.catch(() => null)
|
|
|
22 |
const { text } = input
|
23 |
if (!text || translation.loading) { return null }
|
24 |
if (translation()) { mutate(null) }
|
25 |
+
const response = await fetch(`/api/translate?text=${text}`)
|
26 |
.then(response => response.status===200? response.json() : response.text())
|
27 |
.then(response => response?.text ?? response)
|
28 |
.catch(() => null)
|
test.sh
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
docker stop $(docker ps -q)
|
2 |
+
docker container prune #-f
|
3 |
+
docker image prune -a
|
4 |
+
docker build -t sugoi-v4:1.0 .
|
5 |
+
docker run -p 7860:7860 sugoi-v4:1.0
|