Skip to content

Commit 1b8c4d6

Browse files
Merge pull request #13 from GoogleCloudPlatform/feature/frontend-workbench
Feature/workbench added
2 parents 6dc76e8 + ca42e53 commit 1b8c4d6

36 files changed

+1942
-48
lines changed

backend/src/common/base_dto.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ class MimeTypeEnum(str, Enum):
2525
IMAGE_PNG = "image/png"
2626
VIDEO_MP4 = "video/mp4"
2727
AUDIO_WAV = "audio/wav"
28+
AUDIO_MPEG = "audio/mpeg"
29+
AUDIO_MP3 = "audio/mp3"
30+
AUDIO_OGG = "audio/ogg"
31+
AUDIO_WEBM = "audio/webm"
32+
33+
34+
class WildcardMimeTypeEnum(str, Enum):
35+
"""Wildcard MIME types for search filtering."""
36+
37+
IMAGE_WILDCARD = "image/*"
38+
VIDEO_WILDCARD = "video/*"
39+
AUDIO_WILDCARD = "audio/*"
2840

2941

3042
class GenerationModelEnum(str, Enum):
@@ -156,4 +168,4 @@ class BaseDto(BaseModel):
156168
extra="forbid",
157169
populate_by_name=True,
158170
from_attributes=True,
159-
)
171+
)

backend/src/galleries/dto/gallery_search_dto.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Optional
15+
from typing import Optional, Union
1616

1717
from pydantic import Field
1818

19-
from src.common.base_dto import GenerationModelEnum, MimeTypeEnum
19+
from src.common.base_dto import GenerationModelEnum, MimeTypeEnum, WildcardMimeTypeEnum
2020
from src.common.dto.base_search_dto import BaseSearchDto
2121
from src.common.schema.media_item_model import JobStatusEnum
2222
from src.galleries.dto.gallery_response_dto import MediaItemResponse
2323

2424

