File size: 6,234 Bytes
85a7fa6
a594839
1a8f2c7
ae39b5f
85a7fa6
ae39b5f
85a7fa6
ae39b5f
1a8f2c7
ae39b5f
 
85a7fa6
 
ae39b5f
97f568a
 
ae39b5f
 
1a8f2c7
ae39b5f
1a8f2c7
ae39b5f
3a257f2
fab14c7
ae39b5f
 
3a257f2
ae39b5f
c3f22c6
ae39b5f
 
85a7fa6
ae39b5f
 
 
 
 
 
85a7fa6
ae39b5f
c3f22c6
ae39b5f
 
 
1a8f2c7
 
 
a594839
ae39b5f
85a7fa6
ae39b5f
 
 
 
 
85a7fa6
a594839
ae39b5f
 
 
 
 
 
 
 
c3f22c6
ae39b5f
 
 
 
 
c3f22c6
ae39b5f
c3f22c6
ae39b5f
 
 
 
c3f22c6
ae39b5f
 
 
 
 
 
 
c3f22c6
ae39b5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c3f22c6
ae39b5f
c3f22c6
ae39b5f
 
 
 
 
 
 
 
 
85a7fa6
ae39b5f
85a7fa6
ae39b5f
 
 
85a7fa6
 
 
ae39b5f
 
85857de
ae39b5f
 
 
 
85a7fa6
 
ae39b5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85a7fa6
ae39b5f
 
 
 
 
 
85a7fa6
 
ae39b5f
85a7fa6
1a8f2c7
045423f
ae39b5f
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import gradio as gr
import requests
import base64
import os
import time
import jwt
import logging
from pathlib import Path

# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# ===== CONFIGURATION =====
ACCESS_KEY_ID = "AFyHfnQATghFdCMyAG3gRPbNY4TNKFGB"
ACCESS_KEY_SECRET = "TTepeLyBterLNM3brYPGmdndBnnyKJBA"
BASE_URL = "https://api-singapore.klingai.com"
CREATE_TASK_URL = f"{BASE_URL}/v1/images/generations"

# ===== UTILITY FUNCTIONS =====
def generate_jwt_token():
    """Generate JWT token for API authentication"""
    payload = {
        "iss": ACCESS_KEY_ID,
        "exp": int(time.time()) + 1800,  # Expires in 30 mins
        "nbf": int(time.time()) - 5      # Not before 5 seconds ago
    }
    return jwt.encode(payload, ACCESS_KEY_SECRET, algorithm="HS256")

def validate_image(image_path):
    """Check image meets API requirements"""
    try:
        img_size = os.path.getsize(image_path) / 1024 / 1024  # MB
        if img_size > 10:
            return False, "Image too large (max 10MB)"
        
        # Add actual dimension check if possible (requires PIL)
        return True, ""
    except Exception as e:
        return False, f"Image validation error: {str(e)}"

# ===== API FUNCTIONS =====
def create_image_task(image_base64, prompt):
    """Create image generation task"""
    headers = {
        "Authorization": f"Bearer {generate_jwt_token()}",
        "Content-Type": "application/json"
    }
    
    payload = {
        "model_name": "kling-v2",  # Best for image-to-image
        "prompt": prompt,
        "image": image_base64,
        "resolution": "2k",
        "n": 1,
        "aspect_ratio": "1:1"
    }
    
    try:
        response = requests.post(CREATE_TASK_URL, json=payload, headers=headers)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        logger.error(f"API request failed: {str(e)}")
        return None

def get_task_result(task_id):
    """Retrieve task results"""
    headers = {"Authorization": f"Bearer {generate_jwt_token()}"}
    task_url = f"{BASE_URL}/v1/images/generations/{task_id}"
    
    try:
        response = requests.get(task_url, headers=headers)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        logger.error(f"Task status check failed: {str(e)}")
        return None

# ===== MAIN PROCESSING =====
def generate_image(image_path, prompt=""):
    """Handle end-to-end image generation"""
    # Validate input image
    is_valid, error_msg = validate_image(image_path)
    if not is_valid:
        return None, error_msg

    # Prepare image data
    try:
        with open(image_path, "rb") as img_file:
            image_base64 = base64.b64encode(img_file.read()).decode("utf-8")
    except Exception as e:
        return None, f"Image processing error: {str(e)}"

    # Create generation task
    task_response = create_image_task(image_base64, prompt or "Transform into a vibrant cartoon style")
    if not task_response or task_response.get("code") != 0:
        return None, "Failed to create task"

    task_id = task_response["data"]["task_id"]
    logger.info(f"Created task: {task_id}")

    # Poll for results (max 10 mins)
    for _ in range(60):
        task_data = get_task_result(task_id)
        if not task_data:
            time.sleep(5)
            continue
            
        status = task_data["data"]["task_status"]
        
        if status == "succeed":
            image_url = task_data["data"]["task_result"]["images"][0]["url"]
            try:
                img_data = requests.get(image_url).content
                output_path = Path(f"/tmp/kling_output_{task_id}.png")
                with open(output_path, "wb") as f:
                    f.write(img_data)
                return str(output_path), None
            except Exception as e:
                return None, f"Failed to save image: {str(e)}"
                
        elif status in ("failed", "canceled"):
            return None, f"Task failed: {task_data.get('task_status_msg', 'Unknown error')}"
            
        time.sleep(10)
    
    return None, "Task timed out after 10 minutes"

# ===== GRADIO INTERFACE =====
def chatbot_interface(image, prompt):
    if not image:
        return None, None, "Please upload an image first"
    
    output_path, error = generate_image(image, prompt)
    if error:
        return None, None, error
    
    return output_path, output_path, "Generation successful!"

with gr.Blocks(title="Kling AI Image Transformer") as app:
    gr.Markdown("# 🎨 Kling AI Image-to-Image Generator")
    gr.Markdown("Transform images using Kling AI's Kolors technology")
    
    with gr.Row():
        with gr.Column():
            gr.Markdown("## Input Settings")
            image_input = gr.Image(
                type="filepath", 
                label="Upload Image",
                sources=["upload"],
            )
            prompt_input = gr.Textbox(
                lines=2,
                label="Transformation Prompt",
                placeholder="Describe how you want to transform the image (e.g. 'vibrant watercolor painting')"
            )
            generate_btn = gr.Button("Generate", variant="primary")
            
            gr.Markdown("### Requirements")
            gr.Markdown("""
            - Max image size: 10MB
            - Min dimensions: 300x300px
            - Supported formats: JPG, PNG
            - Aspect ratio: Between 1:2.5 and 2.5:1
            """)
            
        with gr.Column():
            gr.Markdown("## Output")
            output_image = gr.Image(label="Generated Image", interactive=False)
            output_file = gr.File(label="Download Result", file_types=["image/png"])
            status_output = gr.Textbox(label="Status", interactive=False)
    
    generate_btn.click(
        fn=chatbot_interface,
        inputs=[image_input, prompt_input],
        outputs=[output_image, output_file, status_output]
    )

if __name__ == "__main__":
    app.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False,
        show_error=True
    )