AkinyemiAra commited on
Commit
72cd7d2
·
verified ·
1 Parent(s): 82b1628

Upload 9 files

Browse files
Files changed (9) hide show
  1. .huggingface-space +9 -0
  2. LICENSE +21 -0
  3. README.md +67 -14
  4. app.py +232 -0
  5. app_hf.py +222 -0
  6. example_client.py +151 -0
  7. requirements.txt +9 -0
  8. requirements_hf.txt +7 -0
  9. test_local.py +97 -0
.huggingface-space ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ title: Nomic Vision Embedding MCP Server
2
+ emoji: 🖼️
3
+ colorFrom: blue
4
+ colorTo: indigo
5
+ sdk: gradio
6
+ sdk_version: 5.26.0
7
+ app_file: app_hf.py
8
+ pinned: false
9
+ license: mit
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,14 +1,67 @@
1
- ---
2
- title: Nomic
3
- emoji: 📚
4
- colorFrom: gray
5
- colorTo: gray
6
- sdk: gradio
7
- sdk_version: 5.30.0
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- short_description: image embedding
12
- ---
13
-
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Nomic MCP Tool
3
+ emoji: 🗂️
4
+ colorFrom: indigo
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: "5.26.0"
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+ # Nomic Vision Embedding MCP Server
12
+
13
+ This is a Model Context Protocol (MCP) server for the [nomic-ai/nomic-embed-vision-v1.5](https://huggingface.co/nomic-ai/nomic-embed-vision-v1.5) image embedding model, deployed on Huggingface Spaces using Gradio.
14
+
15
+ ## Features
16
+
17
+ - Generate embeddings for images using the nomic-ai/nomic-embed-vision-v1.5 model
18
+ - Expose embedding functionality through a Gradio web interface
19
+ - Implement the Model Context Protocol (MCP) to allow integration with MCP clients
20
+
21
+ ## How It Works
22
+
23
+ This application provides two interfaces:
24
+
25
+ 1. **Web Interface**: A Gradio UI that allows users to upload images and view the generated embeddings
26
+ 2. **MCP Interface**: An implementation of the Model Context Protocol that exposes the embedding functionality as a tool
27
+
28
+ ## MCP Tool
29
+
30
+ The server exposes the following MCP tool:
31
+
32
+ - **embed_image**: Generate embeddings for an image
33
+ - Input:
34
+ - `image_url`: URL of the image to embed, OR
35
+ - `image_data`: Base64-encoded image data
36
+ - Output: JSON object containing the embedding vector and its dimension
37
+
38
+ ## Deployment
39
+
40
+ This application is designed to be deployed on Huggingface Spaces. To deploy:
41
+
42
+ 1. Create a new Space on Huggingface Spaces with the Gradio SDK
43
+ 2. Upload these files to your Space
44
+ 3. The Space will automatically build and deploy the application
45
+
46
+ ## Local Development
47
+
48
+ To run this application locally:
49
+
50
+ 1. Clone this repository
51
+ 2. Install the dependencies: `pip install -r requirements.txt`
52
+ 3. Run the application: `python app.py`
53
+ 4. Open your browser at http://localhost:7860
54
+
55
+ ## Requirements
56
+
57
+ - Python 3.7+
58
+ - Gradio 4.0+
59
+ - Transformers
60
+ - PyTorch
61
+ - Pillow
62
+ - NumPy
63
+ - Model Context Protocol library
64
+
65
+ ## License
66
+
67
+ This project is licensed under the MIT License - see the LICENSE file for details.
app.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import numpy as np
4
+ from PIL import Image
5
+ import os
6
+ import json
7
+ import base64
8
+ from io import BytesIO
9
+ import requests
10
+ from typing import Dict, List, Any, Optional
11
+ from transformers.pipelines import pipeline
12
+
13
+ # MCP imports
14
+ from modelcontextprotocol.server import Server
15
+ from modelcontextprotocol.server.gradio import GradioServerTransport
16
+ from modelcontextprotocol.types import (
17
+ CallToolRequestSchema,
18
+ ErrorCode,
19
+ ListToolsRequestSchema,
20
+ McpError,
21
+ )
22
+
23
+ # Initialize the model
24
+ model = pipeline("image-feature-extraction", model="nomic-ai/nomic-embed-vision-v1.5", trust_remote_code=True)
25
+
26
+ # Function to generate embeddings from an image
27
+ def generate_embedding(image):
28
+ if image is None:
29
+ return None
30
+
31
+ # Convert to PIL Image if needed
32
+ if not isinstance(image, Image.Image):
33
+ image = Image.fromarray(image)
34
+
35
+ try:
36
+ # Generate embedding using the transformers pipeline
37
+ result = model(image)
38
+
39
+ # Process the result based on its type
40
+ embedding_list = None
41
+
42
+ # Handle different possible output types
43
+ if isinstance(result, torch.Tensor):
44
+ embedding_list = result.detach().cpu().numpy().flatten().tolist()
45
+ elif isinstance(result, np.ndarray):
46
+ embedding_list = result.flatten().tolist()
47
+ elif isinstance(result, list):
48
+ # If it's a list of tensors or arrays
49
+ if result and isinstance(result[0], (torch.Tensor, np.ndarray)):
50
+ embedding_list = result[0].flatten().tolist() if hasattr(result[0], 'flatten') else result[0]
51
+ else:
52
+ embedding_list = result
53
+ else:
54
+ # Try to convert to a list as a last resort
55
+ try:
56
+ if result is not None:
57
+ embedding_list = list(result)
58
+ else:
59
+ print("Result is None")
60
+ return None
61
+ except:
62
+ print(f"Couldn't convert result of type {type(result)} to list")
63
+ return None
64
+
65
+ # Ensure we have a valid embedding list
66
+ if embedding_list is None:
67
+ return None
68
+
69
+ # Calculate embedding dimension
70
+ embedding_dim = len(embedding_list)
71
+
72
+ return {
73
+ "embedding": embedding_list,
74
+ "dimension": embedding_dim
75
+ }
76
+ except Exception as e:
77
+ print(f"Error generating embedding: {str(e)}")
78
+ return None
79
+
80
+ return {
81
+ "embedding": embedding_list,
82
+ "dimension": embedding_dim
83
+ }
84
+
85
+ # Gradio Interface
86
+ with gr.Blocks() as demo:
87
+ gr.Markdown("# Nomic Vision Embedding Model (nomic-ai/nomic-embed-vision-v1.5)")
88
+ gr.Markdown("Upload an image to generate embeddings using the Nomic Vision model.")
89
+
90
+ with gr.Row():
91
+ with gr.Column():
92
+ input_image = gr.Image(type="pil", label="Input Image")
93
+ embed_btn = gr.Button("Generate Embedding")
94
+
95
+ with gr.Column():
96
+ embedding_json = gr.JSON(label="Embedding Output")
97
+ embedding_dim = gr.Textbox(label="Embedding Dimension")
98
+
99
+ def update_embedding(img):
100
+ result = generate_embedding(img)
101
+ if result is None:
102
+ return {
103
+ embedding_json: None,
104
+ embedding_dim: "No embedding generated"
105
+ }
106
+ return {
107
+ embedding_json: result,
108
+ embedding_dim: f"Dimension: {len(result['embedding'])}"
109
+ }
110
+
111
+ embed_btn.click(
112
+ fn=update_embedding,
113
+ inputs=[input_image],
114
+ outputs=[embedding_json, embedding_dim]
115
+ )
116
+
117
+ # MCP Server Implementation
118
+ class NomicEmbeddingServer:
119
+ def __init__(self):
120
+ self.server = Server(
121
+ {
122
+ "name": "nomic-embedding-server",
123
+ "version": "0.1.0",
124
+ },
125
+ {
126
+ "capabilities": {
127
+ "tools": {},
128
+ },
129
+ }
130
+ )
131
+
132
+ self.setup_tool_handlers()
133
+
134
+ # Error handling
135
+ self.server.onerror = lambda error: print(f"[MCP Error] {error}")
136
+
137
+ def setup_tool_handlers(self):
138
+ self.server.set_request_handler(ListToolsRequestSchema, self.handle_list_tools)
139
+ self.server.set_request_handler(CallToolRequestSchema, self.handle_call_tool)
140
+
141
+ async def handle_list_tools(self, request):
142
+ return {
143
+ "tools": [
144
+ {
145
+ "name": "embed_image",
146
+ "description": "Generate embeddings for an image using nomic-ai/nomic-embed-vision-v1.5",
147
+ "inputSchema": {
148
+ "type": "object",
149
+ "properties": {
150
+ "image_url": {
151
+ "type": "string",
152
+ "description": "URL of the image to embed",
153
+ },
154
+ "image_data": {
155
+ "type": "string",
156
+ "description": "Base64-encoded image data (alternative to image_url)",
157
+ },
158
+ },
159
+ "anyOf": [
160
+ {"required": ["image_url"]},
161
+ {"required": ["image_data"]},
162
+ ],
163
+ },
164
+ }
165
+ ]
166
+ }
167
+
168
+ async def handle_call_tool(self, request):
169
+ if request.params.name != "embed_image":
170
+ raise McpError(
171
+ ErrorCode.MethodNotFound,
172
+ f"Unknown tool: {request.params.name}"
173
+ )
174
+
175
+ args = request.params.arguments
176
+
177
+ try:
178
+ # Handle image from URL
179
+ if "image_url" in args:
180
+ import requests
181
+ from io import BytesIO
182
+
183
+ response = requests.get(args["image_url"])
184
+ image = Image.open(BytesIO(response.content))
185
+
186
+ # Handle image from base64 data
187
+ elif "image_data" in args:
188
+ import base64
189
+ from io import BytesIO
190
+
191
+ image_data = base64.b64decode(args["image_data"])
192
+ image = Image.open(BytesIO(image_data))
193
+
194
+ else:
195
+ raise McpError(
196
+ ErrorCode.InvalidParams,
197
+ "Either image_url or image_data must be provided"
198
+ )
199
+
200
+ # Generate embedding
201
+ result = generate_embedding(image)
202
+
203
+ return {
204
+ "content": [
205
+ {
206
+ "type": "text",
207
+ "text": json.dumps(result, indent=2),
208
+ }
209
+ ]
210
+ }
211
+
212
+ except Exception as e:
213
+ return {
214
+ "content": [
215
+ {
216
+ "type": "text",
217
+ "text": f"Error generating embedding: {str(e)}",
218
+ }
219
+ ],
220
+ "isError": True,
221
+ }
222
+
223
+ # Initialize and run the MCP server
224
+ embedding_server = NomicEmbeddingServer()
225
+
226
+ # Connect the MCP server to the Gradio app
227
+ transport = GradioServerTransport(demo)
228
+ embedding_server.server.connect(transport)
229
+
230
+ # Launch the Gradio app
231
+ if __name__ == "__main__":
232
+ demo.launch(mcp_server=True)
app_hf.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import numpy as np
4
+ from PIL import Image
5
+ import os
6
+ import json
7
+ import base64
8
+ from io import BytesIO
9
+ import requests
10
+ from typing import Dict, List, Any, Optional
11
+ from transformers.pipelines import pipeline
12
+
13
+ # MCP imports
14
+ from modelcontextprotocol.server import Server
15
+ from modelcontextprotocol.server.gradio import GradioServerTransport
16
+ from modelcontextprotocol.types import (
17
+ CallToolRequestSchema,
18
+ ErrorCode,
19
+ ListToolsRequestSchema,
20
+ McpError,
21
+ )
22
+
23
+ # Initialize the model
24
+ model = pipeline("image-feature-extraction", model="nomic-ai/nomic-embed-vision-v1.5", trust_remote_code=True)
25
+
26
+ # Function to generate embeddings from an image
27
+ def generate_embedding(image):
28
+ if image is None:
29
+ return None
30
+
31
+ # Convert to PIL Image if needed
32
+ if not isinstance(image, Image.Image):
33
+ image = Image.fromarray(image)
34
+
35
+ try:
36
+ # Generate embedding using the transformers pipeline
37
+ result = model(image)
38
+
39
+ # Process the result based on its type
40
+ embedding_list = None
41
+
42
+ # Handle different possible output types
43
+ if isinstance(result, torch.Tensor):
44
+ embedding_list = result.detach().cpu().numpy().flatten().tolist()
45
+ elif isinstance(result, np.ndarray):
46
+ embedding_list = result.flatten().tolist()
47
+ elif isinstance(result, list):
48
+ # If it's a list of tensors or arrays
49
+ if result and isinstance(result[0], (torch.Tensor, np.ndarray)):
50
+ embedding_list = result[0].flatten().tolist() if hasattr(result[0], 'flatten') else result[0]
51
+ else:
52
+ embedding_list = result
53
+ else:
54
+ # Try to convert to a list as a last resort
55
+ try:
56
+ if result is not None:
57
+ embedding_list = list(result)
58
+ else:
59
+ print("Result is None")
60
+ return None
61
+ except:
62
+ print(f"Couldn't convert result of type {type(result)} to list")
63
+ return None
64
+
65
+ # Ensure we have a valid embedding list
66
+ if embedding_list is None:
67
+ return None
68
+
69
+ # Calculate embedding dimension
70
+ embedding_dim = len(embedding_list)
71
+
72
+ return {
73
+ "embedding": embedding_list,
74
+ "dimension": embedding_dim
75
+ }
76
+ except Exception as e:
77
+ print(f"Error generating embedding: {str(e)}")
78
+ return None
79
+
80
+ # Gradio Interface
81
+ with gr.Blocks() as demo:
82
+ gr.Markdown("# Nomic Vision Embedding Model (nomic-ai/nomic-embed-vision-v1.5)")
83
+ gr.Markdown("Upload an image to generate embeddings using the Nomic Vision model.")
84
+
85
+ with gr.Row():
86
+ with gr.Column():
87
+ input_image = gr.Image(type="pil", label="Input Image")
88
+ embed_btn = gr.Button("Generate Embedding")
89
+
90
+ with gr.Column():
91
+ embedding_json = gr.JSON(label="Embedding Output")
92
+ embedding_dim = gr.Textbox(label="Embedding Dimension")
93
+
94
+ def update_embedding(img):
95
+ result = generate_embedding(img)
96
+ if result is None:
97
+ return {
98
+ embedding_json: None,
99
+ embedding_dim: "No embedding generated"
100
+ }
101
+ return {
102
+ embedding_json: result,
103
+ embedding_dim: f"Dimension: {len(result['embedding'])}"
104
+ }
105
+
106
+ embed_btn.click(
107
+ fn=update_embedding,
108
+ inputs=[input_image],
109
+ outputs=[embedding_json, embedding_dim]
110
+ )
111
+
112
+ # MCP Server Implementation
113
+ class NomicEmbeddingServer:
114
+ def __init__(self):
115
+ self.server = Server(
116
+ {
117
+ "name": "nomic-embedding-server",
118
+ "version": "0.1.0",
119
+ },
120
+ {
121
+ "capabilities": {
122
+ "tools": {},
123
+ },
124
+ }
125
+ )
126
+
127
+ self.setup_tool_handlers()
128
+
129
+ # Error handling
130
+ self.server.onerror = lambda error: print(f"[MCP Error] {error}")
131
+
132
+ def setup_tool_handlers(self):
133
+ self.server.set_request_handler(ListToolsRequestSchema, self.handle_list_tools)
134
+ self.server.set_request_handler(CallToolRequestSchema, self.handle_call_tool)
135
+
136
+ async def handle_list_tools(self, request):
137
+ return {
138
+ "tools": [
139
+ {
140
+ "name": "embed_image",
141
+ "description": "Generate embeddings for an image using nomic-ai/nomic-embed-vision-v1.5",
142
+ "inputSchema": {
143
+ "type": "object",
144
+ "properties": {
145
+ "image_url": {
146
+ "type": "string",
147
+ "description": "URL of the image to embed",
148
+ },
149
+ "image_data": {
150
+ "type": "string",
151
+ "description": "Base64-encoded image data (alternative to image_url)",
152
+ },
153
+ },
154
+ "anyOf": [
155
+ {"required": ["image_url"]},
156
+ {"required": ["image_data"]},
157
+ ],
158
+ },
159
+ }
160
+ ]
161
+ }
162
+
163
+ async def handle_call_tool(self, request):
164
+ if request.params.name != "embed_image":
165
+ raise McpError(
166
+ ErrorCode.MethodNotFound,
167
+ f"Unknown tool: {request.params.name}"
168
+ )
169
+
170
+ args = request.params.arguments
171
+
172
+ try:
173
+ # Handle image from URL
174
+ if "image_url" in args:
175
+ response = requests.get(args["image_url"])
176
+ image = Image.open(BytesIO(response.content))
177
+
178
+ # Handle image from base64 data
179
+ elif "image_data" in args:
180
+ image_data = base64.b64decode(args["image_data"])
181
+ image = Image.open(BytesIO(image_data))
182
+
183
+ else:
184
+ raise McpError(
185
+ ErrorCode.InvalidParams,
186
+ "Either image_url or image_data must be provided"
187
+ )
188
+
189
+ # Generate embedding
190
+ result = generate_embedding(image)
191
+
192
+ return {
193
+ "content": [
194
+ {
195
+ "type": "text",
196
+ "text": json.dumps(result, indent=2),
197
+ }
198
+ ]
199
+ }
200
+
201
+ except Exception as e:
202
+ return {
203
+ "content": [
204
+ {
205
+ "type": "text",
206
+ "text": f"Error generating embedding: {str(e)}",
207
+ }
208
+ ],
209
+ "isError": True,
210
+ }
211
+
212
+ # Initialize and run the MCP server
213
+ embedding_server = NomicEmbeddingServer()
214
+
215
+ # Connect the MCP server to the Gradio app
216
+ transport = GradioServerTransport(demo)
217
+ embedding_server.server.connect(transport)
218
+
219
+ # Launch the Gradio app
220
+ if __name__ == "__main__":
221
+ # For Huggingface Spaces, we need to specify the server name and port
222
+ demo.launch(server_name="0.0.0.0", server_port=7860)
example_client.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import base64
3
+ from io import BytesIO
4
+ from PIL import Image
5
+ import json
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+
9
+ # This is an example client that demonstrates how to use the MCP server
10
+ # You would replace this URL with the actual URL of your deployed Huggingface Space
11
+ MCP_SERVER_URL = "https://your-username-nomic-vision-mcp.hf.space/mcp"
12
+
13
+ def embed_image_from_url(image_url):
14
+ """
15
+ Generate embeddings for an image using the MCP server's embed_image tool
16
+
17
+ Args:
18
+ image_url: URL of the image to embed
19
+
20
+ Returns:
21
+ The embedding vector and its dimension
22
+ """
23
+ # Prepare the MCP request
24
+ mcp_request = {
25
+ "jsonrpc": "2.0",
26
+ "method": "callTool",
27
+ "params": {
28
+ "name": "embed_image",
29
+ "arguments": {
30
+ "image_url": image_url
31
+ }
32
+ },
33
+ "id": 1
34
+ }
35
+
36
+ # Send the request to the MCP server
37
+ response = requests.post(MCP_SERVER_URL, json=mcp_request)
38
+
39
+ # Parse the response
40
+ result = response.json()
41
+
42
+ if "error" in result:
43
+ print(f"Error: {result['error']['message']}")
44
+ return None
45
+
46
+ # Extract the embedding from the response
47
+ content = result["result"]["content"][0]["text"]
48
+ embedding_data = json.loads(content)
49
+
50
+ return embedding_data
51
+
52
+ def embed_image_from_file(image_path):
53
+ """
54
+ Generate embeddings for an image using the MCP server's embed_image tool
55
+
56
+ Args:
57
+ image_path: Path to the image file
58
+
59
+ Returns:
60
+ The embedding vector and its dimension
61
+ """
62
+ # Load the image
63
+ with open(image_path, "rb") as f:
64
+ image_data = f.read()
65
+
66
+ # Encode the image as base64
67
+ image_base64 = base64.b64encode(image_data).decode("utf-8")
68
+
69
+ # Prepare the MCP request
70
+ mcp_request = {
71
+ "jsonrpc": "2.0",
72
+ "method": "callTool",
73
+ "params": {
74
+ "name": "embed_image",
75
+ "arguments": {
76
+ "image_data": image_base64
77
+ }
78
+ },
79
+ "id": 1
80
+ }
81
+
82
+ # Send the request to the MCP server
83
+ response = requests.post(MCP_SERVER_URL, json=mcp_request)
84
+
85
+ # Parse the response
86
+ result = response.json()
87
+
88
+ if "error" in result:
89
+ print(f"Error: {result['error']['message']}")
90
+ return None
91
+
92
+ # Extract the embedding from the response
93
+ content = result["result"]["content"][0]["text"]
94
+ embedding_data = json.loads(content)
95
+
96
+ return embedding_data
97
+
98
+ def visualize_embedding(embedding):
99
+ """
100
+ Visualize the embedding vector
101
+
102
+ Args:
103
+ embedding: The embedding vector
104
+ """
105
+ # Convert the embedding to a numpy array
106
+ embedding_array = np.array(embedding)
107
+
108
+ # Plot the embedding
109
+ plt.figure(figsize=(10, 5))
110
+ plt.plot(embedding_array)
111
+ plt.title("Embedding Vector")
112
+ plt.xlabel("Dimension")
113
+ plt.ylabel("Value")
114
+ plt.grid(True)
115
+ plt.show()
116
+
117
+ # Plot the histogram of the embedding
118
+ plt.figure(figsize=(10, 5))
119
+ plt.hist(embedding_array, bins=50)
120
+ plt.title("Embedding Histogram")
121
+ plt.xlabel("Value")
122
+ plt.ylabel("Frequency")
123
+ plt.grid(True)
124
+ plt.show()
125
+
126
+ if __name__ == "__main__":
127
+ # Example usage with an image URL
128
+ image_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/bert-architects.png"
129
+ print(f"Generating embedding for image: {image_url}")
130
+
131
+ embedding_data = embed_image_from_url(image_url)
132
+
133
+ if embedding_data:
134
+ print(f"Embedding dimension: {embedding_data['dimension']}")
135
+ print(f"First 10 values of embedding: {embedding_data['embedding'][:10]}...")
136
+
137
+ # Visualize the embedding
138
+ visualize_embedding(embedding_data['embedding'])
139
+
140
+ # Example usage with a local image file
141
+ # Uncomment the following lines to use a local image file
142
+ # image_path = "path/to/your/image.jpg"
143
+ # print(f"Generating embedding for image: {image_path}")
144
+ # embedding_data = embed_image_from_file(image_path)
145
+ #
146
+ # if embedding_data:
147
+ # print(f"Embedding dimension: {embedding_data['dimension']}")
148
+ # print(f"First 10 values of embedding: {embedding_data['embedding'][:10]}...")
149
+ #
150
+ # # Visualize the embedding
151
+ # visualize_embedding(embedding_data['embedding'])
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ transformers
2
+ torch
3
+ pillow
4
+ numpy
5
+ requests
6
+ modelcontextprotocol
7
+ gradio[mcp]
8
+ mcp
9
+ https://gradio-pypi-previews.s3.amazonaws.com/3b5cace94781b90993b596a83fb39fd1584d68ee/gradio-5.26.0-py3-none-any.whl
requirements_hf.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ transformers>=4.30.0
3
+ torch>=2.0.0
4
+ pillow>=9.0.0
5
+ numpy>=1.20.0
6
+ requests>=2.25.0
7
+ modelcontextprotocol>=0.1.0
test_local.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import base64
3
+ from PIL import Image
4
+ import io
5
+ import json
6
+ import sys
7
+
8
+ def test_local_server(image_path=None):
9
+ """
10
+ Test the local MCP server by sending a request to embed an image
11
+
12
+ Args:
13
+ image_path: Path to the image file. If None, a test URL will be used.
14
+ """
15
+ # Local server URL (default Gradio port)
16
+ server_url = "http://localhost:7860/mcp"
17
+
18
+ if image_path:
19
+ # Load the image
20
+ try:
21
+ with open(image_path, "rb") as f:
22
+ image_data = f.read()
23
+
24
+ # Encode the image as base64
25
+ image_base64 = base64.b64encode(image_data).decode("utf-8")
26
+
27
+ # Prepare the MCP request with image data
28
+ mcp_request = {
29
+ "jsonrpc": "2.0",
30
+ "method": "callTool",
31
+ "params": {
32
+ "name": "embed_image",
33
+ "arguments": {
34
+ "image_data": image_base64
35
+ }
36
+ },
37
+ "id": 1
38
+ }
39
+ except Exception as e:
40
+ print(f"Error loading image: {str(e)}")
41
+ return
42
+ else:
43
+ # Use a test image URL
44
+ test_image_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/bert-architects.png"
45
+ print(f"Using test image URL: {test_image_url}")
46
+
47
+ # Prepare the MCP request with image URL
48
+ mcp_request = {
49
+ "jsonrpc": "2.0",
50
+ "method": "callTool",
51
+ "params": {
52
+ "name": "embed_image",
53
+ "arguments": {
54
+ "image_url": test_image_url
55
+ }
56
+ },
57
+ "id": 1
58
+ }
59
+
60
+ print("Sending request to local MCP server...")
61
+
62
+ try:
63
+ # Send the request to the MCP server
64
+ response = requests.post(server_url, json=mcp_request)
65
+
66
+ # Check if the request was successful
67
+ if response.status_code == 200:
68
+ # Parse the response
69
+ result = response.json()
70
+
71
+ if "error" in result:
72
+ print(f"Error from server: {result['error']['message']}")
73
+ else:
74
+ # Extract the embedding from the response
75
+ content = result["result"]["content"][0]["text"]
76
+ embedding_data = json.loads(content)
77
+
78
+ print("✅ Test successful!")
79
+ print(f"Embedding dimension: {embedding_data['dimension']}")
80
+ print(f"First 10 values of embedding: {embedding_data['embedding'][:10]}...")
81
+ else:
82
+ print(f"❌ Error: HTTP {response.status_code}")
83
+ print(response.text)
84
+
85
+ except Exception as e:
86
+ print(f"❌ Error connecting to server: {str(e)}")
87
+ print("Make sure the server is running with 'python app.py'")
88
+
89
+ if __name__ == "__main__":
90
+ # Check if an image path was provided
91
+ if len(sys.argv) > 1:
92
+ image_path = sys.argv[1]
93
+ print(f"Testing with image: {image_path}")
94
+ test_local_server(image_path)
95
+ else:
96
+ print("No image path provided, using test URL")
97
+ test_local_server()