--- license: apache-2.0 datasets: - PULSE-ECG/ECGInstruct - PULSE-ECG/ECGBench - PULSE-ECG/ecg-log language: - tr - en tags: - aimedlab - pulse - ubden - ck_cankurt --- # PULSE-7B Hugging Face Inference Endpoint [](https://huggingface.co/PULSE-ECG/PULSE-7B) [](https://opensource.org/licenses/Apache-2.0) [](https://www.python.org/downloads/) This repository provides a custom handler for deploying the **PULSE-7B** ECG analysis model as a Hugging Face Inference Endpoint. PULSE-7B is a specialized large language model designed for ECG interpretation and cardiac health analysis. **🚀 Enhanced with DeepSeek Integration**: This handler automatically translates PULSE-7B's English medical analysis into patient-friendly Turkish commentary using DeepSeek AI, providing bilingual ECG interpretation for Turkish healthcare professionals and patients. **⚠️ Important**: PULSE-7B uses `llava_llama` architecture which requires development version of transformers. This is automatically handled in requirements.txt. ## 🚀 Quick Start ### Prerequisites - Hugging Face account with PRO subscription (for GPU endpoints) - Hugging Face API token - Basic knowledge of REST APIs ## 📦 Repository Structure ``` pulse-hf/ ├── handler.py # Custom inference handler with DeepSeek integration ├── utils.py # Performance monitoring and DeepSeek client ├── requirements.txt # Python dependencies ├── generation_config.json # Model generation configuration ├── test_requests.json # Example request templates ├── deployment_guide.md # Detailed deployment guide └── README.md # This file ``` ## 🛠️ Deployment Instructions ### Step 1: Fork or Clone This Repository 1. Go to [https://huggingface.co/ubden/aimedlab-pulse-hf](https://huggingface.co/ubden/aimedlab-pulse-hf) 2. Click "Clone repository" or create your own repository 3. Upload the `handler.py` and `requirements.txt` files ### Step 2: Create Inference Endpoint 1. Navigate to [Hugging Face Inference Endpoints](https://ui.endpoints.huggingface.co/) 2. Click **"New endpoint"** 3. Configure your endpoint: - **Model repository**: `ubden/aimedlab-pulse-hf` - **Endpoint name**: Choose a unique name - **Instance type**: - Minimum: `GPU · medium · 1x NVIDIA A10G · 16GB` - Recommended: `GPU · large · 1x NVIDIA A100 · 80GB` - **Task**: `Custom` - **Container type**: `Default` - **Revision**: `main` 4. Click **"Create Endpoint"** 5. Wait for the status to change from `Building` → `Initializing` → `Running` ### Step 3: Configure DeepSeek API Key (Optional) To enable Turkish commentary feature: 1. Go to your endpoint's **"Environment"** tab 2. In **"Secret Env"** section, add: - **Key**: `deep_key` - **Value**: Your DeepSeek API key 3. Click **"Update Endpoint"** **Note**: Without this configuration, the endpoint will work but without Turkish commentary. ### Step 4: Get Your Endpoint URL Once running, you'll receive an endpoint URL like: ``` https://YOUR-ENDPOINT-NAME.endpoints.huggingface.cloud ``` ## 💻 Usage Examples ### cURL #### Image URL Request (DeepSeek Türkçe Yorum Aktif) ```bash curl -X POST "https://YOUR-ENDPOINT.endpoints.huggingface.cloud" \ -H "Authorization: Bearer YOUR_HF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "inputs": { "query": "What are the main features and diagnosis in this ECG image? Provide a concise, clinical answer.", "image": "https://i.imgur.com/7uuejqO.jpeg" }, "parameters": { "max_new_tokens": 512, "temperature": 0.2, "top_p": 0.9, "repetition_penalty": 1.05, "enable_turkish_commentary": true, "deepseek_timeout": 30 } }' ``` #### Base64 Image Request (DeepSeek Türkçe Yorum Aktif) ```bash curl -X POST "https://YOUR-ENDPOINT.endpoints.huggingface.cloud" \ -H "Authorization: Bearer YOUR_HF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "inputs": { "query": "What are the main features and diagnosis in this ECG image? Provide a concise, clinical answer.", "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k=" }, "parameters": { "max_new_tokens": 512, "temperature": 0.2, "top_p": 0.9, "repetition_penalty": 1.05, "enable_turkish_commentary": true, "deepseek_timeout": 30 } }' ``` #### Image Request (DeepSeek Türkçe Yorum Deaktif) ```bash curl -X POST "https://YOUR-ENDPOINT.endpoints.huggingface.cloud" \ -H "Authorization: Bearer YOUR_HF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "inputs": { "query": "Analyze this ECG image briefly.", "image": "https://i.imgur.com/7uuejqO.jpeg" }, "parameters": { "temperature": 0.2, "enable_turkish_commentary": false } }' ``` #### Text-only Request (DeepSeek Türkçe Yorum Deaktif - Default) ```bash curl -X POST "https://YOUR-ENDPOINT.endpoints.huggingface.cloud" \ -H "Authorization: Bearer YOUR_HF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "inputs": { "query": "What are the key features of atrial fibrillation on an ECG?" }, "parameters": { "max_new_tokens": 256, "temperature": 0.7, "top_p": 0.95 } }' ``` ### Python ```python import requests import json import base64 from PIL import Image from io import BytesIO class PULSEEndpoint: def __init__(self, endpoint_url, hf_token): self.endpoint_url = endpoint_url self.headers = { "Authorization": f"Bearer {hf_token}", "Content-Type": "application/json" } def analyze_text(self, text, max_new_tokens=256, temperature=0.7, enable_turkish_commentary=False): """ Send text to PULSE-7B endpoint for analysis Args: text: Input text/question about ECG max_new_tokens: Maximum tokens to generate temperature: Sampling temperature (0.0-1.0) enable_turkish_commentary: Enable DeepSeek Turkish commentary Returns: Generated response with optional Turkish commentary """ payload = { "inputs": { "query": text }, "parameters": { "max_new_tokens": max_new_tokens, "temperature": temperature, "top_p": 0.95, "do_sample": True, "enable_turkish_commentary": enable_turkish_commentary } } response = requests.post( self.endpoint_url, headers=self.headers, json=payload ) if response.status_code == 200: result = response.json() return result[0] else: raise Exception(f"Request failed: {response.status_code} - {response.text}") def analyze_image_url(self, image_url, query, max_new_tokens=512, temperature=0.2, enable_turkish_commentary=False): """ Analyze ECG image from URL with DeepSeek Turkish commentary Args: image_url: URL of the ECG image query: Question about the ECG image max_new_tokens: Maximum tokens to generate temperature: Sampling temperature enable_turkish_commentary: Enable DeepSeek Turkish commentary Returns: Generated response with optional Turkish commentary """ payload = { "inputs": { "query": query, "image": image_url }, "parameters": { "max_new_tokens": max_new_tokens, "temperature": temperature, "top_p": 0.9, "repetition_penalty": 1.05, "enable_turkish_commentary": enable_turkish_commentary, "deepseek_timeout": 30 } } response = requests.post( self.endpoint_url, headers=self.headers, json=payload ) if response.status_code == 200: result = response.json() return result[0] else: raise Exception(f"Request failed: {response.status_code} - {response.text}") def analyze_image_base64(self, image_path, query, max_new_tokens=512, temperature=0.2, enable_turkish_commentary=False): """ Analyze ECG image from local file with DeepSeek Turkish commentary Args: image_path: Path to local image file query: Question about the ECG image max_new_tokens: Maximum tokens to generate temperature: Sampling temperature enable_turkish_commentary: Enable DeepSeek Turkish commentary Returns: Generated response with optional Turkish commentary """ # Convert image to base64 with open(image_path, "rb") as image_file: image_data = base64.b64encode(image_file.read()).decode('utf-8') mime_type = "image/jpeg" if image_path.lower().endswith('.jpg') else "image/png" base64_string = f"data:{mime_type};base64,{image_data}" payload = { "inputs": { "query": query, "image": base64_string }, "parameters": { "max_new_tokens": max_new_tokens, "temperature": temperature, "top_p": 0.9, "repetition_penalty": 1.05, "enable_turkish_commentary": enable_turkish_commentary, "deepseek_timeout": 30 } } response = requests.post( self.endpoint_url, headers=self.headers, json=payload ) if response.status_code == 200: result = response.json() return result[0] else: raise Exception(f"Request failed: {response.status_code} - {response.text}") # Usage example if __name__ == "__main__": # Initialize endpoint endpoint = PULSEEndpoint( endpoint_url="https://YOUR-ENDPOINT.endpoints.huggingface.cloud", hf_token="YOUR_HF_TOKEN" ) # Example 1: Text analysis (default - no Turkish commentary) response = endpoint.analyze_text( "What are the characteristics of a normal sinus rhythm?" ) print("English Response:", response["generated_text"]) # Example 2: Image URL analysis (default - no Turkish commentary) response = endpoint.analyze_image_url( image_url="https://i.imgur.com/7uuejqO.jpeg", query="What are the main features and diagnosis in this ECG image?" ) print("English Analysis:", response["generated_text"]) # Example 3: Local image analysis with Turkish commentary (explicitly enabled) response = endpoint.analyze_image_base64( image_path="./ecg_image.jpg", query="Analyze this ECG for any abnormalities", enable_turkish_commentary=True ) print("English Analysis:", response["generated_text"]) if "comment_text" in response: print("Turkish Commentary:", response["comment_text"]) # Example 4: Text analysis with Turkish commentary (explicitly enabled) response = endpoint.analyze_text( "What are the characteristics of atrial fibrillation?", enable_turkish_commentary=True ) print("English Response:", response["generated_text"]) if "comment_text" in response: print("Turkish Commentary:", response["comment_text"]) ``` ### JavaScript / Node.js ```javascript // Using fetch (Node.js 18+ or browser) class PULSEEndpoint { constructor(endpointUrl, hfToken) { this.endpointUrl = endpointUrl; this.headers = { 'Authorization': `Bearer ${hfToken}`, 'Content-Type': 'application/json' }; } async analyzeText(text, parameters = {}) { const payload = { inputs: { query: text }, parameters: { max_new_tokens: parameters.maxNewTokens || 256, temperature: parameters.temperature || 0.7, top_p: parameters.topP || 0.95, do_sample: parameters.doSample !== false, enable_turkish_commentary: parameters.enableTurkishCommentary !== false } }; try { const response = await fetch(this.endpointUrl, { method: 'POST', headers: this.headers, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); return result[0]; } catch (error) { console.error('Error calling PULSE endpoint:', error); throw error; } } async analyzeImageUrl(imageUrl, query, parameters = {}) { const payload = { inputs: { query: query, image: imageUrl }, parameters: { max_new_tokens: parameters.maxNewTokens || 512, temperature: parameters.temperature || 0.2, top_p: parameters.topP || 0.9, repetition_penalty: parameters.repetitionPenalty || 1.05, enable_turkish_commentary: parameters.enableTurkishCommentary !== false, deepseek_timeout: parameters.deepseekTimeout || 30 } }; try { const response = await fetch(this.endpointUrl, { method: 'POST', headers: this.headers, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); return result[0]; } catch (error) { console.error('Error calling PULSE endpoint:', error); throw error; } } async analyzeImageBase64(imageFile, query, parameters = {}) { // Convert image file to base64 const base64String = await this.fileToBase64(imageFile); const payload = { inputs: { query: query, image: base64String }, parameters: { max_new_tokens: parameters.maxNewTokens || 512, temperature: parameters.temperature || 0.2, top_p: parameters.topP || 0.9, repetition_penalty: parameters.repetitionPenalty || 1.05, enable_turkish_commentary: parameters.enableTurkishCommentary !== false, deepseek_timeout: parameters.deepseekTimeout || 30 } }; try { const response = await fetch(this.endpointUrl, { method: 'POST', headers: this.headers, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); return result[0]; } catch (error) { console.error('Error calling PULSE endpoint:', error); throw error; } } async fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result); reader.onerror = error => reject(error); }); } } // Usage example async function main() { const pulse = new PULSEEndpoint( 'https://YOUR-ENDPOINT.endpoints.huggingface.cloud', 'YOUR_HF_TOKEN' ); try { // Example 1: Text analysis with Turkish commentary const response1 = await pulse.analyzeText( 'What are the ECG signs of myocardial infarction?', { enableTurkishCommentary: true } ); console.log('English Response:', response1.generated_text); if (response1.comment_text) { console.log('Turkish Commentary:', response1.comment_text); } // Example 2: Image URL analysis with Turkish commentary const response2 = await pulse.analyzeImageUrl( 'https://i.imgur.com/7uuejqO.jpeg', 'What are the main features and diagnosis in this ECG image?', { enableTurkishCommentary: true, maxNewTokens: 512, temperature: 0.2 } ); console.log('English Analysis:', response2.generated_text); if (response2.comment_text) { console.log('Turkish Commentary:', response2.comment_text); } // Example 3: Analysis without Turkish commentary const response3 = await pulse.analyzeImageUrl( 'https://i.imgur.com/7uuejqO.jpeg', 'Brief ECG analysis', { enableTurkishCommentary: false } ); console.log('English Only Response:', response3.generated_text); } catch (error) { console.error('Error:', error); } } main(); ``` ### JavaScript (Browser) ```html