DenisT commited on
Commit
56d3e2f
1 Parent(s): efddbeb

refactor client problems

Browse files
Files changed (4) hide show
  1. server.py +49 -38
  2. static/index.js +37 -13
  3. static/styles.css +8 -0
  4. templates/index.html +20 -17
server.py CHANGED
@@ -9,8 +9,10 @@ from typing import Dict
9
 
10
  import numpy as np
11
  from fastapi import FastAPI
 
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from fastapi.staticfiles import StaticFiles
 
14
  from fastapi.templating import Jinja2Templates
15
  from starlette.requests import Request
16
  from PIL import Image
@@ -50,44 +52,53 @@ def home(request: Request):
50
 
51
  @app.post("/predict")
52
  def predict(request: Dict):
53
- image = request["image"]
54
-
55
- # Decode base64-encoded image
56
- image = base64.b64decode(image)
57
- image = Image.open(io.BytesIO(image))
58
- image_path = "image.png"
59
- translated_image_path = "translated_image.png"
60
-
61
- # Save the image locally
62
- image.save(image_path)
63
-
64
- results = predict_bounding_boxes(object_detection_model, image_path)
65
- image = np.array(image)
66
-
67
- for result in results:
68
- x1, y1, x2, y2, _, _ = result
69
- detected_image = image[int(y1):int(y2), int(x1):int(x2)]
70
- im = Image.fromarray(np.uint8((detected_image)*255))
71
- text = get_text_from_image(im)
72
- detected_image, cont = process_contour(detected_image)
73
- text_translated = translate_manga(text)
74
- add_text(detected_image, text_translated, cont)
75
-
76
- # Display the translated image
77
- result_image = Image.fromarray(image, 'RGB')
78
- result_image.save(translated_image_path)
79
-
80
- # Convert the image to base64
81
- buff = io.BytesIO()
82
- result_image.save(buff, format="PNG")
83
- img_str = base64.b64encode(buff.getvalue()).decode("utf-8")
84
-
85
- # Clean up
86
- os.remove(image_path)
87
- os.remove(translated_image_path)
88
-
89
- return {"image": img_str}
90
-
 
 
 
 
 
 
 
 
 
91
 
92
  if __name__ == '__main__':
93
  uvicorn.run('app:app', host='localhost', port=8000, reload=True)
 
9
 
10
  import numpy as np
11
  from fastapi import FastAPI
12
+ from fastapi import status
13
  from fastapi.middleware.cors import CORSMiddleware
14
  from fastapi.staticfiles import StaticFiles
15
+ from fastapi.responses import JSONResponse
16
  from fastapi.templating import Jinja2Templates
17
  from starlette.requests import Request
18
  from PIL import Image
 
52
 
53
  @app.post("/predict")
54
  def predict(request: Dict):
55
+ try:
56
+
57
+ image = request["image"]
58
+
59
+ # Decode base64-encoded image
60
+ image = base64.b64decode(image)
61
+ image = Image.open(io.BytesIO(image))
62
+ image_path = "image.png"
63
+ translated_image_path = "translated_image.png"
64
+
65
+ # Save the image locally
66
+ image.save(image_path)
67
+
68
+ results = predict_bounding_boxes(object_detection_model, image_path)
69
+ image = np.array(image)
70
+
71
+ for result in results:
72
+ x1, y1, x2, y2, _, _ = result
73
+ detected_image = image[int(y1):int(y2), int(x1):int(x2)]
74
+ im = Image.fromarray(np.uint8((detected_image)*255))
75
+ text = get_text_from_image(im)
76
+ detected_image, cont = process_contour(detected_image)
77
+ text_translated = translate_manga(text)
78
+ add_text(detected_image, text_translated, cont)
79
+
80
+ # Display the translated image
81
+ result_image = Image.fromarray(image, 'RGB')
82
+ result_image.save(translated_image_path)
83
+
84
+ # Convert the image to base64
85
+ buff = io.BytesIO()
86
+ result_image.save(buff, format="PNG")
87
+ img_str = base64.b64encode(buff.getvalue()).decode("utf-8")
88
+
89
+ # Clean up
90
+ os.remove(image_path)
91
+ os.remove(translated_image_path)
92
+
93
+ return {"image": img_str}
94
+ except Exception as e:
95
+ # Return with status code 500 (Internal Server Error) if an error occurs
96
+ return JSONResponse(
97
+ status_code=500,
98
+ content={
99
+ "code": status.HTTP_500_INTERNAL_SERVER_ERROR,
100
+ "message": "Internal Server Error"}
101
+ )
102
 
