basic image support

This commit is contained in:
Micha R. Albert 2025-07-09 11:13:29 -04:00
parent 43b2e33551
commit 1a68c28802
Signed by: mra
SSH key fingerprint: SHA256:2JB0fGfy7m2HQXAzvSXXKm7wPTj9Z60MOjFOQGM2Y/E
2 changed files with 117 additions and 1 deletions

View file

@ -35,7 +35,7 @@ EXPECTED_SCHEMAS = {
},
"items": {
"required_fields": ["Name", "Type", "Level", "Rarity"],
"optional_fields": ["Description", "Game Name (from Games)"],
"optional_fields": ["Description", "Game Name (from Games)", "Image"],
},
"item_instances": {
"required_fields": ["ID", "User", "Item"],

View file

@ -97,6 +97,30 @@ class CreateItemResponse(BaseModel):
)
class ItemImageAttachment(BaseModel):
"""Model for item image attachment details."""
url: str = Field(..., description="Direct URL to the PNG image file")
filename: Optional[str] = Field(None, description="Original filename of the uploaded image")
type: Optional[str] = Field(None, description="MIME type of the image file")
size: Optional[int] = Field(None, description="File size in bytes")
class DetailedItemResponse(BaseModel):
"""Response model for detailed item data including image."""
id: str = Field(..., description="Unique identifier for the item")
name: str = Field(..., description="Display name of the item")
type: str = Field(..., description="Category or type of the item")
level: int = Field(..., description="Required level to use this item")
rarity: str = Field(
..., description="Rarity classification (common, rare, epic, legendary, etc.)"
)
game_name: Optional[str] = Field(None, description="Name of the game this item belongs to")
description: Optional[str] = Field(None, description="Description of the item")
image: Optional[ItemImageAttachment] = Field(None, description="PNG image attachment details")
def create_items_router(
sessions_table, users_table, items_table, item_addons_table, item_instances_table
) -> APIRouter:
@ -245,6 +269,98 @@ The item will be added to the user's inventory and associated with their current
detail=error_response["detail"],
)
@router.get(
"/{item_id}",
response_model=DetailedItemResponse,
summary="Get detailed information for a specific item",
description="""Get complete details for a specific item including image thumbnail.
Returns all available information about the item including name, type, level, rarity, game, description, and base64 encoded image thumbnail.
**Authentication:** None required""",
responses={
200: {
"description": "Item details retrieved successfully",
"content": {
"application/json": {
"example": {
"id": "rec123",
"name": "Iron Sword",
"type": "weapon",
"level": 5,
"rarity": "common",
"game_name": "Adventure Quest",
"description": "A sturdy iron sword perfect for beginning adventurers",
"image": {
"url": "https://v5.airtableusercontent.com/v1/15/15/1704067200000/xyz123/iron-sword.png",
"filename": "iron-sword.png",
"type": "image/png",
"size": 45321
}
}
}
}
},
404: {"description": "Item not found"},
429: {"description": "Rate limit exceeded"}
}
)
@limiter.limit(f"{settings.rate_limit_requests}/minute")
async def get_item(request: Request, item_id: str):
"""Get detailed information for a specific item including image."""
try:
# Validate the item ID format
validate_airtable_id(item_id)
# Get the item
item = await get_item_by_id(item_id, items_table)
if not item:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Item not found"
)
# Extract fields
fields = item.get("fields", {})
# Process image attachment if present
image_data = None
if "Image" in fields and fields["Image"]:
# Airtable attachments are arrays of attachment objects
attachments = fields["Image"]
if isinstance(attachments, list) and len(attachments) > 0:
# Take the first attachment
attachment = attachments[0]
image_data = ItemImageAttachment(
url=attachment.get("url", ""),
filename=attachment.get("filename"),
type=attachment.get("type"),
size=attachment.get("size")
)
# Build response with all available fields
response_data = {
"id": item["id"],
"name": fields.get("Name", ""),
"type": fields.get("Type", ""),
"level": fields.get("Level", 0),
"rarity": str(fields.get("Rarity", "")) if fields.get("Rarity") is not None else "",
"game_name": fields.get("Game Name (from Games)", [None])[0] if fields.get("Game Name (from Games)") else None,
"description": fields.get("Description"),
"image": image_data
}
return response_data
except HTTPException:
raise
except Exception as e:
error_response = create_safe_error_response(e, "Failed to retrieve item")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=error_response["detail"]
)
return router