Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,33 +1,11 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
import os
|
| 4 |
-
import json
|
| 5 |
-
import base64
|
| 6 |
import requests
|
| 7 |
from io import BytesIO
|
| 8 |
from PIL import Image
|
| 9 |
from urllib.parse import urlparse, parse_qs
|
| 10 |
-
|
| 11 |
-
from google.api_core.client_options import ClientOptions
|
| 12 |
-
from google.oauth2 import service_account
|
| 13 |
-
|
| 14 |
-
# 由於您的環境可能沒有服務帳號金鑰,我們將直接使用 GEMINI_API_KEY
|
| 15 |
-
# 如果在 Hugging Face Space 中,這通常會從環境變數中自動加載
|
| 16 |
-
|
| 17 |
-
# 初始化 AI Platform 服務客戶端
|
| 18 |
-
def initialize_ai_platform(api_key):
|
| 19 |
-
# 請替換為您的 GCP 專案 ID 和區域
|
| 20 |
-
PROJECT_ID = "YOUR_GCP_PROJECT_ID" # 這裡需要您提供真實的GCP專案ID
|
| 21 |
-
LOCATION = "us-central1"
|
| 22 |
-
|
| 23 |
-
# 這裡的認證方式取決於您的環境。
|
| 24 |
-
# 創建一個不帶服務帳號憑證的客戶端,這會讓它嘗試從環境中自動尋找憑證
|
| 25 |
-
try:
|
| 26 |
-
aiplatform.init(project=PROJECT_ID, location=LOCATION)
|
| 27 |
-
return True
|
| 28 |
-
except Exception as e:
|
| 29 |
-
print(f"Error initializing AI Platform: {e}")
|
| 30 |
-
return False
|
| 31 |
|
| 32 |
# 全局變數來儲存 API 金鑰
|
| 33 |
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
|
|
@@ -43,144 +21,106 @@ print(f"Debug: Top-level Loaded GEMINI_API_KEY (first 5 chars): {GEMINI_API_KEY[
|
|
| 43 |
if not GEMINI_API_KEY:
|
| 44 |
raise ValueError("ERROR: GEMINI_API_KEY environment variable is not set. Please set it correctly.")
|
| 45 |
|
| 46 |
-
#
|
| 47 |
-
|
| 48 |
-
# 來模擬直接呼叫 API,以適應您在 Hugging Face Space 的需求。
|
| 49 |
-
class NanoBananaImageGenerator:
|
| 50 |
-
def __init__(self, api_key):
|
| 51 |
-
self.api_key = api_key
|
| 52 |
-
self.endpoint_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent"
|
| 53 |
-
|
| 54 |
-
def _load_image_from_url(self, url):
|
| 55 |
-
# 圖片下載邏輯與之前相同,以確保兼容性
|
| 56 |
-
try:
|
| 57 |
-
headers = {'User-Agent': 'Mozilla/5.0'}
|
| 58 |
-
response = requests.get(url, timeout=20, headers=headers)
|
| 59 |
-
response.raise_for_status()
|
| 60 |
-
image = Image.open(BytesIO(response.content)).convert("RGB")
|
| 61 |
-
return image
|
| 62 |
-
except requests.exceptions.HTTPError as e:
|
| 63 |
-
print(f"Error downloading image from {url}: HTTP Error {e.response.status_code}")
|
| 64 |
-
return None
|
| 65 |
-
except Exception as e:
|
| 66 |
-
print(f"An unexpected error occurred: {e}")
|
| 67 |
-
return None
|
| 68 |
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
"
|
| 83 |
-
|
| 84 |
-
base_quality = "Generate a high-quality, photorealistic image"
|
| 85 |
-
format_instruction = f"in {aspect_instructions.get(aspect_ratio, 'square format')}"
|
| 86 |
|
| 87 |
-
|
| 88 |
-
if not has_references:
|
| 89 |
-
final_prompt = f"{base_quality} of: {prompt}. {format_instruction}."
|
| 90 |
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
for img in images:
|
| 101 |
-
contents.append({
|
| 102 |
-
"inline_data": {
|
| 103 |
-
"mime_type": "image/png",
|
| 104 |
-
"data": self._image_to_base64(img)
|
| 105 |
-
}
|
| 106 |
-
})
|
| 107 |
-
|
| 108 |
-
payload = {
|
| 109 |
-
"contents": {"parts": contents},
|
| 110 |
-
"generation_config": {
|
| 111 |
-
"temperature": temperature,
|
| 112 |
-
"response_modalities": ["Text", "Image"]
|
| 113 |
-
}
|
| 114 |
-
}
|
| 115 |
-
|
| 116 |
-
headers = {
|
| 117 |
-
"Content-Type": "application/json",
|
| 118 |
-
"x-goog-api-key": self.api_key
|
| 119 |
-
}
|
| 120 |
-
|
| 121 |
-
print(f"Debug: Attempting to call Gemini API via HTTP request.")
|
| 122 |
-
response = requests.post(self.endpoint_url, headers=headers, json=payload, timeout=60)
|
| 123 |
-
response.raise_for_status()
|
| 124 |
-
|
| 125 |
-
api_response = response.json()
|
| 126 |
-
print(f"Debug: Full API Response: {json.dumps(api_response, indent=2)}")
|
| 127 |
-
|
| 128 |
-
# 解析回應
|
| 129 |
-
candidates = api_response.get('candidates', [])
|
| 130 |
-
if not candidates:
|
| 131 |
-
safety_ratings = api_response.get('prompt_feedback', {}).get('safety_ratings', [])
|
| 132 |
-
if safety_ratings:
|
| 133 |
-
operation_log += f"API 被安全政策阻止。原因:{safety_ratings}\n"
|
| 134 |
-
else:
|
| 135 |
-
operation_log += "API 回應中未找到候選者,可能的原因是內部錯誤或無效請求。\n"
|
| 136 |
-
return [], operation_log
|
| 137 |
-
|
| 138 |
-
image_parts = []
|
| 139 |
-
for candidate in candidates:
|
| 140 |
-
if 'content' in candidate and 'parts' in candidate['content']:
|
| 141 |
-
for part in candidate['content']['parts']:
|
| 142 |
-
if 'inline_data' in part and 'data' in part['inline_data']:
|
| 143 |
-
image_parts.append(base64.b64decode(part['inline_data']['data']))
|
| 144 |
-
elif 'text' in part:
|
| 145 |
-
operation_log += f"API 回應文字:{part['text']}\n"
|
| 146 |
-
|
| 147 |
-
if not image_parts:
|
| 148 |
-
operation_log += "API 回應沒有包含任何圖像數據,請檢查輸入內容是否違反安全政策。\n"
|
| 149 |
-
else:
|
| 150 |
-
operation_log += f"成功生成 {len(image_parts)} 張圖片。\n"
|
| 151 |
-
|
| 152 |
return image_parts, operation_log
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
operation_log
|
| 156 |
-
return
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
def generate_image(white_background_url, reference_image_url, prompt):
|
| 162 |
-
|
| 163 |
-
|
| 164 |
if not GEMINI_API_KEY:
|
| 165 |
return None, "Error: GEMINI_API_KEY is not set."
|
| 166 |
|
| 167 |
-
wb_image =
|
| 168 |
-
ref_image =
|
| 169 |
|
| 170 |
-
if
|
| 171 |
-
return None, "Error:
|
| 172 |
-
if not ref_image:
|
| 173 |
-
return None, "Error: Failed to load reference image from URL."
|
| 174 |
|
| 175 |
images = [wb_image, ref_image]
|
| 176 |
-
final_prompt =
|
| 177 |
|
| 178 |
-
generated_images_binary, operation_log =
|
| 179 |
|
| 180 |
if generated_images_binary:
|
| 181 |
output_dir = "generated_images"
|
| 182 |
os.makedirs(output_dir, exist_ok=True)
|
| 183 |
-
|
|
|
|
|
|
|
| 184 |
with open(output_path, "wb") as f:
|
| 185 |
f.write(generated_images_binary[0])
|
| 186 |
return output_path, operation_log
|
|
@@ -188,6 +128,7 @@ def generate_image(white_background_url, reference_image_url, prompt):
|
|
| 188 |
return None, operation_log
|
| 189 |
|
| 190 |
def read_google_sheet(sheet_url):
|
|
|
|
| 191 |
try:
|
| 192 |
def build_csv_url(url: str) -> str:
|
| 193 |
parsed = urlparse(url)
|
|
@@ -214,6 +155,7 @@ def read_google_sheet(sheet_url):
|
|
| 214 |
raise gr.Error(f"Error reading Google Sheet: {e}")
|
| 215 |
|
| 216 |
def process_sheet_data(sheet_url):
|
|
|
|
| 217 |
try:
|
| 218 |
df = read_google_sheet(sheet_url)
|
| 219 |
|
|
@@ -221,33 +163,35 @@ def process_sheet_data(sheet_url):
|
|
| 221 |
error_msg = f"Error: Google Sheet has only {df.shape[1]} columns, but 3 are expected (White Background URL, Reference Image URL, Prompt)."
|
| 222 |
raise gr.Error(error_msg)
|
| 223 |
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
if pd.notna(wb) and pd.notna(ref) and pd.notna(p):
|
| 231 |
-
data.append([i, wb, ref, p])
|
| 232 |
|
| 233 |
-
return
|
| 234 |
except Exception as e:
|
| 235 |
raise gr.Error(f"Error processing sheet data: {e}")
|
| 236 |
|
| 237 |
def generate_image_for_row(row_index, dataframe_data):
|
| 238 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
return None, "Error: Invalid row index."
|
| 240 |
|
| 241 |
-
row =
|
| 242 |
-
white_background_url = row
|
| 243 |
-
reference_image_url = row
|
| 244 |
-
prompt = row
|
| 245 |
|
| 246 |
return generate_image(white_background_url, reference_image_url, prompt)
|
| 247 |
|
| 248 |
if __name__ == "__main__":
|
| 249 |
with gr.Blocks() as demo:
|
| 250 |
-
gr.Markdown("# AutoLS Gradio Image Generator (Powered by
|
| 251 |
gr.Markdown("輸入 Google Sheet 網址來處理圖像生成請求。")
|
| 252 |
|
| 253 |
sheet_url_input = gr.Textbox(label="Google Sheet URL", value="https://docs.google.com/spreadsheets/d/1G3olHxydDIbnyXdh5nnw5TG0akZFeMeYm-25JmCGDLg/edit?gid=0#gid=0")
|
|
@@ -273,14 +217,15 @@ if __name__ == "__main__":
|
|
| 273 |
inputs=sheet_url_input,
|
| 274 |
outputs=output_dataframe
|
| 275 |
).success(
|
| 276 |
-
fn=lambda x:
|
| 277 |
inputs=output_dataframe,
|
| 278 |
outputs=processed_df_state
|
| 279 |
)
|
| 280 |
-
|
|
|
|
| 281 |
generate_selected_button.click(
|
| 282 |
fn=generate_image_for_row,
|
| 283 |
-
inputs=[row_index_input,
|
| 284 |
outputs=[generated_image_output, operation_log_output]
|
| 285 |
)
|
| 286 |
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
import os
|
|
|
|
|
|
|
| 4 |
import requests
|
| 5 |
from io import BytesIO
|
| 6 |
from PIL import Image
|
| 7 |
from urllib.parse import urlparse, parse_qs
|
| 8 |
+
import google.generativeai as genai
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
# 全局變數來儲存 API 金鑰
|
| 11 |
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
|
|
|
|
| 21 |
if not GEMINI_API_KEY:
|
| 22 |
raise ValueError("ERROR: GEMINI_API_KEY environment variable is not set. Please set it correctly.")
|
| 23 |
|
| 24 |
+
# 配置 Gemini API
|
| 25 |
+
genai.configure(api_key=GEMINI_API_KEY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
+
def load_image_from_url(url: str):
|
| 28 |
+
"""從 URL 下載圖片並以 PIL Image 格式回傳。"""
|
| 29 |
+
try:
|
| 30 |
+
headers = {'User-Agent': 'Mozilla/5.0'}
|
| 31 |
+
response = requests.get(url, timeout=20, headers=headers)
|
| 32 |
+
response.raise_for_status() # 檢查請求是否成功
|
| 33 |
+
image = Image.open(BytesIO(response.content)).convert("RGB")
|
| 34 |
+
print(f"Debug: Successfully loaded image from URL: {url}")
|
| 35 |
+
return image
|
| 36 |
+
except requests.exceptions.HTTPError as e:
|
| 37 |
+
print(f"Error downloading image from {url}: HTTP Error {e.response.status_code}")
|
| 38 |
+
return None
|
| 39 |
+
except Exception as e:
|
| 40 |
+
print(f"An unexpected error occurred: {e}")
|
| 41 |
+
return None
|
| 42 |
+
|
| 43 |
+
def build_prompt_for_operation(prompt, has_references=False, aspect_ratio="1:1"):
|
| 44 |
+
"""根據輸入構建完整的提示詞。"""
|
| 45 |
+
aspect_instructions = {
|
| 46 |
+
"1:1": "square format",
|
| 47 |
+
"16:9": "widescreen landscape format",
|
| 48 |
+
"9:16": "portrait format",
|
| 49 |
+
"4:3": "standard landscape format",
|
| 50 |
+
"3:4": "standard portrait format"
|
| 51 |
+
}
|
| 52 |
+
base_quality = "Generate a high-quality, photorealistic image"
|
| 53 |
+
format_instruction = f"in {aspect_instructions.get(aspect_ratio, 'square format')}"
|
| 54 |
+
|
| 55 |
+
final_prompt = f"{base_quality} inspired by the style and elements of the reference images. {prompt}. {format_instruction}."
|
| 56 |
+
if not has_references:
|
| 57 |
+
final_prompt = f"{base_quality} of: {prompt}. {format_instruction}."
|
| 58 |
+
|
| 59 |
+
return final_prompt
|
| 60 |
|
| 61 |
+
def call_gemini_api(prompt, images):
|
| 62 |
+
"""使用官方函式庫呼叫 Gemini API。"""
|
| 63 |
+
operation_log = ""
|
| 64 |
+
try:
|
| 65 |
+
# 使用官方 genai.generate_content 函式
|
| 66 |
+
response = genai.generate_content(
|
| 67 |
+
contents=[prompt] + images, # 圖片列表直接作為輸入
|
| 68 |
+
model="gemini-1.5-pro-latest" # 使用官方推薦的多模態模型
|
| 69 |
+
)
|
|
|
|
|
|
|
| 70 |
|
| 71 |
+
print(f"Debug: Full API Response: {response.text}")
|
|
|
|
|
|
|
| 72 |
|
| 73 |
+
# 檢查是否有安全政策問題
|
| 74 |
+
if 'prompt_feedback' in response:
|
| 75 |
+
if 'safety_ratings' in response['prompt_feedback']:
|
| 76 |
+
for rating in response['prompt_feedback']['safety_ratings']:
|
| 77 |
+
if rating['block_reason'] != 'NONE':
|
| 78 |
+
operation_log += f"API 被安全政策阻止。原因:{rating['block_reason']}\n"
|
| 79 |
+
return None, operation_log
|
| 80 |
|
| 81 |
+
# 處理回應
|
| 82 |
+
if response.text is not None and "data:image" in response.text:
|
| 83 |
+
# 這是內嵌的圖片 Base64 字串,需要解碼
|
| 84 |
+
base64_string = response.text.split(',')[1]
|
| 85 |
+
image_data = base64.b64decode(base64_string)
|
| 86 |
+
image_parts = [image_data]
|
| 87 |
+
operation_log += f"成功生成 {len(image_parts)} 張圖片。\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
return image_parts, operation_log
|
| 89 |
+
elif response.text is not None:
|
| 90 |
+
# 如果回傳的是文字
|
| 91 |
+
operation_log += f"API 回應文字:{response.text}\n"
|
| 92 |
+
return None, operation_log
|
| 93 |
+
else:
|
| 94 |
+
# 沒有任何回傳
|
| 95 |
+
operation_log += "API 回應沒有包含任何圖像或文字數據。\n"
|
| 96 |
+
return None, operation_log
|
| 97 |
+
|
| 98 |
+
except Exception as e:
|
| 99 |
+
operation_log = f"意外錯誤: {type(e).__name__} - {str(e)}\n"
|
| 100 |
+
return None, operation_log
|
| 101 |
|
| 102 |
def generate_image(white_background_url, reference_image_url, prompt):
|
| 103 |
+
"""Gradio 介面呼叫的主函式。"""
|
|
|
|
| 104 |
if not GEMINI_API_KEY:
|
| 105 |
return None, "Error: GEMINI_API_KEY is not set."
|
| 106 |
|
| 107 |
+
wb_image = load_image_from_url(white_background_url)
|
| 108 |
+
ref_image = load_image_from_url(reference_image_url)
|
| 109 |
|
| 110 |
+
if wb_image is None or ref_image is None:
|
| 111 |
+
return None, "Error: One or more images failed to load from URL."
|
|
|
|
|
|
|
| 112 |
|
| 113 |
images = [wb_image, ref_image]
|
| 114 |
+
final_prompt = build_prompt_for_operation(prompt, has_references=True)
|
| 115 |
|
| 116 |
+
generated_images_binary, operation_log = call_gemini_api(final_prompt, images)
|
| 117 |
|
| 118 |
if generated_images_binary:
|
| 119 |
output_dir = "generated_images"
|
| 120 |
os.makedirs(output_dir, exist_ok=True)
|
| 121 |
+
# 使用時間戳或唯一ID來確保檔名唯一
|
| 122 |
+
import time
|
| 123 |
+
output_path = os.path.join(output_dir, f"generated_{int(time.time())}.png")
|
| 124 |
with open(output_path, "wb") as f:
|
| 125 |
f.write(generated_images_binary[0])
|
| 126 |
return output_path, operation_log
|
|
|
|
| 128 |
return None, operation_log
|
| 129 |
|
| 130 |
def read_google_sheet(sheet_url):
|
| 131 |
+
"""從 Google Sheet 讀取資料。"""
|
| 132 |
try:
|
| 133 |
def build_csv_url(url: str) -> str:
|
| 134 |
parsed = urlparse(url)
|
|
|
|
| 155 |
raise gr.Error(f"Error reading Google Sheet: {e}")
|
| 156 |
|
| 157 |
def process_sheet_data(sheet_url):
|
| 158 |
+
"""處理試算表資料,為 Gradio DataFrame 準備。"""
|
| 159 |
try:
|
| 160 |
df = read_google_sheet(sheet_url)
|
| 161 |
|
|
|
|
| 163 |
error_msg = f"Error: Google Sheet has only {df.shape[1]} columns, but 3 are expected (White Background URL, Reference Image URL, Prompt)."
|
| 164 |
raise gr.Error(error_msg)
|
| 165 |
|
| 166 |
+
# 這裡使用 to_dict('records') 來處理,以確保後續 Pandas 處理時的兼容性
|
| 167 |
+
data = df.to_dict('records')
|
| 168 |
+
data_list = []
|
| 169 |
+
for i, row in enumerate(data):
|
| 170 |
+
if pd.notna(row.iloc[0]) and pd.notna(row.iloc[1]) and pd.notna(row.iloc[2]):
|
| 171 |
+
data_list.append([i, row.iloc[0], row.iloc[1], row.iloc[2]])
|
|
|
|
|
|
|
| 172 |
|
| 173 |
+
return data_list
|
| 174 |
except Exception as e:
|
| 175 |
raise gr.Error(f"Error processing sheet data: {e}")
|
| 176 |
|
| 177 |
def generate_image_for_row(row_index, dataframe_data):
|
| 178 |
+
"""根據 Gradio DataFrame 的行索引生成圖片。"""
|
| 179 |
+
# 將 Gradio 的 dataframe_data 轉換回 pandas DataFrame
|
| 180 |
+
df = pd.DataFrame(dataframe_data, columns=["Index", "白背圖URL", "參考圖URL", "提示詞"])
|
| 181 |
+
|
| 182 |
+
if not (0 <= row_index < len(df)):
|
| 183 |
return None, "Error: Invalid row index."
|
| 184 |
|
| 185 |
+
row = df.iloc[int(row_index)]
|
| 186 |
+
white_background_url = row['白背圖URL']
|
| 187 |
+
reference_image_url = row['參考圖URL']
|
| 188 |
+
prompt = row['提示詞']
|
| 189 |
|
| 190 |
return generate_image(white_background_url, reference_image_url, prompt)
|
| 191 |
|
| 192 |
if __name__ == "__main__":
|
| 193 |
with gr.Blocks() as demo:
|
| 194 |
+
gr.Markdown("# AutoLS Gradio Image Generator (Powered by Gemini API)")
|
| 195 |
gr.Markdown("輸入 Google Sheet 網址來處理圖像生成請求。")
|
| 196 |
|
| 197 |
sheet_url_input = gr.Textbox(label="Google Sheet URL", value="https://docs.google.com/spreadsheets/d/1G3olHxydDIbnyXdh5nnw5TG0akZFeMeYm-25JmCGDLg/edit?gid=0#gid=0")
|
|
|
|
| 217 |
inputs=sheet_url_input,
|
| 218 |
outputs=output_dataframe
|
| 219 |
).success(
|
| 220 |
+
fn=lambda x: x,
|
| 221 |
inputs=output_dataframe,
|
| 222 |
outputs=processed_df_state
|
| 223 |
)
|
| 224 |
+
|
| 225 |
+
# 修正 click 觸發器,確保傳入正確的參數
|
| 226 |
generate_selected_button.click(
|
| 227 |
fn=generate_image_for_row,
|
| 228 |
+
inputs=[row_index_input, output_dataframe],
|
| 229 |
outputs=[generated_image_output, operation_log_output]
|
| 230 |
)
|
| 231 |
|