File size: 8,767 Bytes
60494ed
fd19f35
 
60494ed
6ab2eb1
 
 
2ce0a69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230eb9d
 
6ab2eb1
 
 
 
 
60494ed
6ab2eb1
 
 
 
 
 
 
97c98c3
 
fd19f35
6ab2eb1
 
 
60494ed
6ab2eb1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
038c199
 
 
 
 
 
ec31743
6ab2eb1
038c199
60494ed
038c199
60494ed
6ab2eb1
 
 
 
 
 
 
 
 
 
 
 
 
60494ed
 
6ab2eb1
 
b1255dd
 
 
 
 
 
fd19f35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ce0a69
 
 
fd19f35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b1255dd
fd19f35
 
 
 
 
 
 
 
 
 
 
b1255dd
 
fd19f35
b1255dd
fd19f35
 
 
160d6ec
fd19f35
 
 
 
c1d8f2f
 
 
bb76d8d
 
c1d8f2f
 
 
 
fd19f35
 
 
 
aaf2b16
 
b1255dd
fd19f35
aaf2b16
 
 
fd19f35
 
 
 
 
 
 
2ce0a69
fd19f35
 
 
 
2ce0a69
fd19f35
8d38f4a
fd19f35
aaf2b16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd19f35
 
 
 
 
 
68c6b90
fd19f35
6ab2eb1
b1255dd
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
import os
import json
import re
import gradio as gr
from google import genai
from google.genai import types
import asyncio
from datasets import load_dataset, DatasetDict, Dataset
from huggingface_hub import login
import datetime

# Authenticate with HF token
hf_token = os.getenv("HF_TOKEN")
login(token=hf_token)
dataset_name = "spriambada3/ehealth_transcribe"


def init_dataset():
    try:
        dataset = load_dataset(dataset_name)
    except Exception as e:
        print(e)
        dataset = DatasetDict(
            {"data": Dataset.from_dict({"logintime": [], "email": [], "wa": []})}
        )
    print("init dataset result ")
    print(dataset)
    return dataset


def add_user(dataset, email, wa):
    new_data = {
        "logintime": datetime.datetime.now(),
        "email": email,
        "wa": wa,
    }
    dataset["data"] = dataset["data"].add_item(new_data)
    dataset.push_to_hub(dataset_name)  # Save to HF Hub

    print("add data successful")


def audio_from_bytes(audio_file_path: str):
    """Converts an audio file into Gemini-compatible format."""
    try:
        with open(audio_file_path, "rb") as f:
            audio_data = f.read()

        mime_type = "audio/mp3"  # Adjust based on your audio type
        return types.Part.from_bytes(data=audio_data, mime_type=mime_type)

    except FileNotFoundError:
        return "Error: Audio file not found!"
    except Exception as e:
        return f"An error occurred: {e}"


def transcribe_and_summarize(audio_file, session):
    """Processes audio with Gemini API and returns a SOAP summary."""
    if audio_file is None:
        return "No audio file uploaded."

    # Ensure API Key is set
    GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
    if not GEMINI_API_KEY:
        return "Error: GEMINI_API_KEY environment variable is missing."
    asyncio.set_event_loop(asyncio.new_event_loop())

    client = genai.Client(api_key=GEMINI_API_KEY)
    model = "gemini-2.0-flash"

    # Prepare the request
    contents = [
        types.Content(
            role="user",
            parts=[
                types.Part.from_text(
                    text="""Anda adalah asisten medis yang membantu dokter dalam menyusun catatan medis dalam bentuk paragraf menggunakan bahasa Indonesia.
Buat ringkasan SOAP berdasarkan percakapan dokter dan pasien dalam format berikut:

    Subjective:
    ICD10:
    Objective:
    Assessment:
    Plan:

Identifikasi dan berikan saran dalam bahasa Indonesia tindakan logis selanjutnya dalam format:
    ICD10:
    Obat:
    Laboratorium:
    Radiologi:
"""
                ),
                audio_from_bytes(audio_file),
            ],
        )
    ]

    generate_content_config = types.GenerateContentConfig(
        temperature=0,
        top_p=0.95,
        top_k=40,
        max_output_tokens=8192,
        response_mime_type="text/plain",
    )

    # Process the audio
    response_text = ""
    for chunk in client.models.generate_content_stream(
        model=model,
        contents=contents,
        config=generate_content_config,
    ):
        response_text += chunk.text
    counter_display, session = click_button(session)
    return response_text, counter_display, session


DATA_FILE = "user_data.json"


def load_user_data():
    """Load user data from JSON file."""
    if os.path.exists(DATA_FILE):
        with open(DATA_FILE, "r") as file:
            return json.load(file)
    return {}  # Return empty dictionary if no data


