清理 Ollama/API URL 中的终端控制字符,修复 AI 调用失败。
This commit is contained in:
@@ -18,6 +18,7 @@ from app.schemas import (
|
||||
SystemSettingsOut,
|
||||
SystemSettingsUpdate,
|
||||
)
|
||||
from app.services.url_sanitize import sanitize_http_url, sanitize_model_name
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
|
||||
@@ -66,13 +67,13 @@ def update_settings(
|
||||
if data.ai_provider is not None:
|
||||
row.ai_provider = data.ai_provider.value
|
||||
if data.ollama_base_url is not None:
|
||||
row.ollama_base_url = data.ollama_base_url or None
|
||||
row.ollama_base_url = sanitize_http_url(data.ollama_base_url) or None
|
||||
if data.ollama_model is not None:
|
||||
row.ollama_model = data.ollama_model or None
|
||||
row.ollama_model = sanitize_model_name(data.ollama_model) or None
|
||||
if data.openai_base_url is not None:
|
||||
row.openai_base_url = data.openai_base_url or None
|
||||
row.openai_base_url = sanitize_http_url(data.openai_base_url) or None
|
||||
if data.openai_model is not None:
|
||||
row.openai_model = data.openai_model or None
|
||||
row.openai_model = sanitize_model_name(data.openai_model) or None
|
||||
if data.openai_api_key is not None and data.openai_api_key.strip():
|
||||
row.openai_api_key = data.openai_api_key.strip()
|
||||
if data.ocr_service_url is not None:
|
||||
|
||||
@@ -4,6 +4,7 @@ from sqlalchemy.orm import Session
|
||||
from app.core.config import settings as app_settings
|
||||
from app.models.user import SchoolLevel, SystemSettings
|
||||
from app.services.school_level import school_level_label
|
||||
from app.services.url_sanitize import sanitize_http_url, sanitize_model_name
|
||||
|
||||
CURRICULUM_JUNIOR = """初中课程标准:代数、几何(全等/相似/勾股)、一次函数与简单二次函数、基础概率统计。
|
||||
严禁使用:高中导数、向量、解析几何、排列组合进阶、复数、微积分、大学线性代数等。"""
|
||||
@@ -112,18 +113,18 @@ def load_ai_config(db: Session) -> AIConfig:
|
||||
if row is None:
|
||||
return AIConfig(
|
||||
provider="ollama",
|
||||
ollama_base_url=app_settings.OLLAMA_BASE_URL,
|
||||
ollama_model=app_settings.OLLAMA_MODEL,
|
||||
openai_base_url=app_settings.OPENAI_BASE_URL,
|
||||
openai_model=app_settings.OPENAI_MODEL,
|
||||
ollama_base_url=sanitize_http_url(app_settings.OLLAMA_BASE_URL),
|
||||
ollama_model=sanitize_model_name(app_settings.OLLAMA_MODEL),
|
||||
openai_base_url=sanitize_http_url(app_settings.OPENAI_BASE_URL),
|
||||
openai_model=sanitize_model_name(app_settings.OPENAI_MODEL),
|
||||
openai_api_key=None,
|
||||
)
|
||||
return AIConfig(
|
||||
provider=row.ai_provider or "ollama",
|
||||
ollama_base_url=row.ollama_base_url or app_settings.OLLAMA_BASE_URL,
|
||||
ollama_model=row.ollama_model or app_settings.OLLAMA_MODEL,
|
||||
openai_base_url=row.openai_base_url or app_settings.OPENAI_BASE_URL,
|
||||
openai_model=row.openai_model or app_settings.OPENAI_MODEL,
|
||||
ollama_base_url=sanitize_http_url(row.ollama_base_url or app_settings.OLLAMA_BASE_URL),
|
||||
ollama_model=sanitize_model_name(row.ollama_model or app_settings.OLLAMA_MODEL),
|
||||
openai_base_url=sanitize_http_url(row.openai_base_url or app_settings.OPENAI_BASE_URL),
|
||||
openai_model=sanitize_model_name(row.openai_model or app_settings.OPENAI_MODEL),
|
||||
openai_api_key=row.openai_api_key,
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import re
|
||||
|
||||
# ANSI 颜色/光标控制序列(粘贴终端输出时常见)
|
||||
_ANSI_ESCAPE = re.compile(r"\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07]*\x07|\x1b[@-Z\\-_]")
|
||||
|
||||
# 其它不可见控制字符(保留普通 URL 字符)
|
||||
_CTRL_CHARS = re.compile(r"[\x00-\x1f\x7f]")
|
||||
|
||||
|
||||
def sanitize_http_url(url: str | None) -> str:
|
||||
"""去掉 URL 中的 ANSI/控制字符,避免 httpx Invalid non-printable ASCII character。"""
|
||||
if not url:
|
||||
return ""
|
||||
cleaned = _ANSI_ESCAPE.sub("", url)
|
||||
cleaned = _CTRL_CHARS.sub("", cleaned)
|
||||
return cleaned.strip()
|
||||
|
||||
|
||||
def sanitize_model_name(name: str | None) -> str:
|
||||
if not name:
|
||||
return ""
|
||||
cleaned = _ANSI_ESCAPE.sub("", name)
|
||||
cleaned = _CTRL_CHARS.sub("", cleaned)
|
||||
return cleaned.strip()
|
||||
Reference in New Issue
Block a user