File size: 8,673 Bytes
410fd66
a6dea81
410fd66
 
 
a6dea81
410fd66
a6dea81
410fd66
68390a5
432d77e
 
 
 
68390a5
a6dea81
d2ad93f
a6dea81
68390a5
 
 
 
 
 
 
 
 
 
 
410fd66
a6dea81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d2ad93f
 
 
 
 
 
 
a6dea81
 
 
 
 
 
dd19451
d2ad93f
432d77e
dd19451
a6dea81
 
432d77e
dd19451
432d77e
dd19451
 
 
 
 
d2ad93f
dd19451
a6dea81
dd19451
 
 
a6dea81
 
 
d2ad93f
 
 
 
 
 
 
a6dea81
432d77e
 
a6dea81
 
 
 
dd19451
a6dea81
 
 
 
 
 
432d77e
dd19451
432d77e
dd19451
 
 
 
 
d2ad93f
dd19451
a6dea81
dd19451
 
 
410fd66
 
 
 
432d77e
 
 
 
 
a6dea81
 
 
410fd66
a6dea81
 
 
410fd66
a6dea81
 
 
 
410fd66
a6dea81
 
 
 
410fd66
a6dea81
 
410fd66
a6dea81
 
410fd66
a6dea81
 
410fd66
 
68390a5
a6dea81
 
 
 
 
 
 
 
410fd66
 
 
 
 
a6dea81
410fd66
68390a5
 
 
 
a6dea81
 
 
68390a5
 
 
 
410fd66
a937006
432d77e
 
 
 
 
 
 
 
 
a937006
410fd66
 
 
 
 
 
d2ad93f
410fd66
 
 
a6dea81
410fd66
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import gradio as gr
import requests
import librosa
import numpy as np
import os
import hashlib
from datetime import datetime
from simple_salesforce import Salesforce

# Salesforce credentials (store securely in environment variables)
SF_USERNAME = os.getenv("SF_USERNAME", "[email protected]")
SF_PASSWORD = os.getenv("SF_PASSWORD", "voicebot1")
SF_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN", "jq4VVHUFti6TmzJDjjegv2h6b")
SF_INSTANCE_URL = os.getenv("SF_INSTANCE_URL", "https://voicebot-dev-ed.my.salesforce.com")  # Verify correct API URL

# Hugging Face Inference API token (store in environment variables)
HF_TOKEN = os.getenv("HF_TOKEN")  # No default; must be set in Space secrets

# Initialize Salesforce connection
try:
    sf = Salesforce(
        username=SF_USERNAME,
        password=SF_PASSWORD,
        security_token=SF_SECURITY_TOKEN,
        instance_url=SF_INSTANCE_URL
    )
except Exception as e:
    print(f"Failed to connect to Salesforce: {str(e)}")
    sf = None

# Hugging Face API endpoints
WHISPER_API_URL = "https://api-inference.huggingface.co/models/openai/whisper-tiny.en"
SYMPTOM_API_URL = "https://api-inference.huggingface.co/models/abhirajeshbhai/symptom-2-disease-net"
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"}

def compute_file_hash(file_path):
    """Compute MD5 hash of a file to check uniqueness."""
    hash_md5 = hashlib.md5()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

def transcribe_audio(audio_file):
    """Transcribe audio using Whisper API."""
    if not HF_TOKEN:
        error_msg = (
            "Error transcribing audio: HF_TOKEN not set. Please set HF_TOKEN in Space secrets at "
            "https://huggingface.co/spaces/your-username/HealthVoiceAnalyzer/settings."
        )
        print(error_msg)
        return error_msg
    try:
        with open(audio_file, "rb") as f:
            data = f.read()
        response = requests.post(WHISPER_API_URL, headers=HEADERS, data=data)
        response.raise_for_status()
        result = response.json()
        print(f"Whisper API response: {result}")
        transcription = result.get("text", "").strip()
        if not transcription:
            return "Transcription empty. Please provide clear audio describing symptoms in English."
        print(f"Transcription: {transcription}")
        return transcription
    except requests.exceptions.HTTPError as e:
        error_msg = f"Error transcribing audio: {str(e)}"
        if e.response.status_code == 401:
            error_msg = (
                "Error transcribing audio: Unauthorized. Please check HF_TOKEN in Space secrets at "
                "https://huggingface.co/spaces/your-username/HealthVoiceAnalyzer/settings. "
                "Ensure token has Inference API access (get at https://huggingface.co/settings/tokens)."
            )
        print(f"Whisper API error: {error_msg}, Status: {e.response.status_code}")
        return error_msg
    except Exception as e:
        error_msg = f"Error transcribing audio: {str(e)}"
        print(error_msg)
        return error_msg

