vanhai123 commited on
Commit
36cac86
·
verified ·
1 Parent(s): 7ae3d51

Upload 9 files

Browse files
Files changed (7) hide show
  1. README.md +9 -9
  2. app.py +147 -201
  3. generator.py +47 -21
  4. gradio_theme.css +86 -0
  5. requirements.txt +16 -16
  6. retriever.py +15 -3
  7. uploaded_files.json +10 -0
README.md CHANGED
@@ -1,10 +1,10 @@
1
- ---
2
- title: RAGFlow Enterprise Search
3
- emoji: 🔎
4
- colorFrom: blue
5
- colorTo: green
6
- sdk: gradio
7
- sdk_version: 5.27.0
8
- app_file: app.py
9
- pinned: false
10
  ---
 
1
+ ---
2
+ title: RAGFlow Enterprise Search
3
+ emoji: 🔎
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 4.44.0
8
+ app_file: app.py
9
+ pinned: false
10
  ---
app.py CHANGED
@@ -1,201 +1,147 @@
1
- import gradio as gr
2
- import os
3
- from datetime import datetime
4
- from retriever import retriever, reload_retriever
5
- from generator import answer_query
6
- from langchain_community.document_loaders import PyPDFLoader, TextLoader, CSVLoader, UnstructuredWordDocumentLoader
7
- from langchain.text_splitter import RecursiveCharacterTextSplitter
8
- from langchain_community.embeddings import HuggingFaceEmbeddings
9
- from langchain_community.vectorstores import FAISS
10
-
11
- # Hàm xử lý upload tài liệu và làm mới FAISS
12
- def process_document(file):
13
- file_path = file.name
14
-
15
- # Chọn loader theo đuôi file
16
- if file_path.endswith(".pdf"):
17
- loader = PyPDFLoader(file_path)
18
- elif file_path.endswith(".csv"):
19
- loader = CSVLoader(file_path)
20
- elif file_path.endswith(".txt"):
21
- loader = TextLoader(file_path)
22
- elif file_path.endswith(".docx") or file_path.endswith(".doc"):
23
- loader = UnstructuredWordDocumentLoader(file_path)
24
- else:
25
- return "Định dạng file không hỗ trợ!"
26
-
27
- # Load tài liệu
28
- documents = loader.load()
29
-
30
- # Cắt chunk văn bản
31
- splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
32
- docs = splitter.split_documents(documents)
33
-
34
- if not docs:
35
- return "Không trích xuất được nội dung từ file tải lên."
36
-
37
- # Tạo FAISS mới
38
- embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
39
- db = FAISS.from_documents(docs, embeddings)
40
-
41
- db.save_local("vectorstore")
42
- reload_retriever()
43
-
44
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
45
- return f"Đã xử lý và thêm {len(docs)} đoạn tài liệu vào VectorStore lúc {timestamp}"
46
-
47
- # Hàm xử lý tìm kiếm
48
- def query_function(question, model_choice, temperature, include_sources):
49
- answer, sources = answer_query(question, model=model_choice, temperature=temperature)
50
-
51
- if include_sources and sources:
52
- sources_text = "\n\n**Nguồn tài liệu:**\n"
53
- for i, doc in enumerate(sources):
54
- sources_text += f"{i+1}. {doc.page_content}\n"
55
- if hasattr(doc, 'metadata') and doc.metadata:
56
- sources_text += f" - Nguồn: {doc.metadata.get('source', 'Unknown')}\n"
57
- sources_text += f" - Trang: {doc.metadata.get('page', 'N/A')}\n"
58
- result = answer + sources_text
59
- else:
60
- result = answer
61
- result = result.encode('utf-8', errors='ignore').decode('utf-8')
62
- return result
63
-
64
- def clear_inputs():
65
- return "", []
66
-
67
- # Giao diện Gradio
68
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
69
- with gr.Row():
70
- with gr.Column(scale=3):
71
- gr.Markdown(
72
- """
73
- # 🔎 RAGFlow Enterprise Search
74
- ### Công cụ tìm kiếm thông minh dựa trên RAG (Retrieval-Augmented Generation)
75
-
76
- Hệ thống giúp truy xuất và trả lời câu hỏi từ tài liệu nội bộ doanh nghiệp.
77
- """
78
- )
79
-
80
- with gr.Tabs():
81
- # Tab tìm kiếm
82
- with gr.TabItem("Tìm kiếm 🔍"):
83
- with gr.Row():
84
- with gr.Column(scale=3):
85
- question = gr.Textbox(
86
- label="Nhập câu hỏi của bạn:",
87
- placeholder="Ví dụ: Quy trình xin nghỉ phép nội bộ là gì?",
88
- lines=2
89
- )
90
- with gr.Column(scale=1):
91
- model_choice = gr.Dropdown(
92
- label="Mô hình AI",
93
- choices=["Gemini Pro", "GPT-3.5", "GPT-4", "Claude"],
94
- value="Gemini Pro"
95
- )
96
- temperature = gr.Slider(
97
- label="Temperature",
98
- minimum=0.0,
99
- maximum=1.0,
100
- value=0.2,
101
- step=0.1
102
- )
103
- include_sources = gr.Checkbox(
104
- label="Hiển thị nguồn tài liệu",
105
- value=True
106
- )
107
-
108
- search_button = gr.Button("🔍 Tìm kiếm", variant="primary")
109
- clear_button = gr.Button("🗑️ Xóa")
110
- output = gr.Textbox(
111
- label="Kết quả tìm kiếm:",
112
- lines=15,
113
- interactive=False
114
- )
115
-
116
- search_button.click(
117
- query_function,
118
- inputs=[question, model_choice, temperature, include_sources],
119
- outputs=output
120
- )
121
- question.submit(
122
- query_function,
123
- inputs=[question, model_choice, temperature, include_sources],
124
- outputs=output
125
- )
126
- clear_button.click(clear_inputs, outputs=[question, output])
127
-
128
- # Tab quản tài liệu
129
- with gr.TabItem("📚 Quản tài liệu"):
130
- with gr.Row():
131
- with gr.Column():
132
- upload_file = gr.File(
133
- label="Tải lên tài liệu mới (PDF, Word, CSV, TXT)",
134
- file_types=[".pdf", ".docx", ".doc", ".csv", ".txt"]
135
- )
136
- upload_button = gr.Button("📤 Tải lên xử lý", variant="primary")
137
-
138
- with gr.Column():
139
- upload_status = gr.Textbox(
140
- label="📄 Trạng thái:",
141
- lines=3,
142
- interactive=False
143
- )
144
-
145
- gr.Markdown("### 📊 Danh sách tài liệu đã xử lý")
146
- upload_button.click(
147
- process_document,
148
- inputs=upload_file,
149
- outputs=upload_status
150
- )
151
-
152
- # Tab cài đặt (optional)
153
- with gr.TabItem("⚙️ Cài đặt hệ thống"):
154
- gr.Markdown("### ⚙️ Cấu hình Vector Store & Embedding")
155
- with gr.Row():
156
- with gr.Column():
157
- vector_store = gr.Dropdown(
158
- label="Vector Store",
159
- choices=["FAISS", "Pinecone", "Milvus"],
160
- value="FAISS"
161
- )
162
- embedding_model = gr.Dropdown(
163
- label="Embedding Model",
164
- choices=["Sentence-Transformers", "OpenAI Embeddings", "Cohere Embeddings"],
165
- value="Sentence-Transformers"
166
- )
167
- with gr.Column():
168
- chunk_size = gr.Slider(
169
- label="Chunk size (độ dài văn bản mỗi đoạn)",
170
- minimum=100,
171
- maximum=1000,
172
- value=500,
173
- step=50
174
- )
175
- chunk_overlap = gr.Slider(
176
- label="Chunk overlap (chồng lấp giữa các đoạn)",
177
- minimum=0,
178
- maximum=200,
179
- value=50,
180
- step=10
181
- )
182
-
183
- save_settings = gr.Button("💾 Lưu cài đặt", variant="primary")
184
- settings_status = gr.Textbox(
185
- label="🗂️ Trạng thái:",
186
- interactive=False
187
- )
188
-
189
- def save_system_settings(vector_store, embedding_model, chunk_size, chunk_overlap):
190
- return f"✅ Đã lưu: VectorStore={vector_store}, Embedding={embedding_model}, ChunkSize={chunk_size}, Overlap={chunk_size}"
191
-
192
- save_settings.click(
193
- save_system_settings,
194
- inputs=[vector_store, embedding_model, chunk_size, chunk_overlap],
195
- outputs=settings_status
196
- )
197
-
198
-
199
- demo.launch()
200
-
201
-
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ import shutil
5
+ from datetime import datetime
6
+ from retriever import retriever, reload_retriever
7
+ from generator import answer_query
8
+ from langchain_community.document_loaders import (
9
+ PyPDFLoader, TextLoader, CSVLoader, UnstructuredWordDocumentLoader
10
+ )
11
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
12
+ from langchain_huggingface import HuggingFaceEmbeddings
13
+ from langchain_community.vectorstores import FAISS
14
+ import html
15
+
16
+ # Đường dẫn file CSS
17
+ CUSTOM_CSS_PATH = "gradio_theme.css"
18
+
19
+ # Quản lý danh sách file upload
20
+ UPLOADED_FILES_JSON = "uploaded_files.json"
21
+ uploaded_files = []
22
+
23
+ def save_uploaded_files_to_json():
24
+ with open(UPLOADED_FILES_JSON, "w", encoding="utf-8") as f:
25
+ json.dump(uploaded_files, f, ensure_ascii=False, indent=2)
26
+
27
+ def load_uploaded_files_from_json():
28
+ global uploaded_files
29
+ if os.path.exists(UPLOADED_FILES_JSON):
30
+ with open(UPLOADED_FILES_JSON, "r", encoding="utf-8") as f:
31
+ uploaded_files = json.load(f)
32
+ else:
33
+ uploaded_files = []
34
+
35
+ def update_uploaded_files():
36
+ if not uploaded_files:
37
+ return "_Chưa tài liệu nào được tải lên._"
38
+ return "### 📚 Danh sách tài liệu đã xử lý:\n" + "\n".join(
39
+ f"- {f['name']} (Uploaded: {f['timestamp'][:19]})" for f in uploaded_files
40
+ )
41
+
42
+ # Load khi khởi động
43
+ load_uploaded_files_from_json()
44
+
45
+ def process_document(file):
46
+ file_path = file.name
47
+
48
+ if os.path.exists("vectorstore"):
49
+ shutil.rmtree("vectorstore")
50
+
51
+ try:
52
+ if file_path.endswith(".pdf"):
53
+ loader = PyPDFLoader(file_path)
54
+ elif file_path.endswith(".csv"):
55
+ loader = CSVLoader(file_path)
56
+ elif file_path.endswith(".txt"):
57
+ loader = TextLoader(file_path, autodetect_encoding=True) # <== fix lỗi txt
58
+ elif file_path.endswith(".docx") or file_path.endswith(".doc"):
59
+ loader = UnstructuredWordDocumentLoader(file_path)
60
+ else:
61
+ return "❌ Định dạng file không hỗ trợ.", update_uploaded_files()
62
+
63
+ documents = loader.load()
64
+ except Exception as e:
65
+ return f"❌ Lỗi khi tải tài liệu: {e}", update_uploaded_files()
66
+
67
+ splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
68
+ docs = splitter.split_documents(documents)
69
+
70
+ if not docs:
71
+ return "⚠️ Không trích xuất được nội dung từ tài liệu.", update_uploaded_files()
72
+
73
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
74
+ db = FAISS.from_documents(docs, embeddings)
75
+ db.save_local("vectorstore")
76
+ reload_retriever()
77
+
78
+ uploaded_files.append({"name": os.path.basename(file.name), "timestamp": datetime.now().isoformat()})
79
+ save_uploaded_files_to_json()
80
+
81
+ return f"✅ Đã xử lý {len(docs)} đoạn từ **{file.name}**", update_uploaded_files()
82
+
83
+ def delete_file(filename):
84
+ global uploaded_files
85
+ filename = filename.strip()
86
+ uploaded_files = [f for f in uploaded_files if f["name"] != filename]
87
+ save_uploaded_files_to_json()
88
+ return update_uploaded_files()
89
+
90
+ def clear_inputs():
91
+ return "", ""
92
+
93
+ def query_function(question, model_choice, temperature, include_sources):
94
+ answer, docs = answer_query(question, model=model_choice, temperature=temperature)
95
+ answer = html.escape(answer)
96
+
97
+ if include_sources and docs:
98
+ unique_sources = set()
99
+ for doc in docs:
100
+ section = doc.metadata.get("section")
101
+ if section:
102
+ unique_sources.add(section.strip())
103
+ else:
104
+ filename = os.path.basename(doc.metadata.get("source", "Unknown"))
105
+ unique_sources.add(filename.strip())
106
+ if unique_sources:
107
+ sources_list = [f"- {src}" for src in sorted(unique_sources)]
108
+ sources_text = "\n\n**Nguồn tham khảo:**\n" + "\n".join(sources_list)
109
+ answer += sources_text
110
+ return answer
111
+
112
+ # Giao diện Gradio
113
+ with gr.Blocks(css=CUSTOM_CSS_PATH) as demo:
114
+ with gr.Row():
115
+ with gr.Column(scale=5):
116
+ gr.Markdown("## 🔍 RAGFlow Enterprise Search\nTìm kiếm thông minh từ tài liệu nội bộ", elem_classes="container-box")
117
+
118
+ with gr.Tabs():
119
+ with gr.TabItem("🔍 Tìm kiếm"):
120
+ with gr.Column(elem_classes="container-box"):
121
+ question = gr.Textbox(lines=3, label="Câu hỏi")
122
+ with gr.Row():
123
+ model_choice = gr.Dropdown(["Gemini Pro", "GPT-3.5", "GPT-4", "Claude"], value="Gemini Pro", label="Mô hình")
124
+ temperature = gr.Slider(0, 1, value=0.2, step=0.1, label="Temperature")
125
+ include_sources = gr.Checkbox(label="Hiển thị nguồn", value=True)
126
+ with gr.Row():
127
+ search_btn = gr.Button("🔍 Tìm kiếm", variant="primary", elem_classes="button-primary")
128
+ clear_btn = gr.Button("🗑️ Xóa", variant="secondary", elem_classes="button-secondary")
129
+ output = gr.Markdown(elem_classes="output-box") # Hiển thị kết quả trong khung đẹp
130
+
131
+ search_btn.click(query_function, inputs=[question, model_choice, temperature, include_sources], outputs=[output])
132
+ clear_btn.click(clear_inputs, outputs=[question, output])
133
+
134
+ with gr.TabItem("📚 Quản tài liệu"):
135
+ with gr.Column(elem_classes="container-box"):
136
+ upload_file = gr.File(label="Tải lên tài liệu", file_types=[".pdf", ".docx", ".doc", ".csv", ".txt"])
137
+ upload_btn = gr.Button("📄 Tải lên và xử lý", variant="primary")
138
+ upload_status = gr.Textbox(label="Trạng thái", lines=3, interactive=False)
139
+ uploaded_files_list = gr.Markdown(value=update_uploaded_files(), elem_classes="scroll-box")
140
+ with gr.Column(elem_classes="container-box"):
141
+ delete_filename = gr.Textbox(label="Tên file muốn xóa")
142
+ delete_btn = gr.Button("🗑️ Xóa tài liệu", variant="secondary")
143
+
144
+ upload_btn.click(process_document, inputs=[upload_file], outputs=[upload_status, uploaded_files_list])
145
+ delete_btn.click(delete_file, inputs=[delete_filename], outputs=[uploaded_files_list])
146
+
147
+ demo.launch(share=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
generator.py CHANGED
@@ -1,41 +1,67 @@
 
1
  import requests
2
  from retriever import retrieve_docs
 
 
 
3
 
4
- API_KEY = "AIzaSyClqQssVMjt02qKrGKnghYAK9RkGf0lkS4"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  def answer_query(query, model="Gemini Pro", temperature=0.2):
7
- docs = retrieve_docs(query)
 
 
 
 
8
  context = "\n\n".join([doc.page_content for doc in docs])
9
- prompt = f"""Dựa trên các tài liệu sau, hãy trả lời ngắn gọn, chính xác:
 
10
 
11
  {context}
12
 
13
  Câu hỏi: {query}
 
 
 
 
 
 
 
 
14
  Trả lời:"""
15
 
16
- # Gửi request tới Gemini
17
  url = f"https://generativelanguage.googleapis.com/v1/models/gemini-1.5-pro:generateContent?key={API_KEY}"
18
-
19
- headers = {
20
- "Content-Type": "application/json",
21
- }
22
-
23
  payload = {
24
- "contents": [
25
- {
26
- "parts": [
27
- {"text": prompt}
28
- ]
29
- }
30
- ],
31
- "generationConfig": {
32
- "temperature": temperature
33
- }
34
  }
35
-
36
  response = requests.post(url, headers=headers, json=payload)
37
  data = response.json()
38
-
39
  try:
40
  answer = data['candidates'][0]['content']['parts'][0]['text']
41
  except Exception as e:
 
1
+ import os
2
  import requests
3
  from retriever import retrieve_docs
4
+ from langchain_community.embeddings import HuggingFaceEmbeddings
5
+ from numpy import dot
6
+ from numpy.linalg import norm
7
 
8
+ API_KEY = "AIzaSyClqQssVMjt02qKrGKnghYAK9RkGf0lkS4"
9
+
10
+ def filter_relevant_docs(docs, query, top_k=3):
11
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
12
+ query_embedding = embeddings.embed_query(query)
13
+ scores = []
14
+ for doc in docs:
15
+ doc_embedding = embeddings.embed_query(doc.page_content)
16
+ cosine_sim = dot(query_embedding, doc_embedding) / (norm(query_embedding) * norm(doc_embedding))
17
+ scores.append((doc, cosine_sim))
18
+ scores.sort(key=lambda x: x[1], reverse=True)
19
+ return [doc for doc, _ in scores[:top_k]]
20
+
21
+ def format_sources(docs):
22
+ sources = set()
23
+ for doc in docs:
24
+ section = doc.metadata.get("section")
25
+ if section:
26
+ sources.add(section.strip())
27
+ else:
28
+ filename = os.path.basename(doc.metadata.get("source", "Nguồn không xác định"))
29
+ sources.add(filename)
30
+ return "\n".join(f"- {src}" for src in sorted(sources))
31
 
32
  def answer_query(query, model="Gemini Pro", temperature=0.2):
33
+ all_docs = retrieve_docs(query)
34
+ if not all_docs:
35
+ return "Không tìm thấy tài liệu liên quan để trả lời.", []
36
+
37
+ docs = filter_relevant_docs(all_docs, query)
38
  context = "\n\n".join([doc.page_content for doc in docs])
39
+
40
+ prompt = f"""Dựa trên tài liệu sau, hãy trả lời câu hỏi theo phong cách trang trọng, lịch sự và chuyên nghiệp:
41
 
42
  {context}
43
 
44
  Câu hỏi: {query}
45
+
46
+ Yêu cầu:
47
+ - Sử dụng từ ngữ lịch sự ("Bạn cần...", "Vui lòng...", "Sau khi...")
48
+ - Không sử dụng từ nói miệng như "nhé", "nha", "ok".
49
+ - Câu trúc câu đầy đủ, rõ ràng.
50
+ - Chỉ trả lời dựa trên thông tin trong tài liệu. Nếu không tìm thấy thông tin liên quan, trả lời: "Thông tin không có trong tài liệu được cung cấp."
51
+ - Không tự thêm "Nguồn tham khảo" trong phần trả lời.
52
+
53
  Trả lời:"""
54
 
 
55
  url = f"https://generativelanguage.googleapis.com/v1/models/gemini-1.5-pro:generateContent?key={API_KEY}"
56
+ headers = {"Content-Type": "application/json"}
 
 
 
 
57
  payload = {
58
+ "contents": [{"parts": [{"text": prompt}]}],
59
+ "generationConfig": {"temperature": temperature}
 
 
 
 
 
 
 
 
60
  }
61
+
62
  response = requests.post(url, headers=headers, json=payload)
63
  data = response.json()
64
+
65
  try:
66
  answer = data['candidates'][0]['content']['parts'][0]['text']
67
  except Exception as e:
gradio_theme.css ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* === Giao diện khung chứa === */
2
+ .container-box {
3
+ border: 1px solid var(--border-color-primary);
4
+ border-radius: 10px;
5
+ padding: 20px;
6
+ background-color: var(--background-fill-primary);
7
+ margin-bottom: 20px;
8
+ }
9
+
10
+ /* === Tiêu đề to và rõ === */
11
+ h1, h2, h3, label {
12
+ color: var(--body-text-color);
13
+ font-weight: bold;
14
+ font-size: 1.35rem;
15
+ }
16
+
17
+ /* === Hộp kết quả và danh sách file === */
18
+ .output-box ,.scroll-box {
19
+ background-color: var(--background-fill-primary) !important;
20
+ color: var(--body-text-color) !important;
21
+ border: 2px dashed var(--border-color-primary, #ccc) !important; /* #ccc là giá trị dự phòng */
22
+ border-radius: 10px !important;
23
+ padding: 18px !important;
24
+ font-size: 1.1rem !important;
25
+ }
26
+
27
+ /* === Thanh tải giả định (vòng tròn chờ) cho output nếu muốn thêm bằng js sau này === */
28
+ .output-box::after {
29
+ content: "";
30
+ display: none; /* Khi cần loading thì display: block */
31
+ position: absolute;
32
+ top: 10px;
33
+ right: 20px;
34
+ border: 4px solid #f3f3f3;
35
+ border-top: 4px solid #1e88e5;
36
+ border-radius: 50%;
37
+ width: 20px;
38
+ height: 20px;
39
+ animation: spin 1s linear infinite;
40
+ }
41
+ @keyframes spin {
42
+ 0% { transform: rotate(0deg); }
43
+ 100% { transform: rotate(360deg); }
44
+ }
45
+
46
+ /* === Nút hành động === */
47
+ .button-primary {
48
+ background-color: #1e88e5 !important;
49
+ color: white !important;
50
+ border-radius: 8px !important;
51
+ font-size: 1.05rem !important;
52
+ }
53
+ .button-primary:hover {
54
+ background-color: #1565c0 !important;
55
+ }
56
+
57
+ .button-secondary {
58
+ background-color: #ef5350 !important;
59
+ color: white !important;
60
+ border-radius: 8px !important;
61
+ font-size: 1.05rem !important;
62
+ }
63
+ .button-secondary:hover {
64
+ background-color: #c62828 !important;
65
+ }
66
+
67
+ /* === Input / dropdown đẹp hơn === */
68
+ gradio-textbox,
69
+ gradio-dropdown,
70
+ gradio-slider {
71
+ background-color: var(--background-fill-primary) !important;
72
+ color: var(--body-text-color) !important;
73
+ font-size: 1.05rem !important;
74
+ }
75
+
76
+ /* === Scrollbar custom cho danh sách === */
77
+ .scroll-box::-webkit-scrollbar {
78
+ width: 6px;
79
+ }
80
+ .scroll-box::-webkit-scrollbar-thumb {
81
+ background: #888;
82
+ border-radius: 4px;
83
+ }
84
+ .scroll-box::-webkit-scrollbar-thumb:hover {
85
+ background: #555;
86
+ }
requirements.txt CHANGED
@@ -1,17 +1,17 @@
1
- langchain
2
- faiss-cpu
3
- sentence-transformers
4
- gradio>=4.44.0
5
- fastapi
6
- uvicorn
7
- huggingface_hub
8
- datasets
9
- google-generativeai
10
- langchain-community
11
- requests
12
- python-docx
13
- unstructured
14
- unstructured[docx,pdf]
15
- pdf2image
16
- pytesseract
17
  pdfminer.six
 
1
+ langchain
2
+ faiss-cpu
3
+ sentence-transformers
4
+ gradio>=4.44.0
5
+ fastapi
6
+ uvicorn
7
+ huggingface_hub
8
+ datasets
9
+ google-generativeai
10
+ langchain-community
11
+ requests
12
+ python-docx
13
+ unstructured
14
+ unstructured[docx,pdf]
15
+ pdf2image
16
+ pytesseract
17
  pdfminer.six
retriever.py CHANGED
@@ -1,11 +1,19 @@
1
  import os
2
  from langchain_community.vectorstores import FAISS
3
- from langchain_community.embeddings import HuggingFaceEmbeddings
4
 
5
  # Hàm khởi tạo retriever
6
  def load_retriever():
7
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
8
- retriever = FAISS.load_local("vectorstore", embeddings, allow_dangerous_deserialization=True).as_retriever(search_kwargs={"k": 5})
 
 
 
 
 
 
 
 
9
  return retriever
10
 
11
  # Lần đầu load retriever
@@ -18,4 +26,8 @@ def reload_retriever():
18
 
19
  # Hàm retrieve_docs để lấy tài liệu
20
  def retrieve_docs(query):
21
- return retriever.get_relevant_documents(query)
 
 
 
 
 
1
  import os
2
  from langchain_community.vectorstores import FAISS
3
+ from langchain_huggingface import HuggingFaceEmbeddings
4
 
5
  # Hàm khởi tạo retriever
6
  def load_retriever():
7
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
8
+ vectorstore_path = "vectorstore"
9
+
10
+ # Kiểm tra nếu tồn tại index.faiss mới load
11
+ if os.path.exists(vectorstore_path) and os.path.exists(os.path.join(vectorstore_path, "index.faiss")):
12
+ retriever = FAISS.load_local(vectorstore_path, embeddings, allow_dangerous_deserialization=True).as_retriever(search_kwargs={"k": 5})
13
+ print("✅ Đã load vectorstore thành công.")
14
+ else:
15
+ retriever = None
16
+ print("⚠️ Vectorstore chưa tồn tại. Hãy upload tài liệu trước khi tìm kiếm.")
17
  return retriever
18
 
19
  # Lần đầu load retriever
 
26
 
27
  # Hàm retrieve_docs để lấy tài liệu
28
  def retrieve_docs(query):
29
+ if retriever:
30
+ return retriever.get_relevant_documents(query)
31
+ else:
32
+ print("⚠️ Chưa có vectorstore để tìm kiếm. Bạn cần tải tài liệu trước.")
33
+ return []
uploaded_files.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "CompanyPolicy_TestDocument.txt",
4
+ "timestamp": "2025-04-29T15:06:18.974354"
5
+ },
6
+ {
7
+ "name": "Document 5.docx",
8
+ "timestamp": "2025-04-29T15:07:19.497921"
9
+ }
10
+ ]