File size: 6,291 Bytes
322d2b7
 
 
 
 
 
 
 
 
 
0ec5620
322d2b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0ec5620
322d2b7
 
 
0ec5620
322d2b7
 
 
 
0ec5620
 
 
 
 
 
322d2b7
0ec5620
322d2b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5c8a6b6
 
 
 
 
 
 
 
 
 
 
0ec5620
 
5c8a6b6
 
 
 
 
 
 
322d2b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0ec5620
322d2b7
 
 
 
 
 
 
0ec5620
322d2b7
 
 
 
 
0ec5620
 
322d2b7
0ec5620
322d2b7
0ec5620
 
322d2b7
 
0ec5620
 
322d2b7
 
 
 
0ec5620
322d2b7
 
 
0ec5620
 
 
322d2b7
 
 
0ec5620
 
 
 
 
322d2b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0ec5620
 
 
 
 
 
 
 
 
 
 
 
 
322d2b7
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
from .firebase_config import firebase_bucket
import base64
import os
import tempfile
from PIL import Image
import io
import asyncio
from typing import List, Optional
from datetime import datetime
import pytz
from src.utils.image_utils import base64_to_image


import asyncio
import functools


def upload_file_to_storage_sync(file_path, file_name):
    """
    Synchronous function to upload a file to Firebase Storage.

    param:
        file_path: str - The path of the file on the local machine to be uploaded.
        file_name: str - The name of the file in Firebase Storage.

    return:
        str - The public URL of the uploaded file.
    """
    blob = firebase_bucket.blob(file_name)
    blob.upload_from_filename(file_path)
    blob.make_public()

    return blob.public_url


async def upload_file_to_storage(file_path: str, file_name: str) -> str:
    """
    Asynchronous wrapper to upload a file to Firebase Storage using a thread pool.

    Args:
        file_path: str - The path of the file on the local machine to be uploaded.
        file_name: str - The name of the file in Firebase Storage.

    Returns:
        str - The public URL of the uploaded file.
    """
    loop = asyncio.get_event_loop()

    # Run the synchronous upload in a thread pool
    def upload_sync():
        blob = firebase_bucket.blob(file_name)
        blob.upload_from_filename(file_path)
        blob.make_public()
        return blob.public_url

    public_url = await loop.run_in_executor(None, upload_sync)
    return public_url


def delete_file_from_storage(file_name):
    """
    Delete a file from Firebase Storage
    param:
        file_name: str - The name of the file to be deleted
    return:
        bool - True if the file is deleted successfully, False if the file is not found
    """
    try:
        blob = firebase_bucket.blob(file_name)
        blob.delete()
        return True
    except Exception as e:
        print("Error:", e)
        return False


def delete_file_by_url(public_url):
    """
    Delete a file from Firebase Storage using its public URL
    param:
        public_url: str - The public URL of the file to be deleted
    return:
        bool - True if the file is deleted successfully, False if the file is not found
    """
    try:
        # Extract the file name from the public URL
        # URL format is typically: https://storage.googleapis.com/BUCKET_NAME/FILE_NAME
        file_name = public_url.split("/")[-1]

        # Delete the file using the extracted name
        return delete_file_from_storage(file_name)
    except Exception as e:
        print(f"Error deleting file by URL: {e}")
        return False


def list_all_files_in_storage():
    """
    View all files in Firebase Storage
    return:
        dict - Dictionary with keys are names and values are url of all files in Firebase Storage
    """
    blobs = firebase_bucket.list_blobs()
    blob_dict = {blob.name: blob.public_url for blob in blobs}
    return blob_dict


def download_file_from_storage(file_name, destination_path):
    """
    Download a file from Firebase Storage
    param:
        file_name: str - The name of the file to be downloaded
        destination_path: str - The path to save the downloaded file
    return:
        bool - True if the file is downloaded successfully, False if the file is not found
    """
    try:
        blob = firebase_bucket.blob(file_name)
        blob.download_to_filename(destination_path)
        print("da tai xun thanh cong")
        return True
    except Exception as e:
        print("Error:", e)
        return False


async def upload_base64_image_to_storage(
    base64_image: str, file_name: str, format: str = "JPEG"
) -> Optional[str]:
    """
    Upload a base64 image to Firebase Storage asynchronously.

    Args:
        base64_image: str - The base64 encoded image
        file_name: str - The name of the file to be uploaded
        format: str - The format to save the image in (JPEG, PNG, etc.)

    Returns:
        Optional[str] - The public URL of the uploaded file or None if failed
    """
    try:
        # Convert base64 to PIL Image
        image = base64_to_image(base64_image)

        # Create unique temp file path with appropriate extension
        temp_file_path = os.path.join(
            tempfile.gettempdir(),
            f"{file_name}_{datetime.now().timestamp()}.{format.lower()}",
        )

        # Save image in the specified format
        image.save(temp_file_path, format=format)

        try:
            # Upload to Firebase
            public_url = await upload_file_to_storage(
                temp_file_path, f"{file_name}.{format.lower()}"
            )
            return public_url
        finally:
            # Clean up temp file
            if os.path.exists(temp_file_path):
                os.remove(temp_file_path)

    except Exception as e:
        print(f"Error processing image {file_name}: {str(e)}")
        # If format is not JPEG, try again with JPEG
        if format.upper() != "JPEG":
            return await upload_base64_image_to_storage(
                base64_image, file_name, format="JPEG"
            )
        return None


async def process_images(base64_images: List[str]) -> List[Optional[str]]:
    """
    Process multiple base64 images concurrently.

    Args:
        base64_images: List[str] - List of base64 encoded images

    Returns:
        List[Optional[str]] - List of public URLs or None for failed uploads
    """
    tasks = []
    for idx, base64_image in enumerate(base64_images):
        timestamp = (
            datetime.now(pytz.timezone("Asia/Ho_Chi_Minh"))
            .replace(tzinfo=None)
            .strftime("%Y-%m-%d_%H-%M-%S")
        )
        file_name = f"image_{timestamp}_{idx}"

        # Determine format from base64 header or default to JPEG
        format = "JPEG"
        if "data:image/" in base64_image:
            mime_type = base64_image.split(";")[0].split("/")[1]
            if mime_type == "png":
                format = "PNG"
            elif mime_type == "webp":
                format = "WEBP"

        tasks.append(
            upload_base64_image_to_storage(base64_image, file_name, format=format)
        )

    return await asyncio.gather(*tasks, return_exceptions=True)