Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ BATCH_SIZE=32
MAX_BATCH_SIZE=128
MAX_TEXTS_PER_REQUEST=100
MAX_PASSAGES_PER_RERANK=1000
MAX_PASSAGE_LENGTH=4096
MAX_SEQUENCE_LENGTH=512
DEVICE_MEMORY_FRACTION=0.8
REQUEST_TIMEOUT=300
Expand Down
38 changes: 23 additions & 15 deletions app/models/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Pydantic models for API requests.
"""

import os
from typing import List, Literal, Optional

from pydantic import BaseModel, Field, field_validator
Expand Down Expand Up @@ -30,9 +31,7 @@ class EmbedRequest(BaseModel):
description="Whether to automatically truncate texts exceeding token limits",
json_schema_extra={"example": True},
)
truncation_strategy: Optional[
Literal["smart_truncate", "truncate", "extract", "error"]
] = Field(
truncation_strategy: Optional[Literal["smart_truncate", "truncate", "extract", "error"]] = Field(
"smart_truncate",
description=(
"Strategy for handling long texts: smart_truncate (preserve sentences), "
Expand All @@ -53,7 +52,7 @@ class EmbedRequest(BaseModel):
json_schema_extra={"example": False},
)

@field_validator('texts')
@field_validator("texts")
@classmethod
def validate_texts(cls, v, info):
"""Validate texts array with enhanced error handling."""
Expand All @@ -64,7 +63,7 @@ def validate_texts(cls, v, info):
raise ValueError("texts cannot be empty")

# Get auto_truncate setting from the same data
auto_truncate = info.data.get('auto_truncate', True) if info.data else True
auto_truncate = info.data.get("auto_truncate", True) if info.data else True

for i, text in enumerate(v):
if not isinstance(text, str):
Expand All @@ -79,12 +78,12 @@ def validate_texts(cls, v, info):

return v

@field_validator('batch_size')
@field_validator("batch_size")
@classmethod
def validate_batch_size(cls, v, info):
"""Validate batch size relative to number of texts."""
if info.data and 'texts' in info.data and info.data['texts']:
num_texts = len(info.data['texts'])
if info.data and "texts" in info.data and info.data["texts"]:
num_texts = len(info.data["texts"])
if v > num_texts:
# Adjust batch size to not exceed number of texts
return num_texts
Expand Down Expand Up @@ -121,7 +120,7 @@ class RerankRequest(BaseModel):
True, description="Whether to return the original passage texts", json_schema_extra={"example": True}
)

@field_validator('query')
@field_validator("query")
@classmethod
def validate_query(cls, v):
"""Validate query text."""
Expand All @@ -133,7 +132,7 @@ def validate_query(cls, v):

return v.strip()

@field_validator('passages')
@field_validator("passages")
@classmethod
def validate_passages(cls, v):
"""Validate passage inputs."""
Expand All @@ -147,17 +146,26 @@ def validate_passages(cls, v):
if not passage.strip():
raise ValueError(f"Passage at index {i} cannot be empty or whitespace only")

if len(passage) > 4096: # Reasonable character limit for passages
raise ValueError(f"Passage at index {i} too long: {len(passage)} > 4096 characters")
max_passage_length = int(os.getenv("MAX_PASSAGE_LENGTH", "4096"))

for i, passage in enumerate(v):
if not isinstance(passage, str):
raise ValueError(f"Passage at index {i} must be a string")

if not passage.strip():
raise ValueError(f"Passage at index {i} cannot be empty or whitespace only")

if len(passage) > max_passage_length:
raise ValueError(f"Passage at index {i} too long: {len(passage)} > {max_passage_length} characters")

return v

@field_validator('top_k')
@field_validator("top_k")
@classmethod
def validate_top_k(cls, v, info):
"""Validate top_k relative to number of passages."""
if info.data and 'passages' in info.data and info.data['passages']:
num_passages = len(info.data['passages'])
if info.data and "passages" in info.data and info.data["passages"]:
num_passages = len(info.data["passages"])
if v > num_passages:
# Adjust top_k to not exceed number of passages
return num_passages
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ dependencies = [
"python-dotenv",
"structlog",
"prometheus-client",
"mlx>=0.29.2",
"psutil>=7.1.0",
]

[project.optional-dependencies]
Expand Down
Loading