Trae Assistant
Initial commit with enhanced features
c579494
import os
import json
import time
import requests
import urllib3
import base64
from flask import Flask, render_template, request, jsonify
# Suppress InsecureRequestWarning for verify=False
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
app = Flask(__name__)
app.secret_key = os.urandom(24)
app.config['MAX_CONTENT_LENGTH'] = 32 * 1024 * 1024 # 32MB limit
# Standard Jinja2 delimiters are used.
# Vue.js will be configured to use ['${', '}'] to avoid conflict.
@app.route('/')
def index():
return render_template('index.html')
@app.route('/api/proxy', methods=['POST'])
def proxy_request():
try:
data = request.json
if not data:
return jsonify({'error': 'No data provided'}), 400
method = data.get('method', 'GET').upper()
url = data.get('url')
headers = data.get('headers', {})
body = data.get('body', None)
params = data.get('params', {})
if not url:
return jsonify({'error': 'URL is required'}), 400
# Ensure headers is a dict
if not isinstance(headers, dict):
headers = {}
start_time = time.time()
# Prepare arguments
kwargs = {
'method': method,
'url': url,
'headers': headers,
'params': params,
'timeout': 60, # Increased timeout
'verify': False, # Allow testing local/self-signed endpoints
'allow_redirects': True
}
# Handle Body
if body:
content_type = ''
# Case insensitive search for Content-Type
for k, v in headers.items():
if k.lower() == 'content-type':
content_type = v.lower()
break
if 'application/json' in content_type:
if isinstance(body, str):
try:
# Try to parse to ensure it's valid JSON if we want to send as json kwarg
json_body = json.loads(body)
kwargs['json'] = json_body
except:
# Send as raw string if it fails to parse
kwargs['data'] = body
else:
kwargs['json'] = body
else:
# x-www-form-urlencoded or plain text
kwargs['data'] = body.encode('utf-8') if isinstance(body, str) else body
resp = requests.request(**kwargs)
duration = (time.time() - start_time) * 1000 # ms
# Format response headers
resp_headers = dict(resp.headers)
resp_content_type = resp_headers.get('Content-Type', '').lower()
# Determine how to return data
is_binary = False
is_json = False
resp_data = None
# Check for binary content types (images, pdfs, audio, etc.)
binary_types = ['image/', 'audio/', 'video/', 'application/pdf', 'application/octet-stream', 'application/zip']
if any(bt in resp_content_type for bt in binary_types):
is_binary = True
resp_data = base64.b64encode(resp.content).decode('utf-8')
else:
# Try to parse response body as JSON
try:
resp_data = resp.json()
is_json = True
except:
# Fallback to text
resp_data = resp.text
return jsonify({
'status': resp.status_code,
'status_text': resp.reason,
'headers': resp_headers,
'data': resp_data,
'is_json': is_json,
'is_binary': is_binary,
'content_type': resp_headers.get('Content-Type', ''),
'duration': round(duration, 2),
'size': len(resp.content)
})
except requests.exceptions.RequestException as e:
return jsonify({
'error': str(e),
'duration': round((time.time() - (start_time if 'start_time' in locals() else time.time())) * 1000, 2)
}), 500
except Exception as e:
return jsonify({
'error': f"Internal Server Error: {str(e)}",
'duration': 0
}), 500
if __name__ == '__main__':
port = int(os.environ.get('PORT', 7860))
app.run(host='0.0.0.0', port=port, debug=True)