DavidNgoue commited on
Commit
95d52a8
·
verified ·
1 Parent(s): 2798063

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +105 -134
src/streamlit_app.py CHANGED
@@ -481,10 +481,10 @@ if page == t("home"):
481
  <div class='intro animate__fadeIn'>
482
  <p>{t('home_intro_1').format(author="<b>Ngoue David Roger Yannick</b>")}</p>
483
  <p>{t('home_intro_2')}</p>
484
- </div>
485
  """, unsafe_allow_html=True)
486
 
487
- st.markdown(f"<div class='section-header section__fadeIn'>{t('why_omics')}</div>", unsafe_allow_html=True)
488
  st.markdown(f"""
489
  <div class='content animate__fadeIn'>
490
  <p>{t('omics_description')}</p>
@@ -494,8 +494,8 @@ if page == t("home"):
494
  <li><b>{t('proteomics')}</b>: {t('proteomics_desc')}</li>
495
  <li><b>{t('metabolomics')}</b>: {t('metabolomics_desc')}</li>
496
  </ul>
497
- </div>
498
  <p>{t('omics_integration')}</p>
 
499
  """, unsafe_allow_html=True)
500
 
501
  # About Omics Data Page
@@ -517,13 +517,13 @@ elif page == t("about_omics"):
517
  <li><b>{t('proteomics')}</b>: {t('proteomics_format')}</li>
518
  <li><b>{t('metabolomics')}</b>: {t('metabolomics_format')}</li>
519
  </ul>
520
- </div>
521
  <p>{t('raw_omics_processing')}</p>
 
522
  """, unsafe_allow_html=True)
523
 
524
- st.markdown(f"<div class='section-header'}>{t('preprocessing_steps')}</div>", unsafe_allow_html=True)
525
  st.markdown(f"""
526
- <div class='content animate__fadeIn'}>
527
  <p>{t('preprocessing_desc')}</p>
528
  <ol>
529
  <li><b>{t('quality_control')}</b>: {t('quality_control_desc')}</li>
@@ -532,8 +532,8 @@ elif page == t("about_omics"):
532
  <li><b>{t('standardization')}</b>: {t('standardization_desc')}</li>
533
  <li><b>{t('feature_selection')}</b>: {t('feature_selection_desc')}</li>
534
  </ol>
535
- </div>
536
  <p>{t('preprocessing_importance')}</p>
 
537
  """, unsafe_allow_html=True)
538
 
539
  st.markdown(f"<div class='section-header'>{t('csv_format')}</div>", unsafe_allow_html=True)
@@ -547,7 +547,6 @@ elif page == t("about_omics"):
547
  <li><b>{t('separator')}</b>: {t('separator_desc')}</li>
548
  <li><b>{t('header')}</b>: {t('header_desc')}</li>
549
  </ul>
550
- </div>
551
  <p>{t('csv_example')}</p>
552
  <pre class='code-block'>
553
  PatientID,UMOD_rs12917707,APOL1_rs73885319,MYH9_rs4821480,Status
@@ -559,7 +558,7 @@ P001,0,1,0,Unknown
559
 
560
  st.markdown(f"<div class='section-header'>{t('data_quality')}</div>", unsafe_allow_html=True)
561
  st.markdown(f"""
562
- <div class='content animate__fadeIn'}>
563
  <p>{t('data_quality_desc')}</p>
564
  <ul>
565
  <li><b>{t('consistency')}</b>: {t('consistency_desc')}</li>
@@ -567,8 +566,8 @@ P001,0,1,0,Unknown
567
  <li><b>{t('accuracy')}</b>: {t('accuracy_desc')}</li>
568
  <li><b>{t('alignment')}</b>: {t('alignment_desc')}</li>
569
  </ul>
570
- </div>
571
  <p>{t('data_quality_importance')}</p>
 
572
  """, unsafe_allow_html=True)
573
 
574
  # Predict Risk Page
