VietCat commited on
Commit
ec666c4
·
1 Parent(s): 4fedd9a

init project

Browse files
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # files
2
+ *.DS_Store
Dockerfile ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+ COPY . .
5
+
6
+ RUN pip install --upgrade pip \
7
+ && pip install -r requirements.txt
8
+
9
+ EXPOSE 7860
10
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import logging
3
+ from fastapi import FastAPI, Request
4
+ from rag_core.chunker import chunk_legal_text
5
+ from rag_core.embedder import get_embedding
6
+ from rag_core.retriever import Retriever
7
+ from rag_core.llm import generate_answer
8
+
9
+ app = FastAPI()
10
+ retriever = Retriever()
11
+
12
+ # Khởi tạo nếu chưa có index
13
+ if retriever.index is None:
14
+ logging.info("Không tìm thấy FAISS index, bắt đầu xử lý...")
15
+ with open("data/raw_law.txt", "r", encoding="utf-8") as f:
16
+ text = f.read()
17
+ chunks = chunk_legal_text(text)
18
+ retriever.build(chunks, get_embedding)
19
+
20
+ # API endpoint
21
+ @app.post("/ask")
22
+ async def ask_api(req: Request):
23
+ data = await req.json()
24
+ query = data.get("query")
25
+ docs = retriever.query(query, get_embedding)
26
+ prompt = "\n\n".join(docs) + f"\n\nCâu hỏi: {query}\nTrả lời:"
27
+ answer = generate_answer(prompt)
28
+ return {"answer": answer}
29
+
30
+ # Gradio UI
31
+ iface = gr.Interface(
32
+ fn=lambda q: generate_answer("\n\n".join(retriever.query(q, get_embedding)) + f"\n\nCâu hỏi: {q}\nTrả lời:"),
33
+ inputs=gr.Textbox(label="Nhập câu hỏi"),
34
+ outputs=gr.Textbox(label="Trả lời"),
35
+ title="Luật Giao Thông RAG"
36
+ )
37
+
38
+ import uvicorn
39
+ import threading
40
+
41
+ def start_fastapi():
42
+ uvicorn.run(app, host="0.0.0.0", port=7861)
43
+
44
+ threading.Thread(target=start_fastapi).start()
45
+ iface.launch()
data/raw_law.txt ADDED
The diff for this file is too large to render. See raw diff
 
rag_core/__init__.py ADDED
File without changes
rag_core/chunker.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from typing import List
3
+ from rag_core.utils import log_timed
4
+
5
+ @log_timed("chunking văn bản luật")
6
+ def chunk_legal_text(text: str) -> List[str]:
7
+ pattern = r"(Chương\\s+[IVXLC]+:.*?|Điều\\s+\\d+\\..*?)(?=(Chương\\s+[IVXLC]+:|Điều\\s+\\d+\\.|$))"
8
+ matches = re.findall(pattern, text, flags=re.DOTALL)
9
+ return [m[0].strip() for m in matches if len(m[0].strip()) > 30]
rag_core/embedder.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ from rag_core.utils import log_timed
3
+
4
+ @log_timed("gửi API tạo embedding")
5
+ def get_embedding(text: str):
6
+ response = requests.post(
7
+ "https://vietcat-phobertnode.hf.space/embed",
8
+ json={"text": text},
9
+ timeout=10
10
+ )
11
+ return response.json()["embedding"]
rag_core/llm.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ from rag_core.utils import log_timed
3
+
4
+ @log_timed("gửi prompt tới LLM")
5
+ def generate_answer(prompt: str) -> str:
6
+ response = requests.post(
7
+ "https://vietcat-gemma34b.hf.space/purechat",
8
+ json={"prompt": prompt},
9
+ timeout=30
10
+ )
11
+ return response.json()["response"]
rag_core/retriever.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import faiss
2
+ import numpy as np
3
+ import os
4
+ import pickle
5
+ from rag_core.utils import log_timed
6
+
7
+ INDEX_PATH = "faiss_index/index.faiss"
8
+ META_PATH = "faiss_index/meta.pkl"
9
+
10
+ class Retriever:
11
+ def __init__(self):
12
+ if os.path.exists(INDEX_PATH):
13
+ self.index = faiss.read_index(INDEX_PATH)
14
+ with open(META_PATH, "rb") as f:
15
+ self.texts = pickle.load(f)
16
+ else:
17
+ self.index = None
18
+ self.texts = []
19
+
20
+ @log_timed("xây FAISS index")
21
+ def build(self, texts: list, embed_fn):
22
+ embeddings = [embed_fn(t) for t in texts]
23
+ dim = len(embeddings[0])
24
+ self.index = faiss.IndexFlatL2(dim)
25
+ self.index.add(np.array(embeddings).astype("float32"))
26
+ faiss.write_index(self.index, INDEX_PATH)
27
+ with open(META_PATH, "wb") as f:
28
+ pickle.dump(texts, f)
29
+ self.texts = texts
30
+
31
+ @log_timed("truy vấn FAISS")
32
+ def query(self, query_text, embed_fn, k=3):
33
+ q_emb = np.array([embed_fn(query_text)]).astype("float32")
34
+ D, I = self.index.search(q_emb, k)
35
+ return [self.texts[i] for i in I[0]]
rag_core/utils.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import logging
3
+
4
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
5
+
6
+ def log_timed(message):
7
+ def decorator(func):
8
+ def wrapper(*args, **kwargs):
9
+ logging.info(f"Bắt đầu {message}...")
10
+ start = time.time()
11
+ result = func(*args, **kwargs)
12
+ end = time.time()
13
+ logging.info(f"Hoàn tất {message} trong {end - start:.2f}s.")
14
+ return result
15
+ return wrapper
16
+ return decorator
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ faiss-cpu
2
+ numpy
3
+ requests
4
+ gradio
5
+ uvicorn
6
+ fastapi