diff --git a/src/api/v1/auth.py b/src/api/v1/auth.py index 1388420..cd65e5a 100644 --- a/src/api/v1/auth.py +++ b/src/api/v1/auth.py @@ -28,9 +28,9 @@ router = APIRouter(tags=["Authentication"], prefix="/auth") async def create_api_key( key_data: ApiKeyCreate, request: Request, + auth_service: AuthServiceDep, user_id: str = Query(..., description="User ID for the API key"), - team_id: str = Query(..., description="Team ID for the API key"), - auth_service: AuthServiceDep = Depends() + team_id: str = Query(..., description="Team ID for the API key") ): """ Create a new API key for a specific user and team @@ -61,8 +61,8 @@ async def create_api_key_for_user( user_id: str, key_data: ApiKeyCreate, request: Request, - current_user: UserModel = Depends(get_current_user), - auth_service: AuthServiceDep = Depends() + auth_service: AuthServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Create a new API key for a specific user (admin only) @@ -97,8 +97,8 @@ async def create_api_key_for_user( @router.get("/api-keys", response_model=ApiKeyListResponse) async def list_api_keys( request: Request, - current_user: UserModel = Depends(get_current_user), - auth_service: AuthServiceDep = Depends() + auth_service: AuthServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ List API keys for the current authenticated user @@ -125,8 +125,8 @@ async def list_api_keys( async def revoke_api_key( key_id: str, request: Request, - current_user: UserModel = Depends(get_current_user), - auth_service: AuthServiceDep = Depends() + auth_service: AuthServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Revoke (deactivate) an API key @@ -158,8 +158,8 @@ async def revoke_api_key( @router.get("/verify", status_code=status.HTTP_200_OK) async def verify_authentication( request: Request, - current_user: UserModel = Depends(get_current_user), - auth_service: AuthServiceDep = Depends() + auth_service: AuthServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Verify the current authentication status diff --git a/src/api/v1/images.py b/src/api/v1/images.py index ea8e927..703d631 100644 --- a/src/api/v1/images.py +++ b/src/api/v1/images.py @@ -25,11 +25,11 @@ router = APIRouter(tags=["Images"], prefix="/images") @router.post("", response_model=ImageResponse, status_code=status.HTTP_201_CREATED) async def upload_image( request: Request, + image_service: ImageServiceDep, file: UploadFile = File(..., description="Image file to upload"), description: Optional[str] = Query(None, description="Optional description for the image"), collection_id: Optional[str] = Query(None, description="Optional collection ID to associate with the image"), - current_user: UserModel = Depends(get_current_user), - image_service: ImageServiceDep = Depends() + current_user: UserModel = Depends(get_current_user) ): """ Upload a new image @@ -75,11 +75,11 @@ async def upload_image( @router.get("", response_model=ImageListResponse) async def list_images( request: Request, + image_service: ImageServiceDep, skip: int = Query(0, ge=0, description="Number of records to skip for pagination"), limit: int = Query(50, ge=1, le=100, description="Maximum number of records to return (1-100)"), collection_id: Optional[str] = Query(None, description="Filter by collection ID"), - current_user: UserModel = Depends(get_current_user), - image_service: ImageServiceDep = Depends() + current_user: UserModel = Depends(get_current_user) ): """ List images for the current user's team or all images if admin @@ -125,8 +125,8 @@ async def list_images( async def get_image( image_id: str, request: Request, - current_user: UserModel = Depends(get_current_user), - image_service: ImageServiceDep = Depends() + image_service: ImageServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Get image metadata by ID @@ -173,8 +173,8 @@ async def get_image( async def download_image( image_id: str, request: Request, - current_user: UserModel = Depends(get_current_user), - image_service: ImageServiceDep = Depends() + image_service: ImageServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Download image file @@ -229,8 +229,8 @@ async def update_image( image_id: str, image_data: ImageUpdate, request: Request, - current_user: UserModel = Depends(get_current_user), - image_service: ImageServiceDep = Depends() + image_service: ImageServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Update image metadata @@ -279,8 +279,8 @@ async def update_image( async def delete_image( image_id: str, request: Request, - current_user: UserModel = Depends(get_current_user), - image_service: ImageServiceDep = Depends() + image_service: ImageServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Delete an image diff --git a/src/api/v1/search.py b/src/api/v1/search.py index 19dc57b..5bc7294 100644 --- a/src/api/v1/search.py +++ b/src/api/v1/search.py @@ -22,12 +22,12 @@ router = APIRouter(tags=["Search"], prefix="/search") @router.get("", response_model=SearchResponse) async def search_images( request: Request, + search_service: SearchServiceDep, q: str = Query(..., description="Search query for semantic image search"), limit: int = Query(10, ge=1, le=50, description="Number of results to return (1-50)"), similarity_threshold: float = Query(0.65, ge=0.0, le=1.0, description="Similarity threshold (0.0-1.0)"), collection_id: Optional[str] = Query(None, description="Filter results by collection ID"), - current_user: UserModel = Depends(get_current_user), - search_service: SearchServiceDep = Depends() + current_user: UserModel = Depends(get_current_user) ): """ Search for images using semantic similarity @@ -83,8 +83,8 @@ async def search_images( async def search_images_advanced( search_request: SearchRequest, request: Request, - current_user: UserModel = Depends(get_current_user), - search_service: SearchServiceDep = Depends() + search_service: SearchServiceDep, + current_user: UserModel = Depends(get_current_user) ): """ Advanced search for images with extended options diff --git a/src/api/v1/teams.py b/src/api/v1/teams.py index ad7e5cb..ff8f2ad 100644 --- a/src/api/v1/teams.py +++ b/src/api/v1/teams.py @@ -20,7 +20,7 @@ router = APIRouter(tags=["Teams"], prefix="/teams") async def create_team( team_data: TeamCreate, request: Request, - team_service: TeamServiceDep = Depends() + team_service: TeamServiceDep ): """ Create a new team @@ -55,7 +55,7 @@ async def create_team( @router.get("", response_model=TeamListResponse) async def list_teams( request: Request, - team_service: TeamServiceDep = Depends() + team_service: TeamServiceDep ): """ List all teams @@ -89,7 +89,7 @@ async def list_teams( async def get_team( team_id: str, request: Request, - team_service: TeamServiceDep = Depends() + team_service: TeamServiceDep ): """ Get a team by ID @@ -126,7 +126,7 @@ async def update_team( team_id: str, team_data: TeamUpdate, request: Request, - team_service: TeamServiceDep = Depends() + team_service: TeamServiceDep ): """ Update a team @@ -164,7 +164,7 @@ async def update_team( async def delete_team( team_id: str, request: Request, - team_service: TeamServiceDep = Depends() + team_service: TeamServiceDep ): """ Delete a team diff --git a/src/api/v1/users.py b/src/api/v1/users.py index e11d18e..5ecd5e2 100644 --- a/src/api/v1/users.py +++ b/src/api/v1/users.py @@ -20,8 +20,8 @@ router = APIRouter(tags=["Users"], prefix="/users") @router.get("/me", response_model=UserResponse) async def read_users_me( request: Request, - user_id: str = Query(..., description="User ID to retrieve information for"), - user_service: UserServiceDep = Depends() + user_service: UserServiceDep, + user_id: str = Query(..., description="User ID to retrieve information for") ): """ Get user information by user ID @@ -62,8 +62,8 @@ async def read_users_me( async def update_current_user( user_data: UserUpdate, request: Request, - user_id: str = Query(..., description="User ID to update"), - user_service: UserServiceDep = Depends() + user_service: UserServiceDep, + user_id: str = Query(..., description="User ID to update") ): """ Update user information by user ID @@ -106,7 +106,7 @@ async def update_current_user( async def create_user( user_data: UserCreate, request: Request, - user_service: UserServiceDep = Depends() + user_service: UserServiceDep ): """ Create a new user @@ -146,8 +146,8 @@ async def create_user( @router.get("", response_model=UserListResponse) async def list_users( request: Request, - team_id: Optional[str] = Query(None, description="Filter users by team ID"), - user_service: UserServiceDep = Depends() + user_service: UserServiceDep, + team_id: Optional[str] = Query(None, description="Filter users by team ID") ): """ List users with optional team filtering @@ -187,7 +187,7 @@ async def list_users( async def get_user( user_id: str, request: Request, - user_service: UserServiceDep = Depends() + user_service: UserServiceDep ): """ Get user by ID @@ -228,7 +228,7 @@ async def update_user( user_id: str, user_data: UserUpdate, request: Request, - user_service: UserServiceDep = Depends() + user_service: UserServiceDep ): """ Update user by ID @@ -271,7 +271,7 @@ async def update_user( async def delete_user( user_id: str, request: Request, - user_service: UserServiceDep = Depends() + user_service: UserServiceDep ): """ Delete user by ID diff --git a/src/services/image_service.py b/src/services/image_service.py index 958e321..1ebb0e3 100644 --- a/src/services/image_service.py +++ b/src/services/image_service.py @@ -9,7 +9,7 @@ from src.models.image import ImageModel from src.models.user import UserModel from src.schemas.image import ImageResponse, ImageListResponse from src.db.repositories.image_repository import image_repository -from src.services.storage_service import StorageService +from src.services.storage import StorageService from src.services.embedding_service import EmbeddingService from src.utils.authorization import require_team_access, get_team_filter, AuthorizationError @@ -70,7 +70,7 @@ class ImageService: # Store file try: - self.storage_service.store_file(storage_path, file_content) + self.storage_service.store_file(storage_path, file_content, file.content_type) except Exception as e: logger.error(f"Failed to store file: {e}") raise RuntimeError("Failed to store image file") diff --git a/src/services/storage.py b/src/services/storage.py index e143208..5519c16 100644 --- a/src/services/storage.py +++ b/src/services/storage.py @@ -135,6 +135,44 @@ class StorageService: logger.error(f"Error uploading file: {e}") raise + def store_file(self, storage_path: str, content: bytes, content_type: Optional[str] = None) -> bool: + """ + Store raw bytes content to Google Cloud Storage + + Args: + storage_path: The storage path where the file should be stored + content: Raw bytes content to store + content_type: Optional content type for the file + + Returns: + True if file was stored successfully + + Raises: + Exception: If storage operation fails + """ + try: + # Create a blob in the bucket + blob = self.bucket.blob(storage_path) + + # Set content type if provided + if content_type: + blob.content_type = content_type + + # Set basic metadata + blob.metadata = { + 'upload_time': datetime.utcnow().isoformat(), + 'file_size': str(len(content)) + } + + # Upload the content + blob.upload_from_string(content, content_type=content_type) + + logger.info(f"File stored: {storage_path}") + return True + except Exception as e: + logger.error(f"Error storing file: {e}") + raise + def get_file(self, storage_path: str) -> Optional[bytes]: """ Get a file from Google Cloud Storage