103
  if __name__ == '__main__':
104
  uvicorn.run('app:app', host='localhost', port=8000, reload=True)
static/index.js CHANGED
@@ -1,20 +1,24 @@
1
  "use strict";
2
 
3
- async function predict() {
4
- const fileInput = document.getElementById('fileInput');
5
- const translateButton = document.getElementById('translateButton');
6
- const spinner = document.getElementById('spinner');
7
- const inputImage = document.getElementById('inputImage');
8
- const outputImage = document.getElementById('outputImage');
9
- const downloadButton = document.getElementById('downloadButton');
10
 
11
- downloadButton.style.display = 'none';
12
 
 
13
  if (fileInput.files.length === 0) {
14
  alert('Please select an image file.');
15
  return;
16
  }
17
 
 
 
 
 
18
  const file = fileInput.files[0];
19
  const reader = new FileReader();
20
 
@@ -25,9 +29,16 @@ async function predict() {
25
  };
26
 
27
  reader.readAsDataURL(file);
 
28
 
29
- translateButton.style.display = 'none';
30
- spinner.style.display = 'block';
 
 
 
 
 
 
31
 
32
  reader.onloadend = async function () {
33
  const base64Image = reader.result.split(',')[1];
@@ -42,16 +53,29 @@ async function predict() {
42
 
43
  const result = await response.json();
44
  if (response.status !== 200) {
45
- alert(result.error);
 
 
 
 
 
 
 
 
46
  return;
47
  }
 
48
  outputImage.src = `data:image/jpeg;base64,${result.image}`;
49
  outputImage.style.display = 'block';
50
- downloadButton.href = outputImage.src;
51
  downloadButton.style.display = 'block';
52
 
53
  translateButton.style.display = 'inline-block';
54
  spinner.style.display = 'none';
55
-
56
  };
 
 
 
 
 
57
  }
 
1
  "use strict";
2
 
3
+ const fileInput = document.getElementById('fileInput');
4
+ const translateButton = document.getElementById('translateButton');
5
+ const spinner = document.getElementById('spinner');
6
+ const inputImage = document.getElementById('inputImage');
7
+ const outputImage = document.getElementById('outputImage');
8
+ const downloadButton = document.getElementById('downloadButton');
 
9
 
10
+ downloadButton.style.display = 'none';
11
 
12
+ fileInput.addEventListener('change', () => {
13
  if (fileInput.files.length === 0) {
14
  alert('Please select an image file.');
15
  return;
16
  }
17
 
18
+ // Clear the previous images
19
+ inputImage.src = '';
20
+ outputImage.src = '';
21
+
22
  const file = fileInput.files[0];
23
  const reader = new FileReader();
24
 
 
29
  };
30
 
31
  reader.readAsDataURL(file);
32
+ });
33
 
