AkashKumarave commited on
Commit
dc04565
·
verified ·
1 Parent(s): f750405

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +179 -67
app.py CHANGED
@@ -1,113 +1,225 @@
1
  import gradio as gr
2
  import requests
3
  import base64
 
4
  import time
5
  import jwt
 
6
  from pathlib import Path
7
 
8
- # Configuration
 
 
 
 
9
  ACCESS_KEY_ID = "AFyHfnQATghFdCMyAG3gRPbNY4TNKFGB"
10
  ACCESS_KEY_SECRET = "TTepeLyBterLNM3brYPGmdndBnnyKJBA"
11
- API_URL = "https://api-singapore.klingai.com/v1/images/generations"
 
12
 
 
13
  def generate_jwt_token():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  payload = {
15
- "iss": ACCESS_KEY_ID,
16
- "exp": int(time.time()) + 1800,
17
- "nbf": int(time.time()) - 5
 
 
 
 
 
18
  }
19
- return jwt.encode(payload, ACCESS_KEY_SECRET, algorithm="HS256")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
 
21
  def transform_face(image_path, prompt):
22
- """Core transformation with 97% face fidelity"""
 
 
 
 
 
 
23
  try:
24
- # Prepare image (must contain exactly one face)
25
  with open(image_path, "rb") as f:
26
  image_base64 = base64.b64encode(f.read()).decode('utf-8')
27
-
28
- # API Request with face control
29
- headers = {
30
- "Authorization": f"Bearer {generate_jwt_token()}",
31
- "Content-Type": "application/json"
32
- }
33
-
34
- payload = {
35
- "model_name": "kling-v2.1", # Best for face preservation
36
- "prompt": prompt,
37
- "image": image_base64,
38
- "image_reference": "face", # Critical for face control
39
- "image_fidelity": 0.97, # 97% similarity
40
- "human_fidelity": 0.97, # 97% facial features
41
- "aspect_ratio": "1:1"
42
- }
43
-
44
- # Create task
45
- response = requests.post(API_URL, json=payload, headers=headers)
46
- if response.status_code != 200:
47
- return None, f"API Error: {response.text}"
48
-
49
- task_id = response.json()["data"]["task_id"]
50
-
51
- # Check results (max 2 minutes)
52
- for _ in range(12):
53
- time.sleep(10)
54
- status_response = requests.get(
55
- f"{API_URL}/{task_id}",
56
- headers=headers
57
- )
58
- status_data = status_response.json()
59
 
60
- if status_data["data"]["task_status"] == "succeed":
 
 
 
61
  image_url = status_data["data"]["task_result"]["images"][0]["url"]
62
- img_data = requests.get(image_url).content
63
- output_path = f"/tmp/transformed_{task_id}.png"
 
 
64
  with open(output_path, "wb") as f:
65
- f.write(img_data)
66
  return output_path, None
67
 
68
- return None, "Processing timed out"
69
-
70
- except Exception as e:
71
- return None, f"Error: {str(e)}"
 
 
 
 
72
 
73
- # Gradio Interface
74
- with gr.Blocks(title="Face Transformer") as app:
75
- gr.Markdown("## 🔍 Exact Face Transformation")
76
- gr.Markdown("Upload ONE clear face photo for style transformation (97% face preservation)")
77
 
78
  with gr.Row():
79
  with gr.Column():
80
- img_input = gr.Image(
 
81
  type="filepath",
82
- label="Upload Face (Single Person)",
83
  sources=["upload"],
84
  height=300
85
  )
86
  prompt_input = gr.Textbox(
87
  label="Style Prompt",
88
- placeholder="e.g. 'anime character', 'oil painting portrait'"
89
  )
90
- generate_btn = gr.Button("Transform Face", variant="primary")
91
 
92
  gr.Markdown("### Requirements")
93
  gr.Markdown("""
94
- - **Single clear face photo**
95
- - Front-facing works best
96
  - No glasses/masks/obstructions
97
- - Max 10MB (JPG/PNG)
98
- - Min 300x300px
99
  """)
100
 
101
  with gr.Column():
