{"repo": "adithya-s-k/eurekaagent", "files": {"app.py": {"9fb95d3a68beaeae8af1e8c6083edd257551957a": {"t": 1785674392.5770576, "n": 73434, "h": "5836eb90663a20da", "c": "import os\nimport logging\nimport gradio as gr\nfrom gradio.utils import get_space\nfrom modal_sandbox import create_modal_sandbox\nfrom pathlib import Path\nimport json\nfrom datetime import datetime\nimport threading\nimport re\nfrom openai import OpenAI, AzureOpenAI\nfrom jupyter_handler import JupyterNotebook\n\nif not get_space():\n try:\n from dotenv import load_dotenv\n\n load_dotenv()\n except (ImportError, ModuleNotFoundError):\n pass\nfrom jupyter_agent import (\n run_interactive_notebook_with_session_state,\n SessionStateManager,\n)\n\nTMP_DIR = './temp/'\n\n# Environment and API key management utilities\ndef get_environment():\n \"\"\"Get the current environment (dev/prod)\"\"\"\n return os.environ.get(\"ENVIRONMENT\", \"prod\").lower()\n\ndef is_dev_environment():\n \"\"\"Check if running in development environment\"\"\"\n return get_environment() == \"dev\"\n\ndef get_required_api_keys():\n \"\"\"Get dictionary of required API keys and their current status\"\"\"\n required_keys = {\n \"MODAL_TOKEN_ID\": {\n \"value\": os.environ.get(\"MODAL_TOKEN_ID\"),\n \"required\": True,\n \"description\": \"Modal Token ID for sandbox access\"\n },\n \"MODAL_TOKEN_SECRET\": {\n \"value\": os.environ.get(\"MODAL_TOKEN_SECRET\"),\n \"required\": True,\n \"description\": \"Modal Token Secret for sandbox access\"\n },\n \"HF_TOKEN\": {\n \"value\": os.environ.get(\"HF_TOKEN\"),\n \"required\": False,\n \"description\": \"Hugging Face Token for model access\"\n },\n \"PROVIDER_API_KEY\": {\n \"value\": os.environ.get(\"PROVIDER_API_KEY\"),\n \"required\": True,\n \"description\": \"AI Provider API Key (Anthropic, OpenAI, etc.)\"\n },\n \"PROVIDER_API_ENDPOINT\": {\n \"value\": os.environ.get(\"PROVIDER_API_ENDPOINT\"),\n \"required\": True,\n \"description\": \"AI Provider API Endpoint\"\n },\n \"MODEL_NAME\": {\n \"value\": os.environ.get(\"MODEL_NAME\"),\n \"required\": True,\n \"description\": \"Model name to use\"\n },\n \"TAVILY_API_KEY\": {\n \"value\": os.environ.get(\"TAVILY_API_KEY\"),\n \"required\": False,\n \"description\": \"Tavily API Key for web search functionality\"\n }\n }\n return required_keys\n\ndef get_missing_api_keys():\n \"\"\"Get list of missing required API keys\"\"\"\n required_keys = get_required_api_keys()\n missing_keys = {}\n \n for key, config in required_keys.items():\n if config[\"required\"] and not config[\"value\"]:\n missing_keys[key] = config\n \n return missing_keys\n\ndef validate_api_key_format(key_name, key_value):\n \"\"\"Basic validation for API key formats\"\"\"\n if not key_value or not key_value.strip():\n return False, \"API key cannot be empty\"\n \n key_value = key_value.strip()\n \n # Basic format validation\n if key_name == \"MODAL_TOKEN_ID\" and not key_value.startswith(\"ak-\"):\n return False, \"Modal Token ID should start with 'ak-'\"\n elif key_name == \"MODAL_TOKEN_SECRET\" and not key_value.startswith(\"as-\"):\n return False, \"Modal Token Secret should start with 'as-'\"\n elif key_name == \"HF_TOKEN\" and not key_value.startswith(\"hf_\"):\n return False, \"Hugging Face token should start with 'hf_'\"\n elif key_name == \"PROVIDER_API_KEY\":\n # Check for common API key prefixes\n valid_prefixes = [\"sk-\", \"gsk_\", \"csk-\"]\n if not any(key_value.startswith(prefix) for prefix in valid_prefixes):\n return False, \"API key format may be invalid (expected prefixes: sk-, gsk_, csk-)\"\n elif key_name == \"PROVIDER_API_ENDPOINT\" and not (key_value.startswith(\"http://\") or key_value.startswith(\"https://\")):\n return False, \"API endpoint should start with http:// or https://\"\n elif key_name == \"TAVILY_API_KEY\" and not key_value.startswith(\"tvly-\"):\n return False, \"Tavily API key should start with 'tvly-'\"\n \n return True, \"Valid format\"\n\ndef apply_user_api_keys(api_keys_dict):\n \"\"\"Apply user-provided API keys to environment\"\"\"\n for key, value in api_keys_dict.items():\n if value and value.strip():\n os.environ[key] = value.strip()\n logger.info(f\"Applied user-provided API key: {key}\")\n\ndef get_previous_notebooks():\n \"\"\"Get list of previous notebook sessions (dev only)\"\"\"\n if not is_dev_environment():\n return []\n \n notebooks = []\n tmp_dir = Path(TMP_DIR)\n \n if not tmp_dir.exists():\n return notebooks\n \n for session_dir in tmp_dir.iterdir():\n if session_dir.is_dir() and session_dir.name != \".\":\n notebook_file = session_dir / \"jupyter-agent.ipynb\"\n if notebook_file.exists():\n try:\n # Get creation time and basic info\n stat = notebook_file.stat()\n size = stat.st_size\n modified = stat.st_mtime\n \n # Try to read basic notebook info\n with open(notebook_file, 'r') as f:\n notebook_data = json.load(f)\n cell_count = len(notebook_data.get('cells', []))\n \n # Format timestamp\n formatted_time = datetime.fromtimestamp(modified).strftime(\"%Y-%m-%d %H:%M\")\n \n # Try to load session state for additional info\n config_info = \"\"\n try:\n session_manager = SessionStateManager(session_dir.name, TMP_DIR)\n session_state = session_manager.load_state()\n if session_state:\n hardware = session_state.get(\"hardware_config\", {})\n gpu = hardware.get(\"gpu_type\", \"unknown\")\n config_info = f\", {gpu}\"\n except Exception:\n pass\n \n notebooks.append({\n 'session_id': session_dir.name,\n 'path': str(notebook_file),\n 'modified': modified,\n 'size': size,\n 'cell_count': cell_count,\n 'display_name': f\"{session_dir.name} ({cell_count} cells{config_info}, {formatted_time})\"\n })\n except Exception as e:\n logger.warning(f\"Failed to read notebook info for {session_dir.name}: {e}\")\n \n # Sort by modification time (newest first)\n notebooks.sort(key=lambda x: x['modified'], reverse=True)\n return notebooks\n\ndef parse_environment_variables(env_vars_text):\n \"\"\"\n Parse environment variables from text input\n \n Args:\n env_vars_text: String containing environment variables in KEY=value format, one per line\n \n Returns:\n dict: Dictionary of parsed environment variables\n \"\"\"\n env_dict = {}\n if not env_vars_text or not env_vars_text.strip():\n return env_dict\n \n for line in env_vars_text.strip().split('\\n'):\n line = line.strip()\n if not line or line.startswith('#'): # Skip empty lines and comments\n continue\n \n if '=' in line:\n key, value = line.split('=', 1) # Split only on first =\n key = key.strip()\n value = value.strip()\n if key: # Only add if key is not empty\n env_dict[key] = value\n else:\n logger.warning(f\"Skipping invalid environment variable format: {line}\")\n \n return env_dict\n\ndef create_notification_html(message, notification_type=\"info\", show_spinner=False):\n \"\"\"\n Create HTML for notification messages\n \n Args:\n message: The notification message\n notification_type: Type of notification ('info', 'success', 'warning', 'error')\n show_spinner: Whether to show a loading spinner\n \"\"\"\n colors = {\n 'info': '#3498db',\n 'success': '#27ae60', \n 'warning': '#f39c12',\n 'error': '#e74c3c',\n 'loading': '#6c5ce7'\n }\n \n icons = {\n 'info': 'π',\n 'success': 'β ',\n 'warning': 'β οΈ', \n 'error': 'β',\n 'loading': 'β³'\n }\n \n color = colors.get(notification_type, colors['info'])\n icon = icons.get(notification_type, icons['info'])\n \n spinner_html = \"\"\n if show_spinner or notification_type == 'loading':\n spinner_html = \"\"\"\n
\n \n \"\"\".format(color=color)\n \n return f\"\"\"\n