Spaces:
Sleeping
Sleeping
test: add timeout handling
Browse files
app.py
CHANGED
@@ -609,191 +609,148 @@ def load_all_data(image_root, pkl_root):
|
|
609 |
default_image_name = "christmas-imagenet"
|
610 |
|
611 |
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
gr.Markdown("### ImageNet-Sketch")
|
722 |
-
top_image_2 = gr.Image(
|
723 |
-
value=init_tops[1],
|
724 |
-
type="pil",
|
725 |
-
label="ImageNet-Sketch",
|
726 |
-
show_label=False,
|
727 |
-
)
|
728 |
-
act_value_2 = gr.Markdown(init_values[1])
|
729 |
-
|
730 |
-
gr.Markdown("### Caltech101")
|
731 |
-
top_image_3 = gr.Image(
|
732 |
-
value=init_tops[2], type="pil", label="Caltech101", show_label=False
|
733 |
-
)
|
734 |
-
act_value_3 = gr.Markdown(init_values[2])
|
735 |
-
|
736 |
-
image_display.select(
|
737 |
-
fn=update_radio_options,
|
738 |
-
inputs=[image_selector, model_selector],
|
739 |
-
outputs=[radio_choices],
|
740 |
-
)
|
741 |
-
|
742 |
-
model_selector.change(
|
743 |
-
fn=update_radio_options,
|
744 |
-
inputs=[image_selector, model_selector],
|
745 |
-
outputs=[radio_choices],
|
746 |
-
)
|
747 |
-
|
748 |
-
image_selector.select(
|
749 |
-
fn=update_radio_options,
|
750 |
-
inputs=[image_selector, model_selector],
|
751 |
-
outputs=[radio_choices],
|
752 |
-
)
|
753 |
-
|
754 |
-
radio_choices.change(
|
755 |
-
fn=update_all,
|
756 |
-
inputs=[image_selector, radio_choices, toggle_btn, model_selector],
|
757 |
-
outputs=[
|
758 |
-
seg_mask_display,
|
759 |
-
seg_mask_display_maple,
|
760 |
-
top_image_1,
|
761 |
-
top_image_2,
|
762 |
-
top_image_3,
|
763 |
-
act_value_1,
|
764 |
-
act_value_2,
|
765 |
-
act_value_3,
|
766 |
-
markdown_display,
|
767 |
-
markdown_display_2,
|
768 |
-
],
|
769 |
-
)
|
770 |
-
|
771 |
-
toggle_btn.change(
|
772 |
-
fn=show_activation_heatmap_clip,
|
773 |
-
inputs=[image_selector, radio_choices, toggle_btn],
|
774 |
-
outputs=[
|
775 |
-
seg_mask_display,
|
776 |
-
top_image_1,
|
777 |
-
top_image_2,
|
778 |
-
top_image_3,
|
779 |
-
act_value_1,
|
780 |
-
act_value_2,
|
781 |
-
act_value_3,
|
782 |
-
],
|
783 |
-
)
|
784 |
|
785 |
-
|
786 |
-
# demo.queue()
|
787 |
-
# demo.launch()
|
788 |
|
789 |
-
|
790 |
if __name__ == "__main__":
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
show_error=True,
|
797 |
-
# Optimize concurrency
|
798 |
-
max_threads=8, # Adjust based on your CPU cores
|
799 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
609 |
default_image_name = "christmas-imagenet"
|
610 |
|
611 |
|
612 |
+
def safe_operation(func, *args, timeout=10, default=None):
|
613 |
+
"""Execute function with timeout and return default value on failure."""
|
614 |
+
try:
|
615 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
616 |
+
future = executor.submit(func, *args)
|
617 |
+
return future.result(timeout=timeout)
|
618 |
+
except concurrent.futures.TimeoutError:
|
619 |
+
print(f"Operation timed out: {func.__name__}")
|
620 |
+
return default
|
621 |
+
except Exception as e:
|
622 |
+
print(f"Operation failed: {func.__name__}, Error: {e}")
|
623 |
+
return default
|
624 |
+
|
625 |
+
def create_interface():
|
626 |
+
with gr.Blocks(
|
627 |
+
theme=gr.themes.Citrus(),
|
628 |
+
css="""
|
629 |
+
.image-row .gr-image { margin: 0 !important; padding: 0 !important; }
|
630 |
+
.image-row img { width: auto; height: 50px; }
|
631 |
+
""",
|
632 |
+
) as demo:
|
633 |
+
# State management for preventing duplicate operations
|
634 |
+
state = gr.State({
|
635 |
+
'last_update': 0,
|
636 |
+
'processing': False
|
637 |
+
})
|
638 |
+
|
639 |
+
with gr.Row():
|
640 |
+
with gr.Column():
|
641 |
+
gr.Markdown("## Select input image and patch on the image")
|
642 |
+
image_selector = gr.Dropdown(
|
643 |
+
choices=list(_CACHE['data_dict'].keys()),
|
644 |
+
value=default_image_name,
|
645 |
+
label="Select Image",
|
646 |
+
)
|
647 |
+
image_display = gr.Image(
|
648 |
+
value=_CACHE['data_dict'][default_image_name]["image"],
|
649 |
+
type="pil",
|
650 |
+
interactive=True,
|
651 |
+
)
|
652 |
+
|
653 |
+
def safe_update_image(img_name):
|
654 |
+
return safe_operation(
|
655 |
+
lambda: _CACHE['data_dict'][img_name]["image"],
|
656 |
+
timeout=5,
|
657 |
+
default=Image.new('RGB', (IMAGE_SIZE, IMAGE_SIZE), 'gray')
|
658 |
+
)
|
659 |
+
|
660 |
+
image_selector.change(
|
661 |
+
fn=safe_update_image,
|
662 |
+
inputs=image_selector,
|
663 |
+
outputs=image_display,
|
664 |
+
)
|
665 |
+
|
666 |
+
with gr.Column():
|
667 |
+
gr.Markdown("## SAE latent activations of CLIP and MaPLE")
|
668 |
+
model_options = [f"MaPLE-{dataset_name}" for dataset_name in DATASET_LIST]
|
669 |
+
model_selector = gr.Dropdown(
|
670 |
+
choices=model_options,
|
671 |
+
value=model_options[0],
|
672 |
+
label="Select adapted model (MaPLe)",
|
673 |
+
)
|
674 |
+
|
675 |
+
def safe_plot_activation(evt, selected_image, model_name):
|
676 |
+
try:
|
677 |
+
return safe_operation(
|
678 |
+
plot_activation_distribution,
|
679 |
+
evt, selected_image, model_name,
|
680 |
+
timeout=10,
|
681 |
+
default=go.Figure() # Return empty figure on timeout
|
682 |
+
)
|
683 |
+
except Exception as e:
|
684 |
+
print(f"Error in plot_activation: {e}")
|
685 |
+
return go.Figure()
|
686 |
+
|
687 |
+
neuron_plot = gr.Plot(
|
688 |
+
label="Neuron Activation",
|
689 |
+
value=safe_plot_activation(None, default_image_name, model_options[0]),
|
690 |
+
show_label=False,
|
691 |
+
)
|
692 |
+
|
693 |
+
def debounced_update(*args, minimum_interval=1.0):
|
694 |
+
"""Prevent updates that are too close together"""
|
695 |
+
current_time = time.time()
|
696 |
+
if current_time - state.value['last_update'] < minimum_interval:
|
697 |
+
raise gr.Error("Please wait a moment before updating again")
|
698 |
+
state.value['last_update'] = current_time
|
699 |
+
return safe_plot_activation(*args)
|
700 |
+
|
701 |
+
# Add error handling and debouncing to all event handlers
|
702 |
+
image_selector.change(
|
703 |
+
fn=debounced_update,
|
704 |
+
inputs=[image_selector, model_selector],
|
705 |
+
outputs=neuron_plot,
|
706 |
+
)
|
707 |
+
image_display.select(
|
708 |
+
fn=debounced_update,
|
709 |
+
inputs=[image_selector, model_selector],
|
710 |
+
outputs=neuron_plot,
|
711 |
+
)
|
712 |
+
model_selector.change(
|
713 |
+
fn=debounced_update,
|
714 |
+
inputs=[image_selector, model_selector],
|
715 |
+
outputs=neuron_plot,
|
716 |
+
)
|
717 |
+
|
718 |
+
# Rest of your interface code with similar error handling...
|
719 |
+
|
720 |
+
return demo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
721 |
|
722 |
+
demo = create_interface()
|
|
|
|
|
723 |
|
|
|
724 |
if __name__ == "__main__":
|
725 |
+
# Configure logging
|
726 |
+
import logging
|
727 |
+
logging.basicConfig(
|
728 |
+
level=logging.INFO,
|
729 |
+
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
|
|
|
|
|
730 |
)
|
731 |
+
|
732 |
+
# Initialize the interface with error handling
|
733 |
+
try:
|
734 |
+
demo = create_interface()
|
735 |
+
demo.queue(concurrency_count=2) # Limit concurrent operations
|
736 |
+
demo.launch(
|
737 |
+
server_name="0.0.0.0",
|
738 |
+
server_port=7860,
|
739 |
+
share=False,
|
740 |
+
show_error=True,
|
741 |
+
max_threads=4, # Reduced for better stability
|
742 |
+
prevent_thread_lock=True,
|
743 |
+
# Add health check endpoint
|
744 |
+
root_path="/healthz",
|
745 |
+
# Add automatic cleanup
|
746 |
+
_teardown=lambda: (
|
747 |
+
clear_caches(),
|
748 |
+
logging.info("Caches cleared during teardown")
|
749 |
+
),
|
750 |
+
# Configure timeouts
|
751 |
+
api_open_timeout=60,
|
752 |
+
api_call_timeout=300,
|
753 |
+
)
|
754 |
+
except Exception as e:
|
755 |
+
logging.error(f"Failed to launch interface: {e}")
|
756 |
+
raise
|