File size: 8,121 Bytes
52be21e
 
 
 
 
 
 
bd6eeb8
 
 
 
 
52be21e
 
 
 
 
 
 
bd6eeb8
52be21e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd6eeb8
52be21e
bd6eeb8
 
 
 
 
 
 
 
 
52be21e
bd6eeb8
 
 
 
 
 
52be21e
bd6eeb8
52be21e
 
bd6eeb8
 
 
52be21e
bd6eeb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52be21e
bd6eeb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52be21e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# modules/file_processor.py

import os
import logging
from typing import Optional
from docx import Document
import PyPDF2
from PIL import Image
import pytesseract
from pdf2image import convert_from_path
import cv2
import numpy as np

logger = logging.getLogger(__name__)


class FileProcessor:
    
    def __init__(self):
        logger.info("FileProcessor initialized with OCR support")
    
    def extract_text(self, file_path: str) -> str:
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")
        
        _, ext = os.path.splitext(file_path)
        ext = ext.lower()
        
        logger.info(f"Extracting text from {ext} file")
        
        try:
            if ext == '.txt':
                return self._extract_from_txt(file_path)
            elif ext == '.docx':
                return self._extract_from_docx(file_path)
            elif ext == '.pdf':
                return self._extract_from_pdf(file_path)
            else:
                raise ValueError(f"Unsupported file type: {ext}")
        
        except Exception as e:
            logger.error(f"Error extracting text: {e}")
            raise
    
    def _extract_from_txt(self, path: str) -> str:
        try:
            with open(path, 'r', encoding='utf-8') as f:
                text = f.read()
            logger.info(f"Extracted {len(text)} chars from TXT")
            return text
        except UnicodeDecodeError:
            with open(path, 'r', encoding='latin-1') as f:
                text = f.read()
            logger.warning("Used latin-1 encoding for TXT")
            return text
    
    def _extract_from_docx(self, path: str) -> str:
        doc = Document(path)
        paragraphs = []
        
        for para in doc.paragraphs:
            text = para.text.strip()
            if text:
                paragraphs.append(text)
        
        text = '\n\n'.join(paragraphs)
        logger.info(f"Extracted {len(text)} chars from DOCX")
        return text
    
    def _extract_from_pdf(self, path: str) -> str:
        """Extract text from PDF with OCR fallback"""
        
        # پہلے PyPDF2 سے کوشش کریں
        text = self._extract_with_pypdf2(path)
        
        # اگر کم از کم 30 الفاظ نہیں ملے تو OCR استعمال کریں
        word_count = len(text.split())
        
        if word_count < 30:
            logger.info(f"PyPDF2 extracted only {word_count} words. Trying OCR...")
            ocr_text = self._extract_with_ocr(path)
            
            # جو زیادہ text دے وہ استعمال کریں
            if len(ocr_text) > len(text):
                text = ocr_text
                logger.info(f"OCR extraction successful: {len(text)} chars")
            else:
                logger.warning("OCR did not improve extraction")
        
        logger.info(f"Final extracted text: {len(text)} chars from PDF")
        return text
    
    def _extract_with_pypdf2(self, path: str) -> str:
        """Regular PDF text extraction"""
        text_parts = []
        
        try:
            with open(path, 'rb') as f:
                reader = PyPDF2.PdfReader(f)
                num_pages = len(reader.pages)
                
                logger.info(f"Reading {num_pages} pages with PyPDF2")
                
                for page_num in range(num_pages):
                    page = reader.pages[page_num]
                    text = page.extract_text()
                    
                    if text.strip():
                        text_parts.append(text)
            
            return '\n\n'.join(text_parts)
        except Exception as e:
            logger.error(f"PyPDF2 extraction failed: {e}")
            return ""
    
    def _extract_with_ocr(self, path: str) -> str:
        """OCR-based extraction for scanned PDFs"""
        text_parts = []
        
        try:
            # PDF کو images میں convert کریں
            logger.info("Converting PDF to images for OCR...")
            images = convert_from_path(path, dpi=300)
            
            logger.info(f"Processing {len(images)} pages with OCR...")
            
            for i, image in enumerate(images):
                logger.info(f"OCR on page {i+1}/{len(images)}...")
                
                # Image کو pre-process کریں (better OCR)
                processed_image = self._preprocess_image(image)
                
                # OCR - Urdu اور English دونوں
                try:
                    # پہلے English try کریں
                    text_eng = pytesseract.image_to_string(
                        processed_image,
                        lang='eng',
                        config='--psm 6'
                    )
                    
                    # پھر Urdu try کریں
                    text_urd = pytesseract.image_to_string(
                        processed_image,
                        lang='urd',
                        config='--psm 6'
                    )
                    
                    # جو زیادہ text دے وہ استعمال کریں
                    if len(text_eng) > len(text_urd):
                        text = text_eng
                        logger.info(f"Page {i+1}: English OCR - {len(text)} chars")
                    else:
                        text = text_urd
                        logger.info(f"Page {i+1}: Urdu OCR - {len(text)} chars")
                    
                    if text.strip():
                        text_parts.append(text.strip())
                
                except Exception as e:
                    logger.error(f"OCR failed on page {i+1}: {e}")
                    # Fallback to English only
                    try:
                        text = pytesseract.image_to_string(processed_image, lang='eng')
                        if text.strip():
                            text_parts.append(text.strip())
                    except:
                        logger.error(f"English OCR also failed on page {i+1}")
            
            final_text = '\n\n'.join(text_parts)
            logger.info(f"OCR complete: {len(final_text)} chars extracted")
            return final_text
            
        except Exception as e:
            logger.error(f"OCR extraction failed: {e}")
            return ""
    
    def _preprocess_image(self, pil_image):
        """Image کو OCR کے لیے بہتر بنائیں"""
        try:
            # PIL to numpy array
            img = np.array(pil_image)
            
            # Convert to grayscale
            if len(img.shape) == 3:
                gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
            else:
                gray = img
            
            # Increase contrast
            alpha = 1.5  # Contrast
            beta = 0     # Brightness
            adjusted = cv2.convertScaleAbs(gray, alpha=alpha, beta=beta)
            
            # Denoise
            denoised = cv2.fastNlMeansDenoising(adjusted, None, 10, 7, 21)
            
            # Threshold
            _, thresh = cv2.threshold(
                denoised, 0, 255,
                cv2.THRESH_BINARY + cv2.THRESH_OTSU
            )
            
            # Convert back to PIL
            processed = Image.fromarray(thresh)
            
            return processed
            
        except Exception as e:
            logger.error(f"Image preprocessing failed: {e}")
            return pil_image
    
    def detect_language(self, text: str) -> str:
        """زبان کی شناخت"""
        urdu_chars = sum(1 for c in text if '\u0600' <= c <= '\u06FF')
        english_chars = sum(1 for c in text if c.isalpha() and c.isascii())
        
        total_chars = urdu_chars + english_chars
        
        if total_chars == 0:
            return 'unknown'
        
        urdu_percent = (urdu_chars / total_chars) * 100
        
        if urdu_percent > 70:
            return 'urdu'
        elif urdu_percent < 30:
            return 'english'
        else:
            return 'mixed'