Chris4K commited on
Commit
4bec348
·
verified ·
1 Parent(s): 7bd14af

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +206 -0
app.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import PIL.Image as Image
3
+ import io
4
+ import base64
5
+ import json
6
+ from typing import Union
7
+
8
+ def analyze_image(image: Image.Image) -> str:
9
+ """
10
+ Analyze an image and return detailed information about it.
11
+
12
+ Args:
13
+ image: The image to analyze (can be base64 string or file upload)
14
+
15
+ Returns:
16
+ str: JSON string with image analysis including dimensions, format, mode, and orientation
17
+ """
18
+ if image is None:
19
+ return json.dumps({"error": "No image provided"})
20
+
21
+ try:
22
+ # Get image properties
23
+ width, height = image.size
24
+ format_type = image.format or "Unknown"
25
+ mode = image.mode
26
+ orientation = "Portrait" if height > width else "Landscape" if width > height else "Square"
27
+
28
+ # Calculate aspect ratio
29
+ aspect_ratio = round(width / height, 2) if height > 0 else 0
30
+
31
+ # Get color information
32
+ colors = image.getcolors(maxcolors=256*256*256)
33
+ dominant_colors = len(colors) if colors else "Many"
34
+
35
+ analysis = {
36
+ "dimensions": {"width": width, "height": height},
37
+ "format": format_type,
38
+ "mode": mode,
39
+ "orientation": orientation,
40
+ "aspect_ratio": aspect_ratio,
41
+ "approximate_colors": dominant_colors,
42
+ "file_info": f"{width}x{height} {format_type} image in {mode} mode"
43
+ }
44
+
45
+ return json.dumps(analysis, indent=2)
46
+
47
+ except Exception as e:
48
+ return json.dumps({"error": f"Error analyzing image: {str(e)}"})
49
+
50
+ def get_image_orientation(image: Image.Image) -> str:
51
+ """
52
+ Determine if an image is portrait, landscape, or square.
53
+
54
+ Args:
55
+ image: The image to check orientation
56
+
57
+ Returns:
58
+ str: "Portrait", "Landscape", or "Square"
59
+ """
60
+ if image is None:
61
+ return "No image provided"
62
+
63
+ try:
64
+ width, height = image.size
65
+ if height > width:
66
+ return "Portrait"
67
+ elif width > height:
68
+ return "Landscape"
69
+ else:
70
+ return "Square"
71
+ except Exception as e:
72
+ return f"Error: {str(e)}"
73
+
74
+ def count_colors(image: Image.Image) -> str:
75
+ """
76
+ Count the approximate number of unique colors in an image.
77
+
78
+ Args:
79
+ image: The image to analyze for color count
80
+
81
+ Returns:
82
+ str: Description of color count and dominant color information
83
+ """
84
+ if image is None:
85
+ return "No image provided"
86
+
87
+ try:
88
+ # Convert to RGB if not already
89
+ if image.mode != 'RGB':
90
+ image = image.convert('RGB')
91
+
92
+ # Get colors (limit to prevent memory issues)
93
+ colors = image.getcolors(maxcolors=256*256*256)
94
+
95
+ if colors is None:
96
+ return "Image has more than 16.7 million unique colors"
97
+
98
+ # Sort by frequency
99
+ colors.sort(key=lambda x: x[0], reverse=True)
100
+
101
+ # Get top 3 colors
102
+ top_colors = colors[:3]
103
+ color_info = []
104
+
105
+ for count, color in top_colors:
106
+ if isinstance(color, tuple) and len(color) >= 3:
107
+ r, g, b = color[:3]
108
+ hex_color = f"#{r:02x}{g:02x}{b:02x}"
109
+ percentage = round((count / sum(c[0] for c in colors)) * 100, 1)
110
+ color_info.append(f"RGB{color} ({hex_color}) - {percentage}%")
111
+
112
+ result = f"Total unique colors: {len(colors)}\n"
113
+ result += "Top colors by frequency:\n" + "\n".join(color_info)
114
+
115
+ return result
116
+
117
+ except Exception as e:
118
+ return f"Error analyzing colors: {str(e)}"
119
+
120
+ def extract_text_info(image: Image.Image) -> str:
121
+ """
122
+ Extract basic information about text-like content in an image.
123
+
124
+ Args:
125
+ image: The image to analyze for text content
126
+
127
+ Returns:
128
+ str: Basic information about potential text content
129
+ """
130
+ if image is None:
131
+ return "No image provided"
132
+
133
+ try:
134
+ # Convert to grayscale for analysis
135
+ gray = image.convert('L')
136
+
137
+ # Get image statistics
138
+ extrema = gray.getextrema()
139
+
140
+ # Simple heuristics for text detection
141
+ contrast = extrema[1] - extrema[0]
142
+
143
+ analysis = {
144
+ "image_mode": image.mode,
145
+ "grayscale_range": f"{extrema[0]} to {extrema[1]}",
146
+ "contrast_level": "High" if contrast > 200 else "Medium" if contrast > 100 else "Low",
147
+ "potential_text": "Likely contains text" if contrast > 150 else "May contain text" if contrast > 100 else "Unlikely to contain text",
148
+ "note": "This is a basic analysis. For proper OCR, use specialized text extraction tools."
149
+ }
150
+
151
+ return json.dumps(analysis, indent=2)
152
+
153
+ except Exception as e:
154
+ return f"Error analyzing for text: {str(e)}"
155
+
156
+ # Create the Gradio interface
157
+ with gr.Blocks(title="Image Analysis MCP Server") as demo:
158
+ gr.Markdown("""
159
+ # Image Analysis MCP Server
160
+
161
+ This Gradio app serves as an MCP server that can analyze images sent from Claude or other MCP clients.
162
+
163
+ **Available Tools:**
164
+ - `analyze_image`: Get comprehensive image analysis (dimensions, format, colors, etc.)
165
+ - `get_image_orientation`: Check if image is portrait, landscape, or square
166
+ - `count_colors`: Analyze color information and dominant colors
167
+ - `extract_text_info`: Basic analysis for potential text content
168
+
169
+ **Usage with Claude Desktop:**
170
+ 1. Deploy this to HuggingFace Spaces
171
+ 2. Add the MCP configuration to Claude Desktop
172
+ 3. Send images to Claude and ask it to analyze them using these tools
173
+ """)
174
+
175
+ # Create interface for each function (these will be exposed as MCP tools)
176
+ with gr.Tab("Image Analysis"):
177
+ with gr.Row():
178
+ img_input1 = gr.Image(type="pil", label="Upload Image")
179
+ analysis_output = gr.JSON(label="Analysis Result")
180
+ analyze_btn = gr.Button("Analyze Image")
181
+ analyze_btn.click(analyze_image, inputs=[img_input1], outputs=[analysis_output])
182
+
183
+ with gr.Tab("Orientation Check"):
184
+ with gr.Row():
185
+ img_input2 = gr.Image(type="pil", label="Upload Image")
186
+ orientation_output = gr.Textbox(label="Orientation")
187
+ orientation_btn = gr.Button("Check Orientation")
188
+ orientation_btn.click(get_image_orientation, inputs=[img_input2], outputs=[orientation_output])
189
+
190
+ with gr.Tab("Color Analysis"):
191
+ with gr.Row():
192
+ img_input3 = gr.Image(type="pil", label="Upload Image")
193
+ color_output = gr.Textbox(label="Color Analysis", lines=10)
194
+ color_btn = gr.Button("Analyze Colors")
195
+ color_btn.click(count_colors, inputs=[img_input3], outputs=[color_output])
196
+
197
+ with gr.Tab("Text Detection"):
198
+ with gr.Row():
199
+ img_input4 = gr.Image(type="pil", label="Upload Image")
200
+ text_output = gr.JSON(label="Text Analysis")
201
+ text_btn = gr.Button("Analyze for Text")
202
+ text_btn.click(extract_text_info, inputs=[img_input4], outputs=[text_output])
203
+
204
+ if __name__ == "__main__":
205
+ # Launch with MCP server enabled
206
+ demo.launch(mcp_server=True, share=True)