vanseleem commited on
Commit
c8c2b7d
ยท
verified ยท
1 Parent(s): c7b188d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -48
app.py CHANGED
@@ -1,57 +1,171 @@
1
- from flask import Flask, request, Response, stream_with_context
2
- import requests
 
 
 
 
3
 
4
- app = Flask(__name__)
 
5
 
6
- HOST = "http://26.dragonpro.net:8080"
7
- USER = "kliU0JlomQ"
8
- PASS = "vXre5KnfxF"
9
- USER_AGENT = "IPTVSmarters/1.0.3 (iPad; iOS 13.4.1; Scale/2.00)"
10
 
11
- session = requests.Session()
12
- session.headers.update({'User-Agent': USER_AGENT})
 
 
13
 
14
- @app.route('/')
15
- def status():
16
- return "XTREAM_GATEWAY_V2_LOCKED"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- @app.route('/<path:path>')
19
- def ghost_proxy(path):
20
- query_params = dict(request.args)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- # Credentials are NEVER exposed to the player or the browser.
23
- # They are injected here, inside the server.
24
- if any(x in path for x in ["player_api.php", "xmltv.php", "get.php"]):
25
- query_params['username'] = USER
26
- query_params['password'] = PASS
27
 
28
- target_url = f"{HOST}/{path}"
29
- headers = {k: v for k, v in request.headers if k.lower() not in ['host', 'user-agent']}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  try:
32
- r = session.get(target_url, params=query_params, headers=headers, stream=True, timeout=15)
33
-
34
- excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
35
- resp_headers = [(name, value) for (name, value) in r.raw.headers.items()
36
- if name.lower() not in excluded_headers]
37
-
38
- def stream_logic():
39
- try:
40
- # 128KB chunks for the fastest possible zapping/opening in Cairo.
41
- for chunk in r.iter_content(chunk_size=131072):
42
- if chunk:
43
- yield chunk
44
- except:
45
- pass
46
- finally:
47
- r.close()
48
-
49
- return Response(stream_with_context(stream_logic()),
50
- status=r.status_code,
51
- content_type=r.headers.get('Content-Type', 'video/mp2t'),
52
- headers=resp_headers)
53
- except:
54
- return "Gateway Timeout", 504
55
-
56
- if __name__ == '__main__':
57
- app.run(host='0.0.0.0', port=7860, threaded=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import gradio as gr
4
+ import fitz
5
+ from PIL import Image
6
+ import logging
7
 
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
 
11
+ os.environ["TRANSFORMERS_NO_TORCHVISION"] = "1"
 
 
 
12
 
13
+ _model = None
14
+ _tokenizer = None
15
+ _img_proc = None
16
+ _model_loaded = False
17
 
18
+ def load_model():
19
+ global _model, _tokenizer, _img_proc, _model_loaded
20
+
21
+ if _model_loaded:
22
+ return
23
+
24
+ try:
25
+ from transformers import Qwen2VLForConditionalGeneration, AutoTokenizer, Qwen2VLImageProcessor
26
+ from peft import PeftModel
27
+
28
+ logger.info("Loading base model...")
29
+ _tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-VL-2B-Instruct", trust_remote_code=True)
30
+ _img_proc = Qwen2VLImageProcessor.from_pretrained("Qwen/Qwen2-VL-2B-Instruct", trust_remote_code=True)
31
+
32
+ base = Qwen2VLForConditionalGeneration.from_pretrained(
33
+ "Qwen/Qwen2-VL-2B-Instruct",
34
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
35
+ device_map="auto" if torch.cuda.is_available() else "cpu"
36
+ )
37
+
38
+ logger.info("Loading LoRA adapter...")
39
+ peft_model = PeftModel.from_pretrained(base, "NaserNajeh/Horoof")
40
+ _model = peft_model.merge_and_unload()
41
+ _model.eval()
42
+ _model_loaded = True
43
+ logger.info("โœ… Model loaded!")
44
+
45
+ except Exception as e:
46
+ logger.error(f"Error loading model: {e}")
47
+ raise
48
 
49
+ def pdf_to_images(pdf_bytes, dpi=220, max_pages=2):
50
+ pages_imgs = []
51
+ doc = fitz.open(stream=pdf_bytes, filetype="pdf")
52
+
53
+ n_pages = min(max_pages, doc.page_count)
54
+
55
+ for i in range(n_pages):
56
+ try:
57
+ page = doc.load_page(i)
58
+ mat = fitz.Matrix(dpi/72, dpi/72)
59
+ pix = page.get_pixmap(matrix=mat, alpha=False)
60
+
61
+ img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
62
+
63
+ if max(img.size) > 2048:
64
+ img.thumbnail((2048, 2048), Image.Resampling.LANCZOS)
65
+
66
+ pages_imgs.append((i + 1, img))
67
+ logger.info(f"โœ… Converted page {i+1}")
68
+
69
+ except Exception as e:
70
+ logger.error(f"Error on page {i+1}: {e}")
71
+ continue
72
 
73
+ doc.close()
74
+ return pages_imgs
 
 
 
75
 
76
+ def ocr_page(pil_img, max_tokens=1200):
77
+ try:
78
+ load_model()
79
+
80
+ messages = [
81
+ {
82
+ "role": "user",
83
+ "content": [
84
+ {"type": "image", "image": pil_img},
85
+ {"type": "text", "text": "ุงู‚ุฑุฃ ุงู„ู†ุต ุงู„ุนุฑุจูŠ ููŠ ุงู„ุตูˆุฑุฉ ูƒู…ุง ู‡ูˆ ุฏูˆู† ุฃูŠ ุชุนุฏูŠู„."},
86
+ ],
87
+ }
88
+ ]
89
+
90
+ tok = _tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=True, return_tensors="pt")
91
+ vis = _img_proc(images=[pil_img], return_tensors="pt")
92
+
93
+ inputs = {"input_ids": tok}
94
+ inputs.update(vis)
95
+
96
+ if torch.cuda.is_available():
97
+ for k, v in inputs.items():
98
+ if hasattr(v, "to"):
99
+ inputs[k] = v.to("cuda")
100
+
101
+ with torch.inference_mode():
102
+ output_ids = _model.generate(**inputs, max_new_tokens=max_tokens, do_sample=False)
103
+
104
+ generated_part = output_ids[0][len(inputs["input_ids"][0]):]
105
+ result = _tokenizer.decode(generated_part, skip_special_tokens=True).strip()
106
+
107
+ return result if result else "No text extracted"
108
+
109
+ except Exception as e:
110
+ logger.error(f"OCR Error: {e}")
111
+ return f"Error: {e}"
112
+
113
+ def process_pdf(pdf_file, dpi, pages):
114
+ if pdf_file is None:
115
+ return "โŒ No PDF uploaded"
116
 