102
- output_img = gr.Image(label="Result (97% Face Match)", height=400)
103
- output_file = gr.File(label="Download")
104
- status = gr.Textbox(label="Processing Status")
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  generate_btn.click(
107
- fn=transform_face,
108
- inputs=[img_input, prompt_input],
109
- outputs=[output_img, output_file, status]
110
  )
111
 
112
  if __name__ == "__main__":
113
- app.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
1
  import gradio as gr
2
  import requests
3
  import base64
4
+ import os
5
  import time
6
  import jwt
7
+ import logging
8
  from pathlib import Path
9
 
10
+ # Configure logging
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # ===== API CONFIGURATION =====
15
  ACCESS_KEY_ID = "AFyHfnQATghFdCMyAG3gRPbNY4TNKFGB"
16
  ACCESS_KEY_SECRET = "TTepeLyBterLNM3brYPGmdndBnnyKJBA"
17
+ API_BASE_URL = "https://api-singapore.klingai.com"
18
+ CREATE_TASK_ENDPOINT = f"{API_BASE_URL}/v1/images/generations" # Correct endpoint for single image
19
 
20
+ # ===== AUTHENTICATION =====
21
  def generate_jwt_token():
22
+ """Generate JWT token with error handling"""
23
+ try:
24
+ payload = {
25
+ "iss": ACCESS_KEY_ID,
26
+ "exp": int(time.time()) + 1800,
27
+ "nbf": int(time.time()) - 5
28
+ }
29
+ return jwt.encode(payload, ACCESS_KEY_SECRET, algorithm="HS256")
30
+ except Exception as e:
31
+ logger.error(f"JWT generation failed: {str(e)}")
32
+ return None
33
+
34
+ # ===== IMAGE VALIDATION =====
35
+ def validate_face_image(image_path):
36
+ """Validate the image meets face transformation requirements"""
37
+ try:
38
+ # Check file exists
39
+ if not os.path.exists(image_path):
40
+ return False, "Image file not found"
41
+
42
+ # Check file size (max 10MB)
43
+ file_size = os.path.getsize(image_path) / (1024 * 1024)
44
+ if file_size > 10:
45
+ return False, "Image too large (max 10MB)"
46
+
47
+ # Check file extension
48
+ valid_extensions = ['.jpg', '.jpeg', '.png']
49
+ if not any(image_path.lower().endswith(ext) for ext in valid_extensions):
50
+ return False, "Invalid format (only JPG/PNG)"
51
+
52
+ return True, ""
53
+ except Exception as e:
54
+ return False, f"Validation error: {str(e)}"
55
+
56
+ # ===== API FUNCTIONS =====
57
+ def create_face_task(image_base64, prompt):
58
+ """Create face transformation task with 97% fidelity"""
59
+ token = generate_jwt_token()
60
+ if not token:
61
+ return None, "Authentication failed"
62
+
63
+ headers = {
64
+ "Authorization": f"Bearer {token}",
65
+ "Content-Type": "application/json"
66
+ }
67
+
68
  payload = {
69
+ "model_name": "kling-v2.1",
70
+ "prompt": prompt,
71
+ "image": image_base64,
72
+ "image_reference": "face",
73
+ "image_fidelity": 0.97, # 97% face similarity
74
+ "human_fidelity": 0.97, # 97% facial features
75
+ "aspect_ratio": "1:1",
76
+ "n": 1
77
  }
78
+
79
+ try:
80
+ response = requests.post(
81
+ CREATE_TASK_ENDPOINT,
82
+ json=payload,
83
+ headers=headers,
84
+ timeout=30
85
+ )
86
+
87
+ # Check for API errors
88
+ if response.status_code != 200:
89
+ error_msg = f"API Error {response.status_code}"
90
+ if response.text:
91
+ error_msg += f": {response.text}"
92
+ return None, error_msg
93
+
94
+ data = response.json()
95
+ if data.get("code") != 0:
96
+ return None, f"API Error: {data.get('message', 'Unknown error')}"
97
+
98
+ return data, None
99
+
100
+ except requests.exceptions.RequestException as e:
101
+ return None, f"Request failed: {str(e)}"
102
+
103
+ def check_task_status(task_id):
104
+ """Check task status with retries"""
105
+ token = generate_jwt_token()
106
+ if not token:
107
+ return None, "Authentication failed"
108
+
109
+ headers = {"Authorization": f"Bearer {token}"}
110
+ status_url = f"{API_BASE_URL}/v1/images/generations/{task_id}"
111
+
112
+ try:
113
+ response = requests.get(status_url, headers=headers, timeout=30)
114
+ response.raise_for_status()
115
+ return response.json(), None
116
+ except requests.exceptions.RequestException as e:
117
+ return None, f"Status check failed: {str(e)}"
118
 
