File size: 6,121 Bytes
e1d14d5
 
 
 
 
 
 
 
 
3ece5ec
 
e1d14d5
3ece5ec
 
e1d14d5
 
3ece5ec
 
 
e1d14d5
 
3ece5ec
e1d14d5
 
 
 
 
 
 
 
 
 
 
 
 
 
3ece5ec
e1d14d5
 
3ece5ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e1d14d5
3ece5ec
e1d14d5
 
3ece5ec
e1d14d5
3ece5ec
e1d14d5
 
 
3ece5ec
 
 
 
 
 
 
 
 
 
 
e1d14d5
 
 
 
3ece5ec
e1d14d5
 
 
 
3ece5ec
b6a80c5
8a96280
b6a80c5
8a96280
 
3ece5ec
 
 
 
e1d14d5
 
 
 
3ece5ec
e1d14d5
 
3ece5ec
e1d14d5
 
 
 
 
 
 
3ece5ec
b6a80c5
 
3ece5ec
 
 
 
b6a80c5
 
3ece5ec
b6a80c5
e1d14d5
 
 
 
 
 
 
 
 
3ece5ec
 
 
 
 
 
 
 
e1d14d5
3ece5ec
 
 
8a96280
3ece5ec
 
 
 
 
 
 
 
 
 
 
 
 
e1d14d5
 
3ece5ec
 
 
 
 
 
 
 
 
 
 
 
 
e1d14d5
3ece5ec
 
 
 
 
e1d14d5
 
3ece5ec
b6a80c5
 
 
 
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
187
188
import gradio as gr
import torch
from PIL import Image
import base64
from io import BytesIO
import json

print("πŸš€ Starting Affecto Inference Service...")

# Import our MagicFace model
from magicface_model import MagicFaceModel

# Initialize model
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"πŸ–₯️  Device: {device}")

print("πŸ“₯ Loading MagicFace model...")
model = MagicFaceModel(device=device)
print("βœ… Model ready!")

# ============================================
# UTILITY FUNCTIONS
# ============================================

def pil_to_base64(image):
    """Convert PIL to base64"""
    buffered = BytesIO()
    image.save(buffered, format="JPEG", quality=95)
    return base64.b64encode(buffered.getvalue()).decode()

def base64_to_pil(base64_str):
    """Convert base64 to PIL"""
    image_bytes = base64.b64decode(base64_str)
    return Image.open(BytesIO(image_bytes))

# ============================================
# INFERENCE FUNCTIONS
# ============================================

def transform_gradio(image, au_params_str):
    """Gradio interface function"""
    try:
        # Parse AU params
        au_params = json.loads(au_params_str)
        
        # Ensure image is 512x512
        if image.size != (512, 512):
            image = image.resize((512, 512), Image.LANCZOS)
        
        # Transform
        result_image = model.transform(image, au_params)
        
        return result_image
    except Exception as e:
        print(f"❌ Error: {str(e)}")
        import traceback
        traceback.print_exc()
        return image

def transform_api(image_base64, au_params_str):
    """API function for external calls"""
    try:
        print(f"πŸ“₯ Received API request")
        
        # Decode image
        image = base64_to_pil(image_base64)
        print(f"πŸ“Έ Image size: {image.size}")
        
        # Parse AU params
        au_params = json.loads(au_params_str)
        
        # Ensure 512x512
        if image.size != (512, 512):
            image = image.resize((512, 512), Image.LANCZOS)
        
        # Transform
        result_image = model.transform(image, au_params)
        
        # Encode result
        result_base64 = pil_to_base64(result_image)
        
        print("βœ… Transformation complete")
        
        return result_base64
    except Exception as e:
        print(f"❌ API Error: {str(e)}")
        import traceback
        traceback.print_exc()
        raise

# ============================================
# GRADIO INTERFACE
# ============================================

with gr.Blocks(theme=gr.themes.Soft(), title="Affecto MagicFace API") as demo:
    gr.Markdown("# 🎭 Affecto - MagicFace Emotion Transformation")
    gr.Markdown("Transform facial emotions using Action Units (AU)")
    gr.Markdown("⚠️ **Note:** Currently using simplified model. Full MagicFace pipeline coming soon!")
    
    with gr.Tab("πŸ–ΌοΈ Web Interface"):
        with gr.Row():
            with gr.Column():
                input_image = gr.Image(type="pil", label="Upload Face Image (512x512 recommended)")
                au_params_input = gr.Textbox(
                    label="AU Parameters (JSON)",
                    value='{"AU6": 2.0, "AU12": 2.0}',
                    lines=3
                )
                transform_btn = gr.Button("✨ Transform", variant="primary", size="lg")
            
            with gr.Column():
                output_image = gr.Image(type="pil", label="Transformed Result")
        
        gr.Markdown("### 🎨 Emotion Presets (click to use):")
        gr.Examples(
            examples=[
                ['{"AU6": 2.0, "AU12": 2.0}'],  # Happy
                ['{"AU1": 2.0, "AU4": 2.0, "AU15": 2.0}'],  # Sad
                ['{"AU4": 3.0, "AU5": 2.0, "AU7": 2.0}'],  # Angry
                ['{"AU1": 3.0, "AU2": 2.0, "AU5": 3.0, "AU26": 2.0}'],  # Surprised
            ],
            inputs=[au_params_input],
            label="Emotion Presets"
        )
        
        transform_btn.click(
            fn=transform_gradio,
            inputs=[input_image, au_params_input],
            outputs=output_image
        )
    
    with gr.Tab("πŸ“‘ API Documentation"):
        gr.Markdown("""
        ## API Usage
        
        ### Gradio API Endpoint
        
        ```python
        import requests
        import base64
        import json
        
        # Prepare image
        with open("face.jpg", "rb") as f:
            image_base64 = base64.b64encode(f.read()).decode()
        
        # Call API
        response = requests.post(
            "https://gauravvjhaa-affecto-inference.hf.space/api/predict",
            json={
                "data": [
                    image_base64,
                    '{"AU6": 2.0, "AU12": 2.0}'
                ]
            }
        )
        
        result = response.json()
        result_image = result["data"][0]  # base64 string
        ```
        
        ### Available Action Units:
        - **AU1** (0): Inner Brow Raiser - Values: 0-4
        - **AU2** (1): Outer Brow Raiser - Values: 0-4
        - **AU4** (2): Brow Lowerer - Values: 0-4
        - **AU5** (3): Upper Lid Raiser - Values: 0-4
        - **AU6** (4): Cheek Raiser - Values: 0-4
        - **AU9** (5): Nose Wrinkler - Values: 0-4
        - **AU12** (6): Lip Corner Puller (Smile) - Values: 0-4
        - **AU15** (7): Lip Corner Depressor - Values: 0-4
        - **AU17** (8): Chin Raiser - Values: 0-4
        - **AU20** (9): Lip Stretcher - Values: 0-4
        - **AU25** (10): Lips Part - Values: 0-4
        - **AU26** (11): Jaw Drop - Values: 0-4
        
        ### Example Combinations:
        - **Happy**: `{"AU6": 2, "AU12": 2}`
        - **Sad**: `{"AU1": 2, "AU4": 2, "AU15": 2}`
        - **Angry**: `{"AU4": 3, "AU5": 2, "AU7": 2}`
        - **Surprised**: `{"AU1": 3, "AU2": 2, "AU5": 3, "AU26": 2}`
        """)

print("βœ… Affecto MagicFace API Ready!")
print(f"🌐 Gradio UI: https://gauravvjhaa-affecto-inference.hf.space/")

if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=7860)