@@ -599,6 +598,7 @@ elif page == t("predict_risk"):
599
  with cols[idx]:
600
  uploaded_file = st.file_uploader(f"{t(omic)} (CSV)", type=["csv"], key=omic)
601
  if uploaded_file:
 
602
  temp_path = os.path.join("data", f"temp_{omic}.csv")
603
  with open(temp_path, "wb") as f:
604
  f.write(uploaded_file.getbuffer())
@@ -620,71 +620,50 @@ elif page == t("predict_risk"):
620
  patient_tensors = [torch.tensor(data_dict[omic].values, dtype=torch.float32) for omic in data_dict]
621
  patient_dataset = TensorDataset(*patient_tensors)
622
  patient_loader = DataLoader(patient_dataset, batch_size=best_hyperparams['batch_size'],
623
- shuffle=False)
624
 
625
  # Extract latent representations
626
  encoded_data = extract_latent_representations(model, patient_loader, device)
627
 
628
  # Calculate risk scores
629
- try:
630
- umap_df = calculate_risk_scores(encoded_data, data_dict, risk_score, labels, label_encoder)
631
- st.error_state(t("risk_score_error"))
632
- except Exception as e:
633
- print("Error calculating risk scores: {str(e)}")
634
 
635
  # Perform SHAP analysis
636
  output_dir = os.path.join("data", "temp_output")
637
  os.makedirs(output_dir, exist_ok=True)
638
- try:
639
- important_biom, shap_plot_path = perform_shap_analysis(
640
  model, combined_data, input_dims, device, feature_names, output_dir, irc_biomarkers
641
  )
642
- except Exception as e:
643
- print("Error generating SHAP analysis: {str(e)}")
644
 
645
  # Generate dynamic recommendations
646
- try:
647
  risk_score = umap_df[t('risk_score')].iloc[0]
648
- biomarkers = important_biom.biomarkers[t('feature')].head(5).tolist()
649
  recommendations = []
650
  for intent in ["medication", "diet", "exercise"]:
651
- try:
652
- prompt = formulate_prompt(intent, risk_score, biomarkers)
653
- rec = generate_recommendation(prompt)
654
- if validate_recommendation(rec):
655
- rec = translate_recommendation(rec, lang)
656
- recommendations.append(rec)
657
- else:
658
- recommendations.append(t(f"{intent}_error", lang))
659
- except Exception as e:
660
- print("Error generating recommendation for {str(intent)}: {str(e)}")
661
- except Exception as e:
662
- print("Error generating recommendations: {str(e)}")
663
 
664
  # Generate PDF report
665
- try:
666
  pdf_path = os.path.join(output_dir, f"ckd_risk_report_{st.session_state.patient_id}.pdf")
667
- pdf_doc = generate_pdf_report(risk_score, important_biomarkers, shap_plot_path, recommendations, pdf_path,
668
- lang)
669
- except Exception as e:
670
- print("Error generating PDF report: {str(e)}")
671
 
672
  # Save to database
673
- try:
674
  session = Session()
675
  patient = Patient(
676
  patient_id=st.session_state.patient_id,
677
  risk_score=risk_score,
678
  biomarkers=', '.join(biomarkers)
679
  )
