gahanmakwana commited on
Commit
30de1f3
·
1 Parent(s): e5073bf
Files changed (4) hide show
  1. app.py +35 -42
  2. requirements.txt +4 -4
  3. static/style.css +57 -51
  4. templates/index.html +30 -46
app.py CHANGED
@@ -1,55 +1,48 @@
 
 
1
  import os
2
- from flask import Flask, render_template, request, send_from_directory
3
- from werkzeug.utils import secure_filename
4
  from paddleocr import PaddleOCR
 
5
 
6
  app = Flask(__name__)
7
-
8
- # Configuration
9
- UPLOAD_FOLDER = 'uploads'
10
  app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
11
- os.makedirs(UPLOAD_FOLDER, exist_ok=True)
12
- ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
13
 
14
- def allowed_file(filename):
15
- return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
16
 
17
- # Initialize PaddleOCR (CPU mode)
18
- ocr = PaddleOCR(use_angle_cls=True, lang='en')
19
 
20
  @app.route('/', methods=['GET', 'POST'])
21
  def index():
22
- filename = None
23
  extracted_text = None
24
- error = None
25
 
26
  if request.method == 'POST':
27
- file = request.files.get('image')
28
- if not file or file.filename == '' or not allowed_file(file.filename):
29
- error = "Please upload a valid image file (png/jpg/jpeg/gif)."
30
- else:
31
- # Save the uploaded file
32
- filename = secure_filename(file.filename)
33
- filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
34
- file.save(filepath)
35
-
36
- # Run OCR on the saved image
37
- result = ocr.ocr(filepath, cls=True)
38
- # Flatten nested results if needed
39
- if isinstance(result, list) and len(result) == 1 and isinstance(result[0], list):
40
- result = result[0]
41
- # Extract text lines
42
- lines = [line[1][0] for line in result]
43
- extracted_text = "\n".join(lines) if lines else "No text detected."
44
-
45
- return render_template('index.html', filename=filename,
46
- extracted_text=extracted_text, error=error)
47
-
48
- @app.route('/uploads/<filename>')
49
- def uploaded_file(filename):
50
- return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
51
-
52
- if __name__ == '__main__':
53
- # Use the PORT environment variable if provided by Render, else 5000
54
- port = int(os.environ.get('PORT', 5000))
55
- app.run(host='0.0.0.0', port=port)
 
1
+ # app.py
2
+ from flask import Flask, render_template, request, redirect, flash, url_for
3
  import os
 
 
4
  from paddleocr import PaddleOCR
5
+ from werkzeug.utils import secure_filename
6
 
7
  app = Flask(__name__)
8
+ app.secret_key = os.environ.get('SECRET_KEY', 'change-this') # Replace in production
9
+ UPLOAD_FOLDER = os.path.join('static', 'uploads')
 
10
  app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
 
 
11
 
12
+ # Ensure upload directory exists
13
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
14
 
15
+ # Initialize PaddleOCR once (CPU mode, English; angle_cls=False speeds up simple text)
16
+ ocr = PaddleOCR(use_angle_cls=False, use_gpu=False, lang='en')
17
 
18
  @app.route('/', methods=['GET', 'POST'])
19
  def index():
 
20
  extracted_text = None
21
+ image_file = None
22
 
23
  if request.method == 'POST':
24
+ # Check file in request
25
+ if 'image' not in request.files:
26
+ flash('No file part in the request.')
27
+ return redirect(request.url)
28
+ file = request.files['image']
29
+ if file.filename == '':
30
+ flash('No image selected.')
31
+ return redirect(request.url)
32
+
33
+ # Save uploaded file
34
+ filename = secure_filename(file.filename)
35
+ file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
36
+ file.save(file_path)
37
+
38
+ # Run PaddleOCR on the saved image (CPU mode)
39
+ result = ocr.ocr(file_path, cls=False)
40
+ # Collect recognized text lines
41
+ lines = []
42
+ for res_line in result:
43
+ for box, (txt, prob) in res_line:
44
+ lines.append(txt)
45
+ extracted_text = "\n".join(lines)
46
+ image_file = filename
47
+
48
+ return render_template('index.html', extracted_text=extracted_text, image_file=image_file)
 
 
 
 
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- Flask>=2.0
2
- gunicorn
3
- paddlepaddle
4
  paddleocr>=2.0.1
