akshit4857 commited on
Commit
1e18317
Β·
verified Β·
1 Parent(s): e7d852d

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +239 -1
src/streamlit_app.py CHANGED
@@ -818,4 +818,242 @@ def detector_page(squad, warnings_text=None):
818
  color = "red" if bot_score > 50 else "green"
819
  k1.markdown(
820
  f"""<div class="stat-box">
821
- <div class="stat-num" style="color:{color}">{bot_score:.0f}%
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
818
  color = "red" if bot_score > 50 else "green"
819
  k1.markdown(
820
  f"""<div class="stat-box">
821
+ <div class="stat-num" style="color:{color}">{bot_score:.0f}%</div>
822
+ <div class="stat-txt">AI-Likeness</div>
823
+ </div>""",
824
+ unsafe_allow_html=True
825
+ )
826
+ k2.markdown(
827
+ f"""<div class="stat-box">
828
+ <div class="stat-num">{grammar_score:.0f}%</div>
829
+ <div class="stat-txt">Grammar Quality</div>
830
+ </div>""",
831
+ unsafe_allow_html=True
832
+ )
833
+ k3.markdown(
834
+ f"""<div class="stat-box">
835
+ <div class="stat-num">{mood_label}</div>
836
+ <div class="stat-txt">Sentiment</div>
837
+ </div>""",
838
+ unsafe_allow_html=True
839
+ )
840
+
841
+ st.write("")
842
+ g1, g2, g3 = st.columns(3)
843
+ with g1:
844
+ st.markdown("#### πŸ“Š Scores")
845
+ fig = breakdown_chart(res)
846
+ st.pyplot(fig, use_container_width=True)
847
+ with g2:
848
+ st.markdown("#### πŸ“ Sentence Lengths")
849
+ fig2 = sentence_length_chart(stats)
850
+ st.pyplot(fig2, use_container_width=True)
851
+ with g3:
852
+ st.markdown("#### πŸ”€ Top Words")
853
+ fig3 = word_freq_chart(stats)
854
+ st.pyplot(fig3, use_container_width=True)
855
+
856
+ st.markdown("#### πŸ’‘ Verdict & Explanation")
857
+ if verdict_type == "error":
858
+ st.error(verdict_text)
859
+ elif verdict_type == "warning":
860
+ st.warning(verdict_text)
861
+ else:
862
+ st.success(verdict_text)
863
+
864
+ reasons = explain_text(res, stats, strict_mode_saved)
865
+ for r in reasons:
866
+ st.markdown(f"- {r}")
867
+
868
+ st.markdown(
869
+ "<small>Note: These scores and explanations are signals, not absolute proof. "
870
+ "Always combine them with your own judgement.</small>",
871
+ unsafe_allow_html=True
872
+ )
873
+
874
+ # PDF report button
875
+ st.write("")
876
+ if HAVE_REPORTLAB:
877
+ img_info_for_pdf = st.session_state.get("img_res_for_pdf", None)
878
+ reverse_search_for_pdf = st.session_state.get("reverse_search_for_pdf", None)
879
+ pdf_bytes = generate_pdf_report(
880
+ platform_saved,
881
+ review_text_saved,
882
+ res,
883
+ stats,
884
+ img_info_for_pdf,
885
+ reverse_search_for_pdf
886
+ )
887
+ st.download_button(
888
+ "πŸ“„ Download PDF Report",
889
+ data=pdf_bytes,
890
+ file_name="review_validator_report.pdf",
891
+ mime="application/pdf",
892
+ )
893
+ else:
894
+ st.info("PDF report requires reportlab. Add `reportlab` to requirements.txt to enable export.")
895
+
896
+ # --- IMAGE TAB ---
897
+ with tab2:
898
+ col_in, col_view = st.columns([1, 1])
899
+
900
+ with col_in:
901
+ st.markdown("#### Step 1: Provide Image")
902
+ method = st.radio(
903
+ "Input Method",
904
+ ["Paste URL", "Upload File"],
905
+ horizontal=True,
906
+ label_visibility="collapsed"
907
+ )
908
+
909
+ with st.form("image_form"):
910
+ img_file = None
911
+ img_url = None
912
+
913
+ if method == "Paste URL":
914
+ img_url = st.text_input("Paste Image Link:")
915
+ else:
916
+ img_file = st.file_uploader("Upload Image", type=['jpg', 'jpeg', 'png'])
917
+
918
+ strict_img = st.checkbox("Use Strict AI Mode for Images", value=True)
919
+ do_reverse_search = st.checkbox("πŸ” Perform Reverse Image Search", value=True)
920
+ submitted = st.form_submit_button("Scan Image", type="primary")
921
+
922
+ if submitted:
923
+ target_img = None
924
+ if method == "Paste URL" and img_url:
925
+ target_img = get_image_from_url(img_url)
926
+ elif method == "Upload File" and img_file:
927
+ try:
928
+ target_img = Image.open(img_file).convert("RGB")
929
+ except Exception:
930
+ target_img = None
931
+
932
+ if target_img is None:
933
+ st.error("Could not read image. Try another link or file.")
934
+ else:
935
+ with st.spinner("Scanning image..."):
936
+ data = check_image(target_img, squad)
937
+ st.session_state['img_res'] = (data, strict_img)
938
+ st.session_state['current_img'] = target_img
939
+ # store a simplified version for PDF report
940
+ st.session_state['img_res_for_pdf'] = data
941
+
942
+ # Perform reverse image search if requested
943
+ if do_reverse_search:
944
+ with st.spinner("Performing reverse image search..."):
945
+ reverse_results = reverse_image_search(target_img)
946
+ st.session_state['reverse_search'] = reverse_results
947
+ st.session_state['reverse_search_for_pdf'] = reverse_results
948
+ else:
949
+ st.session_state['reverse_search'] = None
950
+ st.session_state['reverse_search_for_pdf'] = None
951
+
952
+ with col_view:
953
+ if 'current_img' in st.session_state:
954
+ st.image(
955
+ st.session_state['current_img'],
956
+ use_column_width=True,
957
+ caption="Analyzed Image"
958
+ )
959
+
960
+ if 'img_res' in st.session_state:
961
+ data, strict_img = st.session_state['img_res']
962
+ ai_score = data['ai_chance']
963
+ caption = data['caption']
964
+
965
+ st.markdown("#### Step 2: Analysis Results")
966
+
967
+ st.markdown(f"""
968
+ <div class="analysis-box">
969
+ <strong>πŸ‘οΈ Visual Caption (approx):</strong><br>
970
+ <em>{caption}</em>
971
+ </div>
972
+ """, unsafe_allow_html=True)
973
+
974
+ st.write("")
975
+
976
+ if strict_img:
977
+ t_high = 90
978
+ t_mid = 70
979
+ else:
980
+ t_high = 80
981
+ t_mid = 60
982
+
983
+ if ai_score >= t_high:
984
+ st.error(f"πŸ€– Very likely AI-generated ({ai_score:.0f}% AI score)")
985
+ elif ai_score >= t_mid:
986
+ st.warning(f"πŸ€” Suspicious / possibly AI ({ai_score:.0f}% AI score)")
987
+ else:
988
+ st.success(f"πŸ“Έ Likely real photo ({100 - ai_score:.0f}% real score)")
989
+
990
+ st.markdown("**Detector Details:**")
991
+ st.progress(ai_score / 100.0, text=f"AI probability: {ai_score:.1f}%")
992
+
993
+ with st.expander("See raw detector scores"):
994
+ st.write(f"Image AI Score (model): {ai_score:.1f}%")
995
+
996
+ # Display reverse search results
997
+ if 'reverse_search' in st.session_state and st.session_state['reverse_search'] is not None:
998
+ reverse_data = st.session_state['reverse_search']
999
+
1000
+ st.markdown("---")
1001
+ st.markdown("#### πŸ” Reverse Image Search Results")
1002
+
1003
+ if reverse_data['success']:
1004
+ results = reverse_data['results']
1005
+
1006
+ if results:
1007
+ st.markdown(f"""
1008
+ <div class="reverse-search-box">
1009
+ <strong>βœ… Found {len(results)} matches online</strong><br>
1010
+ <small>This image appears on the following websites:</small>
1011
+ </div>
1012
+ """, unsafe_allow_html=True)
1013
+
1014
+ for i, result in enumerate(results, 1):
1015
+ with st.container():
1016
+ st.markdown(f"""
1017
+ <div class="result-item">
1018
+ <strong>{i}. {result['title']}</strong><br>
1019
+ <small>πŸ“ Source: {result['source']}</small><br>
1020
+ <small>πŸ”— <a href="{result['link']}" target="_blank">View Original</a></small>
1021
+ </div>
1022
+ """, unsafe_allow_html=True)
1023
+ else:
1024
+ st.markdown("""
1025
+ <div class="reverse-search-box">
1026
+ <strong>πŸ†• No matches found online</strong><br>
1027
+ <small>This could mean the image is original/new, or not indexed by Google yet.</small>
1028
+ </div>
1029
+ """, unsafe_allow_html=True)
1030
+ else:
1031
+ st.error(f"❌ {reverse_data['error']}")
1032
+ if "SERPAPI_KEY" in reverse_data['error']:
1033
+ st.info("πŸ’‘ To enable reverse image search:\n1. Sign up at https://serpapi.com/\n2. Add your API key to secrets or environment variables")
1034
+
1035
+ # --- MAIN CONTROLLER ---
1036
+ def main():
1037
+ inject_custom_css()
1038
+
1039
+ if 'page' not in st.session_state:
1040
+ st.session_state['page'] = 'landing'
1041
+
1042
+ with st.spinner("Loading AI models (first run can take some time)..."):
1043
+ squad, err = load_ai_squad()
1044
+
1045
+ if squad is None:
1046
+ st.error(err or "Failed to load models.")
1047
+ st.stop()
1048
+
1049
+ warnings_text = None
1050
+ if err:
1051
+ warnings_text = "Some features may be limited:<br>" + err.replace("\n", "<br>")
1052
+
1053
+ if st.session_state['page'] == 'landing':
1054
+ landing_page()
1055
+ else:
1056
+ detector_page(squad, warnings_text=warnings_text)
1057
+
1058
+ if __name__ == "__main__":
1059
+ main()