def analyze_symptoms(text):
    """Analyze symptoms using Symptom-2-Disease API."""
    if not HF_TOKEN:
        error_msg = (
            "Error analyzing symptoms: HF_TOKEN not set. Please set HF_TOKEN in Space secrets at "
            "https://huggingface.co/spaces/your-username/HealthVoiceAnalyzer/settings."
        )
        print(error_msg)
        return error_msg, 0.0
    try:
        if not text or "Error transcribing" in text:
            return "No valid transcription for analysis.", 0.0
        payload = {"inputs": text}
        response = requests.post(SYMPTOM_API_URL, headers=HEADERS, json=payload)
        response.raise_for_status()
        result = response.json()
        print(f"Symptom API response: {result}")
        if result and isinstance(result, list) and len(result) > 0:
            prediction = result[0][0]["label"]
            score = result[0][0]["score"]
            print(f"Health Prediction: {prediction}, Score: {score:.4f}")
            return prediction, score
        return "No health condition predicted", 0.0
    except requests.exceptions.HTTPError as e:
        error_msg = f"Error analyzing symptoms: {str(e)}"
        if e.response.status_code == 401:
            error_msg = (
                "Error analyzing symptoms: Unauthorized. Please check HF_TOKEN in Space secrets at "
                "https://huggingface.co/spaces/your-username/HealthVoiceAnalyzer/settings. "
                "Ensure token has Inference API access (get at https://huggingface.co/settings/tokens)."
            )
        print(f"Symptom API error: {error_msg}, Status: {e.response.status_code}")
        return error_msg, 0.0
    except Exception as e:
        error_msg = f"Error analyzing symptoms: {str(e)}"
        print(error_msg)
        return error_msg, 0.0

def analyze_voice(audio_file):
    """Analyze voice for health indicators."""
    try:
        # Ensure unique file name to avoid Gradio reuse
        unique_path = f"/tmp/gradio/{datetime.now().strftime('%Y%m%d%H%M%S%f')}_{os.path.basename(audio_file)}"
        os.rename(audio_file, unique_path)
        audio_file = unique_path
        
        # Log audio file info
        file_hash = compute_file_hash(audio_file)
        print(f"Processing audio file: {audio_file}, Hash: {file_hash}")
        
        # Load audio to verify format
        audio, sr = librosa.load(audio_file, sr=16000)
        print(f"Audio shape: {audio.shape}, Sampling rate: {sr}, Duration: {len(audio)/sr:.2f}s, Mean: {np.mean(audio):.4f}, Std: {np.std(audio):.4f}")
        
        # Transcribe audio
        transcription = transcribe_audio(audio_file)
        if "Error transcribing" in transcription:
            return transcription
        
        # Analyze symptoms
        prediction, score = analyze_symptoms(transcription)
        if "Error analyzing" in prediction:
            return prediction
        
        # Generate feedback
        if prediction == "No health condition predicted":
            feedback = "No significant health indicators detected."
        else:
            feedback = f"Possible health condition: {prediction} (confidence: {score:.4f}). Consult a doctor."
        
        feedback += f"\n\n**Debug Info**: Transcription = '{transcription}', Prediction = {prediction}, Confidence = {score:.4f}, File Hash = {file_hash}"
        feedback += "\n**Disclaimer**: This is not a diagnostic tool. Consult a healthcare provider for medical advice."
        
        # Store in Salesforce
        if sf:
            store_in_salesforce(audio_file, feedback, transcription, prediction, score)
        
        # Clean up temporary audio file
        try:
            os.remove(audio_file)
            print(f"Deleted temporary audio file: {audio_file}")
        except Exception as e:
            print(f"Failed to delete audio file: {str(e)}")
        
        return feedback
    except Exception as e:
        return f"Error processing audio: {str(e)}"

def store_in_salesforce(audio_file, feedback, transcription, prediction, score):
    """Store analysis results in Salesforce."""
    try:
        sf.HealthAssessment__c.create({
            "AssessmentDate__c": datetime.utcnow().isoformat(),
            "Feedback__c": feedback,
            "Transcription__c": transcription,
            "Prediction__c": prediction,
            "Confidence__c": float(score),
            "AudioFileName__c": os.path.basename(audio_file)
        })
    except Exception as e:
        print(f"Failed to store in Salesforce: {str(e)}")

def test_with_sample_audio():
    """Test the app with sample audio files."""
    samples = ["audio_samples/sample.wav", "audio_samples/common_voice_en.wav"]
    results = []
    for sample in samples:
        if os.path.exists(sample):
            results.append(analyze_voice(sample))
        else:
            results.append(f"Sample not found: {sample}")
    return "\n".join(results)

# Gradio interface
iface = gr.Interface(
    fn=analyze_voice,
    inputs=gr.Audio(type="filepath", label="Record or Upload Voice"),
    outputs=gr.Textbox(label="Health Assessment Feedback"),
    title="Health Voice Analyzer",
    description="Record or upload a voice sample describing symptoms for preliminary health assessment. Supports English (transcription), with symptom analysis in English. Ensure HF_TOKEN is set in Space secrets."
)

if __name__ == "__main__":
    print(test_with_sample_audio())
    iface.launch(server_name="0.0.0.0", server_port=7860)