Skip to content

Add remote Articulation backend to Gradio - #552

Merged
skywhite1024 merged 9 commits into
mainfrom
ljd/gradio-update-articulation
Aug 27, 2026
Merged

Add remote Articulation backend to Gradio#552
skywhite1024 merged 9 commits into
mainfrom
ljd/gradio-update-articulation

Conversation

@skywhite1024

@skywhite1024skywhite1024 commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR adds a dependency-free articulation-server client to the GenSim Gradio workspace and makes Remote server the default Articulation generation backend. The existing Local Codex Articraft workflow, configuration, outputs, and interactive viewer remain available through an explicit UI selector.

Remote generation supports text and optional reference images, asynchronous status polling, atomic USDC downloads, clear terminal errors, bounded timeouts, and session-scoped cancellation for Reset and replacement requests. It does not send authentication headers and never silently falls back to Local Codex.

After a remote USDC download, Gradio now starts EmbodiChain's native preview-asset --viser command in the current Gradio Python environment and embeds the interactive viewer. A viewer startup failure does not discard the successfully generated USDC and falls back to the result summary. The Local Codex Articraft viewer path is unchanged.

The deployment configuration example, architecture notes, and public API reference are updated accordingly.

Dependencies: none.

Issue: none.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (non-breaking change which improves existing functionality)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (existing functionality will not work without user modification)
  • Documentation update

Screenshots

Not included. The focused Gradio panel construction, backend routing, viewer command, and fallback behavior are covered by automated tests.

Validation

  • conda run -n embodichain040 black --check --diff --color ./ (815 files unchanged)
  • PYTHONPATH="$PWD" conda run -n embodichain040 python docs/scripts/check_api_docs.py (1702/1702 exports documented)
  • PYTHONPATH="$PWD" conda run -n embodichain040 python -m pytest tests/gen_sim/gradio_ui -q (65 passed)
  • Manual smoke test using an existing remote USDC: Viser loaded the articulation, enabled joint controls, and returned HTTP 200
  • git diff --check

Checklist

  • I have run the black . formatting gate.
  • I have made corresponding changes to the documentation.
  • Public API changes are reflected in the API docs.
  • I have added tests that prove the feature works.
  • Dependencies have not changed.

Add an unauthenticated articulation-server client and make it the default Gradio backend while preserving the existing Local Codex workflow. Cover remote polling, downloads, failures, timeouts, cancellation, and backend selection with focused tests.
CopilotAI lite review requested due to automatic review settings August 25, 2026 16:23
@skywhite1024skywhite1024 added enhancement New feature or request visualization Features or functions for visualization with the simulation assets Related to simulation assets (robot, CAD, material, etc) labels Aug 25, 2026
@greptile-apps

greptile-appsBot commented Aug 25, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds a dependency-free remote Articulation backend to the Gradio workspace while retaining Local Codex as an explicit alternative.

  • Adds remote submission, polling, cancellation, artifact download, and Viser-preview behavior.
  • Defers and validates remote timeout settings only when the remote backend is selected.
  • Updates deployment configuration, architecture documentation, public API references, and focused tests.

Confidence Score: 4/5

The PR is not yet safe to merge because an in-flight status request can delay timeout reporting and cancellation beyond the configured task deadline.

The polling loop checks its deadline before issuing a blocking status request, but that request retains the independent full HTTP timeout, leaving the previously reported deadline-overrun behavior outstanding.

Files Needing Attention: embodichain/gen_sim/gradio_ui/app_articraft.py and embodichain/gen_sim/gradio_ui/_articulation_server_client.py

Important Files Changed

FilenameOverview
embodichain/gen_sim/gradio_ui/app_articraft.pyAdds backend routing, remote task lifecycle management, bounded polling sleep, artifact handling, and Viser startup; the existing status-request deadline issue remains unresolved.
embodichain/gen_sim/gradio_ui/_articulation_server_client.pyImplements validated dependency-free HTTP operations for health checks, submission, status, cancellation, and atomic artifact downloads.
embodichain/gen_sim/gradio_ui/app_env.pyAdds remote server settings as raw strings so malformed optional values do not abort module import or Local Codex startup.
tests/gen_sim/gradio_ui/test_app_articraft.pyCovers backend routing, timing validation, cancellation, deadline-bounded sleep, download handling, and preview fallback behavior.
tests/gen_sim/gradio_ui/test_articulation_server_client.pyExercises remote client request validation, response handling, and artifact download behavior.

Sequence Diagram

sequenceDiagram
participant User
participant Gradio
participant Server as Articulation Server
participant Viser
User->>Gradio: Generate prompt + optional image
Gradio->>Server: Submit generation request
Server-->>Gradio: request_id
loop Until terminal state or task deadline
Gradio->>Server: Request task status
Server-->>Gradio: Current status
end
Gradio->>Server: Download completed USDC
Server-->>Gradio: USDC artifact
Gradio->>Viser: Start preview-asset process
Viser-->>User: Interactive articulation preview
Loading

