Spaces:
Paused
Paused
| import streamlit as st | |
| import pandas as pd | |
| from sklearn.preprocessing import LabelEncoder | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
| import torch | |
| import math | |
| import urllib.parse | |
| import json | |
| import re | |
| import json | |
| from datetime import datetime | |
| import gspread | |
| from oauth2client.service_account import ServiceAccountCredentials | |
| # Load data and model (ปรับ path ตามที่คุณเก็บไฟล์ไว้ใน Colab) | |
| def load_data_and_model(): | |
| try: | |
| data = pd.read_excel('ortho_traige_gen_symptom_expanded.xlsx') | |
| except FileNotFoundError: | |
| st.error("ไม่พบไฟล์ Excel กรุณาตรวจสอบว่าได้อัปโหลดไฟล์แล้ว") | |
| return None, None, None, None | |
| label_encoder = LabelEncoder() | |
| data['clinic'] = label_encoder.fit_transform(data['clinic']) | |
| model_save_path = 'finetune_saved_model' | |
| try: | |
| loaded_model = AutoModelForSequenceClassification.from_pretrained(model_save_path) | |
| loaded_tokenizer = AutoTokenizer.from_pretrained(model_save_path) | |
| except Exception as e: | |
| st.error(f"เกิดข้อผิดพลาดในการโหลดโมเดล: {str(e)}") | |
| return None, None, None, None | |
| return data, label_encoder, loaded_model, loaded_tokenizer | |
| data, label_encoder, loaded_model, loaded_tokenizer = load_data_and_model() | |
| # Clinic to doctor mapping | |
| clinic_doctor_mapping = { | |
| 'spine': ['จักรพล', 'วรายศ'], | |
| 'hand': ['อรอรุณ', 'เติมพงศ์'], | |
| 'sport': ['สิทธานต์', 'วสพล'], | |
| 'foot': ['ทินนาถ'], | |
| 'oncology': ['ธนพล', 'พิชยา'], | |
| 'osteoporosis': ['รัฐภูมิ'], | |
| 'arthroplasty': ['อรรถพร', 'ณัฐวุฒิ'] | |
| } | |
| # Time slots mapping | |
| doctor_time_slots = { | |
| 'รัฐภูมิ': ["วันพุธ: 9.00 - 16.00", "วันศุกร์: 9.00 - 12.00", "วันพฤหัสบดี: 16.00"], | |
| 'ทินนาถ': ["วันจันทร์: 9.00 - 12.00", "วันอังคาร: 9.00 - 16.00", "วันพุธ: 16.00", "วันอาทิตย์: 9.00 - 12.00"], | |
| 'สิทธานต์': ["วันจันทร์: 9.00 - 16.00", "วันพุธ: 9.00 - 12.00", "วันอังคาร: 16.00", "วันเสาร์: 9.00 - 12.00"], | |
| 'วสพล': ["วันพุธ: 13.00 - 16.00", "วันศุกร์: 9.00 - 16.00", "วันศุกร์: 16.00", "วันอาทิตย์: 9.00 - 12.00"], | |
| 'อรอรุณ': ["วันจันทร์: 13.00 - 16.00", "วันพุธ: 9.00 - 16.00", "วันอังคาร: 16.00", "วันเสาร์: 9.00 - 12.00"], | |
| 'เติมพงศ์': ["วันจันทร์: 9.00 - 16.00", "วันอังคาร: 9.00 - 12.00", "วันพฤหัสบดี: 16.00", "วันศุกร์: 16.00"], | |
| 'อรรถพร': ["วันจันทร์: 9.00 - 16.00", "วันอังคาร: 13.00 - 16.00", "วันอาทิตย์: 9.00 - 12.00"], | |
| 'ณัฐวุฒิ': ["วันอังคาร: 9.00 - 16.00", "วันศุกร์: 9.00 - 12.00", "วันพุธ: 16.00", "วันเสาร์: 9.00 - 12.00"], | |
| 'ธนพล': ["วันพุธ: 9.00 - 16.00", "วันจันทร์: 16.00"], | |
| 'พิชยา': ["วันอังคาร: 9.00 - 16.00", "วันพฤหัสบดี: 13.00 - 16.00", "วันอังคาร: 16.00", "วันพฤหัสบดี: 16.00", "วันเสาร์: 13.00 - 16.00"], | |
| 'จักรพล': ["วันพุธ: 13.00 - 16.00", "วันศุกร์: 9.00 - 16.00", "วันจันทร์: 16.00", "วันอาทิตย์: 9.00 - 12.00"], | |
| 'วรายศ': ["วันพฤหัสบดี: 13.00 - 16.00", "วันศุกร์: 9.00 - 16.00", "วันพฤหัสบดี: 16.00", "วันศุกร์: 16.00"] | |
| } | |
| clinic_name_to_key_mapping = { | |
| 'คลินิกกระดูกสันหลัง': 'spine', | |
| 'คลินิกมือและจุลศัลยกรรม': 'hand', | |
| 'คลินิกเวชศาสตร์การกีฬา และการส่องกล้องหัวไหล่': 'sport', | |
| 'คลินิกเท้าและข้อเท้า': 'foot', | |
| 'คลินิกมะเร็งกระดูกและเนื้อเยื่อ': 'oncology', | |
| 'คลินิกโรคกระดูกพรุนและกระดูกหัก': 'osteoporosis', | |
| 'คลินิกข้อเข่าและข้อสะโพกเทียม': 'arthroplasty' | |
| } | |
| def predict_clinic(age, symptom): | |
| try: | |
| loaded_model.eval() | |
| inputs = loaded_tokenizer(symptom, return_tensors="pt", truncation=True, padding=True, max_length=128) | |
| with torch.no_grad(): | |
| outputs = loaded_model(**inputs) | |
| probabilities = torch.nn.functional.softmax(outputs.logits, dim=1) | |
| predicted_class = torch.argmax(probabilities, dim=1).item() | |
| predicted_label = label_encoder.inverse_transform([predicted_class])[0] | |
| probability = probabilities[0][predicted_class].item() | |
| clinic_mapping = { | |
| 'spine': 'คลินิกกระดูกสันหลัง', | |
| 'hand': 'คลินิกมือและจุลศัลยกรรม', | |
| 'sport': 'คลินิกเวชศาสตร์การกีฬา และการส่องกล้องหัวไหล่', | |
| 'foot': 'คลินิกเท้าและข้อเท้า', | |
| 'oncology': 'คลินิกมะเร็งกระดูกและเนื้อเยื่อ', | |
| 'osteoporosis': 'คลินิกโรคกระดูกพรุนและกระดูกหัก', | |
| 'arthroplasty': 'คลินิกข้อเข่าและข้อสะโพกเทียม' | |
| } | |
| if predicted_label == 'knee': | |
| if age < 50: | |
| predicted_label = 'sport' | |
| else: | |
| predicted_label = 'arthroplasty' | |
| clinic_name = clinic_mapping.get(predicted_label, None) | |
| clinic_key = clinic_name_to_key_mapping.get(clinic_name, None) | |
| if probability < 0.90 or clinic_name is None or clinic_key is None: | |
| return "ไม่พบคลินิกเฉพาะทางที่ท่านค้นหา กรุณาระบุอาการใหม่อีกครั้ง", None, None | |
| else: | |
| return f"ท่านควรเข้ารับการตรวจที่ {clinic_name}", clinic_name, clinic_key | |
| except Exception as e: | |
| st.error(f"เกิดข้อผิดพลาดในการทำนายคลินิก: {str(e)}") | |
| return "เกิดข้อผิดพลาดในการทำนายคลินิก กรุณาลองใหม่อีกครั้ง", None, None | |
| def get_doctor_images(clinic_key): | |
| try: | |
| base_path = "รูปหมอออโถ/" | |
| doctor_images = {} | |
| for doctor in clinic_doctor_mapping[clinic_key]: | |
| image_path = f"{base_path}{doctor}.png" | |
| doctor_images[doctor] = image_path | |
| return doctor_images | |
| except Exception as e: | |
| st.error(f"เกิดข้อผิดพลาดในการโหลดรูปภาพแพทย์: {str(e)}") | |
| return {} | |
| def create_line_deep_link(message, line_id): | |
| try: | |
| encoded_message = urllib.parse.quote(message) | |
| return f"https://line.me/R/oaMessage/{line_id}/?{encoded_message}" | |
| except Exception as e: | |
| st.error(f"เกิดข้อผิดพลาดในการสร้าง LINE Deep Link: {str(e)}") | |
| return None | |
| def save_appointment(appointment_data): | |
| try: | |
| with open('appointments.json', 'a') as f: | |
| json.dump(appointment_data, f) | |
| f.write('\n') | |
| st.success("บันทึกข้อมูลการนัดหมายเรียบร้อยแล้ว") | |
| except Exception as e: | |
| st.error(f"เกิดข้อผิดพลาดในการบันทึกข้อมูลการนัดหมาย: {str(e)}") | |
| def validate_hn(hn): | |
| if not hn.isdigit(): | |
| return False | |
| if len(hn) != 9: | |
| return False | |
| if hn[0] not in ['5', '6']: | |
| return False | |
| return True | |
| def reset_session_state(): | |
| # รายการ keys ที่ต้องการเก็บไว้ | |
| keys_to_keep = ['step', 'age'] | |
| # สร้าง dict ใหม่ที่มีเฉพาะ keys ที่ต้องการเก็บไว้ | |
| new_state = {key: st.session_state[key] for key in keys_to_keep if key in st.session_state} | |
| # ล้าง session state ทั้งหมด | |
| st.session_state.clear() | |
| # เพิ่ม keys ที่ต้องการเก็บไว้กลับเข้าไป | |
| st.session_state.update(new_state) | |
| # กำหนดค่าเริ่มต้นใหม่ | |
| st.session_state.step = 1 | |
| st.session_state.age = 30 | |
| st.session_state.symptom = "" | |
| st.session_state.clinic_result = None | |
| st.session_state.clinic_name = None | |
| st.session_state.clinic_key = None | |
| st.session_state.doctor_images = None | |
| st.session_state.name = "" | |
| st.session_state.has_hn = True | |
| st.session_state.hn = "" | |
| st.session_state.selected_doctor = None | |
| st.session_state.selected_slot = None | |
| st.session_state.appointment_confirmed = False | |
| st.session_state.appointment_saved = False | |
| def on_hn_change(): | |
| # ตรวจสอบว่า 'hn_input' มีอยู่ใน session state ก่อนที่จะใช้ | |
| if 'hn_input' in st.session_state: | |
| st.session_state.hn = st.session_state.hn_input | |
| # เพิ่มฟังก์ชันนี้ที่ด้านบนของไฟล์ของคุณ | |
| def load_feedback(): | |
| try: | |
| with open('user_feedback.json', 'r') as f: | |
| return [json.loads(line) for line in f] | |
| except FileNotFoundError: | |
| return [] | |
| # เพิ่มฟังก์ชันนี้สำหรับบันทึกข้อเสนอแนะพร้อมเวลา | |
| def save_feedback_with_timestamp(feedback): | |
| try: | |
| timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| with open('user_feedback.json', 'a') as f: | |
| json.dump({"feedback": feedback, "timestamp": timestamp}, f) | |
| f.write('\n') | |
| st.success("ขอบคุณสำหรับข้อเสนอแนะของท่าน") | |
| except Exception as e: | |
| st.error(f"เกิดข้อผิดพลาดในการบันทึกข้อเสนอแนะ: {str(e)}") | |
| # ฟังก์ชันสำหรับเชื่อมต่อกับ Google Sheets | |
| def connect_to_sheets(): | |
| scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive'] | |
| creds = ServiceAccountCredentials.from_json_keyfile_name('carbide-calling-435015-v0-039bd8f32a3c.json', scope) | |
| client = gspread.authorize(creds) | |
| return client | |
| # อัพเดทฟังก์ชันสำหรับบันทึกข้อเสนอแนะ | |
| def save_feedback_to_sheet(feedback): | |
| client = connect_to_sheets() | |
| sheet = client.open_by_key('1ge4z5UWXR9QJGHHIdJCwaidbbN62sxtaM8WbiliwNhY').sheet1 | |
| timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| sheet.append_row([timestamp, feedback]) | |
| st.success("ขอบคุณสำหรับข้อเสนอแนะของท่าน") | |
| # อัพเดทฟังก์ชันสำหรับบันทึกข้อมูลการนัดหมาย | |
| def save_appointment_to_sheet(appointment_data): | |
| if not st.session_state.appointment_saved: | |
| client = connect_to_sheets() | |
| sheet = client.open_by_key('1AcYyG43ZjPXa-xn_ztXFW9TNwFUjiopdFiaIO-h3um0').sheet1 | |
| row = [ | |
| appointment_data['name'], | |
| appointment_data['hn'], | |
| appointment_data['age'], | |
| appointment_data['symptom'], | |
| appointment_data['clinic'], | |
| appointment_data['doctor'], | |
| appointment_data['preferred_time_slot'], | |
| "ใดก็ได้" if appointment_data['doctor'] == "แพทย์ท่านใดก็ได้" else "เฉพาะเจาะจง", | |
| datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| ] | |
| sheet.append_row(row) | |
| st.session_state.appointment_saved = True | |
| st.success("บันทึกข้อมูลการนัดหมายเรียบร้อยแล้ว") | |
| else: | |
| st.info("ข้อมูลการนัดหมายได้ถูกบันทึกแล้ว") | |
| def main(): | |
| st.sidebar.title("เมนู") | |
| page = st.sidebar.radio("เลือกหน้า", ["หน้าหลัก", "Admin"]) | |
| if page == "หน้าหลัก": | |
| main_page() | |
| elif page == "Admin": | |
| admin_page() | |
| def main_page(): | |
| st.title("AI ออร์โธปิดิกส์อัจฉริยะ") | |
| st.subheader("จากอาการสู่คลินิก แพทย์ และการนัดหมาย") | |
| st.markdown(""" | |
| ยินดีต้อนรับสู่ระบบ AI ออร์โธปิดิกส์อัจฉริยะ! | |
| เพียงแค่คุณบอกอาการ ระบบของเราจะ: | |
| 1. 🏥 แนะนำคลินิกที่เหมาะสมที่สุดสำหรับคุณ | |
| 2. 👨⚕️ เสนอรายชื่อแพทย์ผู้เชี่ยวชาญ | |
| 3. 📅 ช่วยคุณนัดหมายได้อย่างสะดวกและรวดเร็ว | |
| เริ่มต้นใช้งานได้ทันทีด้านล่างนี้! | |
| """) | |
| # Initialize session state | |
| if 'step' not in st.session_state: | |
| st.session_state.step = 1 | |
| if 'age' not in st.session_state: | |
| st.session_state.age = 30 | |
| if 'symptom' not in st.session_state: | |
| st.session_state.symptom = "" | |
| if 'clinic_result' not in st.session_state: | |
| st.session_state.clinic_result = None | |
| if 'clinic_name' not in st.session_state: | |
| st.session_state.clinic_name = None | |
| if 'clinic_key' not in st.session_state: | |
| st.session_state.clinic_key = None | |
| if 'doctor_images' not in st.session_state: | |
| st.session_state.doctor_images = None | |
| if 'name' not in st.session_state: | |
| st.session_state.name = "" | |
| if 'hn' not in st.session_state: | |
| st.session_state.hn = "" | |
| if 'has_hn' not in st.session_state: | |
| st.session_state.has_hn = True | |
| if 'selected_doctor' not in st.session_state: | |
| st.session_state.selected_doctor = None | |
| if 'selected_slot' not in st.session_state: | |
| st.session_state.selected_slot = None | |
| if 'appointment_confirmed' not in st.session_state: | |
| st.session_state.appointment_confirmed = False | |
| if 'appointment_saved' not in st.session_state: | |
| st.session_state.appointment_saved = False | |
| # Initialize session state | |
| if 'hn_valid' not in st.session_state: | |
| st.session_state.hn_valid = False | |
| if st.session_state.step == 1: | |
| st.session_state.name = st.text_input("ชื่อผู้ป่วย", value=st.session_state.get('name', '')) | |
| st.session_state.has_hn = st.checkbox("มีเลข HN (เลขประจำตัวผู้ป่วยของโรงพยาบาลจุฬาภรณ์)", value=st.session_state.get('has_hn', True)) | |
| if st.session_state.has_hn: | |
| hn_input = st.text_input( | |
| "เลข HN (9 หลัก)", | |
| value=st.session_state.get('hn', ''), | |
| key='hn_input', | |
| on_change=on_hn_change | |
| ) | |
| if hn_input and not validate_hn(hn_input): | |
| st.warning("HN ของท่านน่าจะผิด กรุณากรอกใหม่ หรือถ้าไม่มีให้เลือกว่าไม่มี HN") | |
| st.session_state.hn_valid = False | |
| else: | |
| st.session_state.hn = hn_input | |
| st.session_state.hn_valid = validate_hn(hn_input) | |
| else: | |
| st.warning("ท่านสามารถตรวจสอบอาการและดูข้อมูลแพทย์ได้ แต่จะไม่สามารถทำการนัดหมายผ่านระบบนี้ได้") | |
| st.session_state.hn = "" # เคลียร์ค่า HN เมื่อไม่มี HN | |
| st.session_state.hn_valid = False | |
| st.session_state.age = st.number_input("กรุณาระบุอายุของผู้ป่วย", min_value=0, max_value=120, value=st.session_state.get('age', 30)) | |
| st.session_state.symptom = st.text_area("กรุณาระบุอาการของผู้ป่วย (ภาษาไทยเท่านั้น)", value=st.session_state.get('symptom', '')) | |
| if st.button("ทำนายคลินิก"): | |
| if not st.session_state.name.strip(): | |
| st.warning("กรุณากรอกชื่อผู้ป่วย") | |
| elif not st.session_state.symptom.strip(): | |
| st.warning("กรุณาระบุอาการของผู้ป่วย") | |
| else: | |
| result, clinic_name, clinic_key = predict_clinic(st.session_state.age, st.session_state.symptom) | |
| st.session_state.clinic_result = result | |
| st.session_state.clinic_name = clinic_name | |
| st.session_state.clinic_key = clinic_key | |
| if clinic_key: | |
| st.session_state.doctor_images = get_doctor_images(clinic_key) | |
| st.session_state.step = 2 | |
| if st.session_state.step >= 2: | |
| st.write(f"ผลการทำนาย: {st.session_state.clinic_result}") | |
| if st.session_state.clinic_key: | |
| st.subheader(f"แพทย์ในคลินิก {st.session_state.clinic_name}:") | |
| # แสดงรูปภาพแพทย์ | |
| if st.session_state.doctor_images: | |
| num_doctors = len(st.session_state.doctor_images) | |
| num_rows = math.ceil(num_doctors / 2) | |
| for i in range(0, num_doctors, 2): | |
| col1, col2 = st.columns(2) | |
| doctors = list(st.session_state.doctor_images.items()) | |
| doctor, image_path = doctors[i] | |
| col1.image(image_path, caption=doctor, use_column_width=True) | |
| if i + 1 < num_doctors: | |
| doctor, image_path = doctors[i + 1] | |
| col2.image(image_path, caption=doctor, use_column_width=True) | |
| ## | |
| if st.session_state.hn_valid: | |
| doctor_options = ["-- เลือกชื่อแพทย์ --"] + clinic_doctor_mapping[st.session_state.clinic_key] + ["แพทย์ท่านใดก็ได้"] | |
| st.session_state.selected_doctor = st.selectbox("เลือกแพทย์", options=doctor_options, key='doctor_select') | |
| if st.session_state.selected_doctor and st.session_state.selected_doctor != "-- เลือกชื่อแพทย์ --": | |
| if st.session_state.selected_doctor == "แพทย์ท่านใดก็ได้": | |
| st.subheader("เลือกช่วงเวลาที่สะดวก:") | |
| time_options = ["ในเวลาราชการ", "นอกเวลาราชการ (คิวจะเร็วกว่า เป็นช่วงหลัง 16.00 น. และวันเสาร์-อาทิตย์)"] | |
| st.session_state.selected_slot = st.radio("", options=time_options) | |
| else: | |
| st.subheader(f"เวลาตรวจของ {st.session_state.selected_doctor}:") | |
| time_slots = doctor_time_slots[st.session_state.selected_doctor] | |
| st.session_state.selected_slot = st.selectbox("เลือกเวลาตรวจ", options=["-- เลือกเวลาตรวจ --"] + time_slots, key='time_slot_select') | |
| if st.session_state.selected_doctor == "แพทย์ท่านใดก็ได้": | |
| st.info("หมายเหตุ: การตรวจนอกเวลาราชการ (หลัง 16.00 น.) รวมทั้งวันหยุดเสาร์-อาทิตย์ จะมีค่าใช้จ่ายเพิ่มเติมในการตรวจ") | |
| else: | |
| st.info("หมายเหตุ: การตรวจนอกเวลาราชการ (หลัง 16.00 น.) รวมทั้งวันหยุดเสาร์-อาทิตย์ จะมีค่าใช้จ่ายเพิ่มเติมในการตรวจ") | |
| if ((st.session_state.selected_doctor == "แพทย์ท่านใดก็ได้" and st.session_state.selected_slot) or | |
| (st.session_state.selected_doctor != "แพทย์ท่านใดก็ได้" and st.session_state.selected_slot != "-- เลือกเวลาตรวจ --")): | |
| if st.button("สรุปข้อมูลที่ท่านจะทำนัด"): | |
| st.session_state.appointment_confirmed = True | |
| ## | |
| else: | |
| st.warning("แนะนำให้เปิดเลข HN กับโรงพยาบาลจุฬาภรณ์ก่อน และกลับมาทำนัดทางระบบอีกครั้ง") | |
| st.info("หากท่านต้องการข้อมูลเพิ่มเติมเกี่ยวกับการเปิด HN กรุณาติดต่อ 02-576-6000") | |
| # ส่วนที่เพิ่มใหม่สำหรับการสร้าง LINE Deep Link | |
| if st.session_state.get('appointment_confirmed') and st.session_state.hn_valid: | |
| summary = f"นัดหมาย: คนไข้ {st.session_state.name} อายุ {st.session_state.age} ปี\n" | |
| summary += f"HN: {st.session_state.hn}\n" | |
| summary += f"อาการ: {st.session_state.symptom}\n" | |
| summary += f"คลินิก: {st.session_state.clinic_name}\n" | |
| summary += f"แพทย์: {st.session_state.selected_doctor}\n" | |
| summary += f"เวลาที่ต้องการ: {st.session_state.selected_slot}" | |
| line_id = "@987vwxrs" # LINE ID ของแผนก | |
| deep_link = create_line_deep_link(summary, line_id) | |
| st.success("ข้อมูลการขอนัดหมายของท่านได้ถูกบันทึกแล้ว") | |
| st.warning(""" | |
| โปรดทราบ: การนัดหมายจะสมบูรณ์ต่อเมื่อท่านดำเนินการดังนี้ | |
| 1. ส่งข้อความหาเจ้าหน้าที่ผ่านทาง LINE Official Account | |
| 2. รอการตอบกลับจากเจ้าหน้าที่เพื่อยืนยันวันและเวลานัดที่แน่นอน | |
| เจ้าหน้าที่จะตรวจสอบคิวนัดของแพทย์และเลือกวันนัดที่เร็วที่สุดให้ท่าน | |
| โดยอาจใช้เวลาระหว่าง 1-3 เดือน ขึ้นอยู่กับความพร้อมของแพทย์แต่ละท่าน | |
| """) | |
| if deep_link: | |
| st.markdown(f"<a href='{deep_link}' target='_blank'><button style='padding: 15px 32px; font-size: 20px; margin: 4px 2px; cursor: pointer;'>คลิกที่นี่เพื่อส่งข้อมูลการขอนัดไปยัง LINE Official Account</button></a>", unsafe_allow_html=True) | |
| st.info("คำแนะนำ: กดปุ่มด้านบนเพื่อเปิด LINE และส่งข้อมูลการขอนัดโดยอัตโนมัติ หากปุ่มไม่ทำงาน ให้คัดลอกข้อความด้านล่างและส่งไปยัง LINE @987vwxrs ด้วยตนเอง") | |
| st.text_area("ข้อความสรุปการขอนัด (สามารถคัดลอกได้):", value=summary, height=200) | |
| # บันทึกข้อมูลการนัดหมาย | |
| appointment_data = { | |
| "name": st.session_state.name, | |
| "hn": st.session_state.hn, | |
| "age": st.session_state.age, | |
| "symptom": st.session_state.symptom, | |
| "clinic": st.session_state.clinic_name, | |
| "doctor": st.session_state.selected_doctor, | |
| "preferred_time_slot": st.session_state.selected_slot | |
| } | |
| save_appointment_to_sheet(appointment_data) | |
| if st.button("เริ่มใหม่"): | |
| reset_session_state() | |
| st.rerun() | |
| # แก้ไขส่วนการรับข้อเสนอแนะเป็น: | |
| st.subheader("ข้อเสนอแนะ") | |
| user_feedback = st.text_area("กรุณาแสดงความคิดเห็นหรือข้อเสนอแนะของท่าน:") | |
| if st.button("ส่งข้อเสนอแนะ"): | |
| if user_feedback.strip(): | |
| save_feedback_to_sheet(user_feedback) | |
| else: | |
| st.warning("กรุณากรอกข้อเสนอแนะก่อนกดส่ง") | |
| def on_hn_change(): | |
| if 'hn_input' in st.session_state: | |
| st.session_state.hn = st.session_state.hn_input | |
| st.session_state.hn_valid = validate_hn(st.session_state.hn) | |
| def admin_page(): | |
| st.title("หน้า Admin - AI ออร์โธปิดิกส์อัจฉริยะ") | |
| st.subheader("จัดการระบบแนะนำและนัดหมายอัตโนมัติ") | |
| # รหัสผ่านอย่างง่าย (ในการใช้งานจริงควรใช้วิธีที่ปลอดภัยกว่านี้) | |
| password = st.text_input("กรุณาใส่รหัสผ่าน", type="password") | |
| if password != "admin123": # เปลี่ยนรหัสผ่านนี้เป็นรหัสที่ปลอดภัยกว่า | |
| st.warning("รหัสผ่านไม่ถูกต้อง") | |
| return | |
| st.subheader("ข้อเสนอแนะทั้งหมด") | |
| feedback_data = load_feedback() | |
| for item in feedback_data: | |
| st.text(f"เวลา: {item.get('timestamp', 'ไม่ระบุ')}") | |
| st.text(f"ข้อเสนอแนะ: {item['feedback']}") | |
| st.markdown("---") | |
| if __name__ == "__main__": | |
| main() |