gahanmakwana commited on
Commit
e5073bf
·
1 Parent(s): 0f24da6
Files changed (4) hide show
  1. app.py +22 -18
  2. requirements.txt +3 -5
  3. static/style.css +66 -56
  4. templates/index.html +20 -11
app.py CHANGED
@@ -9,43 +9,47 @@ app = Flask(__name__)
9
  UPLOAD_FOLDER = 'uploads'
10
  app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
11
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
12
-
13
  ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
 
14
  def allowed_file(filename):
15
  return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
16
 
17
- # Initialize OCR model
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
 
25
  if request.method == 'POST':
26
  file = request.files.get('image')
27
  if not file or file.filename == '' or not allowed_file(file.filename):
28
- return render_template('index.html', error="Please upload a valid image file (png/jpg/jpeg/gif).")
29
-
30
- # Save the uploaded file
31
- filename = secure_filename(file.filename)
32
- filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
33
- file.save(filepath)
34
-
35
- # Run OCR
36
- result = ocr.ocr(filepath, cls=True)
37
- # Flatten if nested
38
- if isinstance(result, list) and len(result) == 1 and isinstance(result[0], list):
39
- result = result[0]
40
- lines = [line[1][0] for line in result]
41
- extracted_text = "\n".join(lines) if lines else "No text detected."
42
-
43
- return render_template('index.html', filename=filename, extracted_text=extracted_text)
 
 
44
 
45
  @app.route('/uploads/<filename>')
46
  def uploaded_file(filename):
47
  return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
48
 
49
  if __name__ == '__main__':
 
50
  port = int(os.environ.get('PORT', 5000))
51
  app.run(host='0.0.0.0', port=port)
 
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)
requirements.txt CHANGED
@@ -1,7 +1,5 @@
1
  Flask>=2.0
2
  gunicorn
3
- paddleocr
4
- paddlepaddle==2.5.2
5
- opencv-python
6
- numpy
7
- Pillow
 
1
  Flask>=2.0
2
  gunicorn
3
+ paddlepaddle
4
+ paddleocr>=2.0.1
5
+ opencv-python-headless
 
 
static/style.css CHANGED
@@ -104,59 +104,69 @@ button:hover {
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 { margin-bottom: 20px; color: #333; font-weight: 600; }
127
-
128
- .upload-form {
129
- display: flex;
130
- flex-direction: column;
131
- gap: 15px;
132
- }
133
-
134
- #spinner {
135
- position: fixed;
136
- top: 50%; left: 50%;
137
- transform: translate(-50%, -50%);
138
- z-index: 1000;
139
- }
140
-
141
- .preview img, #result-img {
142
- max-width: 100%;
143
- border-radius: 10px;
144
- border: 1px solid #ddd;
145
- margin-top: 10px;
146
- }
147
-
148
- .output, #extracted-text {
149
- background: #f9f9f9;
150
- padding: 15px;
151
- border-radius: 10px;
152
- text-align: left;
153
- white-space: pre-wrap;
154
- margin-top: 10px;
155
- }
156
-
157
- @keyframes fadeIn {
158
- from { opacity: 0; transform: translateY(20px); }
159
- to { opacity: 1; transform: translateY(0); }
160
- }
161
-
162
-
 
 
 
 
 
 
 
 
 
 
 
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
+
templates/index.html CHANGED
@@ -4,7 +4,7 @@
4
  <meta charset="UTF-8">
5
  <title>OCR Application</title>
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <!-- Bootstrap 5 -->
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">
@@ -14,33 +14,42 @@
14
  <body>
15
  <div class="container text-center">
16
  <h1 class="mt-4">OCR with PaddleOCR</h1>
17
-
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 & Extract Text</button>
21
  </form>
22
 
 
23
  <div id="spinner" class="d-none">
24
  <div class="spinner-border text-primary" role="status">
25
  <span class="visually-hidden">Processing...</span>
26
  </div>
27
  </div>
28
 
 
 
 
 
 
 
29
  {% if filename %}
30
- <div class="preview mt-4">
31
- <h4>Uploaded Image</h4>
32
- <img id="result-img" src="{{ url_for('uploaded_file', filename=filename) }}" alt="Uploaded Image">
33
- </div>
34
  {% endif %}
35
 
 
36
  {% if extracted_text %}
37
- <div class="output mt-4">
38
- <h4>Extracted Text</h4>
39
- <pre id="extracted-text">{{ extracted_text }}</pre>
40
- </div>
41
  {% endif %}
42
  </div>
43
 
 
44
  <script>
45
  document.getElementById('upload-form').onsubmit = () => {
46
  document.getElementById('spinner').classList.remove('d-none');
 
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">
 
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');