Reviews (9): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment threadembodichain/gen_sim/gradio_ui/app_env.py Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a dependency-free HTTP client for an articulation-server and wires it into the GenSim Gradio Articulation (Articraft) panel, making Remote server the default backend while preserving the existing Local Codex (Articraft + Codex CLI) workflow behind an explicit UI selector.

Changes:

  • Add ArticulationServerClient (urllib-based) with submit/status/cancel and atomic artifact download support.
  • Update app_articraft Gradio panel to route generation/configuration through either Remote server (default) or Local Codex, including session-scoped remote cancellation on reset/replacement.
  • Extend configuration + docs + tests to cover the new backend, environment variables, and routing behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
tests/gen_sim/gradio_ui/test_articulation_server_client.pyNew unit tests validating HTTP request construction, auth header absence, and atomic downloads for the server client.
tests/gen_sim/gradio_ui/test_app_articraft.pyExpanded callback-level tests for backend selection, polling/download behavior, timeout/cancellation, and replacement semantics.
embodichain/gen_sim/gradio_ui/gradio_visualization_architecture.mdDocs updated to describe Remote server flow, env vars, and reset semantics.
embodichain/gen_sim/gradio_ui/app_env.pyAdds env-backed configuration for remote server base URL, request timeout, polling interval, and task timeout.
embodichain/gen_sim/gradio_ui/app_articraft.pyAdds backend selector + remote orchestration, status polling, cancellation registry, and updated panel wiring.
embodichain/gen_sim/gradio_ui/_articulation_server_client.pyNew dependency-free articulation-server client implementation.
embodichain/gen_sim/.env.exampleDocuments and provides example remote server environment variables.
docs/source/api_reference/public_api.rstDocuments newly exported app_env settings in the public API reference.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadembodichain/gen_sim/gradio_ui/app_articraft.py
Comment threadembodichain/gen_sim/gradio_ui/app_articraft.py
Comment threadembodichain/gen_sim/gradio_ui/app_env.py Outdated
Comment threadembodichain/gen_sim/gradio_ui/_articulation_server_client.py
Require finite positive values for HTTP, task, and polling timeouts so invalid nan or infinity settings cannot bypass bounded remote generation behavior.
CopilotAI review requested due to automatic review settings August 25, 2026 16:31

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (4)

Previously missed (3) — in code that hasn't changed since the last review.

