Alhdrawi commited on
Commit
e929776
·
verified ·
1 Parent(s): b570faf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -104
app.py CHANGED
@@ -1,112 +1,123 @@
1
- app.py
2
-
3
- Gradio Hugging Face Space connected to Google Gemini (via google-genai)
4
-
5
- - Put your Gemini API key into Hugging Face Space secrets with name: GEMINI_API_KEY
6
-
7
- - Add requirements.txt with: gradio\ngoogle-genai
8
-
9
- import os import io from google import genai from google.genai import types import gradio as gr
10
-
11
- Initialize client using secret from HF environment
12
-
13
- CLIENT = genai.Client(api_key=os.environ.get("GEMINI_API_KEY")) MODEL = "gemini-2.5-flash" # or change to a model available in your project/region
14
-
15
- Fixed short reply for text-only chats
16
-
17
  TEXT_ONLY_REPLY = "أنا R-RAY AI تم تدريبي على قواعد بيانات طبية ضخمة. كيف يمكنني مساعدتك اليوم؟"
18
 
19
- Strict radiology-report instruction (Arabic). The model MUST follow this and reply only with a
20
-
21
- structured medical radiology report. Keep it concise, professional, and in Arabic. Do not add
22
-
23
- extra commentary, safety disclaimers, or step-by-step reasoning in the response.
24
-
25
- RADIology_PROMPT_TEMPLATE = '''أنت "R-RAY AI" — نموذج متخصص في تقارير الأشعة، تدربت على قواعد بيانات طبية ضخمة. تعليمات صارمة:
26
-
27
- 1. عند استلام صور شعاعية (واحدة أو أكثر) أجب فقط بتقرير طبي احترافي بصيغة تقارير الأشعة المستعملة سريريًا.
28
-
29
-
30
- 2. لا تضف جمل ترويجية أو اعتذارات أو نص خارج إطار التقرير.
31
-
32
-
33
- 3. إخراج التقرير يجب أن يحتوي على الأقسام التالية بالترتيب: عنوان الدراسة، تاريخ الاستلام (التاريخ اليومي تلقائيًا)، رقم المريض (إن وُرد)، التاريخ السريري/شكوى المريض (من نص المستخدم إن وُجد)، التقنية (نوع الصور: X-ray, CT, MRI + الإطارات/القطاعات المرفقة)، وصف تفصيلي للنتائج (ملاحظات عامة ومقارنة إن وُجدت معلومات سابقة)، خاتمة/تقرير تشخيصي موجز مع توصية مفيدة واحدة على الأكثر (مثل: متابعة، توصية بإجراء تصوير مقطعي/تصوير رنين، أو استشارة اختصاصي).
34
-
35
-
36
- 4. إذا كان هناك أكثر من صورة — اذكر كل صورة مرقمة ووصف كل واحدة تحت قسم "الصور" ثم ادمج النتائج في قسم "النتائج".
37
-
38
 
39
- 5. اللغة: ال��ربية الفصحى طبية. الطول: تقرير كامل ومحترف (لا تقل عن 6 جمل في الوصف ما لم تكن الصور طبيعية تمامًا).
40
-
41
-
42
-
43
- البيانات المرسلة: {clinical_text}
44
 
45
  الصور المرسلة: {image_list}
46
 
47
- أعد فقط التقرير الطبي بالصيغة المطلوبة. انتهى. '''
48
-
49
- def make_parts_from_images(image_files): parts = [] for idx, img in enumerate(image_files, start=1): # img is a tempfile-like object from Gradio; read bytes img_bytes = img.read() # prefer from_bytes (supported in google-genai). fallback to from_image if exists. try: part = types.Part.from_bytes(img_bytes) except Exception: try: part = types.Part.from_image(img_bytes) except Exception: # if both fail, embed base64 text as a last resort import base64 b64 = base64.b64encode(img_bytes).decode('utf-8') part = types.Part.from_text(f"[BASE64_IMAGE_{idx}] {b64}") parts.append(part) return parts
50
-
51
- def analyze(images, clinical_text): clinical_text = (clinical_text or "").strip() images = images or []
52
-
53
- # If no images: provide the fixed text-only reply
54
- if len(images) == 0:
55
- # If the user sent text only, return the strict assistant opening line
56
- return TEXT_ONLY_REPLY
57
-
58
- # Build list of image names for prompt
59
- image_names = []
60
- for i, f in enumerate(images, start=1):
61
- name = getattr(f, "name", None) or f"image_{i}"
62
- image_names.append(name)
63
- image_list_text = ", ".join(image_names)
64
-
65
- # Prepare prompt (strict)
66
- prompt_text = RADIology_PROMPT_TEMPLATE.format(
67
- clinical_text=clinical_text if clinical_text else "(لا توجد معلومات سريرية إضافية)",
68
- image_list=image_list_text,
69
- )
70
-
71
- # Build content parts: first the images, then the instruction as text part
72
- parts = make_parts_from_images(images)
73
- parts.append(types.Part.from_text(prompt_text))
74
-
75
- contents = [
76
- types.Content(
77
- role="user",
78
- parts=parts,
79
- )
80
- ]
81
-
82
- # Call Gemini (synchronous)
83
- try:
84
- response = CLIENT.models.generate_content(
85
- model=MODEL,
86
- contents=contents,
87
- config=types.GenerateContentConfig(
88
- thinking_config=types.ThinkingConfig(thinking_budget=-1),
89
- ),
 
90
  )