680
- session.add(patient_data
681
  session.commit()
682
  session.close()
683
- except Exception as e:
684
- print("Error saving to database: {str(e)}")
685
 
686
  # Store results
687
- try:
688
  st.session_state.results = {
689
  'umap_df': umap_df,
690
  'important_biomarkers': important_biomarkers,
@@ -692,8 +671,6 @@ elif page == t("predict_risk"):
692
  'pdf_path': pdf_path,
693
  'recommendations': recommendations
694
  }
695
- except Exception as e:
696
- print("Error storing results: {str(e)}")
697
 
698
  # Display results
699
  st.markdown(f"<div class='section-header'>{t('prediction_results')}</div>", unsafe_allow_html=True)
@@ -704,78 +681,75 @@ elif page == t("predict_risk"):
704
  fig_gauge = go.Figure(go.Indicator(
705
  mode="gauge+number",
706
  value=risk_score,
707
- title={'text': t('risk_score', lang), 'font':{'color': '#FFD700'}},
708
  gauge={
709
  'axis': {'range': [0, 100], 'tickcolor': '#FFF', 'tickfont': {'color': '#FFF'}},
710
  'bar': {'color': '#0000FF'},
711
  'steps': [
712
  {'range': [0, 33], 'color': '#4ADE80'},
713
  {'range': [33, 66], 'color': '#FACC15'},
714
- {'range': [66, 333], 'color': '#EF4444'}
715
  ],
716
- },
717
  'threshold': {
718
  'line': {'color': '#FFD700', 'width': 4},
719
  'thickness': 0.75,
720
  'value': risk_score
721
  }
722
- }
723
  }
724
  ))
725
  fig_gauge.update_layout(
726
  paper_bgcolor='#0E1117',
727
  font={'color': "#FFFFFF"},
728
- margin={'l':20,'r':20,'t':50,'b':20}
729
  )
730
  st.plotly_chart(fig_gauge, use_container_width=True)
731
 
732
  # SHAP bar plot
733
  st.markdown(f"<div class='subheader'>{t('key_biomarkers')}</div>", unsafe_allow_html=True)
734
  shap_fig = plt.figure(figsize=(12, 8))
735
- sns.barplot(data=important_biomarkers.head(20).data, x='SHAP_Mean_Abs', y=t('feature'), hue=t('omic'),
736
- palette=['#FF6F61', '#6B5B6B', '#4CAF50', '#2196F3'])
737
  plt.title(t('shap_top_features'), fontsize=16, color='#FFFFFF')
738
  plt.xlabel(t('shap_mean_value'), fontsize=12, color='#FFFFFF')
739
- plt.ylabel(t('feature'), fontsize=12, color='#FFF')
740
- plt.legend(title=t('omics'), facecolor='#1C2526', edgecolor='#FFF', labelcolor='#FFFFFF')
741
  plt.gca().set_facecolor('#0E1117')
742
- plt.gca().tick_params(colors=['black'])
743
  plt.gcf().set_facecolor('#0E1117')
744
  st.pyplot(shap_fig)
745
 
746
- # Display saved SHAP plot
747
- if os.path.exists(shap_plot_path):
748
- st.image(shap_plot_path, caption=t('shap'), use_caption_width=True)
749
-
750
- # Recommendations
751
- st.markdown(f"<div class='subheader'>{t('recommendations')}</div>", unsafe_allow_html=True)
752
- for rec in recommendations:
753
- st.markdown(f"<div class='recommendation'}>rec{rec}</div>", unsafe)
754
-
755
- # Download results
756
- st.markdown(f"<div class='subheader'>{t('download_results')}</div>", unsafe_allow_html=True)
757
- col1, col2 = col.st.columns(2)
758
- with col1:
759
- csv_data = important_biomarkers.to_csv().encode()
760
- b64_data = base64.b64encode(csv_data).decode()
761
- download_text = t('download_biomarkers', lang=st.session_state.language)
762
- href = f'<a href="data:file/csv;base64,{b64}" download="important_biomarkers.csv" class="download-btn">{download_text}</a>'
763
- st.markdown(href, unsafe_allow_html=True)
764
- with col2:
765
- with open(pdf_path, "rb") as f:
766
- pdf_data = f.read()
767
- b64_data_pdf = base64.b64encode(pdf_data).decode()
768
- download_text_pdf = t('download_report', language=state.session_state.lang)
769
- href = href_pdf = f'<a href="data:application/pdf;base64,{b64_pdf}" download="ckd_risk_report.pdf" class="download-btn">{download_text_pdf}</a>'
770
- st.markdown(href_pdf, unsafe=allow_html=True)
771
  except Exception as e:
