diff --git a/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop.ipynb b/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop.ipynb
new file mode 100644
index 000000000..05c8c8663
--- /dev/null
+++ b/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop.ipynb
@@ -0,0 +1,413 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "005cc82d-cc4d-4a25-9d08-bc7f59a40db6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import tkinter as tk\n",
+ "from tkinter import ttk #Combobox\n",
+ "from tkinter import messagebox\n",
+ "from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle\n",
+ "from reportlab.lib import colors\n",
+ "from reportlab.lib.styles import getSampleStyleSheet\n",
+ "from datetime import datetime, timedelta, timezone\n",
+ "#---------------------------------------------------------------------------------\n",
+ "import sounddevice as sd\n",
+ "import numpy as np\n",
+ "from scipy.io.wavfile import write\n",
+ "\n",
+ "def record():\n",
+ " # ----------------------------\n",
+ " # Settings\n",
+ " # ----------------------------\n",
+ " duration = 10 # seconds to record\n",
+ " fs = 16000 # sampling frequency (Hz)\n",
+ " filename = \"recorded_audio.wav\" # output file\n",
+ "\n",
+ " # ----------------------------\n",
+ " # Record audio\n",
+ " # ----------------------------\n",
+ " print(\"Recording...\")\n",
+ " recording = sd.rec(int(duration * fs), samplerate=fs, channels=1)\n",
+ " sd.wait() # Wait until recording is finished\n",
+ " print(\"Recording finished!\")\n",
+ "\n",
+ " # ----------------------------\n",
+ " # Save as WAV file\n",
+ " # ----------------------------\n",
+ " # Convert to int16 for WAV format\n",
+ " write(filename, fs, np.int16(recording * 32767))\n",
+ " print(f\"Audio saved as {filename}\")\n",
+ " speech_to_text()\n",
+ "\n",
+ "#---------------------------------------------------------------------------------\n",
+ "\n",
+ "import wave\n",
+ "import json\n",
+ "from vosk import Model, KaldiRecognizer\n",
+ "\n",
+ "def speech_to_text():\n",
+ " \n",
+ "\n",
+ " # Load the Vosk model\n",
+ " model_path = r\"C:\\Users\\graem\\Downloads\\vosk-model-small-en-us-0.15\\vosk-model-small-en-us-0.15\"\n",
+ " model = Model(model_path)\n",
+ "\n",
+ " # Open recorded audio\n",
+ " wf = wave.open(\"recorded.wav\", \"rb\")\n",
+ "\n",
+ " # Initialize recognizer\n",
+ " rec = KaldiRecognizer(model, wf.getframerate())\n",
+ "\n",
+ " transcription = \"\"\n",
+ "\n",
+ " # Transcribe\n",
+ " while True:\n",
+ " data = wf.readframes(4000)\n",
+ "\n",
+ " if len(data) == 0:\n",
+ " break\n",
+ "\n",
+ " if rec.AcceptWaveform(data):\n",
+ " result = json.loads(rec.Result())\n",
+ " transcription += result.get(\"text\", \"\") + \" \"\n",
+ "\n",
+ " # Final result\n",
+ " result = json.loads(rec.FinalResult())\n",
+ " transcription += result.get(\"text\", \"\")\n",
+ " \n",
+ " text_notes.insert(tk.END, transcription)\n",
+ "\n",
+ " return transcription\n",
+ "\n",
+ "\n",
+ "# Run transcription\n",
+ "#---------------------------------------------------------------------------------\n",
+ "import json\n",
+ "import threading\n",
+ "import wave\n",
+ "import queue\n",
+ "\n",
+ "# Declare model path\n",
+ "model_path = r\"C:\\Users\\graem\\Downloads\\vosk-model-small-en-us-0.15\\vosk-model-small-en-us-0.15\"\n",
+ "model = Model(model_path)\n",
+ "\n",
+ "# Global control flag\n",
+ "global listening\n",
+ "listening = False\n",
+ "\n",
+ "global audio_frames\n",
+ "audio_frames = []\n",
+ "q = queue.Queue()\n",
+ "\n",
+ "#---------------------------------------------------------------------------------\n",
+ "# Function for speech\n",
+ "def audio_thread():\n",
+ " global listening, audio_frames\n",
+ "\n",
+ " rec = KaldiRecognizer(model, 16000)\n",
+ " audio_frames = []\n",
+ "\n",
+ " def callback(indata, frames, time, status):\n",
+ " if listening:\n",
+ " data = bytes(indata)\n",
+ " audio_frames.append(data)\n",
+ "\n",
+ " if rec.AcceptWaveform(data):\n",
+ " result = json.loads(rec.Result())\n",
+ " q.put(result.get(\"text\", \"\"))\n",
+ "\n",
+ " with sd.RawInputStream(samplerate=16000,\n",
+ " blocksize=8000,\n",
+ " dtype='int16',\n",
+ " channels=1,\n",
+ " callback=callback):\n",
+ " while listening:\n",
+ " sd.sleep(100) # IMPORTANT: prevents CPU lock\n",
+ "#---------------------------------------------------------------------------------\n",
+ "def update_textbox():\n",
+ " \"\"\"Safely update UI from queue\"\"\"\n",
+ " try:\n",
+ " while True:\n",
+ " text = q.get_nowait()\n",
+ " text_notes.insert(tk.END, text + \"\\n\")\n",
+ " except queue.Empty:\n",
+ " pass\n",
+ " root.after(100, update_textbox)\n",
+ "\n",
+ "#---------------------------------------------------------------------------------\n",
+ "def save_wav(filename=\"recorded.wav\"):\n",
+ " wf = wave.open(filename, 'wb')\n",
+ " wf.setnchannels(1)\n",
+ " wf.setsampwidth(2)\n",
+ " wf.setframerate(16000)\n",
+ " wf.writeframes(b''.join(audio_frames))\n",
+ " wf.close()\n",
+ "\n",
+ "#---------------------------------------------------------------------------------\n",
+ "# Start Recording\n",
+ "def start_listening():\n",
+ " global listening\n",
+ " listening = True\n",
+ " print(\"Listening...\")\n",
+ " threading.Thread(target=audio_thread, daemon=True).start()\n",
+ "\n",
+ "#---------------------------------------------------------------------------------\n",
+ "# Stop Recording\n",
+ "def stop_listening():\n",
+ " global listening\n",
+ " listening = False\n",
+ "\n",
+ " final = json.loads(KaldiRecognizer(model, 16000).FinalResult())\n",
+ " q.put(\"FINAL: \" + final.get(\"text\", \"\"))\n",
+ " \n",
+ " save_wav()\n",
+ " print(\"Saved to recorded.wav\")\n",
+ "\n",
+ " speech_to_text()\n",
+ "\n",
+ "\n",
+ "#---------------------------------------------------------------------------------\n",
+ "# Create PDF from data on the form\n",
+ "def generate_pdf():\n",
+ " name = entry_name.get()\n",
+ " age = entry_age.get()\n",
+ " gender = combo_gender.get()\n",
+ " diagnosis = entry_diagnosis.get()\n",
+ " bp = entry_bp.get()\n",
+ " avgheartrate = entry_avgheartrate.get()\n",
+ " avgspo2 = entry_avgspo2.get()\n",
+ " avgsleephours = entry_avgsleephours.get()\n",
+ " avgcalorieintake = entry_avgcalorieintake.get()\n",
+ " usualdietcompliance = entry_usualdietcompliance.get()\n",
+ " patientid = patient_id.get()\n",
+ " dt = datetime.get()\n",
+ " \n",
+ " notes = text_notes.get(\"1.0\", tk.END).strip()\n",
+ "\n",
+ " #if not name or not email:\n",
+ " #messagebox.showerror(\"Error\", \"Name and Email are required!\")\n",
+ " #return\n",
+ "\n",
+ " if not name:\n",
+ " messagebox.showerror(\"Error\", \"Name is required!\")\n",
+ " return\n",
+ "\n",
+ " pdf = SimpleDocTemplate(\"form_output.pdf\")\n",
+ " styles = getSampleStyleSheet()\n",
+ "\n",
+ " content = []\n",
+ "\n",
+ " # ✅ 1. Add Logo (make sure logo.png exists in same folder)\n",
+ " try:\n",
+ " logo = Image(\"logo.png\", width=120, height=60)\n",
+ " content.append(logo)\n",
+ " content.append(Spacer(1, 10))\n",
+ " except:\n",
+ " pass # skip if logo not found\n",
+ "\n",
+ " # Title\n",
+ " content.append(Paragraph(\"User Information Report\", styles[\"Title\"]))\n",
+ " content.append(Spacer(1, 20))\n",
+ "\n",
+ " # ✅ 2. Table Layout\n",
+ " data = [\n",
+ " [\"Field\", \"Value\"],\n",
+ " [\"Patient ID\", patientid],\n",
+ " [\"Date / Time\", dt],\n",
+ " [\"Name\", name],\n",
+ " [\"Age\", age],\n",
+ " [\"Gender\", gender],\n",
+ " [\"Diagnosis\", diagnosis],\n",
+ " [\"Blood Pressure\", bp],\n",
+ " [\"Avg. Heart Rate\", avgheartrate],\n",
+ " [\"Avg. SPO2\", avgspo2],\n",
+ " [\"Avg. Sleep Hours\", avgsleephours],\n",
+ " [\"Avg. Calorie Intake\", avgcalorieintake],\n",
+ " [\"Usual Diet Compliance\", usualdietcompliance]\n",
+ " ]\n",
+ "\n",
+ " table = Table(data, colWidths=[100, 250])\n",
+ "\n",
+ " table.setStyle(TableStyle([\n",
+ " (\"BACKGROUND\", (0, 0), (-1, 0), colors.grey),\n",
+ " (\"TEXTCOLOR\", (0, 0), (-1, 0), colors.white),\n",
+ "\n",
+ " (\"GRID\", (0, 0), (-1, -1), 1, colors.black),\n",
+ " (\"FONTNAME\", (0, 0), (-1, 0), \"Helvetica-Bold\"),\n",
+ "\n",
+ " (\"ALIGN\", (0, 0), (-1, -1), \"LEFT\"),\n",
+ " (\"PADDING\", (0, 0), (-1, -1), 8)\n",
+ " ]))\n",
+ "\n",
+ " content.append(table)\n",
+ " content.append(Spacer(1, 20))\n",
+ "\n",
+ " # Notes Section\n",
+ " content.append(Paragraph(\"Notes:\", styles[\"Normal\"]))\n",
+ " content.append(Spacer(1, 10))\n",
+ " content.append(Paragraph(notes, styles[\"Normal\"]))\n",
+ "\n",
+ " # Build PDF\n",
+ " pdf.build(content)\n",
+ "\n",
+ " messagebox.showinfo(\"Success\", \"PDF Generated Successfully!\")\n",
+ "#---------------------------------------------------------------------------------\n",
+ "def close_form():\n",
+ " form.destroy()\n",
+ "#---------------------------------------------------------------------------------\n",
+ "# Tkinter UI\n",
+ "root = tk.Tk()\n",
+ "form = tk.Toplevel(root)\n",
+ "form.title(\"Medical Diagnosis Form\")\n",
+ "form.geometry(\"800x800\")\n",
+ "form.configure(bg=\"#f4f6f7\")\n",
+ "\n",
+ "# --- Make a pop-up modal ---\n",
+ "form.transient(root)\n",
+ "#form.grab_set()\n",
+ "form.focus_force()\n",
+ "form.lift()\n",
+ "\n",
+ "# --- Title ---\n",
+ "tk.Label(form, text=\"Medical Diagnosis Form\",\n",
+ " font=(\"Arial\", 16, \"bold\"),\n",
+ " bg=\"#f4f6f7\").pack(pady=15)\n",
+ "\n",
+ "# --- Container ---\n",
+ "container = tk.Frame(form, bg=\"white\", bd=1, relief=\"solid\")\n",
+ "container.pack(padx=20, pady=10, fill=\"both\", expand=True)\n",
+ "\n",
+ "container.columnconfigure(0, weight=1, minsize=150)\n",
+ "container.columnconfigure(1, weight=2, minsize=300)\n",
+ "\n",
+ "# --- Labels ---\n",
+ "labels = [\"Patient ID\", \"Date / Time\", \"Patient Name *\", \"Age\", \"Gender\", \"Diagnosis *\", \"Blood Pressure\", \"Nursing Notes\", \n",
+ " \"Avg. Heart Rate\", \"Avg. SPO2\",\"Avg. Sleep Hours\", \"Avg. Calorie Intake\", \"Usual Diet Compliance\"]\n",
+ "\n",
+ "for i, text in enumerate(labels):\n",
+ " tk.Label(container, text=text, anchor=\"e\", bg=\"white\", wraplength=150, justify=\"right\")\\\n",
+ " .grid(row=i, column=0, padx=15, pady=10, sticky=\"e\")\n",
+ "\n",
+ "# --- Inputs ---\n",
+ "\n",
+ "patient_id = tk.Entry(container)\n",
+ "patient_id.insert(0,\"0011773333\")\n",
+ "patient_id.grid(row=0, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "patient_id.config(state=\"readonly\") # Makes it read-only\n",
+ "\n",
+ "now = datetime.now()\n",
+ "\n",
+ "datetime = tk.Entry(container)\n",
+ "datetime.insert(1,now.strftime(\"%d/%m/%Y %H:%M:%S\"))\n",
+ "datetime.grid(row=1, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "datetime.config(state=\"readonly\") # Makes it read-only\n",
+ "\n",
+ "entry_name = tk.Entry(container)\n",
+ "entry_name.insert(2,\"John Smith\")\n",
+ "entry_name.grid(row=2, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "name = entry_name.get()\n",
+ "\n",
+ "entry_age = tk.Entry(container)\n",
+ "entry_age.insert(3,\"35\")\n",
+ "entry_age.grid(row=3, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "age = entry_age.get()\n",
+ "\n",
+ "combo_gender = ttk.Combobox(container, values=[\"Male\", \"Female\", \"Other\"])\n",
+ "combo_gender.grid(row=4, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "\n",
+ "entry_diagnosis = tk.Entry(container)\n",
+ "entry_diagnosis.grid(row=5, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "\n",
+ "entry_bp = tk.Entry(container)\n",
+ "entry_bp.grid(row=6, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "\n",
+ "text_notes = tk.Text(container, height=5)\n",
+ "text_notes.grid(row=7, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "\n",
+ "entry_avgheartrate = tk.Entry(container)\n",
+ "entry_avgheartrate.insert(8,\"120 bpm\")\n",
+ "entry_avgheartrate.grid(row=8, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "entry_avgheartrate.config(state=\"readonly\") # Makes it read-only\n",
+ "\n",
+ "entry_avgspo2 = tk.Entry(container)\n",
+ "entry_avgspo2.insert(9,\"Test\")\n",
+ "entry_avgspo2.grid(row=9, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "entry_avgspo2.config(state=\"readonly\") # Makes it read-only\n",
+ "\n",
+ "entry_avgsleephours = tk.Entry(container)\n",
+ "entry_avgsleephours.insert(10,\"Test Sleep Hours\")\n",
+ "entry_avgsleephours.grid(row=10, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "entry_avgsleephours.config(state=\"readonly\") # Makes it read-only\n",
+ "\n",
+ "entry_avgcalorieintake = tk.Entry(container)\n",
+ "entry_avgcalorieintake.insert(11,\"Test Calorie Intake\")\n",
+ "entry_avgcalorieintake.grid(row=11, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "entry_avgcalorieintake.config(state=\"readonly\") # Makes it read-only\n",
+ "\n",
+ "entry_usualdietcompliance = tk.Entry(container)\n",
+ "entry_usualdietcompliance.insert(12,\"Test Usual Diet Compliance\")\n",
+ "entry_usualdietcompliance.grid(row=12, column=1, padx=15, pady=10, sticky=\"ew\")\n",
+ "entry_usualdietcompliance.config(state=\"readonly\") # Makes it read-only\n",
+ "\n",
+ " \n",
+ "# --- Buttons ---\n",
+ "btn_frame = tk.Frame(form, bg=\"#f4f6f7\")\n",
+ "btn_frame.pack(pady=15)\n",
+ "\n",
+ "\n",
+ "#tk.Button(btn_frame, text=\"Submit\", command=submit_form)\\\n",
+ " #.grid(row=0, column=0, padx=15)\n",
+ "\n",
+ "tk.Button(btn_frame, text=\"Close\", command=close_form)\\\n",
+ " .grid(row=0, column=1, padx=15)\n",
+ " \n",
+ "tk.Button(btn_frame, text=\"Record\", command=record)\\\n",
+ " .grid(row=1, column=0, padx=15)\n",
+ " \n",
+ "tk.Button(btn_frame, text=\"Generate PDF\", command=generate_pdf)\\\n",
+ " .grid(row=1, column=0, padx=15)\n",
+ "\n",
+ "tk.Button(btn_frame, text=\"Start Recording\", command=start_listening)\\\n",
+ " .grid(row=1, column=1, padx=15)\n",
+ "\n",
+ "tk.Button(btn_frame, text=\"Stop Recording\", command=stop_listening)\\\n",
+ " .grid(row=1, column=2, padx=15)\n",
+ "\n",
+ "root.mainloop()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3d16eeb-324c-4fb0-b295-5bc92a6b835a",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python [conda env:base] *",
+ "language": "python",
+ "name": "conda-base-py"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop_v2.ipynb b/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop_v2.ipynb
new file mode 100644
index 000000000..1fd92a899
--- /dev/null
+++ b/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop_v2.ipynb
@@ -0,0 +1,531 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "acb2bd8c-ea7c-4dd5-8d22-8060cc1bf9ce",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import json\n",
+ "import tkinter as tk\n",
+ "from tkinter import filedialog, messagebox, ttk\n",
+ "from deep_translator import GoogleTranslator\n",
+ "from datetime import datetime, timedelta, timezone\n",
+ "import re\n",
+ "import wave\n",
+ "import json\n",
+ "from vosk import Model, KaldiRecognizer\n",
+ "import threading\n",
+ "import wave\n",
+ "import queue\n",
+ "\n",
+ "# Declare model path\n",
+ "model_path = r\"C:\\Users\\graem\\Downloads\\vosk-model-small-en-us-0.15\\vosk-model-small-en-us-0.15\"\n",
+ "model = Model(model_path)\n",
+ "\n",
+ "# Global control flag\n",
+ "global listening\n",
+ "listening = False\n",
+ "\n",
+ "global audio_frames\n",
+ "audio_frames = []\n",
+ "q = queue.Queue()\n",
+ "\n",
+ "# Supported languages (can be expanded)\n",
+ "languages = {\n",
+ " \"English\": \"en\",\n",
+ " \"Spanish\": \"es\",\n",
+ " \"French\": \"fr\",\n",
+ " \"German\": \"de\",\n",
+ " \"Chinese (Simplified)\": \"zh-CN\",\n",
+ " \"Japanese\": \"ja\",\n",
+ " \"Korean\": \"ko\",\n",
+ " \"Arabic\": \"ar\",\n",
+ " \"Hindi\": \"hi\",\n",
+ " \"Italian\": \"it\"\n",
+ "}\n",
+ "\n",
+ "class MedicalApp:\n",
+ " def __init__(self, root):\n",
+ " self.root = root\n",
+ " self.root.title(\"Electronic Medical Record System\")\n",
+ " self.root.geometry(\"800x600\")\n",
+ "\n",
+ " self.data = {}\n",
+ "\n",
+ " # Style\n",
+ " style = ttk.Style()\n",
+ " style.theme_use(\"clam\")\n",
+ "\n",
+ " # Top buttons\n",
+ " top_frame = ttk.Frame(root, padding=10)\n",
+ " top_frame.pack(fill=\"x\")\n",
+ "\n",
+ " now = datetime.now().strftime(\"%d/%m/%Y %H:%M:%S\")\n",
+ "\n",
+ " ttk.Button(top_frame, text=\"Load Record\", command=self.load_json).pack(side=\"left\", padx=5)\n",
+ " ttk.Button(top_frame, text=\"Save Record\", command=self.save_json).pack(side=\"left\", padx=5)\n",
+ " ttk.Label(top_frame, text=now).pack(side=\"left\", padx=5)\n",
+ "\n",
+ " # Tabs\n",
+ " self.notebook = ttk.Notebook(root)\n",
+ " self.notebook.pack(fill=\"both\", expand=True, padx=10, pady=10)\n",
+ "\n",
+ " self.create_patient_tab()\n",
+ " self.create_medical_tab()\n",
+ " self.create_nursesnotes_tab()\n",
+ " self.create_languagetranslator_tab()\n",
+ "\n",
+ " # -------------------------\n",
+ " # Patient Info Tab\n",
+ " # -------------------------\n",
+ " def create_patient_tab(self):\n",
+ " self.patient_tab = ttk.Frame(self.notebook)\n",
+ " self.notebook.add(self.patient_tab, text=\"Patient Details\")\n",
+ "\n",
+ " frame = ttk.LabelFrame(self.patient_tab, text=\"Personal Information\", padding=15)\n",
+ " frame.pack(fill=\"x\", padx=10, pady=10)\n",
+ "\n",
+ " self.fields = {}\n",
+ "\n",
+ " labels = [\n",
+ " (\"Patient ID\", \"patient_id\"),\n",
+ " (\"First Name\", \"first_name\"),\n",
+ " (\"Last Name\", \"last_name\"),\n",
+ " (\"Email\", \"email\"),\n",
+ " (\"Phone\", \"phone\")\n",
+ " ]\n",
+ "\n",
+ " for i, (label, key) in enumerate(labels):\n",
+ " ttk.Label(frame, text=label).grid(row=i, column=0, sticky=\"w\", pady=5)\n",
+ " entry = ttk.Entry(frame, width=40)\n",
+ " entry.grid(row=i, column=1, pady=5)\n",
+ " self.fields[key] = entry\n",
+ "\n",
+ " # 👇 Add Gender Combobox (next row)\n",
+ " gender_row = len(labels)\n",
+ " \n",
+ " ttk.Label(frame, text=\"Gender\").grid(row=gender_row, column=0, sticky=\"w\", pady=5)\n",
+ " \n",
+ " self.gender_var = tk.StringVar()\n",
+ " gender_combo = ttk.Combobox(\n",
+ " frame,\n",
+ " textvariable=self.gender_var,\n",
+ " values=[\"Male\", \"Female\", \"Other\"],\n",
+ " state=\"readonly\",\n",
+ " width=37\n",
+ " )\n",
+ " gender_combo.grid(row=gender_row, column=1, pady=5)\n",
+ " gender_combo.set(\"Male\") # default value\n",
+ " \n",
+ " # Store it like other fields (optional but recommended)\n",
+ " self.fields[\"gender\"] = gender_combo\n",
+ "\n",
+ " # -------------------------\n",
+ " # Medical Tab\n",
+ " # -------------------------\n",
+ " def create_medical_tab(self):\n",
+ " self.medical_tab = ttk.Frame(self.notebook)\n",
+ " self.notebook.add(self.medical_tab, text=\"Medical Data\")\n",
+ "\n",
+ " # Conditions\n",
+ " cond_frame = ttk.LabelFrame(self.medical_tab, text=\"Conditions\", padding=10)\n",
+ " cond_frame.pack(fill=\"both\", expand=True, padx=10, pady=5)\n",
+ "\n",
+ " self.conditions_list = tk.Listbox(cond_frame, height=6)\n",
+ " self.conditions_list.pack(side=\"left\", fill=\"both\", expand=True)\n",
+ "\n",
+ " ttk.Button(cond_frame, text=\"Add\", command=self.add_condition).pack(side=\"right\", padx=5)\n",
+ "\n",
+ " # Medications\n",
+ " med_frame = ttk.LabelFrame(self.medical_tab, text=\"Medications\", padding=10)\n",
+ " med_frame.pack(fill=\"both\", expand=True, padx=10, pady=5)\n",
+ "\n",
+ " self.medications_list = tk.Listbox(med_frame, height=6)\n",
+ " self.medications_list.pack(side=\"left\", fill=\"both\", expand=True)\n",
+ "\n",
+ " ttk.Button(med_frame, text=\"Add\", command=self.add_medication).pack(side=\"right\", padx=5)\n",
+ "\n",
+ " # -------------------------\n",
+ " # Nurses Notes Tab\n",
+ " # -------------------------\n",
+ " def create_nursesnotes_tab(self):\n",
+ " self.nursesnotes_tab = ttk.Frame(self.notebook)\n",
+ " self.notebook.add(self.nursesnotes_tab, text=\"Nursing Notes\")\n",
+ " \n",
+ " main_frame = ttk.Frame(self.nursesnotes_tab, padding=10)\n",
+ " main_frame.pack(fill=\"both\", expand=True)\n",
+ "\n",
+ " # Nursing notes text box\n",
+ " ttk.Label(main_frame, text=\"Nursing Notes:\").pack(anchor=\"w\")\n",
+ " self.input_text = tk.Text(main_frame, height=10)\n",
+ " self.input_text.pack(fill=\"x\", pady=5)\n",
+ "\n",
+ " ttk.Button(main_frame, text=\"Start Recording\", command=self.start_listening).pack(side=\"left\", padx=5)\n",
+ " ttk.Button(main_frame, text=\"Stop Recording\", command=self.stop_listening).pack(side=\"left\", padx=5)\n",
+ " \n",
+ " # -------------------------\n",
+ " # Language Translator Tab\n",
+ " # -------------------------\n",
+ " def create_languagetranslator_tab(self):\n",
+ " self.languagetranslator_tab = ttk.Frame(self.notebook)\n",
+ " self.notebook.add(self.languagetranslator_tab, text=\"Language Translator\")\n",
+ " \n",
+ " main_frame = ttk.Frame(self.languagetranslator_tab, padding=10)\n",
+ " main_frame.pack(fill=\"both\", expand=True)\n",
+ " \n",
+ " # Input Text\n",
+ " ttk.Label(main_frame, text=\"Input Text:\").pack(anchor=\"w\")\n",
+ " self.input_text = tk.Text(main_frame, height=6)\n",
+ " self.input_text.pack(fill=\"x\", pady=5)\n",
+ " \n",
+ " # Language selection frame (GRID ONLY here)\n",
+ " control_frame = ttk.Frame(main_frame)\n",
+ " control_frame.pack(pady=10)\n",
+ " \n",
+ " ttk.Label(control_frame, text=\"From:\").grid(row=0, column=0, padx=5)\n",
+ " self.from_lang = ttk.Combobox(control_frame, values=list(languages.keys()), state=\"readonly\")\n",
+ " self.from_lang.grid(row=0, column=1, padx=5)\n",
+ " self.from_lang.set(\"English\")\n",
+ " \n",
+ " ttk.Label(control_frame, text=\"To:\").grid(row=0, column=2, padx=5)\n",
+ " self.to_lang = ttk.Combobox(control_frame, values=list(languages.keys()), state=\"readonly\")\n",
+ " self.to_lang.grid(row=0, column=3, padx=5)\n",
+ " self.to_lang.set(\"Spanish\")\n",
+ " \n",
+ " ttk.Button(main_frame, text=\"Translate\", command=self.translate_text).pack(pady=10)\n",
+ " \n",
+ " # Output Text\n",
+ " ttk.Label(main_frame, text=\"Translated Text:\").pack(anchor=\"w\")\n",
+ " self.output_text = tk.Text(main_frame, height=6)\n",
+ " self.output_text.pack(fill=\"x\", pady=5)\n",
+ "\n",
+ " # -------------------------\n",
+ " # Language Translator Tab Button\n",
+ " # -------------------------\n",
+ " def translate_text(self):\n",
+ " try:\n",
+ " input_value = self.input_text.get(\"1.0\", tk.END).strip()\n",
+ " if not input_value:\n",
+ " messagebox.showwarning(\"Warning\", \"Please enter text to translate.\")\n",
+ " return\n",
+ "\n",
+ " from_language = languages[self.from_lang.get()]\n",
+ " to_language = languages[self.to_lang.get()]\n",
+ "\n",
+ " translated = GoogleTranslator(source=from_language, target=to_language).translate(input_value)\n",
+ "\n",
+ " self.output_text.delete(\"1.0\", tk.END)\n",
+ " self.output_text.insert(tk.END, translated)\n",
+ "\n",
+ " except Exception as e:\n",
+ " messagebox.showerror(\"Error\", str(e))\n",
+ "\n",
+ " # -------------------------\n",
+ " # Validation\n",
+ " # -------------------------\n",
+ " def validate(self):\n",
+ " email = self.fields[\"email\"].get()\n",
+ " phone = self.fields[\"phone\"].get()\n",
+ "\n",
+ " if not re.match(r'^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$', email):\n",
+ " messagebox.showerror(\"Error\", \"Invalid email\")\n",
+ " return False\n",
+ "\n",
+ " if not re.match(r'^\\+?\\d[\\d\\- ]+$', phone):\n",
+ " messagebox.showerror(\"Error\", \"Invalid phone\")\n",
+ " return False\n",
+ "\n",
+ " return True\n",
+ "\n",
+ " # -------------------------\n",
+ " # Load JSON\n",
+ " # -------------------------\n",
+ " def load_json(self):\n",
+ " path = filedialog.askopenfilename(filetypes=[(\"JSON\", \"*.json\")])\n",
+ " if not path:\n",
+ " return\n",
+ "\n",
+ " with open(path) as f:\n",
+ " self.data = json.load(f)\n",
+ "\n",
+ " # Clear fields\n",
+ " for field in self.fields.values():\n",
+ " field.delete(0, tk.END)\n",
+ "\n",
+ " self.conditions_list.delete(0, tk.END)\n",
+ " self.medications_list.delete(0, tk.END)\n",
+ "\n",
+ " # Populate\n",
+ " pd = self.data[\"personal_details\"]\n",
+ " contact = pd[\"contact\"]\n",
+ "\n",
+ " self.fields[\"patient_id\"].insert(0, self.data[\"patient_id\"])\n",
+ " self.fields[\"first_name\"].insert(0, pd[\"first_name\"])\n",
+ " self.fields[\"last_name\"].insert(0, pd[\"last_name\"])\n",
+ " self.fields[\"email\"].insert(0, contact[\"email\"])\n",
+ " self.fields[\"phone\"].insert(0, contact[\"phone\"])\n",
+ "\n",
+ " for c in self.data[\"medical_history\"][\"conditions\"]:\n",
+ " self.conditions_list.insert(tk.END, f\"{c['name']} ({c['status']})\")\n",
+ "\n",
+ " for m in self.data[\"medications\"]:\n",
+ " self.medications_list.insert(tk.END, f\"{m['name']} - {m['dosage']}\")\n",
+ "\n",
+ " # -------------------------\n",
+ " # Add Condition\n",
+ " # -------------------------\n",
+ " def add_condition(self):\n",
+ " win = tk.Toplevel(self.root)\n",
+ " win.title(\"Add Condition\")\n",
+ "\n",
+ " ttk.Label(win, text=\"Name\").pack()\n",
+ " name = ttk.Entry(win)\n",
+ " name.pack()\n",
+ "\n",
+ " ttk.Label(win, text=\"Status\").pack()\n",
+ " status = ttk.Entry(win)\n",
+ " status.pack()\n",
+ "\n",
+ " def save():\n",
+ " self.conditions_list.insert(tk.END, f\"{name.get()} ({status.get()})\")\n",
+ " win.destroy()\n",
+ "\n",
+ " ttk.Button(win, text=\"Save\", command=save).pack()\n",
+ "\n",
+ " # -------------------------\n",
+ " # Add Medication\n",
+ " # -------------------------\n",
+ " def add_medication(self):\n",
+ " win = tk.Toplevel(self.root)\n",
+ " win.title(\"Add Medication\")\n",
+ "\n",
+ " ttk.Label(win, text=\"Name\").pack()\n",
+ " name = ttk.Entry(win)\n",
+ " name.pack()\n",
+ "\n",
+ " ttk.Label(win, text=\"Dosage\").pack()\n",
+ " dosage = ttk.Entry(win)\n",
+ " dosage.pack()\n",
+ "\n",
+ " def save():\n",
+ " self.medications_list.insert(tk.END, f\"{name.get()} - {dosage.get()}\")\n",
+ " win.destroy()\n",
+ "\n",
+ " ttk.Button(win, text=\"Save\", command=save).pack()\n",
+ "\n",
+ " # -------------------------\n",
+ " # Save JSON\n",
+ " # -------------------------\n",
+ " def save_json(self):\n",
+ " if not self.validate():\n",
+ " return\n",
+ "\n",
+ " self.data[\"patient_id\"] = self.fields[\"patient_id\"].get()\n",
+ "\n",
+ " pd = self.data[\"personal_details\"]\n",
+ " contact = pd[\"contact\"]\n",
+ "\n",
+ " pd[\"first_name\"] = self.fields[\"first_name\"].get()\n",
+ " pd[\"last_name\"] = self.fields[\"last_name\"].get()\n",
+ " pd[\"gender\"] = self.fields[\"gender\"].get()\n",
+ " contact[\"email\"] = self.fields[\"email\"].get()\n",
+ " contact[\"phone\"] = self.fields[\"phone\"].get()\n",
+ "\n",
+ " # Conditions\n",
+ " conditions = []\n",
+ " for item in self.conditions_list.get(0, tk.END):\n",
+ " name, status = item.split(\" (\")\n",
+ " conditions.append({\n",
+ " \"name\": name,\n",
+ " \"status\": status.replace(\")\", \"\"),\n",
+ " \"diagnosed_date\": \"\"\n",
+ " })\n",
+ "\n",
+ " self.data[\"medical_history\"][\"conditions\"] = conditions\n",
+ "\n",
+ " # Medications\n",
+ " meds = []\n",
+ " for item in self.medications_list.get(0, tk.END):\n",
+ " name, dosage = item.split(\" - \")\n",
+ " meds.append({\n",
+ " \"name\": name,\n",
+ " \"dosage\": dosage,\n",
+ " \"frequency\": \"\",\n",
+ " \"start_date\": \"\"\n",
+ " })\n",
+ "\n",
+ " self.data[\"medications\"] = meds\n",
+ "\n",
+ " path = filedialog.asksaveasfilename(defaultextension=\".json\")\n",
+ " if not path:\n",
+ " return\n",
+ "\n",
+ " with open(path, \"w\") as f:\n",
+ " json.dump(self.data, f, indent=4)\n",
+ "\n",
+ " messagebox.showinfo(\"Saved\", \"Record saved successfully\")\n",
+ "\n",
+ " def record():\n",
+ " # ----------------------------\n",
+ " # Settings\n",
+ " # ----------------------------\n",
+ " duration = 10 # seconds to record\n",
+ " fs = 16000 # sampling frequency (Hz)\n",
+ " filename = \"recorded_audio.wav\" # output file\n",
+ " \n",
+ " # ----------------------------\n",
+ " # Record audio\n",
+ " # ----------------------------\n",
+ " print(\"Recording...\")\n",
+ " recording = sd.rec(int(duration * fs), samplerate=fs, channels=1)\n",
+ " sd.wait() # Wait until recording is finished\n",
+ " print(\"Recording finished!\")\n",
+ " \n",
+ " # ----------------------------\n",
+ " # Save as WAV file\n",
+ " # ----------------------------\n",
+ " # Convert to int16 for WAV format\n",
+ " write(filename, fs, np.int16(recording * 32767))\n",
+ " print(f\"Audio saved as {filename}\")\n",
+ " speech_to_text()\n",
+ "\n",
+ " def speech_to_text():\n",
+ " # Load the Vosk model\n",
+ " model_path = r\"C:\\Users\\graem\\Downloads\\vosk-model-small-en-us-0.15\\vosk-model-small-en-us-0.15\"\n",
+ " model = Model(model_path)\n",
+ " \n",
+ " # Open recorded audio\n",
+ " wf = wave.open(\"recorded.wav\", \"rb\")\n",
+ " \n",
+ " # Initialize recognizer\n",
+ " rec = KaldiRecognizer(model, wf.getframerate())\n",
+ " \n",
+ " transcription = \"\"\n",
+ " \n",
+ " # Transcribe\n",
+ " while True:\n",
+ " data = wf.readframes(4000)\n",
+ " \n",
+ " if len(data) == 0:\n",
+ " break\n",
+ " \n",
+ " if rec.AcceptWaveform(data):\n",
+ " result = json.loads(rec.Result())\n",
+ " transcription += result.get(\"text\", \"\") + \" \"\n",
+ " \n",
+ " # Final result\n",
+ " result = json.loads(rec.FinalResult())\n",
+ " transcription += result.get(\"text\", \"\")\n",
+ " \n",
+ " text_notes.insert(tk.END, transcription)\n",
+ " \n",
+ " return transcription\n",
+ "\n",
+ " #---------------------------------------------------------------------------------\n",
+ " # Function for speech\n",
+ " def audio_thread():\n",
+ " global listening, audio_frames\n",
+ " \n",
+ " rec = KaldiRecognizer(model, 16000)\n",
+ " audio_frames = []\n",
+ " \n",
+ " def callback(indata, frames, time, status):\n",
+ " if listening:\n",
+ " data = bytes(indata)\n",
+ " audio_frames.append(data)\n",
+ " \n",
+ " if rec.AcceptWaveform(data):\n",
+ " result = json.loads(rec.Result())\n",
+ " q.put(result.get(\"text\", \"\"))\n",
+ " \n",
+ " with sd.RawInputStream(samplerate=16000,\n",
+ " blocksize=8000,\n",
+ " dtype='int16',\n",
+ " channels=1,\n",
+ " callback=callback):\n",
+ " while listening:\n",
+ " sd.sleep(100) # IMPORTANT: prevents CPU lock\n",
+ "\n",
+ " #---------------------------------------------------------------------------------\n",
+ " def update_textbox():\n",
+ " \"\"\"Safely update UI from queue\"\"\"\n",
+ " try:\n",
+ " while True:\n",
+ " text = q.get_nowait()\n",
+ " text_notes.insert(tk.END, text + \"\\n\")\n",
+ " except queue.Empty:\n",
+ " pass\n",
+ " root.after(100, update_textbox)\n",
+ " \n",
+ " #---------------------------------------------------------------------------------\n",
+ " def save_wav(filename=\"recorded.wav\"):\n",
+ " wf = wave.open(filename, 'wb')\n",
+ " wf.setnchannels(1)\n",
+ " wf.setsampwidth(2)\n",
+ " wf.setframerate(16000)\n",
+ " wf.writeframes(b''.join(audio_frames))\n",
+ " wf.close()\n",
+ " \n",
+ " #---------------------------------------------------------------------------------\n",
+ " # Start Recording\n",
+ " def start_listening():\n",
+ " global listening\n",
+ " listening = True\n",
+ " print(\"Listening...\")\n",
+ " threading.Thread(target=audio_thread, daemon=True).start()\n",
+ " \n",
+ " #---------------------------------------------------------------------------------\n",
+ " # Stop Recording\n",
+ " def stop_listening():\n",
+ " global listening\n",
+ " listening = False\n",
+ " \n",
+ " final = json.loads(KaldiRecognizer(model, 16000).FinalResult())\n",
+ " q.put(\"FINAL: \" + final.get(\"text\", \"\"))\n",
+ " \n",
+ " save_wav()\n",
+ " print(\"Saved to recorded.wav\")\n",
+ " \n",
+ " speech_to_text()\n",
+ "\n",
+ "\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " root = tk.Tk()\n",
+ " app = MedicalApp(root)\n",
+ " root.mainloop()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bb6860bc-ca7f-4f49-9021-1a18d91292c3",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python [conda env:base] *",
+ "language": "python",
+ "name": "conda-base-py"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop_v3.ipynb b/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop_v3.ipynb
new file mode 100644
index 000000000..bea9f835c
--- /dev/null
+++ b/AI Guardian/Gopher_AI_FromPDFSp2TextStartstop_v3.ipynb
@@ -0,0 +1,1278 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "id": "5abbf1de-ad66-4c72-b177-491520b24b94",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Listening...\n",
+ "Saved to recorded.wav\n",
+ "facing the recording saying comes out correctly\n"
+ ]
+ }
+ ],
+ "source": [
+ "import json\n",
+ "import tkinter as tk\n",
+ "from tkinter import filedialog, messagebox, ttk\n",
+ "from deep_translator import GoogleTranslator\n",
+ "from datetime import datetime\n",
+ "import re\n",
+ "import wave\n",
+ "import queue\n",
+ "import threading\n",
+ "import sounddevice as sd\n",
+ "\n",
+ "from vosk import Model, KaldiRecognizer\n",
+ "from textblob import TextBlob\n",
+ "\n",
+ "# =========================================================\n",
+ "# PDF IMPORTS\n",
+ "# =========================================================\n",
+ "\n",
+ "from reportlab.lib.pagesizes import letter\n",
+ "from reportlab.platypus import (\n",
+ " SimpleDocTemplate,\n",
+ " Paragraph,\n",
+ " Spacer\n",
+ ")\n",
+ "from reportlab.lib.styles import getSampleStyleSheet\n",
+ "\n",
+ "# =========================================================\n",
+ "# VOSK MODEL\n",
+ "# =========================================================\n",
+ "\n",
+ "model_path = r\"C:\\Users\\graem\\Downloads\\vosk-model-small-en-us-0.15\\vosk-model-small-en-us-0.15\"\n",
+ "\n",
+ "model = Model(model_path)\n",
+ "\n",
+ "# =========================================================\n",
+ "# GLOBALS\n",
+ "# =========================================================\n",
+ "\n",
+ "listening = False\n",
+ "audio_frames = []\n",
+ "q = queue.Queue()\n",
+ "\n",
+ "# Supported languages (can be expanded)\n",
+ "languages = {\n",
+ " \"English\": \"en\",\n",
+ " \"Spanish\": \"es\",\n",
+ " \"French\": \"fr\",\n",
+ " \"German\": \"de\",\n",
+ " \"Chinese (Simplified)\": \"zh-CN\",\n",
+ " \"Japanese\": \"ja\",\n",
+ " \"Korean\": \"ko\",\n",
+ " \"Arabic\": \"ar\",\n",
+ " \"Hindi\": \"hi\",\n",
+ " \"Italian\": \"it\"\n",
+ "}\n",
+ "\n",
+ "# =========================================================\n",
+ "# MAIN APPLICATION\n",
+ "# =========================================================\n",
+ "\n",
+ "class MedicalApp:\n",
+ "\n",
+ " def __init__(self, root):\n",
+ "\n",
+ " self.root = root\n",
+ "\n",
+ " self.root.title(\"Electronic Medical Record System\")\n",
+ " self.root.geometry(\"1000x700\")\n",
+ "\n",
+ " # =====================================================\n",
+ " # GLOBAL UI SETTINGS\n",
+ " # =====================================================\n",
+ "\n",
+ " root.option_add(\"*Font\", (\"Segoe UI\", 10))\n",
+ " root.option_add(\"*Background\", \"#66B2B2\")\n",
+ " root.option_add(\"*Foreground\", \"white\")\n",
+ "\n",
+ " # =====================================================\n",
+ " # COLOURS\n",
+ " # =====================================================\n",
+ "\n",
+ " self.PRIMARY = \"#66B2B2\"\n",
+ " self.DARK = \"#4C9999\"\n",
+ " self.LIGHT = \"#A0D6D6\"\n",
+ " self.WHITE = \"white\"\n",
+ " self.TEXT = \"black\"\n",
+ "\n",
+ " self.root.configure(bg=self.PRIMARY)\n",
+ "\n",
+ " # =====================================================\n",
+ " # STYLE\n",
+ " # =====================================================\n",
+ "\n",
+ " style = ttk.Style()\n",
+ "\n",
+ " style.theme_use(\"clam\")\n",
+ "\n",
+ " style.configure(\n",
+ " \".\",\n",
+ " background=self.PRIMARY,\n",
+ " foreground=self.WHITE,\n",
+ " font=(\"Segoe UI\", 10)\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TFrame\",\n",
+ " background=self.PRIMARY\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TLabelframe\",\n",
+ " background=self.PRIMARY,\n",
+ " bordercolor=self.WHITE,\n",
+ " borderwidth=2,\n",
+ " relief=\"solid\"\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TLabelframe.Label\",\n",
+ " background=self.PRIMARY,\n",
+ " foreground=self.WHITE,\n",
+ " font=(\"Segoe UI\", 10, \"bold\")\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TLabel\",\n",
+ " background=self.PRIMARY,\n",
+ " foreground=self.WHITE,\n",
+ " font=(\"Segoe UI\", 10)\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TButton\",\n",
+ " background=self.LIGHT,\n",
+ " foreground=self.TEXT,\n",
+ " font=(\"Segoe UI\", 10, \"bold\"),\n",
+ " padding=6\n",
+ " )\n",
+ "\n",
+ " style.map(\n",
+ " \"TButton\",\n",
+ " background=[(\"active\", self.DARK)],\n",
+ " foreground=[(\"active\", self.WHITE)]\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TNotebook\",\n",
+ " background=self.PRIMARY\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TNotebook.Tab\",\n",
+ " background=self.LIGHT,\n",
+ " foreground=self.TEXT,\n",
+ " font=(\"Segoe UI\", 10, \"bold\"),\n",
+ " padding=[12, 6]\n",
+ " )\n",
+ "\n",
+ " style.map(\n",
+ " \"TNotebook.Tab\",\n",
+ " background=[(\"selected\", self.DARK)],\n",
+ " foreground=[(\"selected\", self.WHITE)]\n",
+ " )\n",
+ "\n",
+ " style.configure(\n",
+ " \"TCombobox\",\n",
+ " fieldbackground=self.WHITE,\n",
+ " background=self.LIGHT,\n",
+ " foreground=self.TEXT\n",
+ " )\n",
+ "\n",
+ " # =====================================================\n",
+ " # BUTTON STYLE\n",
+ " # =====================================================\n",
+ "\n",
+ " self.button_style = {\n",
+ " \"font\": (\"Segoe UI\", 10, \"bold\"),\n",
+ " \"bg\": self.LIGHT,\n",
+ " \"fg\": self.TEXT,\n",
+ " \"activebackground\": self.DARK,\n",
+ " \"activeforeground\": self.WHITE,\n",
+ " \"relief\": \"solid\",\n",
+ " \"bd\": 1,\n",
+ " \"highlightthickness\": 2,\n",
+ " \"highlightbackground\": self.WHITE,\n",
+ " \"highlightcolor\": self.WHITE,\n",
+ " \"cursor\": \"hand2\",\n",
+ " \"padx\": 10,\n",
+ " \"pady\": 5\n",
+ " }\n",
+ "\n",
+ " # =====================================================\n",
+ " # TOP FRAME\n",
+ " # =====================================================\n",
+ "\n",
+ " top_frame = tk.Frame(\n",
+ " root,\n",
+ " bg=self.PRIMARY\n",
+ " )\n",
+ "\n",
+ " top_frame.pack(\n",
+ " fill=\"x\",\n",
+ " padx=10,\n",
+ " pady=10\n",
+ " )\n",
+ "\n",
+ " tk.Button(\n",
+ " top_frame,\n",
+ " text=\"Load Record\",\n",
+ " command=self.load_json,\n",
+ " **self.button_style\n",
+ " ).pack(side=\"left\", padx=5)\n",
+ "\n",
+ " tk.Button(\n",
+ " top_frame,\n",
+ " text=\"Save Record\",\n",
+ " command=self.save_json,\n",
+ " **self.button_style\n",
+ " ).pack(side=\"left\", padx=5)\n",
+ "\n",
+ " tk.Button(\n",
+ " top_frame,\n",
+ " text=\"Generate PDF\",\n",
+ " command=self.generate_pdf,\n",
+ " **self.button_style\n",
+ " ).pack(side=\"left\", padx=5)\n",
+ "\n",
+ " current_time = datetime.now().strftime(\n",
+ " \"%d/%m/%Y %H:%M:%S\"\n",
+ " )\n",
+ "\n",
+ " tk.Label(\n",
+ " top_frame,\n",
+ " text=current_time,\n",
+ " bg=self.PRIMARY,\n",
+ " fg=self.WHITE,\n",
+ " font=(\"Segoe UI\", 10, \"bold\")\n",
+ " ).pack(side=\"left\", padx=15)\n",
+ "\n",
+ " # =====================================================\n",
+ " # NOTEBOOK\n",
+ " # =====================================================\n",
+ "\n",
+ " self.notebook = ttk.Notebook(root)\n",
+ "\n",
+ " self.notebook.pack(\n",
+ " fill=\"both\",\n",
+ " expand=True,\n",
+ " padx=10,\n",
+ " pady=10\n",
+ " )\n",
+ "\n",
+ " self.create_patient_tab()\n",
+ " self.create_medical_tab()\n",
+ " self.create_notes_tab()\n",
+ " self.create_translator_tab()\n",
+ "\n",
+ " # Start queue updater\n",
+ " self.update_textbox()\n",
+ "\n",
+ " # =========================================================\n",
+ " # STYLED ENTRY\n",
+ " # =========================================================\n",
+ "\n",
+ " def styled_entry(self, parent, width=40):\n",
+ "\n",
+ " return tk.Entry(\n",
+ " parent,\n",
+ " width=width,\n",
+ " font=(\"Segoe UI\", 10),\n",
+ " bg=\"white\",\n",
+ " fg=\"black\",\n",
+ " relief=\"flat\",\n",
+ " bd=0,\n",
+ " highlightthickness=2,\n",
+ " highlightbackground=\"white\",\n",
+ " highlightcolor=\"white\",\n",
+ " insertbackground=\"black\"\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # STYLED TEXT\n",
+ " # =========================================================\n",
+ "\n",
+ " def styled_text(self, parent, height=6):\n",
+ "\n",
+ " return tk.Text(\n",
+ " parent,\n",
+ " height=height,\n",
+ " font=(\"Segoe UI\", 10),\n",
+ " bg=\"white\",\n",
+ " fg=\"black\",\n",
+ " relief=\"flat\",\n",
+ " bd=0,\n",
+ " highlightthickness=2,\n",
+ " highlightbackground=\"white\",\n",
+ " highlightcolor=\"white\",\n",
+ " insertbackground=\"black\"\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # STYLED LISTBOX\n",
+ " # =========================================================\n",
+ "\n",
+ " def styled_listbox(self, parent, height=6):\n",
+ "\n",
+ " return tk.Listbox(\n",
+ " parent,\n",
+ " height=height,\n",
+ " font=(\"Segoe UI\", 10),\n",
+ " bg=\"white\",\n",
+ " fg=\"black\",\n",
+ " relief=\"flat\",\n",
+ " bd=0,\n",
+ " highlightthickness=2,\n",
+ " highlightbackground=\"white\",\n",
+ " highlightcolor=\"white\",\n",
+ " selectbackground=self.DARK,\n",
+ " selectforeground=\"white\"\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # STYLE TOPLEVEL\n",
+ " # =========================================================\n",
+ "\n",
+ " def style_toplevel(self, window):\n",
+ "\n",
+ " window.configure(bg=self.PRIMARY)\n",
+ "\n",
+ " # =========================================================\n",
+ " # PATIENT TAB\n",
+ " # =========================================================\n",
+ "\n",
+ " def create_patient_tab(self):\n",
+ "\n",
+ " self.patient_tab = ttk.Frame(self.notebook)\n",
+ "\n",
+ " self.notebook.add(\n",
+ " self.patient_tab,\n",
+ " text=\"Patient Details\"\n",
+ " )\n",
+ "\n",
+ " frame = ttk.LabelFrame(\n",
+ " self.patient_tab,\n",
+ " text=\"Personal Information\",\n",
+ " padding=20\n",
+ " )\n",
+ "\n",
+ " frame.pack(\n",
+ " fill=\"x\",\n",
+ " padx=10,\n",
+ " pady=10\n",
+ " )\n",
+ "\n",
+ " self.fields = {}\n",
+ "\n",
+ " labels = [\n",
+ " (\"Patient ID\", \"patient_id\"),\n",
+ " (\"First Name\", \"first_name\"),\n",
+ " (\"Last Name\", \"last_name\"),\n",
+ " (\"Email\", \"email\"),\n",
+ " (\"Phone\", \"phone\")\n",
+ " ]\n",
+ "\n",
+ " for i, (label, key) in enumerate(labels):\n",
+ "\n",
+ " ttk.Label(\n",
+ " frame,\n",
+ " text=label\n",
+ " ).grid(\n",
+ " row=i,\n",
+ " column=0,\n",
+ " sticky=\"w\",\n",
+ " pady=12,\n",
+ " padx=10\n",
+ " )\n",
+ "\n",
+ " entry = self.styled_entry(frame)\n",
+ "\n",
+ " entry.grid(\n",
+ " row=i,\n",
+ " column=1,\n",
+ " pady=12,\n",
+ " padx=10,\n",
+ " ipady=5\n",
+ " )\n",
+ "\n",
+ " self.fields[key] = entry\n",
+ "\n",
+ " ttk.Label(\n",
+ " frame,\n",
+ " text=\"Gender\"\n",
+ " ).grid(\n",
+ " row=len(labels),\n",
+ " column=0,\n",
+ " sticky=\"w\",\n",
+ " pady=12,\n",
+ " padx=10\n",
+ " )\n",
+ "\n",
+ " self.gender_var = tk.StringVar()\n",
+ "\n",
+ " gender_combo = ttk.Combobox(\n",
+ " frame,\n",
+ " textvariable=self.gender_var,\n",
+ " values=[\"Male\", \"Female\", \"Other\"],\n",
+ " state=\"readonly\",\n",
+ " width=37\n",
+ " )\n",
+ "\n",
+ " gender_combo.grid(\n",
+ " row=len(labels),\n",
+ " column=1,\n",
+ " pady=12,\n",
+ " padx=10\n",
+ " )\n",
+ "\n",
+ " gender_combo.set(\"Male\")\n",
+ "\n",
+ " # =========================================================\n",
+ " # MEDICAL TAB\n",
+ " # =========================================================\n",
+ "\n",
+ " def create_medical_tab(self):\n",
+ "\n",
+ " self.medical_tab = ttk.Frame(self.notebook)\n",
+ "\n",
+ " self.notebook.add(\n",
+ " self.medical_tab,\n",
+ " text=\"Medical Data\"\n",
+ " )\n",
+ "\n",
+ " # Conditions\n",
+ " cond_frame = ttk.LabelFrame(\n",
+ " self.medical_tab,\n",
+ " text=\"Conditions\",\n",
+ " padding=10\n",
+ " )\n",
+ "\n",
+ " cond_frame.pack(\n",
+ " fill=\"both\",\n",
+ " expand=True,\n",
+ " padx=10,\n",
+ " pady=5\n",
+ " )\n",
+ "\n",
+ " self.conditions_list = self.styled_listbox(\n",
+ " cond_frame,\n",
+ " height=6\n",
+ " )\n",
+ "\n",
+ " self.conditions_list.pack(\n",
+ " side=\"left\",\n",
+ " fill=\"both\",\n",
+ " expand=True\n",
+ " )\n",
+ "\n",
+ " tk.Button(\n",
+ " cond_frame,\n",
+ " text=\"Add\",\n",
+ " command=self.add_condition,\n",
+ " **self.button_style\n",
+ " ).pack(side=\"right\", padx=5)\n",
+ "\n",
+ " # Medications\n",
+ " med_frame = ttk.LabelFrame(\n",
+ " self.medical_tab,\n",
+ " text=\"Medications\",\n",
+ " padding=10\n",
+ " )\n",
+ "\n",
+ " med_frame.pack(\n",
+ " fill=\"both\",\n",
+ " expand=True,\n",
+ " padx=10,\n",
+ " pady=5\n",
+ " )\n",
+ "\n",
+ " self.medications_list = self.styled_listbox(\n",
+ " med_frame,\n",
+ " height=6\n",
+ " )\n",
+ "\n",
+ " self.medications_list.pack(\n",
+ " side=\"left\",\n",
+ " fill=\"both\",\n",
+ " expand=True\n",
+ " )\n",
+ "\n",
+ " tk.Button(\n",
+ " med_frame,\n",
+ " text=\"Add\",\n",
+ " command=self.add_medication,\n",
+ " **self.button_style\n",
+ " ).pack(side=\"right\", padx=5)\n",
+ "\n",
+ " # =========================================================\n",
+ " # NOTES TAB\n",
+ " # =========================================================\n",
+ "\n",
+ " def create_notes_tab(self):\n",
+ "\n",
+ " self.notes_tab = ttk.Frame(self.notebook)\n",
+ "\n",
+ " self.notebook.add(\n",
+ " self.notes_tab,\n",
+ " text=\"Nursing Notes\"\n",
+ " )\n",
+ "\n",
+ " frame = ttk.LabelFrame(\n",
+ " self.notes_tab,\n",
+ " text=\"Nursing Notes\",\n",
+ " padding=15\n",
+ " )\n",
+ "\n",
+ " frame.pack(\n",
+ " fill=\"both\",\n",
+ " expand=True,\n",
+ " padx=10,\n",
+ " pady=10\n",
+ " )\n",
+ "\n",
+ " self.notes_text = self.styled_text(\n",
+ " frame,\n",
+ " height=15\n",
+ " )\n",
+ "\n",
+ " self.notes_text.pack(\n",
+ " fill=\"both\",\n",
+ " expand=True\n",
+ " )\n",
+ "\n",
+ " tk.Button(\n",
+ " frame,\n",
+ " text=\"Start Recording\",\n",
+ " command=self.start_listening,\n",
+ " **self.button_style\n",
+ " ).pack(side=\"left\", padx=5, pady=10)\n",
+ "\n",
+ " tk.Button(\n",
+ " frame,\n",
+ " text=\"Stop Recording\",\n",
+ " command=self.stop_listening,\n",
+ " **self.button_style\n",
+ " ).pack(side=\"left\", padx=5, pady=10)\n",
+ "\n",
+ " # =========================================================\n",
+ " # TRANSLATOR TAB\n",
+ " # =========================================================\n",
+ "\n",
+ " # =========================================================\n",
+ "# TRANSLATOR TAB\n",
+ "# =========================================================\n",
+ "\n",
+ " def create_translator_tab(self):\n",
+ " \n",
+ " self.translator_tab = ttk.Frame(self.notebook)\n",
+ " \n",
+ " self.notebook.add(\n",
+ " self.translator_tab,\n",
+ " text=\"Language Translator\"\n",
+ " )\n",
+ " \n",
+ " frame = ttk.Frame(\n",
+ " self.translator_tab,\n",
+ " padding=15\n",
+ " )\n",
+ " \n",
+ " frame.pack(\n",
+ " fill=\"both\",\n",
+ " expand=True\n",
+ " )\n",
+ "\n",
+ " # =====================================================\n",
+ " # LANGUAGE SELECTION FRAME\n",
+ " # =====================================================\n",
+ " \n",
+ " lang_frame = ttk.Frame(frame)\n",
+ " \n",
+ " lang_frame.pack(\n",
+ " fill=\"x\",\n",
+ " pady=10\n",
+ " )\n",
+ "\n",
+ " # -------------------------\n",
+ " # FROM LANGUAGE\n",
+ " # -------------------------\n",
+ " \n",
+ " ttk.Label(\n",
+ " lang_frame,\n",
+ " text=\"From Language\"\n",
+ " ).grid(\n",
+ " row=0,\n",
+ " column=0,\n",
+ " padx=10,\n",
+ " pady=5,\n",
+ " sticky=\"w\"\n",
+ " )\n",
+ "\n",
+ " self.from_language = tk.StringVar()\n",
+ " \n",
+ " from_combo = ttk.Combobox(\n",
+ " lang_frame,\n",
+ " textvariable=self.from_language,\n",
+ " values=list(languages.keys()),\n",
+ " state=\"readonly\",\n",
+ " width=25\n",
+ " )\n",
+ " \n",
+ " from_combo.grid(\n",
+ " row=1,\n",
+ " column=0,\n",
+ " padx=10,\n",
+ " pady=5\n",
+ " )\n",
+ "\n",
+ " from_combo.set(\"English\")\n",
+ " \n",
+ " # -------------------------\n",
+ " # TO LANGUAGE\n",
+ " # -------------------------\n",
+ " \n",
+ " ttk.Label(\n",
+ " lang_frame,\n",
+ " text=\"To Language\"\n",
+ " ).grid(\n",
+ " row=0,\n",
+ " column=1,\n",
+ " padx=10,\n",
+ " pady=5,\n",
+ " sticky=\"w\"\n",
+ " )\n",
+ "\n",
+ " self.to_language = tk.StringVar()\n",
+ " \n",
+ " to_combo = ttk.Combobox(\n",
+ " lang_frame,\n",
+ " textvariable=self.to_language,\n",
+ " values=list(languages.keys()),\n",
+ " state=\"readonly\",\n",
+ " width=25\n",
+ " )\n",
+ " \n",
+ " to_combo.grid(\n",
+ " row=1,\n",
+ " column=1,\n",
+ " padx=10,\n",
+ " pady=5\n",
+ " )\n",
+ " \n",
+ " to_combo.set(\"Spanish\")\n",
+ "\n",
+ " # =====================================================\n",
+ " # INPUT TEXT\n",
+ " # =====================================================\n",
+ " \n",
+ " ttk.Label(\n",
+ " frame,\n",
+ " text=\"Input Text\"\n",
+ " ).pack(anchor=\"w\")\n",
+ " \n",
+ " self.input_text = self.styled_text(\n",
+ " frame,\n",
+ " height=6\n",
+ " )\n",
+ " \n",
+ " self.input_text.pack(\n",
+ " fill=\"x\",\n",
+ " pady=5\n",
+ " )\n",
+ "\n",
+ " # =====================================================\n",
+ " # TRANSLATE BUTTON\n",
+ " # =====================================================\n",
+ " \n",
+ " tk.Button(\n",
+ " frame,\n",
+ " text=\"Translate\",\n",
+ " command=self.translate_text,\n",
+ " **self.button_style\n",
+ " ).pack(pady=10)\n",
+ " \n",
+ " # =====================================================\n",
+ " # OUTPUT TEXT\n",
+ " # =====================================================\n",
+ " \n",
+ " ttk.Label(\n",
+ " frame,\n",
+ " text=\"Translated Text\"\n",
+ " ).pack(anchor=\"w\")\n",
+ " \n",
+ " self.output_text = self.styled_text(\n",
+ " frame,\n",
+ " height=6\n",
+ " )\n",
+ " \n",
+ " self.output_text.pack(\n",
+ " fill=\"x\",\n",
+ " pady=5\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # ADD CONDITION\n",
+ " # =========================================================\n",
+ "\n",
+ " def add_condition(self):\n",
+ "\n",
+ " win = tk.Toplevel(self.root)\n",
+ "\n",
+ " win.title(\"Add Condition\")\n",
+ "\n",
+ " self.style_toplevel(win)\n",
+ "\n",
+ " ttk.Label(\n",
+ " win,\n",
+ " text=\"Name\"\n",
+ " ).pack(pady=5)\n",
+ "\n",
+ " name = self.styled_entry(win)\n",
+ "\n",
+ " name.pack(pady=5)\n",
+ "\n",
+ " ttk.Label(\n",
+ " win,\n",
+ " text=\"Status\"\n",
+ " ).pack(pady=5)\n",
+ "\n",
+ " status = self.styled_entry(win)\n",
+ "\n",
+ " status.pack(pady=5)\n",
+ "\n",
+ " def save():\n",
+ "\n",
+ " self.conditions_list.insert(\n",
+ " tk.END,\n",
+ " f\"{name.get()} ({status.get()})\"\n",
+ " )\n",
+ "\n",
+ " win.destroy()\n",
+ "\n",
+ " tk.Button(\n",
+ " win,\n",
+ " text=\"Save\",\n",
+ " command=save,\n",
+ " **self.button_style\n",
+ " ).pack(pady=10)\n",
+ "\n",
+ " # =========================================================\n",
+ " # ADD MEDICATION\n",
+ " # =========================================================\n",
+ "\n",
+ " def add_medication(self):\n",
+ "\n",
+ " win = tk.Toplevel(self.root)\n",
+ "\n",
+ " win.title(\"Add Medication\")\n",
+ "\n",
+ " self.style_toplevel(win)\n",
+ "\n",
+ " ttk.Label(\n",
+ " win,\n",
+ " text=\"Name\"\n",
+ " ).pack(pady=5)\n",
+ "\n",
+ " name = self.styled_entry(win)\n",
+ "\n",
+ " name.pack(pady=5)\n",
+ "\n",
+ " ttk.Label(\n",
+ " win,\n",
+ " text=\"Dosage\"\n",
+ " ).pack(pady=5)\n",
+ "\n",
+ " dosage = self.styled_entry(win)\n",
+ "\n",
+ " dosage.pack(pady=5)\n",
+ "\n",
+ " def save():\n",
+ "\n",
+ " self.medications_list.insert(\n",
+ " tk.END,\n",
+ " f\"{name.get()} - {dosage.get()}\"\n",
+ " )\n",
+ "\n",
+ " win.destroy()\n",
+ "\n",
+ " tk.Button(\n",
+ " win,\n",
+ " text=\"Save\",\n",
+ " command=save,\n",
+ " **self.button_style\n",
+ " ).pack(pady=10)\n",
+ "\n",
+ " # =========================================================\n",
+ " # TRANSLATE\n",
+ " # =========================================================\n",
+ "\n",
+ " def translate_text(self):\n",
+ " \n",
+ " try:\n",
+ " \n",
+ " text = self.input_text.get(\n",
+ " \"1.0\",\n",
+ " tk.END\n",
+ " ).strip()\n",
+ " \n",
+ " if not text:\n",
+ " \n",
+ " messagebox.showwarning(\n",
+ " \"Warning\",\n",
+ " \"Please enter text to translate.\"\n",
+ " )\n",
+ " \n",
+ " return\n",
+ " \n",
+ " # Get selected languages\n",
+ " from_lang_name = self.from_language.get()\n",
+ " to_lang_name = self.to_language.get()\n",
+ " \n",
+ " # Convert names to language codes\n",
+ " source_lang = languages[from_lang_name]\n",
+ " target_lang = languages[to_lang_name]\n",
+ " \n",
+ " # Translate\n",
+ " translated = GoogleTranslator(\n",
+ " source=source_lang,\n",
+ " target=target_lang\n",
+ " ).translate(text)\n",
+ " \n",
+ " self.output_text.delete(\n",
+ " \"1.0\",\n",
+ " tk.END\n",
+ " )\n",
+ " \n",
+ " self.output_text.insert(\n",
+ " tk.END,\n",
+ " translated\n",
+ " )\n",
+ " \n",
+ " except Exception as e:\n",
+ " \n",
+ " messagebox.showerror(\n",
+ " \"Translation Error\",\n",
+ " str(e)\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # VALIDATE\n",
+ " # =========================================================\n",
+ "\n",
+ " def validate(self):\n",
+ "\n",
+ " if not self.fields[\"patient_id\"].get().strip():\n",
+ "\n",
+ " messagebox.showerror(\n",
+ " \"Validation Error\",\n",
+ " \"Patient ID required\"\n",
+ " )\n",
+ "\n",
+ " return False\n",
+ "\n",
+ " return True\n",
+ "\n",
+ " # =========================================================\n",
+ " # SAVE JSON\n",
+ " # =========================================================\n",
+ "\n",
+ " def save_json(self):\n",
+ "\n",
+ " if not self.validate():\n",
+ " return\n",
+ "\n",
+ " data = {\n",
+ " \"patient_id\": self.fields[\"patient_id\"].get(),\n",
+ " \"first_name\": self.fields[\"first_name\"].get(),\n",
+ " \"last_name\": self.fields[\"last_name\"].get(),\n",
+ " \"email\": self.fields[\"email\"].get(),\n",
+ " \"phone\": self.fields[\"phone\"].get(),\n",
+ " \"gender\": self.gender_var.get(),\n",
+ " \"notes\": self.notes_text.get(\"1.0\", tk.END).strip()\n",
+ " }\n",
+ "\n",
+ " path = filedialog.asksaveasfilename(\n",
+ " defaultextension=\".json\",\n",
+ " filetypes=[(\"JSON Files\", \"*.json\")]\n",
+ " )\n",
+ "\n",
+ " if not path:\n",
+ " return\n",
+ "\n",
+ " with open(path, \"w\") as f:\n",
+ "\n",
+ " json.dump(\n",
+ " data,\n",
+ " f,\n",
+ " indent=4\n",
+ " )\n",
+ "\n",
+ " messagebox.showinfo(\n",
+ " \"Saved\",\n",
+ " \"Patient record saved successfully!\"\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # LOAD JSON\n",
+ " # =========================================================\n",
+ "\n",
+ " def load_json(self):\n",
+ "\n",
+ " path = filedialog.askopenfilename(\n",
+ " filetypes=[(\"JSON Files\", \"*.json\")]\n",
+ " )\n",
+ "\n",
+ " if not path:\n",
+ " return\n",
+ "\n",
+ " with open(path) as f:\n",
+ "\n",
+ " data = json.load(f)\n",
+ "\n",
+ " self.fields[\"patient_id\"].delete(0, tk.END)\n",
+ " self.fields[\"patient_id\"].insert(0, data.get(\"patient_id\", \"\"))\n",
+ "\n",
+ " self.fields[\"first_name\"].delete(0, tk.END)\n",
+ " self.fields[\"first_name\"].insert(0, data.get(\"first_name\", \"\"))\n",
+ "\n",
+ " self.fields[\"last_name\"].delete(0, tk.END)\n",
+ " self.fields[\"last_name\"].insert(0, data.get(\"last_name\", \"\"))\n",
+ "\n",
+ " self.fields[\"email\"].delete(0, tk.END)\n",
+ " self.fields[\"email\"].insert(0, data.get(\"email\", \"\"))\n",
+ "\n",
+ " self.fields[\"phone\"].delete(0, tk.END)\n",
+ " self.fields[\"phone\"].insert(0, data.get(\"phone\", \"\"))\n",
+ "\n",
+ " self.gender_var.set(\n",
+ " data.get(\"gender\", \"Male\")\n",
+ " )\n",
+ "\n",
+ " self.notes_text.delete(\n",
+ " \"1.0\",\n",
+ " tk.END\n",
+ " )\n",
+ "\n",
+ " self.notes_text.insert(\n",
+ " tk.END,\n",
+ " data.get(\"notes\", \"\")\n",
+ " )\n",
+ "\n",
+ " messagebox.showinfo(\n",
+ " \"Loaded\",\n",
+ " \"Patient record loaded successfully!\"\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # GENERATE PDF\n",
+ " # =========================================================\n",
+ "\n",
+ " def generate_pdf(self):\n",
+ "\n",
+ " try:\n",
+ "\n",
+ " path = filedialog.asksaveasfilename(\n",
+ " defaultextension=\".pdf\",\n",
+ " filetypes=[(\"PDF Files\", \"*.pdf\")]\n",
+ " )\n",
+ "\n",
+ " if not path:\n",
+ " return\n",
+ "\n",
+ " doc = SimpleDocTemplate(\n",
+ " path,\n",
+ " pagesize=letter\n",
+ " )\n",
+ "\n",
+ " styles = getSampleStyleSheet()\n",
+ "\n",
+ " elements = []\n",
+ "\n",
+ " title = Paragraph(\n",
+ " \"Electronic Medical Record\",\n",
+ " styles[\"Title\"]\n",
+ " )\n",
+ "\n",
+ " elements.append(title)\n",
+ "\n",
+ " elements.append(\n",
+ " Spacer(1, 20)\n",
+ " )\n",
+ "\n",
+ " patient_info = f\"\"\"\n",
+ " Patient ID: {self.fields['patient_id'].get()}
\n",
+ " First Name: {self.fields['first_name'].get()}
\n",
+ " Last Name: {self.fields['last_name'].get()}
\n",
+ " Email: {self.fields['email'].get()}
\n",
+ " Phone: {self.fields['phone'].get()}
\n",
+ " \"\"\"\n",
+ "\n",
+ " elements.append(\n",
+ " Paragraph(\n",
+ " patient_info,\n",
+ " styles[\"BodyText\"]\n",
+ " )\n",
+ " )\n",
+ "\n",
+ " notes = self.notes_text.get(\n",
+ " \"1.0\",\n",
+ " tk.END\n",
+ " ).strip()\n",
+ "\n",
+ " elements.append(\n",
+ " Spacer(1, 20)\n",
+ " )\n",
+ "\n",
+ " elements.append(\n",
+ " Paragraph(\n",
+ " \"Nursing Notes\",\n",
+ " styles[\"Heading2\"]\n",
+ " )\n",
+ " )\n",
+ "\n",
+ " elements.append(\n",
+ " Paragraph(\n",
+ " notes,\n",
+ " styles[\"BodyText\"]\n",
+ " )\n",
+ " )\n",
+ "\n",
+ " doc.build(elements)\n",
+ "\n",
+ " messagebox.showinfo(\n",
+ " \"Success\",\n",
+ " \"PDF generated successfully!\"\n",
+ " )\n",
+ "\n",
+ " except Exception as e:\n",
+ "\n",
+ " messagebox.showerror(\n",
+ " \"PDF Error\",\n",
+ " str(e)\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # SPEECH To TEXT\n",
+ " # =========================================================\n",
+ "\n",
+ " def speech_to_text(self):\n",
+ " # Load the Vosk model\n",
+ " model_path = r\"C:\\Users\\graem\\Downloads\\vosk-model-small-en-us-0.15\\vosk-model-small-en-us-0.15\"\n",
+ " model = Model(model_path)\n",
+ " \n",
+ " # Open recorded audio\n",
+ " wf = wave.open(\"recorded.wav\", \"rb\")\n",
+ " \n",
+ " # Initialize recognizer\n",
+ " rec = KaldiRecognizer(model, wf.getframerate())\n",
+ " \n",
+ " transcription = \"\"\n",
+ " \n",
+ " # Transcribe\n",
+ " while True:\n",
+ " data = wf.readframes(4000)\n",
+ " \n",
+ " if len(data) == 0:\n",
+ " break\n",
+ " \n",
+ " if rec.AcceptWaveform(data):\n",
+ " result = json.loads(rec.Result())\n",
+ " transcription += result.get(\"text\", \"\") + \" \"\n",
+ " \n",
+ " # Final result\n",
+ " result = json.loads(rec.FinalResult())\n",
+ " transcription += result.get(\"text\", \"\")\n",
+ "\n",
+ " corrected = TextBlob(transcription)\n",
+ "\n",
+ " print(corrected)\n",
+ " \n",
+ " #text_notes.insert(tk.END, transcription)\n",
+ " self.notes_text.insert(tk.END, corrected)\n",
+ " \n",
+ " return corrected\n",
+ " \n",
+ " \n",
+ " # =========================================================\n",
+ " # SPEECH THREAD\n",
+ " # =========================================================\n",
+ "\n",
+ " def audio_thread(self):\n",
+ "\n",
+ " global listening, audio_frames\n",
+ "\n",
+ " rec = KaldiRecognizer(\n",
+ " model,\n",
+ " 16000\n",
+ " )\n",
+ "\n",
+ " audio_frames = []\n",
+ "\n",
+ " def callback(indata, frames, time, status):\n",
+ "\n",
+ " if listening:\n",
+ "\n",
+ " data = bytes(indata)\n",
+ "\n",
+ " audio_frames.append(data)\n",
+ "\n",
+ " if rec.AcceptWaveform(data):\n",
+ "\n",
+ " result = json.loads(\n",
+ " rec.Result()\n",
+ " )\n",
+ "\n",
+ " q.put(\n",
+ " result.get(\"text\", \"\")\n",
+ " )\n",
+ "\n",
+ " with sd.RawInputStream(\n",
+ " samplerate=16000,\n",
+ " blocksize=8000,\n",
+ " dtype='int16',\n",
+ " channels=1,\n",
+ " callback=callback\n",
+ " ):\n",
+ "\n",
+ " while listening:\n",
+ " sd.sleep(100)\n",
+ "\n",
+ " # =========================================================\n",
+ " # UPDATE TEXTBOX\n",
+ " # =========================================================\n",
+ "\n",
+ " def update_textbox(self):\n",
+ "\n",
+ " try:\n",
+ "\n",
+ " while True:\n",
+ "\n",
+ " text = q.get_nowait()\n",
+ "\n",
+ " self.notes_text.insert(\n",
+ " tk.END,\n",
+ " text + \"\\n\"\n",
+ " )\n",
+ "\n",
+ " self.notes_text.see(tk.END)\n",
+ "\n",
+ " except queue.Empty:\n",
+ " pass\n",
+ "\n",
+ " self.root.after(\n",
+ " 100,\n",
+ " self.update_textbox\n",
+ " )\n",
+ "\n",
+ " # =========================================================\n",
+ " # SAVE WAV\n",
+ " # =========================================================\n",
+ "\n",
+ " def save_wav(self, filename=\"recorded.wav\"):\n",
+ "\n",
+ " wf = wave.open(\n",
+ " filename,\n",
+ " 'wb'\n",
+ " )\n",
+ "\n",
+ " wf.setnchannels(1)\n",
+ " wf.setsampwidth(2)\n",
+ " wf.setframerate(16000)\n",
+ "\n",
+ " wf.writeframes(\n",
+ " b''.join(audio_frames)\n",
+ " )\n",
+ "\n",
+ " wf.close()\n",
+ "\n",
+ " # =========================================================\n",
+ " # START LISTENING\n",
+ " # =========================================================\n",
+ "\n",
+ " def start_listening(self):\n",
+ "\n",
+ " global listening\n",
+ "\n",
+ " listening = True\n",
+ "\n",
+ " print(\"Listening...\")\n",
+ "\n",
+ " threading.Thread(\n",
+ " target=self.audio_thread,\n",
+ " daemon=True\n",
+ " ).start()\n",
+ "\n",
+ " # =========================================================\n",
+ " # STOP LISTENING\n",
+ " # =========================================================\n",
+ "\n",
+ " def stop_listening(self):\n",
+ "\n",
+ " global listening\n",
+ "\n",
+ " listening = False\n",
+ "\n",
+ " self.save_wav()\n",
+ "\n",
+ " print(\"Saved to recorded.wav\")\n",
+ "\n",
+ " messagebox.showinfo(\n",
+ " \"Recording\",\n",
+ " \"Speech recording stopped.\"\n",
+ " )\n",
+ "\n",
+ " self.speech_to_text()\n",
+ "\n",
+ " \n",
+ "# =========================================================\n",
+ "# MAIN\n",
+ "# =========================================================\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ "\n",
+ " root = tk.Tk()\n",
+ "\n",
+ " app = MedicalApp(root)\n",
+ "\n",
+ " root.mainloop()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "898e2732-b4d9-4346-88a4-eef13b58ed9a",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python [conda env:base] *",
+ "language": "python",
+ "name": "conda-base-py"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}