spriambada3's picture
restyle
bb76d8d
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"])