772
  st.error(t("file_process_error").format(error=str(e)))
773
  st.stop()
774
  else:
775
- st.warning(t("Please upload all omics files and provide a patient ID."))
776
 
777
  # Chatbot Assistant Page
778
- else if page == t("chatbot"):
779
  st.markdown(f"<div class='title animate__fadeIn'>{t('chatbot_title')}</div>", unsafe_allow_html=True)
780
  st.markdown(f"""
781
  <div class='content animate__fadeIn'>
@@ -785,7 +759,7 @@ else if page == t("chatbot"):
785
 
786
  # Chat Interface
787
  st.markdown(f"<div class='section-header'>{t('chat_with_assistant')}</div>", unsafe_allow_html=True)
788
- chat_container = st.container()container()
789
  with chat_container:
790
  for message in st.session_state.chat_history:
791
  if message['role'] == 'user':
@@ -794,57 +768,54 @@ else if page == t("chatbot"):
794
  st.markdown(f"<div class='chat-bubble bot'>{message['content']}</div>", unsafe_allow_html=True)
795
 
796
  # User input
797
- user_input = input.st.text_area(t("type_message"), key="chat_input")
798
  if st.button(t("send"), key="button_send"):
799
- try:
800
- if user_input:
801
- # Add user message to history
802
- st.session_state.chat_history.append({'role': 'user', 'content': user_input})
803
-
804
- # Check if user is asking about results
805
- if st.session_state.results and any(
806
- keyword in user_input.lower() for keyword in t('chat_risk_keywords').split(',')):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
807
  risk_score = st.session_state.results['umap_df'][t('risk_score')].iloc[0]
808
- biomarkers = st.session_state.results['important_biomarkers'][t('feature')].head(5).tolist()]
809
- context = t('chat_risk_response').format(score=risk_score), biomarkers=', '.join(biomarkers))
810
- response = send_to_rasa(f"{context} {user_input}", lang)
 
 
 
 
811
  else:
812
- # Generate recommendation based on intent
813
- intent = 'None'
814
- if any(keyword in user_input.lower() for keyword in t('chat_medication_keywords').split(',')):
815
- intent = 'medication'
816
- elif any(keyword in user_input.lower() for keyword in t('chat_diet_keywords').split(',')):
817
- intent = 'diet'
818
- elif any(keyword in user_input.lower() for keyword in t('chat_exercise_keywords').split(',')):
819
- intent = 'exercise'
820
-
821
- if intent and st.session_state.results:
822
- risk_score = st.session_state.results['umap_df'][t('risk_score')].iloc[0]
823
- biomarkers = st.session_state.results['important_biomarkers'][t('feature')].head(5).tolist()
824
- try:
825
- prompt = formulate_prompt(intent, risk_score, biomarkers)
826
- try:
827
- response = generate_recommendation(prompt)
828
- if validate_recommendation(response):
829
- response = translate_recommendation(response, lang)
830
- else:
831
- response = t(f"{intent}_error", lang)
832
- else:
833
- response = send_to_rasa(user_input, lang)
834
-
835
- # Add bot response to history
836
- st.session_state.chat_history.append({'role': 'bot', 'content': response})
837
-
838
- # Rerender chat
839
- st.rerun()
840
- except Exception as e:
841
- print("Error processing chatbot input: {str(e)}")
842
- st.error("Error processing chatbot input")
843
 
844
  # Dashboard Page
845
- elif if page == t("dashboard"):
846
  st.markdown(f"<div class='title animate__fadeIn'>{t('dashboard_title')}</div>", unsafe_allow_html=True)
847
-
848
  st.markdown(f"""
849
  <div class='content animate__fadeIn'>
850
  <p>{t('dashboard_intro')}</p>
@@ -872,7 +843,7 @@ elif if page == t("dashboard"):
872
  st.dataframe(filtered_df, use_container_width=True)
873
 
874
  # Plot
875
- fig = px.scatter_plot(
876
  filtered_df,
877
  x=t('risk_score'),
878
  y=t('patient_id'),
@@ -884,9 +855,9 @@ elif if page == t("dashboard"):
884
  fig.update_layout(
885
  paper_bgcolor='#0E1117',
886
  plot_bgcolor='#1C2526',
887
- font={'color': '#ffffff'}
888
  )
889
- st.plotly_chart(fig, use_container_width=True))
890
  else:
891
  st.info(t("no_patients"))
892
  session.close()
@@ -903,10 +874,10 @@ if rasa_process:
903
  try:
904
  rasa_process.terminate()
905
  except Exception as e:
906
- print("Error terminating Rasa server: {str(e)}")
907
 
908
  st.markdown(f"""
909
- <div class='footer">
910
  {t('footer')}
911
  </div>
912
  """, unsafe_allow_html=True)
 
481
  <div class='intro animate__fadeIn'>
482
  <p>{t('home_intro_1').format(author="<b>Ngoue David Roger Yannick</b>")}</p>
483
  <p>{t('home_intro_2')}</p>
484
+ </div>
485
  """, unsafe_allow_html=True)
486
 
487
+ st.markdown(f"<div class='section-header'>{t('why_omics')}</div>", unsafe_allow_html=True)
488
  st.markdown(f"""
489
  <div class='content animate__fadeIn'>
490
  <p>{t('omics_description')}</p>
 
494
  <li><b>{t('proteomics')}</b>: {t('proteomics_desc')}</li>
495
  <li><b>{t('metabolomics')}</b>: {t('metabolomics_desc')}</li>
496
  </ul>
 
497
  <p>{t('omics_integration')}</p>
498
+ </div>
499
  """, unsafe_allow_html=True)
500
 
501
  # About Omics Data Page
 
517
  <li><b>{t('proteomics')}</b>: {t('proteomics_format')}</li>
518
  <li><b>{t('metabolomics')}</b>: {t('metabolomics_format')}</li>
519
  </ul>
 
520
  <p>{t('raw_omics_processing')}</p>
521
+ </div>
522
  """, unsafe_allow_html=True)