91
- # return text output
92
- return response.text
93
- except Exception as e:
94
- return f"خطأ أثناء الاتصال بنموذج Gemini: {e}"
95
-
96
- Build Gradio UI
97
-
98
- with gr.Blocks() as demo: gr.Markdown("# R-RAY AI — تقارير الأشعة\nارفع صور شعاعية (X-ray, CT, MRI) ويمكنك أيضًا ارفاق ملاحظات سريرية قصيرة.")
99
-
100
- with gr.Row():
101
- image_input = gr.Files(label="تحميل صور (يمكن رفع أكثر من صورة)", file_count="multiple", type="file")
102
- clinical_input = gr.Textbox(label="معلومات سريرية / تاريخ المريض (اختياري)", lines=4)
103
-
104
- output = gr.Textbox(label="تقرير الأشعة (الناتج)", lines=20)
105
-
106
- btn = gr.Button("تحليل وإصدار التقرير")
107
- btn.click(fn=analyze, inputs=[image_input, clinical_input], outputs=[output])
108
-
109
- gr.Markdown("**ملاحظة:** هذا النموذج للاختبار/التطوير فقط ولا يغني عن استشارة طبية حقيقية.")
110
-
111
- if name == "main": demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ # Gradio Hugging Face Space connected to Google Gemini (via google-genai)
3
+ # - Put your Gemini API key into Hugging Face Space secrets with name: GEMINI_API_KEY
4
+ # - Add requirements.txt with: gradio\ngoogle-genai
5
+
6
+ import os
7
+ import io
8
+ from google import genai
9
+ from google.genai import types
10
+ import gradio as gr
11
+
12
+ # Initialize client using secret from HF environment
13
+ CLIENT = genai.Client(api_key=os.environ.get("GEMINI_API_KEY"))
14
+ MODEL = "gemini-2.5-flash" # or change to a model available in your project/region
15
+
16
+ # Fixed short reply for text-only chats
17
  TEXT_ONLY_REPLY = "أنا R-RAY AI تم تدريبي على قواعد بيانات طبية ضخمة. كيف يمكنني مساعدتك اليوم؟"
18
 
