Your Name commited on
Commit
37370f7
·
1 Parent(s): 241b467

Implement cloud GPU processing for image editing, adding support for multiple GPU Spaces (InstructPix2Pix and SD-XL Turbo) with automatic fallback. Refactor image processing function to handle requests and responses from these services, enhancing user experience with improved error handling and UI updates.

Browse files
PROFESSIONAL_NAMING.md ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Professional Space Naming Guide
2
+
3
+ Based on research of successful Hugging Face Spaces, here are naming conventions and suggestions for your AI-powered facial and body feature editing application.
4
+
5
+ ## Naming Conventions for Professional Spaces
6
+
7
+ Successful Spaces on Hugging Face typically follow these naming patterns:
8
+
9
+ 1. **Descriptive + AI/Studio/Pro**: Combines what the tool does with a professional suffix
10
+ - Examples: FaceEditorPro, FeatureStudioAI, PortraitEnhancerPro
11
+
12
+ 2. **Action + Subject**: Describes the action and what it affects
13
+ - Examples: EditFace, EnhancePortrait, RefineFacial
14
+
15
+ 3. **Product-Style Names**: Short, memorable names that sound like commercial products
16
+ - Examples: FaceCraft, VisagePro, FeatureFusion
17
+
18
+ 4. **Tech-Focused Names**: Emphasizes the technology behind the application
19
+ - Examples: AI-Portrait-Editor, Neural-Face-Enhancer, DiffusionEditor
20
+
21
+ 5. **Creator/Company + Product**: Includes your name or brand
22
+ - Examples: YourName-FaceEditor, YourBrand-PortraitPro
23
+
24
+ ## Recommended Professional Names
25
+
26
+ Based on these conventions, here are professional name suggestions for your Space:
27
+
28
+ ### Premium/Professional Focus
29
+ - **PortraitPerfectAI**
30
+ - **FacialRefinePro**
31
+ - **FeatureStudioPro**
32
+ - **VisageEnhancerAI**
33
+
34
+ ### Technology-Focused
35
+ - **AI-Feature-Editor**
36
+ - **Neural-Portrait-Enhancer**
37
+ - **DiffusionFacialEditor**
38
+ - **StableFaceRefine**
39
+
40
+ ### Creative/Memorable
41
+ - **FaceCraft**
42
+ - **VisageSculpt**
43
+ - **FeatureFusion**
44
+ - **PortraitGenius**
45
+
46
+ ### Industry-Standard Style
47
+ - **PhotoFacialPro**
48
+ - **EditPortraitAI**
49
+ - **FaceRefinementStudio**
50
+ - **PortraitEnhancementAI**
51
+
52
+ ## Recommendations for Income Generation
53
+
54
+ For attracting potential income, consider these additional naming tips:
55
+
56
+ 1. Include terms like "Pro," "Studio," or "AI" to suggest professional quality
57
+ 2. Avoid overly technical names that might confuse non-technical users
58
+ 3. Choose a name that suggests the value proposition (enhancement, perfection, refinement)
59
+ 4. Consider SEO-friendly terms that people might search for
60
+ 5. Ensure the name is easy to pronounce and remember
61
+
62
+ ## Top Recommendations
63
+
64
+ Based on all factors, these names would be most effective for professional positioning and income potential:
65
+
66
+ 1. **PortraitPerfectAI** - Suggests high-quality results with AI technology
67
+ 2. **FacialRefinePro** - Clearly communicates the professional editing capability
68
+ 3. **FeatureStudioPro** - Implies a professional suite of editing tools
69
+ 4. **VisageEnhancerAI** - Sophisticated name with clear AI connection
70
+
71
+ These names follow the conventions of successful Spaces while positioning your application as a professional tool with income potential.
app.py CHANGED
@@ -6,6 +6,8 @@ import numpy as np
6
  import io
7
  import json
8
  import base64
 
 
9
 
10
  # Global variables
11
  FEATURE_TYPES = ["Eyes", "Nose", "Lips", "Face Shape", "Hair", "Body"]
