ntphuc149 commited on
Commit
a54671e
·
verified ·
1 Parent(s): f998e73

feat: login FB and subscrie app

Browse files
Files changed (1) hide show
  1. app.py +353 -239
app.py CHANGED
@@ -5,6 +5,14 @@ import streamlit as st
5
 
6
  st.set_page_config(page_title="ViBidLQA - Trợ lý AI hỗ trợ hỏi đáp luật Việt Nam", page_icon="./app/static/ai.jpg", layout="centered", initial_sidebar_state="collapsed")
7
 
 
 
 
 
 
 
 
 
8
  routing_response_module = st.secrets["ViBidLQA_Routing_Module"]
9
  retrieval_module = st.secrets["ViBidLQA_Retrieval_Module"]
10
  reranker_module = st.secrets["ViBidLQA_Rerank_Module"]
@@ -20,256 +28,362 @@ url_api_generation_model = f"{abs_QA_module}/answer"
20
 
21
  with open("./static/styles.css") as f:
22
  st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)
23
-
24
- if 'messages' not in st.session_state:
25
- st.session_state.messages = [{'role': 'assistant', 'content': "Xin chào. Tôi là trợ lý AI văn bản luật Đấu thầu Việt Nam được phát triển bởi Nguyễn Trường Phúc và các cộng sự. Rất vui khi được hỗ trợ bạn trong các vấn đề pháp lý tại Việt Nam!"}]
26
-
27
- st.markdown(f"""
28
- <div class=logo_area>
29
- <img src="./app/static/ai.jpg"/>
30
- </div>
31
- """, unsafe_allow_html=True)
32
- st.markdown("<h2 style='text-align: center;'>ViBidLQA</h2>", unsafe_allow_html=True)
33
-
34
- def classify_question(question):
35
- data = {
36
- "question": question
37
- }
38
-
39
- response = requests.post(url_api_question_classify_model, json=data)
40
-
41
- if response.status_code == 200:
42
- print(response)
43
- return response
44
- else:
45
- return f"Lỗi: {response.status_code} - {response.text}"
46
-
47
- def introduce_system(question):
48
- data = {
49
- "question": question
50
- }
51
-
52
- response = requests.post(url_api_introduce_system_model, json=data, stream=True)
53
-
54
- if response.status_code == 200:
55
- return response
56
- else:
57
- return f"Lỗi: {response.status_code} - {response.text}"
58
-
59
- def response_unrelated_question(question):
60
- data = {
61
- "question": question
62
- }
63
-
64
- response = requests.post(url_api_unrelated_question_response_model, json=data, stream=True)
65
-
66
- if response.status_code == 200:
67
- return response
68
- else:
69
- return f"Lỗi: {response.status_code} - {response.text}"
70
-
71
- def retrieve_context(question, top_k=10):
72
- data = {
73
- "query": question,
74
- "top_k": top_k
75
- }
76
-
77
- response = requests.post(url_api_retrieval_model, json=data)
78
-
79
- if response.status_code == 200:
80
- results = response.json()["results"]
81
- return results
82
- else:
83
- return f"Lỗi tại Retrieval Module: {response.status_code} - {response.text}"
84
-
85
- def rerank_context(url_rerank_module, question, relevant_docs, top_k=5):
86
- data = {
87
- "question": question,
88
- "relevant_docs": relevant_docs,
89
- "top_k": top_k
90
- }
91
-
92
- response = requests.post(url_rerank_module, json=data)
93
-
94
- if response.status_code == 200:
95
- results = response.json()["reranked_docs"]
96
- return results
97
- else:
98
- return f"Lỗi tại Rerank module: {response.status_code} - {response.text}"
99
-
100
- def get_abstractive_answer(question):
101
- retrieved_context = retrieve_context(question=question)
102
- retrieved_context = [item['text'] for item in retrieved_context]
103
 
104
- reranked_context = rerank_context(url_rerank_module=url_api_reranker_model,
105
- question=question,
106
- relevant_docs=retrieved_context,
107
- top_k=5)[0]
 
 
108
 
