File size: 6,199 Bytes
33f1e89
 
6ace570
 
33f1e89
 
 
 
6ace570
 
 
 
 
 
33f1e89
 
 
 
 
 
 
6ace570
 
 
 
33f1e89
 
 
6ace570
 
33f1e89
 
6ace570
33f1e89
 
 
 
 
 
 
 
 
 
 
6ace570
33f1e89
 
 
6ace570
 
 
 
 
 
33f1e89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6ace570
 
 
 
 
d40bc97
6ace570
 
 
 
 
 
 
 
33f1e89
6ace570
 
 
 
 
 
 
 
 
 
 
 
 
33f1e89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import os
import gradio as gr
from google import genai
from google.genai import types
from PIL import Image
import io
import base64

# 載入環境變數(本機開發時需要)
try:
    from dotenv import load_dotenv
    load_dotenv()
except ImportError:
    pass

# 配置Google AI
def configure_google_ai():
    """配置Google AI API"""
    api_key = os.getenv("GOOGLE_API_KEY")
    if not api_key:
        raise ValueError("請設定GOOGLE_API_KEY環境變數")
    
    # 使用新的 Gen AI 客戶端
    client = genai.Client(api_key=api_key)
    return client

# 初始化模型
try:
    client = configure_google_ai()
    model_name = "gemini-1.5-flash"
except Exception as e:
    print(f"警告:無法初始化Google AI模型 - {e}")
    client = None

def analyze_food_calories(image):
    """
    分析圖片中的食物並估算卡路里
    
    Args:
        image: PIL Image 物件
        
    Returns:
        str: 分析結果
    """
    if client is None:
        return "錯誤:Google AI模型未正確初始化,請檢查API KEY設定"
    
    try:
        # 將圖片轉換為 base64
        img_byte_arr = io.BytesIO()
        image.save(img_byte_arr, format='PNG')
        img_byte_arr = img_byte_arr.getvalue()
        img_base64 = base64.b64encode(img_byte_arr).decode('utf-8')
        
        # 準備提示詞
        prompt = """
請分析這張圖片中的內容:

1. 首先判斷圖片中是否包含食物
2. 如果不是食物,請回答:「這個不是食物」
3. 如果是食物,請:
   - 識別食物種類
   - 估算大概的份量
   - 計算大概的卡路里含量
   - 以繁體中文回答

請以以下格式回答:
- 食物名稱:[食物名稱]
- 估算份量:[份量描述]
- 預估卡路里:[卡路里數值] 大卡
- 營養說明:[簡短的營養價值說明]

如果不是食物,就直接回答「這個不是食物」。
"""
        
        # 建立內容,包含文字和圖片
        contents = [
            types.Content(
                role="user",
                parts=[
                    types.Part.from_text(text=prompt),
                    types.Part.from_bytes(
                        data=img_byte_arr,
                        mime_type="image/png"
                    )
                ]
            )
        ]
        
        # 生成回應
        response = client.models.generate_content(
            model=model_name,
            contents=contents,
            config=types.GenerateContentConfig(
                temperature=0.4,
                max_output_tokens=1024,
            )
        )
        
        if response.text:
            return response.text
        else:
            return "無法生成回應"
        
    except Exception as e:
        return f"分析時發生錯誤:{str(e)}"

def process_image(image):
    """
    處理上傳的圖片
    
    Args:
        image: Gradio上傳的圖片
        
    Returns:
        str: 分析結果
    """
    if image is None:
        return "請上傳一張圖片"
    
    try:
        # 確保圖片是PIL Image格式
        if isinstance(image, str):
            # 如果是路徑字串,載入圖片
            pil_image = Image.open(image)
        else:
            pil_image = image
        
        # 分析圖片
        result = analyze_food_calories(pil_image)
        return result
        
    except Exception as e:
        return f"處理圖片時發生錯誤:{str(e)}"

# 建立Gradio介面
def create_interface():
    """建立Gradio使用者介面"""
    
    # 自訂CSS樣式
    css = """
    .gradio-container {
        font-family: 'Microsoft JhengHei', sans-serif;
    }
    .title {
        text-align: center;
        color: #2E7D32;
        margin-bottom: 20px;
    }
    .description {
        text-align: center;
        color: #666;
        margin-bottom: 30px;
    }
    """
    
    with gr.Blocks(css=css, title="食物卡路里檢測器") as demo:
        gr.HTML("<h1 class='title'>🍎 食物卡路里檢測器</h1>")
        gr.HTML("<p class='description'>上傳食物照片,AI會幫你識別食物種類並估算卡路里含量</p>")
        
        with gr.Row():
            with gr.Column():
                # 圖片上傳元件
                image_input = gr.Image(
                    label="上傳食物照片",
                    type="pil",
                    height=400
                )
                
                # 分析按鈕
                analyze_btn = gr.Button(
                    "🔍 分析卡路里",
                    variant="primary",
                    size="lg"
                )
            
            with gr.Column():
                # 結果顯示
                result_output = gr.Textbox(
                    label="分析結果",
                    lines=10,
                    placeholder="上傳圖片後點擊分析按鈕...",
                    interactive=False
                )
        
        # 使用說明
        gr.HTML("""
        <div style="margin-top: 30px; padding: 20px; background-color: #f5f5f5; border-radius: 10px;">
            <h3>📋 使用說明:</h3>
            <ul>
                <li>📸 上傳一張包含食物的清晰照片</li>
                <li>🤖 AI會自動識別食物種類</li>
                <li>📊 獲得卡路里估算和營養資訊</li>
                <li>⚠️ 如果不是食物,系統會提醒您</li>
            </ul>
            <p><strong>注意:</strong>卡路里估算僅供參考,實際數值可能因烹飪方式和份量而有所差異。</p>
        </div>
        """)
        
        # 設定事件處理
        analyze_btn.click(
            fn=process_image,
            inputs=[image_input],
            outputs=[result_output]
        )
        
        # 也可以在上傳圖片後自動分析
        image_input.change(
            fn=process_image,
            inputs=[image_input],
            outputs=[result_output]
        )
    
    return demo

# 主程式
if __name__ == "__main__":
    # 建立介面
    demo = create_interface()
    
    # 啟動應用
    # HuggingFace Spaces 使用預設設定
    demo.launch()