# app.py import gradio as gr import time import datetime # --- Core Browser Logic (Slightly modified for Gradio) --- # Changes: # - Removed print() statements. Methods now return status/log messages. # - Removed time.sleep() as Gradio handles user feedback. class Tab: """Represents a single browser tab with its own history.""" def __init__(self, homepage): self.history = [] self.current_index = -1 self.homepage = homepage self.navigate(self.homepage) def navigate(self, url): """Navigates to a new URL, clearing any 'forward' history.""" if self.current_index < len(self.history) - 1: self.history = self.history[:self.current_index + 1] self.history.append(url) self.current_index += 1 return f"Navigating to {url}..." def go_back(self): if self.current_index > 0: self.current_index -= 1 return f"Going back to {self.current_url()}" return "No more history to go back to." def go_forward(self): if self.current_index < len(self.history) - 1: self.current_index += 1 return f"Going forward to {self.current_url()}" return "No more history to go forward to." def current_url(self): return self.history[self.current_index] if self.current_index != -1 else "about:blank" class PseudoBrowser: """Simulates a web browser's core functionality.""" def __init__(self): self.homepage = "https://www.startpage.com" self.tabs = [Tab(self.homepage)] self.active_tab_index = 0 self.bookmarks = set() self.global_history = [] self.cache = {} def _get_active_tab(self): return self.tabs[self.active_tab_index] def _fetch_content(self, url, refresh=False): """Simulates fetching content, using a cache.""" log = "" if url in self.cache and not refresh: log += f"âšĄī¸ Loading '{url}' from cache.\n" content = self.cache[url] else: log += f"â˜ī¸ Fetching '{url}' from network...\n" content = f"

Welcome to {url}

Content 'rendered' at {datetime.datetime.now().strftime('%H:%M:%S')}