109
- data = {
110
- "context": reranked_context,
111
- "question": question
112
- }
113
-
114
- response = requests.post(url_api_generation_model, json=data, stream=True)
115
-
116
- if response.status_code == 200:
117
- return response
118
- else:
119
- return f"Lỗi: {response.status_code} - {response.text}"
120
-
121
- def generate_text_effect(answer):
122
- words = answer.split()
123
- for i in range(len(words)):
124
- time.sleep(0.03)
125
- yield " ".join(words[:i+1])
126
-
127
- for message in st.session_state.messages:
128
- if message['role'] == 'assistant':
129
- avatar_class = "assistant-avatar"
130
- message_class = "assistant-message"
131
- avatar = './app/static/ai.jpg'
132
- else:
133
- avatar_class = ""
134
- message_class = "user-message"
135
- avatar = ''
136
  st.markdown(f"""
137
- <div class="{message_class}">
138
- <img src="{avatar}" class="{avatar_class}" />
139
- <div class="stMarkdown">{message['content']}</div>
140
  </div>
141
  """, unsafe_allow_html=True)
142
-
143
- if prompt := st.chat_input(placeholder='Tôi có thể giúp được gì cho bạn?'):
144
- st.markdown(f"""
145
- <div class="user-message">
146
- <div class="stMarkdown">{prompt}</div>
147
- </div>
148
- """, unsafe_allow_html=True)
149
- st.session_state.messages.append({'role': 'user', 'content': prompt})
150
 
151
- message_placeholder = st.empty()
 
 
 
 
 
 
 
 
 
 
 
152
 
153
- full_response = ""
154
- classify_result = classify_question(question=prompt).json()
155
-
156
- print(f"The type of user query: {classify_result}")
157
-
158
- if classify_result == "BIDDING_RELATED":
159
- abs_answer = get_abstractive_answer(question=prompt)
160
-
161
- if isinstance(abs_answer, str):
162
- full_response = abs_answer
163
- message_placeholder.markdown(f"""
164
- <div class="assistant-message">
165
- <img src="./app/static/ai.jpg" class="assistant-avatar" />
166
- <div class="stMarkdown">{full_response}</div>
167
- </div>
168
- """, unsafe_allow_html=True)
169
  else:
170
- full_response = ""
171
- for line in abs_answer.iter_lines():
172
- if line:
173
- line = line.decode('utf-8')
174
- if line.startswith('data: '):
175
- data_str = line[6:]
176
- if data_str == '[DONE]':
177
- break
178
-
179
- try:
180
- data = json.loads(data_str)
181
- token = data.get('token', '')
182
- full_response += token
183
-
184
- message_placeholder.markdown(f"""
185
- <div class="assistant-message">
186
- <img src="./app/static/ai.jpg" class="assistant-avatar" />
187
- <div class="stMarkdown">{full_response}●</div>
188
- </div>
189
- """, unsafe_allow_html=True)
190
-
191
- except json.JSONDecodeError:
192
- pass
193
-
194
- elif classify_result == "ABOUT_CHATBOT":
195
- answer = introduce_system(question=prompt)
196
-
197
- if isinstance(answer, str):
198
- full_response = answer
199
- message_placeholder.markdown(f"""
200
- <div class="assistant-message">
201
- <img src="./app/static/ai.jpg" class="assistant-avatar" />
202
- <div class="stMarkdown">{full_response}</div>
203
- </div>
204
- """, unsafe_allow_html=True)
205
  else:
206
- full_response = ""
207
- for line in answer.iter_lines():
208
- if line:
209
- line = line.decode('utf-8')
210
- if line.startswith('data: '):
211
- data_str = line[6:]
212
- if data_str == '[DONE]':
213
- break
214
-
215
- try:
216
- data = json.loads(data_str)
217
- token = data.get('token', '')
218
- full_response += token
219
-
220
- message_placeholder.markdown(f"""
221
- <div class="assistant-message">
222
- <img src="./app/static/ai.jpg" class="assistant-avatar" />
223
- <div class="stMarkdown">{full_response}●</div>
224
- </div>
225
- """, unsafe_allow_html=True)
226
-
227
- except json.JSONDecodeError:
228
- pass
229
 
