Upload folder using huggingface_hub
Browse files
README.md
CHANGED
@@ -4,7 +4,6 @@ emoji: 😁
|
|
4 |
colorFrom: indigo
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 5.25.2
|
8 |
app_file: app.py
|
9 |
pinned: true
|
10 |
---
|
@@ -21,6 +20,9 @@ A simple, user-friendly application that uses Google's Gemini AI to enhance smil
|
|
21 |
- Maintains each person's unique smile features and tooth coloration
|
22 |
- Enhances eye crinkles and cheek raising for authentic expressions
|
23 |
- Preserves facial identity while enhancing smiles
|
|
|
|
|
|
|
24 |
- Works with most portrait photos showing visible teeth
|
25 |
- No API key or login required
|
26 |
|
@@ -28,4 +30,15 @@ A simple, user-friendly application that uses Google's Gemini AI to enhance smil
|
|
28 |
|
29 |
1. Upload a clear selfie with a visible smile
|
30 |
2. Click "Enhance Smile with Natural Expressions" to process your image
|
31 |
-
3. Download your enhanced smile image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
colorFrom: indigo
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
|
|
7 |
app_file: app.py
|
8 |
pinned: true
|
9 |
---
|
|
|
20 |
- Maintains each person's unique smile features and tooth coloration
|
21 |
- Enhances eye crinkles and cheek raising for authentic expressions
|
22 |
- Preserves facial identity while enhancing smiles
|
23 |
+
- Multi-attempt enhancement that compares results to select the best outcome
|
24 |
+
- Intelligent backend processing that may run multiple enhancement passes for better results
|
25 |
+
- Results may improve or degrade across multiple attempts as the system learns what works best
|
26 |
- Works with most portrait photos showing visible teeth
|
27 |
- No API key or login required
|
28 |
|
|
|
30 |
|
31 |
1. Upload a clear selfie with a visible smile
|
32 |
2. Click "Enhance Smile with Natural Expressions" to process your image
|
33 |
+
3. Download your enhanced smile image
|
34 |
+
|
35 |
+
## How It Works
|
36 |
+
|
37 |
+
This application uses an advanced process that may run multiple enhancement attempts to achieve the best results:
|
38 |
+
|
39 |
+
- The first enhancement attempt might not always be the best result
|
40 |
+
- Our system intelligently runs multiple passes on your image (up to 3 attempts)
|
41 |
+
- Each attempt is assessed and compared to find the highest quality enhancement
|
42 |
+
- The best result is automatically selected and presented to you
|
43 |
+
|
44 |
+
Please note that results may vary as we haven't provided the system with extensive example data. Sometimes later attempts produce better results, while in other cases earlier attempts may be superior. The system intelligently selects the best outcome from all attempts.
|
app.py
CHANGED
@@ -13,8 +13,7 @@ from google.genai import types
|
|
13 |
|
14 |
def save_binary_file(file_name, data):
|
15 |
with open(file_name, "wb") as f:
|
16 |
-
f.write(data
|
17 |
-
)
|
18 |
|
19 |
def generate(text, file_name, api_key, model="gemini-2.0-flash-exp"):
|
20 |
# Initialize client using provided api_key (or fallback to env variable)
|
@@ -139,7 +138,32 @@ def assess_image_quality(original_image, enhanced_image):
|
|
139 |
# Default to not accepting the image if assessment fails
|
140 |
return False, f"Assessment error: {str(e)}"
|
141 |
|
142 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
try:
|
144 |
if input_image is None:
|
145 |
return None, "", ""
|
@@ -158,9 +182,9 @@ def process_smile_enhancement(input_image, max_attempts=2):
|
|
158 |
|
159 |
# Initialize attempt counter and result variables
|
160 |
current_attempt = 0
|
161 |
-
|
162 |
feedback_history = []
|
163 |
-
max_processing_time =
|
164 |
start_processing_time = time.time()
|
165 |
|
166 |
while current_attempt < max_attempts:
|
@@ -175,32 +199,32 @@ def process_smile_enhancement(input_image, max_attempts=2):
|
|
175 |
# Create a comprehensive prompt for true smile enhancement that affects facial features naturally
|
176 |
# Adjust prompt based on previous attempts if needed
|
177 |
prompt = """
|
178 |
-
Create a naturally enhanced smile that
|
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 |
# If not the first attempt, add previous feedback to the prompt
|
@@ -233,28 +257,32 @@ def process_smile_enhancement(input_image, max_attempts=2):
|
|
233 |
if image_path:
|
234 |
# Load and convert the image if needed
|
235 |
try:
|
236 |
-
|
237 |
-
if
|
238 |
-
|
239 |
|
240 |
-
print("Successfully loaded generated image")
|
241 |
|
242 |
# Assess the quality of the enhanced image
|
243 |
-
is_acceptable, assessment_feedback = assess_image_quality(input_image,
|
244 |
print(f"Image quality assessment: {is_acceptable}, {assessment_feedback}")
|
245 |
|
246 |
if is_acceptable:
|
247 |
-
#
|
248 |
-
|
249 |
-
|
|
|
|
|
|
|
|
|
|
|
250 |
else:
|
251 |
# Image didn't pass quality assessment, add feedback for next attempt
|
252 |
feedback_history.append(assessment_feedback)
|
253 |
|
254 |
-
#
|
255 |
-
|
256 |
-
|
257 |
-
return [result_img], "", ""
|
258 |
except Exception as img_error:
|
259 |
print(f"Error processing the generated image: {str(img_error)}")
|
260 |
feedback_history.append(f"Error with image: {str(img_error)}")
|
@@ -262,22 +290,24 @@ def process_smile_enhancement(input_image, max_attempts=2):
|
|
262 |
# No image was generated, only text response
|
263 |
print("No image was generated, only text response")
|
264 |
feedback_history.append("No image was generated in the previous attempt.")
|
265 |
-
|
266 |
-
# If we've reached max attempts, return the original image
|
267 |
-
if current_attempt >= max_attempts:
|
268 |
-
print("Max attempts reached, returning original image")
|
269 |
-
return [input_image], "", ""
|
270 |
except Exception as gen_error:
|
271 |
print(f"Error during generation attempt {current_attempt}: {str(gen_error)}")
|
272 |
feedback_history.append(f"Error during processing: {str(gen_error)}")
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
|
278 |
# Return the original image as a fallback without messages
|
279 |
-
print("Returning original image as fallback")
|
280 |
-
return [input_image], "", ""
|
281 |
except Exception as e:
|
282 |
# Return the original image silently on error
|
283 |
print(f"Overall error in process_smile_enhancement: {str(e)}")
|
|
|
13 |
|
14 |
def save_binary_file(file_name, data):
|
15 |
with open(file_name, "wb") as f:
|
16 |
+
f.write(data)
|
|
|
17 |
|
18 |
def generate(text, file_name, api_key, model="gemini-2.0-flash-exp"):
|
19 |
# Initialize client using provided api_key (or fallback to env variable)
|
|
|
138 |
# Default to not accepting the image if assessment fails
|
139 |
return False, f"Assessment error: {str(e)}"
|
140 |
|
141 |
+
def compare_image_results(results_list):
|
142 |
+
"""
|
143 |
+
Compares multiple generated images and returns the best one.
|
144 |
+
If no valid results, returns None.
|
145 |
+
"""
|
146 |
+
if not results_list or all(img is None for img in results_list):
|
147 |
+
return None
|
148 |
+
|
149 |
+
# Filter out None values
|
150 |
+
valid_results = [img for img in results_list if img is not None]
|
151 |
+
|
152 |
+
if not valid_results:
|
153 |
+
return None
|
154 |
+
|
155 |
+
# If there's only one valid result, return it
|
156 |
+
if len(valid_results) == 1:
|
157 |
+
return valid_results[0]
|
158 |
+
|
159 |
+
# For now, we just return the last valid result
|
160 |
+
# In a more advanced implementation, this could use computer vision techniques
|
161 |
+
# to analyze facial features, smile quality, and natural appearance
|
162 |
+
|
163 |
+
print(f"Comparing {len(valid_results)} valid results and selecting best one")
|
164 |
+
return valid_results[-1] # Return the last attempt as potentially the best one
|
165 |
+
|
166 |
+
def process_smile_enhancement(input_image, max_attempts=3):
|
167 |
try:
|
168 |
if input_image is None:
|
169 |
return None, "", ""
|
|
|
182 |
|
183 |
# Initialize attempt counter and result variables
|
184 |
current_attempt = 0
|
185 |
+
result_images = [] # Store all generated images for comparison
|
186 |
feedback_history = []
|
187 |
+
max_processing_time = 150 # Maximum time in seconds for overall processing
|
188 |
start_processing_time = time.time()
|
189 |
|
190 |
while current_attempt < max_attempts:
|
|
|
199 |
# Create a comprehensive prompt for true smile enhancement that affects facial features naturally
|
200 |
# Adjust prompt based on previous attempts if needed
|
201 |
prompt = """
|
202 |
+
Create a naturally enhanced smile that focuses primarily on the overall facial expression rather than perfect teeth. Make the following personalized improvements:
|
203 |
+
|
204 |
+
- Focus on enhancing the OVERALL SMILE EXPRESSION with natural eye crinkles, cheeks, and subtle facial changes
|
205 |
+
- Create authentic "Duchenne smile" characteristics with proper eye corner crinkles (crow's feet) appropriate for this person's age
|
206 |
+
- Enhance the natural lifting of cheeks that occurs in genuine smiles WITHOUT widening the face
|
207 |
+
- Add the characteristic slight narrowing of the eyes that happens in genuine smiles
|
208 |
+
- Create subtle dimples ONLY if they already exist in the original image
|
209 |
+
- Boost the overall joyful expression while maintaining the person's unique facial structure
|
210 |
+
- Maintain natural-looking nasolabial folds (smile lines) consistent with the smile intensity
|
211 |
+
- Subtly complement existing teeth - they should remain natural looking with their original character
|
212 |
+
|
213 |
+
IMPORTANT GUIDELINES:
|
214 |
+
- FOCUS ON THE SMILE AS A COMPLETE FACIAL EXPRESSION - not just teeth
|
215 |
+
- The most important aspects are eye crinkles, cheek raising, and natural facial expressions
|
216 |
+
- Teeth should be subtly complemented but NOT the main focus of the enhancement
|
217 |
+
- PRESERVE THE PERSON'S NATURAL DENTAL CHARACTERISTICS - teeth should look like THEIR teeth
|
218 |
+
- Keep teeth coloration natural and appropriate for the person - avoid any artificial whitening
|
219 |
+
- Maintain all natural imperfections in tooth alignment that give character to the smile
|
220 |
+
- Create a genuine, authentic-looking smile that affects the entire face naturally
|
221 |
+
- ABSOLUTELY CRITICAL: DO NOT widen the face or change face width/shape at all
|
222 |
+
- Preserve the person's identity completely (extremely important)
|
223 |
+
- Preserve exact facial proportions of the original image
|
224 |
+
- Maintain natural-looking results appropriate for the person's age and face structure
|
225 |
+
- Keep the original background, lighting, and image quality intact
|
226 |
+
- Ensure the enhanced smile looks natural, genuine, and believable
|
227 |
+
- Create a smile that looks like a moment of true happiness for THIS specific person
|
228 |
"""
|
229 |
|
230 |
# If not the first attempt, add previous feedback to the prompt
|
|
|
257 |
if image_path:
|
258 |
# Load and convert the image if needed
|
259 |
try:
|
260 |
+
current_result = Image.open(image_path)
|
261 |
+
if current_result.mode == "RGBA":
|
262 |
+
current_result = current_result.convert("RGB")
|
263 |
|
264 |
+
print("Successfully loaded generated image for attempt " + str(current_attempt))
|
265 |
|
266 |
# Assess the quality of the enhanced image
|
267 |
+
is_acceptable, assessment_feedback = assess_image_quality(input_image, current_result)
|
268 |
print(f"Image quality assessment: {is_acceptable}, {assessment_feedback}")
|
269 |
|
270 |
if is_acceptable:
|
271 |
+
# Store the acceptable result for later comparison
|
272 |
+
result_images.append(current_result)
|
273 |
+
print(f"Added acceptable result from attempt {current_attempt} to results list")
|
274 |
+
|
275 |
+
# Continue with additional attempts to potentially get even better results
|
276 |
+
if current_attempt < max_attempts:
|
277 |
+
feedback_history.append("Previous attempt successful, trying to further improve...")
|
278 |
+
continue
|
279 |
else:
|
280 |
# Image didn't pass quality assessment, add feedback for next attempt
|
281 |
feedback_history.append(assessment_feedback)
|
282 |
|
283 |
+
# Still store the result for potential use if no better options are found
|
284 |
+
result_images.append(current_result)
|
285 |
+
|
|
|
286 |
except Exception as img_error:
|
287 |
print(f"Error processing the generated image: {str(img_error)}")
|
288 |
feedback_history.append(f"Error with image: {str(img_error)}")
|
|
|
290 |
# No image was generated, only text response
|
291 |
print("No image was generated, only text response")
|
292 |
feedback_history.append("No image was generated in the previous attempt.")
|
|
|
|
|
|
|
|
|
|
|
293 |
except Exception as gen_error:
|
294 |
print(f"Error during generation attempt {current_attempt}: {str(gen_error)}")
|
295 |
feedback_history.append(f"Error during processing: {str(gen_error)}")
|
296 |
+
|
297 |
+
# Compare all results and select the best one
|
298 |
+
print(f"All attempts completed. Comparing {len(result_images)} results")
|
299 |
+
|
300 |
+
if result_images:
|
301 |
+
# Select the best result from all generated images
|
302 |
+
best_result = compare_image_results(result_images)
|
303 |
+
if best_result:
|
304 |
+
print("Returning best result from multiple attempts")
|
305 |
+
success_message = "Enhancement completed after multiple attempts to find the best result"
|
306 |
+
return [best_result], "", success_message
|
307 |
|
308 |
# Return the original image as a fallback without messages
|
309 |
+
print("Returning original image as fallback - no valid results generated")
|
310 |
+
return [input_image], "", "No satisfactory enhancements could be generated"
|
311 |
except Exception as e:
|
312 |
# Return the original image silently on error
|
313 |
print(f"Overall error in process_smile_enhancement: {str(e)}")
|