File size: 7,703 Bytes
9d3281a
7894107
 
9d3281a
 
 
 
7894107
 
 
 
 
 
 
 
 
 
 
 
9d3281a
 
 
 
 
 
 
93b9aec
 
 
9d3281a
93b9aec
 
9d3281a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7894107
 
 
 
9d3281a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7894107
9d3281a
 
 
7894107
9d3281a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7894107
 
 
 
 
 
 
9d3281a
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
import streamlit as st
import time
import os
from supabase import create_client
from datetime import datetime
from zoneinfo import ZoneInfo
from supabase_auth.errors import AuthApiError
from transformers import pipeline


@st.cache_resource
def load_sentiment_model():
    return pipeline(
        "sentiment-analysis",
        model="wonrax/phobert-base-vietnamese-sentiment"
    )
sentiment_model = load_sentiment_model()


# ========== CONFIG ==========
st.set_page_config(
    page_title="Personal Diary",
    page_icon="📔",
    layout="wide"
)

SUPABASE_URL = os.environ.get("SUPABASE_URL")
SUPABASE_KEY = os.environ.get("SUPABASE_KEY")

supabase = create_client(
    SUPABASE_URL,
    SUPABASE_KEY
)

# ========== STYLE ==========
st.markdown("""

<style>

.diary-card {

    padding: 1rem;

    border-radius: 12px;

    background-color: #f8f9fa;

    margin-bottom: 1rem;

}

.small-text {

    font-size: 0.8rem;

    color: #6c757d;

}

</style>

""", unsafe_allow_html=True)

def signup(email, password):
    return supabase.auth.sign_up({
        "email": email,
        "password": password
    })

def analyze_sentiment(text: str) -> str:
    result = sentiment_model(text)[0]
    return result["label"]  # POS / NEG / NEU


# ========== HEADER ==========
st.title("📔 Personal Diary")
st.caption("Ghi chép suy nghĩ mỗi ngày – phiên bản demo")

# ========== LOGIN ==========
if "user" not in st.session_state:
    st.subheader("🔐 Tài khoản")

    tab_login, tab_signup = st.tabs(["Đăng nhập", "Đăng ký"])

    # ===== LOGIN =====
    with tab_login:
        email = st.text_input("Email", key="login_email")
        password = st.text_input("Mật khẩu", type="password", key="login_pw")

        if st.button("➡️ Đăng nhập", use_container_width=True):
            res = supabase.auth.sign_in_with_password({
                "email": email,
                "password": password
            })

            if res.user:
                st.session_state.user = res.user
                st.success("Đăng nhập thành công")
                st.rerun()
            else:
                st.error("Sai email hoặc mật khẩu")

    # ===== SIGNUP =====
    with tab_signup:
        email = st.text_input("Email đăng ký", key="signup_email")
        password = st.text_input(
            "Mật khẩu (tối thiểu 6 ký tự)",
            type="password",
            key="signup_pw"
        )

        # init cooldown
        if "signup_cooldown_until" not in st.session_state:
            st.session_state.signup_cooldown_until = 0

        now = time.time()
        cooldown_left = int(st.session_state.signup_cooldown_until - now)

        if cooldown_left > 0:
            st.warning(f"⏳ Vui lòng thử lại sau {cooldown_left} giây")

        signup_disabled = cooldown_left > 0

        if st.button(
                "🆕 Tạo tài khoản",
                use_container_width=True,
                disabled=signup_disabled
        ):
            try:
                res = signup(email, password)

                if res.user:
                    st.session_state.user = res.user
                    st.success("Đăng ký thành công 🎉")
                    st.rerun()
                else:
                    st.error("Không thể đăng ký")

            except AuthApiError as e:
                msg = str(e)

                # Bắt lỗi rate limit 60s
                if "only request this after" in msg:
                    # Mặc định 60s nếu parse không được
                    wait_seconds = 60

                    # cố gắng parse số giây từ message
                    import re

                    match = re.search(r"after (\d+) seconds", msg)
                    if match:
                        wait_seconds = int(match.group(1))

                    st.session_state.signup_cooldown_until = time.time() + wait_seconds
                    st.error(f"🚫 Bạn đã thử quá nhiều lần. Vui lòng đợi {wait_seconds} giây rồi thử lại.")
                    st.rerun()
                else:
                    st.error("Lỗi đăng ký: " + msg)


# ========== MAIN APP ==========
else:
    user = st.session_state.user

    # Top bar
    top_left, top_right = st.columns([4, 1])
    with top_left:
        st.markdown(f"👋 Xin chào **{user.email}**")
    with top_right:
        if st.button("🚪 Đăng xuất", use_container_width=True):
            st.session_state.clear()
            st.rerun()

    st.divider()

    # Main layout
    left, right = st.columns([2, 3])

    # ===== LEFT: WRITE =====
    with left:
        st.subheader("✍️ Viết nhật ký")

        content = st.text_area(
            "Hôm nay bạn nghĩ gì?",
            height=250,
            placeholder="Viết suy nghĩ của bạn ở đây..."
        )

        if st.button("💾 Lưu nhật ký", use_container_width=True):
            if content.strip():
                sentiment = analyze_sentiment(content)
                supabase.table("journals").insert({
                    "user_id": user.id,
                    "content": content,
                    "sentiment": sentiment,
                    "created_at": datetime.utcnow().isoformat()
                }).execute()

                st.success("Đã lưu nhật ký ✨")
                st.rerun()
            else:
                st.warning("Nội dung đang trống")

    # ===== RIGHT: LIST =====
    with right:
        st.subheader("📜 Nhật ký của bạn")

        data = supabase.table("journals") \
            .select("*") \
            .eq("user_id", user.id) \
            .order("created_at", desc=True) \
            .execute()

        if not data.data:
            st.info("Chưa có nhật ký nào")
        else:
            for row in data.data:
                # Format ngày cho gọn
                created_dt = datetime.fromisoformat(
                    row["created_at"].replace("Z", "+00:00")
                ).astimezone(ZoneInfo("Asia/Ho_Chi_Minh"))

                date_label = created_dt.strftime("%d/%m/%Y – %H:%M")

                # Dropdown theo ngày
                with st.expander(f"📅 {date_label}", expanded=False):

                    new_content = st.text_area(
                        "Nội dung",
                        row["content"],
                        key=row["id"],
                        height=120
                    )
                    sentiment = row.get("sentiment", "N/A")
                    emoji_map = {
                        "Vui vẻ": "😊",
                        "Buồn": "😔",
                        "Trung tính": "😐"
                    }
                    st.caption(f"Cảm xúc: {emoji_map.get(sentiment, '❓')} {sentiment}")

                    col_u, col_d = st.columns(2)

                    if col_u.button("✏️ Cập nhật", key=f"u{row['id']}"):
                        supabase.table("journals").update({
                            "content": new_content,
                            "updated_at": datetime.utcnow().isoformat()
                        }).eq("id", row["id"]).execute()
                        st.rerun()

                    if col_d.button("🗑️ Xoá", key=f"d{row['id']}"):
                        supabase.table("journals").delete() \
                            .eq("id", row["id"]).execute()
                        st.rerun()