" self.cache[url] = content return content, log def open_url(self, url): tab = self._get_active_tab() log = tab.navigate(url) self.global_history.append((datetime.datetime.now(), url)) content, fetch_log = self._fetch_content(url) return content, log + "\n" + fetch_log def back(self): tab = self._get_active_tab() log = tab.go_back() content, fetch_log = self._fetch_content(tab.current_url()) return content, log + "\n" + fetch_log def forward(self): tab = self._get_active_tab() log = tab.go_forward() content, fetch_log = self._fetch_content(tab.current_url()) return content, log + "\n" + fetch_log def refresh(self): tab = self._get_active_tab() url = tab.current_url() log = f"🔄 Refreshing {url}..." content, fetch_log = self._fetch_content(url, refresh=True) return content, log + "\n" + fetch_log def new_tab(self): new_tab = Tab(self.homepage) self.tabs.append(new_tab) self.active_tab_index = len(self.tabs) - 1 content, fetch_log = self._fetch_content(new_tab.current_url()) return content, f"✨ New tab opened.\n" + fetch_log def close_tab(self): if len(self.tabs) == 1: return None, "❌ Cannot close the last tab!" closed_tab = self.tabs.pop(self.active_tab_index) log = f"đŸ’Ŗ Tab ({closed_tab.current_url()}) closed." if self.active_tab_index >= len(self.tabs): self.active_tab_index = len(self.tabs) - 1 active_tab = self._get_active_tab() content, fetch_log = self._fetch_content(active_tab.current_url()) return content, log + "\n" + fetch_log def switch_tab(self, tab_label): # The label is "Tab 0: https://..." index = int(tab_label.split(":")[0].replace("Tab", "").strip()) if 0 <= index < len(self.tabs): self.active_tab_index = index tab = self._get_active_tab() content, fetch_log = self._fetch_content(tab.current_url()) return content, f"Switched to Tab {index}.\n" + fetch_log return None, "❌ Invalid tab index." def add_bookmark(self): url = self._get_active_tab().current_url() if url not in self.bookmarks: self.bookmarks.add(url) return f"⭐ Bookmarked: {url}" return f"â„šī¸ Already bookmarked: {url}" # --- Gradio UI and Event Handlers --- def update_ui_components(browser: PseudoBrowser): """Generates all UI component values from the browser state.""" # Main Content active_tab = browser._get_active_tab() content, _ = browser._fetch_content(active_tab.current_url()) url_text = active_tab.current_url() # Tab Selector tab_choices = [f"Tab {i}: {tab.current_url()}" for i, tab in enumerate(browser.tabs)] active_tab_label = f"Tab {browser.active_tab_index}: {active_tab.current_url()}" # History history_md = "### 📜 Global History\n" if not browser.global_history: history_md += "_(empty)_" else: for ts, url in reversed(browser.global_history[-10:]): # Show last 10 history_md += f"- `{ts.strftime('%H:%M:%S')}`: {url}\n" # Bookmarks bookmarks_md = "### 📚 Bookmarks\n" if not browser.bookmarks: bookmarks_md += "_(empty)_" else: for bm in sorted(list(browser.bookmarks)): bookmarks_md += f"- ⭐ {bm}\n" return { html_view: gr.HTML(value=content), url_textbox: gr.Textbox(value=url_text), tab_selector: gr.Radio(choices=tab_choices, value=active_tab_label, label="Active Tabs"), history_display: gr.Markdown(history_md), bookmarks_display: gr.Markdown(bookmarks_md) } # --- Event Handlers --- def handle_go(browser_state, url): content, log = browser_state.open_url(url) return { **update_ui_components(browser_state), log_display: gr.Textbox(log) } def handle_back(browser_state): content, log = browser_state.back() return { **update_ui_components(browser_state), log_display: gr.Textbox(log) } def handle_forward(browser_state): content, log = browser_state.forward() return { **update_ui_components(browser_state), log_display: gr.Textbox(log) } def handle_refresh(browser_state): content, log = browser_state.refresh() return { **update_ui_components(browser_state), log_display: gr.Textbox(log) } def handle_new_tab(browser_state): content, log = browser_state.new_tab() return { **update_ui_components(browser_state), log_display: gr.Textbox(log) } def handle_close_tab(browser_state): content, log = browser_state.close_tab() # Update UI components. If content is None, it means the last tab wasn't closed. updated_components = update_ui_components(browser_state) if content is not None: updated_components[html_view] = gr.HTML(value=content) return { **updated_components, log_display: gr.Textbox(log) } def handle_switch_tab(browser_state, tab_label): content, log = browser_state.switch_tab(tab_label) return { **update_ui_components(browser_state), log_display: gr.Textbox(log) } def handle_add_bookmark(browser_state): log = browser_state.add_bookmark() return { **update_ui_components(browser_state), log_display: gr.Textbox(log) } # --- Gradio Interface Layout --- with gr.Blocks(theme=gr.themes.Soft(), title="Pseudo Browser") as demo: browser_state = gr.State(PseudoBrowser()) gr.Markdown("# 🌐 Pseudo Browser Demo") gr.Markdown("A simulation of a web browser's state and actions, built with Python and Gradio.") with gr.Row(): with gr.Column(scale=3): # URL and Navigation Controls with gr.Row(): back_btn = gr.Button("◀") forward_btn = gr.Button("â–ļ") refresh_btn = gr.Button("🔄") url_textbox = gr.Textbox(label="URL", placeholder="https://example.com", interactive=True) go_btn = gr.Button("Go", variant="primary") bookmark_btn = gr.Button("⭐") # Main "rendered" content view html_view = gr.HTML(value="

Welcome!

") # Log display log_display = gr.Textbox(label="Log", interactive=False) with gr.Column(scale=1): # Tab Management with gr.Row(): new_tab_btn = gr.Button("➕ New Tab") close_tab_btn = gr.Button("❌ Close Active Tab") tab_selector = gr.Radio(choices=[], label="Active Tabs", interactive=True) # Accordion for History and Bookmarks with gr.Accordion("History & Bookmarks", open=True): history_display = gr.Markdown("...") bookmarks_display = gr.Markdown("...") # --- Component Wiring --- # Define all outputs that can be updated outputs = [html_view, url_textbox, tab_selector, history_display, bookmarks_display, log_display] # Initial load demo.load( fn=lambda state: {**update_ui_components(state), log_display: "🚀 Browser Initialized!"}, inputs=[browser_state], outputs=outputs ) # Wire up buttons go_btn.click(handle_go, [browser_state, url_textbox], outputs) url_textbox.submit(handle_go, [browser_state, url_textbox], outputs) back_btn.click(handle_back, [browser_state], outputs) forward_btn.click(handle_forward, [browser_state], outputs) refresh_btn.click(handle_refresh, [browser_state], outputs) new_tab_btn.click(handle_new_tab, [browser_state], outputs) close_tab_btn.click(handle_close_tab, [browser_state], outputs) tab_selector.input(handle_switch_tab, [browser_state, tab_selector], outputs) bookmark_btn.click(handle_add_bookmark, [browser_state], outputs) demo.launch()