Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import gradio as gr
|
| 3 |
+
import google.generativeai as genai
|
| 4 |
+
|
| 5 |
+
# 在 Hugging Face Space 裡,把 GEMINI_API_KEY 設在「Settings → Variables and secrets」
|
| 6 |
+
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
| 7 |
+
|
| 8 |
+
if not GEMINI_API_KEY:
|
| 9 |
+
raise RuntimeError("請在環境變數中設定 GEMINI_API_KEY,避免將金鑰寫死在程式裡。")
|
| 10 |
+
|
| 11 |
+
genai.configure(api_key=GEMINI_API_KEY)
|
| 12 |
+
|
| 13 |
+
# 你可以改成想用的模型,例如 "gemini-1.5-pro" 或你說的 2.0 flash 對應名稱
|
| 14 |
+
MODEL_NAME = "gemini-1.5-flash"
|
| 15 |
+
|
| 16 |
+
SYSTEM_PROMPT = """
|
| 17 |
+
你是一個以科學為基礎、態度保守的「成分安全性與相互作用說明助手」。
|
| 18 |
+
|
| 19 |
+
【任務】
|
| 20 |
+
使用者會提供:
|
| 21 |
+
1. 主成分(單一或少數幾個關鍵成分)
|
| 22 |
+
2. 其餘成分(配方中其他成分,可以是逗號或換行分隔)
|
| 23 |
+
3. 產品類型(食品 / 保健品 / 藥品)
|
| 24 |
+
4. 預期用途(例如:幫助睡眠、運動表現、慢性病患者使用等)
|
| 25 |
+
|
| 26 |
+
你的工作是:
|
| 27 |
+
A. 逐一說明每一個成分在人類使用上的:
|
| 28 |
+
- 一般用途與大致機轉(如果有公認機制)
|
| 29 |
+
- 安全性概況(低風險 / 需注意 / 高風險或需醫師監督)
|
| 30 |
+
- 常見副作用或注意事項(如果已知)
|
| 31 |
+
- 資料不足時要明確說「目前缺乏足夠的人體安全性資料」
|
| 32 |
+
|
| 33 |
+
B. 評估成分之間可能的化學/生物交互作用:
|
| 34 |
+
- 是否有機轉上可能的加乘效果、拮抗效果
|
| 35 |
+
- 是否可能同時影響相同的器官(例如肝臟、腎臟、中樞神經系統、心血管系統)
|
| 36 |
+
- 是否存在理論上或已知的風險(例如:與抗凝血藥、降糖藥、抗癲癇藥等常見用藥可能交互作用)
|
| 37 |
+
- 若資料有限或僅為理論推測,請清楚標示為「推測性風險」
|
| 38 |
+
|
| 39 |
+
C. 依使用者輸入的「用途」評估此配方是否「合理對應用途」:
|
| 40 |
+
- 簡要說明:此配方是否在機轉上大致合理?是否有明顯不符用途或畫蛇添足的成分?
|
| 41 |
+
- 將整體風險分為:低 / 中 / 高,並簡短說明理由。
|
| 42 |
+
|
| 43 |
+
D. 報告格式:
|
| 44 |
+
請用清楚分段與標題輸出,建議結構如下:
|
| 45 |
+
1. 配方與用途摘要
|
| 46 |
+
2. 各成分安全性與注意事項(條列)
|
| 47 |
+
3. 成分間可能的交互作用與潛在風險
|
| 48 |
+
4. 對「用途」的整體評估
|
| 49 |
+
5. 重要提醒與建議(務必包含下列警語)
|
| 50 |
+
|
| 51 |
+
E. 重要限制與警語(必須每次都出現):
|
| 52 |
+
- 你提供的是一般性科學與安全性資訊整理,不是醫療診斷或治療建議。
|
| 53 |
+
- 不提供劑量建議、不替使用者調整處方、不對個人疾病狀況做具體指示。
|
| 54 |
+
- 如使用者有慢性疾病、正在懷孕、服用處方藥或有特殊體質,應諮詢醫師或藥師後再決定是否使用。
|
| 55 |
+
- 對於資料不足或爭議較大的成分,應明確說明「尚無充分高品質人體試驗證據」。
|
| 56 |
+
|
| 57 |
+
【風格要求】
|
| 58 |
+
- 口吻專業但易懂,偏向「風險溝通」而不是行銷。
|
| 59 |
+
- 寧可保守一點,也不要誇大功效或安全性。
|
| 60 |
+
- 禁止使用「完全無副作用」、「百分之百安全」這類絕對用語。
|
| 61 |
+
- 有不確定的地方要說「目前證據有限」或「資料不足」,不要硬編造。
|
| 62 |
+
"""
|
| 63 |
+
|
| 64 |
+
def build_prompt(main_ingredient: str,
|
| 65 |
+
other_ingredients: str,
|
| 66 |
+
product_type: str,
|
| 67 |
+
purpose: str) -> str:
|
| 68 |
+
user_part = f"""
|
| 69 |
+
主成分:{main_ingredient}
|
| 70 |
+
|
| 71 |
+
其餘成分:
|
| 72 |
+
{other_ingredients}
|
| 73 |
+
|
| 74 |
+
產品類型:{product_type}
|
| 75 |
+
預期用途:{purpose}
|
| 76 |
+
|
| 77 |
+
請依照系統提示詞的規範,產生一份結構化的中文報告。
|
| 78 |
+
"""
|
| 79 |
+
# 用單輪 prompt,把系統說明 + 使用者輸入合併
|
| 80 |
+
full_prompt = SYSTEM_PROMPT.strip() + "\n\n==== 使用者輸入 ====\n" + user_part.strip()
|
| 81 |
+
return full_prompt
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def call_gemini(main_ingredient, other_ingredients, product_type, purpose):
|
| 85 |
+
if not main_ingredient and not other_ingredients:
|
| 86 |
+
return "請至少輸入主成分或其餘成分。"
|
| 87 |
+
|
| 88 |
+
prompt = build_prompt(main_ingredient, other_ingredients, product_type, purpose)
|
| 89 |
+
|
| 90 |
+
model = genai.GenerativeModel(MODEL_NAME)
|
| 91 |
+
try:
|
| 92 |
+
response = model.generate_content(prompt)
|
| 93 |
+
except Exception as e:
|
| 94 |
+
return f"模型呼叫失敗:{e}"
|
| 95 |
+
|
| 96 |
+
if not response or not response.candidates:
|
| 97 |
+
return "模型沒有回應,請稍後再試。"
|
| 98 |
+
|
| 99 |
+
# google-generativeai 的文字結果通常在 .text
|
| 100 |
+
return response.text.strip()
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def clear_all():
|
| 104 |
+
# 依照下面 .click 的 outputs 順序回傳預設值
|
| 105 |
+
return "", "", "保健品", "", ""
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
with gr.Blocks(title="成分安全性與交互作用評估") as demo:
|
| 109 |
+
gr.Markdown(
|
| 110 |
+
"""
|
| 111 |
+
# 成分安全性與交互作用評估(Gemini 示範)
|
| 112 |
+
|
| 113 |
+
輸入主成分、其餘成分、產品類型與預期用途,產生一份簡易的安全性與交互作用報告。
|
| 114 |
+
|
| 115 |
+
> ⚠️ 本工具僅提供一般性資訊整理,**不構成醫療建議或處方依據**。
|
| 116 |
+
"""
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
with gr.Row():
|
| 120 |
+
main_ingredient = gr.Textbox(
|
| 121 |
+
label="主成分",
|
| 122 |
+
placeholder="例如:氫化珊瑚鈣、維生素D3…",
|
| 123 |
+
)
|
| 124 |
+
product_type = gr.Radio(
|
| 125 |
+
label="產品類型",
|
| 126 |
+
choices=["食品", "保健品", "藥品"],
|
| 127 |
+
value="保健品",
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
other_ingredients = gr.Textbox(
|
| 131 |
+
label="其餘成分",
|
| 132 |
+
lines=4,
|
| 133 |
+
placeholder="可用逗號或換行分隔,例如:麥芽糊精、硬脂酸鎂、明膠膠囊…"
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
purpose = gr.Textbox(
|
| 137 |
+
label="預期用途",
|
| 138 |
+
lines=3,
|
| 139 |
+
placeholder="例如:協助入睡、運動後恢復、長期糖尿病患者補充鈣質…"
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
report = gr.Markdown(label="分析報告")
|
| 143 |
+
|
| 144 |
+
with gr.Row():
|
| 145 |
+
analyze_btn = gr.Button("分析配方", variant="primary")
|
| 146 |
+
clear_btn = gr.Button("清空", variant="secondary")
|
| 147 |
+
|
| 148 |
+
# 單次分析(不保留歷史)──每按一次就重新組 prompt
|
| 149 |
+
analyze_btn.click(
|
| 150 |
+
fn=call_gemini,
|
| 151 |
+
inputs=[main_ingredient, other_ingredients, product_type, purpose],
|
| 152 |
+
outputs=report,
|
| 153 |
+
)
|
| 154 |
+
|
| 155 |
+
# 清空所有輸入 + 輸出
|
| 156 |
+
clear_btn.click(
|
| 157 |
+
fn=clear_all,
|
| 158 |
+
inputs=[],
|
| 159 |
+
outputs=[main_ingredient, other_ingredients, product_type, purpose, report],
|
| 160 |
+
)
|
| 161 |
+
|
| 162 |
+
if __name__ == "__main__":
|
| 163 |
+
demo.launch()
|