Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -52,7 +52,7 @@ logging.basicConfig(
|
|
| 52 |
# -------------------------------------------------------------------------
|
| 53 |
# 🤖 Roboflow configuration
|
| 54 |
# -------------------------------------------------------------------------
|
| 55 |
-
ROBOFLOW_API_KEY = "JKuvVbqDgv4mBdVM0fUE" # ✅
|
| 56 |
PROJECT_NAME = "model_verification_project"
|
| 57 |
VERSION_NUMBER = 2
|
| 58 |
|
|
@@ -60,129 +60,65 @@ VERSION_NUMBER = 2
|
|
| 60 |
os.environ["ROBOFLOW_API_KEY"] = ROBOFLOW_API_KEY
|
| 61 |
|
| 62 |
# -------------------------------------------------------------------------
|
| 63 |
-
# ✍️ Handwriting model (Hugging Face Space)
|
| 64 |
# -------------------------------------------------------------------------
|
| 65 |
HANDWRITING_MODEL_ENDPOINT = "3morrrrr/Handwriting_Model_Inf"
|
| 66 |
|
| 67 |
-
|
| 68 |
-
# -------------------------------------------------------------------------
|
| 69 |
-
# Text and sizing configuration
|
| 70 |
-
# -------------------------------------------------------------------------
|
| 71 |
-
MIN_WIDTH_PERCENTAGE = 0.8 # minimum scaling for text width
|
| 72 |
-
TEXT_SCALE_FACTOR = 1.2 # base scale factor for text resizing
|
| 73 |
-
|
| 74 |
# -------------------------------------------------------------------------
|
| 75 |
-
#
|
| 76 |
# -------------------------------------------------------------------------
|
|
|
|
|
|
|
| 77 |
DEBUG = True
|
| 78 |
DEBUG_DIR = os.path.join(tempfile.gettempdir(), "debug_images")
|
| 79 |
os.makedirs(DEBUG_DIR, exist_ok=True)
|
| 80 |
|
| 81 |
-
logging.info(f"Debug images
|
| 82 |
logging.info(f"Using Roboflow project '{PROJECT_NAME}' (v{VERSION_NUMBER}) with API key ending in {ROBOFLOW_API_KEY[-4:]}")
|
| 83 |
logging.info(f"Using handwriting model endpoint: {HANDWRITING_MODEL_ENDPOINT}")
|
| 84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
"""
|
| 89 |
-
Format text to fit within paper boundaries
|
| 90 |
-
|
| 91 |
-
Parameters:
|
| 92 |
-
- text: The input text to format
|
| 93 |
-
- paper_width: Width of the paper in pixels
|
| 94 |
-
- char_limit: Optional character limit per line (default: calculated from paper width)
|
| 95 |
-
|
| 96 |
-
Returns:
|
| 97 |
-
- Formatted text with appropriate line breaks
|
| 98 |
-
"""
|
| 99 |
-
# Calculate character limit based on paper width if not provided
|
| 100 |
-
# This is an approximation - characters have different widths
|
| 101 |
-
if char_limit is None:
|
| 102 |
-
# Rough estimate: ~12-15 pixels per character for most fonts at reasonable size
|
| 103 |
-
pixels_per_char = 13
|
| 104 |
-
estimated_chars = max(10, int((paper_width * 0.8) / pixels_per_char))
|
| 105 |
-
char_limit = min(60, estimated_chars) # Never exceed the 60 char model limit
|
| 106 |
-
|
| 107 |
-
logging.debug(f"Formatting text with {char_limit} chars per line for paper width {paper_width}px")
|
| 108 |
-
|
| 109 |
-
# Split text by existing newlines first
|
| 110 |
-
paragraphs = text.split('\n')
|
| 111 |
-
formatted_lines = []
|
| 112 |
-
|
| 113 |
-
for paragraph in paragraphs:
|
| 114 |
-
# Skip empty paragraphs but preserve the line break
|
| 115 |
-
if not paragraph.strip():
|
| 116 |
-
formatted_lines.append('')
|
| 117 |
-
continue
|
| 118 |
-
|
| 119 |
-
words = paragraph.split(' ')
|
| 120 |
-
current_line = words[0]
|
| 121 |
-
|
| 122 |
-
for word in words[1:]:
|
| 123 |
-
# If adding this word would exceed the limit, start a new line
|
| 124 |
-
if len(current_line) + 1 + len(word) <= char_limit:
|
| 125 |
-
current_line += ' ' + word
|
| 126 |
-
else:
|
| 127 |
-
formatted_lines.append(current_line)
|
| 128 |
-
current_line = word
|
| 129 |
-
|
| 130 |
-
# Don't forget the last line
|
| 131 |
-
if current_line:
|
| 132 |
-
formatted_lines.append(current_line)
|
| 133 |
-
|
| 134 |
-
# Join lines with newlines
|
| 135 |
-
formatted_text = '\n'.join(formatted_lines)
|
| 136 |
-
logging.debug(f"Formatted text from {len(text)} chars into {len(formatted_lines)} lines")
|
| 137 |
-
|
| 138 |
-
return formatted_text
|
| 139 |
-
|
| 140 |
-
# Function to save debug images - updated to handle numpy arrays
|
| 141 |
-
def save_debug_image(image, filename, boxes=None, text=None):
|
| 142 |
if not DEBUG:
|
| 143 |
return
|
| 144 |
-
|
| 145 |
-
# Convert numpy array to PIL Image if needed
|
| 146 |
if isinstance(image, np.ndarray):
|
| 147 |
-
|
| 148 |
-
debug_img = Image.fromarray(image).convert('RGBA')
|
| 149 |
-
else: # RGB or RGBA
|
| 150 |
-
debug_img = Image.fromarray(image).convert('RGBA')
|
| 151 |
-
else:
|
| 152 |
-
debug_img = image.copy()
|
| 153 |
-
if debug_img.mode != 'RGBA':
|
| 154 |
-
debug_img = debug_img.convert('RGBA')
|
| 155 |
-
|
| 156 |
-
# Create a drawing context
|
| 157 |
-
draw = ImageDraw.Draw(debug_img)
|
| 158 |
-
|
| 159 |
-
# Draw boxes if provided
|
| 160 |
-
if boxes:
|
| 161 |
-
for label, box in boxes:
|
| 162 |
-
# Draw rectangle
|
| 163 |
-
draw.rectangle(box, outline=(255, 0, 0, 255), width=3)
|
| 164 |
-
# Draw label
|
| 165 |
-
draw.text((box[0], box[1] - 20), label, fill=(255, 0, 0, 255))
|
| 166 |
-
|
| 167 |
-
# Draw text if provided
|
| 168 |
if text:
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
# Draw text at the top of the image
|
| 177 |
-
draw.rectangle([(0, 0), (debug_img.width, 60)], fill=(0, 0, 0, 128))
|
| 178 |
-
draw.text((10, 10), text, fill=(255, 255, 255, 255), font=font)
|
| 179 |
-
|
| 180 |
-
# Save the image
|
| 181 |
-
debug_path = os.path.join(DEBUG_DIR, filename)
|
| 182 |
-
debug_img.save(debug_path)
|
| 183 |
-
logging.debug(f"Saved debug image: {debug_path}")
|
| 184 |
-
return debug_path
|
| 185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
# Improved function to detect paper angle
|
| 187 |
def detect_paper_angle(image, bounding_box):
|
| 188 |
"""
|
|
|
|
| 52 |
# -------------------------------------------------------------------------
|
| 53 |
# 🤖 Roboflow configuration
|
| 54 |
# -------------------------------------------------------------------------
|
| 55 |
+
ROBOFLOW_API_KEY = "JKuvVbqDgv4mBdVM0fUE" # ✅ your key
|
| 56 |
PROJECT_NAME = "model_verification_project"
|
| 57 |
VERSION_NUMBER = 2
|
| 58 |
|
|
|
|
| 60 |
os.environ["ROBOFLOW_API_KEY"] = ROBOFLOW_API_KEY
|
| 61 |
|
| 62 |
# -------------------------------------------------------------------------
|
| 63 |
+
# ✍️ Handwriting model (Hugging Face Space)
|
| 64 |
# -------------------------------------------------------------------------
|
| 65 |
HANDWRITING_MODEL_ENDPOINT = "3morrrrr/Handwriting_Model_Inf"
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
# -------------------------------------------------------------------------
|
| 68 |
+
# ⚙️ General configuration
|
| 69 |
# -------------------------------------------------------------------------
|
| 70 |
+
MIN_WIDTH_PERCENTAGE = 0.8
|
| 71 |
+
TEXT_SCALE_FACTOR = 1.2
|
| 72 |
DEBUG = True
|
| 73 |
DEBUG_DIR = os.path.join(tempfile.gettempdir(), "debug_images")
|
| 74 |
os.makedirs(DEBUG_DIR, exist_ok=True)
|
| 75 |
|
| 76 |
+
logging.info(f"Debug images stored in: {DEBUG_DIR}")
|
| 77 |
logging.info(f"Using Roboflow project '{PROJECT_NAME}' (v{VERSION_NUMBER}) with API key ending in {ROBOFLOW_API_KEY[-4:]}")
|
| 78 |
logging.info(f"Using handwriting model endpoint: {HANDWRITING_MODEL_ENDPOINT}")
|
| 79 |
|
| 80 |
+
# -------------------------------------------------------------------------
|
| 81 |
+
# 🧩 Helper functions
|
| 82 |
+
# -------------------------------------------------------------------------
|
| 83 |
+
def format_text_for_paper(text, paper_width):
|
| 84 |
+
"""Auto-wrap text to fit detected paper area."""
|
| 85 |
+
pixels_per_char = 13
|
| 86 |
+
est_chars = max(10, int((paper_width * 0.8) / pixels_per_char))
|
| 87 |
+
char_limit = min(60, est_chars)
|
| 88 |
+
words = text.split(" ")
|
| 89 |
+
lines, line = [], ""
|
| 90 |
+
for word in words:
|
| 91 |
+
if len(line + " " + word) <= char_limit:
|
| 92 |
+
line += (" " if line else "") + word
|
| 93 |
+
else:
|
| 94 |
+
lines.append(line)
|
| 95 |
+
line = word
|
| 96 |
+
if line:
|
| 97 |
+
lines.append(line)
|
| 98 |
+
return "\n".join(lines)
|
| 99 |
|
| 100 |
+
def save_debug_image(image, filename, text=None):
|
| 101 |
+
"""Save debug images for visualization."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
if not DEBUG:
|
| 103 |
return
|
|
|
|
|
|
|
| 104 |
if isinstance(image, np.ndarray):
|
| 105 |
+
image = Image.fromarray(image)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
if text:
|
| 107 |
+
draw = ImageDraw.Draw(image)
|
| 108 |
+
draw.rectangle([(0, 0), (image.width, 60)], fill=(0, 0, 0, 128))
|
| 109 |
+
draw.text((10, 10), text, fill=(255, 255, 255))
|
| 110 |
+
path = os.path.join(DEBUG_DIR, filename)
|
| 111 |
+
image.save(path)
|
| 112 |
+
logging.debug(f"Saved debug image: {path}")
|
| 113 |
+
return path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
|
| 115 |
+
# -------------------------------------------------------------------------
|
| 116 |
+
# 🧠 Load Roboflow + HuggingFace models
|
| 117 |
+
# -------------------------------------------------------------------------
|
| 118 |
+
rf = Roboflow(api_key=ROBOFLOW_API_KEY)
|
| 119 |
+
project = rf.workspace().project(PROJECT_NAME)
|
| 120 |
+
model = project.version(VERSION_NUMBER).model
|
| 121 |
+
client = Client(HANDWRITING_MODEL_ENDPOINT)
|
| 122 |
# Improved function to detect paper angle
|
| 123 |
def detect_paper_angle(image, bounding_box):
|
| 124 |
"""
|