Ahmed-El-Sharkawy commited on
Commit
33a5595
·
verified ·
1 Parent(s): cdde84b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +126 -126
app.py CHANGED
@@ -1,126 +1,126 @@
1
- import base64
2
- import io
3
- import os
4
- from dotenv import load_dotenv
5
- from PIL import Image
6
- import gradio as gr
7
- from openai import OpenAI
8
- import re
9
-
10
- # Config
11
- load_dotenv()
12
- APP_Name = os.getenv("APP_Name", "Ghaymah Vision QA")
13
- APP_Version = os.getenv("APP_Version", "1.0.0")
14
- API_KEY = os.getenv("API_KEY")
15
- BASE_URL = os.getenv("BASE_URL", "disappear")
16
-
17
- CSS = """
18
- .app-header{display:flex;align-items:center;gap:12px;justify-content:center;margin:6px 0 16px}
19
- .app-header img{height:60px;border-radius:12px}
20
- .app-title{font-weight:800;font-size:28px;line-height:1.1}
21
- .app-sub{opacity:.7;font-size:14px}
22
- """
23
-
24
- # Branding
25
- COMPANY_LOGO = "download.jpeg"
26
- OWNER_NAME = "ENG. Ahmed Yasser El Sharkawy"
27
-
28
- client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
29
-
30
- # Map PIL formats to MIME types
31
- PIL_TO_MIME = {
32
- "JPEG": "image/jpeg",
33
- "PNG": "image/png",
34
- "WEBP": "image/webp",
35
- "GIF": "image/gif",
36
- "BMP": "image/bmp",
37
- "TIFF": "image/tiff",
38
- }
39
-
40
- def encode_image_to_data_url(pil_image: Image.Image) -> str:
41
- fmt = (pil_image.format or "PNG").upper()
42
- mime = PIL_TO_MIME.get(fmt, "image/png")
43
- buf = io.BytesIO()
44
- if fmt == "JPEG" and pil_image.mode not in ("RGB", "L"):
45
- pil_image = pil_image.convert("RGB")
46
- pil_image.save(buf, format=fmt)
47
- b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
48
- return f"data:{mime};base64,{b64}"
49
-
50
- def logo_data_uri(path: str) -> str:
51
- if not os.path.exists(path):
52
- return ""
53
- ext = os.path.splitext(path)[1].lower()
54
- mime = {
55
- ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
56
- ".webp": "image/webp", ".gif": "image/gif"
57
- }.get(ext, "image/png")
58
- with open(path, "rb") as f:
59
- b64 = base64.b64encode(f.read()).decode("utf-8")
60
- return f"data:{mime};base64,{b64}"
61
-
62
-
63
- def to_plain_text(s: str) -> str:
64
- s = re.sub(r'\*\*(.*?)\*\*', r'\1', s) # bold
65
- s = re.sub(r'\*(.*?)\*', r'\1', s) # italics
66
- s = re.sub(r'`{1,3}(.*?)`{1,3}', r'\1', s, flags=re.S) # code
67
- s = re.sub(r'^\s*[-*]\s+', '• ', s, flags=re.M) # bullets
68
- return s
69
-
70
- def ask_image_question(image: Image.Image, question: str):
71
- if image is None:
72
- return "⚠️ Please upload an image first."
73
- if not question or not question.strip():
74
- question = "Describe this image."
75
- try:
76
- data_url = encode_image_to_data_url(image)
77
- msg_content = [
78
- {"type": "text", "text": question.strip()},
79
- {"type": "image_url", "image_url": {"url": data_url}},
80
- ]
81
- resp = client.chat.completions.create(
82
- model="gemma-3-4b-it",
83
- messages=[{"role": "user", "content": msg_content}],
84
- max_tokens=400,
85
- temperature=0.2,
86
- )
87
- return to_plain_text(resp.choices[0].message.content or "")
88
-
89
- except Exception as e:
90
- return f"❌ Error: {e}"
91
-
92
- # Gradio UI
93
- with gr.Blocks(title=f"{APP_Name} v{APP_Version}", css=CSS) as demo:
94
- header_logo_src = logo_data_uri(COMPANY_LOGO)
95
- logo_html = f"<img src='{header_logo_src}' alt='logo'>" if header_logo_src else ""
96
- gr.HTML(f"""
97
- <div class="app-header">
98
- {logo_html}
99
- <div class="app-header-text">
100
- <div class="app-title">{APP_Name}</div>
101
- <div class="app-sub">v{APP_Version} • {OWNER_NAME}</div>
102
- </div>
103
- </div>
104
- """)
105
-
106
- with gr.Row():
107
- # Left column: image -> question -> ask button
108
- with gr.Column(scale=3):
109
- image_in = gr.Image(type="pil", label="Upload image", sources=["upload", "clipboard"])
110
- question_in = gr.Textbox(label="Your question",
111
- placeholder="e.g., What objects do you see? What is happening?",
112
- lines=3)
113
- ask_btn = gr.Button("Ask", variant="primary")
114
-
115
- # Right column: logo -> answer box
116
- with gr.Column(scale=2, min_width=320):
117
- if os.path.exists(COMPANY_LOGO):
118
- gr.Image(COMPANY_LOGO, show_label=False, container=False, height=96)
119
- answer_out = gr.Textbox(label="Answer", lines=14, interactive=False, show_copy_button=True)
120
-
121
- ask_btn.click(ask_image_question, [image_in, question_in], [answer_out])
122
- question_in.submit(ask_image_question, [image_in, question_in], [answer_out])
123
-
124
-
125
- if __name__ == "__main__":
126
- demo.launch(debug=True)
 
