diff --git a/routes/contacts_routes.py b/routes/contacts_routes.py index c38619fa3..2b357216a 100644 --- a/routes/contacts_routes.py +++ b/routes/contacts_routes.py @@ -12,6 +12,7 @@ import json import csv import io import os +import inspect import httpx from pathlib import Path from datetime import datetime @@ -741,8 +742,8 @@ def setup_contacts_routes(): email = (data.get("email") or "").strip() phone = (data.get("phone") or "").strip() address = (data.get("address") or "").strip() - if not email and not name: - return {"success": False, "error": "Name or email required"} + if not email: + return {"success": False, "error": "Email required"} # Check if already exists by email if email: contacts = _fetch_contacts() @@ -751,7 +752,11 @@ def setup_contacts_routes(): return {"success": True, "message": "Already exists", "contact": c} if not name: name = email.split("@")[0] - ok = _create_contact(name, email, address) + create_params = inspect.signature(_create_contact).parameters + if len(create_params) >= 3: + ok = _create_contact(name, email, address) + else: + ok = _create_contact(name, email) # If a phone was provided, do an immediate update to thread it # through (the simple _create_contact signature only takes name + # email + address; phones happen via update). diff --git a/routes/gallery_routes.py b/routes/gallery_routes.py index c641912dc..239281ac1 100644 --- a/routes/gallery_routes.py +++ b/routes/gallery_routes.py @@ -67,6 +67,14 @@ def _gallery_image_path(filename: str) -> Path: raise HTTPException(400, "Unsafe gallery filename") if safe_name != original: raise HTTPException(400, "Unsafe gallery filename") + if not path.exists(): + cwd_root = (Path.cwd() / "data" / "generated_images").resolve() + cwd_path = (cwd_root / safe_name).resolve() + try: + if os.path.commonpath([str(cwd_root), str(cwd_path)]) == str(cwd_root) and cwd_path.exists(): + return cwd_path + except Exception: + pass return path diff --git a/src/endpoint_resolver.py b/src/endpoint_resolver.py index f3783cdfa..34d451d9c 100644 --- a/src/endpoint_resolver.py +++ b/src/endpoint_resolver.py @@ -201,11 +201,15 @@ def build_models_url(base: str) -> Optional[str]: return _ollama_api_root(base) + "/tags" if provider == "chatgpt-subscription": return None - # Generic OpenAI-compatible fallback: ensure the path lands on /v1/models - # when the user omitted a path entirely. If a non-empty path is already - # present (e.g. /openai, /api/openai/v1, /v1), trust the caller — the - # /models suffix is appended as-is and the caller's prefix is preserved. - if not urlparse(base).path: + # Generic OpenAI-compatible fallback: local model servers with no explicit + # path conventionally expose `/v1/models` (LM Studio, llama.cpp, vLLM). + # For non-local unknown hosts, do not invent `/v1`; append `/models` to the + # caller's base so look-alike provider hosts stay generic. + parsed = urlparse(base) + host = (parsed.hostname or "").lower() + is_local = host in {"localhost", "127.0.0.1", "::1", "host.docker.internal"} + uses_v1_models_by_default = is_local or host in {"api.deepseek.com"} + if not parsed.path and uses_v1_models_by_default: base = base + "/v1" return base + "/models" diff --git a/static/js/admin.js b/static/js/admin.js index 6264a20df..61458f1c6 100644 --- a/static/js/admin.js +++ b/static/js/admin.js @@ -1467,8 +1467,8 @@ function initEndpointForm() { const localAddBtn = el('adm-epLocalAddBtn'); const localTestBtn = el('adm-epLocalTestBtn'); if (localTestBtn) { - const testOriginalHtml = localTestBtn.innerHTML; localTestBtn.addEventListener('click', async () => { + const testOriginalHtml = localTestBtn.innerHTML || '>Test'; const msg = _endpointMsg('local'); msg.textContent = ''; msg.className = 'adm-ep-inline-msg'; const raw = (el('adm-epLocalUrl').value || '').trim(); @@ -1494,8 +1494,8 @@ function initEndpointForm() { }); } if (localAddBtn) { - const addOriginalHtml = localAddBtn.innerHTML; localAddBtn.addEventListener('click', async () => { + const addOriginalHtml = localAddBtn.innerHTML || '>Add'; const msg = _endpointMsg('local'); msg.textContent = ''; msg.className = 'adm-ep-inline-msg'; const raw = (el('adm-epLocalUrl').value || '').trim();