Spaces:
Runtime error
Runtime error
| # ---------------------------- | |
| # FIX FOR HUGGING FACE TIMEOUT | |
| # ---------------------------- | |
| import os | |
| os.environ["STREAMLIT_BROWSER_GATHER_USAGE_STATS"] = "false" | |
| os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" | |
| # ---------------------------- | |
| # IMPORTS | |
| # ---------------------------- | |
| import streamlit as st | |
| import tensorflow as tf | |
| from tensorflow import keras | |
| from tensorflow.keras import layers | |
| import numpy as np | |
| from PIL import Image | |
| # ---------------------------- | |
| # PAGE CONFIG | |
| # ---------------------------- | |
| st.set_page_config( | |
| page_title="Captcha OCR", | |
| page_icon="π", | |
| layout="centered" | |
| ) | |
| st.title("π Captcha OCR") | |
| st.markdown("CRNN + CTC Model Deployment") | |
| # ---------------------------- | |
| # LOAD CHARACTERS | |
| # ---------------------------- | |
| def load_characters(): | |
| with open("characters.txt", "r") as f: | |
| characters = list(f.read().strip()) | |
| return characters | |
| characters = load_characters() | |
| charToNum = layers.StringLookup(vocabulary=characters, mask_token=None) | |
| numToChar = layers.StringLookup( | |
| vocabulary=charToNum.get_vocabulary(), | |
| mask_token=None, | |
| invert=True | |
| ) | |
| # ---------------------------- | |
| # LOAD MODEL (LAZY + SAFE) | |
| # ---------------------------- | |
| def load_model(): | |
| model = keras.models.load_model( | |
| "ocr_model.keras", | |
| compile=False # IMPORTANT for memory reduction | |
| ) | |
| return model | |
| # Lazy loading (prevents reload crash) | |
| if "model" not in st.session_state: | |
| st.session_state.model = load_model() | |
| model = st.session_state.model | |
| # ---------------------------- | |
| # PREPROCESS FUNCTION | |
| # ---------------------------- | |
| def preprocess_image(image): | |
| image = image.convert("L") # grayscale | |
| image = image.resize((200, 50)) # same as training | |
| image = np.array(image).astype("float32") / 255.0 | |
| image = np.expand_dims(image, axis=-1) | |
| image = np.transpose(image, (1, 0, 2)) # IMPORTANT (match training) | |
| image = np.expand_dims(image, axis=0) | |
| return image | |
| # ---------------------------- | |
| # DECODE FUNCTION | |
| # ---------------------------- | |
| def decode_prediction(pred): | |
| input_len = np.ones(pred.shape[0]) * pred.shape[1] | |
| results = keras.backend.ctc_decode( | |
| pred, | |
| input_length=input_len, | |
| greedy=True | |
| )[0][0] | |
| output_text = [] | |
| for res in results: | |
| res = tf.gather(res, tf.where(res != -1)) | |
| res = tf.squeeze(res) | |
| text = tf.strings.reduce_join(numToChar(res)).numpy().decode("utf-8") | |
| output_text.append(text) | |
| return output_text[0] | |
| # ---------------------------- | |
| # FILE UPLOADER | |
| # ---------------------------- | |
| uploaded_file = st.file_uploader( | |
| "Upload Captcha Image", | |
| type=["png", "jpg", "jpeg"] | |
| ) | |
| if uploaded_file is not None: | |
| image = Image.open(uploaded_file) | |
| st.image(image, caption="Uploaded Image", use_column_width=True) | |
| processed = preprocess_image(image) | |
| with st.spinner("Predicting..."): | |
| prediction = model.predict(processed) | |
| text = decode_prediction(prediction) | |
| st.success(f"π― Prediction: {text}") | |