AkashKumarave commited on
Commit
3a53c8d
·
verified ·
1 Parent(s): deecbc4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -67
app.py CHANGED
@@ -4,118 +4,176 @@ import base64
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 = "AFyHfnQATghFdCMyAG3gRPbNY4TNKFGB"
11
  ACCESS_KEY_SECRET = "TTepeLyBterLNM3brYPGmdndBnnyKJBA"
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
  )
 
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" # SINGLE image endpoint
19
 
20
+ # ===== AUTHENTICATION =====
21
  def generate_jwt_token():
22
+ """Generate JWT token for API authentication"""
23
  payload = {
24
  "iss": ACCESS_KEY_ID,
25
+ "exp": int(time.time()) + 1800, # 30 minutes expiration
26
+ "nbf": int(time.time()) - 5 # Not before 5 seconds ago
27
  }
28
  return jwt.encode(payload, ACCESS_KEY_SECRET, algorithm="HS256")
29
 
30
+ # ===== IMAGE PROCESSING =====
31
+ def prepare_image_base64(image_path):
32
+ """Convert image to base64 without prefix"""
33
+ try:
34
+ with open(image_path, "rb") as img_file:
35
+ return base64.b64encode(img_file.read()).decode('utf-8')
36
+ except Exception as e:
37
+ logger.error(f"Image processing failed: {str(e)}")
38
+ return None
39
+
40
+ def validate_face_image(image_path):
41
+ """Validate the image meets face transformation requirements"""
42
  try:
43
+ # Check file exists
44
  if not os.path.exists(image_path):
45
+ return False, "Image file not found"
46
+
47
+ # Check file size (max 10MB)
48
+ file_size = os.path.getsize(image_path) / (1024 * 1024)
49
+ if file_size > 10:
50
+ return False, "Image too large (max 10MB)"
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
+ headers = {
60
+ "Authorization": f"Bearer {generate_jwt_token()}",
61
+ "Content-Type": "application/json"
62
+ }
63
+
64
+ payload = {
65
+ "model_name": "kling-v2.1", # Best for face preservation
66
+ "prompt": prompt,
67
+ "image": image_base64,
68
+ "image_reference": "face", # Critical for face control
69
+ "image_fidelity": 0.97, # 97% similarity
70
+ "human_fidelity": 0.97, # 97% facial features
71
+ "aspect_ratio": "1:1",
72
+ "n": 1
73
+ }
74
+
75
+ try:
76
+ response = requests.post(CREATE_TASK_ENDPOINT, json=payload, headers=headers)
77
+ response.raise_for_status()
78
+ return response.json()
79
+ except Exception as e:
80
+ logger.error(f"API Error: {str(e)}")
81
+ return None
82
+
83
+ def check_task_status(task_id):
84
+ headers = {"Authorization": f"Bearer {generate_jwt_token()}"}
85
+ try:
86
+ response = requests.get(
87
+ f"{API_BASE_URL}/v1/images/generations/{task_id}",
88
+ headers=headers
89
+ )
90
+ response.raise_for_status()
91
+ return response.json()
92
+ except Exception as e:
93
+ logger.error(f"Status Check Error: {str(e)}")
94
+ return None
95
+
96
+ # ===== MAIN FUNCTION =====
97
+ def transform_face(image_path, prompt):
98
+ """Full transformation workflow"""
99
+ # Validate image
100
+ is_valid, error_msg = validate_face_image(image_path)
101
+ if not is_valid:
102
+ return None, error_msg
103
+
104
+ try:
105
+ # Prepare image
106
+ image_base64 = prepare_image_base64(image_path)
107
+ if not image_base64:
108
+ return None, "Failed to process image"
109
 
110
+ # Create task
111
+ task_data = create_face_task(image_base64, prompt)
112
+ if not task_data or task_data.get("code") != 0:
113
+ return None, "Failed to start transformation"
114
 
115
+ task_id = task_data["data"]["task_id"]
116
+ logger.info(f"Task created: {task_id}")
117
 
118
+ # Check results (max 3 minutes)
119
+ for _ in range(18): # 18 attempts × 10 seconds
120
  time.sleep(10)
121
+ status_data = check_task_status(task_id)
122
+ if not status_data:
123
+ continue
124
+
 
 
125
  if status_data["data"]["task_status"] == "succeed":
126
  image_url = status_data["data"]["task_result"]["images"][0]["url"]
127
  img_data = requests.get(image_url).content
128
+ output_path = f"/tmp/face_result_{task_id}.png"
129
  with open(output_path, "wb") as f:
130
  f.write(img_data)
131
  return output_path, None
132
 
133
  elif status_data["data"]["task_status"] in ("failed", "canceled"):
134
+ error_msg = status_data["data"].get("task_status_msg", "Task failed")
135
+ return None, error_msg
136
 
137
  return None, "Processing timed out"
138
 
139
  except Exception as e:
140
  return None, f"Error: {str(e)}"
141
 
142
+ # ===== GRADIO INTERFACE =====
143
+ with gr.Blocks(title="Face Transformer") as app:
144
+ gr.Markdown("# 🎭 Exact Face Transformation (97% Match)")
145
+ gr.Markdown("Upload ONE face photo and describe your desired style")
146
 
147
  with gr.Row():
148
  with gr.Column():
149
+ image_input = gr.Image(
150
+ type="filepath",
151
+ label="Upload Face Photo",
152
+ sources=["upload"],
153
+ height=300
154
+ )
155
+ prompt_input = gr.Textbox(
156
+ label="Style Prompt",
157
+ placeholder="e.g. 'anime character', 'oil painting'"
158
+ )
159
  generate_btn = gr.Button("Transform", variant="primary")
160
 
161
+ gr.Markdown("### Requirements")
162
  gr.Markdown("""
163
+ - **Single clear face photo**
164
+ - Front-facing works best
165
+ - No glasses/masks
166
  - Max 10MB (JPG/PNG)
167
+ - Min 300x300px
168
  """)
169
 
170
  with gr.Column():
171
+ output_image = gr.Image(label="Transformed Result", height=400)
172
+ output_file = gr.File(label="Download")
173
  status_output = gr.Textbox(label="Status")
174
 
175
  generate_btn.click(
176
+ fn=lambda img, prompt: transform_face(img, prompt) + (None,),
177
  inputs=[image_input, prompt_input],
178
  outputs=[output_image, output_file, status_output]
179
  )