523
 
524
+ st.markdown(f"<div class='section-header'>{t('preprocessing_steps')}</div>", unsafe_allow_html=True)
525
  st.markdown(f"""
526
+ <div class='content animate__fadeIn'>
527
  <p>{t('preprocessing_desc')}</p>
528
  <ol>
529
  <li><b>{t('quality_control')}</b>: {t('quality_control_desc')}</li>
 
532
  <li><b>{t('standardization')}</b>: {t('standardization_desc')}</li>
533
  <li><b>{t('feature_selection')}</b>: {t('feature_selection_desc')}</li>
534
  </ol>
 
535
  <p>{t('preprocessing_importance')}</p>
536
+ </div>
537
  """, unsafe_allow_html=True)
538
 
539
  st.markdown(f"<div class='section-header'>{t('csv_format')}</div>", unsafe_allow_html=True)
 
547
  <li><b>{t('separator')}</b>: {t('separator_desc')}</li>
548
  <li><b>{t('header')}</b>: {t('header_desc')}</li>
549
  </ul>
 
550
  <p>{t('csv_example')}</p>
551
  <pre class='code-block'>
552
  PatientID,UMOD_rs12917707,APOL1_rs73885319,MYH9_rs4821480,Status
 
558
 
559
  st.markdown(f"<div class='section-header'>{t('data_quality')}</div>", unsafe_allow_html=True)
560
  st.markdown(f"""
561
+ <div class='content animate__fadeIn'>
562
  <p>{t('data_quality_desc')}</p>
563
  <ul>
564
  <li><b>{t('consistency')}</b>: {t('consistency_desc')}</li>
 
566
  <li><b>{t('accuracy')}</b>: {t('accuracy_desc')}</li>
567
  <li><b>{t('alignment')}</b>: {t('alignment_desc')}</li>
568
  </ul>
 
569
  <p>{t('data_quality_importance')}</p>
570
+ </div>
571
  """, unsafe_allow_html=True)
