Skip to content
Merged
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
84 changes: 84 additions & 0 deletions backend/app/database/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,90 @@ def db_get_image_by_id(image_id: str) -> Optional[dict]:
conn.close()


def db_search_images_by_tag(tag_name: str) -> List[dict]:
"""
Get all images that match a specific tag name, returning their full tag list.
"""
conn = _connect()
cursor = conn.cursor()

try:
query = """
SELECT
i.id,
i.path,
i.folder_id,
i.thumbnailPath,
i.metadata,
i.isTagged,
i.isFavourite,
i.latitude,
i.longitude,
i.captured_at,
m.name as tag_name
FROM images i
LEFT JOIN image_classes ic ON i.id = ic.image_id
LEFT JOIN mappings m ON ic.class_id = m.class_id
WHERE i.id IN (
SELECT ic2.image_id FROM image_classes ic2
JOIN mappings m2 ON ic2.class_id = m2.class_id
WHERE LOWER(m2.name) = LOWER(?)
)
ORDER BY i.path, m.name
"""

cursor.execute(query, [tag_name])
results = cursor.fetchall()

# Group results by image ID
images_dict = {}
for (
image_id,
path,
folder_id,
thumbnail_path,
metadata,
is_tagged,
is_favourite,
latitude,
longitude,
captured_at,
tag_name_result,
) in results:
if image_id not in images_dict:
images_dict[image_id] = {
"id": image_id,
"path": path,
"folder_id": str(folder_id) if folder_id is not None else "",
"thumbnailPath": thumbnail_path,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"metadata": metadata,
"isTagged": bool(is_tagged),
"isFavourite": bool(is_favourite),
"latitude": latitude,
"longitude": longitude,
"captured_at": captured_at if captured_at else None,
"tags": [],
}

if tag_name_result and tag_name_result not in images_dict[image_id]["tags"]:
images_dict[image_id]["tags"].append(tag_name_result)

images = []
for image_data in images_dict.values():
if not image_data["tags"]:
image_data["tags"] = None
images.append(image_data)

images.sort(key=lambda x: x["path"])
return images

except sqlite3.Error as e:
logger.error(f"Error searching images by tag: {e}")
raise
finally:
conn.close()


# ============================================================================
# MEMORIES FEATURE - Location and Time-based Queries
# ============================================================================
Expand Down
48 changes: 47 additions & 1 deletion backend/app/routes/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
from app.schemas.images import ErrorResponse
from app.utils.images import image_util_parse_metadata
from pydantic import BaseModel
from app.database.images import db_toggle_image_favourite_status, db_get_image_by_id
from app.database.images import (
db_toggle_image_favourite_status,
db_get_image_by_id,
db_search_images_by_tag,
)
from app.logging.setup_logging import get_logger

# Initialize logger
Expand Down Expand Up @@ -88,6 +92,48 @@ def get_all_images(
)


@router.get(
"/search",
response_model=GetAllImagesResponse,
responses={code: {"model": ErrorResponse} for code in [400, 404, 500]},
)
def search_images_by_tag(tag: str = Query(..., description="Tag name to search for")):
"""Search images by tag name."""
try:
images = db_search_images_by_tag(tag)

image_data = [
ImageData(
id=image["id"],
path=image["path"],
folder_id=image["folder_id"],
thumbnailPath=image["thumbnailPath"],
metadata=image_util_parse_metadata(image["metadata"]),
isTagged=image["isTagged"],
isFavourite=image.get("isFavourite", False),
tags=image["tags"],
)
for image in images
]

return GetAllImagesResponse(
success=True,
message=f"Successfully retrieved {len(image_data)} images for tag '{tag}'",
data=image_data,
)

except Exception as e:
logger.error(f"Error searching images: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=ErrorResponse(
success=False,
error="Internal server error",
message="Unable to search images due to an internal error",
).model_dump(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)


# adding add to favourite and remove from favourite routes


Expand Down
Loading
Loading