34
+ async function predict() {
35
+ if (fileInput.files.length === 0) {
36
+ alert('Please select an image file.');
37
+ return;
38
+ }
39
+
40
+ const file = fileInput.files[0];
41
+ const reader = new FileReader();
42
 
43
  reader.onloadend = async function () {
44
  const base64Image = reader.result.split(',')[1];
 
53
 
54
  const result = await response.json();
55
  if (response.status !== 200) {
56
+ alert(result.message);
57
+
58
+ // Reset the input
59
+ fileInput.value = '';
60
+ inputImage.style.display = 'none';
61
+ outputImage.style.display = 'none';
62
+ spinner.style.display = 'none';
63
+ downloadButton.style.display = 'none';
64
+ translateButton.style.display = 'block';
65
  return;
66
  }
67
+
68
  outputImage.src = `data:image/jpeg;base64,${result.image}`;
69
  outputImage.style.display = 'block';
70
+ downloadButton.querySelector('a').href = outputImage.src;
71
  downloadButton.style.display = 'block';
72
 
73
  translateButton.style.display = 'inline-block';
74
  spinner.style.display = 'none';
 
75
  };
76
+
77
+ reader.readAsDataURL(file);
78
+
79
+ translateButton.style.display = 'none';
80
+ spinner.style.display = 'block';
81
  }
static/styles.css CHANGED
@@ -26,6 +26,14 @@ a {
26
  padding: 20px;
27
  }
28
 
 
 
 
 
 
 
 
 
29
  input[type="file"] {
30
  margin: 20px 0;
31
  padding: 10px;
 
26
  padding: 20px;
27
  }
28
 
29
+ .actions {
30
+ display: flex;
31
+ justify-content: center;
32
+ align-items: center;
33
+ flex-flow: column wrap;
34
+ gap: 1rem;
35
+ }
36
+
37
  input[type="file"] {
38
  margin: 20px 0;
39
  padding: 10px;
templates/index.html CHANGED
@@ -9,20 +9,32 @@
9
  <body>
10
  <header>
11
  <h1>Manga Translator</h1>
 
 
 
 
 
 
 
 
12
  </header>
13
  <div class="container">
14
- <input type="file" id="fileInput" accept="image/*" />
15
- <br />
16
- <button id="translateButton" onclick="predict()">Translate</button>
 
 
 
 
 
 
 
 
17
  <div id="spinner" class="spinner" style="display: none"></div>
18
  <div class="images-container">
19
  <div class="image-wrapper">
20
  <h3>Original Image</h3>
21
- <img
22
- id="inputImage"
23
- alt="Selected Manga"
24
- style="max-width: 100%"
25
- />
26
  </div>
27
  <div class="image-wrapper">
28
  <h3>Translated Image</h3>
@@ -31,15 +43,6 @@
31
  alt="Translated Manga"
32
  style="max-width: 100%; display: none"
33
  />
34
- <button>
35
- <a
36
- id="downloadButton"
37
- href="#"
38
- download="translated_manga.jpg"
39
- style="display: none"
40
- >Download Translated Image</a
41
- >
42
- </button>
43
  </div>
44
  </div>
45
  </div>
 
9
  <body>
10
  <header>
11
  <h1>Manga Translator</h1>
12
+ <p>
13
+ Translate your manga panels from <b>Japanese</b> to
14
+ <b>English</b>!
15
+ </p>
16
+ <p>
17
+ Make sure the image is clear, black and white, and has text in
18
+ Japanese.
19
+ </p>
20
  </header>
21
  <div class="container">
22
+ <div class="actions">
23
+ <input type="file" id="fileInput" accept="image/*" />
24
+ <button id="translateButton" onclick="predict()">
25
+ Translate
26
+ </button>
27
+ <button id="downloadButton" style="display: none">
28
+ <a href="#" download="translated_manga.jpg">
29
+ Download Translated Image
30
+ </a>
31
+ </button>
32
+ </div>
33
  <div id="spinner" class="spinner" style="display: none"></div>
34
  <div class="images-container">
35
  <div class="image-wrapper">
36
  <h3>Original Image</h3>
37
+ <img id="inputImage" style="max-width: 100%" />
 
 
 
 
38
  </div>
39
  <div class="image-wrapper">
40
  <h3>Translated Image</h3>
 
43
  alt="Translated Manga"
44
  style="max-width: 100%; display: none"
45
  />
 
 
 
 
 
 
 
 
 
46
  </div>
47
  </div>
48
  </div>