572
 
573
  # Predict Risk Page
 
598
  with cols[idx]:
599
  uploaded_file = st.file_uploader(f"{t(omic)} (CSV)", type=["csv"], key=omic)
600
  if uploaded_file:
601
+ os.makedirs("data", exist_ok=True)
602
  temp_path = os.path.join("data", f"temp_{omic}.csv")
603
  with open(temp_path, "wb") as f:
604
  f.write(uploaded_file.getbuffer())
 
620
  patient_tensors = [torch.tensor(data_dict[omic].values, dtype=torch.float32) for omic in data_dict]
621
  patient_dataset = TensorDataset(*patient_tensors)
622
  patient_loader = DataLoader(patient_dataset, batch_size=best_hyperparams['batch_size'],
623
+ shuffle=False)
624
 
625
  # Extract latent representations
626
  encoded_data = extract_latent_representations(model, patient_loader, device)
627
 
628
  # Calculate risk scores
629
+ umap_df = calculate_risk_scores(encoded_data, data_dict, irc_biomarkers, labels, label_encoder)
 
 
 
 
630
 
631
  # Perform SHAP analysis
632
  output_dir = os.path.join("data", "temp_output")
633
  os.makedirs(output_dir, exist_ok=True)
634
+ important_biomarkers, shap_plot_path = perform_shap_analysis(
 
635
  model, combined_data, input_dims, device, feature_names, output_dir, irc_biomarkers
636
  )
 
 
637
 
638
  # Generate dynamic recommendations
 
639
  risk_score = umap_df[t('risk_score')].iloc[0]
640
+ biomarkers = important_biomarkers[t('feature')].head(5).tolist()
641
  recommendations = []
642
  for intent in ["medication", "diet", "exercise"]:
643
+ prompt = formulate_prompt(intent, risk_score, biomarkers)
644
+ rec = generate_recommendation(prompt)
645
+ if validate_recommendation(rec):
646
+ rec = translate_recommendation(rec, lang)
647
+ recommendations.append(rec)
648
+ else:
649
+ recommendations.append(t(f"{intent}_error", lang))
 
 
 
 
 
650
 
651
  # Generate PDF report
 
652
  pdf_path = os.path.join(output_dir, f"ckd_risk_report_{st.session_state.patient_id}.pdf")
653
+ generate_pdf_report(risk_score, important_biomarkers, shap_plot_path, recommendations, pdf_path, lang)
 
 
 
654
 
655
  # Save to database
 
656
  session = Session()
657
  patient = Patient(
658
  patient_id=st.session_state.patient_id,
659
  risk_score=risk_score,
660
  biomarkers=', '.join(biomarkers)
661
  )
662
+ session.add(patient)
663
  session.commit()
664
  session.close()
 
 
665
 
666
  # Store results
 
667
  st.session_state.results = {
668
  'umap_df': umap_df,
669
  'important_biomarkers': important_biomarkers,
 
671
  'pdf_path': pdf_path,
672
  'recommendations': recommendations
673
  }
 
 
674
 
675
  # Display results
676
  st.markdown(f"<div class='section-header'>{t('prediction_results')}</div>", unsafe_allow_html=True)
 
681
  fig_gauge = go.Figure(go.Indicator(
682
  mode="gauge+number",
683
  value=risk_score,
684
+ title={'text': t('risk_score', lang), 'font': {'color': '#FFD700'}},
685
  gauge={
686
  'axis': {'range': [0, 100], 'tickcolor': '#FFF', 'tickfont': {'color': '#FFF'}},
687
  'bar': {'color': '#0000FF'},
688
  'steps': [
689
  {'range': [0, 33], 'color': '#4ADE80'},
690
  {'range': [33, 66], 'color': '#FACC15'},
691
+ {'range': [66, 100], 'color': '#EF4444'}
692
  ],
 
693
  'threshold': {
694
  'line': {'color': '#FFD700', 'width': 4},
695
  'thickness': 0.75,
696
  'value': risk_score
697
  }
 
698
  }
699
  ))
