Spaces:
Running
Running
import gevent.monkey | |
gevent.monkey.patch_all(asyncio=True) | |
# app.py | |
import asyncio | |
from flask import Flask, request, jsonify | |
from proxy_lite import Runner, RunnerConfig | |
import os | |
import logging | |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
logger = logging.getLogger(__name__) | |
app = Flask(__name__) | |
_runner = None | |
async def initialize_runner(): | |
global _runner | |
if _runner is None: | |
logger.info("Initializing Proxy-lite Runner...") | |
# Retrieve Hugging Face API token from environment variables | |
hf_api_token = os.environ.get("HF_API_TOKEN") | |
if not hf_api_token: | |
logger.error("HF_API_TOKEN environment variable not set. Cannot initialize Runner.") | |
raise ValueError("HF_API_TOKEN environment variable not set. Please set it as a Space secret.") | |
# Define RunnerConfig | |
config = RunnerConfig.from_dict({ | |
"environment": { | |
"name": "webbrowser", | |
"homepage": "https://dwd000006jia1mae.lightning.force.com/lightning/setup/AccountForecastSettings/home", | |
"headless": True, # Keep headless for production environments | |
"launch_args": ["--no-sandbox", "--disable-setuid-sandbox"] , | |
# "environment_timeout": 1800.0, # <-- THIS LINE WAS IN THE WRONG PLACE IN app.py | |
"screenshot_delay": 3.0, # Increased delay for full page render before screenshot | |
"include_html": True, # Include full HTML for richer observations | |
"include_poi_text": True, # Keep including points of interest text | |
}, | |
"solver": { | |
"name": "simple", | |
"agent": { | |
"name": "proxy_lite", | |
"client": { | |
"name": "convergence", | |
"model_id": "convergence-ai/proxy-lite-3b", | |
"api_base": "https://convergence-ai-demo-api.hf.space/v1", | |
"api_key": hf_api_token | |
} | |
} | |
}, | |
# --- MOVE environment_timeout HERE, AS A TOP-LEVEL KEY --- | |
"environment_timeout": 1800.0, | |
# You can also set other top-level RunnerConfig fields here if desired, | |
# e.g., "action_timeout": 1800.0, "max_steps": 150, "task_timeout": 18000.0, | |
# Ensure these match your desired values and not the defaults from RunnerConfig. | |
# Based on your logs, action_timeout and task_timeout seem to be default, so let's add them: | |
"action_timeout": 1800.0, # As per your earlier runner.py __main__ block | |
"task_timeout": 18000.0, # As per your earlier runner.py __main__ block | |
"max_steps": 150, # As per your earlier runner.py __main__ block | |
"logger_level": "DEBUG", # Set this to DEBUG for more detailed logging during troubleshooting | |
# --- END OF MOVED KEY --- | |
}) | |
# --- ADDED DEBUG LOGGING HERE --- | |
logger.info(f"DEBUG: app.py - Initializing Runner with environment_timeout: {config.environment_timeout} seconds") | |
logger.info(f"DEBUG: app.py - Full config used: {config.model_dump_json(indent=2)}") # For Pydantic v2 | |
# If you are using Pydantic v1, use: logger.info(f"DEBUG: app.py - Full config used: {config.json(indent=2)}") | |
# --- END ADDED DEBUG LOGGING --- | |
_runner = Runner(config=config) | |
logger.info("Proxy-lite Runner initialized successfully.") | |
return _runner | |
# --- MODIFIED run_async_task FUNCTION --- | |
def run_async_task(coro): | |
""" | |
Helper to run async coroutines in a synchronous context (like Flask routes). | |
Ensures an event loop exists and runs the coroutine. | |
""" | |
try: | |
# Try to get the running loop (for current thread/greenlet) | |
loop = asyncio.get_running_loop() | |
except RuntimeError: | |
# If no loop is running, create a new one for this thread | |
loop = asyncio.new_event_loop() | |
asyncio.set_event_loop(loop) | |
# Run the coroutine until it completes | |
return loop.run_until_complete(coro) | |
# --- END MODIFIED run_async_task FUNCTION --- | |
def run_proxy_task_endpoint(): | |
data = request.json | |
request_task_instruction = data.get('task') | |
if not request_task_instruction: | |
logger.warning("Received request without 'task' field. Returning 400.") | |
return jsonify({"error": "No 'task' provided in request body"}), 400 | |
logger.info(f"Received user request task: '{request_task_instruction}'") | |
salesforce_username = os.environ.get("SALESFORCE_USERNAME") | |
salesforce_password = os.environ.get("SALESFORCE_PASSWORD") | |
if not salesforce_username or not salesforce_password: | |
logger.error("Salesforce credentials (SALESFORCE_USERNAME, SALESFORCE_PASSWORD) environment variables not set.") | |
return jsonify({"error": "Salesforce credentials not configured. Please set SALESFORCE_USERNAME and SALESFORCE_PASSWORD as Space secrets."}), 500 | |
# Construct the full task for the proxy-lite agent, | |
# combining login instructions with the dynamic task from the user, | |
# and adding explicit verification steps for login success. | |
agent_task = ( | |
f"Log in to Salesforce. The username is '{salesforce_username}' and the password is '{salesforce_password}'. " | |
f"After attempting to log in, observe the page carefully. " | |
f"If the login was successful, the URL should change from the login page, and you should see elements indicating a logged-in state (e.g., a Salesforce navigation menu, a home screen, or a profile icon), rather than a login form or an error message. " | |
f"If the login is successful, {request_task_instruction}. " | |
f"Report the final status of the requested action and confirmation of successful login." | |
) | |
logger.info(f"Executing agent task: '{agent_task[:200]}...'") | |
try: | |
runner = run_async_task(initialize_runner()) | |
result = run_async_task(runner.run(agent_task)) | |
logger.info(f"Proxy-lite task completed. Output: {result[:200]}...") | |
return jsonify({"output": result}) | |
except Exception as e: | |
logger.exception(f"Error processing Salesforce task: {e}") | |
return jsonify({"error": f"An error occurred: {str(e)}. Check logs for details."}), 500 | |
def root(): | |
logger.info("Root endpoint accessed.") | |
return "Proxy-lite API is running. Send POST requests to /run_proxy_task with a 'task' in JSON body." | |
if __name__ == '__main__': | |
if not os.environ.get("HF_API_TOKEN"): | |
logger.error("HF_API_TOKEN environment variable is not set. Please set it for local testing.") | |
exit(1) | |
logger.info("Starting Flask development server on 0.0.0.0:7860...") | |
app.run(host='0.0.0.0', port=7860, debug=True) |