Spaces:
Runtime error
Runtime error
| import fitz | |
| import docx | |
| import tempfile | |
| import os | |
| import re | |
| from typing import List, Dict, Any | |
| from utils import ( | |
| extract_latex_blocks, | |
| extract_equations_with_llm | |
| ) | |
| # ===================================================== | |
| # PDF READER | |
| # ===================================================== | |
| def read_pdf(file_path: str) -> str: | |
| text = "" | |
| try: | |
| doc = fitz.open(file_path) | |
| for page in doc: | |
| try: | |
| page_text = page.get_text() | |
| if page_text: | |
| text += page_text + "\n" | |
| except Exception: | |
| continue | |
| doc.close() | |
| except Exception as e: | |
| print(f"ERREUR PDF: {e}") | |
| return text | |
| # ===================================================== | |
| # DOCX READER | |
| # ===================================================== | |
| def read_docx(uploaded_file) -> str: | |
| try: | |
| document = docx.Document(uploaded_file) | |
| paragraphs = [] | |
| for p in document.paragraphs: | |
| if p.text.strip(): | |
| paragraphs.append(p.text) | |
| return "\n".join(paragraphs) | |
| except Exception as e: | |
| print(f"ERREUR DOCX: {e}") | |
| return "" | |
| # ===================================================== | |
| # TEXT CLEANER | |
| # ===================================================== | |
| def clean_text(text: str) -> str: | |
| if not text: | |
| return "" | |
| text = text.replace("\x00", " ") | |
| text = re.sub(r"\s+", " ", text) | |
| return text.strip() | |
| # ===================================================== | |
| # NORMALIZE EQUATIONS | |
| # ===================================================== | |
| def normalize_equation(eq: Any) -> str: | |
| if isinstance(eq, dict): | |
| eq = eq.get("latex", "") | |
| if not isinstance(eq, str): | |
| eq = str(eq) | |
| eq = eq.strip() | |
| eq = eq.replace("\n", " ") | |
| return eq | |
| # ===================================================== | |
| # BUILD RESULTS | |
| # ===================================================== | |
| def build_equation_results( | |
| equations: List[Any], | |
| context: str | |
| ) -> List[Dict[str, Any]]: | |
| results = [] | |
| seen = set() | |
| for i, eq in enumerate(equations): | |
| latex = normalize_equation(eq) | |
| if not latex: | |
| continue | |
| if latex in seen: | |
| continue | |
| seen.add(latex) | |
| results.append({ | |
| "id": f"eq_{i}", | |
| "latex": latex, | |
| "context": context[:500] | |
| }) | |
| return results | |
| # ===================================================== | |
| # HEURISTIC EXTRACTION | |
| # ===================================================== | |
| def heuristic_equation_detection(text: str): | |
| candidates = [] | |
| lines = text.split("\n") | |
| patterns = [ | |
| r".*=.*", | |
| r".+\+.+", | |
| r".+\-.+", | |
| r".+\\frac.+", | |
| r".+\\sum.+", | |
| r".+\\int.+", | |
| r".+\^.+", | |
| ] | |
| for line in lines: | |
| line = line.strip() | |
| if len(line) < 3: | |
| continue | |
| for pattern in patterns: | |
| if re.match(pattern, line): | |
| candidates.append(line) | |
| break | |
| return candidates | |
| # ===================================================== | |
| # EXTRACT FROM TEXT | |
| # ===================================================== | |
| def extract_from_text( | |
| text: str, | |
| use_llm: bool = True | |
| ) -> List[Dict[str, Any]]: | |
| text = clean_text(text) | |
| if not text: | |
| return [] | |
| equations = [] | |
| # ------------------------------------------------- | |
| # LATEX EXTRACTION | |
| # ------------------------------------------------- | |
| latex_equations = extract_latex_blocks(text) | |
| equations.extend(latex_equations) | |
| # ------------------------------------------------- | |
| # HEURISTIC EXTRACTION | |
| # ------------------------------------------------- | |
| if len(equations) == 0: | |
| heuristic_eqs = heuristic_equation_detection(text) | |
| equations.extend(heuristic_eqs) | |
| # ------------------------------------------------- | |
| # LLM EXTRACTION | |
| # ------------------------------------------------- | |
| if ( | |
| use_llm | |
| and len(equations) == 0 | |
| and len(text) > 30 | |
| ): | |
| try: | |
| llm_eqs = extract_equations_with_llm(text) | |
| if isinstance(llm_eqs, list): | |
| equations.extend(llm_eqs) | |
| except Exception as e: | |
| print(f"ERREUR LLM EXTRACTION: {e}") | |
| # ------------------------------------------------- | |
| # FALLBACK | |
| # ------------------------------------------------- | |
| if len(equations) == 0: | |
| equations = [ | |
| "E = mc^2" | |
| ] | |
| return build_equation_results( | |
| equations[:20], | |
| text | |
| ) | |
| # ===================================================== | |
| # EXTRACT FROM FILE | |
| # ===================================================== | |
| def extract_from_file( | |
| uploaded_file | |
| ) -> List[Dict[str, Any]]: | |
| text = "" | |
| filename = uploaded_file.name.lower() | |
| # ------------------------------------------------- | |
| # ------------------------------------------------- | |
| if filename.endswith(".pdf"): | |
| with tempfile.NamedTemporaryFile( | |
| delete=False, | |
| suffix=".pdf" | |
| ) as tmp: | |
| tmp.write(uploaded_file.read()) | |
| tmp_path = tmp.name | |
| try: | |
| text = read_pdf(tmp_path) | |
| finally: | |
| if os.path.exists(tmp_path): | |
| os.unlink(tmp_path) | |
| # ------------------------------------------------- | |
| # DOCX | |
| # ------------------------------------------------- | |
| elif filename.endswith(".docx"): | |
| text = read_docx(uploaded_file) | |
| # ------------------------------------------------- | |
| # TXT | |
| # ------------------------------------------------- | |
| else: | |
| try: | |
| text = uploaded_file.read().decode( | |
| "utf-8", | |
| errors="ignore" | |
| ) | |
| except Exception: | |
| text = "" | |
| return extract_from_text(text) |