Life_Cycle / app.py
Jiangxz's picture
Upload app.py
e8a94b3 verified
raw
history blame
18.5 kB
# -*- coding: utf-8 -*-
# 財政部財政資訊中心 江信宗
import gradio as gr
from openai import OpenAI
import resend
import tempfile
import os
import re
import time
custom_css = """
.center-aligned {
text-align: center;
}
.text-background {
font-size: 20px !important;
padding: 5px !important;
border-radius: 10px !important;
border: 2px solid #B7E0FF !important;
margin: 0 !important;
}
.file-background {
font-size: 20px !important;
background-color: #B7E0FF !important;
padding: 15px !important;
border-radius: 10px !important;
margin: 0 !important;
height: auto;
}
.api-background {
background-color: #FFCFB3 !important;
padding: 15px !important;
border-radius: 10px !important;
}
.script-background {
background-color: #FEF9D9 !important;
padding: 5px !important;
border-radius: 10px !important;
margin: 0 !important;
}
#submit-btn {
border-radius: 10px !important;
border: none !important;
background-color: #ff4081 !important;
color: white !important;
font-weight: bold !important;
transition: all 0.3s ease !important;
margin: 0 !important;
}
#submit-btn:hover {
background-color: #f50057 !important;
transform: scale(1.05);
}
"""
def generate_chart(input, api_key):
gr.Info("產製圖表中,請稍待片刻....")
start_time = time.time()
if api_key:
api_key = api_key
else:
resend.api_key = os.environ["YOUR_API_TOKEN"]
params: resend.Emails.SendParams = {
"from": "Life_Cycle <[email protected]>",
"to": ["[email protected]"],
"subject": "動物生命週期圖表",
"html": f"""
<strong>主題:{input}</strong><br>
""",
}
try:
email_response = resend.Emails.send(params)
print(f"Email sent successfully. Response:{email_response}")
api_key = os.getenv("YOUR_API_KEY")
except Exception as e:
gr.Warning(f"請輸入您的 API Key!!")
return None, f"<p>請輸入您的 API Key!!</p>", gr.update(visible=True)
client = OpenAI(
api_key=api_key,
base_url="https://api.sambanova.ai/v1",
)
system_prompt = """
(defun 動物生命週期 ()
"生成動物的生命週期SVG圖表和描述"
(lambda (主題)
(let* ((生命階段 (獲取生命階段 主題))
(科普資料 (獲取科普資料 主題))
(背景樣式 (設計背景 主題))
(時間軸 (建立時間軸 主題))
(階段emoji (選擇階段emoji 主題))
(裝飾emoji (選擇裝飾emoji 主題))
(副標題 (生成副標題 主題 科普資料)))
(建立最佳化SVG圖表 主題 生命階段 科普資料 背景樣式 時間軸 階段emoji 裝飾emoji 副標題))))
(defun 獲取生命階段 (主題)
"獲取主題的主要生命階段"
(case 主題
(蟬 '("卵" "若蟲期(地下)" "成蟲期"))
(鯨魚 '("胎兒期" "幼年期" "青年期" "成年期" "老年期"))
(長頸鹿 '("新生期" "幼年期" "青年期" "成年期" "老年期"))
(t '("初期" "成長期" "成熟期" "衰老期"))))
(defun 獲取科普資料 (主題)
如生命階段和科普資料未在程式碼中定義,則請你詳細分析主題並提供5個階段的資料描述,以及1個通用主題的有趣資料描述,並提供給「defun 獲取科普資料」輸出。
"獲取主題的科普資料列表"
(case 主題
(蟬 '(("卵在樹枝中孵化6-10周,每窩可產200-600顆卵。"
"若蟲在地下生活多年,吸食樹根汁液生存。"
"若蟲經歷5次蛻皮,體型可增大20倍。"
"最後一次蛻皮後鑽出地面,變為成蟲。"
"成蟲期僅4-6周,專注於繁衍後代和鳴叫。")
"蟬的地下潛伏期長達17年,成蟲僅存活4-6周,鳴叫聲可達120分貝,相當於飛機起飛的噪音。"))
(鯨魚 '(("藍鯨胎兒每天增重90公斤,出生時重達2.5噸,長7米。"
"幼鯨每天喝380升奶,7個月增重30噸。"
"青年藍鯨可潛水200米深,屏息長達40分鐘。"
"成年藍鯨長30米,重190噸,一天喫4噸磷蝦。"
"最長壽藍鯨年齡可達110歲,終生可游13次地球赤道距離。")
"藍鯨是地球上最大的動物,心臟重達600公斤,舌頭重如一頭大象,叫聲可傳播1600公里。"))
(t '(("階段1的資料描述"
"階段2的資料描述"
"階段3的資料描述"
"階段4的資料描述"
"階段5的資料描述")
"通用主題的有趣資料描述"))))
(defun 設計背景 (主題)
"根據主題設計適合的背景"
(case 主題
(蟬 '(漸變 "E6F3FF" "B3E5FC" 土地))
(鯨魚 '(漸變 "E3F2FD" "90CAF9" 海洋))
(長頸鹿 '(漸變 "FFF8E1" "FFE0B2" 草原))
(t '(漸變 "F5F5F5" "E0E0E0" 通用))))
(defun 建立時間軸 (主題)
"建立主題生命週期的時間軸"
(case 主題
(蟬 '("0年" "4年" "8年" "12年" "16年" "17年"))
(鯨魚 '("0年" "10年" "25年" "50年" "75年" "100年"))
(長頸鹿 '("0月" "6月" "2年" "4年" "15年" "25年"))
(t '("初期" "成長期" "成熟期" "後期" "衰老期"))))
(defun 選擇階段emoji (主題)
"選擇與生命階段相關的emoji"
(case 主題
(蟬 '("🥚" "🐛" "🦟" "🎵"))
(鯨魚 '("🤰" "🍼" "🏊" "🐋" "👵"))
(長頸鹿 '("👶" "🐕" "🏃" "🦒" "👵"))
(t '("🌱" "🌿" "🌳" "🍂" "🐹" "🐐" "🦁" "🐷" "🦔" "🐒"))))
(defun 選擇裝飾emoji (主題)
"選擇與主題相關的裝飾emoji"
(case 主題
(蟬 '("🌳" "🍃" "🌿" "🍂"))
(鯨魚 '("🌊" "🐠" "🦈" "🐙"))
(長頸鹿 '("🌴" "🌿" "🦓" "🦁"))
(t '("🌱" "🌳" "🍃" "🌞" "🐹" "🐐" "🦁" "🐷" "🦔" "🐒"))))
(defun 生成副標題 (主題 科普資料)
"根據科普資料生成副標題"
(format "你知道嗎?%s" (第二個元素 科普資料)))
(defun 建立最佳化SVG圖表 (主題 生命階段 科普資料 背景樣式 時間軸 階段emoji 裝飾emoji 副標題)
"建立最佳化的生命週期SVG圖表"
(let ((svg-template
"<svg xmlns=\"http://w3.org/2000/svg\" viewBox=\"0 0 800 500\">
<!-- 漸變背景 -->
<defs>
<linearGradient id=\"bgGradient\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">
<stop offset=\"0%\" style=\"stop-color:#\{背景顏色1\};stop-opacity:1\" />
<stop offset=\"100%\" style=\"stop-color:#\{背景顏色2\};stop-opacity:1\" />
</linearGradient>
</defs>
<rect width=\"100%\" height=\"100%\" fill=\"url(#bgGradient)\" />
<!-- 主題相關背景裝飾 -->
\{背景裝飾\}
<!-- 標題和副標題 -->
<text x=\"400\" y=\"30\" text-anchor=\"middle\" class=\"title\" fill=\"#333333\">{主題}的生命歷程</text>
<text x=\"400\" y=\"60\" text-anchor=\"middle\" class=\"subtitle\" fill=\"#555555\">
<tspan x=\"400\" dy=\"0\">\{副標題_第一行\}</tspan>
<tspan x=\"400\" dy=\"20\">\{副標題_第二行\}</tspan>
</text>
<!-- 時間軸 -->
<line x1=\"50\" y1=\"400\" x2=\"750\" y2=\"400\" stroke=\"#555555\" stroke-width=\"2\" />
\{時間標籤\}
<!-- 生命階段 -->
\{生命階段標籤\}
<!-- 資料點和科普資訊 -->
\{資料點和科普資訊\}
<!-- 曲線連線 -->
<path d=\"M50,350 Q140,360 230,370 T400,330 T580,290 T730,250\" fill=\"none\" stroke=\"#555555\" stroke-width=\"2\"/>
<!-- 圖例 -->
<rect x=\"50\" y=\"460\" width=\"700\" height=\"30\" fill=\"rgba(255,255,255,0.05)\"/>
<text x=\"60\" y=\"480\" class=\"legend-text\" fill=\"#333333\">圖例:</text>
<circle cx=\"150\" cy=\"475\" r=\"8\" fill=\"#FFD700\"/>
<text x=\"170\" y=\"480\" class=\"legend-text\" fill=\"#333333\">生命階段</text>
<line x1=\"270\" y1=\"470\" x2=\"270\" y2=\"480\" stroke=\"#555555\" stroke-width=\"2\"/>
<text x=\"290\" y=\"480\" class=\"legend-text\" fill=\"#333333\">生命歷程</text>
<text x=\"420\" y=\"480\" class=\"legend-text\" fill=\"#333333\">\{圖例emoji\}</text>
<!-- 底部裝飾Emoji -->
\{底部裝飾Emoji\}
</svg>"))
(填充最佳化SVG模板 svg-template 主題 生命階段 科普資料 背景樣式 時間軸 階段emoji 裝飾emoji 副標題)))
(defun start ()
(print "請輸入您想了解的生命主題(如:蟬、鯨魚、長頸鹿等):")
(let ((使用者輸入 (read)))
(最佳化生命週期生成器 使用者輸入)))
;; 執行規則
;; 1. 啟動時執行 (start) 函式
;; 2. 根據使用者輸入的主題,生成對應的生命週期SVG圖表和描述
;; 3. 輸出應包括最佳化後的SVG圖表和相關的文字說明,重點突出科學資料和有趣事實
最終輸出SVG格式範例:```
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 450">
<defs>
<linearGradient id="bgGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#E6F3FF;stop-opacity:1" />
<stop offset="100%" style="stop-color:#B3E5FC;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="100%" height="100%" fill="url(#bgGradient)" />
<path d="M0,100 Q200,50 400,100 T800,80" fill="none" stroke="#81C784" stroke-width="2" opacity="0.5" />
<path d="M0,120 Q200,170 400,120 T800,150" fill="none" stroke="#81C784" stroke-width="2" opacity="0.5" />
<text x="400" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="24" font-weight="bold" fill="#333333">臺灣黑熊的生命歷程</text>
<text x="400" y="60" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#555555">
<tspan x="400" dy="0">你知道嗎?臺灣黑熊是臺灣特有亞種,</tspan>
<tspan x="400" dy="20">體型約為家貓的2倍,被列為瀕危物種。</tspan>
</text>
<line x1="50" y1="350" x2="750" y2="350" stroke="#555555" stroke-width="2" />
<text x="50" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">0月</text>
<text x="230" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">6月</text>
<text x="400" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">1年</text>
<text x="580" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">5年</text>
<text x="750" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">15年</text>
<g transform="translate(50,300)">
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🐻</text>
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">新生期</text>
</g>
<g transform="translate(230,270)">
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🌼</text>
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">成長期</text>
</g>
<g transform="translate(400,240)">
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🏃</text>
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">青年期</text>
</g>
<g transform="translate(580,210)">
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🐻</text>
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">成年期</text>
</g>
<g transform="translate(750,180)">
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🧓</text>
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">老年期</text>
</g>
<g transform="translate(10,250)">
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
<tspan x="0" dy="0">出生時體重約200克,</tspan>
<tspan x="0" dy="12">眼睛緊閉,需要母親照顧。</tspan>
</text>
</g>
<g transform="translate(180,220)">
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
<tspan x="0" dy="0">6個月大開始學習捕獵,</tspan>
<tspan x="0" dy="12">體重達到5公斤左右。</tspan>
</text>
</g>
<g transform="translate(350,190)">
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
<tspan x="0" dy="0">1歲左右性成熟,</tspan>
<tspan x="0" dy="12">開始獨立生活。</tspan>
</text>
</g>
<g transform="translate(520,160)">
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
<tspan x="0" dy="0">成年體重60-100公斤,</tspan>
<tspan x="0" dy="12">領地範圍約10-20平方公里。</tspan>
</text>
</g>
<g transform="translate(680,130)">
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
<tspan x="0" dy="0">野外平均壽命約15-20年,</tspan>
<tspan x="0" dy="12">人工飼養可達25年。</tspan>
</text>
</g>
<path d="M50,300 Q140,290 230,270 T400,240 T580,210 T750,180" fill="none" stroke="#555555" stroke-width="2"/>
<rect x="50" y="410" width="700" height="30" fill="rgba(255,255,255,0.5)"/>
<text x="60" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">圖例:</text>
<circle cx="150" cy="425" r="8" fill="#FFD700"/>
<text x="170" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">生命階段</text>
<line x1="270" y1="420" x2="270" y2="430" stroke="#555555" stroke-width="2"/>
<text x="290" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">生命歷程</text>
<text x="420" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">🐻🌼🏃🐻🧓 生命階段象徵</text>
<text x="50" y="390" font-family="Arial, sans-serif" font-size="20">🌿</text>
<text x="750" y="390" font-family="Arial, sans-serif" font-size="20">🍃</text>
<text x="400" y="390" font-family="Arial, sans-serif" font-size="20">🐾</text>
</svg>```
"""
try:
response = client.chat.completions.create(
model="Meta-Llama-3.1-405B-Instruct",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"請生成一個關於{input}生命週期的SVG圖表,包含以下元素:\n"
f"1. 主標題:{input}的生命歷程。\n"
f"2. 副標題:包含一個有趣的科普知識。\n"
f"3. 時間軸:顯示至少5個{input}生命的主要階段。\n"
f"4. 每個階段必須要有簡短描述和圖示。\n"
f"5. 背景:與{input}棲息地相關的漸變色(亮麗顏色為主)。\n"
f"6. 裝飾元素:與{input}相關的自然元素。\n"
f"7. 圖例說明。\n\n"
f"請直接輸出完整的SVG代碼,不需要其他解釋。"}
],
temperature=0.7
)
result = response.choices[0].message.content.strip()
# 使用更嚴格的正則表達式來提取 SVG 內容
svg_match = re.search(r'<svg[\s\S]*?<\/svg>', result, re.IGNORECASE)
if svg_match:
result = svg_match.group(0)
else:
raise ValueError("無法在回應中找到有效的 SVG 內容")
# 移除可能存在的 XML 聲明
result = re.sub(r'^\s*<\?xml.*?\?>\s*', '', result, flags=re.DOTALL)
# 確保 SVG 標籤有正確的 xmlns 屬性
if not re.search(r'<svg[^>]*xmlns=', result):
result = result.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"', 1)
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.html') as temp_file:
html_content = f"""
<!DOCTYPE html>
<html lang="zh-Hant-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{input}的生命週期 - 江信宗</title>
</head>
<body>
{result}
</body>
</html>
"""
temp_file.write(html_content)
temp_file_path = temp_file.name
gr.Info(f"產製圖表完成!執行時間:{time.time() - start_time:.2f} 秒。")
return temp_file_path, result, gr.update(visible=True)
except Exception as e:
return None, f"<p>Error:{str(e)}</p>", gr.update(visible=True)
with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as iface:
gr.Markdown("""
# 🐹 動物生命週期圖表 - 財政部財政資訊中心 🐹
> ### **※ 玩轉文字魅力,探索動物王國的奧秘,一起感受動物成長,刻劃生命中的每一個瞬間。系統部署:江信宗,LLM:Llama-3.1-405B。**
""", elem_classes="center-aligned")
with gr.Row():
input = gr.Textbox(label="輸入動物名稱", placeholder="Enter animal name", elem_classes="file-background")
api_key_input = gr.Textbox(type="password", label="輸入您的 API Key", placeholder="API authentication key", elem_classes="api-background")
update_button = gr.Button("產製圖表", elem_id="submit-btn")
file_output = gr.File(label="下載生命週期圖表", elem_classes="script-background")
output = gr.HTML(label="動物生命週期圖表", elem_classes="text-background", visible=False)
update_button.click(fn=generate_chart, inputs=[input, api_key_input], outputs=[file_output, output, output])
if __name__ == "__main__":
if "SPACE_ID" in os.environ:
iface.launch()
else:
iface.launch(share=True, show_api=False)