19
+ # Strict radiology-report instruction (Arabic). The model MUST follow this and reply only with a
20
+ # structured medical radiology report. Keep it concise, professional, and in Arabic. Do not add
21
+ # extra commentary, safety disclaimers, or step-by-step reasoning in the response.
22
+ RADIology_PROMPT_TEMPLATE = '''أنت "R-RAY AI" — نموذج متخصص في تقارير الأشعة، تدربت على قواعد بيانات طبية ضخمة.
23
+ تعليمات صارمة:
24
+ 1) عند استلام صور شعاعية (واحدة أو أكثر) — أجب **فقط** بتقرير طبي احترافي بصيغة تقارير الأشعة المستعملة سريريًا.
25
+ 2) لا تضف جمل ترويجية أو اعتذارات أو نص خارج إطار التقرير.
26
+ 3) إخراج التقرير يجب أن يحتوي على الأقسام التالية بالترتيب: عنوان الدراسة، تاريخ الاستلام (التاريخ اليومي تلقائيًا)، رقم المريض (إن وُرد)، التاريخ السريري/شكوى المريض (من نص المستخدم إن وُجد)، التقنية (نوع الصور: X-ray, CT, MRI + الإطارات/القطاعات المرفقة)، وصف تفصيلي للنتائج (ملاحظات عامة ومقارنة إن وُجدت معلومات سابقة)، خاتمة/تقرير تشخيصي موجز مع توصية مفيدة واحدة على الأكثر (مثل: متابعة، توصية بإجراء تصوير مقطعي/تصوير رنين، أو استشارة اختصاصي).
27
+ 4) إذا كان هناك أكثر من صورة اذكر كل صورة مرقمة ووصف كل واحدة تحت قسم "الصور" ثم ادمج النتائج في قسم "النتائج".
28
+ 5) اللغة: العربية الفصحى طبية. الطول: تقرير كامل ومحترف (لا تقل عن 6 جمل في الوصف ما لم تكن الصور طبيعية تمامًا).
 
 
 
 
 
 
 
 
 
29
 
30
+ البيانات المرسلة:
31
+ {clinical_text}
 
 
 
32
 
33
  الصور المرسلة: {image_list}
34
 
35
+ أعد فقط التقرير الطبي بالصيغة المطلوبة. انتهى.
36
+ '''
37
+
38
+
39
+ def make_parts_from_images(image_files):
40
+ parts = []
41
+ for idx, img in enumerate(image_files, start=1):
42
+ # img is a tempfile-like object from Gradio; read bytes
43
+ img_bytes = img.read()
44
+ # prefer from_bytes (supported in google-genai). fallback to from_image if exists.
45
+ try:
46
+ part = types.Part.from_bytes(img_bytes)
47
+ except Exception:
48
+ try:
49
+ part = types.Part.from_image(img_bytes)
50
+ except Exception:
51
+ # if both fail, embed base64 text as a last resort
52
+ import base64
53
+ b64 = base64.b64encode(img_bytes).decode('utf-8')
54
+ part = types.Part.from_text(f"[BASE64_IMAGE_{idx}] {b64}")
55
+ parts.append(part)
56
+ return parts
57
+
58
+
59
+ def analyze(images, clinical_text):
60
+ clinical_text = (clinical_text or "").strip()
61
+ images = images or []
62
+
63
+ # If no images: provide the fixed text-only reply
64
+ if len(images) == 0:
65
+ # If the user sent text only, return the strict assistant opening line
66
+ return TEXT_ONLY_REPLY
67
+
68
+ # Build list of image names for prompt
69
+ image_names = []
70
+ for i, f in enumerate(images, start=1):
71
+ name = getattr(f, "name", None) or f"image_{i}"
72
+ image_names.append(name)
73
+ image_list_text = ", ".join(image_names)
74
+
75
+ # Prepare prompt (strict)
76
+ prompt_text = RADIology_PROMPT_TEMPLATE.format(
77
+ clinical_text=clinical_text if clinical_text else "(لا توجد معلومات سريرية إضافية)",
78
+ image_list=image_list_text,
79
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
+ # Build content parts: first the images, then the instruction as text part
82
+ parts = make_parts_from_images(images)
83
+ parts.append(types.Part.from_text(prompt_text))
84
+
85
+ contents = [
86
+ types.Content(
87
+ role="user",
88
+ parts=parts,
89
+ )
90
+ ]
91
+
92
+ # Call Gemini (synchronous)
93
+ try:
94
+ response = CLIENT.models.generate_content(
95
+ model=MODEL,
96
+ contents=contents,
97
+ config=types.GenerateContentConfig(
98
+ thinking_config=types.ThinkingConfig(thinking_budget=-1),
99
+ ),
100
+ )
101
+ # return text output
102
+ return response.text
103
+ except Exception as e:
104
+ return f"خطأ أثناء الاتصال بنموذج Gemini: {e}"
105
+
106
+
107
+ # Build Gradio UI
108
+ with gr.Blocks() as demo:
109
+ gr.Markdown("# R-RAY AI — تقارير الأشعة\nارفع صور شعاعية (X-ray, CT, MRI) ويمكنك أيضًا ارفاق ملاحظات سريرية قصيرة.")
110
+
111
+ with gr.Row():
112
+ image_input = gr.Files(label="تحميل صور (يمكن رفع أكثر من صورة)", file_count="multiple", type="file")
113
+ clinical_input = gr.Textbox(label="معلومات سريرية / تاريخ المريض (اختياري)", lines=4)
114
+
115
+ output = gr.Textbox(label="تقرير الأشعة (الناتج)", lines=20)
116
+
117
+ btn = gr.Button("تحليل وإصدار التقرير")
118
+ btn.click(fn=analyze, inputs=[image_input, clinical_input], outputs=[output])
119
+
120
+ gr.Markdown("**ملاحظة:** هذا النموذج للاختبار/التطوير فقط ولا يغني عن استشارة طبية حقيقية.")
121
+
122
+ if __name__ == "__main__":
123
+ demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))