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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -182
app.py CHANGED
@@ -4,222 +4,121 @@ 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
- )
 
4
  import os
5
  import time
6
  import jwt
 
7
  from pathlib import Path
8
 
9
+ # Configuration - REPLACE WITH YOUR ACTUAL CREDENTIALS
10
+ ACCESS_KEY_ID = "YOUR_ACCESS_KEY_ID"
11
+ ACCESS_KEY_SECRET = "YOUR_ACCESS_KEY_SECRET"
 
 
 
 
12
  API_BASE_URL = "https://api-singapore.klingai.com"
13
+ ENDPOINT = f"{API_BASE_URL}/v1/images/generations" # Image-to-image endpoint
14
 
 
15
  def generate_jwt_token():
16
+ """Generate authentication token"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  payload = {
18
+ "iss": ACCESS_KEY_ID,
19
+ "exp": int(time.time()) + 1800, # 30 min expiration
20
+ "nbf": int(time.time()) - 5 # Not before 5 sec ago
 
 
 
 
 
21
  }
22
+ return jwt.encode(payload, ACCESS_KEY_SECRET, algorithm="HS256")
23
+
24
+ def process_image(image_path, prompt):
25
+ """Core image processing function"""
26
  try:
27
+ # 1. Validate image
28
+ if not os.path.exists(image_path):
29
+ return None, "Image file not found"
30
+
31
+ if os.path.getsize(image_path) > 10 * 1024 * 1024: # 10MB
32
+ return None, "Image too large (max 10MB)"
33
+
34
+ # 2. Prepare image
35
+ with open(image_path, "rb") as f:
36
+ image_base64 = base64.b64encode(f.read()).decode('utf-8')
37
 
38
+ # 3. API Request
39
+ headers = {
40
+ "Authorization": f"Bearer {generate_jwt_token()}",
41
+ "Content-Type": "application/json"
42
+ }
43
+
44
+ payload = {
45
+ "model_name": "kling-v2.1",
46
+ "prompt": prompt,
47
+ "image": image_base64,
48
+ "image_reference": "face",
49
+ "image_fidelity": 0.97,
50
+ "human_fidelity": 0.97,
51
+ "aspect_ratio": "1:1",
52
+ "n": 1
53
+ }
54
+
55
+ response = requests.post(ENDPOINT, json=payload, headers=headers)
56
+
57
+ # 4. Handle response
58
  if response.status_code != 200:
59
+ return None, f"API Error: {response.text}"
60
+
 
 
 
61
  data = response.json()
62
  if data.get("code") != 0:
63
  return None, f"API Error: {data.get('message', 'Unknown error')}"
 
 
64
 
65
+ task_id = data["data"]["task_id"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ # 5. Check task status (max 3 minutes)
68
+ for _ in range(18): # 18 attempts × 10 seconds = 3 minutes
69
+ time.sleep(10)
70
+ status_response = requests.get(
71
+ f"{API_BASE_URL}/v1/images/generations/{task_id}",
72
+ headers=headers
73
+ )
74
+ status_data = status_response.json()
75
+
76
+ if status_data["data"]["task_status"] == "succeed":
77
  image_url = status_data["data"]["task_result"]["images"][0]["url"]
78
+ img_data = requests.get(image_url).content
79
+ output_path = f"/tmp/result_{task_id}.png"
 
 
80
  with open(output_path, "wb") as f:
81
+ f.write(img_data)
82
  return output_path, None
83
 
84
+ elif status_data["data"]["task_status"] in ("failed", "canceled"):
85
+ return None, status_data["data"].get("task_status_msg", "Task failed")
86
+
87
+ return None, "Processing timed out"
88
+
89
+ except Exception as e:
90
+ return None, f"Error: {str(e)}"
 
91
 
92
+ # Gradio Interface
93
+ with gr.Blocks() as app:
94
+ gr.Markdown("# 🖼️ Face Style Transformer")
95
+ gr.Markdown("Upload a clear face photo and describe your desired style")
96
 
97
  with gr.Row():
98
  with gr.Column():
99
+ image_input = gr.Image(type="filepath", label="Upload Face Photo")
100
+ prompt_input = gr.Textbox(label="Style Prompt",
101
+ placeholder="e.g. 'anime character', 'oil painting'")
 
 
 
 
 
 
 
 
102
  generate_btn = gr.Button("Transform", variant="primary")
103
 
104
+ gr.Markdown("### Requirements:")
105
  gr.Markdown("""
106
+ - Clear frontal face photo
107
+ - Single person only
108
+ - Max 10MB (JPG/PNG)
109
  - Min 300x300 resolution
110
  """)
111
 
112
  with gr.Column():
113
+ output_image = gr.Image(label="Result", interactive=False)
114
+ output_file = gr.File(label="Download Result")
115
+ status_output = gr.Textbox(label="Status")
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  generate_btn.click(
118
+ fn=lambda img, prompt: process_image(img, prompt) + (None,),
119
  inputs=[image_input, prompt_input],
120
  outputs=[output_image, output_file, status_output]
121
  )
122
 
123
  if __name__ == "__main__":
124
+ app.launch(server_name="0.0.0.0", server_port=7860)