def save_user_data(username, email):
    """Save user data to JSON file with default counter = 10 if new."""
    data = load_user_data()

    if username not in data:  # New user
        data[username] = {"email": email, "counter": 10}  # Set default counter to 10

    with open(DATA_FILE, "w") as file:
        json.dump(data, file, indent=4)
    wa = username
    dataset = init_dataset()
    add_user(dataset, email, wa)
    return data


def is_valid_wa(username):
    """Check if username is all numbers, at least 11 characters, and starts with 08 or 62."""
    return re.fullmatch(r"^(08|62)\d{9,}$", username) is not None


def is_valid_email(email):
    """Check if email format is valid."""
    return re.fullmatch(r"^[\w\.-]+@[\w\.-]+\.\w+$", email) is not None


def login(username, email, session):
    """Handles user login or registration with validation."""

    if not is_valid_wa(username):
        return (
            "❌ Invalid WA! Nomor WA minimal 12 digits dimulai '08' atau '62'.",
            session,
            gr.update(visible=True),
            gr.update(visible=False),
        )

    if not is_valid_email(email):
        return (
            "❌ Invalid email format! Please enter a valid email.",
            session,
            gr.update(visible=True),
            gr.update(visible=False),
        )

    data = save_user_data(username, email)  # Save or retrieve user data

    session["username"] = username
    session["counter"] = data[username]["counter"]

    return "", session, gr.update(visible=False), gr.update(visible=True)


def click_button(session):
    """Decrease counter on button click."""
    err = f"⚠️ Quota habis. Silahkan mengunjungi https://ehealth.co.id atau WA 6285777779926 untuk menambah kuota"
    if session["counter"] > 0:
        session["counter"] -= 1

        # Update the user data in JSON file
        data = load_user_data()
        data[session["username"]]["counter"] = session["counter"]

        with open(DATA_FILE, "w") as file:
            json.dump(data, file, indent=4)

        if session["counter"] == 0:
            return (err, session)
        return f"Quota: {session['counter']}", session
    else:
        return (err, session)


# Gradio Interface
with gr.Blocks(theme=gr.themes.Default()) as demo:
    session = gr.State({"username": None, "counter": 0})  # Manage session state
    # Login Section
    login_block = gr.Column(visible=True)
    with login_block:
        gr.HTML(
            """
        <div style="text-align: center;">
            <a href="https://youtube.com/shorts/DmiVhj9ROag?si=j5Opmjny3kNdLlrf" target="_blank" style="font-size: 20px;">
                <strong>Klik disini untuk Demo Video <img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/YouTube_Logo_2017.svg" alt="YouTube" width="100"><br></strong>
            </a>
        </div>
        """
        )
        email_input = gr.Textbox(label="Email")
        username_input = gr.Textbox(label="WA", type="password")  # Hide input
        login_button = gr.Button("🔑 Login / Register")
        gr.Markdown(
            """### dengan login, saya menyetujui ketentuan penggunaan data perusahaan https://eHealth.co.id dan tidak akan menuntut eHealth.co.id dalam uji coba gratis AI Transkripsi Medis ini
                        
            seluruh data yang saya sediakan adalah data yang benar dan tidak melanggar hukum
            
            saya memahami bahwa tidak ada data suara maupun tulisan medis yang akan disimpan oleh eHealth.co.id, namun perusahaan tidak dapat menjamin perlakuan data penyedia model AI (OpenAI, DeepSeek, Google, Mistral, dll.) 

            ### setelah quota habis, saya dapat menambah quota dengan mengunjungi https://ehealth.co.id atau WA 6285777779926"""
        )
        output_text = gr.Textbox(label="Status", interactive=False)

    # Main User Interface (After Login)
    user_block = gr.Column(visible=False)
    with user_block:
        counter_display = gr.Textbox(label="Status Message", interactive=False)

        gr.Interface(
            fn=transcribe_and_summarize,
            inputs=[gr.Audio(type="filepath", sources="microphone"), session],
            outputs=["text", counter_display, session],
            description="Halo, pastikan HP/Laptop memiliki microphone untuk merekam percakapan dokter-pasien menjadi rekam medis SOAP. Akun berlangganan https://ehealth.co.id dapat terintegrasi SATUSEHAT & BPJS secara otomatis",
            allow_flagging="never",
            theme="light",
        )
        use_case_description = gr.Markdown(
            """
        Selain Rekam Medis Pasien, dokumen lain yang dapat digitalisasi:

        - Surgery Notes atau Catatan Tindakan Lain 

        - Inform Concern (Dokter dan Keluarga Pasien/Pasien)

        - Counseling

        - Nursing reports

        - Clinical documentation

        - Continue Care Document (untuk RS dokumentasi pemberian obat, infus, dll)."""
        )

        # Login button action
        login_button.click(
            login,
            [username_input, email_input, session],
            [output_text, session, login_block, user_block],
            trigger_mode="once",
        )

demo.launch(allowed_paths=["./images/eHwhite.png", "eHwhite.png", "./images/pp.png"])