JuanjoSG5
commited on
Commit
·
cc083b4
1
Parent(s):
417d69b
curretn progress
Browse files- mcp_server.py +71 -9
- src/utils/describe.py +3 -0
- src/utils/generate_image.py +2 -8
- src/utils/remove_background.py +66 -24
mcp_server.py
CHANGED
@@ -1,11 +1,9 @@
|
|
1 |
import gradio as gr
|
2 |
from src.utils.change_format import change_format
|
3 |
-
from src.utils.remove_background import
|
4 |
-
from src.utils.visualize_image import visualize_base64_image
|
5 |
from src.utils.generate_image import generate_image
|
6 |
from src.utils.apply_filter import apply_filter
|
7 |
from src.utils.add_text import add_text_to_image
|
8 |
-
from src.utils.resize_image import resize_image
|
9 |
from src.utils.watermark import add_watermark, remove_watermark
|
10 |
from src.utils.describe import describe_image
|
11 |
from src.utils.compress import compress_image
|
@@ -24,9 +22,55 @@ def image_to_base64(image):
|
|
24 |
def base64_to_image(base64_str):
|
25 |
if not base64_str:
|
26 |
return None
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
def url_to_base64(url):
|
31 |
response = requests.get(url)
|
32 |
return base64.b64encode(response.content).decode()
|
@@ -35,8 +79,26 @@ def gradio_remove_background(image):
|
|
35 |
if image is None:
|
36 |
return None
|
37 |
base64_img = image_to_base64(image)
|
38 |
-
result =
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
def gradio_describe_image(image):
|
42 |
if image is None:
|
@@ -53,7 +115,7 @@ def gradio_change_format(image, format_type):
|
|
53 |
|
54 |
def gradio_generate_image(prompt, width=512, height=512):
|
55 |
result = generate_image(prompt, width, height)
|
56 |
-
return base64_to_image(result)
|
57 |
|
58 |
def gradio_apply_filter(image, filter_type):
|
59 |
if image is None:
|
|
|
1 |
import gradio as gr
|
2 |
from src.utils.change_format import change_format
|
3 |
+
from src.utils.remove_background import remove_background
|
|
|
4 |
from src.utils.generate_image import generate_image
|
5 |
from src.utils.apply_filter import apply_filter
|
6 |
from src.utils.add_text import add_text_to_image
|
|
|
7 |
from src.utils.watermark import add_watermark, remove_watermark
|
8 |
from src.utils.describe import describe_image
|
9 |
from src.utils.compress import compress_image
|
|
|
22 |
def base64_to_image(base64_str):
|
23 |
if not base64_str:
|
24 |
return None
|
25 |
+
|
26 |
+
# Remove data URI prefix if present (e.g., "data:image/png;base64,")
|
27 |
+
if isinstance(base64_str, str) and "base64," in base64_str:
|
28 |
+
base64_str = base64_str.split("base64,", 1)[1]
|
29 |
+
|
30 |
+
try:
|
31 |
+
# Strip any whitespace that might be in the base64 string
|
32 |
+
if isinstance(base64_str, str):
|
33 |
+
base64_str = base64_str.strip()
|
34 |
+
|
35 |
+
# Decode the base64 data
|
36 |
+
image_data = base64.b64decode(base64_str)
|
37 |
+
|
38 |
+
# Check if we have data
|
39 |
+
if not image_data:
|
40 |
+
print("Decoded base64 data is empty")
|
41 |
+
return None
|
42 |
+
|
43 |
+
# Attempt to open the image
|
44 |
+
image = Image.open(io.BytesIO(image_data))
|
45 |
+
|
46 |
+
# Convert the image to ensure it's valid
|
47 |
+
return image.copy()
|
48 |
+
|
49 |
+
except base64.binascii.Error as e:
|
50 |
+
print(f"Base64 decoding error: {str(e)}")
|
51 |
+
if isinstance(base64_str, str):
|
52 |
+
preview = base64_str[:30] + "..." if len(base64_str) > 30 else base64_str
|
53 |
+
print(f"Base64 preview: {preview}")
|
54 |
+
return None
|
55 |
+
|
56 |
+
except Exception as e:
|
57 |
+
print(f"Error converting base64 to image: {str(e)}")
|
58 |
+
|
59 |
+
# Print preview of the base64 string for debugging
|
60 |
+
if isinstance(base64_str, str):
|
61 |
+
preview = base64_str[:30] + "..." if len(base64_str) > 30 else base64_str
|
62 |
+
print(f"Base64 preview: {preview}")
|
63 |
+
|
64 |
+
# Additional debug information
|
65 |
+
if 'image_data' in locals() and image_data:
|
66 |
+
try:
|
67 |
+
magic_bytes = image_data[:12].hex()
|
68 |
+
print(f"First 12 bytes: {magic_bytes}")
|
69 |
+
except:
|
70 |
+
pass
|
71 |
+
|
72 |
+
return None
|
73 |
+
|
74 |
def url_to_base64(url):
|
75 |
response = requests.get(url)
|
76 |
return base64.b64encode(response.content).decode()
|
|
|
79 |
if image is None:
|
80 |
return None
|
81 |
base64_img = image_to_base64(image)
|
82 |
+
result = remove_background(f"data:image/png;base64,{base64_img}")
|
83 |
+
|
84 |
+
# Check if the result is directly a base64 string or has an image_data key
|
85 |
+
if isinstance(result, str):
|
86 |
+
return base64_to_image(result)
|
87 |
+
elif isinstance(result, dict) and "image_data" in result:
|
88 |
+
# If image_data contains a data URI prefix
|
89 |
+
if isinstance(result["image_data"], str) and result["image_data"].startswith("data:"):
|
90 |
+
# The response already contains the full data URI
|
91 |
+
return base64_to_image(result["image_data"])
|
92 |
+
else:
|
93 |
+
# Try to process it as a regular base64 string
|
94 |
+
try:
|
95 |
+
return base64_to_image(result["image_data"])
|
96 |
+
except Exception as e:
|
97 |
+
print(f"Error processing image data: {e}")
|
98 |
+
return None
|
99 |
+
else:
|
100 |
+
print(f"Unexpected response format from remove_background: {type(result)}")
|
101 |
+
return None
|
102 |
|
103 |
def gradio_describe_image(image):
|
104 |
if image is None:
|
|
|
115 |
|
116 |
def gradio_generate_image(prompt, width=512, height=512):
|
117 |
result = generate_image(prompt, width, height)
|
118 |
+
return base64_to_image(result["b64"])
|
119 |
|
120 |
def gradio_apply_filter(image, filter_type):
|
121 |
if image is None:
|
src/utils/describe.py
CHANGED
@@ -4,6 +4,8 @@ import requests
|
|
4 |
from pathlib import Path
|
5 |
from openai import OpenAI
|
6 |
from urllib.parse import urlparse
|
|
|
|
|
7 |
|
8 |
def describe_image(image_path: str) -> str:
|
9 |
"""
|
@@ -14,6 +16,7 @@ def describe_image(image_path: str) -> str:
|
|
14 |
|
15 |
Returns:
|
16 |
A string description of the image """
|
|
|
17 |
|
18 |
# Check if API key is available
|
19 |
api_key = os.getenv("NEBIUS_API_KEY")
|
|
|
4 |
from pathlib import Path
|
5 |
from openai import OpenAI
|
6 |
from urllib.parse import urlparse
|
7 |
+
from dotenv import load_dotenv
|
8 |
+
|
9 |
|
10 |
def describe_image(image_path: str) -> str:
|
11 |
"""
|
|
|
16 |
|
17 |
Returns:
|
18 |
A string description of the image """
|
19 |
+
load_dotenv()
|
20 |
|
21 |
# Check if API key is available
|
22 |
api_key = os.getenv("NEBIUS_API_KEY")
|
src/utils/generate_image.py
CHANGED
@@ -3,9 +3,8 @@ import base64
|
|
3 |
from typing import Dict, Any
|
4 |
from openai import OpenAI
|
5 |
|
6 |
-
|
7 |
prompt: str,
|
8 |
-
output_path: str = "generated_image.png",
|
9 |
width: int = 1024,
|
10 |
height: int = 1024,
|
11 |
num_inference_steps: int = 28,
|
@@ -50,17 +49,12 @@ async def generate_image(
|
|
50 |
|
51 |
image_data = base64.b64decode(response.data[0].b64_json)
|
52 |
|
53 |
-
with open(output_path, 'wb') as output_file:
|
54 |
-
output_file.write(image_data)
|
55 |
-
|
56 |
-
output_size = os.path.getsize(output_path)
|
57 |
|
58 |
return {
|
59 |
"success": True,
|
60 |
"message": "Image generated successfully",
|
61 |
"prompt": prompt,
|
62 |
-
"
|
63 |
-
"output_size_bytes": output_size,
|
64 |
"generation_params": {
|
65 |
"width": width,
|
66 |
"height": height,
|
|
|
3 |
from typing import Dict, Any
|
4 |
from openai import OpenAI
|
5 |
|
6 |
+
def generate_image(
|
7 |
prompt: str,
|
|
|
8 |
width: int = 1024,
|
9 |
height: int = 1024,
|
10 |
num_inference_steps: int = 28,
|
|
|
49 |
|
50 |
image_data = base64.b64decode(response.data[0].b64_json)
|
51 |
|
|
|
|
|
|
|
|
|
52 |
|
53 |
return {
|
54 |
"success": True,
|
55 |
"message": "Image generated successfully",
|
56 |
"prompt": prompt,
|
57 |
+
"b64": image_data,
|
|
|
58 |
"generation_params": {
|
59 |
"width": width,
|
60 |
"height": height,
|
src/utils/remove_background.py
CHANGED
@@ -1,46 +1,88 @@
|
|
1 |
import requests
|
2 |
-
from typing import Optional, Dict, Any
|
3 |
import os
|
4 |
import rembg
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
-
|
7 |
-
|
8 |
-
output_path: str,
|
9 |
model_name: str = "u2net"
|
10 |
) -> Dict[str, Any]:
|
11 |
"""
|
12 |
-
Remove background from an image
|
13 |
|
14 |
Args:
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
|
|
17 |
model_name: Background removal model to use
|
18 |
|
19 |
Returns:
|
20 |
-
Dictionary with result information
|
21 |
"""
|
22 |
|
23 |
try:
|
24 |
-
#
|
25 |
-
response = requests.get(image_url, timeout=30)
|
26 |
-
response.raise_for_status()
|
27 |
-
|
28 |
-
# Remove background
|
29 |
session = rembg.new_session(model_name=model_name)
|
30 |
-
output_data = rembg.remove(response.content, session=session)
|
31 |
|
32 |
-
#
|
33 |
-
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
-
|
|
|
37 |
|
38 |
return {
|
39 |
"success": True,
|
40 |
-
"message": f"Background removed from
|
41 |
-
"
|
42 |
-
"output_path": output_path,
|
43 |
-
"output_size_bytes": output_size,
|
44 |
"model_used": model_name
|
45 |
}
|
46 |
|
@@ -48,11 +90,11 @@ async def remove_background_from_url(
|
|
48 |
return {
|
49 |
"success": False,
|
50 |
"error": f"Failed to download image: {str(e)}",
|
51 |
-
"
|
52 |
}
|
53 |
except Exception as e:
|
54 |
return {
|
55 |
"success": False,
|
56 |
"error": f"Failed to process image: {str(e)}",
|
57 |
-
"
|
58 |
}
|
|
|
1 |
import requests
|
2 |
+
from typing import Optional, Dict, Any, Union
|
3 |
import os
|
4 |
import rembg
|
5 |
+
import numpy as np
|
6 |
+
from PIL import Image
|
7 |
+
import io
|
8 |
+
import base64
|
9 |
+
import re
|
10 |
|
11 |
+
def remove_background(
|
12 |
+
image_input: Union[str, bytes, np.ndarray, Image.Image],
|
|
|
13 |
model_name: str = "u2net"
|
14 |
) -> Dict[str, Any]:
|
15 |
"""
|
16 |
+
Remove background from an image.
|
17 |
|
18 |
Args:
|
19 |
+
image_input: Can be one of:
|
20 |
+
- URL string
|
21 |
+
- Data URL string (base64 encoded)
|
22 |
+
- Image bytes
|
23 |
+
- NumPy array
|
24 |
+
- PIL Image
|
25 |
model_name: Background removal model to use
|
26 |
|
27 |
Returns:
|
28 |
+
Dictionary with result information and processed image data
|
29 |
"""
|
30 |
|
31 |
try:
|
32 |
+
# Initialize session
|
|
|
|
|
|
|
|
|
33 |
session = rembg.new_session(model_name=model_name)
|
|
|
34 |
|
35 |
+
# Handle different input types
|
36 |
+
if isinstance(image_input, str):
|
37 |
+
if image_input.startswith('http://') or image_input.startswith('https://'):
|
38 |
+
# If input is a URL, download the image
|
39 |
+
response = requests.get(image_input, timeout=30)
|
40 |
+
response.raise_for_status()
|
41 |
+
input_data = response.content
|
42 |
+
source_info = f"URL: {image_input}"
|
43 |
+
elif image_input.startswith('data:'):
|
44 |
+
# If input is a data URL (base64 encoded string)
|
45 |
+
# Extract the base64 part after the comma
|
46 |
+
base64_data = re.sub('^data:image/.+;base64,', '', image_input)
|
47 |
+
input_data = base64.b64decode(base64_data)
|
48 |
+
source_info = "data URL"
|
49 |
+
else:
|
50 |
+
return {
|
51 |
+
"success": False,
|
52 |
+
"error": f"Unsupported string input format: {image_input[:30]}...",
|
53 |
+
"image_data": None
|
54 |
+
}
|
55 |
+
elif isinstance(image_input, bytes):
|
56 |
+
# If input is bytes, use directly
|
57 |
+
input_data = image_input
|
58 |
+
source_info = "image bytes"
|
59 |
+
elif isinstance(image_input, np.ndarray):
|
60 |
+
# If input is numpy array, convert to bytes
|
61 |
+
pil_img = Image.fromarray(image_input)
|
62 |
+
buffer = io.BytesIO()
|
63 |
+
pil_img.save(buffer, format="PNG")
|
64 |
+
input_data = buffer.getvalue()
|
65 |
+
source_info = "numpy array"
|
66 |
+
elif isinstance(image_input, Image.Image):
|
67 |
+
# If input is PIL Image, convert to bytes
|
68 |
+
buffer = io.BytesIO()
|
69 |
+
image_input.save(buffer, format="PNG")
|
70 |
+
input_data = buffer.getvalue()
|
71 |
+
source_info = "PIL Image"
|
72 |
+
else:
|
73 |
+
return {
|
74 |
+
"success": False,
|
75 |
+
"error": f"Unsupported input type: {type(image_input)}",
|
76 |
+
"image_data": None
|
77 |
+
}
|
78 |
|
79 |
+
# Remove background
|
80 |
+
output_data = rembg.remove(input_data, session=session)
|
81 |
|
82 |
return {
|
83 |
"success": True,
|
84 |
+
"message": f"Background removed from {source_info} using {model_name} model",
|
85 |
+
"image_data": output_data,
|
|
|
|
|
86 |
"model_used": model_name
|
87 |
}
|
88 |
|
|
|
90 |
return {
|
91 |
"success": False,
|
92 |
"error": f"Failed to download image: {str(e)}",
|
93 |
+
"image_data": None
|
94 |
}
|
95 |
except Exception as e:
|
96 |
return {
|
97 |
"success": False,
|
98 |
"error": f"Failed to process image: {str(e)}",
|
99 |
+
"image_data": None
|
100 |
}
|