sundaram22verma's picture
initial commit
9d76e23
"""
This file defines the data structures (schemas) for the recommender system's API using Pydantic.
It ensures that data exchanged with the API (requests and responses) adheres to a specific format,
providing benefits like automatic data validation, serialization/deserialization,
and clear API documentation.
"""
from pydantic import BaseModel, Field, validator
from typing import List, Optional, Any, Union
from src.config.settings import DEFAULT_K # For default 'k' value
class MsgPayload(BaseModel):
"""
Represents the payload for a message.
"""
msg_id: int # Unique identifier for the message.
msg_name: str # Name or description of the message.
class RecommendationRequest(BaseModel):
"""
Defines the structure for a recommendation request.
"""
user_id: Optional[str] = None # Optional unique identifier for the user making the request.
query: str = Field(..., description="The search query or input text for which recommendations are sought.")
k: Optional[int] = Field(default=DEFAULT_K, description=f"The number of recommendations to return, defaults to {DEFAULT_K}.")
class UserItemRecommendationRequest(BaseModel):
"""
Defines the structure for an item-based recommendation request.
"""
id: str = Field(..., description="The item ID (msid) to get recommendations for.")
user_id: Optional[str] = Field(None, description="Optional user ID. If not provided, an anonymous ID will be generated.")
k: Optional[int] = Field(default=DEFAULT_K, description=f"Number of recommendations to return, defaults to {DEFAULT_K}.")
class RetrievedDocument(BaseModel):
"""
Represents a single document retrieved as part of a recommendation.
"""
id: str # Unique identifier for the retrieved document (msid, typically a string).
hl: str # Headline of the document.
synopsis: Optional[str] = None # Synopsis or main content of the document.
keywords: Optional[str] = None # Keywords associated with the document.
type: Optional[str] = None # Optional type or category of the document.
taxonomy: Optional[List[str]] = None # List of taxonomy terms.
score: Optional[float] = None # Relevance score of the document.
seolocation: Optional[str] = None # Optional SEO location or URL.
dl: Optional[str] = None # Optional deeplink.
lu: Optional[str] = None # Optional last updated timestamp or string.
imageid: Optional[str] = None # Optional image identifier.
imgratio: Optional[str] = None # Optional image ratio (e.g., "16:9").
imgsize: Optional[str] = None # Optional image size (e.g., "1024x768").
# summary and smart_tip fields removed as they should only be in summary endpoint response
# Create a new model for documents with summary and smart tip
class RetrievedDocumentWithSummary(RetrievedDocument):
"""
Represents a document retrieved as part of a recommendation with additional summary and smart tip fields.
"""
summary: Optional[str] = "" # Generated summary of the article, defaults to empty string
smart_tip: Optional[Any] = None # Smart tip with related articles and summaries.
class SmartTipSuggestion(BaseModel):
label: str
url: str
# summary: Optional[str] = "" # Removed as per request
class SmartTip(BaseModel):
title: str
description: str
suggestions: List[SmartTipSuggestion] = Field(default_factory=list)
class PastFeedbackItem(BaseModel):
srcMsid: Optional[str] = ""
clickedMsid: Optional[str] = ""
resultMsids: List[str] = Field(default_factory=list)
# timestamp: Optional[datetime] = None # Optional: if you want to include timestamp
class RecommendationResponse(BaseModel):
"""
Defines the structure for a recommendation response.
"""
msid: Optional[str] = None # Made optional to handle cases where it might not be set (e.g. query-based recs)
retrieved_documents: List[RetrievedDocument] = Field(default_factory=list) # Use RetrievedDocument
generated_response: Optional[str] = None # Added to match recommender output
clicked_msid: Optional[Union[str, List[Any]]] = None # To match existing logic in routes.py
past_feedback: List[PastFeedbackItem] = Field(default_factory=list)
@validator('retrieved_documents', pre=True, each_item=True)
def ensure_smart_tip_format(cls, v):
if isinstance(v, dict) and 'smart_tip' in v and isinstance(v['smart_tip'], str): # Compatibility if old format string is somehow passed
v['smart_tip'] = None # Or convert to new format if possible, for now, nullify
return v
# ...other fields if present...
class OutputData(BaseModel):
"""
Represents a single data item in the output, often a simplified version of a retrieved document.
"""
id: str # Unique identifier for the output data item (msid, typically a string).
headline: Optional[str] = None # Optional headline or title for the data item.
type: Optional[str] = None # Optional type or category of the data item.
class OutputResponse(BaseModel):
"""
Defines the structure for a generic output response containing a list of data items.
"""
data: List[OutputData] # A list of output data items.
class FeedbackRecommendationRequest(BaseModel):
user_id: str
msid: str
clicked_msid: Optional[str] = None
k: Optional[int] = 5
# Refine RetrievedDocument.smart_tip type
RetrievedDocument.model_fields['smart_tip'] = Field(default=None, description="Smart tip with related articles and summaries.")
RetrievedDocument.model_rebuild(force=True)
# Update the RecommendationResponse model to use RetrievedDocumentWithSummary for summary endpoint
class RecommendationResponseWithSummary(BaseModel):
"""
Defines the structure for a recommendation response with summaries and smart tips.
"""
msid: Optional[str] = None # Made optional to handle cases where it might not be set (e.g. query-based recs)
retrieved_documents: List[RetrievedDocumentWithSummary] = Field(default_factory=list)
generated_response: Optional[str] = None # Added to match recommender output
clicked_msid: Optional[Union[str, List[Any]]] = None # To match existing logic in routes.py
past_feedback: List[PastFeedbackItem] = Field(default_factory=list)
@validator('retrieved_documents', pre=True, each_item=True)
def ensure_smart_tip_format(cls, v):
if isinstance(v, dict) and 'smart_tip' in v and isinstance(v['smart_tip'], str): # Compatibility if old format string is somehow passed
v['smart_tip'] = None # Or convert to new format if possible, for now, nullify
return v