embodichain/gen_sim/gradio_ui/_articulation_server_client.py:128

  • Artifact downloads currently reuse the default Accept: application/json header from _open(). If the server performs content negotiation, this can cause the USDC download to return JSON or an error instead of the binary artifact.
 with (
self._open("GET", relative_url) as response,
temporary.open("wb") as output,

embodichain/gen_sim/.env.example:42

  • .env.example defaults the remote server URL to a private LAN IP. For an example file, a localhost default is less surprising and matches typical local deployment docs.
# Remote Articulation generation is the default UI mode.
ARTICULATION_SERVER_BASE_URL="http://192.168.3.23:18688"
ARTICULATION_SERVER_TIMEOUT_S=30
ARTICULATION_SERVER_TASK_TIMEOUT_S=7200
ARTICULATION_SERVER_POLL_INTERVAL_S=1

embodichain/gen_sim/gradio_ui/gradio_visualization_architecture.md:66

  • The architecture doc uses a private LAN IP as the default ARTICULATION_SERVER_BASE_URL. Using 127.0.0.1 (or wording it as an example) avoids implying this is a universally valid default.
| `ARTICULATION_SERVER_BASE_URL` | `http://192.168.3.23:18688` | 默认 Remote server 的 HTTP(S) 地址。 |
| `ARTICULATION_SERVER_TIMEOUT_S` | `30` | 单次 HTTP 请求超时。 |
| `ARTICULATION_SERVER_TASK_TIMEOUT_S` | `7200` | 服务端生成任务总等待时间。 |

embodichain/gen_sim/gradio_ui/app_env.py:99

  • The default ARTICULATION_SERVER_BASE_URL is hard-coded to a private LAN IP (192.168.3.23), which will fail for most users and can cause confusing defaults when Remote server is the UI default. Prefer a local default (or require explicit configuration).
ARTICULATION_SERVER_BASE_URL = _getenv(
"ARTICULATION_SERVER_BASE_URL", "http://192.168.3.23:18688"
)

Bound remote task logs, discard locally invalid cancellation IDs, require explicit server endpoint configuration, use artifact-appropriate Accept headers, and preserve HTTP error wrapping when response bodies are unavailable.
CopilotAI review requested due to automatic review settings August 25, 2026 17:08
@skywhite1024

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the Copilot review feedback in faaac710:

  • discard locally invalid cancellation IDs instead of permanently restoring them;
  • cap remote per-session logs at 300 lines;
  • require explicit ARTICULATION_SERVER_BASE_URL configuration and remove the repository-specific LAN default from code/examples/docs;
  • preserve ArticulationServerError wrapping when an HTTPError has no readable body;
  • use Accept: */* for artifact downloads.

Validation: pytest tests/gen_sim/gradio_ui -q (56 passed), full Black gate (815 files unchanged), API docs coverage (1702/1702), and git diff --check.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment threadembodichain/gen_sim/gradio_ui/_articulation_server_client.py Outdated
Limit remote HTTP error detail reads and rendered messages, add regression coverage for oversized JSON errors, and align the architecture summary with Remote server and Local Codex output behavior.
CopilotAI review requested due to automatic review settings August 25, 2026 17:21

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment threadembodichain/gen_sim/gradio_ui/_articulation_server_client.py Outdated
Treat empty or whitespace-only remote artifact paths as missing so the client cannot download the service root into a USDC destination. Add focused request-count regression coverage.
CopilotAI review requested due to automatic review settings August 25, 2026 17:33
Comment threadembodichain/gen_sim/gradio_ui/app_env.py Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment on lines +117 to +122
relative_url = artifacts.get(artifact) if isinstance(artifacts, dict) else None
if not isinstance(relative_url, str) or not relative_url.strip():
raise ArticulationServerError(
f"task {request_id} has no artifact named {artifact!r}"
)

Keep optional articulation-server timing values unparsed during application import, then validate them only when the Remote server backend is checked or used so malformed remote settings cannot block Local Codex startup.
CopilotAI review requested due to automatic review settings August 25, 2026 17:43
Comment threadembodichain/gen_sim/gradio_ui/app_articraft.py Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

embodichain/gen_sim/gradio_ui/app_articraft.py:861

  • Hard-coded 300 here duplicates _SERVER_LOG_LIMIT and can drift if the limit changes. Prefer slicing by the constant so the cap is defined in one place.
 "**Remote Articulation status check failed.**\n\n"
f"- {detail}\n"
"- The request was not retried with Local Codex.",
"\n".join(log_lines[-300:]),
"",

Check the remote task deadline before each status request and cap each polling sleep by the remaining task time so long polling intervals cannot delay timeout cancellation.
CopilotAI review requested due to automatic review settings August 25, 2026 17:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Comment threadembodichain/gen_sim/gradio_ui/app_articraft.py
Launch EmbodiChain's native Viser preview from the current Gradio Python environment after downloading a remote USDC artifact. Preserve the USDC result when preview startup fails, and cover the command, lifecycle, fallback, and documentation.
CopilotAI review requested due to automatic review settings August 26, 2026 11:01
@skywhite1024

Copy link
Copy Markdown
CollaboratorAuthor

Updated in commit 14a4f95d: remote Articulation results now launch EmbodiChain's native Viser preview from the current Gradio Python environment. The downloaded USDC remains available if Viser startup fails, while the Local Codex/Articraft viewer path is unchanged.\n\nValidation: full Gradio UI suite 65 passed; Black 815 files unchanged; API docs 1702/1702; manual existing-USDC Viser smoke test returned HTTP 200 with articulation joint controls enabled.

)
return
try:
task = client.status(request_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1Status request exceeds deadline

When a status request begins shortly before the task deadline, client.status() uses the full independent HTTP timeout, causing timeout reporting and cancellation to occur up to one request timeout after ARTICULATION_SERVER_TASK_TIMEOUT_S expires.

Fix in CodexFix in Claude Code

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment on lines +686 to +690
def _select_available_viser_port() -> int:
"""Reserve an ephemeral loopback port for a session-owned Viser preview."""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listener:
listener.bind(("127.0.0.1", 0))
return int(listener.getsockname()[1])
Comment on lines +942 to +946
"**Remote Articulation request timed out and cancellation was requested.**\n\n"
f"- Request: `{request_id}`\n"
"- The request was not retried with Local Codex.",
"\n".join(log_lines[-300:]),
"",
CopilotAI review requested due to automatic review settings August 27, 2026 02:27

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

embodichain/gen_sim/gradio_ui/_articulation_server_client.py:121

  • download() validates relative_url.strip() but then uses the unstripped string when constructing the request. If the server returns a relative URL with leading/trailing whitespace (e.g. " /tasks/..."), this can produce an invalid request URL and fail downloads even though the artifact is present.
 relative_url = artifacts.get(artifact) if isinstance(artifacts, dict) else None
if not isinstance(relative_url, str) or not relative_url.strip():
raise ArticulationServerError(
f"task {request_id} has no artifact named {artifact!r}"
)

@skywhite1024
skywhite1024 merged commit a783488 into mainAug 27, 2026
6 checks passed
@skywhite1024
skywhite1024 deleted the ljd/gradio-update-articulation branch August 27, 2026 04:49
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

assetsRelated to simulation assets (robot, CAD, material, etc)enhancementNew feature or requestvisualizationFeatures or functions for visualization with the simulation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@skywhite1024