openfree commited on
Commit
c211f06
·
verified ·
1 Parent(s): 2f67ef7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -390
app.py CHANGED
@@ -1,391 +1,2 @@
1
- # Authenticate with Hugging Face
2
- from huggingface_hub import login
3
  import os
4
- # Log in to Hugging Face using the provided token
5
- hf_token = os.getenv("HF_TOKEN")
6
- login(hf_token)
7
-
8
- # Required imports
9
- import gradio as gr
10
- import spaces
11
- from transformers import Qwen2VLForConditionalGeneration, AutoProcessor, TextIteratorStreamer
12
- from qwen_vl_utils import process_vision_info
13
- import torch
14
- from PIL import Image
15
- import os
16
- import uuid
17
- import io
18
- from threading import Thread
19
- from reportlab.lib.pagesizes import A4
20
- from reportlab.lib.styles import getSampleStyleSheet
21
- from reportlab.lib import colors
22
- from reportlab.platypus import SimpleDocTemplate, Image as RLImage, Paragraph, Spacer
23
- from reportlab.pdfbase import pdfmetrics
24
- from reportlab.pdfbase.ttfonts import TTFont
25
- import docx
26
- from docx.enum.text import WD_ALIGN_PARAGRAPH
27
- from reportlab.lib.units import inch
28
-
29
- # Define model options
30
- MODEL_OPTIONS = {
31
- "ChemQwen-1": "prithivMLmods/ChemQwen-vL",
32
- "ChemQwen-2": "prithivMLmods/ChemQwen2-vL",
33
- }
34
-
35
- # Preload models and processors into CUDA
36
- models = {}
37
- processors = {}
38
- for name, model_id in MODEL_OPTIONS.items():
39
- print(f"Loading {name}...")
40
- models[name] = Qwen2VLForConditionalGeneration.from_pretrained(
41
- model_id,
42
- trust_remote_code=True,
43
- torch_dtype=torch.float16
44
- ).to("cuda").eval()
45
- processors[name] = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
46
-
47
- image_extensions = Image.registered_extensions()
48
-
49
- def identify_and_save_blob(blob_path):
50
- """Identifies if the blob is an image and saves it."""
51
- try:
52
- with open(blob_path, 'rb') as file:
53
- blob_content = file.read()
54
- try:
55
- Image.open(io.BytesIO(blob_content)).verify()
56
- extension = ".png"
57
- media_type = "image"
58
- except (IOError, SyntaxError):
59
- raise ValueError("Unsupported media type. Please upload a valid image.")
60
-
61
- filename = f"temp_{uuid.uuid4()}_media{extension}"
62
- with open(filename, "wb") as f:
63
- f.write(blob_content)
64
-
65
- return filename, media_type
66
-
67
- except FileNotFoundError:
68
- raise ValueError(f"The file {blob_path} was not found.")
69
- except Exception as e:
70
- raise ValueError(f"An error occurred while processing the file: {e}")
71
-
72
-
73
- @spaces.GPU
74
- def qwen_inference(model_name, media_input, text_input=None):
75
- """Handles inference for the selected model."""
76
- model = models[model_name]
77
- processor = processors[model_name]
78
-
79
- if isinstance(media_input, str):
80
- media_path = media_input
81
- if media_path.endswith(tuple([i for i in image_extensions.keys()])):
82
- media_type = "image"
83
- else:
84
- try:
85
- media_path, media_type = identify_and_save_blob(media_input)
86
- except Exception as e:
87
- raise ValueError("Unsupported media type. Please upload a valid image.")
88
-
89
- messages = [
90
- {
91
- "role": "user",
92
- "content": [
93
- {
94
- "type": media_type,
95
- media_type: media_path
96
- },
97
- {"type": "text", "text": text_input},
98
- ],
99
- }
100
- ]
101
-
102
- text = processor.apply_chat_template(
103
- messages, tokenize=False, add_generation_prompt=True
104
- )
105
- image_inputs, _ = process_vision_info(messages)
106
- inputs = processor(
107
- text=[text],
108
- images=image_inputs,
109
- padding=True,
110
- return_tensors="pt",
111
- ).to("cuda")
112
-
113
- streamer = TextIteratorStreamer(
114
- processor.tokenizer, skip_prompt=True, skip_special_tokens=True
115
- )
116
- generation_kwargs = dict(inputs, streamer=streamer, max_new_tokens=1024)
117
-
118
- thread = Thread(target=model.generate, kwargs=generation_kwargs)
119
- thread.start()
120
-
121
- buffer = ""
122
- for new_text in streamer:
123
- buffer += new_text
124
- # Remove <|im_end|> or similar tokens from the output
125
- buffer = buffer.replace("<|im_end|>", "")
126
- yield buffer
127
-
128
-
129
- def format_plain_text(output_text):
130
- """Formats the output text as plain text without LaTeX delimiters."""
131
- plain_text = output_text.replace("\\(", "").replace("\\)", "").replace("\\[", "").replace("\\]", "")
132
- return plain_text
133
-
134
- def generate_document(media_path, output_text, file_format, font_size, line_spacing, alignment, image_size):
135
- """Generates a document with the input image and plain text output."""
136
- plain_text = format_plain_text(output_text)
137
- if file_format == "pdf":
138
- return generate_pdf(media_path, plain_text, font_size, line_spacing, alignment, image_size)
139
- elif file_format == "docx":
140
- return generate_docx(media_path, plain_text, font_size, line_spacing, alignment, image_size)
141
-
142
- def generate_pdf(media_path, plain_text, font_size, line_spacing, alignment, image_size):
143
- """Generates a PDF document."""
144
- filename = f"output_{uuid.uuid4()}.pdf"
145
- doc = SimpleDocTemplate(
146
- filename,
147
- pagesize=A4,
148
- rightMargin=inch,
149
- leftMargin=inch,
150
- topMargin=inch,
151
- bottomMargin=inch
152
- )
153
- styles = getSampleStyleSheet()
154
- styles["Normal"].fontSize = int(font_size)
155
- styles["Normal"].leading = int(font_size) * line_spacing
156
- styles["Normal"].alignment = {
157
- "Left": 0,
158
- "Center": 1,
159
- "Right": 2,
160
- "Justified": 4
161
- }[alignment]
162
-
163
- story = []
164
-
165
- image_sizes = {
166
- "Small": (200, 200),
167
- "Medium": (400, 400),
168
- "Large": (600, 600)
169
- }
170
- img = RLImage(media_path, width=image_sizes[image_size][0], height=image_sizes[image_size][1])
171
- story.append(img)
172
- story.append(Spacer(1, 12))
173
-
174
- text = Paragraph(plain_text, styles["Normal"])
175
- story.append(text)
176
-
177
- doc.build(story)
178
- return filename
179
-
180
- def generate_docx(media_path, plain_text, font_size, line_spacing, alignment, image_size):
181
- """Generates a DOCX document."""
182
- filename = f"output_{uuid.uuid4()}.docx"
183
- doc = docx.Document()
184
-
185
- # Convert image to PNG format before adding to document
186
- try:
187
- img = Image.open(media_path)
188
- temp_image_path = f"temp_{uuid.uuid4()}.png"
189
- img.save(temp_image_path, "PNG")
190
-
191
- image_sizes = {
192
- "Small": docx.shared.Inches(2),
193
- "Medium": docx.shared.Inches(4),
194
- "Large": docx.shared.Inches(6)
195
- }
196
-
197
- doc.add_picture(temp_image_path, width=image_sizes[image_size])
198
-
199
- # Clean up temporary image file
200
- os.remove(temp_image_path)
201
-
202
- except Exception as e:
203
- print(f"Error processing image: {e}")
204
- # Continue without image if there's an error
205
-
206
- doc.add_paragraph()
207
-
208
- paragraph = doc.add_paragraph()
209
- paragraph.paragraph_format.line_spacing = line_spacing
210
- paragraph.paragraph_format.alignment = {
211
- "Left": WD_ALIGN_PARAGRAPH.LEFT,
212
- "Center": WD_ALIGN_PARAGRAPH.CENTER,
213
- "Right": WD_ALIGN_PARAGRAPH.RIGHT,
214
- "Justified": WD_ALIGN_PARAGRAPH.JUSTIFY
215
- }[alignment]
216
- run = paragraph.add_run(plain_text)
217
- run.font.size = docx.shared.Pt(int(font_size))
218
-
219
- doc.save(filename)
220
- return filename
221
-
222
- # CSS styling
223
- css = """
224
- #output {
225
- height: 500px;
226
- overflow: auto;
227
- border: 1px solid #ccc;
228
- }
229
- .container {
230
- background: linear-gradient(145deg, #f0f0f0, #ffffff);
231
- border-radius: 20px;
232
- box-shadow: 20px 20px 60px #bebebe, -20px -20px 60px #ffffff;
233
- padding: 2rem;
234
- margin: 1rem;
235
- }
236
- .title {
237
- text-align: center;
238
- font-size: 2.5rem;
239
- color: #2d3436;
240
- text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
241
- margin-bottom: 2rem;
242
- }
243
- .submit-btn {
244
- background: linear-gradient(145deg, #ff4757, #ff6b81) !important;
245
- color: white !important;
246
- border: none !important;
247
- border-radius: 10px !important;
248
- padding: 0.8rem 1.5rem !important;
249
- font-weight: bold !important;
250
- transform: translateY(0);
251
- transition: all 0.3s ease !important;
252
- box-shadow: 0 4px 15px rgba(255, 71, 87, 0.3) !important;
253
- }
254
- .submit-btn:hover {
255
- transform: translateY(-2px) !important;
256
- box-shadow: 0 6px 20px rgba(255, 71, 87, 0.4) !important;
257
- }
258
- .download-btn {
259
- background: linear-gradient(145deg, #00b894, #00cec9) !important;
260
- color: white !important;
261
- border: none !important;
262
- border-radius: 10px !important;
263
- padding: 0.8rem 1.5rem !important;
264
- font-weight: bold !important;
265
- transform: translateY(0);
266
- transition: all 0.3s ease !important;
267
- box-shadow: 0 4px 15px rgba(0, 184, 148, 0.3) !important;
268
- }
269
- .download-btn:hover {
270
- transform: translateY(-2px) !important;
271
- box-shadow: 0 6px 20px rgba(0, 184, 148, 0.4) !important;
272
- }
273
- .input-box {
274
- border-radius: 10px !important;
275
- border: 2px solid #dfe6e9 !important;
276
- transition: all 0.3s ease !important;
277
- }
278
- .input-box:focus {
279
- border-color: #00b894 !important;
280
- box-shadow: 0 0 10px rgba(0, 184, 148, 0.2) !important;
281
- }
282
- """
283
-
284
- # Gradio app setup
285
- with gr.Blocks(css=css) as demo:
286
- gr.Markdown("# 🧪 Chemical Genesis 🤖", elem_classes="title")
287
-
288
- with gr.Tab(label="🖼️ Image Analysis"):
289
- with gr.Row(elem_classes="container"):
290
- with gr.Column():
291
- model_choice = gr.Dropdown(
292
- label="🔍 Select Model",
293
- choices=list(MODEL_OPTIONS.keys()),
294
- value="ChemQwen-1",
295
- elem_classes="input-box"
296
- )
297
- input_media = gr.File(
298
- label="📤 Upload Image",
299
- type="filepath",
300
- elem_classes="input-box"
301
- )
302
- text_input = gr.Textbox(
303
- label="❓ Your Question",
304
- placeholder="Ask anything about the image...",
305
- elem_classes="input-box"
306
- )
307
- submit_btn = gr.Button(value="🚀 Analyze", elem_classes="submit-btn")
308
-
309
- with gr.Column():
310
- output_text = gr.Textbox(
311
- label="📝 AI Response",
312
- lines=10,
313
- elem_classes="input-box"
314
- )
315
- plain_text_output = gr.Textbox(
316
- label="📋 Standardized Text",
317
- lines=10,
318
- elem_classes="input-box"
319
- )
320
-
321
- with gr.Row(elem_classes="container"):
322
- with gr.Column():
323
- gr.Markdown("### 📄 Document Settings")
324
- line_spacing = gr.Dropdown(
325
- choices=[0.5, 1.0, 1.15, 1.5, 2.0, 2.5, 3.0],
326
- value=1.5,
327
- label="↕️ Line Spacing",
328
- elem_classes="input-box"
329
- )
330
- font_size = gr.Dropdown(
331
- choices=["8", "10", "12", "14", "16", "18", "20", "22", "24"],
332
- value="18",
333
- label="📏 Font Size",
334
- elem_classes="input-box"
335
- )
336
- alignment = gr.Dropdown(
337
- choices=["Left", "Center", "Right", "Justified"],
338
- value="Justified",
339
- label="⚡ Text Alignment",
340
- elem_classes="input-box"
341
- )
342
- image_size = gr.Dropdown(
343
- choices=["Small", "Medium", "Large"],
344
- value="Medium",
345
- label="🖼️ Image Size",
346
- elem_classes="input-box"
347
- )
348
- file_format = gr.Radio(
349
- ["pdf", "docx"],
350
- label="📁 File Format",
351
- value="pdf",
352
- elem_classes="input-box"
353
- )
354
- get_document_btn = gr.Button(
355
- value="💾 Generate Document",
356
- elem_classes="download-btn"
357
- )
358
-
359
-
360
-
361
- submit_btn.click(
362
- qwen_inference,
363
- [model_choice, input_media, text_input],
364
- output_text,
365
- ).then(
366
- format_plain_text,
367
- output_text,
368
- plain_text_output
369
- )
370
-
371
-
372
- get_document_btn.click(
373
- generate_document,
374
- [input_media, output_text, file_format, font_size, line_spacing, alignment, image_size],
375
- gr.File(label="📥 Download Document")
376
- )
377
-
378
- gr.Markdown("""
379
- ### 🌟 Features
380
- - 🔬 Advanced Chemical Structure Analysis
381
- - 📊 Multiple Model Support
382
- - 💫 Real-time Processing
383
- - 📑 Custom Document Generation
384
-
385
- ### 💡 Tips
386
- - 📸 Upload clear images for better results
387
- - ✍️ Be specific with your questions
388
- - 📝 Use the document generator for professional reports
389
- """)
390
-
391
- demo.launch(debug=True)
 
 
 
1
  import os
2
+ exec(os.environ.get('APP'))