mirror of
https://github.com/wowlikon/LiB.git
synced 2026-03-21 23:53:38 +00:00
ограничение векторного поиска, смена llm и проверка объёма ОЗУ
This commit is contained in:
@@ -28,12 +28,14 @@ from .core import (
|
||||
decode_token,
|
||||
authenticate_user,
|
||||
get_current_user,
|
||||
get_optional_user,
|
||||
get_current_active_user,
|
||||
get_user_from_partial_token,
|
||||
require_role,
|
||||
require_any_role,
|
||||
is_user_staff,
|
||||
is_user_admin,
|
||||
OptionalAuth,
|
||||
RequireAuth,
|
||||
RequireAdmin,
|
||||
RequireMember,
|
||||
@@ -91,10 +93,12 @@ __all__ = [
|
||||
"authenticate_user",
|
||||
"get_current_user",
|
||||
"get_current_active_user",
|
||||
"get_optional_user",
|
||||
"require_role",
|
||||
"require_any_role",
|
||||
"is_user_staff",
|
||||
"is_user_admin",
|
||||
"OptionalAuth",
|
||||
"RequireAuth",
|
||||
"RequireAdmin",
|
||||
"RequireMember",
|
||||
@@ -107,7 +111,7 @@ __all__ = [
|
||||
"get_provisioning_uri",
|
||||
"verify_totp_code",
|
||||
"qr_to_bitmap_b64",
|
||||
"generate_totp_setup," "generate_codes_for_user",
|
||||
"generate_totp_setup,generate_codes_for_user",
|
||||
"verify_and_use_code",
|
||||
"get_codes_status",
|
||||
"CODES_COUNT",
|
||||
|
||||
@@ -46,7 +46,7 @@ SECRET_KEY = os.getenv("SECRET_KEY")
|
||||
logger = get_logger()
|
||||
|
||||
# OAuth2 схема
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token")
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token", auto_error=False)
|
||||
|
||||
|
||||
class KeyDeriver:
|
||||
@@ -217,6 +217,23 @@ def authenticate_user(session: Session, username: str, password: str) -> User |
|
||||
return user
|
||||
|
||||
|
||||
def get_optional_user(
|
||||
token: Annotated[str | None, Depends(oauth2_scheme)],
|
||||
session: Session = Depends(get_session),
|
||||
) -> User | None:
|
||||
"""Возвращает текущего пользователя или None, если не авторизован"""
|
||||
if not token:
|
||||
return None
|
||||
try:
|
||||
token_data = decode_token(token)
|
||||
user = session.get(User, token_data.user_id)
|
||||
if user and user.is_active:
|
||||
return user
|
||||
except HTTPException:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def get_current_user(
|
||||
token: Annotated[str, Depends(oauth2_scheme)],
|
||||
session: Session = Depends(get_session),
|
||||
@@ -299,6 +316,7 @@ def require_any_role(allowed_roles: list[str]):
|
||||
|
||||
|
||||
# Создание dependencies
|
||||
OptionalAuth = Annotated[User | None, Depends(get_optional_user)]
|
||||
RequireAuth = Annotated[User, Depends(get_current_active_user)]
|
||||
RequireAdmin = Annotated[User, Depends(require_role("admin"))]
|
||||
RequireMember = Annotated[User, Depends(require_role("member"))]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Основной модуль"""
|
||||
|
||||
import asyncio, sys, traceback
|
||||
import asyncio, psutil, sys, traceback
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -56,12 +56,18 @@ async def lifespan(_):
|
||||
logger.error(f"[-] Seeding failed: {e}")
|
||||
|
||||
logger.info("[+] Loading ollama models...")
|
||||
ollama_client = Client(host=OLLAMA_URL)
|
||||
try:
|
||||
ollama_client = Client(host=OLLAMA_URL)
|
||||
ollama_client.pull("mxbai-embed-large")
|
||||
ollama_client.pull("llama3.2")
|
||||
|
||||
total_memory_bytes = psutil.virtual_memory().total
|
||||
total_memory_gb = total_memory_bytes / (1024 ** 3)
|
||||
if total_memory_gb > 5:
|
||||
ollama_client.pull("qwen3:4b")
|
||||
|
||||
except ResponseError as e:
|
||||
logger.error(f"[-] Failed to pull models {e}")
|
||||
|
||||
asyncio.create_task(cleanup_task())
|
||||
logger.info("[+] Starting application...")
|
||||
yield # Обработка запросов
|
||||
|
||||
@@ -13,7 +13,7 @@ from sqlalchemy import text, case, distinct
|
||||
from sqlalchemy.orm import selectinload, defer
|
||||
from sqlmodel import Session, select, col, func
|
||||
|
||||
from library_service.auth import RequireStaff
|
||||
from library_service.auth import RequireStaff, OptionalAuth
|
||||
from library_service.services import transcode_image
|
||||
from library_service.settings import get_session, OLLAMA_URL, BOOKS_PREVIEW_DIR
|
||||
from library_service.models.enums import BookStatus
|
||||
@@ -62,6 +62,7 @@ from sqlalchemy.orm import selectinload
|
||||
|
||||
@router.get("/filter", response_model=BookFilteredList)
|
||||
def filter_books(
|
||||
current_user: OptionalAuth,
|
||||
session: Session = Depends(get_session),
|
||||
q: str | None = Query(None, max_length=50, description="Поиск"),
|
||||
min_page_count: int | None = Query(None, ge=0),
|
||||
@@ -100,12 +101,16 @@ def filter_books(
|
||||
total = session.scalar(count_statement)
|
||||
|
||||
if q:
|
||||
emb = ollama_client.embeddings(model="mxbai-embed-large", prompt=q)["embedding"]
|
||||
distance_col = Book.embedding.cosine_distance(emb) # ty: ignore
|
||||
statement = statement.where(Book.embedding.is_not(None)) # ty: ignore
|
||||
if current_user:
|
||||
emb = ollama_client.embeddings(model="mxbai-embed-large", prompt=q)["embedding"]
|
||||
distance_col = Book.embedding.cosine_distance(emb) # ty: ignore
|
||||
statement = statement.where(Book.embedding.is_not(None)) # ty: ignore
|
||||
|
||||
keyword_match = case((Book.title.ilike(f"%{q}%"), 0), else_=1) # ty: ignore
|
||||
statement = statement.order_by(keyword_match, distance_col)
|
||||
keyword_match = case((Book.title.ilike(f"%{q}%"), 0), else_=1) # ty: ignore
|
||||
statement = statement.order_by(keyword_match, distance_col)
|
||||
else:
|
||||
statement = statement.where(Book.title.ilike(f"%{q}%")) # ty: ignore
|
||||
statement = statement.order_by(Book.id) # ty: ignore
|
||||
else:
|
||||
statement = statement.order_by(Book.id) # ty: ignore
|
||||
|
||||
|
||||
@@ -731,7 +731,7 @@ $(document).ready(() => {
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await Api.get("/api/users?skip=0&limit=500");
|
||||
const data = await Api.get("/api/users/?skip=0&limit=500");
|
||||
cachedUsers = data.users;
|
||||
renderUsersList(cachedUsers);
|
||||
} catch (error) {
|
||||
|
||||
@@ -504,7 +504,7 @@ $(() => {
|
||||
$(SELECTORS.adminActions).removeClass("hidden");
|
||||
}
|
||||
|
||||
Promise.all([Api.get("/api/authors"), Api.get("/api/genres")])
|
||||
Promise.all([Api.get("/api/authors/"), Api.get("/api/genres/")])
|
||||
.then(([authorsData, genresData]) => {
|
||||
initAuthors(authorsData.authors || []);
|
||||
initGenres(genresData.genres || []);
|
||||
|
||||
@@ -21,7 +21,7 @@ $(document).ready(() => {
|
||||
showLoadingState();
|
||||
|
||||
Promise.all([
|
||||
Api.get("/api/users?skip=0&limit=100"),
|
||||
Api.get("/api/users/?skip=0&limit=100"),
|
||||
Api.get("/api/users/roles"),
|
||||
])
|
||||
.then(([usersData, rolesData]) => {
|
||||
|
||||
Reference in New Issue
Block a user