|
|
|
|
|
import os
|
|
|
import cv2
|
|
|
from flask import Blueprint, render_template, request, jsonify
|
|
|
from pix2text import Pix2Text
|
|
|
from utils.math_solver import solve_equation
|
|
|
from controller.models.camera_to_latex import camera_to_latex
|
|
|
|
|
|
|
|
|
print("🔹 Loading Pix2Text model (mfd)...")
|
|
|
try:
|
|
|
p2t = Pix2Text(analyzer_config=dict(model_name='mfd'))
|
|
|
print("✅ Pix2Text model loaded successfully.")
|
|
|
except Exception as e:
|
|
|
print(f"❌ Pix2Text failed to initialize: {e}")
|
|
|
p2t = None
|
|
|
|
|
|
|
|
|
pix2text_bp = Blueprint('pix2text_bp', __name__)
|
|
|
|
|
|
UPLOAD_FOLDER = 'static/uploads'
|
|
|
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
|
|
|
|
|
|
|
|
def preprocess_image(image_path):
|
|
|
"""Preprocess image for better OCR results"""
|
|
|
try:
|
|
|
|
|
|
img = cv2.imread(image_path)
|
|
|
if img is None:
|
|
|
raise ValueError("Could not read image")
|
|
|
|
|
|
|
|
|
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
|
|
|
|
|
|
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
|
|
|
|
|
|
|
|
|
thresh = cv2.adaptiveThreshold(
|
|
|
blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 2
|
|
|
)
|
|
|
|
|
|
|
|
|
processed_path = os.path.join(
|
|
|
PROCESSED_FOLDER,
|
|
|
os.path.basename(image_path).replace('.', '_processed.')
|
|
|
)
|
|
|
cv2.imwrite(processed_path, thresh)
|
|
|
|
|
|
return processed_path
|
|
|
except Exception as e:
|
|
|
print(f"Preprocessing error: {e}")
|
|
|
return image_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pix2text_bp.route("/math")
|
|
|
def math_page():
|
|
|
return render_template("math.html")
|
|
|
|
|
|
@pix2text_bp.route("/math/process", methods=["POST"])
|
|
|
def process_math_image():
|
|
|
try:
|
|
|
if 'image' not in request.files:
|
|
|
return jsonify({'error': 'No image file provided'}), 400
|
|
|
|
|
|
file = request.files['image']
|
|
|
if not file.filename:
|
|
|
return jsonify({'error': 'No file selected'}), 400
|
|
|
|
|
|
filename = file.filename
|
|
|
filepath = os.path.join(UPLOAD_FOLDER, filename)
|
|
|
file.save(filepath)
|
|
|
|
|
|
|
|
|
processed_path = preprocess_image(filepath)
|
|
|
|
|
|
|
|
|
if p2t:
|
|
|
result = p2t.recognize(processed_path)
|
|
|
if isinstance(result, dict):
|
|
|
latex = result.get('text', '')
|
|
|
elif isinstance(result, list) and result and isinstance(result[0], dict):
|
|
|
latex = result[0].get('text', '')
|
|
|
else:
|
|
|
latex = str(result)
|
|
|
else:
|
|
|
latex = "\\text{Pix2Text not initialized}"
|
|
|
|
|
|
return jsonify({
|
|
|
'success': True,
|
|
|
'latex': latex,
|
|
|
'image_path': filepath
|
|
|
})
|
|
|
|
|
|
except Exception as e:
|
|
|
print(f"❌ Error in /math/process: {e}")
|
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
@pix2text_bp.route("/math/solve", methods=["POST"])
|
|
|
def solve_math_equation():
|
|
|
try:
|
|
|
data = request.get_json()
|
|
|
if not data or 'latex' not in data:
|
|
|
return jsonify({'error': 'No equation provided'}), 400
|
|
|
|
|
|
solution = solve_equation(data['latex'])
|
|
|
return jsonify({'success': True, 'solution': solution})
|
|
|
|
|
|
except Exception as e:
|
|
|
print(f"❌ Error in /math/solve: {e}")
|
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pix2text_bp.route("/camera")
|
|
|
def camera_page():
|
|
|
"""Render the camera capture page"""
|
|
|
return render_template("camera.html")
|
|
|
|
|
|
|
|
|
@pix2text_bp.route("/camera/solve", methods=["POST"])
|
|
|
def solve_camera_equation():
|
|
|
"""Solve a LaTeX equation from camera input"""
|
|
|
try:
|
|
|
data = request.get_json()
|
|
|
if not data:
|
|
|
return jsonify({'error': 'No data provided'}), 400
|
|
|
|
|
|
latex_equation = data.get('latex', '')
|
|
|
if not latex_equation:
|
|
|
return jsonify({'error': 'No equation provided'}), 400
|
|
|
|
|
|
|
|
|
solution = solve_equation(latex_equation)
|
|
|
|
|
|
return jsonify({
|
|
|
'success': True,
|
|
|
'solution': solution
|
|
|
})
|
|
|
|
|
|
except Exception as e:
|
|
|
return jsonify({'error': str(e)}), 500
|
|
|
return jsonify({'error': 'Unknown error'}), 500
|
|
|
|
|
|
|
|
|
@pix2text_bp.route("/camera/process", methods=["POST"])
|
|
|
def process_camera_image():
|
|
|
"""Process camera captured image using Pix2Text"""
|
|
|
try:
|
|
|
if 'image' not in request.files:
|
|
|
return jsonify({'error': 'No image file provided'}), 400
|
|
|
|
|
|
file = request.files['image']
|
|
|
if file.filename == '':
|
|
|
return jsonify({'error': 'No image file selected'}), 400
|
|
|
|
|
|
if file and file.filename:
|
|
|
|
|
|
filename = file.filename
|
|
|
filepath = os.path.join(UPLOAD_FOLDER, filename)
|
|
|
file.save(filepath)
|
|
|
|
|
|
|
|
|
|
|
|
processed_path = filepath
|
|
|
|
|
|
|
|
|
if p2t:
|
|
|
print(f"Processing image: {processed_path}")
|
|
|
result = p2t.recognize(processed_path)
|
|
|
print(f"Raw result: {result}")
|
|
|
|
|
|
|
|
|
if isinstance(result, dict):
|
|
|
latex_code = result.get('text', '')
|
|
|
elif isinstance(result, list):
|
|
|
|
|
|
if result and isinstance(result[0], dict):
|
|
|
latex_code = result[0].get('text', '')
|
|
|
else:
|
|
|
latex_code = str(result)
|
|
|
else:
|
|
|
latex_code = str(result)
|
|
|
|
|
|
|
|
|
if len(latex_code.strip()) < 2:
|
|
|
print("Result too short, trying with preprocessing...")
|
|
|
processed_path = preprocess_image(filepath)
|
|
|
result = p2t.recognize(processed_path)
|
|
|
print(f"Preprocessed result: {result}")
|
|
|
|
|
|
if isinstance(result, dict):
|
|
|
latex_code = result.get('text', '')
|
|
|
elif isinstance(result, list):
|
|
|
if result and isinstance(result[0], dict):
|
|
|
latex_code = result[0].get('text', '')
|
|
|
else:
|
|
|
latex_code = str(result)
|
|
|
else:
|
|
|
latex_code = str(result)
|
|
|
|
|
|
print(f"Final extracted LaTeX: {latex_code}")
|
|
|
else:
|
|
|
latex_code = "\\text{Pix2Text not available}"
|
|
|
|
|
|
return jsonify({
|
|
|
'success': True,
|
|
|
'latex': latex_code,
|
|
|
'image_path': filepath
|
|
|
})
|
|
|
|
|
|
except Exception as e:
|
|
|
print(f"Error processing camera image: {e}")
|
|
|
return jsonify({'error': str(e)}), 500
|
|
|
return jsonify({'error': 'Unknown error'}), 500
|
|
|
|