NCT_chatbot_QA / app.py
buianh0803's picture
Upload 4 files
a0c2313 verified
from typing import List, Dict, Tuple, Optional
import gradio as gr
import json
import os
import google.generativeai as genai
from tqdm import tqdm
import re
from langchain.prompts import PromptTemplate
from file_loader import load_vectorstore
from typing import List, Dict, Tuple, Optional
from google.genai import types
key = "AIzaSyAmOsIFpQdU1W7mBce0KRyvvKGV525oe2c"
genai.configure(api_key=key)
# Load vectorstore globally to avoid reloading for each query
print("Loading vectorstore...")
vectorstore = load_vectorstore()
# Initialize the LLM
llm = genai.GenerativeModel("gemini-2.0-flash")
def extract_program_information(question):
"""Extract program information from the question using context from CSV data"""
# Prepare CSV data as context
csv_context = """
department_name, department_brief, program_name, degree, program_brief, level, major_name, major_code, file_path
Khoa Công nghệ thông tin, FIT, Chương trình An toàn thông tin, Cử nhân/Bachelor, IS, Đại học/Undergraduate, Cử nhân An toàn thông tin /Bachelor of Information Security, 7480202, syllabus_nct_word_format/Trường Công nghệ/Chương trình An toàn thông tin/CTĐT ngành An toàn thông tin.docx
Khoa Công nghệ thông tin, FIT, Chương trình Công nghệ thông tin, Cử nhân/Bachelor, IT, Đại học/Undergraduate, Cử nhân Công nghệ thông tin /Bachelor of Information Technology, 7480201, syllabus_nct_word_format/Trường Công nghệ/Chương trình Công nghệ thông tin/Công nghệ thông tin_CTĐT_2023.docx
Khoa Công nghệ thông tin, FIT, Chương trình Khoa học máy tính, Cử nhân/Bachelor, CS, Đại học/Undergraduate, Cử nhân Khoa học máy tính /Bachelor of Computer Science, 7480101, syllabus_nct_word_format/Trường Công nghệ/Chương trình Khoa học máy tính/Khoa học máy tính_CTĐT_2023.docx
Khoa Công nghệ thông tin, FIT, Chương trình Kỹ thuật phần mềm, Cử nhân/Bachelor, SE, Đại học/Undergraduate, Cử nhân Kỹ thuật phần mềm/Bachelor of Software Engineering, 7480103, syllabus_nct_word_format/Trường Công nghệ/Chương trình Kỹ thuật phần mềm/CTĐT ngành Kỹ thuât phần mềm.docx
Khoa Hệ thống thông tin quản lý, MIS, Chương trình Hệ thống thông tin, Cử nhân/Bachelor, IS, Đại học/Undergraduate, Cử nhân Hệ thống thông tin/Bachelor of Information Systems, 7480104, syllabus_nct_word_format/Trường Công nghệ/Chương trình Hệ thống thông tin/CTĐT ngành HTTT.docx
Khoa Hệ thống thông tin quản lý, MIS, Chương trình Hệ thống thông tin quản lý, Cử nhân/Bachelor, MIS, Đại học/Undergraduate, Cử nhân Hệ thống thông tin quản lý/Bachelor of Management Information Systems, 7340405, syllabus_nct_word_format/Trường Công nghệ/Chương trình Hệ thống thông tin quản lý/Hệ thống thông tin quản lý_CTĐT_2023.docx
Khoa Khoa học dữ liệu và Trí tuệ nhân tạo, FDA, Chương trình Khoa học dữ liệu, Cử nhân/Bachelor, DS, Đại học/Undergraduate, Cử nhân Khoa học dữ liệu trong Tài chính và thương mại điện tử/ Bachelor of Data Science in Finance and E-commerce, 7460108, syllabus_nct_word_format/Trường Công nghệ/Chương trình Khoa học dữ liệu/22.5.1.CTĐT_ngành KHDL_cử nhân.docx
Khoa Khoa học dữ liệu và Trí tuệ nhân tạo, FDA, Chương trình Khoa học dữ liệu, Kỹ sư/Engineer, DS, Đại học/Undergraduate, Kỹ sư Khoa học dữ liệu trong Tài chính và thương mại điện tử/ Engineer of Data Science in Finance and E-commerce, 7460108, syllabus_nct_word_format/Trường Công nghệ/Chương trình Khoa học dữ liệu/22.5.2.CTĐT_ngành KHDL_kỹ sư.docx
Khoa Khoa học dữ liệu và Trí tuệ nhân tạo, FDA, Chương trình Trí tuệ nhân tạo, Cử nhân/Bachelor, AI, Đại học/Undergraduate, Cử nhân Trí tuệ nhân tạo /Bachelor of Artificial Intelligence, 7480107, syllabus_nct_word_format/Trường Công nghệ/Chương trình Trí tuệ nhân tạo/22.5.1.CTĐT_ngành TTNT_cử nhân.docx
Khoa Khoa học dữ liệu và Trí tuệ nhân tạo, FDA, Chương trình Trí tuệ nhân tạo, Kỹ sư/Engineer, AI, Đại học/Undergraduate, Kỹ sư Trí tuệ nhân tạo /Engineer of Artificial Intelligence, 7480107, syllabus_nct_word_format/Trường Công nghệ/Chương trình Trí tuệ nhân tạo/22.5.2.CTĐT_ngành TTNT_kỹ sư.docx
Khoa Thống kê, , Chương trình Thống kê kinh tế, Cử nhân/Bachelor, ES, Đại học/Undergraduate, Cử nhân Thống kê kinh tế/Bachelor of Economic Statistics, 7310107, syllabus_nct_word_format/Trường Công nghệ/Chương trình Thống kê kinh tế/Thống kê kinh tế_CTĐT_2023.docx
Khoa Toán kinh tế, MFE, Chương trình Toán kinh tế, Cử nhân/Bachelor, TOKT, Đại học/Undergraduate, Cử nhân Toán kinh tế/Bachelor of Mathematical Economics, 7310108, syllabus_nct_word_format/Trường Công nghệ/Chương trình Toán kinh tế/Toán kinh tế_CTĐT_2023.docx
Khoa Toán kinh tế, MFE, Chương trình Phân tích dữ liệu trong Kinh tế, Cử nhân/Bachelor, DSEB, Đại học/Undergraduate, Cử nhân khoa học dữ liệu trong kinh tế và kinh doanh/Bachelor of Data science in economiscs and business, 7310108, syllabus_nct_word_format/Trường Công nghệ/Chương trình Phân tích dữ liệu trong Kinh tế/DSEB_khung_chuong_trinh.docx
Khoa Toán Kinh tế, MFE, Chương trình Định phí bảo hiểm và Quản trị rủi ro, Cử nhân/Bachelor, Actuary, Đại học/Undergraduate, Cử nhân Định phí bảo hiểm và Quản trị rủi ro/Bachelor of Actuarial Science and Risk Management, 7310108, syllabus_nct_word_format/Trường Công nghệ/Chương trình Định phí bảo hiểm và Quản trị rủi ro/Actury program.pdf
"""
prompt = f"""
Dựa vào dữ liệu trong bảng sau:
{csv_context}
Hãy phân tích câu hỏi sau và xác định chính xác thông tin về department_name, program_name và degree được đề cập.
Câu hỏi: {question}
Yêu cầu:
1. Trả về giá trị chính xác từ bảng dữ liệu, không tự tạo ra thông tin.
2. QUAN TRỌNG: Chỉ trả về một JSON object (không đặt trong array), không có markdown formatting như ```json hoặc ```.
3. Chỉ trả về đúng format sau:
"department_name": "<giá trị chính xác>",
"program_name": "<giá trị chính xác>",
"degree": "<giá trị chính xác>"
LƯU Ý QUAN TRỌNG:
- KHÔNG thêm backticks, markdown, hay bất kỳ text nào khác.
- Với bằng cấp, nếu không đề cập gì và chương trình là "khoa học dữ liệu" hoặc "trí tuệ nhân tạo", trả về "both".
- Với bằng cấp, nếu đề cập "Kỹ sư" và chương trình là "khoa học dữ liệu" hoặc "trí tuệ nhân tạo", trả về "Kỹ sư/Engineer".
- Nếu giá trị nào không được đề cập, trả về "unknown".
- Hãy trích xuất cẩn thận tên khoa, chương trình và bằng cấp từ câu hỏi vì sẽ có trường hợp tên chương trình giống với tên khoa, hãy để ý tới từ khóa "khoa" hoặc "chương trình" để phân biệt.
"""
prompt = prompt.format(context=csv_context, question=question)
response = llm.generate_content(prompt).text.strip()
try:
# Xử lý trường hợp có backticks và language tag
if "```json" in response:
# Trích xuất phần JSON từ giữa các dấu backtick
import re
json_match = re.search(r'```json\s*([\s\S]*?)\s*```', response)
if json_match:
json_str = json_match.group(1).strip()
else:
json_str = response
else:
json_str = response
# Parse JSON
parsed_data = json.loads(json_str)
# Xử lý trường hợp nó là một array
if isinstance(parsed_data, list) and len(parsed_data) > 0:
result = parsed_data[0] # Lấy phần tử đầu tiên nếu là array
else:
result = parsed_data
# Kiểm tra các trường cần thiết
if "program_name" not in result or "degree" not in result or "department_name" not in result:
raise ValueError("Missing required fields in JSON response")
return result
except Exception as e:
print(f"Error processing response: {str(e)}")
print(f"Original response: {response}")
return {"program_name": "unknown", "degree": "unknown", "department_name": "unknown"}
def get_answer(question, history):
"""Process the question and return an answer"""
try:
# Extract program and degree information
program_info = extract_program_information(question)
department_name = program_info["department_name"].strip()
program_name = program_info["program_name"].strip()
degree = program_info["degree"].strip()
print("\n" + program_name + "\n" +
degree + "\n" + department_name + "\n")
# Xây dựng filter theo thứ tự ưu tiên
filters = []
# Xử lý logic filter - ưu tiên theo program_name > degree > department_name
if program_name != "unknown":
# Có thông tin về chương trình - đây là ưu tiên hàng đầu
filters.append(
{"term": {"metadata.program_name.keyword": program_name}})
# Nếu có cả degree và không phải "both", thêm vào filter
if degree != "unknown" and degree != "both":
filters.append({"term": {"metadata.degree.keyword": degree}})
elif department_name != "unknown":
# Không có program_name nhưng có department_name
filters.append(
{"term": {"metadata.department_name.keyword": department_name}})
# Thực hiện tìm kiếm
if filters:
print(f"Searching with filters: {filters}")
docs = vectorstore.similarity_search(
question,
k=50,
filter=filters
)
else:
# Không có filter nào, tìm kiếm toàn bộ
print("Searching without filters")
docs = vectorstore.similarity_search(question, k=50)
print(f"Found {len(docs)} relevant documents")
# Format context from retrieved documents
if docs:
context = "\n\n".join([doc.page_content for doc in docs])
# Generate response with prompt
prompt_template = """
Dựa trên các thông tin chính xác sau đây:
{context}
Hãy trả lời câu hỏi: {question}
Hướng dẫn:
1. Trả lời đầy đủ, chi tiết bằng tiếng Việt
2. Suy luận câu trả lời từ thông tin được cung cấp
3. Không bịa đặt hoặc thêm thông tin không có trong tài liệu
4. Nếu câu hỏi có liên quan đến chương trình "khoa học dữ liệu" hoặc "trí tuệ nhân tạo", câu trả lời cần đề cập đến bằng cấp chính xác được đặt ra ở câu hỏi, nếu không có đề cập gì thì trả lời nội dung của cả hai chương trình "Cử nhân/Bachelor" và "Kỹ sư/Engineer".
"""
formatted_prompt = prompt_template.format(
context=context, question=question)
response = llm.generate_content(formatted_prompt).text
# Cập nhật history đúng định dạng cho Gradio chatbot
history = history + [(question, response)]
return history
else:
# Cập nhật history khi không tìm thấy document
response = "Tôi không tìm thấy thông tin liên quan trong cơ sở dữ liệu. Vui lòng thử lại với câu hỏi khác."
history = history + [(question, response)]
return history
except Exception as e:
print(f"Error processing question: {str(e)}")
response = f"Xin lỗi, có lỗi xảy ra: {str(e)}"
history = history + [(question, response)]
return history
def create_gradio_interface():
# Khai báo danh sách khoa và chương trình
departments = [
'Tất cả',
'Khoa Công nghệ thông tin (FIT)',
'Khoa Khoa học dữ liệu và TTNT (FDA)',
'Khoa Hệ thống thông tin quản lý (MIS)',
'Khoa Toán kinh tế (MFE)',
'Khoa Thống kê (KTK)'
]
programs = [
'Tất cả',
'An toàn thông tin (ATTT)',
'Công nghệ thông tin (CNTT)',
'Khoa học máy tính (KHMT)',
'Kỹ thuật phần mềm (KTPM)',
'Trí tuệ nhân tạo (TTNT)',
'Khoa học dữ liệu (KHDL)',
'Hệ thống thông tin (HTTT)',
'Hệ thống thông tin quản lý (HTTTQL)'
]
with gr.Blocks(title="Trợ lý Thông tin Chương trình Đào tạo", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
## 🎓 Trợ lý thông tin chương trình đào tạo NCT
""")
with gr.Row():
department = gr.Dropdown(
choices=departments,
value='Tất cả',
label="Khoa/Viện"
)
program = gr.Dropdown(
choices=programs,
value='Tất cả',
label="Chương trình đào tạo"
)
txt = gr.Textbox(
show_label=False,
placeholder="Nhập câu hỏi của bạn tại đây và nhấn Enter...",
container=False
)
chatbot = gr.Chatbot(
height=500,
bubble_full_width=False,
show_label=False,
)
clear = gr.Button("🗑️ Xóa trò chuyện", variant="secondary")
# Sự kiện submit câu hỏi
txt.submit(
fn=get_answer,
inputs=[txt, chatbot],
outputs=chatbot,
queue=True
).then(
fn=lambda: "",
outputs=txt
)
# Sự kiện xóa lịch sử chat
clear.click(
fn=lambda: [],
outputs=chatbot,
queue=False
)
return demo
if __name__ == "__main__":
demo = create_gradio_interface()
demo.launch(share=True)