Upload app.py
Browse files
app.py
CHANGED
|
@@ -406,6 +406,8 @@ if "attached_file_name" not in st.session_state:
|
|
| 406 |
st.session_state.attached_file_name = None
|
| 407 |
if "attached_file_mime" not in st.session_state:
|
| 408 |
st.session_state.attached_file_mime = None
|
|
|
|
|
|
|
| 409 |
|
| 410 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 411 |
# SUPABASE β Persistent chat history
|
|
@@ -2858,156 +2860,74 @@ for i, msg in enumerate(st.session_state.messages):
|
|
| 2858 |
st.code(msg["content"], language=None)
|
| 2859 |
|
| 2860 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2861 |
-
# FILE ATTACH β
|
| 2862 |
-
#
|
| 2863 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2864 |
|
| 2865 |
-
|
| 2866 |
-
|
| 2867 |
-
"main_attach",
|
| 2868 |
-
type=["jpg", "jpeg", "png", "webp", "pdf"],
|
| 2869 |
-
label_visibility="collapsed",
|
| 2870 |
-
key="main_uploader"
|
| 2871 |
-
)
|
| 2872 |
-
if main_uploader:
|
| 2873 |
-
_fkey = f"{main_uploader.size}_{main_uploader.type}"
|
| 2874 |
-
if _fkey != st.session_state.get("last_uploaded_file", ""):
|
| 2875 |
-
st.session_state["last_uploaded_file"] = _fkey
|
| 2876 |
-
st.session_state.pending_file_bytes = main_uploader.read()
|
| 2877 |
-
st.session_state.pending_file_name = main_uploader.name
|
| 2878 |
-
st.session_state.pending_file_mime = main_uploader.type or "application/octet-stream"
|
| 2879 |
-
st.rerun()
|
| 2880 |
-
|
| 2881 |
-
# ββ Status values βββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2882 |
-
_pending = st.session_state.pending_file_bytes is not None
|
| 2883 |
-
_memfile = st.session_state.attached_file_name
|
| 2884 |
|
|
|
|
| 2885 |
if _pending:
|
| 2886 |
-
|
| 2887 |
-
|
| 2888 |
-
|
| 2889 |
-
|
| 2890 |
-
|
| 2891 |
-
|
| 2892 |
-
|
| 2893 |
-
|
| 2894 |
-
|
| 2895 |
-
|
| 2896 |
-
else:
|
| 2897 |
-
_status = "Click <b>π</b> below to attach an image or PDF"
|
| 2898 |
-
_bcolor = "#111827"
|
| 2899 |
-
_bborder = "#2d3748"
|
| 2900 |
-
_tcolor = "#6b7280"
|
| 2901 |
-
|
| 2902 |
-
# ββ Fixed bar: [π button] [status text] [β if file exists] ββββββ
|
| 2903 |
-
st.markdown(
|
| 2904 |
-
f"""
|
| 2905 |
-
<style>
|
| 2906 |
-
/* Hide the Streamlit file-uploader widget β triggered via JS */
|
| 2907 |
-
[data-testid="stFileUploader"] {{
|
| 2908 |
-
visibility: hidden !important;
|
| 2909 |
-
height: 0 !important;
|
| 2910 |
-
min-height: 0 !important;
|
| 2911 |
-
overflow: hidden !important;
|
| 2912 |
-
margin: 0 !important;
|
| 2913 |
-
padding: 0 !important;
|
| 2914 |
-
position: absolute !important;
|
| 2915 |
-
pointer-events: none !important;
|
| 2916 |
-
}}
|
| 2917 |
-
/* Keep the actual <input type=file> reachable by JS */
|
| 2918 |
-
[data-testid="stFileUploaderDropzoneInput"] {{
|
| 2919 |
-
visibility: visible !important;
|
| 2920 |
-
pointer-events: auto !important;
|
| 2921 |
-
}}
|
| 2922 |
-
/* Hide the Streamlit β clear-buttons below β they're fired by JS */
|
| 2923 |
-
div[data-testid="stHorizontalBlock"]:has(button[kind="secondary"]) {{
|
| 2924 |
-
visibility: hidden !important;
|
| 2925 |
-
height: 0 !important;
|
| 2926 |
-
overflow: hidden !important;
|
| 2927 |
-
margin: 0 !important;
|
| 2928 |
-
padding: 0 !important;
|
| 2929 |
-
position: absolute !important;
|
| 2930 |
-
}}
|
| 2931 |
-
</style>
|
| 2932 |
-
|
| 2933 |
-
<script>
|
| 2934 |
-
function saadAttach() {{
|
| 2935 |
-
var inp = document.querySelector('[data-testid="stFileUploaderDropzoneInput"]');
|
| 2936 |
-
if (inp) {{ inp.click(); }}
|
| 2937 |
-
}}
|
| 2938 |
-
function saadClearFile() {{
|
| 2939 |
-
/* Find and click the Streamlit β button by its text content */
|
| 2940 |
-
var btns = document.querySelectorAll('button');
|
| 2941 |
-
for (var b of btns) {{
|
| 2942 |
-
if (b.innerText.trim() === 'β') {{ b.click(); break; }}
|
| 2943 |
-
}}
|
| 2944 |
-
}}
|
| 2945 |
-
</script>
|
| 2946 |
-
|
| 2947 |
-
<!-- Fixed attach bar just above the chat input -->
|
| 2948 |
-
<div style="
|
| 2949 |
-
position: fixed;
|
| 2950 |
-
bottom: 68px;
|
| 2951 |
-
left: 50%;
|
| 2952 |
-
transform: translateX(-50%);
|
| 2953 |
-
width: 720px;
|
| 2954 |
-
max-width: 88vw;
|
| 2955 |
-
display: flex;
|
| 2956 |
-
align-items: center;
|
| 2957 |
-
gap: 8px;
|
| 2958 |
-
z-index: 9999;
|
| 2959 |
-
">
|
| 2960 |
-
<!-- π Paperclip button β triggers hidden file input -->
|
| 2961 |
-
<button onclick="saadAttach()" title="Attach image or PDF"
|
| 2962 |
-
style="flex-shrink:0; width:40px; height:36px;
|
| 2963 |
-
background:#1e293b; border:1.5px solid #334155;
|
| 2964 |
-
border-radius:9px; cursor:pointer; font-size:17px;
|
| 2965 |
-
color:#9ca3af; line-height:1; transition:all .15s;"
|
| 2966 |
-
onmouseover="this.style.background='#334155';this.style.borderColor='#60a5fa';this.style.color='#93c5fd';"
|
| 2967 |
-
onmouseout="this.style.background='#1e293b';this.style.borderColor='#334155';this.style.color='#9ca3af';">
|
| 2968 |
-
π
|
| 2969 |
-
</button>
|
| 2970 |
-
<!-- Status pill -->
|
| 2971 |
-
<div style="flex:1; background:{_bcolor}; border:1px solid {_bborder};
|
| 2972 |
-
border-radius:9px; padding:6px 14px; font-size:0.79rem;
|
| 2973 |
-
color:{_tcolor}; white-space:nowrap; overflow:hidden;
|
| 2974 |
-
text-overflow:ellipsis;">
|
| 2975 |
-
{_status}
|
| 2976 |
-
</div>
|
| 2977 |
-
{"""<!-- β clear button -->
|
| 2978 |
-
<button onclick="saadClearFile()" title="Remove file"
|
| 2979 |
-
style="flex-shrink:0; width:30px; height:30px;
|
| 2980 |
-
background:transparent; border:1px solid #4b5563;
|
| 2981 |
-
border-radius:7px; cursor:pointer; font-size:13px;
|
| 2982 |
-
color:#9ca3af; line-height:1; transition:all .15s;"
|
| 2983 |
-
onmouseover="this.style.borderColor='#f87171';this.style.color='#f87171';"
|
| 2984 |
-
onmouseout="this.style.borderColor='#4b5563';this.style.color='#9ca3af';">
|
| 2985 |
-
β
|
| 2986 |
-
</button>""" if (_pending or _memfile) else ""}
|
| 2987 |
-
</div>
|
| 2988 |
-
""",
|
| 2989 |
-
unsafe_allow_html=True
|
| 2990 |
-
)
|
| 2991 |
-
|
| 2992 |
-
# ββ Real Streamlit clear-buttons (hidden by CSS, fired by JS above) β
|
| 2993 |
-
if _pending:
|
| 2994 |
-
col_sp, col_rm = st.columns([11, 1])
|
| 2995 |
-
with col_rm:
|
| 2996 |
-
if st.button("β", key="remove_pending", help="Remove file"):
|
| 2997 |
st.session_state.pending_file_bytes = None
|
| 2998 |
st.session_state.pending_file_name = None
|
| 2999 |
st.session_state.pending_file_mime = None
|
| 3000 |
st.session_state["last_uploaded_file"] = ""
|
|
|
|
| 3001 |
st.rerun()
|
|
|
|
| 3002 |
elif _memfile:
|
| 3003 |
-
|
| 3004 |
-
with
|
| 3005 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3006 |
st.session_state.attached_file_bytes = None
|
| 3007 |
st.session_state.attached_file_name = None
|
| 3008 |
st.session_state.attached_file_mime = None
|
| 3009 |
st.rerun()
|
| 3010 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3011 |
# βββββββββββββββοΏ½οΏ½οΏ½ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 3012 |
# INPUT β ChatGPT-style input bar
|
| 3013 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 406 |
st.session_state.attached_file_name = None
|
| 407 |
if "attached_file_mime" not in st.session_state:
|
| 408 |
st.session_state.attached_file_mime = None
|
| 409 |
+
if "show_uploader" not in st.session_state:
|
| 410 |
+
st.session_state.show_uploader = False
|
| 411 |
|
| 412 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 413 |
# SUPABASE β Persistent chat history
|
|
|
|
| 2860 |
st.code(msg["content"], language=None)
|
| 2861 |
|
| 2862 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2863 |
+
# FILE ATTACH β FIXED: real Streamlit button toggle (no JS tricks)
|
| 2864 |
+
# Works reliably on HuggingFace Spaces β no iframe/JS issues
|
| 2865 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2866 |
|
| 2867 |
+
_pending = st.session_state.pending_file_bytes is not None
|
| 2868 |
+
_memfile = st.session_state.attached_file_name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2869 |
|
| 2870 |
+
# ββ Status bar βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2871 |
if _pending:
|
| 2872 |
+
col_s, col_x = st.columns([9, 1])
|
| 2873 |
+
with col_s:
|
| 2874 |
+
st.markdown(
|
| 2875 |
+
f'<div style="background:#0d2318;border:1px solid #22c55e;border-radius:10px;'
|
| 2876 |
+
f'padding:0.5rem 0.9rem;font-size:0.8rem;color:#86efac;margin-bottom:0.3rem;">'
|
| 2877 |
+
f'β
<b>{st.session_state.pending_file_name}</b> β ready Β· type your question and press Enter</div>',
|
| 2878 |
+
unsafe_allow_html=True
|
| 2879 |
+
)
|
| 2880 |
+
with col_x:
|
| 2881 |
+
if st.button("β", key="rm_pending", help="Remove file"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2882 |
st.session_state.pending_file_bytes = None
|
| 2883 |
st.session_state.pending_file_name = None
|
| 2884 |
st.session_state.pending_file_mime = None
|
| 2885 |
st.session_state["last_uploaded_file"] = ""
|
| 2886 |
+
st.session_state.show_uploader = False
|
| 2887 |
st.rerun()
|
| 2888 |
+
|
| 2889 |
elif _memfile:
|
| 2890 |
+
col_s, col_x = st.columns([9, 1])
|
| 2891 |
+
with col_s:
|
| 2892 |
+
st.markdown(
|
| 2893 |
+
f'<div style="background:#0d1a2e;border:1px solid #3b82f6;border-radius:10px;'
|
| 2894 |
+
f'padding:0.5rem 0.9rem;font-size:0.8rem;color:#93c5fd;margin-bottom:0.3rem;">'
|
| 2895 |
+
f'π <b>{_memfile}</b> in memory β ask a follow-up or click π to attach new</div>',
|
| 2896 |
+
unsafe_allow_html=True
|
| 2897 |
+
)
|
| 2898 |
+
with col_x:
|
| 2899 |
+
if st.button("β", key="rm_attached", help="Clear file memory"):
|
| 2900 |
st.session_state.attached_file_bytes = None
|
| 2901 |
st.session_state.attached_file_name = None
|
| 2902 |
st.session_state.attached_file_mime = None
|
| 2903 |
st.rerun()
|
| 2904 |
|
| 2905 |
+
# ββ π Attach toggle button ββββββββββββββββββββββββββββββββββββββββββ
|
| 2906 |
+
attach_col, _ = st.columns([1, 8])
|
| 2907 |
+
with attach_col:
|
| 2908 |
+
btn_label = "π Attached" if (st.session_state.show_uploader or _pending) else "π Attach"
|
| 2909 |
+
if st.button(btn_label, key="toggle_uploader", help="Attach image or PDF"):
|
| 2910 |
+
st.session_state.show_uploader = not st.session_state.show_uploader
|
| 2911 |
+
st.rerun()
|
| 2912 |
+
|
| 2913 |
+
# ββ Real file uploader β only shown when toggled on ββββββββββββββββββ
|
| 2914 |
+
if st.session_state.show_uploader and not _pending:
|
| 2915 |
+
uploaded = st.file_uploader(
|
| 2916 |
+
"Upload image or PDF",
|
| 2917 |
+
type=["jpg", "jpeg", "png", "webp", "pdf"],
|
| 2918 |
+
label_visibility="collapsed",
|
| 2919 |
+
key="main_uploader"
|
| 2920 |
+
)
|
| 2921 |
+
if uploaded is not None:
|
| 2922 |
+
_fkey = f"{uploaded.size}_{uploaded.type}_{uploaded.name}"
|
| 2923 |
+
if _fkey != st.session_state.get("last_uploaded_file", ""):
|
| 2924 |
+
st.session_state["last_uploaded_file"] = _fkey
|
| 2925 |
+
st.session_state.pending_file_bytes = uploaded.read()
|
| 2926 |
+
st.session_state.pending_file_name = uploaded.name
|
| 2927 |
+
st.session_state.pending_file_mime = uploaded.type or "application/octet-stream"
|
| 2928 |
+
st.session_state.show_uploader = False
|
| 2929 |
+
st.rerun()
|
| 2930 |
+
|
| 2931 |
# βββββββββββββββοΏ½οΏ½οΏ½ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2932 |
# INPUT β ChatGPT-style input bar
|
| 2933 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|