fix: network-share readers, model unload off the loop, bad save requests (#620)
Every read-only SQLite open now uses one URI helper, so a library on a Windows network share works in backups, restores, moves and history reads. Unloading a model no longer blocks the server. A malformed /save body gets a 400, not a 500.
This commit is contained in:
+3
-1
@@ -30,8 +30,10 @@ from .jobs import (
|
||||
)
|
||||
|
||||
try:
|
||||
from ...database.sqlite_uri import readonly_uri
|
||||
from ...utils.parallel import map_parallel
|
||||
except ImportError:
|
||||
from database.sqlite_uri import readonly_uri
|
||||
from utils.parallel import map_parallel
|
||||
|
||||
try:
|
||||
@@ -399,7 +401,7 @@ def _inspect_restore_upload(path):
|
||||
Returns:
|
||||
None when acceptable, otherwise a human-readable reason (blocking).
|
||||
"""
|
||||
uri = Path(os.path.abspath(path)).as_uri() + "?mode=ro"
|
||||
uri = readonly_uri(path)
|
||||
try:
|
||||
conn = sqlite3.connect(uri, uri=True)
|
||||
except sqlite3.Error as e:
|
||||
|
||||
@@ -1411,7 +1411,8 @@ class AutotagRoutesMixin:
|
||||
)
|
||||
|
||||
model_type = service.get_loaded_model_type()
|
||||
service.unload_model()
|
||||
# Off the loop; a dropped request keeps the gate until it ends.
|
||||
await model_gate.run(owner, service.unload_model)
|
||||
finally:
|
||||
model_gate.release(owner)
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ import os
|
||||
import sqlite3
|
||||
import tempfile
|
||||
from contextlib import closing
|
||||
from pathlib import Path
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
@@ -56,6 +55,7 @@ from .maintenance_plans import PlanExpired, PlanUsed
|
||||
from .restore_plans import RestorePlanStore
|
||||
|
||||
try:
|
||||
from ...database.sqlite_uri import readonly_uri
|
||||
from ...database import restore_stage
|
||||
from ...database.operations import PromptDatabase
|
||||
from ...database.safety_backup import (
|
||||
@@ -66,6 +66,7 @@ try:
|
||||
safety_temp,
|
||||
)
|
||||
except ImportError:
|
||||
from database.sqlite_uri import readonly_uri
|
||||
from database import restore_stage
|
||||
from database.operations import PromptDatabase
|
||||
from database.safety_backup import (
|
||||
@@ -186,7 +187,7 @@ def snapshot_corruption(path):
|
||||
with open(path, "rb") as handle:
|
||||
if handle.read(len(SQLITE_HEADER)) != SQLITE_HEADER:
|
||||
return "Not a SQLite database file"
|
||||
uri = Path(os.path.abspath(path)).as_uri() + "?mode=ro"
|
||||
uri = readonly_uri(path)
|
||||
with closing(sqlite3.connect(uri, uri=True)) as conn:
|
||||
row = conn.execute("PRAGMA integrity_check").fetchone()
|
||||
except (OSError, sqlite3.Error) as error:
|
||||
|
||||
+9
-1
@@ -727,7 +727,15 @@ class PromptRoutesMixin:
|
||||
async def save_prompt(self, request):
|
||||
"""Save a new prompt with metadata and duplicate detection."""
|
||||
try:
|
||||
data = await request.json()
|
||||
data, error = await self._read_json_body(request)
|
||||
if error is not None:
|
||||
return error
|
||||
for field in ("text", "category", "notes"):
|
||||
if data.get(field) is not None and not isinstance(data[field], str):
|
||||
return web.json_response(
|
||||
{"success": False, "error": f"{field} must be text"},
|
||||
status=400,
|
||||
)
|
||||
|
||||
text = (data.get("text") or "").strip()
|
||||
if not text:
|
||||
|
||||
Reference in New Issue
Block a user