File size: 9,096 Bytes
60d1d13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
243
244
245
246
247
"""
Trợ lý AI ViettelPay - Giao diện Streamlit cho cuộc trò chuyện đa lượt
"""

import streamlit as st
import os
import uuid
import time

# For backward compatibility with local development using .env files
try:
    from dotenv import load_dotenv

    load_dotenv()
except ImportError:
    pass  # dotenv not required in production

# Simple page config
st.set_page_config(page_title="Trợ lý AI ViettelPay", page_icon="💳", layout="centered")

# Header
st.title("💳 Trợ lý AI ViettelPay")
st.caption("Trợ lý ảo hỗ trợ dịch vụ ViettelPay Pro - Cuộc trò chuyện đa lượt")

# Initialize session state
if "messages" not in st.session_state:
    st.session_state.messages = []

if "agent" not in st.session_state:
    st.session_state.agent = None

if "agent_initialization_status" not in st.session_state:
    st.session_state.agent_initialization_status = "not_started"

if "thread_id" not in st.session_state:
    # Generate a unique thread ID for this session
    st.session_state.thread_id = str(uuid.uuid4())[:8]

if "conversation_started" not in st.session_state:
    st.session_state.conversation_started = False


@st.cache_resource
def initialize_agent():
    """Khởi tạo agent ViettelPay với bộ nhớ đệm"""
    try:
        from src.agent.viettelpay_agent import ViettelPayAgent

        return ViettelPayAgent()
    except Exception as e:
        st.error(f"❌ Lỗi khởi tạo agent: {str(e)}")
        return None


# Auto-initialize agent when app starts
if (
    st.session_state.agent is None
    and st.session_state.agent_initialization_status == "not_started"
):
    st.session_state.agent_initialization_status = "initializing"

    with st.spinner("🚀 Đang khởi tạo Trợ lý AI ViettelPay..."):
        st.session_state.agent = initialize_agent()
        if st.session_state.agent:
            st.session_state.agent_initialization_status = "success"
            st.success("✅ Khởi tạo agent thành công!")
        else:
            st.session_state.agent_initialization_status = "failed"
            st.error("❌ Khởi tạo agent thất bại")

# Sidebar
with st.sidebar:
    st.header("🛠️ Điều khiển")

    # Agent status
    if st.session_state.agent_initialization_status == "initializing":
        st.info("🔄 Đang khởi tạo agent...")
    elif st.session_state.agent_initialization_status == "success":
        st.success("✅ Agent đã sẵn sàng!")

        # Health check
        if st.button("🏥 Kiểm tra tình trạng"):
            try:
                health = st.session_state.agent.health_check()
                for component, status in health.items():
                    if component != "overall":
                        icon = "✅" if status else "❌"
                        st.write(f"{icon} {component}")
            except Exception as e:
                st.error(f"Kiểm tra tình trạng thất bại: {e}")

    elif st.session_state.agent_initialization_status == "failed":
        st.error("❌ Khởi tạo agent thất bại")
        if st.button("🔄 Thử lại khởi tạo"):
            st.session_state.agent_initialization_status = "not_started"
            st.session_state.agent = None
            st.rerun()

    st.divider()

    # Conversation Management
    st.subheader("💬 Cuộc trò chuyện")

    # Show current thread ID
    st.write(f"**ID Cuộc trò chuyện:** `{st.session_state.thread_id}`")

    # Show conversation stats
    if st.session_state.agent and st.session_state.conversation_started:
        try:
            history = st.session_state.agent.get_conversation_history(
                st.session_state.thread_id
            )
            st.write(f"**Số tin nhắn:** {len(history)}")
        except:
            st.write("**Số tin nhắn:** Không thể đếm")

    # Clear current conversation
    if st.button("🗑️ Xóa cuộc trò chuyện"):
        st.session_state.messages = []
        st.session_state.conversation_started = False
        if st.session_state.agent:
            st.session_state.agent.clear_conversation(st.session_state.thread_id)
        st.rerun()

    # Start new conversation
    if st.button("🆕 Cuộc trò chuyện mới"):
        st.session_state.messages = []
        st.session_state.thread_id = str(uuid.uuid4())[:8]
        st.session_state.conversation_started = False
        st.rerun()

    st.divider()

    # Conversation History Viewer
    if st.session_state.agent and st.session_state.conversation_started:
        st.subheader("📜 Lịch sử")
        if st.button("🔍 Xem toàn bộ lịch sử"):
            try:
                history = st.session_state.agent.get_conversation_history(
                    st.session_state.thread_id
                )
                with st.expander("Lịch sử cuộc trò chuyện đầy đủ", expanded=True):
                    for i, msg in enumerate(history, 1):
                        role_icon = "👤" if msg["role"] == "user" else "🤖"
                        role_text = "Người dùng" if msg["role"] == "user" else "Trợ lý"
                        st.write(f"{i}. {role_icon} **{role_text}:** {msg['content']}")
            except Exception as e:
                st.error(f"Lỗi tải lịch sử: {e}")

