memora / validation /validation.py
167AliRaza's picture
add Rag agent along with document ingestion pipeline
d0b1449
from datetime import datetime
from pydantic import BaseModel, EmailStr, Field, field_validator
from typing import Any, Optional
import re
class UserCreate(BaseModel):
email: EmailStr
name: str = Field(..., min_length=1, max_length=100)
password: str = Field(..., min_length=8)
@field_validator('name')
def validate_name(cls, v):
if not v.strip():
raise ValueError('Name cannot be empty or just whitespace')
return v.strip()
@field_validator('password')
def validate_password(cls, v):
if not validate_password_strength(v):
raise ValueError(
'Password must be at least 8 characters long and contain '
'at least one uppercase letter, one lowercase letter, '
'one digit'
)
return v
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
expires_in: int
email: EmailStr
name: str
class LogoutResponse(BaseModel):
message: str
class MessageResponse(BaseModel):
message: str
class EmailVerificationRequest(BaseModel):
email: EmailStr
class UserPublic(BaseModel):
id: str
email: EmailStr
name: str
created_at: datetime
model_config = {
"json_encoders": {
datetime: lambda v: v.isoformat()
}
}
def validate_password_strength(password: str) -> bool:
"""Validate password meets security requirements"""
if len(password) < 8:
return False
if not re.search(r"[A-Z]", password):
return False
if not re.search(r"[a-z]", password):
return False
if not re.search(r"[0-9]", password):
return False
return True
class UserQuery(BaseModel):
query:str
thread_id: Optional[str] = None
create_new_thread: Optional[bool] = False
class SourceItem(BaseModel):
document_id: str
filename: str
chunk_index: Optional[int] = None
score: Optional[float] = None
class ChatResponse(BaseModel):
result: str
thread_id: str
user_id: str
is_new_thread: bool
sources: list[SourceItem] = Field(default_factory=list)
class ThreadItem(BaseModel):
thread_id: str
title: str
created_at: Optional[datetime] = None
class ThreadsResponse(BaseModel):
threads: list[ThreadItem]
total: int
class MessageContent(BaseModel):
query: Optional[str] = None
messages: list[Any] = Field(default_factory=list)
@field_validator("messages", mode="before")
@classmethod
def normalize_messages(cls, v):
"""Always coerce a bare string into a single-element list."""
if isinstance(v, str):
return [v]
if v is None:
return []
return v
class ThreadMessagesResponse(BaseModel):
thread_id: str
messages: MessageContent
class DocumentItem(BaseModel):
document_id: str
filename: str
content_type: str
status: str
chunk_count: int = 0
created_at: datetime
updated_at: datetime
error_message: Optional[str] = None
class DocumentListResponse(BaseModel):
documents: list[DocumentItem]
total: int
class DocumentUploadResponse(BaseModel):
message: str
document: DocumentItem
class DocumentDeleteResponse(BaseModel):
message: str
document_id: str