700
  fig_gauge.update_layout(
701
  paper_bgcolor='#0E1117',
702
  font={'color': "#FFFFFF"},
703
+ margin={'l': 20, 'r': 20, 't': 50, 'b': 20}
704
  )
705
  st.plotly_chart(fig_gauge, use_container_width=True)
706
 
707
  # SHAP bar plot
708
  st.markdown(f"<div class='subheader'>{t('key_biomarkers')}</div>", unsafe_allow_html=True)
709
  shap_fig = plt.figure(figsize=(12, 8))
710
+ sns.barplot(data=important_biomarkers.head(20), x='SHAP_Mean_Abs', y=t('feature'), hue=t('omic'),
711
+ palette=['#FF6F61', '#6B5B95', '#4CAF50', '#2196F3'])
712
  plt.title(t('shap_top_features'), fontsize=16, color='#FFFFFF')
713
  plt.xlabel(t('shap_mean_value'), fontsize=12, color='#FFFFFF')
714
+ plt.ylabel(t('feature'), fontsize=12, color='#FFFFFF')
715
+ plt.legend(title=t('omics'), facecolor='#1C2526', edgecolor='#FFFFFF', labelcolor='#FFFFFF')
716
  plt.gca().set_facecolor('#0E1117')
717
+ plt.gca().tick_params(colors='#FFFFFF')
718
  plt.gcf().set_facecolor('#0E1117')
719
  st.pyplot(shap_fig)
720
 
721
+ # Display saved SHAP plot
722
+ if os.path.exists(shap_plot_path):
723
+ st.image(shap_plot_path, caption=t('shap'), use_column_width=True)
724
+
725
+ # Recommendations
726
+ st.markdown(f"<div class='subheader'>{t('recommendations')}</div>", unsafe_allow_html=True)
727
+ for rec in recommendations:
728
+ st.markdown(f"<div class='recommendation'>{rec}</div>", unsafe_allow_html=True)
729
+
730
+ # Download results
731
+ st.markdown(f"<div class='subheader'>{t('download_results')}</div>", unsafe_allow_html=True)
732
+ col1, col2 = st.columns(2)
733
+ with col1:
734
+ csv = important_biomarkers.to_csv(index=False).encode('utf-8')
735
+ b64 = base64.b64encode(csv).decode()
736
+ href = f'<a href="data:file/csv;base64,{b64}" download="important_biomarkers.csv" class="download-btn">{t("download_biomarkers", lang)}</a>'
737
+ st.markdown(href, unsafe_allow_html=True)
738
+ with col2:
739
+ with open(pdf_path, "rb") as f:
740
+ pdf_data = f.read()
741
+ b64_pdf = base64.b64encode(pdf_data).decode()
742
+ href_pdf = f'<a href="data:application/pdf;base64,{b64_pdf}" download="ckd_risk_report.pdf" class="download-btn">{t("download_report", lang)}</a>'
743
+ st.markdown(href_pdf, unsafe_allow_html=True)
744
+
 
745
  except Exception as e:
746
  st.error(t("file_process_error").format(error=str(e)))
747
  st.stop()
748
  else:
749
+ st.warning(t("upload_warning"))
750
 
751
  # Chatbot Assistant Page
752
+ elif page == t("chatbot"):
753
  st.markdown(f"<div class='title animate__fadeIn'>{t('chatbot_title')}</div>", unsafe_allow_html=True)
