mirror of
https://github.com/open-webui/open-terminal.git
synced 2026-11-04 08:10:53 +00:00
init
This commit is contained in:
commit
3f7c544835
9 files changed
+171
No files matched your search
+23
@@ -0,0 +1,23 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.egg-info/
|
||||
dist/
|
||||
build/
|
||||
|
||||
# venv
|
||||
.venv/
|
||||
|
||||
# uv
|
||||
uv.lock
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -0,0 +1 @@
|
||||
3.11
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
jq \
|
||||
vim-tiny \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
openssh-client \
|
||||
unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN pip install --no-cache-dir .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
ENTRYPOINT ["open-terminal"]
|
||||
CMD ["run"]
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
uv run uvicorn open_terminal.main:app --reload
|
||||
@@ -0,0 +1 @@
|
||||
"""open-terminal — a barebones terminal interaction API."""
|
||||
@@ -0,0 +1,20 @@
|
||||
import click
|
||||
import uvicorn
|
||||
|
||||
|
||||
@click.group()
|
||||
def main():
|
||||
"""open-terminal — terminal interaction API"""
|
||||
pass
|
||||
|
||||
|
||||
@main.command()
|
||||
@click.option("--host", default="0.0.0.0", help="Bind host")
|
||||
@click.option("--port", default=8000, type=int, help="Bind port")
|
||||
def run(host: str, port: int):
|
||||
"""Start the sandbox API server."""
|
||||
uvicorn.run("open_terminal.main:app", host=host, port=port)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,78 @@
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import StreamingResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI(title="open-terminal")
|
||||
|
||||
|
||||
class ExecRequest(BaseModel):
|
||||
command: str
|
||||
timeout: Optional[float] = 30.0
|
||||
|
||||
|
||||
class ExecResponse(BaseModel):
|
||||
exit_code: int
|
||||
stdout: str
|
||||
stderr: str
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.post("/execute")
|
||||
async def execute(req: ExecRequest, stream: bool = False):
|
||||
if stream:
|
||||
return _stream_response(req)
|
||||
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_shell(
|
||||
req.command,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
stdout, stderr = await asyncio.wait_for(
|
||||
proc.communicate(), timeout=req.timeout
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
proc.kill()
|
||||
await proc.communicate()
|
||||
return ExecResponse(
|
||||
exit_code=-1,
|
||||
stdout="",
|
||||
stderr=f"Command timed out after {req.timeout}s",
|
||||
)
|
||||
|
||||
return ExecResponse(
|
||||
exit_code=proc.returncode or 0,
|
||||
stdout=stdout.decode(errors="replace"),
|
||||
stderr=stderr.decode(errors="replace"),
|
||||
)
|
||||
|
||||
|
||||
def _stream_response(req: ExecRequest):
|
||||
async def generate():
|
||||
proc = await asyncio.create_subprocess_shell(
|
||||
req.command,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
|
||||
async def read_stream(s, label):
|
||||
async for line in s:
|
||||
yield json.dumps({"type": label, "data": line.decode(errors="replace")}) + "\n"
|
||||
|
||||
async for chunk in read_stream(proc.stdout, "stdout"):
|
||||
yield chunk
|
||||
async for chunk in read_stream(proc.stderr, "stderr"):
|
||||
yield chunk
|
||||
|
||||
await proc.wait()
|
||||
yield json.dumps({"type": "exit", "data": proc.returncode}) + "\n"
|
||||
|
||||
return StreamingResponse(generate(), media_type="application/x-ndjson")
|
||||
@@ -0,0 +1,24 @@
|
||||
[project]
|
||||
name = "open-terminal"
|
||||
version = "0.1.0"
|
||||
description = "A barebones terminal interaction API"
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
{ name = "Timothy Jaeryang Baek", email = "tim@openwebui.com" }
|
||||
]
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"fastapi>=0.115.0",
|
||||
"uvicorn[standard]>=0.34.0",
|
||||
"click>=8.1.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
open-terminal = "open_terminal.cli:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["open_terminal"]
|
||||
Reference in new issue
Block a user