mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-13 22:15:10 +00:00
feat: code exec tool and desc
This commit is contained in:
1 parent
0606c5ddcb
commit
b61e190df3
6 files changed
+217
-66
No files matched your search
@@ -0,0 +1,108 @@
|
||||
"""Build a Daytona snapshot preloaded with the artifact-render libraries.
|
||||
|
||||
The Daytona managed sandbox backend (``SANDBOX_BACKEND=daytona``) creates each
|
||||
session from a snapshot. The default snapshot is a plain Python image, so the
|
||||
``artifact`` tool's renderers — which ``import`` ``python-pptx`` / ``python-docx``
|
||||
/ ``openpyxl`` / ``reportlab`` inside the sandbox — fail with
|
||||
``render failed: ExecutionError``. This script bakes those libraries into a
|
||||
snapshot once; point ``DAYTONA_SNAPSHOT`` at its name to fix rendering on Daytona.
|
||||
|
||||
Usage::
|
||||
|
||||
# Reads DAYTONA_API_KEY / DAYTONA_API_URL / DAYTONA_TARGET from .env (settings):
|
||||
python scripts/build_daytona_snapshot.py
|
||||
python scripts/build_daytona_snapshot.py --name docsgpt-artifacts-py312 --python 3.12
|
||||
|
||||
Then set in .env::
|
||||
|
||||
DAYTONA_SNAPSHOT=docsgpt-artifacts-py312
|
||||
|
||||
Keep the pins in sync with the backend venv (python-pptx / openpyxl / lxml /
|
||||
pillow are in application/requirements.txt; python-docx and reportlab arrive
|
||||
transitively) so the Daytona render output matches the Jupyter-backend output.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
# Render libraries imported by the artifact tool's renderers, pinned to the
|
||||
# versions installed in the backend venv as of this writing.
|
||||
RENDER_PINS = [
|
||||
"python-pptx==1.0.2",
|
||||
"python-docx==1.2.0",
|
||||
"openpyxl==3.1.5",
|
||||
"reportlab==4.5.1",
|
||||
"lxml==6.0.2",
|
||||
"pillow==11.3.0",
|
||||
]
|
||||
|
||||
DEFAULT_NAME = "docsgpt-artifacts-py312"
|
||||
DEFAULT_PYTHON = "3.12"
|
||||
|
||||
|
||||
def _parse_args(argv: list[str]) -> argparse.Namespace:
|
||||
"""Parse CLI arguments for the snapshot name and Python series."""
|
||||
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
parser.add_argument("--name", default=DEFAULT_NAME, help="snapshot name (default: %(default)s)")
|
||||
parser.add_argument("--python", default=DEFAULT_PYTHON, help="Python series, e.g. 3.12")
|
||||
parser.add_argument(
|
||||
"--force", action="store_true", help="rebuild even if a snapshot with that name exists"
|
||||
)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
"""Build (or skip) the snapshot and print the value to set as DAYTONA_SNAPSHOT."""
|
||||
args = _parse_args(argv)
|
||||
|
||||
from application.core.settings import settings
|
||||
|
||||
if not settings.DAYTONA_API_KEY:
|
||||
print("DAYTONA_API_KEY is not set (check .env).", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
from daytona import (
|
||||
CreateSnapshotParams,
|
||||
Daytona,
|
||||
DaytonaConfig,
|
||||
DaytonaConflictError,
|
||||
Image,
|
||||
)
|
||||
|
||||
cfg: dict[str, object] = {"api_key": settings.DAYTONA_API_KEY}
|
||||
if settings.DAYTONA_API_URL:
|
||||
cfg["api_url"] = settings.DAYTONA_API_URL
|
||||
if settings.DAYTONA_TARGET:
|
||||
cfg["target"] = settings.DAYTONA_TARGET
|
||||
client = Daytona(DaytonaConfig(**cfg))
|
||||
|
||||
if not args.force:
|
||||
try:
|
||||
existing = client.snapshot.get(args.name)
|
||||
print(f"snapshot {args.name!r} already exists (state={getattr(existing, 'state', '?')}).")
|
||||
print(f"set DAYTONA_SNAPSHOT={args.name}")
|
||||
return 0
|
||||
except Exception as exc: # noqa: BLE001 - "not found" is the happy path; build it
|
||||
if type(exc).__name__ != "DaytonaNotFoundError" and "not found" not in str(exc).lower():
|
||||
print(f"warning: get({args.name!r}) probe: {type(exc).__name__}: {exc}", file=sys.stderr)
|
||||
|
||||
image = Image.debian_slim(args.python).pip_install(RENDER_PINS)
|
||||
print(f"building snapshot {args.name!r} (python {args.python}) with: {', '.join(RENDER_PINS)}")
|
||||
print("--- build logs ---")
|
||||
try:
|
||||
snap = client.snapshot.create(
|
||||
CreateSnapshotParams(name=args.name, image=image), on_logs=print, timeout=600
|
||||
)
|
||||
except DaytonaConflictError:
|
||||
print(f"snapshot {args.name!r} already exists (conflict) — reuse it or pass --force a new name.")
|
||||
return 0
|
||||
print("--- created ---")
|
||||
print(f"name={getattr(snap, 'name', args.name)} state={getattr(snap, 'state', '?')}")
|
||||
print(f"\nNow set in .env:\n DAYTONA_SNAPSHOT={args.name}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
Reference in new issue
Block a user