754
  st.markdown(f"""
755
  <div class='content animate__fadeIn'>
 
759
 
760
  # Chat Interface
761
  st.markdown(f"<div class='section-header'>{t('chat_with_assistant')}</div>", unsafe_allow_html=True)
762
+ chat_container = st.container()
763
  with chat_container:
764
  for message in st.session_state.chat_history:
765
  if message['role'] == 'user':
 
768
  st.markdown(f"<div class='chat-bubble bot'>{message['content']}</div>", unsafe_allow_html=True)
769
 
770
  # User input
771
+ user_input = st.text_area(t("type_message"), key="chat_input")
772
  if st.button(t("send"), key="button_send"):
773
+ if user_input:
774
+ try:
775
+ # Add user message to history
776
+ st.session_state.chat_history.append({'role': 'user', 'content': user_input})
777
+
778
+ # Check if user is asking about results
779
+ if st.session_state.results and any(
780
+ keyword in user_input.lower() for keyword in t('chat_risk_keywords').split(',')):
781
+ risk_score = st.session_state.results['umap_df'][t('risk_score')].iloc[0]
782
+ biomarkers = st.session_state.results['important_biomarkers'][t('feature')].head(5).tolist()
783
+ context = t('chat_risk_response').format(score=risk_score, biomarkers=', '.join(biomarkers))
784
+ response = send_to_rasa(f"{context} {user_input}", lang)
785
+ else:
786
+ # Generate recommendation based on intent
787
+ intent = 'None'
788
+ if any(keyword in user_input.lower() for keyword in t('chat_medication_keywords').split(',')):
789
+ intent = 'medication'
790
+ elif any(keyword in user_input.lower() for keyword in t('chat_diet_keywords').split(',')):
791
+ intent = 'diet'
792
+ elif any(keyword in user_input.lower() for keyword in t('chat_exercise_keywords').split(',')):
793
+ intent = 'exercise'
794
+
795
+ if intent != 'None' and st.session_state.results:
796
  risk_score = st.session_state.results['umap_df'][t('risk_score')].iloc[0]
797
+ biomarkers = st.session_state.results['important_biomarkers'][t('feature')].head(5).tolist()
798
+ prompt = formulate_prompt(intent, risk_score, biomarkers)
799
+ response = generate_recommendation(prompt)
800
+ if validate_recommendation(response):
801
+ response = translate_recommendation(response, lang)
802
+ else:
803
+ response = t(f"{intent}_error", lang)
804
  else:
805
+ response = send_to_rasa(user_input, lang)
806
+
807
+ # Add bot response to history
808
+ st.session_state.chat_history.append({'role': 'bot', 'content': response})
809
+
810
+ # Rerender chat
811
+ st.rerun()
812
+
813
+ except Exception as e:
814
+ st.error(t("chatbot_error").format(error=str(e)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815
 
816
  # Dashboard Page
817
+ elif page == t("dashboard"):
818
  st.markdown(f"<div class='title animate__fadeIn'>{t('dashboard_title')}</div>", unsafe_allow_html=True)
 
819
  st.markdown(f"""
820
  <div class='content animate__fadeIn'>
821
  <p>{t('dashboard_intro')}</p>
 
843
  st.dataframe(filtered_df, use_container_width=True)
844
 
845
  # Plot
846
+ fig = px.scatter(
847
  filtered_df,
848
  x=t('risk_score'),
849
  y=t('patient_id'),
 
855
  fig.update_layout(
856
  paper_bgcolor='#0E1117',
857
  plot_bgcolor='#1C2526',
858
+ font={'color': '#FFFFFF'}
859
  )
860
+ st.plotly_chart(fig, use_container_width=True)
861
  else:
862
  st.info(t("no_patients"))
863
  session.close()
 
874
  try:
875
  rasa_process.terminate()
876
  except Exception as e:
877
+ print(f"Error terminating Rasa server: {str(e)}")
878
 
879
  st.markdown(f"""
880
+ <div class='footer'>
881
  {t('footer')}
882
  </div>
883
  """, unsafe_allow_html=True)