Spaces:
Running
Running
Upload 2 files
Browse files- app.py +7 -93
- requirements.txt +0 -1
app.py
CHANGED
|
@@ -12,12 +12,6 @@ import easyocr
|
|
| 12 |
from PIL import Image
|
| 13 |
import numpy as np
|
| 14 |
import re
|
| 15 |
-
import matplotlib.pyplot as plt
|
| 16 |
-
import matplotlib
|
| 17 |
-
from io import BytesIO
|
| 18 |
-
|
| 19 |
-
# Use non-interactive backend for matplotlib
|
| 20 |
-
matplotlib.use('Agg')
|
| 21 |
|
| 22 |
@st.cache_data(show_spinner=False)
|
| 23 |
def get_pdf_text(pdf_docs):
|
|
@@ -47,24 +41,16 @@ def get_image_text(image_files):
|
|
| 47 |
try:
|
| 48 |
# Open image using PIL
|
| 49 |
image = Image.open(image_file)
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
image = image.convert('L') # Grayscale
|
| 53 |
-
# Simple contrast enhancement using numpy
|
| 54 |
-
img_np = np.array(image)
|
| 55 |
-
# Normalize
|
| 56 |
-
img_np = (img_np - np.min(img_np)) / (np.max(img_np) - np.min(img_np)) * 255
|
| 57 |
-
img_np = img_np.astype(np.uint8)
|
| 58 |
-
|
| 59 |
# Extract text using EasyOCR with parameters optimized for math/handwriting
|
| 60 |
results = reader.readtext(
|
| 61 |
-
|
| 62 |
detail=1,
|
| 63 |
paragraph=False,
|
| 64 |
contrast_ths=0.1,
|
| 65 |
adjust_contrast=0.5,
|
| 66 |
-
text_threshold=0.
|
| 67 |
-
low_text=0.3
|
| 68 |
)
|
| 69 |
# Combine all detected text with confidence filtering
|
| 70 |
extracted_text = ' '.join([result[1] for result in results if result[2] > 0.3])
|
|
@@ -112,67 +98,6 @@ def get_conversation_chain(vectorstore, api_key):
|
|
| 112 |
)
|
| 113 |
return conversation_chain
|
| 114 |
|
| 115 |
-
def render_math_as_image(text):
|
| 116 |
-
"""
|
| 117 |
-
Detect LaTeX math in text and render complex equations as images.
|
| 118 |
-
Returns tuple: (has_math, processed_text_or_image)
|
| 119 |
-
"""
|
| 120 |
-
# Check if text contains LaTeX math patterns
|
| 121 |
-
math_patterns = [
|
| 122 |
-
r'\$\$.*?\$\$', r'\$.*?\$',
|
| 123 |
-
r'\\frac', r'\\sqrt', r'\\sum', r'\\int',
|
| 124 |
-
r'\\begin\{.*?\}', r'\\\[.*?\\\]',
|
| 125 |
-
r'\[\s*\\begin' # Catch [\begin cases
|
| 126 |
-
]
|
| 127 |
-
has_complex_math = any(re.search(pattern, text, re.DOTALL) for pattern in math_patterns)
|
| 128 |
-
|
| 129 |
-
if has_complex_math:
|
| 130 |
-
try:
|
| 131 |
-
# Clean the text for rendering
|
| 132 |
-
clean_text = text
|
| 133 |
-
|
| 134 |
-
# Normalize delimiters
|
| 135 |
-
clean_text = clean_text.replace('$$', '$')
|
| 136 |
-
clean_text = clean_text.replace(r'\[', '$').replace(r'\]', '$')
|
| 137 |
-
clean_text = clean_text.replace(r'\(', '$').replace(r'\)', '$')
|
| 138 |
-
|
| 139 |
-
# Fix specific issue seen in screenshot: [\begin -> $\begin
|
| 140 |
-
clean_text = re.sub(r'\[\s*\\begin', r'$\n\\begin', clean_text)
|
| 141 |
-
clean_text = re.sub(r'\\end\{.*?\}\s*\]', r'\\end{cases}$', clean_text) # Simplified fix for end
|
| 142 |
-
|
| 143 |
-
# Remove spacing arguments like \\[2mm] -> \\
|
| 144 |
-
clean_text = re.sub(r'\\\\\[.*?\]', r'\\\\', clean_text)
|
| 145 |
-
|
| 146 |
-
# Estimate height based on text length (rough approximation)
|
| 147 |
-
lines = clean_text.count('\n') + (len(clean_text) // 60)
|
| 148 |
-
fig_height = max(4, lines * 0.5)
|
| 149 |
-
|
| 150 |
-
# Create figure
|
| 151 |
-
fig, ax = plt.subplots(figsize=(10, fig_height))
|
| 152 |
-
ax.axis('off')
|
| 153 |
-
|
| 154 |
-
# Render text with math
|
| 155 |
-
ax.text(0.5, 0.5, clean_text,
|
| 156 |
-
fontsize=12,
|
| 157 |
-
ha='center',
|
| 158 |
-
va='center',
|
| 159 |
-
wrap=True,
|
| 160 |
-
usetex=False) # Use matplotlib's math rendering
|
| 161 |
-
|
| 162 |
-
# Save to bytes
|
| 163 |
-
buf = BytesIO()
|
| 164 |
-
plt.savefig(buf, format='png', bbox_inches='tight', dpi=200, facecolor='#f5f2e8')
|
| 165 |
-
buf.seek(0)
|
| 166 |
-
plt.close(fig)
|
| 167 |
-
|
| 168 |
-
return True, buf
|
| 169 |
-
except Exception as e:
|
| 170 |
-
# If rendering fails, return text but try to clean it for markdown
|
| 171 |
-
print(f"Rendering failed: {e}")
|
| 172 |
-
return False, text
|
| 173 |
-
|
| 174 |
-
return False, text
|
| 175 |
-
|
| 176 |
def handle_userinput(user_question):
|
| 177 |
# Display user message immediately
|
| 178 |
st.chat_message("user").write(user_question)
|
|
@@ -181,15 +106,9 @@ def handle_userinput(user_question):
|
|
| 181 |
response = st.session_state.conversation({'question': user_question})
|
| 182 |
st.session_state.chat_history = response['chat_history']
|
| 183 |
|
| 184 |
-
# Display assistant response
|
| 185 |
answer = response['answer']
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
with st.chat_message("assistant"):
|
| 189 |
-
if has_math:
|
| 190 |
-
st.image(content, use_column_width=True)
|
| 191 |
-
else:
|
| 192 |
-
st.markdown(content, unsafe_allow_html=True)
|
| 193 |
|
| 194 |
def main():
|
| 195 |
load_dotenv()
|
|
@@ -306,12 +225,7 @@ def main():
|
|
| 306 |
if i % 2 == 0:
|
| 307 |
st.chat_message("user").write(message.content)
|
| 308 |
else:
|
| 309 |
-
|
| 310 |
-
with st.chat_message("assistant"):
|
| 311 |
-
if has_math:
|
| 312 |
-
st.image(content, use_column_width=True)
|
| 313 |
-
else:
|
| 314 |
-
st.markdown(content, unsafe_allow_html=True)
|
| 315 |
|
| 316 |
user_question = st.chat_input("Ask a question about your documents:")
|
| 317 |
if user_question:
|
|
|
|
| 12 |
from PIL import Image
|
| 13 |
import numpy as np
|
| 14 |
import re
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
@st.cache_data(show_spinner=False)
|
| 17 |
def get_pdf_text(pdf_docs):
|
|
|
|
| 41 |
try:
|
| 42 |
# Open image using PIL
|
| 43 |
image = Image.open(image_file)
|
| 44 |
+
# Convert to numpy array for easyocr
|
| 45 |
+
image_np = np.array(image)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
# Extract text using EasyOCR with parameters optimized for math/handwriting
|
| 47 |
results = reader.readtext(
|
| 48 |
+
image_np,
|
| 49 |
detail=1,
|
| 50 |
paragraph=False,
|
| 51 |
contrast_ths=0.1,
|
| 52 |
adjust_contrast=0.5,
|
| 53 |
+
text_threshold=0.5
|
|
|
|
| 54 |
)
|
| 55 |
# Combine all detected text with confidence filtering
|
| 56 |
extracted_text = ' '.join([result[1] for result in results if result[2] > 0.3])
|
|
|
|
| 98 |
)
|
| 99 |
return conversation_chain
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
def handle_userinput(user_question):
|
| 102 |
# Display user message immediately
|
| 103 |
st.chat_message("user").write(user_question)
|
|
|
|
| 106 |
response = st.session_state.conversation({'question': user_question})
|
| 107 |
st.session_state.chat_history = response['chat_history']
|
| 108 |
|
| 109 |
+
# Display assistant response with LaTeX support
|
| 110 |
answer = response['answer']
|
| 111 |
+
st.chat_message("assistant").markdown(answer, unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
def main():
|
| 114 |
load_dotenv()
|
|
|
|
| 225 |
if i % 2 == 0:
|
| 226 |
st.chat_message("user").write(message.content)
|
| 227 |
else:
|
| 228 |
+
st.chat_message("assistant").markdown(message.content, unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
|
| 230 |
user_question = st.chat_input("Ask a question about your documents:")
|
| 231 |
if user_question:
|
requirements.txt
CHANGED
|
@@ -12,5 +12,4 @@ python-dotenv
|
|
| 12 |
tiktoken
|
| 13 |
easyocr
|
| 14 |
Pillow
|
| 15 |
-
matplotlib
|
| 16 |
|
|
|
|
| 12 |
tiktoken
|
| 13 |
easyocr
|
| 14 |
Pillow
|
|
|
|
| 15 |
|