5
- opencv-python-headless
 
 
1
+ Flask>=2.0.0
2
+ gunicorn>=20.1.0
 
3
  paddleocr>=2.0.1
4
+ paddlepaddle>=2.0.0
5
+ opencv-python-headless>=4.8.0
static/style.css CHANGED
@@ -103,70 +103,76 @@ button:hover {
103
  transform: translate(-50%, -50%);
104
  z-index: 1000;
105
  } */
 
106
  body {
107
- font-family: 'Poppins', sans-serif;
108
- background: linear-gradient(135deg, #74ebd5, #ACB6E5);
109
- min-height: 100vh;
110
- display: flex;
111
- justify-content: center;
112
- align-items: center;
113
  margin: 0;
 
114
  }
115
-
116
  .container {
117
- background: #fff;
118
- padding: 30px 40px;
119
- border-radius: 20px;
120
- box-shadow: 0 10px 30px rgba(0,0,0,0.2);
121
  max-width: 600px;
122
- width: 100%;
123
- animation: fadeIn 1s ease-in;
 
 
 
124
  }
125
-
126
- h1 {
127
- margin-bottom: 20px;
128
- color: #333;
129
- font-weight: 600;
 
130
  }
131
-
132
- .upload-form {
133
  display: flex;
134
- flex-direction: column;
135
- gap: 15px;
136
- margin-bottom: 30px;
137
  }
138
-
139
- #spinner {
140
- position: fixed;
141
- top: 50%; left: 50%;
142
- transform: translate(-50%, -50%);
143
- z-index: 1000;
144
  }
145
-
146
- .preview img, #result-img {
147
- max-width: 100%;
148
- border-radius: 10px;
149
- border: 1px solid #ddd;
150
- margin-top: 10px;
 
151
  }
152
-
153
- .output, #extracted-text {
154
- background: #f9f9f9;
155
- padding: 15px;
156
- border-radius: 10px;
157
- text-align: left;
 
 
 
 
 
 
158
  white-space: pre-wrap;
159
- margin-top: 10px;
160
  }
161
-
162
- .error {
163
- color: red;
164
- font-weight: bold;
165
- margin-top: 10px;
 
 
166
  }
167
-
168
- @keyframes fadeIn {
169
- from { opacity: 0; transform: translateY(20px); }
170
- to { opacity: 1; transform: translateY(0); }
 
 
 
171
  }
172
 
 
103
  transform: translate(-50%, -50%);
104
  z-index: 1000;
105
  } */
106
+ /* static/style.css */
107
  body {
108
+ background: #f0f2f5;
109
+ font-family: 'Segoe UI', Tahoma, sans-serif;
110
+ color: #333;
 
 
 
111
  margin: 0;
112
+ padding: 0;
113
  }
 
114
  .container {
 
 
 
 
115
  max-width: 600px;
116
+ margin: 40px auto;
117
+ background: #fff;
118
+ border-radius: 8px;
119
+ padding: 20px;
120
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
121
  }
122
+ h1, h2 {
123
+ color: #444;
124
+ margin-bottom: 10px;
125
+ }
126
+ p {
127
+ color: #666;
128
  }
129
+ form {
130
+ margin-top: 20px;
131
  display: flex;
132
+ gap: 10px;
 
 
133
  }
134
+ input[type="file"] {
135
+ flex: 1;
136
+ padding: 8px;
137
+ border: 1px solid #ccc;
138
+ border-radius: 4px;
 
139
  }
140
+ button {
141
+ background-color: #007BFF;
142
+ color: white;
143
+ border: none;
144
+ padding: 8px 16px;
145
+ border-radius: 4px;
146
+ cursor: pointer;
147
  }
148
+ button:hover {
149
+ background-color: #0056b3;
150
+ }
151
+ .result, .image-preview {
152
+ margin-top: 20px;
153
+ padding: 10px;
154
+ border-top: 1px solid #e1e1e1;
155
+ }
156
+ .result pre {
157
+ background: #f8f9fa;
158
+ padding: 10px;
159
+ border-radius: 4px;
160
  white-space: pre-wrap;
 
161
  }
