import gradio as gr import requests import json from typing import Optional import base64 API_BASE_URL = "https://api.mixpeek.com/v1" def encode_file_to_base64(file_path: str) -> str: """Encode a file to base64 string.""" with open(file_path, "rb") as f: return base64.b64encode(f.read()).decode("utf-8") def get_file_type(file_path: str) -> str: """Determine file type from extension.""" ext = file_path.lower().split(".")[-1] video_exts = {"mp4", "mov", "avi", "mkv", "webm", "flv"} if ext in video_exts: return "video" return "image" def extract_features( api_key: str, namespace_id: str, file: Optional[str], text_input: str, input_type: str, model_choice: str, ) -> str: """Extract features from the input using Mixpeek API.""" if not api_key: return json.dumps({"error": "Please provide your Mixpeek API key"}, indent=2) if not namespace_id: return json.dumps({"error": "Please provide your Namespace ID"}, indent=2) headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "X-Namespace": namespace_id, } # Map model choice to model name model_map = { "Google Multimodal (1408D)": "multimodalembedding", "OpenAI text-embedding-3-large": "text-embedding-3-large", "OpenAI text-embedding-3-small": "text-embedding-3-small", } model = model_map.get(model_choice, "multimodalembedding") try: # Handle text input if input_type == "Text": if not text_input.strip(): return json.dumps({"error": "Please provide text input"}, indent=2) payload = { "provider": "google" if "multimodal" in model else "openai", "model": model, "inputs": {"text": text_input}, "parameters": {} } # Handle file input else: if not file: return json.dumps({"error": "Please upload a file"}, indent=2) file_type = get_file_type(file) base64_data = encode_file_to_base64(file) # Only Google multimodal supports image/video embeddings if "multimodal" not in model: return json.dumps({ "error": f"OpenAI embedding models only support text. Use 'Google Multimodal (1408D)' for {file_type} embeddings." }, indent=2) payload = { "provider": "google", "model": model, "inputs": { f"{file_type}_base64": base64_data }, "parameters": {} } response = requests.post( f"{API_BASE_URL}/inference", headers=headers, json=payload, timeout=180 ) if response.status_code == 200: result = response.json() # Format the output nicely output = { "status": "success", "model": model, "input_type": input_type.lower() if input_type == "Text" else get_file_type(file), } if "data" in result: data = result["data"] if "embeddings" in data: embeddings = data["embeddings"] if embeddings and len(embeddings) > 0: output["embedding_dimensions"] = len(embeddings[0]) output["embedding_preview"] = embeddings[0][:10] # First 10 dims output["embedding_full"] = embeddings[0] else: output["data"] = data else: output["raw_response"] = result if "latency_ms" in result: output["latency_ms"] = result["latency_ms"] return json.dumps(output, indent=2) else: return json.dumps({ "error": f"API returned status {response.status_code}", "details": response.text }, indent=2) except requests.exceptions.Timeout: return json.dumps({"error": "Request timed out. Try a smaller file."}, indent=2) except Exception as e: return json.dumps({"error": str(e)}, indent=2) # Build the Gradio interface with gr.Blocks( title="Mixpeek Multimodal Feature Extractor", theme=gr.themes.Soft(), ) as demo: gr.Markdown(""" # Mixpeek Multimodal Feature Extractor Extract **1408-dimensional embeddings** from **videos**, **images**, and **text** using [Mixpeek's](https://mixpeek.com) inference API powered by Google Vertex AI. **Supported Inputs:** - **Image**: JPG, PNG, WebP, BMP, GIF - **Video**: MP4, MOV, AVI, MKV, WebM - **Text**: Any text string --- """) with gr.Row(): with gr.Column(scale=1): api_key = gr.Textbox( label="Mixpeek API Key", placeholder="Enter your API key from mixpeek.com", type="password", ) namespace_id = gr.Textbox( label="Namespace ID", placeholder="Enter your namespace ID (e.g., ns_abc123)", info="Required for API access. Find this in your Mixpeek dashboard." ) input_type = gr.Radio( choices=["File Upload", "Text"], value="File Upload", label="Input Type", ) file_input = gr.File( label="Upload File", file_types=[".mp4", ".mov", ".avi", ".mkv", ".webm", ".flv", ".jpg", ".jpeg", ".png", ".webp", ".bmp", ".gif"], visible=True, ) text_input = gr.Textbox( label="Text Input", placeholder="Enter text to embed...", lines=3, visible=False, ) model_choice = gr.Dropdown( choices=[ "Google Multimodal (1408D)", "OpenAI text-embedding-3-large", "OpenAI text-embedding-3-small", ], value="Google Multimodal (1408D)", label="Embedding Model", info="Google Multimodal supports text, image, and video. OpenAI models support text only." ) extract_btn = gr.Button("Extract Embedding", variant="primary", size="lg") with gr.Column(scale=1): output = gr.Code( label="Results", language="json", lines=30, ) # Toggle visibility based on input type def toggle_input(choice): if choice == "Text": return gr.update(visible=False), gr.update(visible=True) else: return gr.update(visible=True), gr.update(visible=False) input_type.change( toggle_input, inputs=[input_type], outputs=[file_input, text_input] ) # Extract button click handler extract_btn.click( extract_features, inputs=[ api_key, namespace_id, file_input, text_input, input_type, model_choice, ], outputs=[output], ) gr.Markdown(""" --- ### API Usage ```bash curl -X POST https://api.mixpeek.com/v1/inference \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -H "X-Namespace: YOUR_NAMESPACE_ID" \\ -H "Content-Type: application/json" \\ -d '{ "provider": "google", "model": "multimodalembedding", "inputs": {"text": "your text here"}, "parameters": {} }' ``` ### Resources - [Mixpeek Documentation](https://docs.mixpeek.com) - [API Reference](https://docs.mixpeek.com/api-reference) - [Get API Key](https://mixpeek.com) """) if __name__ == "__main__": demo.launch()