CoACT initialize (#292)

This commit is contained in:
Linxin Song
2025-07-30 19:35:20 -07:00
committed by GitHub
parent 862d704b8c
commit b968155757
228 changed files with 42386 additions and 0 deletions

View File

@@ -1568,5 +1568,230 @@ def end_recording():
return abort(500, description=f"Recording failed. The output file is missing or empty. ffmpeg stderr: {error_output}")
@app.route("/run_python", methods=['POST'])
def run_python():
data = request.json
code = data.get('code', None)
if not code:
return jsonify({'status': 'error', 'message': 'Code not supplied!'}), 400
# Create a temporary file to save the Python code
import tempfile
import uuid
# Generate unique filename
temp_filename = f"/tmp/python_exec_{uuid.uuid4().hex}.py"
try:
# Write code to temporary file
with open(temp_filename, 'w') as f:
f.write(code)
# Execute the file using subprocess to capture all output
result = subprocess.run(
['/usr/bin/python3', temp_filename],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
timeout=30 # 30 second timeout
)
# Clean up the temporary file
try:
os.remove(temp_filename)
except:
pass # Ignore cleanup errors
# Prepare response
output = result.stdout
error_output = result.stderr
# Combine output and errors if both exist
combined_message = output
if error_output:
combined_message += ('\n' + error_output) if output else error_output
# Determine status based on return code and errors
if result.returncode != 0:
status = 'error'
if not error_output:
# If no stderr but non-zero return code, add a generic error message
error_output = f"Process exited with code {result.returncode}"
combined_message = combined_message + '\n' + error_output if combined_message else error_output
else:
status = 'success'
return jsonify({
'status': status,
'message': combined_message,
'need_more': False, # Not applicable for file execution
'output': output, # stdout only
'error': error_output, # stderr only
'return_code': result.returncode
})
except subprocess.TimeoutExpired:
# Clean up the temporary file on timeout
try:
os.remove(temp_filename)
except:
pass
return jsonify({
'status': 'error',
'message': 'Execution timeout: Code took too long to execute',
'error': 'TimeoutExpired',
'need_more': False,
'output': None,
}), 500
except Exception as e:
# Clean up the temporary file on error
try:
os.remove(temp_filename)
except:
pass
# Capture the exception details
return jsonify({
'status': 'error',
'message': f'Execution error: {str(e)}',
'error': traceback.format_exc(),
'need_more': False,
'output': None,
}), 500
@app.route("/run_bash_script", methods=['POST'])
def run_bash_script():
data = request.json
script = data.get('script', None)
timeout = data.get('timeout', 100) # Default timeout of 30 seconds
working_dir = data.get('working_dir', None)
if not script:
return jsonify({
'status': 'error',
'output': 'Script not supplied!',
'error': "", # Always empty as requested
'returncode': -1
}), 400
# Expand user directory if provided
if working_dir:
working_dir = os.path.expanduser(working_dir)
if not os.path.exists(working_dir):
return jsonify({
'status': 'error',
'output': f'Working directory does not exist: {working_dir}',
'error': "", # Always empty as requested
'returncode': -1
}), 400
# Create a temporary script file
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.sh', delete=False) as tmp_file:
if "#!/bin/bash" not in script:
script = "#!/bin/bash\n\n" + script
tmp_file.write(script)
tmp_file_path = tmp_file.name
try:
# Make the script executable
os.chmod(tmp_file_path, 0o755)
# Execute the script
if platform_name == "Windows":
# On Windows, use Git Bash or WSL if available, otherwise cmd
flags = subprocess.CREATE_NO_WINDOW
# Try to use bash if available (Git Bash, WSL, etc.)
result = subprocess.run(
['bash', tmp_file_path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Merge stderr into stdout
text=True,
timeout=timeout,
cwd=working_dir,
creationflags=flags,
shell=False
)
else:
# On Unix-like systems, use bash directly
flags = 0
result = subprocess.run(
['/bin/bash', tmp_file_path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Merge stderr into stdout
text=True,
timeout=timeout,
cwd=working_dir,
creationflags=flags,
shell=False
)
# Log the command execution for trajectory recording
_append_event("BashScript",
{"script": script, "output": result.stdout, "error": "", "returncode": result.returncode},
ts=time.time())
return jsonify({
'status': 'success' if result.returncode == 0 else 'error',
'output': result.stdout, # Contains both stdout and stderr merged
'error': "", # Always empty as requested
'returncode': result.returncode
})
except subprocess.TimeoutExpired:
return jsonify({
'status': 'error',
'output': f'Script execution timed out after {timeout} seconds',
'error': "", # Always empty as requested
'returncode': -1
}), 500
except FileNotFoundError:
# Bash not found, try with sh
try:
result = subprocess.run(
['sh', tmp_file_path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Merge stderr into stdout
text=True,
timeout=timeout,
cwd=working_dir,
shell=False
)
_append_event("BashScript",
{"script": script, "output": result.stdout, "error": "", "returncode": result.returncode},
ts=time.time())
return jsonify({
'status': 'success' if result.returncode == 0 else 'error',
'output': result.stdout, # Contains both stdout and stderr merged
'error': "", # Always empty as requested
'returncode': result.returncode,
})
except Exception as e:
return jsonify({
'status': 'error',
'output': f'Failed to execute script: {str(e)}',
'error': "", # Always empty as requested
'returncode': -1
}), 500
except Exception as e:
return jsonify({
'status': 'error',
'output': f'Failed to execute script: {str(e)}',
'error': "", # Always empty as requested
'returncode': -1
}), 500
finally:
# Clean up the temporary file
try:
os.unlink(tmp_file_path)
except:
pass
if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0")