162
+ .flashes {
163
+ list-style: none;
164
+ padding: 10px;
165
+ background: #ffe0e0;
166
+ border: 1px solid #ffb3b3;
167
+ border-radius: 4px;
168
+ color: #a94442;
169
  }
170
+ .flashes li {
171
+ margin: 5px 0;
172
+ }
173
+ img {
174
+ max-width: 100%;
175
+ height: auto;
176
+ border-radius: 4px;
177
  }
178
 
templates/index.html CHANGED
@@ -1,59 +1,43 @@
 
1
  <!DOCTYPE html>
2
- <html lang="en">
3
  <head>
4
- <meta charset="UTF-8">
5
- <title>OCR Application</title>
6
- <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <!-- Bootstrap CSS -->
8
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
9
- <!-- Google Font -->
10
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
11
- <!-- Custom Styles -->
12
- <link href="{{ url_for('static', filename='style.css') }}" rel="stylesheet">
13
  </head>
14
  <body>
15
- <div class="container text-center">
16
- <h1 class="mt-4">OCR with PaddleOCR</h1>
17
- <!-- Upload Form -->
18
- <form id="upload-form" method="post" enctype="multipart/form-data" class="upload-form mx-auto">
19
- <input type="file" name="image" accept="image/*" class="form-control mb-3" required>
20
- <button type="submit" class="btn btn-primary">Upload &amp; Extract Text</button>
21
- </form>
22
 
23
- <!-- Spinner (shown while processing) -->
24
- <div id="spinner" class="d-none">
25
- <div class="spinner-border text-primary" role="status">
26
- <span class="visually-hidden">Processing...</span>
27
- </div>
28
- </div>
 
 
 
29
 
30
- <!-- Error Message -->
31
- {% if error %}
32
- <div class="error mt-3">{{ error }}</div>
33
- {% endif %}
34
 
35
- <!-- Display Uploaded Image Preview -->
36
- {% if filename %}
37
- <div class="preview mt-4">
38
- <h4>Uploaded Image</h4>
39
- <img id="result-img" src="{{ url_for('uploaded_file', filename=filename) }}" alt="Uploaded Image">
40
- </div>
41
  {% endif %}
42
 
43
- <!-- Display Extracted Text -->
44
- {% if extracted_text %}
45
- <div class="output mt-4">
46
- <h4>Extracted Text</h4>
47
- <pre id="extracted-text">{{ extracted_text }}</pre>
48
- </div>
49
  {% endif %}
50
  </div>
51
-
52
- <!-- Show spinner on form submit -->
53
- <script>
54
- document.getElementById('upload-form').onsubmit = () => {
55
- document.getElementById('spinner').classList.remove('d-none');
56
- };
57
- </script>
58
  </body>
59
  </html>
 
1
+ <!-- templates/index.html -->
2
  <!DOCTYPE html>
3
+ <html>
4
  <head>
5
+ <title>OCR App</title>
6
+ <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
 
 
 
 
 
 
 
7
  </head>
8
  <body>
9
+ <div class="container">
10
+ <h1>Image Text Extraction</h1>
11
+ <p>Upload an image to extract text using PaddleOCR.</p>
 
 
 
 
12
 
13
+ {% with messages = get_flashed_messages() %}
14
+ {% if messages %}
15
+ <ul class="flashes">
16
+ {% for message in messages %}
17
+ <li>{{ message }}</li>
18
+ {% endfor %}
19
+ </ul>
20
+ {% endif %}
21
+ {% endwith %}
22
 
23
+ <form method="POST" enctype="multipart/form-data">
24
+ <input type="file" name="image" accept="image/*" required>
25
+ <button type="submit">Extract Text</button>
26
+ </form>
27
 
28
+ {% if extracted_text %}
29
+ <div class="result">
30
+ <h2>Extracted Text:</h2>
31
+ <pre>{{ extracted_text }}</pre>
32
+ </div>
 
33
  {% endif %}
34
 
35
+ {% if image_file %}
36
+ <div class="image-preview">
37
+ <h2>Uploaded Image:</h2>
38
+ <img src="{{ url_for('static', filename='uploads/' + image_file) }}" alt="Uploaded Image">
39
+ </div>
 
40
  {% endif %}
41
  </div>
 
 
 
 
 
 
 
42
  </body>
43
  </html>