Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -151,7 +151,7 @@ def save_api_settings(api_key, api_base_url, session_id):
|
|
| 151 |
|
| 152 |
def save_pdf(file, session_id):
|
| 153 |
if file is None:
|
| 154 |
-
return
|
| 155 |
try:
|
| 156 |
papers_dir, _, _ = get_user_dirs(session_id)
|
| 157 |
for f in os.listdir(papers_dir):
|
|
@@ -160,9 +160,10 @@ def save_pdf(file, session_id):
|
|
| 160 |
|
| 161 |
file_path = os.path.join(papers_dir, os.path.basename(file.name))
|
| 162 |
shutil.copy(file.name, file_path)
|
| 163 |
-
|
|
|
|
| 164 |
except Exception as e:
|
| 165 |
-
return create_progress_html(0, f"❌ Error: {str(e)}", "error"), get_debug_info(session_id), False
|
| 166 |
|
| 167 |
def clear_pdf(session_id):
|
| 168 |
try:
|
|
@@ -171,9 +172,10 @@ def clear_pdf(session_id):
|
|
| 171 |
shutil.rmtree(user_base)
|
| 172 |
|
| 173 |
disable_btn = gr.update(interactive=False)
|
| 174 |
-
|
|
|
|
| 175 |
except Exception as e:
|
| 176 |
-
return create_progress_html(0, f"❌ Clear Error: {str(e)}", "error"), gr.update(), get_debug_info(session_id), False, gr.update(), gr.update(), gr.update(), gr.update()
|
| 177 |
|
| 178 |
def build_user_env(api_key, api_base_url, papers_dir, output_dir):
|
| 179 |
env = os.environ.copy()
|
|
@@ -193,7 +195,7 @@ def run_mineru_parsing_and_dag_gen(session_id, api_key, api_base_url, progress=g
|
|
| 193 |
papers_dir, output_dir, _ = get_user_dirs(session_id)
|
| 194 |
|
| 195 |
if not os.path.exists(papers_dir) or not any(f.endswith('.pdf') for f in os.listdir(papers_dir)):
|
| 196 |
-
yield create_progress_html(0, "❌ No PDF file found", "error"), get_debug_info(session_id), "No execution logs.", no_change, no_change, no_change, no_change
|
| 197 |
return
|
| 198 |
|
| 199 |
full_log = ""
|
|
@@ -204,7 +206,7 @@ def run_mineru_parsing_and_dag_gen(session_id, api_key, api_base_url, progress=g
|
|
| 204 |
|
| 205 |
# 10%
|
| 206 |
progress(0.1, desc="启动 Mineru 解析...")
|
| 207 |
-
yield create_progress_html(10, "⏳ Starting Mineru parsing...", "active"), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 208 |
|
| 209 |
process_mineru = subprocess.Popen(
|
| 210 |
command_mineru, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1
|
|
@@ -214,13 +216,13 @@ def run_mineru_parsing_and_dag_gen(session_id, api_key, api_base_url, progress=g
|
|
| 214 |
progress(0.3, desc="Mineru 正在解析 PDF...")
|
| 215 |
for line in iter(process_mineru.stdout.readline, ''):
|
| 216 |
full_log += line
|
| 217 |
-
yield create_progress_html(30, "⏳ Mineru parsing PDF...", "active"), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 218 |
process_mineru.stdout.close()
|
| 219 |
returncode_mineru = process_mineru.wait()
|
| 220 |
|
| 221 |
if returncode_mineru != 0:
|
| 222 |
progress(1.0, desc="Mineru 解析失败")
|
| 223 |
-
yield create_progress_html(30, f"❌ Mineru failed (Code {returncode_mineru})", "error"), get_debug_info(session_id), full_log, disable_btn, disable_btn, disable_btn, disable_btn
|
| 224 |
return
|
| 225 |
|
| 226 |
command_dag = [sys.executable, "gen_dag.py"]
|
|
@@ -228,7 +230,7 @@ def run_mineru_parsing_and_dag_gen(session_id, api_key, api_base_url, progress=g
|
|
| 228 |
|
| 229 |
# 60%
|
| 230 |
progress(0.6, desc="执行 DAG 生成...")
|
| 231 |
-
yield create_progress_html(60, "⏳ Executing DAG generation...", "active"), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 232 |
|
| 233 |
process_dag = subprocess.Popen(
|
| 234 |
command_dag, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1
|
|
@@ -238,28 +240,28 @@ def run_mineru_parsing_and_dag_gen(session_id, api_key, api_base_url, progress=g
|
|
| 238 |
progress(0.8, desc="构建图结构中...")
|
| 239 |
for line in iter(process_dag.stdout.readline, ''):
|
| 240 |
full_log += line
|
| 241 |
-
yield create_progress_html(80, "⏳ Building DAG...", "active"), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 242 |
process_dag.stdout.close()
|
| 243 |
returncode_dag = process_dag.wait()
|
| 244 |
|
| 245 |
if returncode_dag == 0:
|
| 246 |
progress(1.0, desc="解析与构建完成!")
|
| 247 |
enable_btn = gr.update(interactive=True)
|
| 248 |
-
yield create_progress_html(100, "✅ Fully completed", "success"), get_debug_info(session_id), full_log, enable_btn, enable_btn, enable_btn, enable_btn
|
| 249 |
else:
|
| 250 |
progress(1.0, desc="DAG 生成失败")
|
| 251 |
-
yield create_progress_html(80, "❌ DAG generation failed", "error"), get_debug_info(session_id), full_log, disable_btn, disable_btn, disable_btn, disable_btn
|
| 252 |
|
| 253 |
except Exception as e:
|
| 254 |
progress(1.0, desc="发生异常")
|
| 255 |
error_log = full_log + f"\n[Global Exception]:\n{str(e)}"
|
| 256 |
-
yield create_progress_html(0, "❌ Execution Exception", "error"), get_debug_info(session_id), error_log, disable_btn, disable_btn, disable_btn, disable_btn
|
| 257 |
|
| 258 |
def run_final_generation(task_type, session_id, api_key, api_base_url, progress=gr.Progress()):
|
| 259 |
papers_dir, output_dir, zip_path = get_user_dirs(session_id)
|
| 260 |
|
| 261 |
if not os.path.exists(output_dir):
|
| 262 |
-
yield create_progress_html(0, "❌ Please run parsing first", "error"), get_debug_info(session_id), "No output folder found.", gr.update(visible=False)
|
| 263 |
return
|
| 264 |
|
| 265 |
scripts_to_run = []
|
|
@@ -270,7 +272,7 @@ def run_final_generation(task_type, session_id, api_key, api_base_url, progress=
|
|
| 270 |
|
| 271 |
full_log = f"🚀 Starting {len(scripts_to_run)} tasks for session {session_id[:8]}...\n"
|
| 272 |
progress(0.1, desc=f"启动 {task_type.upper()} 生成任务...")
|
| 273 |
-
yield create_progress_html(10, f"⏳ Starting {task_type.upper()}...", "active"), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 274 |
|
| 275 |
q = queue.Queue()
|
| 276 |
processes = []
|
|
@@ -298,7 +300,7 @@ def run_final_generation(task_type, session_id, api_key, api_base_url, progress=
|
|
| 298 |
try:
|
| 299 |
script_name, line = q.get(timeout=0.1)
|
| 300 |
full_log += f"[{script_name}] {line}"
|
| 301 |
-
yield create_progress_html(50, f"⏳ Generating {task_type.upper()}...", "active"), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 302 |
except queue.Empty:
|
| 303 |
active_processes = sum(1 for _, p in processes if p.poll() is None)
|
| 304 |
|
|
@@ -306,24 +308,24 @@ def run_final_generation(task_type, session_id, api_key, api_base_url, progress=
|
|
| 306 |
|
| 307 |
if not success:
|
| 308 |
progress(1.0, desc="生成失败")
|
| 309 |
-
yield create_progress_html(50, "❌ Tasks failed", "error"), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 310 |
return
|
| 311 |
|
| 312 |
full_log += "\n📦 Zipping output directory...\n"
|
| 313 |
progress(0.9, desc="打包压缩结果...")
|
| 314 |
-
yield create_progress_html(90, "⏳ Zipping outputs...", "active"), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 315 |
|
| 316 |
zip_base_name = zip_path.replace(".zip", "")
|
| 317 |
shutil.make_archive(zip_base_name, 'zip', output_dir)
|
| 318 |
|
| 319 |
full_log += "✅ All tasks completed successfully.\n"
|
| 320 |
progress(1.0, desc="全部完成!")
|
| 321 |
-
yield create_progress_html(100, f"✅ {task_type.upper()} Generated", "success"), get_debug_info(session_id), full_log, gr.update(value=zip_path, visible=True)
|
| 322 |
|
| 323 |
except Exception as e:
|
| 324 |
progress(1.0, desc="发生全局异常")
|
| 325 |
error_log = full_log + f"\n[Global Exception]:\n{str(e)}"
|
| 326 |
-
yield create_progress_html(0, "❌ Global exception", "error"), get_debug_info(session_id), error_log, gr.update(visible=False)
|
| 327 |
|
| 328 |
# ==========================================
|
| 329 |
# --- 🚀 UI Configuration & Advanced CSS ---
|
|
@@ -468,7 +470,7 @@ body, .gradio-container {
|
|
| 468 |
margin-right: auto !important;
|
| 469 |
margin-top: 10px !important;
|
| 470 |
margin-bottom: 10px !important;
|
| 471 |
-
display: block !important;
|
| 472 |
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), box-shadow 0.3s ease !important;
|
| 473 |
box-shadow: 0 4px 15px rgba(126, 34, 206, 0.3) !important;
|
| 474 |
cursor: pointer !important;
|
|
@@ -562,8 +564,8 @@ with gr.Blocks(theme=purple_theme, css=custom_css) as demo:
|
|
| 562 |
pdf_input = gr.File(label="Upload Document", file_types=[".pdf"], elem_id="pdf-upload-box")
|
| 563 |
parse_btn = gr.Button("🚀 Start Mineru & DAG Extraction", elem_classes="primary-action-btn", interactive=False)
|
| 564 |
|
| 565 |
-
# 进度条
|
| 566 |
-
parse_progress = gr.HTML(
|
| 567 |
|
| 568 |
# 3. Asset Generation
|
| 569 |
with gr.Group(elem_classes="gradio-group"):
|
|
@@ -574,15 +576,14 @@ with gr.Blocks(theme=purple_theme, css=custom_css) as demo:
|
|
| 574 |
gen_pr_btn = gr.Button("📰 Gen PR", elem_classes="action-btn", interactive=False)
|
| 575 |
gen_all_btn = gr.Button("✨ Generate All Assets (ALL)", elem_classes="primary-action-btn", interactive=False)
|
| 576 |
|
| 577 |
-
#
|
| 578 |
-
gen_progress = gr.HTML(
|
| 579 |
|
| 580 |
with gr.Column(scale=1):
|
| 581 |
# 4. Results & Downloads
|
| 582 |
with gr.Group(elem_classes="gradio-group"):
|
| 583 |
gr.Markdown("### 📦 Generation Results & Download")
|
| 584 |
|
| 585 |
-
# --- 新增:无输出时的美化空状态提示词 ---
|
| 586 |
download_placeholder = gr.HTML(
|
| 587 |
'''
|
| 588 |
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 160px; border: 2px dashed rgba(192, 132, 252, 0.6); border-radius: 16px; background-color: rgba(250, 245, 255, 0.5); color: #9333EA; text-align: center; transition: all 0.3s ease;">
|
|
@@ -657,7 +658,6 @@ with gr.Blocks(theme=purple_theme, css=custom_css) as demo:
|
|
| 657 |
refresh_btn.click(fn=get_debug_info, inputs=[session_id_state], outputs=debug_view)
|
| 658 |
|
| 659 |
def toggle_empty_placeholder(file_val):
|
| 660 |
-
# 如果获取到了文件(值不为空),就隐藏占位提示词;否则保持显示
|
| 661 |
return gr.update(visible=(file_val is None))
|
| 662 |
|
| 663 |
download_file.change(
|
|
|
|
| 151 |
|
| 152 |
def save_pdf(file, session_id):
|
| 153 |
if file is None:
|
| 154 |
+
return gr.update(visible=False), get_debug_info(session_id), False
|
| 155 |
try:
|
| 156 |
papers_dir, _, _ = get_user_dirs(session_id)
|
| 157 |
for f in os.listdir(papers_dir):
|
|
|
|
| 160 |
|
| 161 |
file_path = os.path.join(papers_dir, os.path.basename(file.name))
|
| 162 |
shutil.copy(file.name, file_path)
|
| 163 |
+
# 上传成功后显示进度条以反馈状态
|
| 164 |
+
return gr.update(value=create_progress_html(100, f"✅ PDF Uploaded: {os.path.basename(file.name)}", "success"), visible=True), get_debug_info(session_id), True
|
| 165 |
except Exception as e:
|
| 166 |
+
return gr.update(value=create_progress_html(0, f"❌ Error: {str(e)}", "error"), visible=True), get_debug_info(session_id), False
|
| 167 |
|
| 168 |
def clear_pdf(session_id):
|
| 169 |
try:
|
|
|
|
| 172 |
shutil.rmtree(user_base)
|
| 173 |
|
| 174 |
disable_btn = gr.update(interactive=False)
|
| 175 |
+
# 清除时隐藏全部进度条
|
| 176 |
+
return gr.update(visible=False), gr.update(visible=False), get_debug_info(session_id), False, disable_btn, disable_btn, disable_btn, disable_btn
|
| 177 |
except Exception as e:
|
| 178 |
+
return gr.update(value=create_progress_html(0, f"❌ Clear Error: {str(e)}", "error"), visible=True), gr.update(), get_debug_info(session_id), False, gr.update(), gr.update(), gr.update(), gr.update()
|
| 179 |
|
| 180 |
def build_user_env(api_key, api_base_url, papers_dir, output_dir):
|
| 181 |
env = os.environ.copy()
|
|
|
|
| 195 |
papers_dir, output_dir, _ = get_user_dirs(session_id)
|
| 196 |
|
| 197 |
if not os.path.exists(papers_dir) or not any(f.endswith('.pdf') for f in os.listdir(papers_dir)):
|
| 198 |
+
yield gr.update(value=create_progress_html(0, "❌ No PDF file found", "error"), visible=True), get_debug_info(session_id), "No execution logs.", no_change, no_change, no_change, no_change
|
| 199 |
return
|
| 200 |
|
| 201 |
full_log = ""
|
|
|
|
| 206 |
|
| 207 |
# 10%
|
| 208 |
progress(0.1, desc="启动 Mineru 解析...")
|
| 209 |
+
yield gr.update(value=create_progress_html(10, "⏳ Starting Mineru parsing...", "active"), visible=True), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 210 |
|
| 211 |
process_mineru = subprocess.Popen(
|
| 212 |
command_mineru, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1
|
|
|
|
| 216 |
progress(0.3, desc="Mineru 正在解析 PDF...")
|
| 217 |
for line in iter(process_mineru.stdout.readline, ''):
|
| 218 |
full_log += line
|
| 219 |
+
yield gr.update(value=create_progress_html(30, "⏳ Mineru parsing PDF...", "active"), visible=True), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 220 |
process_mineru.stdout.close()
|
| 221 |
returncode_mineru = process_mineru.wait()
|
| 222 |
|
| 223 |
if returncode_mineru != 0:
|
| 224 |
progress(1.0, desc="Mineru 解析失败")
|
| 225 |
+
yield gr.update(value=create_progress_html(30, f"❌ Mineru failed (Code {returncode_mineru})", "error"), visible=True), get_debug_info(session_id), full_log, disable_btn, disable_btn, disable_btn, disable_btn
|
| 226 |
return
|
| 227 |
|
| 228 |
command_dag = [sys.executable, "gen_dag.py"]
|
|
|
|
| 230 |
|
| 231 |
# 60%
|
| 232 |
progress(0.6, desc="执行 DAG 生成...")
|
| 233 |
+
yield gr.update(value=create_progress_html(60, "⏳ Executing DAG generation...", "active"), visible=True), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 234 |
|
| 235 |
process_dag = subprocess.Popen(
|
| 236 |
command_dag, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1
|
|
|
|
| 240 |
progress(0.8, desc="构建图结构中...")
|
| 241 |
for line in iter(process_dag.stdout.readline, ''):
|
| 242 |
full_log += line
|
| 243 |
+
yield gr.update(value=create_progress_html(80, "⏳ Building DAG...", "active"), visible=True), get_debug_info(session_id), full_log, no_change, no_change, no_change, no_change
|
| 244 |
process_dag.stdout.close()
|
| 245 |
returncode_dag = process_dag.wait()
|
| 246 |
|
| 247 |
if returncode_dag == 0:
|
| 248 |
progress(1.0, desc="解析与构建完成!")
|
| 249 |
enable_btn = gr.update(interactive=True)
|
| 250 |
+
yield gr.update(value=create_progress_html(100, "✅ Fully completed", "success"), visible=True), get_debug_info(session_id), full_log, enable_btn, enable_btn, enable_btn, enable_btn
|
| 251 |
else:
|
| 252 |
progress(1.0, desc="DAG 生成失败")
|
| 253 |
+
yield gr.update(value=create_progress_html(80, "❌ DAG generation failed", "error"), visible=True), get_debug_info(session_id), full_log, disable_btn, disable_btn, disable_btn, disable_btn
|
| 254 |
|
| 255 |
except Exception as e:
|
| 256 |
progress(1.0, desc="发生异常")
|
| 257 |
error_log = full_log + f"\n[Global Exception]:\n{str(e)}"
|
| 258 |
+
yield gr.update(value=create_progress_html(0, "❌ Execution Exception", "error"), visible=True), get_debug_info(session_id), error_log, disable_btn, disable_btn, disable_btn, disable_btn
|
| 259 |
|
| 260 |
def run_final_generation(task_type, session_id, api_key, api_base_url, progress=gr.Progress()):
|
| 261 |
papers_dir, output_dir, zip_path = get_user_dirs(session_id)
|
| 262 |
|
| 263 |
if not os.path.exists(output_dir):
|
| 264 |
+
yield gr.update(value=create_progress_html(0, "❌ Please run parsing first", "error"), visible=True), get_debug_info(session_id), "No output folder found.", gr.update(visible=False)
|
| 265 |
return
|
| 266 |
|
| 267 |
scripts_to_run = []
|
|
|
|
| 272 |
|
| 273 |
full_log = f"🚀 Starting {len(scripts_to_run)} tasks for session {session_id[:8]}...\n"
|
| 274 |
progress(0.1, desc=f"启动 {task_type.upper()} 生成任务...")
|
| 275 |
+
yield gr.update(value=create_progress_html(10, f"⏳ Starting {task_type.upper()}...", "active"), visible=True), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 276 |
|
| 277 |
q = queue.Queue()
|
| 278 |
processes = []
|
|
|
|
| 300 |
try:
|
| 301 |
script_name, line = q.get(timeout=0.1)
|
| 302 |
full_log += f"[{script_name}] {line}"
|
| 303 |
+
yield gr.update(value=create_progress_html(50, f"⏳ Generating {task_type.upper()}...", "active"), visible=True), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 304 |
except queue.Empty:
|
| 305 |
active_processes = sum(1 for _, p in processes if p.poll() is None)
|
| 306 |
|
|
|
|
| 308 |
|
| 309 |
if not success:
|
| 310 |
progress(1.0, desc="生成失败")
|
| 311 |
+
yield gr.update(value=create_progress_html(50, "❌ Tasks failed", "error"), visible=True), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 312 |
return
|
| 313 |
|
| 314 |
full_log += "\n📦 Zipping output directory...\n"
|
| 315 |
progress(0.9, desc="打包压缩结果...")
|
| 316 |
+
yield gr.update(value=create_progress_html(90, "⏳ Zipping outputs...", "active"), visible=True), get_debug_info(session_id), full_log, gr.update(visible=False)
|
| 317 |
|
| 318 |
zip_base_name = zip_path.replace(".zip", "")
|
| 319 |
shutil.make_archive(zip_base_name, 'zip', output_dir)
|
| 320 |
|
| 321 |
full_log += "✅ All tasks completed successfully.\n"
|
| 322 |
progress(1.0, desc="全部完成!")
|
| 323 |
+
yield gr.update(value=create_progress_html(100, f"✅ {task_type.upper()} Generated", "success"), visible=True), get_debug_info(session_id), full_log, gr.update(value=zip_path, visible=True)
|
| 324 |
|
| 325 |
except Exception as e:
|
| 326 |
progress(1.0, desc="发生全局异常")
|
| 327 |
error_log = full_log + f"\n[Global Exception]:\n{str(e)}"
|
| 328 |
+
yield gr.update(value=create_progress_html(0, "❌ Global exception", "error"), visible=True), get_debug_info(session_id), error_log, gr.update(visible=False)
|
| 329 |
|
| 330 |
# ==========================================
|
| 331 |
# --- 🚀 UI Configuration & Advanced CSS ---
|
|
|
|
| 470 |
margin-right: auto !important;
|
| 471 |
margin-top: 10px !important;
|
| 472 |
margin-bottom: 10px !important;
|
| 473 |
+
display: block !important;
|
| 474 |
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), box-shadow 0.3s ease !important;
|
| 475 |
box-shadow: 0 4px 15px rgba(126, 34, 206, 0.3) !important;
|
| 476 |
cursor: pointer !important;
|
|
|
|
| 564 |
pdf_input = gr.File(label="Upload Document", file_types=[".pdf"], elem_id="pdf-upload-box")
|
| 565 |
parse_btn = gr.Button("🚀 Start Mineru & DAG Extraction", elem_classes="primary-action-btn", interactive=False)
|
| 566 |
|
| 567 |
+
# 默认隐藏进度条
|
| 568 |
+
parse_progress = gr.HTML(visible=False)
|
| 569 |
|
| 570 |
# 3. Asset Generation
|
| 571 |
with gr.Group(elem_classes="gradio-group"):
|
|
|
|
| 576 |
gen_pr_btn = gr.Button("📰 Gen PR", elem_classes="action-btn", interactive=False)
|
| 577 |
gen_all_btn = gr.Button("✨ Generate All Assets (ALL)", elem_classes="primary-action-btn", interactive=False)
|
| 578 |
|
| 579 |
+
# 默认隐藏进度条
|
| 580 |
+
gen_progress = gr.HTML(visible=False)
|
| 581 |
|
| 582 |
with gr.Column(scale=1):
|
| 583 |
# 4. Results & Downloads
|
| 584 |
with gr.Group(elem_classes="gradio-group"):
|
| 585 |
gr.Markdown("### 📦 Generation Results & Download")
|
| 586 |
|
|
|
|
| 587 |
download_placeholder = gr.HTML(
|
| 588 |
'''
|
| 589 |
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 160px; border: 2px dashed rgba(192, 132, 252, 0.6); border-radius: 16px; background-color: rgba(250, 245, 255, 0.5); color: #9333EA; text-align: center; transition: all 0.3s ease;">
|
|
|
|
| 658 |
refresh_btn.click(fn=get_debug_info, inputs=[session_id_state], outputs=debug_view)
|
| 659 |
|
| 660 |
def toggle_empty_placeholder(file_val):
|
|
|
|
| 661 |
return gr.update(visible=(file_val is None))
|
| 662 |
|
| 663 |
download_file.change(
|