119
+ # ===== CORE FUNCTION =====
120
  def transform_face(image_path, prompt):
121
+ """Full transformation workflow"""
122
+ # Validate image
123
+ is_valid, error_msg = validate_face_image(image_path)
124
+ if not is_valid:
125
+ return None, error_msg
126
+
127
+ # Prepare image
128
  try:
 
129
  with open(image_path, "rb") as f:
130
  image_base64 = base64.b64encode(f.read()).decode('utf-8')
131
+ except Exception as e:
132
+ return None, f"Image processing failed: {str(e)}"
133
+
134
+ # Create task
135
+ task_data, error = create_face_task(image_base64, prompt)
136
+ if error:
137
+ return None, error
138
+
139
+ task_id = task_data["data"]["task_id"]
140
+ logger.info(f"Task created: {task_id}")
141
+
142
+ # Check results (max 3 minutes)
143
+ for _ in range(18): # 18 attempts * 10 seconds = 3 minutes
144
+ time.sleep(10)
145
+ status_data, error = check_task_status(task_id)
146
+ if error:
147
+ continue # Retry on transient errors
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ status = status_data["data"]["task_status"]
150
+
151
+ if status == "succeed":
152
+ try:
153
  image_url = status_data["data"]["task_result"]["images"][0]["url"]
154
+ response = requests.get(image_url, timeout=30)
155
+ response.raise_for_status()
156
+
157
+ output_path = f"/tmp/face_transform_{task_id}.png"
158
  with open(output_path, "wb") as f:
159
+ f.write(response.content)
160
  return output_path, None
161
 
162
+ except Exception as e:
163
+ return None, f"Failed to save result: {str(e)}"
164
+
165
+ elif status in ("failed", "canceled"):
166
+ error_msg = status_data["data"].get("task_status_msg", "Unknown error")
167
+ return None, f"Task failed: {error_msg}"
168
+
169
+ return None, "Processing timed out after 3 minutes"
170
 
171
+ # ===== GRADIO INTERFACE =====
172
+ with gr.Blocks(title="Face Transformer Pro") as app:
173
+ gr.Markdown("## 🎭 Exact Face Transformation (97% Fidelity)")
 
174
 
175
  with gr.Row():
176
  with gr.Column():
177
+ gr.Markdown("### Input")
178
+ image_input = gr.Image(
179
  type="filepath",
180
+ label="Upload Clear Face Photo",
181
  sources=["upload"],
182
  height=300
183
  )
184
  prompt_input = gr.Textbox(
185
  label="Style Prompt",
186
+ placeholder="Describe the transformation style (e.g. 'anime character', 'oil painting')"
187
  )
188
+ generate_btn = gr.Button("Transform", variant="primary")
189
 
190
  gr.Markdown("### Requirements")
191
  gr.Markdown("""
192
+ - **Single clear face** (front-facing recommended)
 
193
  - No glasses/masks/obstructions
194
+ - Max 10MB (JPG/PNG only)
195
+ - Min 300x300 resolution
196
  """)
197
 
198
  with gr.Column():
199
+ gr.Markdown("### Output")
200
+ output_image = gr.Image(
201
+ label="Transformed Result",
202
+ interactive=False,
203
+ height=400
204
+ )
205
+ output_file = gr.File(
206
+ label="Download",
207
+ file_types=["image/png"]
208
+ )
209
+ status_output = gr.Textbox(
210
+ label="Status",
211
+ interactive=False
212
+ )
213
 
214
  generate_btn.click(
215
+ fn=lambda img, prompt: transform_face(img, prompt) + (None,),
216
+ inputs=[image_input, prompt_input],
217
+ outputs=[output_image, output_file, status_output]
218
  )
219
 
220
  if __name__ == "__main__":
221
+ app.launch(
222
+ server_name="0.0.0.0",
223
+ server_port=7860,
224
+ share=False
225
+ )