230
- else:
231
- answer = response_unrelated_question(question=prompt)
232
-
233
- if isinstance(answer, str):
234
- full_response = answer
235
- message_placeholder.markdown(f"""
236
- <div class="assistant-message">
237
- <img src="./app/static/ai.jpg" class="assistant-avatar" />
238
- <div class="stMarkdown">{full_response}</div>
239
- </div>
240
- """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  else:
242
- full_response = ""
243
- for line in answer.iter_lines():
244
- if line:
245
- line = line.decode('utf-8')
246
- if line.startswith('data: '):
247
- data_str = line[6:]
248
- if data_str == '[DONE]':
249
- break
250
-
251
- try:
252
- data = json.loads(data_str)
253
- token = data.get('token', '')
254
- full_response += token
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
 
256
- message_placeholder.markdown(f"""
257
- <div class="assistant-message">
258
- <img src="./app/static/ai.jpg" class="assistant-avatar" />
259
- <div class="stMarkdown">{full_response}●</div>
260
- </div>
261
- """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
 
263
- except json.JSONDecodeError:
264
- pass
265
-
266
- message_placeholder.markdown(f"""
267
- <div class="assistant-message">
268
- <img src="./app/static/ai.jpg" class="assistant-avatar" />
269
- <div class="stMarkdown">
270
- {full_response}
271
- </div>
272
- </div>
273
- """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
 
275
- st.session_state.messages.append({'role': 'assistant', 'content': full_response})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  st.set_page_config(page_title="ViBidLQA - Trợ lý AI hỗ trợ hỏi đáp luật Việt Nam", page_icon="./app/static/ai.jpg", layout="centered", initial_sidebar_state="collapsed")
7
 
8
+ # ==== MÔI TRƯỜNG OAuth ====
9
+ FB_APP_ID = os.getenv("FB_APP_ID")
10
+ FB_APP_SECRET = os.getenv("FB_APP_SECRET")
11
+ FB_REDIRECT_URI = os.getenv("FB_REDIRECT_URI")
12
+ FB_CLIENT_URL = os.getenv("FB_CLIENT_URL", "https://www.facebook.com")
13
+ FB_API_URL = os.getenv("FB_API_URL", "https://graph.facebook.com")
14
+
15
+ # ==== MODULE URL ====
16
  routing_response_module = st.secrets["ViBidLQA_Routing_Module"]
17
  retrieval_module = st.secrets["ViBidLQA_Retrieval_Module"]
18
  reranker_module = st.secrets["ViBidLQA_Rerank_Module"]
 
28
 
29
  with open("./static/styles.css") as f:
30
  st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ # =============================
33
+ # TAB 1: VIBIDLQA CHATBOT
34
+ # =============================
35
+ with tab1:
36
+ if 'messages' not in st.session_state:
37
+ st.session_state.messages = [{'role': 'assistant', 'content': "Xin chào. Tôi là trợ lý AI văn bản luật Đấu thầu Việt Nam được phát triển bởi Nguyễn Trường Phúc và các cộng sự. Rất vui khi được hỗ trợ bạn trong các vấn đề pháp lý tại Việt Nam!"}]
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  st.markdown(f"""
40
+ <div class=logo_area>
41
+ <img src="./app/static/ai.jpg"/>
 
42
  </div>
43
  """, unsafe_allow_html=True)
44
+ st.markdown("<h2 style='text-align: center;'>ViBidLQA</h2>", unsafe_allow_html=True)
 
 
 
 
 
 
 
45
 
46
+ def classify_question(question):
47
+ data = {
48
+ "question": question
49
+ }
50
+
51
+ response = requests.post(url_api_question_classify_model, json=data)
52
+
53
+ if response.status_code == 200:
54
+ print(response)
55
+ return response
56
+ else:
57
+ return f"Lỗi: {response.status_code} - {response.text}"
58
 
59
+ def introduce_system(question):
60
+ data = {
61
+ "question": question
62
+ }
63
+
64
+ response = requests.post(url_api_introduce_system_model, json=data, stream=True)
65
+
66
+ if response.status_code == 200:
67
+ return response
 
 
 
 
 
 
 
68
  else:
69
+ return f"Lỗi: {response.status_code} - {response.text}"
70
+
71
+ def response_unrelated_question(question):
72
+ data = {
73
+ "question": question
74
+ }
75
+
76
+ response = requests.post(url_api_unrelated_question_response_model, json=data, stream=True)
77
+
78
+ if response.status_code == 200:
79
+ return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  else:
81
+ return f"Lỗi: {response.status_code} - {response.text}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
+ def retrieve_context(question, top_k=10):
84
+ data = {
85
+ "query": question,
86
+ "top_k": top_k
87
+ }
88
+
89
+ response = requests.post(url_api_retrieval_model, json=data)
90
+
91
+ if response.status_code == 200:
92
+ results = response.json()["results"]
93
+ return results
94
+ else:
95
+ return f"Lỗi tại Retrieval Module: {response.status_code} - {response.text}"
96
+
97
+ def rerank_context(url_rerank_module, question, relevant_docs, top_k=5):
98
+ data = {
99
+ "question": question,
100
+ "relevant_docs": relevant_docs,
101
+ "top_k": top_k
102
+ }
103
+
104
+ response = requests.post(url_rerank_module, json=data)
105
+
106
+ if response.status_code == 200:
107
+ results = response.json()["reranked_docs"]
108
+ return results
109
+ else:
110
+ return f"Lỗi tại Rerank module: {response.status_code} - {response.text}"
111
+
112
+ def get_abstractive_answer(question):
113
+ retrieved_context = retrieve_context(question=question)
114
+ retrieved_context = [item['text'] for item in retrieved_context]
115
+
116
+ reranked_context = rerank_context(url_rerank_module=url_api_reranker_model,
117
+ question=question,
118
+ relevant_docs=retrieved_context,
119
+ top_k=5)[0]
120
+
121
+ data = {
122
+ "context": reranked_context,
123
+ "question": question
124
+ }
125
+
126
+ response = requests.post(url_api_generation_model, json=data, stream=True)
127
+
128
+ if response.status_code == 200:
129
+ return response
130
  else:
131
+ return f"Lỗi: {response.status_code} - {response.text}"
132
+
133
+ def generate_text_effect(answer):
134
+ words = answer.split()
135
+ for i in range(len(words)):
136
+ time.sleep(0.03)
137
+ yield " ".join(words[:i+1])
138
+
139
+ for message in st.session_state.messages:
140
+ if message['role'] == 'assistant':
141
+ avatar_class = "assistant-avatar"
142
+ message_class = "assistant-message"
143
+ avatar = './app/static/ai.jpg'
144
+ else:
145
+ avatar_class = ""
146
+ message_class = "user-message"
147
+ avatar = ''
148
+ st.markdown(f"""
149
+ <div class="{message_class}">
150
+ <img src="{avatar}" class="{avatar_class}" />
151
+ <div class="stMarkdown">{message['content']}</div>
152
+ </div>
153
+ """, unsafe_allow_html=True)
154
+
155
+ if prompt := st.chat_input(placeholder='Tôi có thể giúp được gì cho bạn?'):
156
+ st.markdown(f"""
157
+ <div class="user-message">
158
+ <div class="stMarkdown">{prompt}</div>
159
+ </div>
160
+ """, unsafe_allow_html=True)
161
+ st.session_state.messages.append({'role': 'user', 'content': prompt})
162
+
163
+ message_placeholder = st.empty()
164
+
165
+ full_response = ""
166
+ classify_result = classify_question(question=prompt).json()
167
+
168
+ print(f"The type of user query: {classify_result}")
169
+
170
+ if classify_result == "BIDDING_RELATED":
171
+ abs_answer = get_abstractive_answer(question=prompt)
172
+
173
+ if isinstance(abs_answer, str):
174
+ full_response = abs_answer
175
+ message_placeholder.markdown(f"""
176
+ <div class="assistant-message">
177
+ <img src="./app/static/ai.jpg" class="assistant-avatar" />
178
+ <div class="stMarkdown">{full_response}</div>
179
+ </div>
180
+ """, unsafe_allow_html=True)
181
+ else:
182
+ full_response = ""
183
+ for line in abs_answer.iter_lines():
184
+ if line:
185
+ line = line.decode('utf-8')
186
+ if line.startswith('data: '):
187
+ data_str = line[6:]
188
+ if data_str == '[DONE]':
189
+ break
190
 
191
+ try:
192
+ data = json.loads(data_str)
193
+ token = data.get('token', '')
194
+ full_response += token
195
+
196
+ message_placeholder.markdown(f"""
197
+ <div class="assistant-message">
198
+ <img src="./app/static/ai.jpg" class="assistant-avatar" />
199
+ <div class="stMarkdown">{full_response}●</div>
200
+ </div>
201
+ """, unsafe_allow_html=True)
202
+
203
+ except json.JSONDecodeError:
204
+ pass
205
+
206
+ elif classify_result == "ABOUT_CHATBOT":
207
+ answer = introduce_system(question=prompt)
208
+
209
+ if isinstance(answer, str):
210
+ full_response = answer
211
+ message_placeholder.markdown(f"""
212
+ <div class="assistant-message">
213
+ <img src="./app/static/ai.jpg" class="assistant-avatar" />
214
+ <div class="stMarkdown">{full_response}</div>
215
+ </div>
216
+ """, unsafe_allow_html=True)
217
+ else:
218
+ full_response = ""
219
+ for line in answer.iter_lines():
220
+ if line:
221
+ line = line.decode('utf-8')
222
+ if line.startswith('data: '):
223
+ data_str = line[6:]
224
+ if data_str == '[DONE]':
225
+ break
226
 
227
+ try:
228
+ data = json.loads(data_str)
229
+ token = data.get('token', '')
230
+ full_response += token
231
+
232
+ message_placeholder.markdown(f"""
233
+ <div class="assistant-message">
234
+ <img src="./app/static/ai.jpg" class="assistant-avatar" />
235
+ <div class="stMarkdown">{full_response}●</div>
236
+ </div>
237
+ """, unsafe_allow_html=True)
238
+
239
+ except json.JSONDecodeError:
240
+ pass
241
+
242
+ else:
243
+ answer = response_unrelated_question(question=prompt)
244
+
245
+ if isinstance(answer, str):
246
+ full_response = answer
247
+ message_placeholder.markdown(f"""
248
+ <div class="assistant-message">
249
+ <img src="./app/static/ai.jpg" class="assistant-avatar" />
250
+ <div class="stMarkdown">{full_response}</div>
251
+ </div>
252
+ """, unsafe_allow_html=True)
253
+ else:
254
+ full_response = ""
255
+ for line in answer.iter_lines():
256
+ if line:
257
+ line = line.decode('utf-8')
258
+ if line.startswith('data: '):
259
+ data_str = line[6:]
260
+ if data_str == '[DONE]':
261
+ break
262
+
263
+ try:
264
+ data = json.loads(data_str)
265
+ token = data.get('token', '')
266
+ full_response += token
267
+
268
+ message_placeholder.markdown(f"""
269
+ <div class="assistant-message">
270
+ <img src="./app/static/ai.jpg" class="assistant-avatar" />
271
+ <div class="stMarkdown">{full_response}●</div>
272
+ </div>
273
+ """, unsafe_allow_html=True)
274
+
275
+ except json.JSONDecodeError:
276
+ pass
277
+
278
+ message_placeholder.markdown(f"""
279
+ <div class="assistant-message">
280
+ <img src="./app/static/ai.jpg" class="assistant-avatar" />
281
+ <div class="stMarkdown">
282
+ {full_response}
283
+ </div>
284
+ </div>
285
+ """, unsafe_allow_html=True)
286
+
287
+ st.session_state.messages.append({'role': 'assistant', 'content': full_response})
288
+
289
+ # =============================
290
+ # TAB 2: FACEBOOK OAUTH
291
+ # =============================
292
+ with tab2:
293
+ st.title("Facebook OAuth Integration")
294
+
295
+ # Định nghĩa hàm đăng ký webhook Facebook
296
+ def register_facebook_webhook(page_id: str, page_access_token: str):
297
+ try:
298
+ url = f"https://graph.facebook.com/v19.0/{page_id}/subscribed_apps"
299
+ params = {
300
+ "subscribed_fields": "messages,messaging_postbacks",
301
+ "access_token": page_access_token
302
+ }
303
+
304
+ response = requests.post(url, params=params)
305
+ response.raise_for_status()
306
+ data = response.json()
307
 
308
+ if data.get("success"):
309
+ return True, "Đăng ký webhook thành công."
310
+ else:
311
+ return False, f"Facebook trả về lỗi: {data}"
312
+ except requests.exceptions.RequestException as e:
313
+ return False, f"Lỗi khi gọi Facebook API: {e}"
314
+
315
+ if "token" not in st.session_state:
316
+ params = {
317
+ "client_id": FB_APP_ID,
318
+ "redirect_uri": FB_REDIRECT_URI,
319
+ "scope": "pages_show_list,pages_manage_metadata,pages_messaging",
320
+ }
321
+ auth_url = f"{FB_CLIENT_URL}/dialog/oauth?{urlencode(params)}"
322
+ st.markdown("### Step 1: Đăng nhập Facebook")
323
+ st.markdown(f"[Bấm vào đây để đăng nhập Facebook]({auth_url})")
324
+
325
+ st.markdown("### Step 2: Dán URL sau khi đăng nhập")
326
+ redirect_input = st.text_input("Redirect URL (sau khi đăng nhập thành công)")
327
+
328
+ if redirect_input:
329
+ parsed_url = urlparse(redirect_input)
330
+ code = parse_qs(parsed_url.query).get("code", [None])[0]
331
+
332
+ if code:
333
+ try:
334
+ token_response = requests.get(f"{FB_API_URL}/oauth/access_token", params={
335
+ "client_id": FB_APP_ID,
336
+ "redirect_uri": FB_REDIRECT_URI,
337
+ "client_secret": FB_APP_SECRET,
338
+ "code": code,
339
+ })
340
+
341
+ token = token_response.json()["access_token"]
342
+ st.session_state.token = token
343
+ st.success("Lấy access token thành công!")
344
+
345
+ pages_response = requests.get(f"{FB_API_URL}/me/accounts", params={"access_token": token})
346
+ pages = pages_response.json().get("data", [])
347
+ st.session_state.pages = pages
348
+
349
+ st.markdown("### Danh sách các Page bạn quản lý:")
350
+ for page in pages:
351
+ st.json(page)
352
+
353
+ except Exception as e:
354
+ st.error(f"Lỗi: {e}")
355
+
356
+ if "pages" in st.session_state and st.session_state.pages:
357
+ st.markdown("### Step 3: Đăng ký Webhook cho các page")
358
+ selected_pages = st.multiselect(
359
+ "Chọn các page để đăng ký webhook:",
360
+ options=[f"{p['name']} ({p['id']})" for p in st.session_state.pages]
361
+ )
362
+
363
+ if st.button("Đăng ký Webhook"):
364
+ selected_pages = st.session_state.selected_pages # Giả sử bạn có danh sách page đã chọn
365
+ for page in st.session_state.pages:
366
+ label = f"{page['name']} ({page['id']})"
367
+ if label in selected_pages:
368
+ page_id = page['id']
369
+ page_access_token = page['access_token']
370
+
371
+ # Gọi hàm đăng ký webhook
372
+ success, message = register_facebook_webhook(page_id, page_access_token)
373
+
374
+ if success:
375
+ st.success(f"✅ Đã đăng ký Webhook cho page: {page['name']}")
376
+ else:
377
+ st.warning(f"⚠️ Không thể đăng ký Webhook cho page: {page['name']} - {message}")
378
+
379
+ if st.button("Hiển thị Thông tin Trang"):
380
+ for page in st.session_state.pages:
381
+ page_id = page['id']
382
+ page_name = page['name']
383
+ page_access_token = page['access_token']
384
+
385
+ # Hiển thị thông tin của từng page
386
+ st.write(f"**Page Name**: {page_name}")
387
+ st.write(f"**Page ID**: {page_id}")
388
+ st.write(f"**Page Access Token**: {page_access_token}")
389
+ st.write("---") # Dấu phân cách giữa các trang