Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- openenv_repl.egg-info/PKG-INFO +1 -0
- openenv_repl.egg-info/SOURCES.txt +9 -0
- openenv_repl.egg-info/requires.txt +1 -0
- pyproject.toml +2 -0
- server/gradio_ui.py +61 -2
- uv.lock +14 -0
openenv_repl.egg-info/PKG-INFO
CHANGED
|
@@ -11,6 +11,7 @@ Requires-Dist: requests>=2.31.0
|
|
| 11 |
Requires-Dist: smolagents<2,>=1.22.0
|
| 12 |
Requires-Dist: huggingface_hub>=0.20.0
|
| 13 |
Requires-Dist: gradio>=4.0.0
|
|
|
|
| 14 |
Provides-Extra: dev
|
| 15 |
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
| 16 |
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
|
|
| 11 |
Requires-Dist: smolagents<2,>=1.22.0
|
| 12 |
Requires-Dist: huggingface_hub>=0.20.0
|
| 13 |
Requires-Dist: gradio>=4.0.0
|
| 14 |
+
Requires-Dist: pypdf>=4.0.0
|
| 15 |
Provides-Extra: dev
|
| 16 |
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
| 17 |
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
openenv_repl.egg-info/SOURCES.txt
CHANGED
|
@@ -1,5 +1,14 @@
|
|
| 1 |
README.md
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
pyproject.toml
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
./__init__.py
|
| 4 |
./client.py
|
| 5 |
./local.py
|
|
|
|
| 1 |
README.md
|
| 2 |
+
__init__.py
|
| 3 |
+
client.py
|
| 4 |
+
local.py
|
| 5 |
+
models.py
|
| 6 |
+
prompts.py
|
| 7 |
pyproject.toml
|
| 8 |
+
recursive_backends.py
|
| 9 |
+
recursive_controller.py
|
| 10 |
+
rubrics.py
|
| 11 |
+
runner.py
|
| 12 |
./__init__.py
|
| 13 |
./client.py
|
| 14 |
./local.py
|
openenv_repl.egg-info/requires.txt
CHANGED
|
@@ -6,6 +6,7 @@ requests>=2.31.0
|
|
| 6 |
smolagents<2,>=1.22.0
|
| 7 |
huggingface_hub>=0.20.0
|
| 8 |
gradio>=4.0.0
|
|
|
|
| 9 |
|
| 10 |
[dev]
|
| 11 |
pytest>=9.0.3
|
|
|
|
| 6 |
smolagents<2,>=1.22.0
|
| 7 |
huggingface_hub>=0.20.0
|
| 8 |
gradio>=4.0.0
|
| 9 |
+
pypdf>=4.0.0
|
| 10 |
|
| 11 |
[dev]
|
| 12 |
pytest>=9.0.3
|
pyproject.toml
CHANGED
|
@@ -26,6 +26,8 @@ dependencies = [
|
|
| 26 |
"huggingface_hub>=0.20.0",
|
| 27 |
# REPL custom Gradio tab on /web
|
| 28 |
"gradio>=4.0.0",
|
|
|
|
|
|
|
| 29 |
]
|
| 30 |
|
| 31 |
[project.optional-dependencies]
|
|
|
|
| 26 |
"huggingface_hub>=0.20.0",
|
| 27 |
# REPL custom Gradio tab on /web
|
| 28 |
"gradio>=4.0.0",
|
| 29 |
+
# Document upload support in the Gradio tab (server-side only, not in the sandbox)
|
| 30 |
+
"pypdf>=4.0.0",
|
| 31 |
]
|
| 32 |
|
| 33 |
[project.optional-dependencies]
|
server/gradio_ui.py
CHANGED
|
@@ -8,12 +8,19 @@
|
|
| 8 |
|
| 9 |
from __future__ import annotations
|
| 10 |
|
|
|
|
| 11 |
import json
|
|
|
|
| 12 |
from typing import Any, Dict, List, Optional
|
| 13 |
|
| 14 |
import gradio as gr
|
| 15 |
from openenv.core.env_server.types import EnvironmentMetadata
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
# Pre-canned demos for the "Load example" dropdown. Each entry is
|
| 19 |
# (label, context, task_prompt, code) and showcases one of the three
|
|
@@ -104,6 +111,33 @@ Pass **Expected answer** at Reset to enable rubric-based scoring: the observatio
|
|
| 104 |
"""
|
| 105 |
|
| 106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
def _code_block(title: str, content: str) -> str:
|
| 108 |
if not content:
|
| 109 |
return ""
|
|
@@ -229,11 +263,26 @@ def build_repl_gradio_app(
|
|
| 229 |
ctx, task, code, expected = _EXAMPLES[label]
|
| 230 |
return ctx, task, code, expected
|
| 231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
with gr.Blocks(title=f"{title} - REPL") as blocks:
|
| 233 |
gr.Markdown(
|
| 234 |
"# REPL Control Panel\n\n"
|
| 235 |
-
"Recursive Language Model REPL. Pick a demo from **💡 Load example**
|
| 236 |
-
"
|
|
|
|
| 237 |
"*Injected helpers: `context`, `llm_query`, `llm_query_batched`, "
|
| 238 |
"`rlm_query`, `rlm_query_batched`, `FINAL(...)`, `FINAL_VAR(...)`.*"
|
| 239 |
)
|
|
@@ -247,6 +296,11 @@ def build_repl_gradio_app(
|
|
| 247 |
value=None,
|
| 248 |
info="Pick a pre-canned demo to fill Context, Task Prompt, and Python Code.",
|
| 249 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
context = gr.Textbox(
|
| 251 |
label="Context",
|
| 252 |
placeholder="Problem context or source text...",
|
|
@@ -338,5 +392,10 @@ def build_repl_gradio_app(
|
|
| 338 |
inputs=[example_dropdown],
|
| 339 |
outputs=[context, task_prompt, code, expected_answer],
|
| 340 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 341 |
|
| 342 |
return blocks
|
|
|
|
| 8 |
|
| 9 |
from __future__ import annotations
|
| 10 |
|
| 11 |
+
import io
|
| 12 |
import json
|
| 13 |
+
from pathlib import Path
|
| 14 |
from typing import Any, Dict, List, Optional
|
| 15 |
|
| 16 |
import gradio as gr
|
| 17 |
from openenv.core.env_server.types import EnvironmentMetadata
|
| 18 |
|
| 19 |
+
try:
|
| 20 |
+
import pypdf
|
| 21 |
+
except ImportError: # pragma: no cover - optional dep
|
| 22 |
+
pypdf = None # type: ignore[assignment]
|
| 23 |
+
|
| 24 |
|
| 25 |
# Pre-canned demos for the "Load example" dropdown. Each entry is
|
| 26 |
# (label, context, task_prompt, code) and showcases one of the three
|
|
|
|
| 111 |
"""
|
| 112 |
|
| 113 |
|
| 114 |
+
def _extract_text_from_upload(file_path: str) -> str:
|
| 115 |
+
"""Read a .txt or .pdf upload from disk and return its text content.
|
| 116 |
+
|
| 117 |
+
Runs in the Gradio server process (outside the smolagents sandbox),
|
| 118 |
+
so it can use `pypdf` and the filesystem without triggering the
|
| 119 |
+
REPL's import restrictions.
|
| 120 |
+
"""
|
| 121 |
+
path = Path(file_path)
|
| 122 |
+
suffix = path.suffix.lower()
|
| 123 |
+
if suffix == ".txt":
|
| 124 |
+
return path.read_text(encoding="utf-8", errors="replace")
|
| 125 |
+
if suffix == ".pdf":
|
| 126 |
+
if pypdf is None:
|
| 127 |
+
return "[pypdf is not installed in this deployment; cannot parse PDFs.]"
|
| 128 |
+
with path.open("rb") as fh:
|
| 129 |
+
reader = pypdf.PdfReader(io.BytesIO(fh.read()))
|
| 130 |
+
pages = []
|
| 131 |
+
for page in reader.pages:
|
| 132 |
+
try:
|
| 133 |
+
pages.append(page.extract_text() or "")
|
| 134 |
+
except Exception as exc: # pypdf can raise on malformed PDFs
|
| 135 |
+
pages.append(f"[page extraction failed: {exc}]")
|
| 136 |
+
text = "\n\n".join(pages).strip()
|
| 137 |
+
return text or "[No extractable text — PDF may be image-only.]"
|
| 138 |
+
return f"[Unsupported file type: {suffix}. Use .txt or .pdf.]"
|
| 139 |
+
|
| 140 |
+
|
| 141 |
def _code_block(title: str, content: str) -> str:
|
| 142 |
if not content:
|
| 143 |
return ""
|
|
|
|
| 263 |
ctx, task, code, expected = _EXAMPLES[label]
|
| 264 |
return ctx, task, code, expected
|
| 265 |
|
| 266 |
+
def load_uploaded_document(file_obj):
|
| 267 |
+
if file_obj is None:
|
| 268 |
+
return gr.update(), gr.update()
|
| 269 |
+
file_path = (
|
| 270 |
+
file_obj if isinstance(file_obj, str) else getattr(file_obj, "name", None)
|
| 271 |
+
)
|
| 272 |
+
if not file_path:
|
| 273 |
+
return gr.update(), "Upload error: could not read file path."
|
| 274 |
+
try:
|
| 275 |
+
text = _extract_text_from_upload(file_path)
|
| 276 |
+
except Exception as exc:
|
| 277 |
+
return gr.update(), f"Upload error: {exc}"
|
| 278 |
+
return text, f"Loaded {Path(file_path).name} ({len(text)} chars) into Context."
|
| 279 |
+
|
| 280 |
with gr.Blocks(title=f"{title} - REPL") as blocks:
|
| 281 |
gr.Markdown(
|
| 282 |
"# REPL Control Panel\n\n"
|
| 283 |
+
"Recursive Language Model REPL. Pick a demo from **💡 Load example**, or drop "
|
| 284 |
+
"your own **text file / PDF**, paste your **Hugging Face Token**, "
|
| 285 |
+
"click **🔁 Reset episode**, then **▶ Run**.\n\n"
|
| 286 |
"*Injected helpers: `context`, `llm_query`, `llm_query_batched`, "
|
| 287 |
"`rlm_query`, `rlm_query_batched`, `FINAL(...)`, `FINAL_VAR(...)`.*"
|
| 288 |
)
|
|
|
|
| 296 |
value=None,
|
| 297 |
info="Pick a pre-canned demo to fill Context, Task Prompt, and Python Code.",
|
| 298 |
)
|
| 299 |
+
upload = gr.File(
|
| 300 |
+
label="📎 Drop a text file or PDF here",
|
| 301 |
+
file_types=[".txt", ".pdf"],
|
| 302 |
+
type="filepath",
|
| 303 |
+
)
|
| 304 |
context = gr.Textbox(
|
| 305 |
label="Context",
|
| 306 |
placeholder="Problem context or source text...",
|
|
|
|
| 392 |
inputs=[example_dropdown],
|
| 393 |
outputs=[context, task_prompt, code, expected_answer],
|
| 394 |
)
|
| 395 |
+
upload.change(
|
| 396 |
+
fn=load_uploaded_document,
|
| 397 |
+
inputs=[upload],
|
| 398 |
+
outputs=[context, status],
|
| 399 |
+
)
|
| 400 |
|
| 401 |
return blocks
|
uv.lock
CHANGED
|
@@ -1608,6 +1608,7 @@ dependencies = [
|
|
| 1608 |
{ name = "huggingface-hub" },
|
| 1609 |
{ name = "openenv-core", extra = ["core"] },
|
| 1610 |
{ name = "pydantic" },
|
|
|
|
| 1611 |
{ name = "requests" },
|
| 1612 |
{ name = "smolagents" },
|
| 1613 |
{ name = "uvicorn" },
|
|
@@ -1626,6 +1627,7 @@ requires-dist = [
|
|
| 1626 |
{ name = "huggingface-hub", specifier = ">=0.20.0" },
|
| 1627 |
{ name = "openenv-core", extras = ["core"], specifier = ">=0.2.3" },
|
| 1628 |
{ name = "pydantic", specifier = ">=2.0.0" },
|
|
|
|
| 1629 |
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=9.0.3" },
|
| 1630 |
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0.0" },
|
| 1631 |
{ name = "requests", specifier = ">=2.31.0" },
|
|
@@ -2218,6 +2220,18 @@ crypto = [
|
|
| 2218 |
{ name = "cryptography" },
|
| 2219 |
]
|
| 2220 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2221 |
[[package]]
|
| 2222 |
name = "pyperclip"
|
| 2223 |
version = "1.11.0"
|
|
|
|
| 1608 |
{ name = "huggingface-hub" },
|
| 1609 |
{ name = "openenv-core", extra = ["core"] },
|
| 1610 |
{ name = "pydantic" },
|
| 1611 |
+
{ name = "pypdf" },
|
| 1612 |
{ name = "requests" },
|
| 1613 |
{ name = "smolagents" },
|
| 1614 |
{ name = "uvicorn" },
|
|
|
|
| 1627 |
{ name = "huggingface-hub", specifier = ">=0.20.0" },
|
| 1628 |
{ name = "openenv-core", extras = ["core"], specifier = ">=0.2.3" },
|
| 1629 |
{ name = "pydantic", specifier = ">=2.0.0" },
|
| 1630 |
+
{ name = "pypdf", specifier = ">=4.0.0" },
|
| 1631 |
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=9.0.3" },
|
| 1632 |
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0.0" },
|
| 1633 |
{ name = "requests", specifier = ">=2.31.0" },
|
|
|
|
| 2220 |
{ name = "cryptography" },
|
| 2221 |
]
|
| 2222 |
|
| 2223 |
+
[[package]]
|
| 2224 |
+
name = "pypdf"
|
| 2225 |
+
version = "6.10.2"
|
| 2226 |
+
source = { registry = "https://pypi.org/simple" }
|
| 2227 |
+
dependencies = [
|
| 2228 |
+
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
| 2229 |
+
]
|
| 2230 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7b/3f/9f2167401c2e94833ca3b69535bad89e533b5de75fefe4197a2c224baec2/pypdf-6.10.2.tar.gz", hash = "sha256:7d09ce108eff6bf67465d461b6ef352dcb8d84f7a91befc02f904455c6eea11d", size = 5315679, upload-time = "2026-04-15T16:37:36.978Z" }
|
| 2231 |
+
wheels = [
|
| 2232 |
+
{ url = "https://files.pythonhosted.org/packages/0c/d6/1d5c60cc17bbdf37c1552d9c03862fc6d32c5836732a0415b2d637edc2d0/pypdf-6.10.2-py3-none-any.whl", hash = "sha256:aa53be9826655b51c96741e5d7983ca224d898ac0a77896e64636810517624aa", size = 336308, upload-time = "2026-04-15T16:37:34.851Z" },
|
| 2233 |
+
]
|
| 2234 |
+
|
| 2235 |
[[package]]
|
| 2236 |
name = "pyperclip"
|
| 2237 |
version = "1.11.0"
|