Trisha Tomy commited on
Commit
689e710
·
1 Parent(s): c584818

Initial commit for proxy-lite API

Browse files
Files changed (4) hide show
  1. Dockerfile +71 -0
  2. Procfile +1 -0
  3. app.py +97 -0
  4. requirements.txt +6 -0
Dockerfile ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dockerfile
2
+ # Use a Python base image that is compatible with Playwright's system dependencies
3
+ FROM python:3.9-slim-buster
4
+
5
+ # Set the working directory inside the container
6
+ WORKDIR /app
7
+
8
+ # Install system dependencies required by Playwright's Chromium browser
9
+ # These are common dependencies for running headless Chrome/Chromium.
10
+ # This list might need minor adjustments based on specific runtime errors.
11
+ RUN apt-get update && apt-get install -y \
12
+ # Core libraries for graphics/rendering
13
+ fonts-liberation \
14
+ libappindicator3-1 \
15
+ libasound2 \
16
+ libatk-bridge2.0-0 \
17
+ libatk1.0-0 \
18
+ libatspi2.0-0 \
19
+ libcairo2 \
20
+ libcups2 \
21
+ libdbus-1-3 \
22
+ libdrm2 \
23
+ libgdk-pixbuf2.0-0 \
24
+ libglib2.0-0 \
25
+ libgtk-3-0 \
26
+ libnspr4 \
27
+ libnss3 \
28
+ libpangocairo-1.0-0 \
29
+ libxcomposite1 \
30
+ libxdamage1 \
31
+ libxext6 \
32
+ libxfixes3 \
33
+ libxrandr2 \
34
+ libxrender1 \
35
+ libxss1 \
36
+ libxtst6 \
37
+ # Specific to Chromium/GPU (even if not using GPU, these are for display stack)
38
+ libgbm-dev \
39
+ libasound2-dev \
40
+ # xvfb provides a virtual display server, often necessary for headless browsers
41
+ xvfb \
42
+ # Ensure Chromium is installed on the system (Playwright uses its own, but sometimes useful)
43
+ chromium \
44
+ # Clean up apt caches to reduce image size
45
+ && rm -rf /var/lib/apt/lists/*
46
+
47
+ # Copy Python dependencies and install them
48
+ # This layer is cached efficiently if requirements.txt doesn't change
49
+ COPY requirements.txt .
50
+ RUN pip install --no-cache-dir -r requirements.txt
51
+
52
+ # Copy your application code into the container
53
+ COPY . .
54
+
55
+ # Install Playwright browser binaries within the container
56
+ # This downloads Chromium into the container's Playwright-managed location.
57
+ RUN playwright install chromium
58
+
59
+ # Set environment variables for Playwright
60
+ # PLAYWRIGHT_BROWSERS_PATH: Tells Playwright where to find the installed browsers.
61
+ # DISPLAY, XDG_RUNTIME_DIR: Often needed for headless browser environments.
62
+ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright/
63
+ ENV DISPLAY=:99
64
+ ENV XDG_RUNTIME_DIR=/tmp
65
+
66
+ # Expose the port your Flask app will listen on. Hugging Face Spaces expects 7860.
67
+ EXPOSE 7860
68
+
69
+ # Define the command to run your Flask application using Gunicorn for production
70
+ # Hugging Face Spaces will execute this command to start your web service.
71
+ CMD exec gunicorn --bind 0.0.0.0:7860 --workers 2 --worker-class gevent app:app --timeout 300
Procfile ADDED
@@ -0,0 +1 @@
 
 
1
+ web: gunicorn --bind 0.0.0.0:7860 --workers 2 --worker-class gevent app:app --timeout 300
app.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import asyncio
3
+ from flask import Flask, request, jsonify
4
+ from proxy_lite import Runner, RunnerConfig
5
+ import os
6
+ import logging
7
+
8
+ # Configure logging for better visibility in Space logs
9
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
10
+ logger = logging.getLogger(__name__)
11
+
12
+ app = Flask(__name__)
13
+
14
+ # Global runner instance. It will be initialized once.
15
+ _runner = None
16
+
17
+ async def initialize_runner():
18
+ """Initializes the Proxy-lite Runner asynchronously."""
19
+ global _runner
20
+ if _runner is None:
21
+ logger.info("Initializing Proxy-lite Runner...")
22
+ # Retrieve Hugging Face API Token from environment variables (set as Space Secret)
23
+ hf_api_token = os.environ.get("HF_API_TOKEN")
24
+ if not hf_api_token:
25
+ logger.error("HF_API_TOKEN environment variable not set. Cannot initialize Runner.")
26
+ raise ValueError("HF_API_TOKEN environment variable not set. Please set it as a Space secret.")
27
+
28
+ config = RunnerConfig.from_dict({
29
+ "environment": {
30
+ "name": "webbrowser",
31
+ "homepage": "https://www.google.com",
32
+ "headless": True, # Runs browser without a visible UI
33
+ },
34
+ "solver": {
35
+ "name": "simple",
36
+ "agent": {
37
+ "name": "proxy_lite",
38
+ "client": {
39
+ "name": "convergence",
40
+ "model_id": "convergence-ai/proxy-lite-3b",
41
+ # THIS IS THE HUGGING FACE INFERENCE API ENDPOINT
42
+ "api_base": "https://api-inference.huggingface.co/models/convergence-ai/proxy-lite-3b",
43
+ "api_key": hf_api_token # Use the token from environment variable
44
+ }
45
+ }
46
+ }
47
+ })
48
+ _runner = Runner(config)
49
+ logger.info("Proxy-lite Runner initialized successfully.")
50
+ return _runner
51
+
52
+ # Helper function to run asynchronous code within a synchronous Flask route
53
+ def run_async_task(coro):
54
+ """Helper to run async coroutines in a synchronous context (like Flask routes)."""
55
+ loop = asyncio.get_event_loop()
56
+ return loop.run_until_complete(coro)
57
+
58
+ @app.route('/run_proxy_task', methods=['POST'])
59
+ def run_proxy_task_endpoint():
60
+ """API endpoint to receive a task and execute it with Proxy-lite."""
61
+ data = request.json
62
+ task = data.get('task')
63
+ if not task:
64
+ logger.warning("Received request without 'task' field. Returning 400.")
65
+ return jsonify({"error": "No 'task' provided in request body"}), 400
66
+
67
+ logger.info(f"Received task for proxy-lite: '{task}'")
68
+ try:
69
+ # Initialize runner if not already done
70
+ runner = run_async_task(initialize_runner())
71
+ # Run the task using the proxy-lite runner
72
+ result = run_async_task(runner.run(task))
73
+
74
+ logger.info(f"Proxy-lite task completed. Output: {result[:200]}...") # Log truncated output
75
+ # Return the result as a JSON response
76
+ return jsonify({"output": result})
77
+ except Exception as e:
78
+ logger.exception(f"Error processing task '{task}':") # Logs full traceback for debugging
79
+ return jsonify({"error": f"An error occurred: {str(e)}. Check logs for details."}), 500
80
+
81
+ @app.route('/')
82
+ def root():
83
+ """Basic root endpoint for health check."""
84
+ logger.info("Root endpoint accessed.")
85
+ return "Proxy-lite API is running. Send POST requests to /run_proxy_task with a 'task' in JSON body."
86
+
87
+ if __name__ == '__main__':
88
+ # Check if HF_API_TOKEN is set during local development/testing
89
+ if not os.environ.get("HF_API_TOKEN"):
90
+ logger.error("HF_API_TOKEN environment variable is not set. Please set it for local testing.")
91
+ # For local execution, you might choose to exit or just log
92
+ # For deployment on Hugging Face Spaces, it MUST be set as a Secret.
93
+ # exit(1) # Uncomment this if you want to force exit without token locally
94
+
95
+ logger.info("Starting Flask development server on 0.0.0.0:7860...")
96
+ # Hugging Face Spaces requires binding to 0.0.0.0 and listening on port 7860
97
+ app.run(host='0.0.0.0', port=7860, debug=True) # debug=True for local, disable for production
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ Flask
2
+ proxy-lite
3
+ playwright
4
+ playwright-stealth==1.0.6
5
+ gunicorn
6
+ gevent