feat: add Chinese UI, Responses models, and mirrored Windows setup
Localize the web console and persist custom model and capability settings. Use OpenAI Responses exclusively and move runtime limits into environment configuration. Bootstrap uv and the virtual environment on Windows, support optional China mirrors, and package source distributions without environments, build output, or credentials. Update regression tests and repository quality checks for the new behavior.
This commit is contained in:
1 parent
371aa6df56
commit
2ddec53954
183 files changed
+3427
-11857
No files matched your search
@@ -31,6 +31,63 @@ from artemis.core.diagnostics.schema import SystemReadinessReport
|
||||
|
||||
router = APIRouter(prefix="/api/system", tags=["system"])
|
||||
|
||||
from apps.admin_console.services.model_settings_service import (
|
||||
ModelSettingsUpdate,
|
||||
get_model_settings,
|
||||
save_model_settings,
|
||||
test_model_settings,
|
||||
CapabilitySettings,
|
||||
get_capability_settings,
|
||||
save_capability_settings,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/capability-settings")
|
||||
async def read_capability_settings():
|
||||
return get_capability_settings()
|
||||
|
||||
|
||||
@router.post("/capability-settings")
|
||||
async def write_capability_settings(payload: CapabilitySettings):
|
||||
try:
|
||||
return save_capability_settings(payload)
|
||||
except OSError as exc:
|
||||
raise HTTPException(
|
||||
status_code=500, detail="无法保存功能开关,请检查 .env 文件权限"
|
||||
) from exc
|
||||
|
||||
|
||||
@router.get("/model-settings")
|
||||
async def read_model_settings():
|
||||
return get_model_settings()
|
||||
|
||||
|
||||
@router.post("/model-settings")
|
||||
async def write_model_settings(payload: ModelSettingsUpdate):
|
||||
try:
|
||||
result = save_model_settings(payload)
|
||||
except OSError as exc:
|
||||
raise HTTPException(status_code=500, detail="无法写入 .env,请检查文件权限") from exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail="API Key 格式不正确,请检查后重试") from exc
|
||||
await readiness_engine.run_all(force_refresh=True)
|
||||
return {**result, "message": "配置已保存,新任务立即生效,重启后自动加载。"}
|
||||
|
||||
|
||||
@router.post("/model-settings/test")
|
||||
async def check_model_settings(payload: ModelSettingsUpdate):
|
||||
try:
|
||||
return await test_model_settings(payload)
|
||||
except Exception as exc:
|
||||
# SDK exceptions may contain URLs or request data; never echo credentials.
|
||||
status = getattr(exc, "status_code", None)
|
||||
detail = (
|
||||
f"Responses 连接失败(HTTP {status})"
|
||||
if status
|
||||
else "Responses 连接失败,请检查接口地址、模型、密钥和超时设置。"
|
||||
)
|
||||
raise HTTPException(status_code=400, detail=detail) from exc
|
||||
|
||||
|
||||
def _require_local_admin_request(request: Request) -> None:
|
||||
"""Keep endpoint probing and mutation on the local administration boundary."""
|
||||
@@ -264,8 +321,8 @@ class UpdateCredentialsRequest(BaseModel):
|
||||
"""Payload to update and configure LLM or Vision OCR API credentials."""
|
||||
|
||||
provider: str = Field(
|
||||
default="google",
|
||||
description="Provider identifier (e.g. google, gemini, openai, anthropic, openrouter, ocr)",
|
||||
default="openai",
|
||||
description="Provider identifier (openai or ocr)",
|
||||
)
|
||||
api_key: str = Field(description="The secret API key string to configure")
|
||||
persist_to_env: bool = Field(
|
||||
@@ -277,8 +334,8 @@ class ValidateCredentialsRequest(BaseModel):
|
||||
"""Payload to test and verify LLM or Vision OCR API credentials without saving."""
|
||||
|
||||
provider: str = Field(
|
||||
default="google",
|
||||
description="Provider identifier (e.g. google, gemini, openai, anthropic, openrouter, ocr)",
|
||||
default="openai",
|
||||
description="Provider identifier (openai or ocr)",
|
||||
)
|
||||
api_key: str = Field(description="The secret API key string to test")
|
||||
base_url: str | None = Field(default=None, description="Optional custom base URL")
|
||||
@@ -294,9 +351,8 @@ async def get_credentials():
|
||||
"""
|
||||
from artemis.config import settings
|
||||
|
||||
providers = ("google", "openai", "anthropic", "openrouter", "ocr")
|
||||
providers = ("openai", "ocr")
|
||||
status = {name: bool(settings.get_api_key(name)) for name in providers}
|
||||
status["gemini"] = status["google"]
|
||||
return {
|
||||
"providers": [
|
||||
{"name": name, "configured": configured} for name, configured in status.items()
|
||||
@@ -415,13 +471,7 @@ async def get_model_config_and_env():
|
||||
return "****"
|
||||
return f"****{k[-4:]}"
|
||||
|
||||
gemini_real = get_real_env_value("GEMINI_API_KEY", "google") or get_real_env_value(
|
||||
"GOOGLE_API_KEY", "google"
|
||||
)
|
||||
openai_real = get_real_env_value("OPENAI_API_KEY", "openai")
|
||||
anthropic_real = get_real_env_value("ANTHROPIC_API_KEY", "anthropic")
|
||||
openrouter_real = get_real_env_value("OPEN_ROUTER_API_KEY", "openrouter")
|
||||
xai_real = get_real_env_value("XAI_API_KEY", "xai")
|
||||
base_url_val = settings.OPENAI_BASE_URL or os.environ.get("OPENAI_BASE_URL")
|
||||
if base_url_val and is_placeholder_key(base_url_val):
|
||||
base_url_val = None
|
||||
@@ -430,47 +480,19 @@ async def get_model_config_and_env():
|
||||
)
|
||||
|
||||
env_vars = [
|
||||
{
|
||||
"name": "GEMINI_API_KEY",
|
||||
"provider": "google",
|
||||
"is_set": bool(gemini_real),
|
||||
"preview": mask_key(gemini_real),
|
||||
"description": "Google Gemini multimodal vision API key (free tier available)",
|
||||
},
|
||||
{
|
||||
"name": "OPENAI_API_KEY",
|
||||
"provider": "openai",
|
||||
"is_set": bool(openai_real),
|
||||
"preview": mask_key(openai_real),
|
||||
"description": "OpenAI API key (GPT-4o, GPT-4o-mini)",
|
||||
},
|
||||
{
|
||||
"name": "ANTHROPIC_API_KEY",
|
||||
"provider": "anthropic",
|
||||
"is_set": bool(anthropic_real),
|
||||
"preview": mask_key(anthropic_real),
|
||||
"description": "Anthropic Claude API key (Claude 3.5 Sonnet, Claude 3.7)",
|
||||
},
|
||||
{
|
||||
"name": "OPEN_ROUTER_API_KEY",
|
||||
"provider": "openrouter",
|
||||
"is_set": bool(openrouter_real),
|
||||
"preview": mask_key(openrouter_real),
|
||||
"description": "OpenRouter unified API gateway key",
|
||||
},
|
||||
{
|
||||
"name": "XAI_API_KEY",
|
||||
"provider": "xai",
|
||||
"is_set": bool(xai_real),
|
||||
"preview": mask_key(xai_real),
|
||||
"description": "xAI Grok vision API key",
|
||||
"description": "OpenAI Responses API 密钥",
|
||||
},
|
||||
{
|
||||
"name": "OPENAI_BASE_URL",
|
||||
"provider": "custom",
|
||||
"provider": "openai",
|
||||
"is_set": bool(base_url_val),
|
||||
"preview": base_url_val,
|
||||
"description": "Custom API endpoint (for local Ollama, vLLM, DeepSeek, or proxies)",
|
||||
"description": "OpenAI Responses 接口根地址(包含 /v1,不包含 /responses)",
|
||||
},
|
||||
{
|
||||
"name": "VISION_API_KEY",
|
||||
|
||||
Reference in new issue
Block a user