2525
class GallerySearchDto(BaseSearchDto):
2626
user_email: Optional[str] = None
27-
mime_type: Optional[MimeTypeEnum] = None
27+
mime_type: Optional[Union[MimeTypeEnum, WildcardMimeTypeEnum]] = None
2828
model: Optional[GenerationModelEnum] = None
2929
status: Optional[JobStatusEnum] = None
3030
workspace_id: int = Field(

backend/src/images/repository/media_item_repository.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@ async def query(
4545
query = query.where(self.model.user_email == search_dto.user_email)
4646

4747
if search_dto.mime_type:
48-
query = query.where(self.model.mime_type == search_dto.mime_type.value)
48+
if search_dto.mime_type.value.endswith("/*"):
49+
# Handle wildcard search (e.g., "image/*")
50+
prefix = search_dto.mime_type.value[:-1] # Remove the "*"
51+
query = query.where(self.model.mime_type.like(f"{prefix}%"))
52+
else:
53+
# Handle exact match
54+
query = query.where(self.model.mime_type == search_dto.mime_type.value)
4955

5056
if search_dto.model:
5157
query = query.where(self.model.model == search_dto.model.value)

backend/src/source_assets/repository/source_asset_repository.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,17 @@ async def query(
6363

6464
# Apply filters
6565
if search_dto.mime_type:
66-
if search_dto.mime_type.endswith("image/*"):
67-
# Handle wildcard prefix search
68-
# In SQL, we can use LIKE 'image/%'
69-
# But the original code did "!=" "video/mp4" which is weird for "image/*"
70-
# Let's assume we want to match "image/%"
66+
if search_dto.mime_type == "image/*":
67+
# Filter for all image types using SQL LIKE
7168
query = query.where(self.model.mime_type.like("image/%"))
69+
elif search_dto.mime_type == "video/*":
70+
# Filter for all video types
71+
query = query.where(self.model.mime_type.like("video/%"))
72+
elif search_dto.mime_type == "audio/*":
73+
# Filter for all audio types
74+
query = query.where(self.model.mime_type.like("audio/%"))
7275
else:
76+
# Exact match for specific mime types like "image/png"
7377
query = query.where(self.model.mime_type == search_dto.mime_type)
7478

7579
if target_user_id:
@@ -184,4 +188,4 @@ async def find_system_and_private_assets_by_types(
184188
.where(self.model.asset_type.in_([t.value for t in asset_types]))
185189
)
186190
assets = result.scalars().all()
187-
return [self.schema.model_validate(asset) for asset in assets]
191+
return [self.schema.model_validate(asset) for asset in assets]

backend/src/source_assets/source_asset_service.py

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,13 @@ async def upload_asset(
189189
)
190190
return await self._create_asset_response(existing_asset)
191191

192-
# 2. Handle file processing based on type (image vs. video)
192+
# 2. Handle file processing based on type (image vs. video vs. audio)
193193
is_video: bool = bool(
194194
file.content_type and "video" in file.content_type
195195
)
196+
is_audio: bool = bool(
197+
file.content_type and "audio" in file.content_type
198+
)
196199
final_gcs_uri: Optional[str] = None
197200
thumbnail_gcs_uri: Optional[str] = None
198201
temp_dir = f"temp/source_assets/{uuid.uuid4()}"
@@ -230,6 +233,23 @@ async def upload_asset(
230233
destination_blob_name=f"source_assets/{user.id}/{file_hash}/thumbnail.png",
231234
mime_type="image/png",
232235
)
236+
elif is_audio:
237+
# --- Audio Upload Logic ---
238+
# Audio files don't need image processing or aspect ratio
239+
final_aspect_ratio = aspect_ratio or AspectRatioEnum.RATIO_1_1
240+
241+
# Determine audio mime type
242+
audio_mime = file.content_type or "audio/mpeg"
243+
file_extension = os.path.splitext(file.filename or "audio.mp3")[1] or ".mp3"
244+
245+
# Upload the audio file directly
246+
final_gcs_uri = self.gcs_service.store_to_gcs(
247+
folder=f"source_assets/{user.id}/audio",
248+
file_name=f"{file_hash}{file_extension}",
249+
mime_type=audio_mime,
250+
contents=contents,
251+
decode=False,
252+
)
233253
else:
234254
# --- Image Upload & Upscale Logic ---
235255
# Check for valid aspect ratio early in the process
@@ -334,11 +354,25 @@ async def upload_asset(
334354
shutil.rmtree(temp_dir)
335355

336356
# 4. Create and save the new UserAsset document
337-
mime_type: MimeTypeEnum = (
338-
MimeTypeEnum.VIDEO_MP4
339-
if file.content_type == MimeTypeEnum.VIDEO_MP4
340-
else MimeTypeEnum.IMAGE_PNG
341-
)
357+
# Determine mime_type based on content_type
358+
content_type = file.content_type or ""
359+
if content_type.startswith("video/"):
360+
mime_type = MimeTypeEnum.VIDEO_MP4
361+
elif content_type.startswith("audio/"):
362+
# Map common audio types to enum values
363+
if content_type in ["audio/mpeg", "audio/mp3"]:
364+
mime_type = MimeTypeEnum.AUDIO_MPEG
365+
elif content_type == "audio/wav":
366+
mime_type = MimeTypeEnum.AUDIO_WAV
367+
elif content_type == "audio/ogg":
368+
mime_type = MimeTypeEnum.AUDIO_OGG
369+
elif content_type == "audio/webm":
370+
mime_type = MimeTypeEnum.AUDIO_WEBM
371+
else:
372+
# Default to MPEG for unknown audio types
373+
mime_type = MimeTypeEnum.AUDIO_MPEG
374+
else:
375+
mime_type = MimeTypeEnum.IMAGE_PNG
342376

343377
is_admin = UserRoleEnum.ADMIN in user.roles
344378
final_scope = AssetScopeEnum.PRIVATE
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 10 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)