117
  try:
118
+ logger.info("๐Ÿ”„ Processing PDF...")
119
+
120
+ if hasattr(pdf_file, 'read'):
121
+ pdf_bytes = pdf_file.read()
122
+ else:
123
+ pdf_bytes = pdf_file
124
+
125
+ if not pdf_bytes:
126
+ return "โŒ Empty file"
127
+
128
+ dpi_val = max(150, min(300, int(dpi)))
129
+ pages_limit = max(1, int(pages))
130
+
131
+ logger.info(f"Converting {pages_limit} pages at {dpi_val} DPI...")
132
+ pages_imgs = pdf_to_images(pdf_bytes, dpi=dpi_val, max_pages=pages_limit)
133
+
134
+ if not pages_imgs:
135
+ return "โŒ No valid pages"
136
+
137
+ results = []
138
+ for page_num, img in pages_imgs:
139
+ logger.info(f"Processing page {page_num}...")
140
+ text = ocr_page(img)
141
+ results.append(f"๐Ÿ“„ **Page {page_num}**\n{'='*60}\n{text}")
142
+
143
+ return "\n\n".join(results)
144
+
145
+ except Exception as e:
146
+ logger.error(f"Error: {e}")
147
+ return f"โŒ Error: {e}"
148
+
149
+ # Gradio Interface
150
+ with gr.Blocks(title="Horoof OCR") as demo:
151
+ gr.Markdown("""
152
+ # ๐Ÿ”ค Horoof OCR - Arabic Text Extraction
153
+
154
+ **Model**: Qwen2-VL-2B + Horoof LoRA
155
+ **For**: Quran & Arabic Text with Diacritics
156
+ """)
157
+
158
+ with gr.Row():
159
+ with gr.Column(scale=1):
160
+ pdf_input = gr.File(label="๐Ÿ“ Upload PDF", file_types=[".pdf"], type="binary")
161
+ dpi_slider = gr.Slider(150, 300, 220, step=10, label="๐ŸŽฏ DPI")
162
+ pages_slider = gr.Slider(1, 10, 2, step=1, label="๐Ÿ“Š Pages")
163
+ btn = gr.Button("๐Ÿš€ Extract Text", variant="primary", size="lg")
164
+
165
+ with gr.Column(scale=2):
166
+ output = gr.Textbox(label="๐Ÿ“ Extracted Text", lines=20, show_copy_button=True)
167
+
168
+ btn.click(fn=process_pdf, inputs=[pdf_input, dpi_slider, pages_slider], outputs=output)
169
+
170
+ demo.queue()
171
+ demo.launch()