1
+ import base64
2
+ import io
3
+ import os
4
+ from dotenv import load_dotenv
5
+ from PIL import Image
6
+ import gradio as gr
7
+ from openai import OpenAI
8
+ import re
9
+
10
+ # Config
11
+ load_dotenv()
12
+ APP_Name = os.getenv("APP_Name", "Ghaymah Vision QA")
13
+ APP_Version = os.getenv("APP_Version", "1.0.0")
14
+ API_KEY = os.getenv("API_KEY")
15
+ BASE_URL = os.getenv("BASE_URL", "https://genai.ghaymah.systems")
16
+
17
+ CSS = """
18
+ .app-header{display:flex;align-items:center;gap:12px;justify-content:center;margin:6px 0 16px}
19
+ .app-header img{height:60px;border-radius:12px}
20
+ .app-title{font-weight:800;font-size:28px;line-height:1.1}
21
+ .app-sub{opacity:.7;font-size:14px}
22
+ """
23
+
24
+ # Branding
25
+ COMPANY_LOGO = "download.jpeg"
26
+ OWNER_NAME = "ENG. Ahmed Yasser El Sharkawy"
27
+
28
+ client = OpenAI(api_key=API_KEY, base_url="https://genai.ghaymah.systems")
29
+
30
+ # Map PIL formats to MIME types
31
+ PIL_TO_MIME = {
32
+ "JPEG": "image/jpeg",
33
+ "PNG": "image/png",
34
+ "WEBP": "image/webp",
35
+ "GIF": "image/gif",
36
+ "BMP": "image/bmp",
37
+ "TIFF": "image/tiff",
38
+ }
39
+
40
+ def encode_image_to_data_url(pil_image: Image.Image) -> str:
41
+ fmt = (pil_image.format or "PNG").upper()
42
+ mime = PIL_TO_MIME.get(fmt, "image/png")
43
+ buf = io.BytesIO()
44
+ if fmt == "JPEG" and pil_image.mode not in ("RGB", "L"):
45
+ pil_image = pil_image.convert("RGB")
46
+ pil_image.save(buf, format=fmt)
47
+ b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
48
+ return f"data:{mime};base64,{b64}"
49
+
50
+ def logo_data_uri(path: str) -> str:
51
+ if not os.path.exists(path):
52
+ return ""
53
+ ext = os.path.splitext(path)[1].lower()
54
+ mime = {
55
+ ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
56
+ ".webp": "image/webp", ".gif": "image/gif"
57
+ }.get(ext, "image/png")
58
+ with open(path, "rb") as f:
59
+ b64 = base64.b64encode(f.read()).decode("utf-8")
60
+ return f"data:{mime};base64,{b64}"
61
+
62
+
63
+ def to_plain_text(s: str) -> str:
64
+ s = re.sub(r'\*\*(.*?)\*\*', r'\1', s) # bold
65
+ s = re.sub(r'\*(.*?)\*', r'\1', s) # italics
66
+ s = re.sub(r'`{1,3}(.*?)`{1,3}', r'\1', s, flags=re.S) # code
67
+ s = re.sub(r'^\s*[-*]\s+', '• ', s, flags=re.M) # bullets
68
+ return s
69
+
70
+ def ask_image_question(image: Image.Image, question: str):
71
+ if image is None:
72
+ return "⚠️ Please upload an image first."
73
+ if not question or not question.strip():
74
+ question = "Describe this image."
75
+ try:
76
+ data_url = encode_image_to_data_url(image)
77
+ msg_content = [
78
+ {"type": "text", "text": question.strip()},
79
+ {"type": "image_url", "image_url": {"url": data_url}},
80
+ ]
81
+ resp = client.chat.completions.create(
82
+ model="gemma-3-4b-it",
83
+ messages=[{"role": "user", "content": msg_content}],
84
+ max_tokens=400,
85
+ temperature=0.2,
86
+ )
87
+ return to_plain_text(resp.choices[0].message.content or "")
88
+
89
+ except Exception as e:
90
+ return f"❌ Error: {e}"
91
+
92
+ # Gradio UI
93
+ with gr.Blocks(title=f"{APP_Name} v{APP_Version}", css=CSS) as demo:
94
+ header_logo_src = logo_data_uri(COMPANY_LOGO)
95
+ logo_html = f"<img src='{header_logo_src}' alt='logo'>" if header_logo_src else ""
96
+ gr.HTML(f"""
97
+ <div class="app-header">
98
+ {logo_html}
99
+ <div class="app-header-text">
100
+ <div class="app-title">{APP_Name}</div>
101
+ <div class="app-sub">v{APP_Version} • {OWNER_NAME}</div>
102
+ </div>
103
+ </div>
104
+ """)
105
+
106
+ with gr.Row():
107
+ # Left column: image -> question -> ask button
108
+ with gr.Column(scale=3):
109
+ image_in = gr.Image(type="pil", label="Upload image", sources=["upload", "clipboard"])
110
+ question_in = gr.Textbox(label="Your question",
111
+ placeholder="e.g., What objects do you see? What is happening?",
112
+ lines=3)
113
+ ask_btn = gr.Button("Ask", variant="primary")
114
+
115
+ # Right column: logo -> answer box
116
+ with gr.Column(scale=2, min_width=320):
117
+ if os.path.exists(COMPANY_LOGO):
118
+ gr.Image(COMPANY_LOGO, show_label=False, container=False, height=96)
119
+ answer_out = gr.Textbox(label="Answer", lines=14, interactive=False, show_copy_button=True)
120
+
121
+ ask_btn.click(ask_image_question, [image_in, question_in], [answer_out])
122
+ question_in.submit(ask_image_question, [image_in, question_in], [answer_out])
123
+
124
+
125
+ if __name__ == "__main__":
126
+ demo.launch(debug=True)