@@ -18,7 +20,7 @@ MODIFICATION_PRESETS = {
18
  "Body": ["Slim", "Athletic", "Curvy", "Muscular"]
19
  }
20
 
21
- # Mapping from our UI controls to InstructPix2Pix instructions
22
  INSTRUCTION_MAPPING = {
23
  "Eyes": {
24
  "Larger": "make the eyes larger",
@@ -55,88 +57,124 @@ INSTRUCTION_MAPPING = {
55
  }
56
  }
57
 
58
- # Function to process image using InstructPix2Pix
59
- def process_with_instructpix2pix(image, feature_type, modification_type, intensity, custom_prompt="", use_custom_prompt=False):
60
- if image is None:
61
- return None, "Please upload an image first."
62
-
63
- try:
64
- # Prepare the instruction
65
- if use_custom_prompt and custom_prompt:
66
- instruction = custom_prompt
67
- else:
68
- instruction = INSTRUCTION_MAPPING[feature_type][modification_type]
69
-
70
- # Adjust instruction based on intensity
71
- if intensity < 0.3:
72
- instruction = "slightly " + instruction
73
- elif intensity > 0.7:
74
- instruction = "dramatically " + instruction
75
-
76
- # Convert image to base64 for API request
77
- if isinstance(image, np.ndarray):
78
- image_pil = Image.fromarray(image)
79
- else:
80
- image_pil = image
81
-
82
- # Resize image if too large (InstructPix2Pix works best with images around 512x512)
83
- width, height = image_pil.size
84
- max_dim = 512
85
- if width > max_dim or height > max_dim:
86
- if width > height:
87
- new_width = max_dim
88
- new_height = int(height * (max_dim / width))
89
- else:
90
- new_height = max_dim
91
- new_width = int(width * (max_dim / height))
92
- image_pil = image_pil.resize((new_width, new_height), Image.LANCZOS)
93
-
94
- # Convert to bytes for API request
95
- buffered = io.BytesIO()
96
- image_pil.save(buffered, format="PNG")
97
- img_str = base64.b64encode(buffered.getvalue()).decode()
98
-
99
- # Create API request to InstructPix2Pix Space
100
- api_url = "https://timbrooks-instruct-pix2pix.hf.space/api/predict"
101
- payload = {
102
  "data": [
103
  f"data:image/png;base64,{img_str}", # Input image
104
  instruction, # Instruction
105
  50, # Steps
106
  7.5, # Text CFG
107
  1.5, # Image CFG
108
- 1371, # Seed
109
  False, # Randomize seed
110
  True, # Fix CFG
111
  False # Randomize CFG
112
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
- # Send request
116
- response = requests.post(api_url, json=payload)
 
 
 
 
 
 
 
 
 
117
 
118
- if response.status_code == 200:
119
- result = response.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
- # Extract the output image
122
- if 'data' in result and len(result['data']) >= 1:
123
- output_data = result['data'][0]
124
- if isinstance(output_data, str) and output_data.startswith('data:image'):
125
- # Handle base64 encoded image
126
- image_data = output_data.split(',')[1]
 
 
127
  decoded_image = base64.b64decode(image_data)
128
  output_image = Image.open(io.BytesIO(decoded_image))
129
- return output_image, f"Edit completed successfully using instruction: '{instruction}'"
130
 
131
- # If we couldn't parse the image from the response
132
- return image, f"Error: Could not parse response from InstructPix2Pix."
133
- else:
134
- return image, f"Error: InstructPix2Pix returned status code {response.status_code}."
 
 
135
 
136
- except Exception as e:
137
- import traceback
138
- traceback.print_exc()
139
- return image, f"Error processing with InstructPix2Pix: {str(e)}"
140
 
141
  # UI Components
142
  def create_ui():
@@ -200,15 +238,20 @@ def create_ui():
200
  gr.Markdown("""
201
  ### About Cloud GPU Processing
202
 
203
- This application uses InstructPix2Pix, a public GPU-accelerated Space on Hugging Face, to process your images.
 
 
 
 
 
204
 
205
  **Benefits:**
206
  - GPU-accelerated processing without local setup
 
207
  - Works on any device with internet access
208
- - No need to install CUDA or PyTorch
209
 
210
  **How it works:**
211
- 1. Your image is sent to the InstructPix2Pix Space
212
  2. Your feature selections are converted to text instructions
213
  3. The Space processes your image using GPU acceleration
214
  4. The edited image is returned to this interface
@@ -227,7 +270,7 @@ def create_ui():
227
  )
228
 
229
  edit_button.click(
230
- fn=process_with_instructpix2pix,
231
  inputs=[
232
  input_image,
233
  feature_type,
 
6
  import io
7
  import json
8
  import base64
9
+ import time
10
+ import random
11
 
12
  # Global variables
13
  FEATURE_TYPES = ["Eyes", "Nose", "Lips", "Face Shape", "Hair", "Body"]
 
20
  "Body": ["Slim", "Athletic", "Curvy", "Muscular"]
21
  }
22
 
23
+ # Mapping from our UI controls to text instructions
24
  INSTRUCTION_MAPPING = {
25
  "Eyes": {
26
  "Larger": "make the eyes larger",
 
57
  }
58
  }
59
 
60
+ # List of available GPU Spaces for image editing
61
+ GPU_SPACES = [
62
+ {
63
+ "name": "InstructPix2Pix",
64
+ "url": "https://timbrooks-instruct-pix2pix.hf.space/api/predict",
65
+ "format_request": lambda img_str, instruction: {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  "data": [
67
  f"data:image/png;base64,{img_str}", # Input image
68
  instruction, # Instruction
69
  50, # Steps
70
  7.5, # Text CFG
71
  1.5, # Image CFG
72
+ random.randint(1, 9999), # Random Seed
73
  False, # Randomize seed
74
  True, # Fix CFG
75
  False # Randomize CFG
76
  ]
77
+ },
78
+ "parse_response": lambda response: {
79
+ "success": response.status_code == 200,
80
+ "data": response.json()["data"][0] if response.status_code == 200 and "data" in response.json() and len(response.json()["data"]) > 0 else None
81
+ }
82
+ },
83
+ {
84
+ "name": "SD-XL Turbo",
85
+ "url": "https://fffiloni-sdxl-turbo.hf.space/api/predict",
86
+ "format_request": lambda img_str, instruction: {
87
+ "data": [
88
+ f"data:image/png;base64,{img_str}", # Input image
89
+ instruction, # Prompt
90
+ "", # Negative prompt
91
+ 25, # Steps
92
+ 1024, # Width
93
+ 1024, # Height
94
+ 1.0, # Guidance scale
95
+ 0.5, # Strength
96
+ random.randint(1, 9999), # Seed
97
+ ]
98
+ },
99
+ "parse_response": lambda response: {
100
+ "success": response.status_code == 200,
101
+ "data": response.json()["data"][0] if response.status_code == 200 and "data" in response.json() and len(response.json()["data"]) > 0 else None
102
  }
103
+ }
104
+ ]
105
+
106
+ # Function to process image using cloud GPU services with fallback
107
+ def process_with_cloud_gpu(image, feature_type, modification_type, intensity, custom_prompt="", use_custom_prompt=False):
108
+ if image is None:
109
+ return None, "Please upload an image first."
110
+
111
+ # Prepare the instruction
112
+ if use_custom_prompt and custom_prompt:
113
+ instruction = custom_prompt
114
+ else:
115
+ instruction = INSTRUCTION_MAPPING[feature_type][modification_type]
116
 
117
+ # Adjust instruction based on intensity
118
+ if intensity < 0.3:
119
+ instruction = "slightly " + instruction
120
+ elif intensity > 0.7:
121
+ instruction = "dramatically " + instruction
122
+
123
+ # Convert image to base64 for API request
124
+ if isinstance(image, np.ndarray):
125
+ image_pil = Image.fromarray(image)
126
+ else:
127
+ image_pil = image
128
 
129
+ # Resize image if too large (most models work best with images around 512-1024px)
130
+ width, height = image_pil.size
131
+ max_dim = 1024
132
+ if width > max_dim or height > max_dim:
133
+ if width > height:
134
+ new_width = max_dim
135
+ new_height = int(height * (max_dim / width))
136
+ else:
137
+ new_height = max_dim
138
+ new_width = int(width * (max_dim / height))
139
+ image_pil = image_pil.resize((new_width, new_height), Image.LANCZOS)
140
+
141
+ # Convert to bytes for API request
142
+ buffered = io.BytesIO()
143
+ image_pil.save(buffered, format="PNG")
144
+ img_str = base64.b64encode(buffered.getvalue()).decode()
145
+
146
+ # Try each GPU Space in order until one succeeds
147
+ errors = []
148
+ for space in GPU_SPACES:
149
+ try:
150
+ # Format the request according to this space's requirements
151
+ payload = space["format_request"](img_str, instruction)
152
+
153
+ # Send request with timeout
154
+ response = requests.post(space["url"], json=payload, timeout=60)
155
 
156
+ # Parse the response
157
+ result = space["parse_response"](response)
158
+
159
+ if result["success"] and result["data"]:
160
+ # Handle base64 encoded image
161
+ if isinstance(result["data"], str) and result["data"].startswith('data:image'):
162
+ # Extract the output image
163
+ image_data = result["data"].split(',')[1]
164
  decoded_image = base64.b64decode(image_data)
165
  output_image = Image.open(io.BytesIO(decoded_image))
166
+ return output_image, f"Edit completed successfully using {space['name']} with instruction: '{instruction}'"
167
 
168
+ # If we get here, this space didn't work
169
+ errors.append(f"{space['name']}: {response.status_code} - {response.text[:100]}...")
170
+
171
+ except Exception as e:
172
+ errors.append(f"{space['name']}: {str(e)}")
173
+ continue
174
 
175
+ # If all spaces failed, return the original image and error details
176
+ error_msg = "All GPU Spaces failed. Details:\n" + "\n".join(errors)
177
+ return image, error_msg
 
178
 
179
  # UI Components
180
  def create_ui():
 
238
  gr.Markdown("""
239
  ### About Cloud GPU Processing
240
 
241
+ This application uses multiple public GPU-accelerated Spaces on Hugging Face to process your images:
242
+
243
+ 1. **InstructPix2Pix** - For natural language guided image editing
244
+ 2. **SD-XL Turbo** - For fast, high-quality image modifications
245
+
246
+ The application will automatically try each service in order until one succeeds.
247
 
248
  **Benefits:**
249
  - GPU-accelerated processing without local setup
250
+ - Automatic fallback if one service is unavailable
251
  - Works on any device with internet access
 
252
 
253
  **How it works:**
254
+ 1. Your image is sent to a GPU-accelerated Space
255
  2. Your feature selections are converted to text instructions
256
  3. The Space processes your image using GPU acceleration
257
  4. The edited image is returned to this interface
 
270
  )
271
 
272
  edit_button.click(
273
+ fn=process_with_cloud_gpu,
274
  inputs=[
275
  input_image,
276
  feature_type,
app_cloud_gpu_robust.py ADDED
@@ -0,0 +1,312 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import requests
4
+ from PIL import Image
5
+ import numpy as np
6
+ import io
7
+ import json
8
+ import base64
9
+ import time
10
+ import random
11
+
12
+ # Global variables
13
+ FEATURE_TYPES = ["Eyes", "Nose", "Lips", "Face Shape", "Hair", "Body"]
14
+ MODIFICATION_PRESETS = {
15
+ "Eyes": ["Larger", "Smaller", "Change Color", "Change Shape"],
16
+ "Nose": ["Refine", "Reshape", "Resize"],
17
+ "Lips": ["Fuller", "Thinner", "Change Color"],
18
+ "Face Shape": ["Slim", "Round", "Define Jawline", "Soften Features"],
19
+ "Hair": ["Change Color", "Change Style", "Add Volume"],
20
+ "Body": ["Slim", "Athletic", "Curvy", "Muscular"]
21
+ }
22
+
23
+ # Mapping from our UI controls to text instructions
24
+ INSTRUCTION_MAPPING = {
25
+ "Eyes": {
26
+ "Larger": "make the eyes larger",
27
+ "Smaller": "make the eyes smaller",
28
+ "Change Color": "change the eye color to blue",
29
+ "Change Shape": "make the eyes more almond shaped"
30
+ },
31
+ "Nose": {
32
+ "Refine": "refine the nose shape",
33
+ "Reshape": "make the nose more straight",
34
+ "Resize": "make the nose smaller"
35
+ },
36
+ "Lips": {
37
+ "Fuller": "make the lips fuller",
38
+ "Thinner": "make the lips thinner",
39
+ "Change Color": "make the lips more red"
40
+ },
41
+ "Face Shape": {
42
+ "Slim": "make the face slimmer",
43
+ "Round": "make the face more round",
44
+ "Define Jawline": "define the jawline more",
45
+ "Soften Features": "soften the facial features"
46
+ },
47
+ "Hair": {
48
+ "Change Color": "change the hair color to blonde",
49
+ "Change Style": "make the hair wavy",
50
+ "Add Volume": "add more volume to the hair"
51
+ },
52
+ "Body": {
53
+ "Slim": "make the body slimmer",
54
+ "Athletic": "make the body more athletic",
55
+ "Curvy": "make the body more curvy",
56
+ "Muscular": "make the body more muscular"
57
+ }
58
+ }
59
+
60
+ # List of available GPU Spaces for image editing
61
+ GPU_SPACES = [
62
+ {
63
+ "name": "InstructPix2Pix",
64
+ "url": "https://timbrooks-instruct-pix2pix.hf.space/api/predict",
65
+ "format_request": lambda img_str, instruction: {
66
+ "data": [
67
+ f"data:image/png;base64,{img_str}", # Input image
68
+ instruction, # Instruction
69
+ 50, # Steps
70
+ 7.5, # Text CFG
71
+ 1.5, # Image CFG
72
+ random.randint(1, 9999), # Random Seed
73
+ False, # Randomize seed
74
+ True, # Fix CFG
75
+ False # Randomize CFG
76
+ ]
77
+ },
78
+ "parse_response": lambda response: {
79
+ "success": response.status_code == 200,
80
+ "data": response.json()["data"][0] if response.status_code == 200 and "data" in response.json() and len(response.json()["data"]) > 0 else None
81
+ }
82
+ },
83
+ {
84
+ "name": "SD-XL Turbo",
85
+ "url": "https://fffiloni-sdxl-turbo.hf.space/api/predict",
86
+ "format_request": lambda img_str, instruction: {
87
+ "data": [
88
+ f"data:image/png;base64,{img_str}", # Input image
89
+ instruction, # Prompt
90
+ "", # Negative prompt
91
+ 25, # Steps
92
+ 1024, # Width
93
+ 1024, # Height
94
+ 1.0, # Guidance scale
95
+ 0.5, # Strength
96
+ random.randint(1, 9999), # Seed
97
+ ]
98
+ },
99
+ "parse_response": lambda response: {
100
+ "success": response.status_code == 200,
101
+ "data": response.json()["data"][0] if response.status_code == 200 and "data" in response.json() and len(response.json()["data"]) > 0 else None
102
+ }
103
+ }
104
+ ]
105
+
106
+ # Function to process image using cloud GPU services with fallback
107
+ def process_with_cloud_gpu(image, feature_type, modification_type, intensity, custom_prompt="", use_custom_prompt=False):
108
+ if image is None:
109
+ return None, "Please upload an image first."
110
+
111
+ # Prepare the instruction
112
+ if use_custom_prompt and custom_prompt:
113
+ instruction = custom_prompt
114
+ else:
115
+ instruction = INSTRUCTION_MAPPING[feature_type][modification_type]
116
+
117
+ # Adjust instruction based on intensity
118
+ if intensity < 0.3:
119
+ instruction = "slightly " + instruction
120
+ elif intensity > 0.7:
121
+ instruction = "dramatically " + instruction
122
+
123
+ # Convert image to base64 for API request
124
+ if isinstance(image, np.ndarray):
125
+ image_pil = Image.fromarray(image)
126
+ else:
127
+ image_pil = image
128
+
129
+ # Resize image if too large (most models work best with images around 512-1024px)
130
+ width, height = image_pil.size
131
+ max_dim = 1024
132
+ if width > max_dim or height > max_dim:
133
+ if width > height:
134
+ new_width = max_dim
135
+ new_height = int(height * (max_dim / width))
136
+ else:
137
+ new_height = max_dim
138
+ new_width = int(width * (max_dim / height))
139
+ image_pil = image_pil.resize((new_width, new_height), Image.LANCZOS)
140
+
141
+ # Convert to bytes for API request
142
+ buffered = io.BytesIO()
143
+ image_pil.save(buffered, format="PNG")
144
+ img_str = base64.b64encode(buffered.getvalue()).decode()
145
+
146
+ # Try each GPU Space in order until one succeeds
147
+ errors = []
148
+ for space in GPU_SPACES:
149
+ try:
150
+ # Format the request according to this space's requirements
151
+ payload = space["format_request"](img_str, instruction)
152
+
153
+ # Send request with timeout
154
+ response = requests.post(space["url"], json=payload, timeout=60)
155
+
156
+ # Parse the response
157
+ result = space["parse_response"](response)
158
+
159
+ if result["success"] and result["data"]:
160
+ # Handle base64 encoded image
161
+ if isinstance(result["data"], str) and result["data"].startswith('data:image'):
162
+ # Extract the output image
163
+ image_data = result["data"].split(',')[1]
164
+ decoded_image = base64.b64decode(image_data)
165
+ output_image = Image.open(io.BytesIO(decoded_image))
166
+ return output_image, f"Edit completed successfully using {space['name']} with instruction: '{instruction}'"
167
+
168
+ # If we get here, this space didn't work
169
+ errors.append(f"{space['name']}: {response.status_code} - {response.text[:100]}...")
170
+
171
+ except Exception as e:
172
+ errors.append(f"{space['name']}: {str(e)}")
173
+ continue
174
+
175
+ # If all spaces failed, return the original image and error details
176
+ error_msg = "All GPU Spaces failed. Details:\n" + "\n".join(errors)
177
+ return image, error_msg
178
+
179
+ # UI Components
180
+ def create_ui():
181
+ with gr.Blocks(title="AI-Powered Facial & Body Feature Editor") as app:
182
+ gr.Markdown("# AI-Powered Facial & Body Feature Editor")
183
+ gr.Markdown("Upload an image and use the controls to edit specific facial and body features using cloud GPU processing.")
184
+
185
+ with gr.Row():
186
+ with gr.Column(scale=1):
187
+ # Input controls
188
+ input_image = gr.Image(label="Upload Image", type="pil")
189
+
190
+ with gr.Group():
191
+ gr.Markdown("### Feature Selection")
192
+ feature_type = gr.Dropdown(
193
+ choices=FEATURE_TYPES,
194
+ label="Select Feature",
195
+ value="Eyes"
196
+ )
197
+
198
+ # Initialize with choices for the default feature (Eyes)
199
+ modification_type = gr.Dropdown(
200
+ choices=MODIFICATION_PRESETS["Eyes"],
201
+ label="Modification Type",
202
+ value="Larger"
203
+ )
204
+
205
+ intensity = gr.Slider(
206
+ minimum=0.1,
207
+ maximum=1.0,
208
+ value=0.5,
209
+ step=0.1,
210
+ label="Intensity"
211
+ )
212
+
213
+ with gr.Group():
214
+ gr.Markdown("### Custom Prompt (Advanced)")
215
+ use_custom_prompt = gr.Checkbox(
216
+ label="Use Custom Prompt",
217
+ value=False
218
+ )
219
+ custom_prompt = gr.Textbox(
220
+ label="Custom Prompt",
221
+ placeholder="e.g., make the eyes blue and add long eyelashes"
222
+ )
223
+
224
+ edit_button = gr.Button("Apply Edit", variant="primary")
225
+ reset_button = gr.Button("Reset")
226
+ status_text = gr.Textbox(label="Status", interactive=False)
227
+
228
+ with gr.Column(scale=1):
229
+ # Output display
230
+ output_image = gr.Image(label="Edited Image", type="pil")
231
+
232
+ with gr.Accordion("Edit History", open=False):
233
+ edit_history = gr.State([])
234
+ history_gallery = gr.Gallery(label="Previous Edits")
235
+
236
+ # Information about cloud processing
237
+ with gr.Accordion("Cloud GPU Processing Information", open=True):
238
+ gr.Markdown("""
239
+ ### About Cloud GPU Processing
240
+
241
+ This application uses multiple public GPU-accelerated Spaces on Hugging Face to process your images:
242
+
243
+ 1. **InstructPix2Pix** - For natural language guided image editing
244
+ 2. **SD-XL Turbo** - For fast, high-quality image modifications
245
+
246
+ The application will automatically try each service in order until one succeeds.
247
+
248
+ **Benefits:**
249
+ - GPU-accelerated processing without local setup
250
+ - Automatic fallback if one service is unavailable
251
+ - Works on any device with internet access
252
+
253
+ **How it works:**
254
+ 1. Your image is sent to a GPU-accelerated Space
255
+ 2. Your feature selections are converted to text instructions
256
+ 3. The Space processes your image using GPU acceleration
257
+ 4. The edited image is returned to this interface
258
+
259
+ **Note:** Processing may take 10-30 seconds depending on server load.
260
+ """)
261
+
262
+ # Event handlers
263
+ def update_modification_choices(feature):
264
+ return gr.Dropdown(choices=MODIFICATION_PRESETS[feature])
265
+
266
+ feature_type.change(
267
+ fn=update_modification_choices,
268
+ inputs=feature_type,
269
+ outputs=modification_type
270
+ )
271
+
272
+ edit_button.click(
273
+ fn=process_with_cloud_gpu,
274
+ inputs=[
275
+ input_image,
276
+ feature_type,
277
+ modification_type,
278
+ intensity,
279
+ custom_prompt,
280
+ use_custom_prompt
281
+ ],
282
+ outputs=[output_image, status_text]
283
+ )
284
+
285
+ def reset_image():
286
+ return None, "Image reset."
287
+
288
+ reset_button.click(
289
+ fn=reset_image,
290
+ inputs=[],
291
+ outputs=[output_image, status_text]
292
+ )
293
+
294
+ # Add ethical usage notice
295
+ gr.Markdown("""
296
+ ## Ethical Usage Notice
297
+
298
+ This tool is designed for creative and personal use. Please ensure:
299
+
300
+ - You have appropriate rights to edit the images you upload
301
+ - You use this tool responsibly and respect the dignity of individuals
302
+ - You understand that AI-generated modifications are artificial and may not represent reality
303
+
304
+ By using this application, you agree to these terms.
305
+ """)
306
+
307
+ return app
308
+
309
+ # Launch the app
310
+ if __name__ == "__main__":
311
+ app = create_ui()
312
+ app.launch(server_name="0.0.0.0", share=False)
image-edit-app-cloud-gpu-robust.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ec9c4e5490ee3147a4bb63928d872320f4ca2a9286ebd7602cf6c9d843a089e7
3
+ size 5280