AkashKumarave commited on
Commit
c0c3ada
·
verified ·
1 Parent(s): 65d9ae0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -81
app.py CHANGED
@@ -15,48 +15,66 @@ logger = logging.getLogger(__name__)
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"
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,
26
- "nbf": int(time.time()) - 5
27
  }
28
  return jwt.encode(payload, ACCESS_KEY_SECRET, algorithm="HS256")
29
 
30
- # ===== FACE VALIDATION =====
31
- def validate_face_image(image_path):
32
- """Check if image contains exactly one face"""
33
  try:
34
- # In production, you'd use face detection here
35
- # For demo, we'll just check basic image properties
 
 
 
 
 
 
 
 
36
  size_mb = os.path.getsize(image_path) / (1024 * 1024)
37
  if size_mb > 10:
38
  return False, "Image too large (max 10MB)"
 
 
39
  return True, ""
40
  except Exception as e:
41
  return False, f"Image validation error: {str(e)}"
42
 
43
  # ===== API FUNCTIONS =====
44
- def create_face_transform_task(image_base64, prompt, strength=0.97):
45
- """Create face transformation task with high reference strength"""
46
  headers = {
47
  "Authorization": f"Bearer {generate_jwt_token()}",
48
  "Content-Type": "application/json"
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
 
51
  payload = {
52
- "model_name": "kling-v2-1", # Best for face transformation
53
  "prompt": prompt,
54
- "image": image_base64,
55
- "image_reference": "face", # Critical for face transformation
56
- "image_fidelity": strength, # 0.97 = 97% reference strength
57
- "resolution": "1k",
58
- "aspect_ratio": "1:1",
59
- "n": 1
60
  }
61
 
62
  try:
@@ -65,12 +83,14 @@ def create_face_transform_task(image_base64, prompt, strength=0.97):
65
  return response.json(), None
66
  except requests.exceptions.RequestException as e:
67
  logger.error(f"API request failed: {str(e)}")
 
 
68
  return None, f"API Error: {str(e)}"
69
 
70
  def check_task_status(task_id):
71
  """Check task completion status"""
72
  headers = {"Authorization": f"Bearer {generate_jwt_token()}"}
73
- status_url = f"{API_BASE_URL}/v1/images/generations/{task_id}"
74
 
75
  try:
76
  response = requests.get(status_url, headers=headers)
@@ -80,22 +100,17 @@ def check_task_status(task_id):
80
  return None, f"Status check failed: {str(e)}"
81
 
82
  # ===== MAIN PROCESSING =====
83
- def transform_face(image_path, prompt, strength=0.97):
84
- """Handle face transformation workflow"""
85
- # Validate image
86
- is_valid, error_msg = validate_face_image(image_path)
87
- if not is_valid:
88
- return None, error_msg
 
 
89
 
90
- # Read and encode image
91
- try:
92
- with open(image_path, "rb") as img_file:
93
- image_base64 = base64.b64encode(img_file.read()).decode('utf-8')
94
- except Exception as e:
95
- return None, f"Failed to process image: {str(e)}"
96
-
97
- # Create task with face reference
98
- task_response, error = create_face_transform_task(image_base64, prompt, strength)
99
  if error:
100
  return None, error
101
 
@@ -103,10 +118,10 @@ def transform_face(image_path, prompt, strength=0.97):
103
  return None, f"API error: {task_response.get('message', 'Unknown error')}"
104
 
105
  task_id = task_response["data"]["task_id"]
106
- logger.info(f"Face transformation task created: {task_id}")
107
 
108
- # Poll for results
109
- for _ in range(30): # Max 5 minutes (10s intervals)
110
  task_data, error = check_task_status(task_id)
111
  if error:
112
  return None, error
@@ -118,12 +133,12 @@ def transform_face(image_path, prompt, strength=0.97):
118
  try:
119
  response = requests.get(image_url)
120
  response.raise_for_status()
121
- output_path = Path(f"/tmp/kling_face_{task_id}.png")
122
  with open(output_path, "wb") as f:
123
  f.write(response.content)
124
  return str(output_path), None
125
  except Exception as e:
126
- return None, f"Failed to save result: {str(e)}"
127
 
128
  elif status in ("failed", "canceled"):
129
  error_msg = task_data["data"].get("task_status_msg", "Unknown error")
@@ -131,73 +146,66 @@ def transform_face(image_path, prompt, strength=0.97):
131
 
132
  time.sleep(10)
133
 
134
- return None, "Task timed out after 5 minutes"
135
 
136
  # ===== GRADIO INTERFACE =====
137
- def process_interface(image, prompt, strength):
138
- if not image:
139
- return None, None, "Please upload an image with a clear face"
 
 
 
140
 
141
- output_path, error = transform_face(image, prompt, strength/100)
142
  if error:
143
  return None, None, error
144
 
145
- return output_path, output_path, "Face transformation successful!"
146
 
147
- with gr.Blocks(title="Kling AI Face Transformer") as app:
148
- gr.Markdown("## 👤 Kling AI Face Transformation")
149
- gr.Markdown("Transform faces with high precision (97% reference strength)")
150
 
151
  with gr.Row():
152
  with gr.Column():
153
  gr.Markdown("### Input Settings")
154
- image_input = gr.Image(
155
- type="filepath",
156
- label="Upload Face Image",
157
- sources=["upload"],
158
- height=300
159
- )
 
160
  prompt_input = gr.Textbox(
161
- label="Transformation Style",
162
- placeholder="Describe the new style (e.g. 'anime character', 'oil painting portrait')"
163
- )
164
- strength_slider = gr.Slider(
165
- minimum=80,
166
- maximum=100,
167
- value=97,
168
- step=1,
169
- label="Reference Strength (%)",
170
- info="Higher values preserve more facial features"
171
  )
172
- generate_btn = gr.Button("Transform Face", variant="primary")
 
173
 
174
  gr.Markdown("### Requirements")
175
  gr.Markdown("""
176
- - **Must contain exactly one clear face**
177
- - Max size: 10MB
 
178
  - Formats: JPG, PNG
179
- - Min resolution: 300x300px
180
  """)
181
 
182
  with gr.Column():
183
  gr.Markdown("### Output")
184
- output_image = gr.Image(
185
- label="Transformed Face",
186
- interactive=False,
187
- height=400
188
- )
189
- output_file = gr.File(
190
- label="Download Result",
191
- file_types=["image/png"]
192
- )
193
- status_output = gr.Textbox(
194
- label="Status",
195
- interactive=False
196
- )
197
 
198
  generate_btn.click(
199
  fn=process_interface,
200
- inputs=[image_input, prompt_input, strength_slider],
 
 
 
 
 
201
  outputs=[output_image, output_file, status_output]
202
  )
203
 
 
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/multi-image2image"
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_image(image_path):
41
+ """Validate image meets API requirements"""
42
+ try:
43
+ # Check file size
44
  size_mb = os.path.getsize(image_path) / (1024 * 1024)
45
  if size_mb > 10:
46
  return False, "Image too large (max 10MB)"
47
+
48
+ # Check dimensions (basic check - should use PIL for actual dimensions)
49
  return True, ""
50
  except Exception as e:
51
  return False, f"Image validation error: {str(e)}"
52
 
53
  # ===== API FUNCTIONS =====
54
+ def create_multi_image_task(subject_images, prompt):
55
+ """Create multi-image generation task"""
56
  headers = {
57
  "Authorization": f"Bearer {generate_jwt_token()}",
58
  "Content-Type": "application/json"
59
  }
60
 
61
+ # Prepare subject images list
62
+ subject_image_list = []
63
+ for img_path in subject_images:
64
+ if img_path: # Skip empty/None images
65
+ base64_img = prepare_image_base64(img_path)
66
+ if base64_img:
67
+ subject_image_list.append({"subject_image": base64_img})
68
+
69
+ if len(subject_image_list) < 2:
70
+ return None, "At least 2 subject images required"
71
+
72
  payload = {
73
+ "model_name": "kling-v2",
74
  "prompt": prompt,
75
+ "subject_image_list": subject_image_list,
76
+ "n": 1,
77
+ "aspect_ratio": "1:1"
 
 
 
78
  }
79
 
80
  try:
 
83
  return response.json(), None
84
  except requests.exceptions.RequestException as e:
85
  logger.error(f"API request failed: {str(e)}")
86
+ if hasattr(e, 'response') and e.response:
87
+ logger.error(f"API response: {e.response.text}")
88
  return None, f"API Error: {str(e)}"
89
 
90
  def check_task_status(task_id):
91
  """Check task completion status"""
92
  headers = {"Authorization": f"Bearer {generate_jwt_token()}"}
93
+ status_url = f"{API_BASE_URL}/v1/images/multi-image2image/{task_id}"
94
 
95
  try:
96
  response = requests.get(status_url, headers=headers)
 
100
  return None, f"Status check failed: {str(e)}"
101
 
102
  # ===== MAIN PROCESSING =====
103
+ def generate_image(subject_images, prompt):
104
+ """Handle complete image generation workflow"""
105
+ # Validate images
106
+ for img in subject_images:
107
+ if img: # Only validate non-empty images
108
+ is_valid, error_msg = validate_image(img)
109
+ if not is_valid:
110
+ return None, error_msg
111
 
112
+ # Create task
113
+ task_response, error = create_multi_image_task(subject_images, prompt)
 
 
 
 
 
 
 
114
  if error:
115
  return None, error
116
 
 
118
  return None, f"API error: {task_response.get('message', 'Unknown error')}"
119
 
120
  task_id = task_response["data"]["task_id"]
121
+ logger.info(f"Task created: {task_id}")
122
 
123
+ # Poll for results (max 10 minutes)
124
+ for _ in range(60):
125
  task_data, error = check_task_status(task_id)
126
  if error:
127
  return None, error
 
133
  try:
134
  response = requests.get(image_url)
135
  response.raise_for_status()
136
+ output_path = Path(f"/tmp/kling_output_{task_id}.png")
137
  with open(output_path, "wb") as f:
138
  f.write(response.content)
139
  return str(output_path), None
140
  except Exception as e:
141
+ return None, f"Failed to download result: {str(e)}"
142
 
143
  elif status in ("failed", "canceled"):
144
  error_msg = task_data["data"].get("task_status_msg", "Unknown error")
 
146
 
147
  time.sleep(10)
148
 
149
+ return None, "Task timed out after 10 minutes"
150
 
151
  # ===== GRADIO INTERFACE =====
152
+ def process_interface(subject_images, prompt):
153
+ # Filter out None values from subject_images
154
+ valid_images = [img for img in subject_images if img is not None]
155
+
156
+ if len(valid_images) < 2:
157
+ return None, None, "Please upload at least 2 subject images"
158
 
159
+ output_path, error = generate_image(valid_images, prompt)
160
  if error:
161
  return None, None, error
162
 
163
+ return output_path, output_path, "Generation successful!"
164
 
165
+ with gr.Blocks(title="Kling AI Multi-Image Generator") as app:
166
+ gr.Markdown("## 🖼️ Kling AI Multi-Image to Image")
167
+ gr.Markdown("Combine features from multiple images into one result")
168
 
169
  with gr.Row():
170
  with gr.Column():
171
  gr.Markdown("### Input Settings")
172
+ with gr.Row():
173
+ subject_image1 = gr.Image(type="filepath", label="Subject Image 1")
174
+ subject_image2 = gr.Image(type="filepath", label="Subject Image 2")
175
+ with gr.Row():
176
+ subject_image3 = gr.Image(type="filepath", label="Subject Image 3 (Optional)")
177
+ subject_image4 = gr.Image(type="filepath", label="Subject Image 4 (Optional)")
178
+
179
  prompt_input = gr.Textbox(
180
+ label="Transformation Prompt",
181
+ placeholder="Describe how to combine these images (e.g. 'merge facial features from all images')"
 
 
 
 
 
 
 
 
182
  )
183
+
184
+ generate_btn = gr.Button("Generate", variant="primary")
185
 
186
  gr.Markdown("### Requirements")
187
  gr.Markdown("""
188
+ - **Minimum 2 subject images required**
189
+ - Max 4 images total
190
+ - Max size per image: 10MB
191
  - Formats: JPG, PNG
192
+ - Min dimensions: 300x300px
193
  """)
194
 
195
  with gr.Column():
196
  gr.Markdown("### Output")
197
+ output_image = gr.Image(label="Generated Image", interactive=False, height=400)
198
+ output_file = gr.File(label="Download Result", file_types=["image/png"])
199
+ status_output = gr.Textbox(label="Status", interactive=False)
 
 
 
 
 
 
 
 
 
 
200
 
201
  generate_btn.click(
202
  fn=process_interface,
203
+ inputs=[gr.components.List([
204
+ subject_image1,
205
+ subject_image2,
206
+ subject_image3,
207
+ subject_image4
208
+ ]), prompt_input],
209
  outputs=[output_image, output_file, status_output]
210
  )
211