ethansteininger commited on
Commit
f2d841b
Β·
verified Β·
1 Parent(s): 065b1c3

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +145 -123
app.py CHANGED
@@ -1,10 +1,8 @@
1
  import gradio as gr
2
  import requests
3
  import json
4
- import os
5
  from typing import Optional
6
  import base64
7
- import tempfile
8
 
9
  API_BASE_URL = "https://api.mixpeek.com/v1"
10
 
@@ -37,89 +35,139 @@ def extract_features(
37
  file: Optional[str],
38
  text_input: str,
39
  input_type: str,
40
- split_method: str,
41
- enable_transcription: bool,
42
  enable_embed: bool,
43
- enable_ocr: bool,
44
- enable_description: bool,
45
- enable_thumbnail: bool,
46
- interval_sec: int,
47
  ) -> str:
48
  """Extract features from the input using Mixpeek API."""
49
 
50
  if not api_key:
51
  return json.dumps({"error": "Please provide your Mixpeek API key"}, indent=2)
52
 
53
- headers = {
54
- "Authorization": f"Bearer {api_key}",
55
- "Content-Type": "application/json",
56
- }
57
 
58
- # Build the request payload
59
- payload = {
60
- "type": "multimodal_extractor_v1",
61
- "settings": {}
62
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
- # Handle different input types
65
- if input_type == "Text":
66
- if not text_input.strip():
67
- return json.dumps({"error": "Please provide text input"}, indent=2)
68
- payload["input"] = {"type": "text", "value": text_input}
69
- else:
70
- if not file:
71
- return json.dumps({"error": "Please upload a file"}, indent=2)
72
-
73
- # Determine the input type from file
74
- mime_type = get_file_mime_type(file)
75
- base64_data = encode_file_to_base64(file)
76
-
77
- if mime_type.startswith("video"):
78
- payload["input"] = {
79
- "type": "video",
80
- "value": f"data:{mime_type};base64,{base64_data}"
81
- }
82
- # Video-specific settings
83
- payload["settings"]["split"] = {
84
- "method": split_method.lower(),
85
- }
86
- if split_method.lower() == "time":
87
- payload["settings"]["split"]["interval_sec"] = interval_sec
88
 
89
- elif mime_type == "image/gif":
90
- payload["input"] = {
91
- "type": "gif",
92
- "value": f"data:{mime_type};base64,{base64_data}"
93
- }
94
  else:
95
- payload["input"] = {
96
- "type": "image",
97
- "value": f"data:{mime_type};base64,{base64_data}"
 
 
 
 
 
 
98
  }
99
 
100
- # Feature toggles
101
- payload["settings"]["transcription"] = {"enabled": enable_transcription}
102
- payload["settings"]["embed"] = {"enabled": enable_embed}
103
- payload["settings"]["ocr"] = {"enabled": enable_ocr}
104
- payload["settings"]["describe"] = {"enabled": enable_description}
105
- payload["settings"]["thumbnail"] = {"enabled": enable_thumbnail}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
- try:
108
- response = requests.post(
109
- f"{API_BASE_URL}/collections/features/extract",
110
- headers=headers,
111
- json=payload,
112
- timeout=120
113
- )
114
-
115
- if response.status_code == 200:
116
- result = response.json()
117
- return json.dumps(result, indent=2)
118
- else:
119
- return json.dumps({
120
- "error": f"API returned status {response.status_code}",
121
- "details": response.text
122
- }, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
  except requests.exceptions.Timeout:
125
  return json.dumps({"error": "Request timed out. Try a smaller file."}, indent=2)
@@ -136,16 +184,14 @@ with gr.Blocks(
136
  # 🎯 Mixpeek Multimodal Feature Extractor
137
 
138
  Extract embeddings and features from **videos**, **images**, **GIFs**, and **text** using
139
- [Mixpeek's](https://mixpeek.com) multimodal AI pipeline.
140
 
141
  **Features:**
142
- - 🎬 Video decomposition (time, scene, or silence-based splitting)
143
- - πŸ–ΌοΈ Image & GIF processing
144
  - πŸ“ Text embedding
145
- - 🎀 Transcription (Whisper)
146
- - πŸ‘οΈ OCR text extraction
147
- - πŸ“Έ Thumbnail generation
148
- - πŸ”’ 1408D multimodal embeddings (Google Vertex AI)
149
 
150
  ---
151
  """)
@@ -178,43 +224,26 @@ with gr.Blocks(
178
  visible=False,
179
  )
180
 
181
- gr.Markdown("### βš™οΈ Extraction Settings")
182
-
183
- with gr.Accordion("Video Settings", open=False):
184
- split_method = gr.Dropdown(
185
- choices=["Time", "Scene", "Silence"],
186
- value="Time",
187
- label="Split Method",
188
- info="How to segment videos"
189
- )
190
- interval_sec = gr.Slider(
191
- minimum=1,
192
- maximum=60,
193
- value=10,
194
- step=1,
195
- label="Time Interval (seconds)",
196
- info="For time-based splitting"
197
- )
198
 
199
- with gr.Accordion("Feature Toggles", open=True):
200
  enable_embed = gr.Checkbox(
201
- label="Generate Embeddings (1408D)",
202
  value=True,
203
  )
204
  enable_transcription = gr.Checkbox(
205
- label="Transcription (Whisper)",
206
- value=True,
207
- )
208
- enable_ocr = gr.Checkbox(
209
- label="OCR Text Extraction",
210
- value=False,
211
- )
212
- enable_description = gr.Checkbox(
213
- label="AI Description",
214
- value=False,
215
- )
216
- enable_thumbnail = gr.Checkbox(
217
- label="Generate Thumbnail",
218
  value=False,
219
  )
220
 
@@ -248,13 +277,9 @@ with gr.Blocks(
248
  file_input,
249
  text_input,
250
  input_type,
251
- split_method,
252
- enable_transcription,
253
  enable_embed,
254
- enable_ocr,
255
- enable_description,
256
- enable_thumbnail,
257
- interval_sec,
258
  ],
259
  outputs=[output],
260
  )
@@ -267,13 +292,10 @@ with gr.Blocks(
267
  - [Get API Key](https://mixpeek.com)
268
 
269
  ### πŸ“Š Output Schema
270
- Each extracted segment contains:
271
- - `start_time` / `end_time` - Timing in seconds (for video/GIF)
272
- - `transcription` - Speech-to-text output
273
- - `embedding` - 1408D multimodal vector
274
- - `ocr_text` - Extracted text from frames
275
- - `description` - AI-generated description
276
- - `thumbnail_url` - Preview image URL
277
  """)
278
 
279
  if __name__ == "__main__":
 
1
  import gradio as gr
2
  import requests
3
  import json
 
4
  from typing import Optional
5
  import base64
 
6
 
7
  API_BASE_URL = "https://api.mixpeek.com/v1"
8
 
 
35
  file: Optional[str],
36
  text_input: str,
37
  input_type: str,
38
+ model_choice: str,
 
39
  enable_embed: bool,
40
+ enable_transcription: bool,
 
 
 
41
  ) -> str:
42
  """Extract features from the input using Mixpeek API."""
43
 
44
  if not api_key:
45
  return json.dumps({"error": "Please provide your Mixpeek API key"}, indent=2)
46
 
47
+ results = {}
 
 
 
48
 
49
+ try:
50
+ # Handle text input
51
+ if input_type == "Text":
52
+ if not text_input.strip():
53
+ return json.dumps({"error": "Please provide text input"}, indent=2)
54
+
55
+ if enable_embed:
56
+ headers = {
57
+ "Authorization": f"Bearer {api_key}",
58
+ "Content-Type": "application/json",
59
+ }
60
+
61
+ # Map model choice to provider/model
62
+ model_map = {
63
+ "Google Multimodal (1408D)": ("google", "multimodalembedding@001"),
64
+ "OpenAI text-embedding-3-large": ("openai", "text-embedding-3-large"),
65
+ "OpenAI text-embedding-3-small": ("openai", "text-embedding-3-small"),
66
+ }
67
+ provider, model = model_map.get(model_choice, ("google", "multimodalembedding@001"))
68
+
69
+ payload = {
70
+ "provider": provider,
71
+ "model": model,
72
+ "inputs": {"text": text_input},
73
+ "parameters": {}
74
+ }
75
+
76
+ response = requests.post(
77
+ f"{API_BASE_URL}/inference",
78
+ headers=headers,
79
+ json=payload,
80
+ timeout=120
81
+ )
82
 
83
+ if response.status_code == 200:
84
+ results["embedding"] = response.json()
85
+ else:
86
+ results["embedding_error"] = {
87
+ "status": response.status_code,
88
+ "details": response.text
89
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ results["input_type"] = "text"
92
+ results["text"] = text_input
93
+
94
+ # Handle file input
 
95
  else:
96
+ if not file:
97
+ return json.dumps({"error": "Please upload a file"}, indent=2)
98
+
99
+ mime_type = get_file_mime_type(file)
100
+ base64_data = encode_file_to_base64(file)
101
+
102
+ headers = {
103
+ "Authorization": f"Bearer {api_key}",
104
+ "Content-Type": "application/json",
105
  }
106
 
107
+ results["input_type"] = "image" if mime_type.startswith("image") else "video"
108
+ results["mime_type"] = mime_type
109
+
110
+ if enable_embed:
111
+ # Map model choice
112
+ model_map = {
113
+ "Google Multimodal (1408D)": ("google", "multimodalembedding@001"),
114
+ "OpenAI text-embedding-3-large": ("openai", "text-embedding-3-large"),
115
+ "OpenAI text-embedding-3-small": ("openai", "text-embedding-3-small"),
116
+ }
117
+ provider, model = model_map.get(model_choice, ("google", "multimodalembedding@001"))
118
+
119
+ payload = {
120
+ "provider": provider,
121
+ "model": model,
122
+ "inputs": {},
123
+ "parameters": {}
124
+ }
125
+
126
+ if mime_type.startswith("image"):
127
+ payload["inputs"]["image"] = f"data:{mime_type};base64,{base64_data}"
128
+ else:
129
+ payload["inputs"]["video"] = f"data:{mime_type};base64,{base64_data}"
130
+
131
+ response = requests.post(
132
+ f"{API_BASE_URL}/inference",
133
+ headers=headers,
134
+ json=payload,
135
+ timeout=180
136
+ )
137
 
138
+ if response.status_code == 200:
139
+ results["embedding"] = response.json()
140
+ else:
141
+ results["embedding_error"] = {
142
+ "status": response.status_code,
143
+ "details": response.text
144
+ }
145
+
146
+ # Transcription for video/audio
147
+ if enable_transcription and (mime_type.startswith("video") or mime_type.startswith("audio")):
148
+ payload = {
149
+ "provider": "openai",
150
+ "model": "whisper-1",
151
+ "inputs": {"audio": f"data:{mime_type};base64,{base64_data}"},
152
+ "parameters": {}
153
+ }
154
+
155
+ response = requests.post(
156
+ f"{API_BASE_URL}/inference",
157
+ headers=headers,
158
+ json=payload,
159
+ timeout=180
160
+ )
161
+
162
+ if response.status_code == 200:
163
+ results["transcription"] = response.json()
164
+ else:
165
+ results["transcription_error"] = {
166
+ "status": response.status_code,
167
+ "details": response.text
168
+ }
169
+
170
+ return json.dumps(results, indent=2)
171
 
172
  except requests.exceptions.Timeout:
173
  return json.dumps({"error": "Request timed out. Try a smaller file."}, indent=2)
 
184
  # 🎯 Mixpeek Multimodal Feature Extractor
185
 
186
  Extract embeddings and features from **videos**, **images**, **GIFs**, and **text** using
187
+ [Mixpeek's](https://mixpeek.com) inference API.
188
 
189
  **Features:**
190
+ - πŸ–ΌοΈ Image embedding (JPG, PNG, WebP, BMP, GIF)
191
+ - 🎬 Video embedding (MP4, MOV, AVI, MKV, WebM)
192
  - πŸ“ Text embedding
193
+ - 🎀 Audio transcription (Whisper)
194
+ - πŸ”’ Multiple embedding models available
 
 
195
 
196
  ---
197
  """)
 
224
  visible=False,
225
  )
226
 
227
+ gr.Markdown("### βš™οΈ Settings")
228
+
229
+ model_choice = gr.Dropdown(
230
+ choices=[
231
+ "Google Multimodal (1408D)",
232
+ "OpenAI text-embedding-3-large",
233
+ "OpenAI text-embedding-3-small",
234
+ ],
235
+ value="Google Multimodal (1408D)",
236
+ label="Embedding Model",
237
+ info="Select the embedding model to use"
238
+ )
 
 
 
 
 
239
 
240
+ with gr.Row():
241
  enable_embed = gr.Checkbox(
242
+ label="Generate Embeddings",
243
  value=True,
244
  )
245
  enable_transcription = gr.Checkbox(
246
+ label="Transcription (video/audio only)",
 
 
 
 
 
 
 
 
 
 
 
 
247
  value=False,
248
  )
249
 
 
277
  file_input,
278
  text_input,
279
  input_type,
280
+ model_choice,
 
281
  enable_embed,
282
+ enable_transcription,
 
 
 
283
  ],
284
  outputs=[output],
285
  )
 
292
  - [Get API Key](https://mixpeek.com)
293
 
294
  ### πŸ“Š Output Schema
295
+ Results contain:
296
+ - `input_type` - Type of input processed (text/image/video)
297
+ - `embedding` - Vector embedding from selected model
298
+ - `transcription` - Speech-to-text output (for video/audio)
 
 
 
299
  """)
300
 
301
  if __name__ == "__main__":