Update app.py
Browse files
app.py
CHANGED
@@ -16,16 +16,14 @@ MODEL = "gemini-2.5-flash" # or change to a model available in your project/reg
|
|
16 |
# Fixed short reply for text-only chats
|
17 |
TEXT_ONLY_REPLY = "أنا R-RAY AI تم تدريبي على قواعد بيانات طبية ضخمة. كيف يمكنني مساعدتك اليوم؟"
|
18 |
|
19 |
-
# Strict radiology-report instruction (Arabic)
|
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) اللغة: العربية الفصحى طبية. الطول: تقرير كامل ومحترف (لا
|
29 |
|
30 |
البيانات المرسلة:
|
31 |
{clinical_text}
|
@@ -39,16 +37,13 @@ RADIology_PROMPT_TEMPLATE = '''أنت "R-RAY AI" — نموذج متخصص في
|
|
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}")
|
@@ -60,25 +55,20 @@ 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 |
|
@@ -89,7 +79,6 @@ def analyze(images, clinical_text):
|
|
89 |
)
|
90 |
]
|
91 |
|
92 |
-
# Call Gemini (synchronous)
|
93 |
try:
|
94 |
response = CLIENT.models.generate_content(
|
95 |
model=MODEL,
|
@@ -98,18 +87,16 @@ def analyze(images, clinical_text):
|
|
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.
|
113 |
clinical_input = gr.Textbox(label="معلومات سريرية / تاريخ المريض (اختياري)", lines=4)
|
114 |
|
115 |
output = gr.Textbox(label="تقرير الأشعة (الناتج)", lines=20)
|
|
|
16 |
# Fixed short reply for text-only chats
|
17 |
TEXT_ONLY_REPLY = "أنا R-RAY AI تم تدريبي على قواعد بيانات طبية ضخمة. كيف يمكنني مساعدتك اليوم؟"
|
18 |
|
19 |
+
# Strict radiology-report instruction (Arabic)
|
|
|
|
|
20 |
RADIology_PROMPT_TEMPLATE = '''أنت "R-RAY AI" — نموذج متخصص في تقارير الأشعة، تدربت على قواعد بيانات طبية ضخمة.
|
21 |
تعليمات صارمة:
|
22 |
1) عند استلام صور شعاعية (واحدة أو أكثر) — أجب **فقط** بتقرير طبي احترافي بصيغة تقارير الأشعة المستعملة سريريًا.
|
23 |
2) لا تضف جمل ترويجية أو اعتذارات أو نص خارج إطار التقرير.
|
24 |
+
3) إخراج التقرير يجب أن يحتوي على الأقسام التالية بالترتيب: عنوان الدراسة، تاريخ الاستلام (التاريخ اليومي تلقائيًا)، رقم المريض (إن وُرد)، التاريخ السريري/شكوى المريض (من نص المستخدم إن وُجد)، التقنية (نوع الصور: X-ray, CT, MRI + الإطارات/القطاعات المرفقة)، وصف تفصيلي للنتائج، خاتمة/تقرير تشخيصي موجز مع توصية واحدة على الأكثر.
|
25 |
4) إذا كان هناك أكثر من صورة — اذكر كل صورة مرقمة ووصف كل واحدة تحت قسم "الصور" ثم ادمج النتائج في قسم "النتائج".
|
26 |
+
5) اللغة: العربية الفصحى طبية. الطول: تقرير كامل ومحترف (لا يقل عن 6 جمل في الوصف ما لم تكن الصور طبيعية تمامًا).
|
27 |
|
28 |
البيانات المرسلة:
|
29 |
{clinical_text}
|
|
|
37 |
def make_parts_from_images(image_files):
|
38 |
parts = []
|
39 |
for idx, img in enumerate(image_files, start=1):
|
|
|
40 |
img_bytes = img.read()
|
|
|
41 |
try:
|
42 |
part = types.Part.from_bytes(img_bytes)
|
43 |
except Exception:
|
44 |
try:
|
45 |
part = types.Part.from_image(img_bytes)
|
46 |
except Exception:
|
|
|
47 |
import base64
|
48 |
b64 = base64.b64encode(img_bytes).decode('utf-8')
|
49 |
part = types.Part.from_text(f"[BASE64_IMAGE_{idx}] {b64}")
|
|
|
55 |
clinical_text = (clinical_text or "").strip()
|
56 |
images = images or []
|
57 |
|
|
|
58 |
if len(images) == 0:
|
|
|
59 |
return TEXT_ONLY_REPLY
|
60 |
|
|
|
61 |
image_names = []
|
62 |
for i, f in enumerate(images, start=1):
|
63 |
name = getattr(f, "name", None) or f"image_{i}"
|
64 |
image_names.append(name)
|
65 |
image_list_text = ", ".join(image_names)
|
66 |
|
|
|
67 |
prompt_text = RADIology_PROMPT_TEMPLATE.format(
|
68 |
clinical_text=clinical_text if clinical_text else "(لا توجد معلومات سريرية إضافية)",
|
69 |
image_list=image_list_text,
|
70 |
)
|
71 |
|
|
|
72 |
parts = make_parts_from_images(images)
|
73 |
parts.append(types.Part.from_text(prompt_text))
|
74 |
|
|
|
79 |
)
|
80 |
]
|
81 |
|
|
|
82 |
try:
|
83 |
response = CLIENT.models.generate_content(
|
84 |
model=MODEL,
|
|
|
87 |
thinking_config=types.ThinkingConfig(thinking_budget=-1),
|
88 |
),
|
89 |
)
|
|
|
90 |
return response.text
|
91 |
except Exception as e:
|
92 |
return f"خطأ أثناء الاتصال بنموذج Gemini: {e}"
|
93 |
|
94 |
|
|
|
95 |
with gr.Blocks() as demo:
|
96 |
gr.Markdown("# R-RAY AI — تقارير الأشعة\nارفع صور شعاعية (X-ray, CT, MRI) ويمكنك أيضًا ارفاق ملاحظات سريرية قصيرة.")
|
97 |
|
98 |
with gr.Row():
|
99 |
+
image_input = gr.File(label="تحميل صور (يمكن رفع أكثر من صورة)", file_types=[".png", ".jpg", ".jpeg", ".dcm"], file_types_description="Images", type="binary", file_count="multiple")
|
100 |
clinical_input = gr.Textbox(label="معلومات سريرية / تاريخ المريض (اختياري)", lines=4)
|
101 |
|
102 |
output = gr.Textbox(label="تقرير الأشعة (الناتج)", lines=20)
|