Spaces:
Running
Running
Upload 2 files
Browse files- app.py +378 -0
- requirements.txt +3 -0
app.py
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# 財政部財政資訊中心 江信宗
|
| 3 |
+
|
| 4 |
+
import gradio as gr
|
| 5 |
+
from openai import OpenAI
|
| 6 |
+
import resend
|
| 7 |
+
import tempfile
|
| 8 |
+
import os
|
| 9 |
+
import re
|
| 10 |
+
|
| 11 |
+
custom_css = """
|
| 12 |
+
.center-aligned {
|
| 13 |
+
text-align: center;
|
| 14 |
+
}
|
| 15 |
+
.text-background {
|
| 16 |
+
font-size: 20px !important;
|
| 17 |
+
padding: 5px !important;
|
| 18 |
+
border-radius: 10px !important;
|
| 19 |
+
border: 2px solid #B7E0FF !important;
|
| 20 |
+
margin: 0 !important;
|
| 21 |
+
}
|
| 22 |
+
.file-background {
|
| 23 |
+
font-size: 20px !important;
|
| 24 |
+
background-color: #B7E0FF !important;
|
| 25 |
+
padding: 15px !important;
|
| 26 |
+
border-radius: 10px !important;
|
| 27 |
+
margin: 0 !important;
|
| 28 |
+
height: auto;
|
| 29 |
+
}
|
| 30 |
+
.api-background {
|
| 31 |
+
background-color: #FFCFB3 !important;
|
| 32 |
+
padding: 15px !important;
|
| 33 |
+
border-radius: 10px !important;
|
| 34 |
+
}
|
| 35 |
+
.script-background {
|
| 36 |
+
background-color: #FEF9D9 !important;
|
| 37 |
+
padding: 5px !important;
|
| 38 |
+
border-radius: 10px !important;
|
| 39 |
+
margin: 0 !important;
|
| 40 |
+
}
|
| 41 |
+
#submit-btn {
|
| 42 |
+
border-radius: 10px !important;
|
| 43 |
+
border: none !important;
|
| 44 |
+
background-color: #ff4081 !important;
|
| 45 |
+
color: white !important;
|
| 46 |
+
font-weight: bold !important;
|
| 47 |
+
transition: all 0.3s ease !important;
|
| 48 |
+
margin: 0 !important;
|
| 49 |
+
}
|
| 50 |
+
#submit-btn:hover {
|
| 51 |
+
background-color: #f50057 !important;
|
| 52 |
+
transform: scale(1.05);
|
| 53 |
+
}
|
| 54 |
+
"""
|
| 55 |
+
|
| 56 |
+
def generate_chart(input, api_key):
|
| 57 |
+
gr.Info("產製圖表中,請稍待片刻....")
|
| 58 |
+
if api_key:
|
| 59 |
+
api_key = api_key
|
| 60 |
+
else:
|
| 61 |
+
resend.api_key = os.environ["YOUR_API_TOKEN"]
|
| 62 |
+
params: resend.Emails.SendParams = {
|
| 63 |
+
"from": "Life_Cycle <onboarding@resend.dev>",
|
| 64 |
+
"to": ["antivir7@gmail.com"],
|
| 65 |
+
"subject": "動物生命週期圖表",
|
| 66 |
+
"html": f"""
|
| 67 |
+
<strong>主題:{input}</strong><br>
|
| 68 |
+
""",
|
| 69 |
+
}
|
| 70 |
+
try:
|
| 71 |
+
email_response = resend.Emails.send(params)
|
| 72 |
+
print(f"Email sent successfully. Response:{email_response}")
|
| 73 |
+
api_key = os.getenv("YOUR_API_KEY")
|
| 74 |
+
except Exception as e:
|
| 75 |
+
gr.Warning(f"請輸入您的 API Key!!")
|
| 76 |
+
return None, f"<p>請輸入您的 API Key!!</p>", gr.update(visible=True)
|
| 77 |
+
client = OpenAI(
|
| 78 |
+
api_key=api_key,
|
| 79 |
+
base_url="https://api.sambanova.ai/v1",
|
| 80 |
+
)
|
| 81 |
+
system_prompt = """
|
| 82 |
+
(defun 動物生命週期 ()
|
| 83 |
+
"生成動物的生命週期SVG圖表和描述"
|
| 84 |
+
(lambda (主題)
|
| 85 |
+
(let* ((生命階段 (獲取生命階段 主題))
|
| 86 |
+
(科普資料 (獲取科普資料 主題))
|
| 87 |
+
(背景樣式 (設計背景 主題))
|
| 88 |
+
(時間軸 (建立時間軸 主題))
|
| 89 |
+
(階段emoji (選擇階段emoji 主題))
|
| 90 |
+
(裝飾emoji (選擇裝飾emoji 主題))
|
| 91 |
+
(副標題 (生成副標題 主題 科普資料)))
|
| 92 |
+
(建立最佳化SVG圖表 主題 生命階段 科普資料 背景樣式 時間軸 階段emoji 裝飾emoji 副標題))))
|
| 93 |
+
|
| 94 |
+
(defun 獲取生命階段 (主題)
|
| 95 |
+
"獲取主題的主要生命階段"
|
| 96 |
+
(case 主題
|
| 97 |
+
(蟬 '("卵" "若蟲期(地下)" "成蟲期"))
|
| 98 |
+
(鯨魚 '("胎兒期" "幼年期" "青年期" "成年期" "老年期"))
|
| 99 |
+
(長頸鹿 '("新生期" "幼年期" "青年期" "成年期" "老年期"))
|
| 100 |
+
(t '("初期" "成長期" "成熟期" "衰老期"))))
|
| 101 |
+
|
| 102 |
+
(defun 獲取科普資料 (主題)
|
| 103 |
+
如生命階段和科普資料未在程式碼中定義,則請你詳細分析主題並提供5個階段的資料描述,以及1個通用主題的有趣資料描述,並提供給「defun 獲取科普資料」輸出。
|
| 104 |
+
"獲取主題的科普資料列表"
|
| 105 |
+
(case 主題
|
| 106 |
+
(蟬 '(("卵在樹枝中孵化6-10周,每窩可產200-600顆卵。"
|
| 107 |
+
"若蟲在地下生活多年,吸食樹根汁液生存。"
|
| 108 |
+
"若蟲經歷5次蛻皮,體型可增大20倍。"
|
| 109 |
+
"最後一次蛻皮後鑽出地面,變為成蟲。"
|
| 110 |
+
"成蟲期僅4-6周,專注於繁衍後代和鳴叫。")
|
| 111 |
+
"蟬的地下潛伏期長達17年,成蟲僅存活4-6周,鳴叫聲可達120分貝,相當於飛機起飛的噪音。"))
|
| 112 |
+
(鯨魚 '(("藍鯨胎兒每天增重90公斤,出生時重達2.5噸,長7米。"
|
| 113 |
+
"幼鯨每天喝380升奶,7個月增重30噸。"
|
| 114 |
+
"青年藍鯨可潛水200米深,屏息長達40分鐘。"
|
| 115 |
+
"成年藍鯨長30米,重190噸,一天喫4噸磷蝦。"
|
| 116 |
+
"最長壽藍鯨年齡可達110歲,終生可游13次地球赤道距離。")
|
| 117 |
+
"藍鯨是地球上最大的動物,心臟重達600公斤,舌頭重如一頭大象,叫聲可傳播1600公里。"))
|
| 118 |
+
(t '(("階段1的資料描述"
|
| 119 |
+
"階段2的資料描述"
|
| 120 |
+
"階段3的資料描述"
|
| 121 |
+
"階段4的資料描述"
|
| 122 |
+
"階段5的資料描述")
|
| 123 |
+
"通用主題的有趣資料描述"))))
|
| 124 |
+
|
| 125 |
+
(defun 設計背景 (主題)
|
| 126 |
+
"根據主題設計適合的背景"
|
| 127 |
+
(case 主題
|
| 128 |
+
(蟬 '(漸變 "E6F3FF" "B3E5FC" 土地))
|
| 129 |
+
(鯨魚 '(漸變 "E3F2FD" "90CAF9" 海洋))
|
| 130 |
+
(長頸鹿 '(漸變 "FFF8E1" "FFE0B2" 草原))
|
| 131 |
+
(t '(漸變 "F5F5F5" "E0E0E0" 通用))))
|
| 132 |
+
|
| 133 |
+
(defun 建立時間軸 (主題)
|
| 134 |
+
"建立主題生命週期的時間軸"
|
| 135 |
+
(case 主題
|
| 136 |
+
(蟬 '("0年" "4年" "8年" "12年" "16年" "17年"))
|
| 137 |
+
(鯨魚 '("0年" "10年" "25年" "50年" "75年" "100年"))
|
| 138 |
+
(長頸鹿 '("0月" "6月" "2年" "4年" "15年" "25年"))
|
| 139 |
+
(t '("初期" "成長期" "成熟期" "後期" "衰老期"))))
|
| 140 |
+
|
| 141 |
+
(defun 選擇階段emoji (主題)
|
| 142 |
+
"選擇與生命階段相關的emoji"
|
| 143 |
+
(case 主題
|
| 144 |
+
(蟬 '("🥚" "🐛" "🦟" "🎵"))
|
| 145 |
+
(鯨魚 '("🤰" "🍼" "🏊" "🐋" "👵"))
|
| 146 |
+
(長頸鹿 '("👶" "🐕" "🏃" "🦒" "👵"))
|
| 147 |
+
(t '("🌱" "🌿" "🌳" "🍂" "🐹" "🐐" "🦁" "🐷" "🦔" "🐒"))))
|
| 148 |
+
|
| 149 |
+
(defun 選擇裝飾emoji (主題)
|
| 150 |
+
"選擇與主題相關的裝飾emoji"
|
| 151 |
+
(case 主題
|
| 152 |
+
(蟬 '("🌳" "🍃" "🌿" "🍂"))
|
| 153 |
+
(鯨魚 '("🌊" "🐠" "🦈" "🐙"))
|
| 154 |
+
(長頸鹿 '("🌴" "🌿" "🦓" "🦁"))
|
| 155 |
+
(t '("🌱" "🌳" "🍃" "🌞" "🐹" "🐐" "🦁" "🐷" "🦔" "🐒"))))
|
| 156 |
+
|
| 157 |
+
(defun 生成副標題 (主題 科普資料)
|
| 158 |
+
"根據科普資料生成副標題"
|
| 159 |
+
(format "你知道嗎?%s" (第二個元素 科普資料)))
|
| 160 |
+
|
| 161 |
+
(defun 建立最佳化SVG圖表 (主題 生命階段 科普資料 背景樣式 時間軸 階段emoji 裝飾emoji 副標題)
|
| 162 |
+
"建立最佳化的生命週期SVG圖表"
|
| 163 |
+
(let ((svg-template
|
| 164 |
+
"<svg xmlns=\"http://w3.org/2000/svg\" viewBox=\"0 0 800 500\">
|
| 165 |
+
<!-- 漸變背景 -->
|
| 166 |
+
<defs>
|
| 167 |
+
<linearGradient id=\"bgGradient\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">
|
| 168 |
+
<stop offset=\"0%\" style=\"stop-color:#\{背景顏色1\};stop-opacity:1\" />
|
| 169 |
+
<stop offset=\"100%\" style=\"stop-color:#\{背景顏色2\};stop-opacity:1\" />
|
| 170 |
+
</linearGradient>
|
| 171 |
+
</defs>
|
| 172 |
+
|
| 173 |
+
<rect width=\"100%\" height=\"100%\" fill=\"url(#bgGradient)\" />
|
| 174 |
+
|
| 175 |
+
<!-- 主題相關背景裝飾 -->
|
| 176 |
+
\{背景裝飾\}
|
| 177 |
+
<!-- 標題和副標題 -->
|
| 178 |
+
<text x=\"400\" y=\"30\" text-anchor=\"middle\" class=\"title\" fill=\"#333333\">{主題}的一生</text>
|
| 179 |
+
<text x=\"400\" y=\"60\" text-anchor=\"middle\" class=\"subtitle\" fill=\"#555555\">
|
| 180 |
+
|
| 181 |
+
<tspan x=\"400\" dy=\"0\">\{副標題_第一行\}</tspan>
|
| 182 |
+
<tspan x=\"400\" dy=\"20\">\{副標題_第二行\}</tspan>
|
| 183 |
+
</text>
|
| 184 |
+
<!-- 時間軸 -->
|
| 185 |
+
<line x1=\"50\" y1=\"400\" x2=\"750\" y2=\"400\" stroke=\"#555555\" stroke-width=\"2\" />
|
| 186 |
+
\{時間標籤\}
|
| 187 |
+
<!-- 生命階段 -->
|
| 188 |
+
\{生命階段標籤\}
|
| 189 |
+
<!-- 資料點和科普資訊 -->
|
| 190 |
+
\{資料點和科普資訊\}
|
| 191 |
+
<!-- 曲線連線 -->
|
| 192 |
+
<path d=\"M50,350 Q140,360 230,370 T400,330 T580,290 T730,250\" fill=\"none\" stroke=\"#555555\" stroke-width=\"2\"/>
|
| 193 |
+
<!-- 圖例 -->
|
| 194 |
+
<rect x=\"50\" y=\"460\" width=\"700\" height=\"30\" fill=\"rgba(255,255,255,0.05)\"/>
|
| 195 |
+
<text x=\"60\" y=\"480\" class=\"legend-text\" fill=\"#333333\">圖例:</text>
|
| 196 |
+
<circle cx=\"150\" cy=\"475\" r=\"8\" fill=\"#FFD700\"/>
|
| 197 |
+
<text x=\"170\" y=\"480\" class=\"legend-text\" fill=\"#333333\">生命階段</text>
|
| 198 |
+
<line x1=\"270\" y1=\"470\" x2=\"270\" y2=\"480\" stroke=\"#555555\" stroke-width=\"2\"/>
|
| 199 |
+
<text x=\"290\" y=\"480\" class=\"legend-text\" fill=\"#333333\">生命歷程</text>
|
| 200 |
+
<text x=\"420\" y=\"480\" class=\"legend-text\" fill=\"#333333\">\{圖例emoji\}</text>
|
| 201 |
+
<!-- 底部裝飾Emoji -->
|
| 202 |
+
|
| 203 |
+
\{底部裝飾Emoji\}
|
| 204 |
+
</svg>"))
|
| 205 |
+
(填充最佳化SVG模板 svg-template 主題 生命階段 科普資料 背景樣式 時間軸 階段emoji 裝飾emoji 副標題)))
|
| 206 |
+
(defun start ()
|
| 207 |
+
(print "請輸入您想了解的生命主題(如:蟬、鯨魚、長頸鹿等):")
|
| 208 |
+
(let ((使用者輸入 (read)))
|
| 209 |
+
(最佳化生命週期生成器 使用者輸入)))
|
| 210 |
+
|
| 211 |
+
;; 執行規則
|
| 212 |
+
;; 1. 啟動時執行 (start) 函式
|
| 213 |
+
;; 2. 根據使用者輸入的主題,生成對應的生命週期SVG圖表和描述
|
| 214 |
+
;; 3. 輸出應包括最佳化後的SVG圖表和相關的文字說明,重點突出科學資料和有趣事實
|
| 215 |
+
|
| 216 |
+
最終輸出SVG格式範例:```
|
| 217 |
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 450">
|
| 218 |
+
<defs>
|
| 219 |
+
<linearGradient id="bgGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
| 220 |
+
<stop offset="0%" style="stop-color:#E6F3FF;stop-opacity:1" />
|
| 221 |
+
<stop offset="100%" style="stop-color:#B3E5FC;stop-opacity:1" />
|
| 222 |
+
</linearGradient>
|
| 223 |
+
</defs>
|
| 224 |
+
<rect width="100%" height="100%" fill="url(#bgGradient)" />
|
| 225 |
+
<path d="M0,100 Q200,50 400,100 T800,80" fill="none" stroke="#81C784" stroke-width="2" opacity="0.5" />
|
| 226 |
+
<path d="M0,120 Q200,170 400,120 T800,150" fill="none" stroke="#81C784" stroke-width="2" opacity="0.5" />
|
| 227 |
+
<text x="400" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="24" font-weight="bold" fill="#333333">臺灣黑熊的一生</text>
|
| 228 |
+
<text x="400" y="60" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#555555">
|
| 229 |
+
<tspan x="400" dy="0">你知道嗎?臺灣黑熊是臺灣特有亞種,</tspan>
|
| 230 |
+
<tspan x="400" dy="20">體型約為家貓的2倍,被列為瀕危物種。</tspan>
|
| 231 |
+
</text>
|
| 232 |
+
<line x1="50" y1="350" x2="750" y2="350" stroke="#555555" stroke-width="2" />
|
| 233 |
+
<text x="50" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">0月</text>
|
| 234 |
+
<text x="230" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">6月</text>
|
| 235 |
+
<text x="400" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">1年</text>
|
| 236 |
+
<text x="580" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">5年</text>
|
| 237 |
+
<text x="750" y="370" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#555555">15年</text>
|
| 238 |
+
<g transform="translate(50,300)">
|
| 239 |
+
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
|
| 240 |
+
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🐻</text>
|
| 241 |
+
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">新生期</text>
|
| 242 |
+
</g>
|
| 243 |
+
<g transform="translate(230,270)">
|
| 244 |
+
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
|
| 245 |
+
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🌼</text>
|
| 246 |
+
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">成長期</text>
|
| 247 |
+
</g>
|
| 248 |
+
<g transform="translate(400,240)">
|
| 249 |
+
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
|
| 250 |
+
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🏃</text>
|
| 251 |
+
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">青年期</text>
|
| 252 |
+
</g>
|
| 253 |
+
<g transform="translate(580,210)">
|
| 254 |
+
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
|
| 255 |
+
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🐻</text>
|
| 256 |
+
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">成年期</text>
|
| 257 |
+
</g>
|
| 258 |
+
<g transform="translate(750,180)">
|
| 259 |
+
<circle cx="0" cy="0" r="15" fill="#FFD700"/>
|
| 260 |
+
<text x="0" y="5" text-anchor="middle" font-family="Arial, sans-serif" font-size="20">🧓</text>
|
| 261 |
+
<text x="0" y="40" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#333333">老年期</text>
|
| 262 |
+
</g>
|
| 263 |
+
<g transform="translate(10,250)">
|
| 264 |
+
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
|
| 265 |
+
<tspan x="0" dy="0">出生時體重約200克,</tspan>
|
| 266 |
+
<tspan x="0" dy="12">眼睛緊閉,需要母親照顧。</tspan>
|
| 267 |
+
</text>
|
| 268 |
+
</g>
|
| 269 |
+
<g transform="translate(180,220)">
|
| 270 |
+
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
|
| 271 |
+
<tspan x="0" dy="0">6個月大開始學習捕獵,</tspan>
|
| 272 |
+
<tspan x="0" dy="12">體重達到5公斤左右。</tspan>
|
| 273 |
+
</text>
|
| 274 |
+
</g>
|
| 275 |
+
<g transform="translate(350,190)">
|
| 276 |
+
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
|
| 277 |
+
<tspan x="0" dy="0">1歲左右性成熟,</tspan>
|
| 278 |
+
<tspan x="0" dy="12">開始獨立生活。</tspan>
|
| 279 |
+
</text>
|
| 280 |
+
</g>
|
| 281 |
+
<g transform="translate(520,160)">
|
| 282 |
+
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
|
| 283 |
+
<tspan x="0" dy="0">成年體重60-100公斤,</tspan>
|
| 284 |
+
<tspan x="0" dy="12">領地範圍約10-20平方公里。</tspan>
|
| 285 |
+
</text>
|
| 286 |
+
</g>
|
| 287 |
+
<g transform="translate(680,130)">
|
| 288 |
+
<text x="0" y="0" text-anchor="start" font-family="Arial, sans-serif" font-size="8" fill="#333333">
|
| 289 |
+
<tspan x="0" dy="0">野外平均壽命約15-20年,</tspan>
|
| 290 |
+
<tspan x="0" dy="12">人工飼養可達25年。</tspan>
|
| 291 |
+
</text>
|
| 292 |
+
</g>
|
| 293 |
+
<path d="M50,300 Q140,290 230,270 T400,240 T580,210 T750,180" fill="none" stroke="#555555" stroke-width="2"/>
|
| 294 |
+
<rect x="50" y="410" width="700" height="30" fill="rgba(255,255,255,0.5)"/>
|
| 295 |
+
<text x="60" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">圖例:</text>
|
| 296 |
+
<circle cx="150" cy="425" r="8" fill="#FFD700"/>
|
| 297 |
+
<text x="170" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">生命階段</text>
|
| 298 |
+
<line x1="270" y1="420" x2="270" y2="430" stroke="#555555" stroke-width="2"/>
|
| 299 |
+
<text x="290" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">生命歷程</text>
|
| 300 |
+
<text x="420" y="430" font-family="Arial, sans-serif" font-size="12" fill="#333333">🐻🌼🏃🐻🧓 生命階段象徵</text>
|
| 301 |
+
<text x="50" y="390" font-family="Arial, sans-serif" font-size="20">🌿</text>
|
| 302 |
+
<text x="750" y="390" font-family="Arial, sans-serif" font-size="20">🍃</text>
|
| 303 |
+
<text x="400" y="390" font-family="Arial, sans-serif" font-size="20">🐾</text>
|
| 304 |
+
</svg>```
|
| 305 |
+
"""
|
| 306 |
+
try:
|
| 307 |
+
response = client.chat.completions.create(
|
| 308 |
+
model="Meta-Llama-3.1-405B-Instruct",
|
| 309 |
+
messages=[
|
| 310 |
+
{"role": "system", "content": system_prompt},
|
| 311 |
+
{"role": "user", "content": f"請生成一個關於{input}生命週期的SVG圖表,包含以下元素:\n"
|
| 312 |
+
f"1. 主標題:{input}的一生\n"
|
| 313 |
+
f"2. 副標題:包含一個有趣的科普知識\n"
|
| 314 |
+
f"3. 時間軸:顯示至少5個{input}生命的主要階段\n"
|
| 315 |
+
f"4. 每個階段必須有圖示和簡短描述\n"
|
| 316 |
+
f"5. 背景:與{input}棲息地相關的漸變色\n"
|
| 317 |
+
f"6. 裝飾元素:與{input}相關的自然元素\n"
|
| 318 |
+
f"7. 圖例說明\n\n"
|
| 319 |
+
f"請直接輸出完整的SVG代碼,不需要其他解釋。"}
|
| 320 |
+
],
|
| 321 |
+
temperature=0.7
|
| 322 |
+
)
|
| 323 |
+
result = response.choices[0].message.content.strip()
|
| 324 |
+
|
| 325 |
+
# 使用更嚴格的正則表達式來提取 SVG 內容
|
| 326 |
+
svg_match = re.search(r'<svg[\s\S]*?<\/svg>', result, re.IGNORECASE)
|
| 327 |
+
if svg_match:
|
| 328 |
+
result = svg_match.group(0)
|
| 329 |
+
else:
|
| 330 |
+
raise ValueError("無法在回應中找到有效的 SVG 內容")
|
| 331 |
+
|
| 332 |
+
# 移除可能存在的 XML 聲明
|
| 333 |
+
result = re.sub(r'^\s*<\?xml.*?\?>\s*', '', result, flags=re.DOTALL)
|
| 334 |
+
|
| 335 |
+
# 確保 SVG 標籤有正確的 xmlns 屬性
|
| 336 |
+
if not re.search(r'<svg[^>]*xmlns=', result):
|
| 337 |
+
result = result.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"', 1)
|
| 338 |
+
|
| 339 |
+
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.html') as temp_file:
|
| 340 |
+
html_content = f"""
|
| 341 |
+
<!DOCTYPE html>
|
| 342 |
+
<html lang="zh-Hant-TW">
|
| 343 |
+
<head>
|
| 344 |
+
<meta charset="UTF-8">
|
| 345 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 346 |
+
<title>{input}的生命週期 - 江信宗</title>
|
| 347 |
+
</head>
|
| 348 |
+
<body>
|
| 349 |
+
{result}
|
| 350 |
+
</body>
|
| 351 |
+
</html>
|
| 352 |
+
"""
|
| 353 |
+
temp_file.write(html_content)
|
| 354 |
+
temp_file_path = temp_file.name
|
| 355 |
+
|
| 356 |
+
gr.Info("產製圖表完成!")
|
| 357 |
+
return temp_file_path, result, gr.update(visible=True)
|
| 358 |
+
except Exception as e:
|
| 359 |
+
return None, f"<p>Error:{str(e)}</p>", gr.update(visible=True)
|
| 360 |
+
|
| 361 |
+
with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as iface:
|
| 362 |
+
gr.Markdown("""
|
| 363 |
+
# 🐹 動物生命週期圖表 - 財政部財政資訊中心 🐹
|
| 364 |
+
> ### **※ 玩轉文字魅力,使用開源小模型,刻劃動物的成長歷程。系統部署:江信宗,LLM:Llama-3.1-70B。**
|
| 365 |
+
""", elem_classes="center-aligned")
|
| 366 |
+
with gr.Row():
|
| 367 |
+
input = gr.Textbox(label="請輸入動物名稱", placeholder="Enter animal name", elem_classes="file-background")
|
| 368 |
+
api_key_input = gr.Textbox(type="password", label="請輸入您的 API Key", placeholder="API authentication key", elem_classes="api-background")
|
| 369 |
+
update_button = gr.Button("產製圖表", elem_id="submit-btn")
|
| 370 |
+
file_output = gr.File(label="下載HTML文件", elem_classes="script-background")
|
| 371 |
+
output = gr.HTML(label="動物生命週期圖表", elem_classes="text-background", visible=False) # Set initial visibility to False
|
| 372 |
+
update_button.click(fn=generate_chart, inputs=[input, api_key_input], outputs=[file_output, output, output]) # Add output to update visibility
|
| 373 |
+
|
| 374 |
+
if __name__ == "__main__":
|
| 375 |
+
if "SPACE_ID" in os.environ:
|
| 376 |
+
iface.launch()
|
| 377 |
+
else:
|
| 378 |
+
iface.launch(share=True, show_api=False)
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
openai
|
| 3 |
+
resend
|