Spaces:
Running on Zero
Running on Zero
update
Browse files- app.py +2 -2
- app_style.py +1 -1
- embodied_gen/utils/gpt_clients.py +240 -25
- embodied_gen/utils/gpt_config.yaml +8 -1
- embodied_gen/utils/tags.py +1 -1
app.py
CHANGED
|
@@ -818,13 +818,13 @@ with gr.Blocks(
|
|
| 818 |
<a href="https://horizonrobotics.github.io/EmbodiedGen">
|
| 819 |
<img alt="📖 Documentation" src="https://img.shields.io/badge/📖-Documentation-blue">
|
| 820 |
</a>
|
| 821 |
-
<a href="https://arxiv.org/abs/
|
| 822 |
<img alt="📄 arXiv" src="https://img.shields.io/badge/📄-arXiv-b31b1b">
|
| 823 |
</a>
|
| 824 |
<a href="https://github.com/HorizonRobotics/EmbodiedGen">
|
| 825 |
<img alt="💻 GitHub" src="https://img.shields.io/badge/GitHub-000000?logo=github">
|
| 826 |
</a>
|
| 827 |
-
<a href="https://
|
| 828 |
<img alt="🎥 Video" src="https://img.shields.io/badge/🎥-Video-red">
|
| 829 |
</a>
|
| 830 |
</p>
|
|
|
|
| 818 |
<a href="https://horizonrobotics.github.io/EmbodiedGen">
|
| 819 |
<img alt="📖 Documentation" src="https://img.shields.io/badge/📖-Documentation-blue">
|
| 820 |
</a>
|
| 821 |
+
<a href="https://arxiv.org/abs/2607.07459">
|
| 822 |
<img alt="📄 arXiv" src="https://img.shields.io/badge/📄-arXiv-b31b1b">
|
| 823 |
</a>
|
| 824 |
<a href="https://github.com/HorizonRobotics/EmbodiedGen">
|
| 825 |
<img alt="💻 GitHub" src="https://img.shields.io/badge/GitHub-000000?logo=github">
|
| 826 |
</a>
|
| 827 |
+
<a href="https://youtu.be/MIkJJSVM8L4">
|
| 828 |
<img alt="🎥 Video" src="https://img.shields.io/badge/🎥-Video-red">
|
| 829 |
</a>
|
| 830 |
</p>
|
app_style.py
CHANGED
|
@@ -15,7 +15,7 @@
|
|
| 15 |
# permissions and limitations under the License.
|
| 16 |
|
| 17 |
from gradio.themes import Soft
|
| 18 |
-
from gradio.themes.utils.colors import gray,
|
| 19 |
|
| 20 |
lighting_css = """
|
| 21 |
<style>
|
|
|
|
| 15 |
# permissions and limitations under the License.
|
| 16 |
|
| 17 |
from gradio.themes import Soft
|
| 18 |
+
from gradio.themes.utils.colors import gray, stone
|
| 19 |
|
| 20 |
lighting_css = """
|
| 21 |
<style>
|
embodied_gen/utils/gpt_clients.py
CHANGED
|
@@ -16,10 +16,15 @@
|
|
| 16 |
|
| 17 |
|
| 18 |
import base64
|
|
|
|
| 19 |
import logging
|
| 20 |
import math
|
| 21 |
import os
|
|
|
|
|
|
|
|
|
|
| 22 |
from io import BytesIO
|
|
|
|
| 23 |
from typing import Optional
|
| 24 |
|
| 25 |
import openai
|
|
@@ -43,12 +48,55 @@ __all__ = [
|
|
| 43 |
"GPTclient",
|
| 44 |
]
|
| 45 |
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
DEFAULT_GPT_TIMEOUT = float(os.environ.get("GPT_TIMEOUT", 120))
|
| 49 |
# GPT-5.x counts reasoning tokens against this cap, so it must be high
|
| 50 |
# enough to leave room for both reasoning and the visible reply.
|
| 51 |
GPT5_DEFAULT_MAX_COMPLETION_TOKENS = 8192
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
|
| 54 |
def combine_images_to_grid(
|
|
@@ -84,7 +132,7 @@ def combine_images_to_grid(
|
|
| 84 |
|
| 85 |
|
| 86 |
class GPTclient:
|
| 87 |
-
"""A client to interact with GPT models via
|
| 88 |
|
| 89 |
Supports text and image prompts, connection checking, and configurable parameters.
|
| 90 |
|
|
@@ -96,6 +144,9 @@ class GPTclient:
|
|
| 96 |
check_connection (bool, optional): Whether to check API connection.
|
| 97 |
verbose (bool, optional): Enable verbose logging.
|
| 98 |
timeout (float, optional): Max seconds for a single GPT request.
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
Example:
|
| 101 |
```sh
|
|
@@ -117,15 +168,28 @@ class GPTclient:
|
|
| 117 |
|
| 118 |
def __init__(
|
| 119 |
self,
|
| 120 |
-
endpoint: str,
|
| 121 |
-
api_key: str,
|
| 122 |
-
model_name: str = "yfb-gpt-4o",
|
| 123 |
-
api_version: str = None,
|
| 124 |
check_connection: bool = True,
|
| 125 |
verbose: bool = False,
|
| 126 |
timeout: float = DEFAULT_GPT_TIMEOUT,
|
|
|
|
| 127 |
):
|
| 128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
self.client = AzureOpenAI(
|
| 130 |
azure_endpoint=endpoint,
|
| 131 |
api_key=api_key,
|
|
@@ -151,6 +215,131 @@ class GPTclient:
|
|
| 151 |
|
| 152 |
logger.info(f"Using GPT model: {self.model_name}.")
|
| 153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
@staticmethod
|
| 155 |
def _is_gpt5_model(model_name: str) -> bool:
|
| 156 |
name = (model_name or "").lower()
|
|
@@ -168,7 +357,9 @@ class GPTclient:
|
|
| 168 |
def query(
|
| 169 |
self,
|
| 170 |
text_prompt: str,
|
| 171 |
-
image_base64: Optional[
|
|
|
|
|
|
|
| 172 |
system_role: Optional[str] = None,
|
| 173 |
params: Optional[dict] = None,
|
| 174 |
) -> Optional[str]:
|
|
@@ -186,6 +377,23 @@ class GPTclient:
|
|
| 186 |
if system_role is None:
|
| 187 |
system_role = "You are a highly knowledgeable assistant specializing in physics, engineering, and object properties." # noqa
|
| 188 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
content_user = [
|
| 190 |
{
|
| 191 |
"type": "text",
|
|
@@ -292,6 +500,20 @@ class GPTclient:
|
|
| 292 |
ConnectionError: If connection fails.
|
| 293 |
"""
|
| 294 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
probe_kwargs = dict(
|
| 296 |
messages=[
|
| 297 |
{"role": "system", "content": "You are a test system."},
|
|
@@ -314,26 +536,19 @@ class GPTclient:
|
|
| 314 |
)
|
| 315 |
|
| 316 |
|
| 317 |
-
with open(CONFIG_FILE, "r") as f:
|
| 318 |
config = yaml.safe_load(f)
|
| 319 |
|
| 320 |
-
|
| 321 |
-
agent_config = config.get(agent_type, {})
|
| 322 |
-
|
| 323 |
-
# Prefer environment variables, fallback to YAML config
|
| 324 |
-
endpoint = os.environ.get("ENDPOINT", agent_config.get("endpoint"))
|
| 325 |
-
api_key = os.environ.get("API_KEY", agent_config.get("api_key"))
|
| 326 |
-
api_version = os.environ.get("API_VERSION", agent_config.get("api_version"))
|
| 327 |
-
model_name = os.environ.get("MODEL_NAME", agent_config.get("model_name"))
|
| 328 |
-
timeout = DEFAULT_GPT_TIMEOUT
|
| 329 |
|
| 330 |
GPT_CLIENT = GPTclient(
|
| 331 |
-
endpoint=endpoint,
|
| 332 |
-
api_key=api_key,
|
| 333 |
-
api_version=api_version,
|
| 334 |
-
model_name=model_name,
|
| 335 |
check_connection=False,
|
| 336 |
-
timeout=
|
|
|
|
| 337 |
)
|
| 338 |
|
| 339 |
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
import base64
|
| 19 |
+
import json
|
| 20 |
import logging
|
| 21 |
import math
|
| 22 |
import os
|
| 23 |
+
import shutil
|
| 24 |
+
import subprocess
|
| 25 |
+
import tempfile
|
| 26 |
from io import BytesIO
|
| 27 |
+
from pathlib import Path
|
| 28 |
from typing import Optional
|
| 29 |
|
| 30 |
import openai
|
|
|
|
| 48 |
"GPTclient",
|
| 49 |
]
|
| 50 |
|
| 51 |
+
CONFIG_FILE = str(Path(__file__).with_name("gpt_config.yaml"))
|
| 52 |
+
DEFAULT_GPT_TIMEOUT = float(os.environ.get("GPT_TIMEOUT", 90))
|
|
|
|
| 53 |
# GPT-5.x counts reasoning tokens against this cap, so it must be high
|
| 54 |
# enough to leave room for both reasoning and the visible reply.
|
| 55 |
GPT5_DEFAULT_MAX_COMPLETION_TOKENS = 8192
|
| 56 |
+
_CODEX_DEFAULT_REASONING_EFFORT = "medium"
|
| 57 |
+
_CODEX_ENV_KEYS = {
|
| 58 |
+
"ALL_PROXY",
|
| 59 |
+
"CODEX_HOME",
|
| 60 |
+
"HOME",
|
| 61 |
+
"HTTPS_PROXY",
|
| 62 |
+
"HTTP_PROXY",
|
| 63 |
+
"NO_PROXY",
|
| 64 |
+
"PATH",
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def _resolve_agent_settings(
|
| 69 |
+
config: dict, environ: Optional[dict[str, str]] = None
|
| 70 |
+
) -> dict:
|
| 71 |
+
"""Resolve one provider configuration with environment overrides."""
|
| 72 |
+
environ = os.environ if environ is None else environ
|
| 73 |
+
agent_type = config["agent_type"]
|
| 74 |
+
agent_config = config.get(agent_type, {})
|
| 75 |
+
provider_override = environ.get("GPT_PROVIDER")
|
| 76 |
+
|
| 77 |
+
if provider_override is not None:
|
| 78 |
+
agent_config = {}
|
| 79 |
+
|
| 80 |
+
return {
|
| 81 |
+
"endpoint": environ.get("ENDPOINT", agent_config.get("endpoint")),
|
| 82 |
+
"api_key": environ.get("API_KEY", agent_config.get("api_key")),
|
| 83 |
+
"api_version": environ.get(
|
| 84 |
+
"API_VERSION", agent_config.get("api_version")
|
| 85 |
+
),
|
| 86 |
+
"model_name": environ.get(
|
| 87 |
+
"MODEL_NAME", agent_config.get("model_name")
|
| 88 |
+
),
|
| 89 |
+
"provider": provider_override or agent_config.get("provider"),
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def _codex_subprocess_environment() -> dict[str, str]:
|
| 94 |
+
"""Return the minimal host environment required by Codex CLI."""
|
| 95 |
+
return {
|
| 96 |
+
key: value
|
| 97 |
+
for key, value in os.environ.items()
|
| 98 |
+
if key.upper() in _CODEX_ENV_KEYS
|
| 99 |
+
}
|
| 100 |
|
| 101 |
|
| 102 |
def combine_images_to_grid(
|
|
|
|
| 132 |
|
| 133 |
|
| 134 |
class GPTclient:
|
| 135 |
+
"""A client to interact with GPT models via API or Codex CLI.
|
| 136 |
|
| 137 |
Supports text and image prompts, connection checking, and configurable parameters.
|
| 138 |
|
|
|
|
| 144 |
check_connection (bool, optional): Whether to check API connection.
|
| 145 |
verbose (bool, optional): Enable verbose logging.
|
| 146 |
timeout (float, optional): Max seconds for a single GPT request.
|
| 147 |
+
provider (str, optional): Backend provider. Use ``codex`` to reuse a
|
| 148 |
+
local Codex CLI login; otherwise the existing Azure/OpenAI-
|
| 149 |
+
compatible API selection is preserved.
|
| 150 |
|
| 151 |
Example:
|
| 152 |
```sh
|
|
|
|
| 168 |
|
| 169 |
def __init__(
|
| 170 |
self,
|
| 171 |
+
endpoint: Optional[str],
|
| 172 |
+
api_key: Optional[str],
|
| 173 |
+
model_name: Optional[str] = "yfb-gpt-4o",
|
| 174 |
+
api_version: Optional[str] = None,
|
| 175 |
check_connection: bool = True,
|
| 176 |
verbose: bool = False,
|
| 177 |
timeout: float = DEFAULT_GPT_TIMEOUT,
|
| 178 |
+
provider: Optional[str] = None,
|
| 179 |
):
|
| 180 |
+
self.provider = (
|
| 181 |
+
provider or ("azure" if api_version else "openai")
|
| 182 |
+
).lower()
|
| 183 |
+
self.codex_executable = None
|
| 184 |
+
if self.provider == "codex":
|
| 185 |
+
self.codex_executable = shutil.which("codex")
|
| 186 |
+
if self.codex_executable is None:
|
| 187 |
+
raise RuntimeError(
|
| 188 |
+
"Codex CLI was not found. Install Codex and run "
|
| 189 |
+
"`codex login` before using the Codex provider."
|
| 190 |
+
)
|
| 191 |
+
self.client = None
|
| 192 |
+
elif self.provider == "azure" or api_version is not None:
|
| 193 |
self.client = AzureOpenAI(
|
| 194 |
azure_endpoint=endpoint,
|
| 195 |
api_key=api_key,
|
|
|
|
| 215 |
|
| 216 |
logger.info(f"Using GPT model: {self.model_name}.")
|
| 217 |
|
| 218 |
+
def _materialize_codex_image(
|
| 219 |
+
self,
|
| 220 |
+
image: str | Image.Image,
|
| 221 |
+
target_stem: Path,
|
| 222 |
+
) -> Path:
|
| 223 |
+
"""Normalize one Codex image input to a temporary PNG file."""
|
| 224 |
+
target = target_stem.with_suffix(".png")
|
| 225 |
+
if isinstance(image, Image.Image):
|
| 226 |
+
image.convert("RGB").save(target, format="PNG")
|
| 227 |
+
return target
|
| 228 |
+
|
| 229 |
+
if not isinstance(image, str):
|
| 230 |
+
raise TypeError(
|
| 231 |
+
"Codex image input must be a path, base64 string, or PIL Image"
|
| 232 |
+
)
|
| 233 |
+
|
| 234 |
+
if not image.startswith("data:"):
|
| 235 |
+
source = Path(image).expanduser()
|
| 236 |
+
try:
|
| 237 |
+
source_is_file = source.is_file()
|
| 238 |
+
except OSError:
|
| 239 |
+
source_is_file = False
|
| 240 |
+
if source_is_file:
|
| 241 |
+
try:
|
| 242 |
+
with Image.open(source) as source_image:
|
| 243 |
+
source_image.convert("RGB").save(target, format="PNG")
|
| 244 |
+
except OSError as exc:
|
| 245 |
+
raise ValueError(f"Invalid image file: {image}") from exc
|
| 246 |
+
return target
|
| 247 |
+
if source.suffix.lower() in self.image_formats:
|
| 248 |
+
raise FileNotFoundError(f"Image file not found: {image}")
|
| 249 |
+
encoded = image
|
| 250 |
+
else:
|
| 251 |
+
header, separator, encoded = image.partition(",")
|
| 252 |
+
if not separator or ";base64" not in header.lower():
|
| 253 |
+
raise ValueError("Image data URI must contain base64 data")
|
| 254 |
+
|
| 255 |
+
try:
|
| 256 |
+
image_data = base64.b64decode(encoded, validate=True)
|
| 257 |
+
with Image.open(BytesIO(image_data)) as decoded_image:
|
| 258 |
+
decoded_image.convert("RGB").save(target, format="PNG")
|
| 259 |
+
except (OSError, ValueError) as exc:
|
| 260 |
+
raise ValueError(
|
| 261 |
+
"Codex image input is neither an existing image nor valid base64"
|
| 262 |
+
) from exc
|
| 263 |
+
return target
|
| 264 |
+
|
| 265 |
+
def _query_codex(
|
| 266 |
+
self,
|
| 267 |
+
text_prompt: str,
|
| 268 |
+
image_base64: Optional[str | Image.Image | list[str | Image.Image]],
|
| 269 |
+
system_role: str,
|
| 270 |
+
params: Optional[dict],
|
| 271 |
+
) -> str:
|
| 272 |
+
"""Run one non-interactive Codex CLI request."""
|
| 273 |
+
params = params or {}
|
| 274 |
+
with tempfile.TemporaryDirectory(prefix="embodiedgen-codex-") as tmp:
|
| 275 |
+
tmp_path = Path(tmp)
|
| 276 |
+
output_path = tmp_path / "response.txt"
|
| 277 |
+
image_paths = []
|
| 278 |
+
|
| 279 |
+
images = image_base64 or []
|
| 280 |
+
if not isinstance(images, list):
|
| 281 |
+
images = [images]
|
| 282 |
+
for index, image in enumerate(images):
|
| 283 |
+
image_paths.append(
|
| 284 |
+
self._materialize_codex_image(
|
| 285 |
+
image,
|
| 286 |
+
tmp_path / f"image_{index}",
|
| 287 |
+
)
|
| 288 |
+
)
|
| 289 |
+
|
| 290 |
+
prompt = f"{system_role}\n\nUser request:\n{text_prompt}"
|
| 291 |
+
command = [
|
| 292 |
+
self.codex_executable,
|
| 293 |
+
"exec",
|
| 294 |
+
"--ephemeral",
|
| 295 |
+
"--sandbox",
|
| 296 |
+
"read-only",
|
| 297 |
+
"--skip-git-repo-check",
|
| 298 |
+
"--ignore-user-config",
|
| 299 |
+
"--ignore-rules",
|
| 300 |
+
"--color",
|
| 301 |
+
"never",
|
| 302 |
+
"--output-last-message",
|
| 303 |
+
str(output_path),
|
| 304 |
+
"--cd",
|
| 305 |
+
str(tmp_path),
|
| 306 |
+
]
|
| 307 |
+
model_name = params.get("model", self.model_name)
|
| 308 |
+
if model_name:
|
| 309 |
+
command.extend(["--model", model_name])
|
| 310 |
+
reasoning_effort = params.get(
|
| 311 |
+
"model_reasoning_effort", _CODEX_DEFAULT_REASONING_EFFORT
|
| 312 |
+
)
|
| 313 |
+
if not isinstance(reasoning_effort, str) or not reasoning_effort:
|
| 314 |
+
raise ValueError(
|
| 315 |
+
"model_reasoning_effort must be a non-empty string"
|
| 316 |
+
)
|
| 317 |
+
command.extend(
|
| 318 |
+
[
|
| 319 |
+
"--config",
|
| 320 |
+
f"model_reasoning_effort={json.dumps(reasoning_effort)}",
|
| 321 |
+
]
|
| 322 |
+
)
|
| 323 |
+
for image_path in image_paths:
|
| 324 |
+
command.extend(["--image", str(image_path)])
|
| 325 |
+
command.append("-")
|
| 326 |
+
|
| 327 |
+
result = subprocess.run(
|
| 328 |
+
command,
|
| 329 |
+
input=prompt,
|
| 330 |
+
encoding="utf-8",
|
| 331 |
+
capture_output=True,
|
| 332 |
+
timeout=self.timeout,
|
| 333 |
+
check=False,
|
| 334 |
+
env=_codex_subprocess_environment(),
|
| 335 |
+
)
|
| 336 |
+
if result.returncode != 0:
|
| 337 |
+
raise RuntimeError(result.stderr.strip() or "Codex CLI failed")
|
| 338 |
+
response = output_path.read_text(encoding="utf-8").strip()
|
| 339 |
+
if not response:
|
| 340 |
+
raise RuntimeError("Codex CLI returned an empty response")
|
| 341 |
+
return response
|
| 342 |
+
|
| 343 |
@staticmethod
|
| 344 |
def _is_gpt5_model(model_name: str) -> bool:
|
| 345 |
name = (model_name or "").lower()
|
|
|
|
| 357 |
def query(
|
| 358 |
self,
|
| 359 |
text_prompt: str,
|
| 360 |
+
image_base64: Optional[
|
| 361 |
+
str | Image.Image | list[str | Image.Image]
|
| 362 |
+
] = None,
|
| 363 |
system_role: Optional[str] = None,
|
| 364 |
params: Optional[dict] = None,
|
| 365 |
) -> Optional[str]:
|
|
|
|
| 377 |
if system_role is None:
|
| 378 |
system_role = "You are a highly knowledgeable assistant specializing in physics, engineering, and object properties." # noqa
|
| 379 |
|
| 380 |
+
if self.provider == "codex":
|
| 381 |
+
try:
|
| 382 |
+
response = self._query_codex(
|
| 383 |
+
text_prompt=text_prompt,
|
| 384 |
+
image_base64=image_base64,
|
| 385 |
+
system_role=system_role,
|
| 386 |
+
params=params,
|
| 387 |
+
)
|
| 388 |
+
except Exception as e:
|
| 389 |
+
logger.error(f"Error Codex CLI call: {e}")
|
| 390 |
+
response = None
|
| 391 |
+
|
| 392 |
+
if self.verbose:
|
| 393 |
+
logger.info(f"Prompt: {text_prompt}")
|
| 394 |
+
logger.info(f"Response: {response}")
|
| 395 |
+
return response
|
| 396 |
+
|
| 397 |
content_user = [
|
| 398 |
{
|
| 399 |
"type": "text",
|
|
|
|
| 500 |
ConnectionError: If connection fails.
|
| 501 |
"""
|
| 502 |
try:
|
| 503 |
+
if self.provider == "codex":
|
| 504 |
+
response = self._query_codex(
|
| 505 |
+
text_prompt="Reply with OK.",
|
| 506 |
+
image_base64=None,
|
| 507 |
+
system_role="You are a test system.",
|
| 508 |
+
params=None,
|
| 509 |
+
)
|
| 510 |
+
if not response:
|
| 511 |
+
raise ConnectionError(
|
| 512 |
+
"Codex CLI returned an empty response"
|
| 513 |
+
)
|
| 514 |
+
logger.info("Connection check success.")
|
| 515 |
+
return
|
| 516 |
+
|
| 517 |
probe_kwargs = dict(
|
| 518 |
messages=[
|
| 519 |
{"role": "system", "content": "You are a test system."},
|
|
|
|
| 536 |
)
|
| 537 |
|
| 538 |
|
| 539 |
+
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
|
| 540 |
config = yaml.safe_load(f)
|
| 541 |
|
| 542 |
+
settings = _resolve_agent_settings(config)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
|
| 544 |
GPT_CLIENT = GPTclient(
|
| 545 |
+
endpoint=settings["endpoint"],
|
| 546 |
+
api_key=settings["api_key"],
|
| 547 |
+
api_version=settings["api_version"],
|
| 548 |
+
model_name=settings["model_name"],
|
| 549 |
check_connection=False,
|
| 550 |
+
timeout=DEFAULT_GPT_TIMEOUT,
|
| 551 |
+
provider=settings["provider"],
|
| 552 |
)
|
| 553 |
|
| 554 |
|
embodied_gen/utils/gpt_config.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
# config.yaml
|
| 2 |
-
agent_type: "gpt-5.4" # gpt-4o, gpt-5.4 or gemma-4-31b
|
| 3 |
|
| 4 |
gpt-4o:
|
| 5 |
endpoint: https://xxx.openai.azure.com
|
|
@@ -18,3 +18,10 @@ gemma-4-31b:
|
|
| 18 |
api_key: sk-or-v1-xxx
|
| 19 |
api_version: null
|
| 20 |
model_name: google/gemma-4-31b-it:free
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# config.yaml
|
| 2 |
+
agent_type: "gpt-5.4" # gpt-4o, gpt-5.4 or gemma-4-31b or codex
|
| 3 |
|
| 4 |
gpt-4o:
|
| 5 |
endpoint: https://xxx.openai.azure.com
|
|
|
|
| 18 |
api_key: sk-or-v1-xxx
|
| 19 |
api_version: null
|
| 20 |
model_name: google/gemma-4-31b-it:free
|
| 21 |
+
|
| 22 |
+
codex:
|
| 23 |
+
provider: codex
|
| 24 |
+
endpoint: null
|
| 25 |
+
api_key: null
|
| 26 |
+
api_version: null
|
| 27 |
+
model_name: null
|
embodied_gen/utils/tags.py
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
VERSION = "v2.
|
|
|
|
| 1 |
+
VERSION = "v2.1.0"
|