userIdc2024 commited on
Commit
3c2b4ae
·
verified ·
1 Parent(s): 332be4e

Upload 3 files

Browse files
helpers_function/helper_email.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import smtplib
3
+ from email.mime.multipart import MIMEMultipart
4
+ from email.mime.text import MIMEText
5
+
6
+ from core.settings import cnf
7
+ from database.connections import get_mongo_client
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def _send_email(to_email: str, subject: str, body: str) -> bool:
13
+ """Low-level Gmail SMTP email sender."""
14
+ try:
15
+ SMTP_SERVER = "smtp.gmail.com"
16
+ SMTP_PORT = 587
17
+ EMAIL_USER = cnf.EMAIL_USER
18
+ EMAIL_PASS = cnf.EMAIL_PASS
19
+
20
+ if not all([to_email, subject, body, EMAIL_USER, EMAIL_PASS]):
21
+ logger.error("Missing required email parameters")
22
+ return False
23
+
24
+ msg = MIMEMultipart()
25
+ msg["From"] = EMAIL_USER
26
+ msg["To"] = to_email
27
+ msg["Subject"] = subject
28
+ msg.attach(MIMEText(body, "plain"))
29
+
30
+ with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
31
+ server.starttls()
32
+ server.login(EMAIL_USER, EMAIL_PASS)
33
+ server.sendmail(EMAIL_USER, to_email, msg.as_string())
34
+
35
+ logger.info(f"Email sent to {to_email}")
36
+ return True
37
+ except Exception as e:
38
+ logger.error(f"Failed to send email: {e}")
39
+ return False
40
+
41
+
42
+ def all_tasks_completed_notification(user_email: str, product_name: str) -> bool:
43
+ """
44
+ Send success email if the user has completed image, script, and video tasks.
45
+ """
46
+ db = get_mongo_client()
47
+ if db is None:
48
+ logger.error("MongoDB not available for notifications")
49
+ return False
50
+
51
+ has_image = db["results"].count_documents({"created_by": user_email, "type": {"$in": ["generation", "variation"]}}) > 0
52
+ has_script = db["script_generator"].count_documents({"created_by": user_email}) > 0
53
+ has_video = db["video_analyses"].count_documents({"created_by": user_email}) > 0
54
+
55
+
56
+ if has_image and has_script and has_video:
57
+ body = f"""Hey {user_email},
58
+
59
+ 🎉 Congratulations!
60
+
61
+ You have successfully:
62
+ - Generated Images
63
+ - Generated Scripts
64
+ - Analyzed Videos
65
+
66
+ Your work for **{product_name}** has been completed successfully.
67
+ You can now review all assets in the AI Library.
68
+
69
+ Best regards,
70
+ The Creative AdGenesis Team
71
+ """
72
+ return _send_email(user_email, "All Tasks Completed Successfully ", body)
73
+
74
+ logger.info(f"Tasks not fully completed for {user_email}")
75
+ return False
helpers_function/helper_meta_data.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import piexif
3
+ from PIL import Image
4
+ from io import BytesIO
5
+
6
+ def generate_metadata(model):
7
+ # Define different values based on iPhone model
8
+ exposure_times = {
9
+ "iPhone 11": "1/60",
10
+ "iPhone 11 Pro": "1/70",
11
+ "iPhone 12": "1/100",
12
+ "iPhone 12 Pro": "1/110",
13
+ "iPhone 13": "1/120",
14
+ "iPhone 13 Pro": "1/130",
15
+ "iPhone 13 Pro Max": "1/140",
16
+ "iPhone 14": "1/200",
17
+ "iPhone 14 Pro": "1/220",
18
+ "iPhone 14 Pro Max": "1/240",
19
+ "iPhone 15": "1/300",
20
+ "iPhone 15 Plus": "1/320",
21
+ "iPhone 15 Pro": "1/400",
22
+ "iPhone 15 Pro Max": "1/500",
23
+ "iPhone 16": "1/600",
24
+ "iPhone 16 Pro": "1/700",
25
+ "iPhone 16 Pro Max": "1/1000"
26
+ }
27
+ f_numbers = {
28
+ "iPhone 11": "f/1.8",
29
+ "iPhone 11 Pro": "f/1.8",
30
+ "iPhone 12": "f/1.6",
31
+ "iPhone 12 Pro": "f/1.6",
32
+ "iPhone 13": "f/1.5",
33
+ "iPhone 13 Pro": "f/1.5",
34
+ "iPhone 13 Pro Max": "f/1.5",
35
+ "iPhone 14": "f/1.4",
36
+ "iPhone 14 Pro": "f/1.4",
37
+ "iPhone 14 Pro Max": "f/1.4",
38
+ "iPhone 15": "f/1.4",
39
+ "iPhone 15 Plus": "f/1.4",
40
+ "iPhone 15 Pro": "f/1.4",
41
+ "iPhone 15 Pro Max": "f/1.3",
42
+ "iPhone 16": "f/1.3",
43
+ "iPhone 16 Pro": "f/1.3",
44
+ "iPhone 16 Pro Max": "f/1.3"
45
+ }
46
+ focal_lengths = {
47
+ "iPhone 11": "3.99 mm",
48
+ "iPhone 11 Pro": "4.0 mm",
49
+ "iPhone 12": "4.2 mm",
50
+ "iPhone 12 Pro": "4.3 mm",
51
+ "iPhone 13": "5.0 mm",
52
+ "iPhone 13 Pro": "5.1 mm",
53
+ "iPhone 13 Pro Max": "5.2 mm",
54
+ "iPhone 14": "6.0 mm",
55
+ "iPhone 14 Pro": "6.1 mm",
56
+ "iPhone 14 Pro Max": "6.2 mm",
57
+ "iPhone 15": "6.0 mm",
58
+ "iPhone 15 Plus": "6.1 mm",
59
+ "iPhone 15 Pro": "6.1 mm",
60
+ "iPhone 15 Pro Max": "6.2 mm",
61
+ "iPhone 16": "6.5 mm",
62
+ "iPhone 16 Pro": "6.6 mm",
63
+ "iPhone 16 Pro Max": "6.7 mm"
64
+ }
65
+
66
+ metadata = {
67
+ "Make": "Apple",
68
+ "Model": model,
69
+ "Software": "iOS {}".format(random.choice([14, 15, 16, 17, 18, 19])),
70
+ "Orientation": random.choice(["Horizontal (normal)", "Rotate 90 CW", "Rotate 180", "Rotate 90 CCW"]),
71
+ "DateTime": "{}:{}:{} {:02}:{:02}:{:02}".format(random.randint(2022, 2024), random.randint(1, 12), random.randint(1, 28), random.randint(0, 23), random.randint(0, 59), random.randint(0, 59)),
72
+ "ExposureTime": exposure_times[model],
73
+ "FNumber": f_numbers[model],
74
+ "ISOSpeedRatings": random.choice([100, 200, 400, 800, 1600]),
75
+ "FocalLength": focal_lengths[model],
76
+ "Flash": random.choice(["Flash fired", "Flash did not fire, compulsory mode", "Flash fired, auto mode"]),
77
+ "WhiteBalance": random.choice(["Auto", "Manual"]),
78
+ "MeteringMode": random.choice(["Pattern", "CenterWeightedAverage", "Spot"]),
79
+ "SceneCaptureType": random.choice(["Standard", "Landscape", "Portrait", "NightScene"]),
80
+ "GPSLatitude": "{:.4f} N".format(random.uniform(0.0, 90.0)),
81
+ "GPSLongitude": "{:.4f} W".format(random.uniform(0.0, 180.0)),
82
+ "Altitude": "{:.1f} m".format(random.uniform(0, 100)),
83
+ "LensMake": "Apple",
84
+ "LensModel": "{} back triple camera {} f/1.5".format(model, focal_lengths[model]),
85
+ "ColorSpace": random.choice(["sRGB", "Adobe RGB"]),
86
+ "PixelXDimension": random.choice([3024, 4032, 2160]),
87
+ "PixelYDimension": random.choice([3024, 4032, 2160]),
88
+ "ExposureBiasValue": random.choice(["0 EV", "+1 EV", "-1 EV"]),
89
+ "BrightnessValue": "{:.1f}".format(random.uniform(-5, 10)),
90
+ "ExposureMode": random.choice(["Auto Exposure", "Manual Exposure"])
91
+ }
92
+ return metadata
93
+
94
+ def dms_coordinates(value):
95
+ """Convert decimal degrees to EXIF GPS (DMS format)."""
96
+ degrees = int(value)
97
+ minutes_float = (value - degrees) * 60
98
+ minutes = int(minutes_float)
99
+ seconds = round((minutes_float - minutes) * 60 * 10000)
100
+ return [(degrees, 1), (minutes, 1), (seconds, 10000)]
101
+
102
+ def meta_data_helper_function(image_bytes,model=None):
103
+ """
104
+ Takes raw image bytes, adds realistic EXIF metadata, and returns new bytes.
105
+ """
106
+ if model is None:
107
+ model = random.choice([
108
+ "iPhone 11", "iPhone 11 Pro", "iPhone 12", "iPhone 12 Pro",
109
+ "iPhone 13", "iPhone 13 Pro", "iPhone 13 Pro Max", "iPhone 14",
110
+ "iPhone 14 Pro", "iPhone 14 Pro Max", "iPhone 15", "iPhone 15 Plus",
111
+ "iPhone 15 Pro", "iPhone 15 Pro Max", "iPhone 16", "iPhone 16 Pro",
112
+ "iPhone 16 Pro Max"
113
+ ])
114
+
115
+ # Load image from bytes
116
+ img = Image.open(BytesIO(image_bytes))
117
+ img = img.convert("RGB") # Ensure compatibility
118
+
119
+ # Generate metadata
120
+ metadata = generate_metadata(model)
121
+
122
+ # Build EXIF data
123
+ exif_dict = {"0th": {}, "Exif": {}, "GPS": {}}
124
+
125
+ exif_dict["0th"][piexif.ImageIFD.Make] = metadata["Make"]
126
+ exif_dict["0th"][piexif.ImageIFD.Model] = metadata["Model"]
127
+ exif_dict["0th"][piexif.ImageIFD.Software] = metadata["Software"]
128
+ exif_dict["0th"][piexif.ImageIFD.DateTime] = metadata["DateTime"]
129
+
130
+ # Exposure time (rational)
131
+ num, den = map(int, metadata["ExposureTime"].split("/"))
132
+ exif_dict["Exif"][piexif.ExifIFD.ExposureTime] = (num, den)
133
+
134
+ # FNumber
135
+ f_number = float(metadata["FNumber"].replace("f/", ""))
136
+ exif_dict["Exif"][piexif.ExifIFD.FNumber] = (int(f_number * 10), 10)
137
+
138
+ # ISO
139
+ exif_dict["Exif"][piexif.ExifIFD.ISOSpeedRatings] = metadata["ISOSpeedRatings"]
140
+
141
+ # Focal Length
142
+ focal_length = float(metadata["FocalLength"].split()[0])
143
+ exif_dict["Exif"][piexif.ExifIFD.FocalLength] = (int(focal_length * 10), 10)
144
+
145
+ # GPS
146
+ lat = float(metadata["GPSLatitude"].split()[0])
147
+ lon = float(metadata["GPSLongitude"].split()[0])
148
+
149
+ exif_dict["GPS"][piexif.GPSIFD.GPSLatitudeRef] = b'N' if lat >= 0 else b'S'
150
+ exif_dict["GPS"][piexif.GPSIFD.GPSLatitude] = dms_coordinates(abs(lat))
151
+
152
+ exif_dict["GPS"][piexif.GPSIFD.GPSLongitudeRef] = b'E' if lon >= 0 else b'W'
153
+ exif_dict["GPS"][piexif.GPSIFD.GPSLongitude] = dms_coordinates(abs(lon))
154
+
155
+ altitude_value = float(metadata["Altitude"].replace(" m", ""))
156
+ exif_dict["GPS"][piexif.GPSIFD.GPSAltitude] = (int(altitude_value), 1)
157
+
158
+
159
+ # Dump to bytes
160
+ exif_bytes = piexif.dump(exif_dict)
161
+
162
+ # Save to in-memory buffer
163
+ output_io = BytesIO()
164
+ img.save(output_io, format="JPEG", exif=exif_bytes)
165
+ return output_io.getvalue()
166
+
helpers_function/helpers.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import boto3
2
+ from uuid import uuid4
3
+ import os
4
+
5
+ import cv2
6
+ import base64
7
+ import logging
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ def get_video_thumbnail_base64(video_path: str, time_sec: int = 1) -> str:
12
+ try:
13
+ cap = cv2.VideoCapture(video_path)
14
+ cap.set(cv2.CAP_PROP_POS_MSEC, time_sec * 1000)
15
+ success, frame = cap.read()
16
+ cap.release()
17
+ if not success:
18
+ return ""
19
+ _, buffer = cv2.imencode(".jpg", frame)
20
+ return base64.b64encode(buffer).decode("utf-8")
21
+ except Exception:
22
+ logger.exception("Thumbnail extraction failed")
23
+ return ""
24
+
25
+
26
+ log = logging.getLogger(__name__)
27
+
28
+ def upload_image_to_r2(image_bytes, folder_name="search_arb", app_type="bulk_generation"):
29
+ try:
30
+ s3 = boto3.client(
31
+ "s3",
32
+ endpoint_url=os.getenv('R2_ENDPOINT'),
33
+ aws_access_key_id=os.getenv('R2_ACCESS_KEY'),
34
+ aws_secret_access_key=os.getenv('R2_SECRET_KEY'),
35
+ region_name="auto"
36
+ )
37
+ filename = f"{uuid4().hex}.png"
38
+ file_key = f"hug_face/{app_type.strip('/')}/{folder_name.strip('/')}/{filename}" if folder_name else f"hug_face/{app_type.strip('/')}/{filename}"
39
+ s3.put_object(Bucket=os.getenv('R2_BUCKET_NAME'), Key=file_key, Body=image_bytes, ContentType="image/png")
40
+ return f"{os.getenv('NEW_BASE').rstrip('/')}/{file_key}"
41
+ except Exception as e:
42
+ log.error(e)
43
+ return None
44
+
45
+
46
+ def encode_image_to_base64(image_path: str) -> str:
47
+ with open(image_path, "rb") as f:
48
+ return base64.b64encode(f.read()).decode("utf-8")
49
+
50
+ def is_valid_image(file_name: str) -> bool:
51
+ return file_name.lower().endswith((".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp"))
52
+
53
+ def _mean_effectiveness(metrics):
54
+ if not metrics: return 0.0
55
+ scores = []
56
+ for m in metrics:
57
+ s = str(m.get("effectiveness_score", "0/10")).split("/")[0]
58
+ try: scores.append(int(s))
59
+ except Exception: pass
60
+ return round(sum(scores) / len(scores), 2) if scores else 0.0
61
+