# Main chat area
st.subheader("💬 Trò chuyện")

# Display messages
for msg in st.session_state.messages:
    if msg["role"] == "user":
        with st.chat_message("user"):
            st.write(msg["content"])
    elif msg["role"] == "assistant":
        with st.chat_message("assistant"):
            st.write(msg["content"])
            # Show metadata if available
            if "metadata" in msg:
                with st.expander("📊 Chi tiết"):
                    metadata = msg["metadata"]
                    col1, col2, col3 = st.columns(3)
                    with col1:
                        st.metric("Ý định", metadata.get("intent", "không xác định"))
                    with col2:
                        st.metric("Độ tin cậy", f"{metadata.get('confidence', 0):.2f}")
                    with col3:
                        st.metric(
                            "Loại", metadata.get("response_type", "không xác định")
                        )

                    # Show enhanced query if available and different from original
                    if metadata.get("enhanced_query"):
                        st.write(
                            f"**🚀 Câu hỏi được tối ưu:** {metadata['enhanced_query']}"
                        )

                    if metadata.get("thread_id"):
                        st.write(f"**Cuộc trò chuyện:** {metadata['thread_id']}")
                    if metadata.get("message_count"):
                        st.write(f"**Tổng số tin nhắn:** {metadata['message_count']}")
    elif msg["role"] == "error":
        st.error(msg["content"])

# Chat input
if prompt := st.chat_input("Nhập câu hỏi của bạn..."):
    if st.session_state.agent is None:
        st.error("Vui lòng đợi quá trình khởi tạo agent hoàn thành!")
        st.stop()

    # Mark conversation as started
    st.session_state.conversation_started = True

    # Add user message
    st.session_state.messages.append({"role": "user", "content": prompt})

    # Process message
    try:
        with st.spinner("Đang xử lý..."):
            # Use the session's thread_id for conversation continuity

            # Check the time processing
            start_time = time.time()
            result = st.session_state.agent.process_message(
                prompt, st.session_state.thread_id
            )
            end_time = time.time()
            processing_time = end_time - start_time
            print(f"Thời gian xử lý: {processing_time:.2f} giây")

            # Add response
            st.session_state.messages.append(
                {
                    "role": "assistant",
                    "content": result["response"],
                    "metadata": {
                        "intent": result.get("intent"),
                        "confidence": result.get("confidence"),
                        "response_type": result.get("response_type"),
                        "enhanced_query": result.get("enhanced_query"),
                        "success": result.get("success"),
                        "thread_id": result.get("thread_id"),
                        "message_count": result.get("message_count"),
                    },
                }
            )

            if result.get("error"):
                st.session_state.messages.append(
                    {"role": "error", "content": f"Lỗi: {result['error']}"}
                )

    except Exception as e:
        st.session_state.messages.append(
            {"role": "error", "content": f"Lỗi hệ thống: {str(e)}"}
        )

    st.rerun()

# Footer
st.caption(
    "🚀 Được hỗ trợ bởi LangGraph & Gemini AI | Cuộc trò chuyện đa lượt với InMemorySaver"
)