Spaces:
Sleeping
Sleeping
Minh commited on
Commit ·
3034da3
1
Parent(s): 7fc82bd
new file: .python-version
Browse filesmodified: app.py
new file: pyproject.toml
modified: requirements.txt
- .python-version +1 -0
- app.py +126 -130
- pyproject.toml +15 -0
- requirements.txt +3 -0
.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3.13
|
app.py
CHANGED
|
@@ -1,138 +1,134 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
# import gradio as gr
|
| 4 |
-
|
| 5 |
-
# from uuid import uuid4
|
| 6 |
-
# from pprint import pprint
|
| 7 |
-
# from dotenv import load_dotenv
|
| 8 |
-
# from qdrant_client import QdrantClient
|
| 9 |
-
# from fastembed import TextEmbedding
|
| 10 |
-
# from langchain_core.documents import Document
|
| 11 |
-
# from src.utils.qdrant_vector_store import QdrantVectorStore, RetrievalMode
|
| 12 |
-
# from src.utils.fastembed_manager import add_custom_embedding_model
|
| 13 |
-
# from src.utils.fastembed_sparse import FastEmbedSparse
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
# from qdrant_client import QdrantClient
|
| 18 |
-
# from qdrant_client.http import models
|
| 19 |
-
# load_dotenv()
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
# COLLECTION_NAME = "test_collection"
|
| 23 |
-
# qdrant_api_key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.T97XMDCPTieAz5kVDkKtF0_HU_9BkFA71tH2j4WovkU"
|
| 24 |
-
# qdrant_endpoint = "https://9ea9b30f-4284-455b-bbae-65e4e458ed35.europe-west3-0.gcp.cloud.qdrant.io"
|
| 25 |
-
# qdrant_client = QdrantClient(
|
| 26 |
-
# url=qdrant_endpoint,
|
| 27 |
-
# api_key=qdrant_api_key,
|
| 28 |
-
# prefer_grpc=True,
|
| 29 |
-
# )
|
| 30 |
-
# sparse_embeddings = FastEmbedSparse(model_name="Qdrant/BM25")
|
| 31 |
-
# embedding = add_custom_embedding_model(
|
| 32 |
-
# model_name="models/Vietnamese_Embedding_OnnX_Quantized",
|
| 33 |
-
# source_model="Mint1456/Vietnamese_Embedding_OnnX_Quantized",
|
| 34 |
-
# dim=1024,
|
| 35 |
-
# source_file="model.onnx"
|
| 36 |
-
# )
|
| 37 |
-
# client = QdrantVectorStore(
|
| 38 |
-
# client=qdrant_client,
|
| 39 |
-
# collection_name=COLLECTION_NAME,
|
| 40 |
-
# embedding=embedding,
|
| 41 |
-
# sparse_embedding=sparse_embeddings,
|
| 42 |
-
# retrieval_mode=RetrievalMode.HYBRID,
|
| 43 |
-
# )
|
| 44 |
-
|
| 45 |
-
# def search_document(query, top_k, search_type, slider_lambda):
|
| 46 |
-
# if not query.strip():
|
| 47 |
-
# return "⚠️ Enter query to look up!"
|
| 48 |
-
# try:
|
| 49 |
-
# if search_type == "Default":
|
| 50 |
-
# hits = client.similarity_search_with_score(query=query,k=top_k)
|
| 51 |
-
# else:
|
| 52 |
-
|
| 53 |
-
# hits = client.max_marginal_relevance_search_with_score(query=query, k=top_k, lambda_mult=slider_lambda)
|
| 54 |
-
# except Exception as e:
|
| 55 |
-
# print("error", e)
|
| 56 |
-
|
| 57 |
-
# total_found = len(hits)
|
| 58 |
-
# if total_found == 0:
|
| 59 |
-
# return json.dumps([], indent=2)
|
| 60 |
-
|
| 61 |
-
# # Nếu tìm được 10 mà đòi 15 -> chỉ lấy 10. Nếu tìm được 100 mà đòi 15 -> lấy 15
|
| 62 |
-
# safe_k = min(top_k, total_found)
|
| 63 |
-
# results = []
|
| 64 |
-
# for i in range(safe_k):
|
| 65 |
-
# hit = hits[i]
|
| 66 |
-
# if hit[0].metadata.get('parent_chunking', None) is not None:
|
| 67 |
-
# content = hit[0].metadata['parent_chunking']
|
| 68 |
-
# elif hit[0].metadata.get('type', None) == "intro":
|
| 69 |
-
# content = hit[0].page_content
|
| 70 |
-
# else:
|
| 71 |
-
# content = None
|
| 72 |
-
# results.append({
|
| 73 |
-
# "Score": round(hit[1], 4),
|
| 74 |
-
# "Content": content,
|
| 75 |
-
# # "Metadata:": {k: v for k, v in hit[0].metadata.items() if k != "page_content"}
|
| 76 |
-
# })
|
| 77 |
-
|
| 78 |
-
# return json.dumps(results, indent=2, ensure_ascii=False)
|
| 79 |
-
|
| 80 |
-
# # --- GIAO DIỆN GRADIO ---
|
| 81 |
-
|
| 82 |
-
# with gr.Blocks(title="Qdrant Vector DB Demo") as demo:
|
| 83 |
-
# gr.Markdown("# 🚀 Demo Qdrant Vector Search")
|
| 84 |
-
# gr.Markdown("Tool test nhanh khả năng thêm dữ liệu và tìm kiếm ngữ nghĩa (Semantic Search).")
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
# with gr.Tab("2. Tìm Kiếm (Search)"):
|
| 88 |
-
# with gr.Row():
|
| 89 |
-
# with gr.Column(scale=1):
|
| 90 |
-
# txt_query = gr.Textbox(label="Câu truy vấn", placeholder="Ví dụ: Tìm về một số thông tin trên website Bệnh Viện Tâm Anh", lines=2)
|
| 91 |
-
# gr.Examples(
|
| 92 |
-
# examples=[
|
| 93 |
-
# "Rủi ro khi khâu cổ tử cung",
|
| 94 |
-
# "Biến chứng của tràn dịch phổi",
|
| 95 |
-
# "Triệu chứng của viêm phế quản",
|
| 96 |
-
# "Phòng ngừa đau tim"
|
| 97 |
-
# ],
|
| 98 |
-
# inputs=txt_query,
|
| 99 |
-
# label="Ví dụ mẫu (Click để chọn)"
|
| 100 |
-
# )
|
| 101 |
-
# # Component mới: Chọn thuật toán
|
| 102 |
-
# radio_type = gr.Radio(
|
| 103 |
-
# choices=["Default", "MMR"],
|
| 104 |
-
# value="Default",
|
| 105 |
-
# label="Search Type",
|
| 106 |
-
# info="Default: Giống nhất | MMR: Đa dạng kết quả"
|
| 107 |
-
# )
|
| 108 |
-
|
| 109 |
-
# # Component mới: Slider cho MMR
|
| 110 |
-
# # visible=False mặc định, sẽ hiện khi chọn MMR (nếu bạn muốn làm xịn, ở đây để luôn True cho dễ)
|
| 111 |
-
# slider_lambda = gr.Slider(
|
| 112 |
-
# minimum=0.0, maximum=1.0, value=0.5, step=0.1,
|
| 113 |
-
# label="Độ đa dạng (Lambda)",
|
| 114 |
-
# info="1.0 = Chính xác nhất (như Default), 0.0 = Đa dạng nhất"
|
| 115 |
-
# )
|
| 116 |
-
|
| 117 |
-
# slider_k = gr.Slider(minimum=1, maximum=20, value=3, step=1, label="Số lượng kết quả (Top K)")
|
| 118 |
-
|
| 119 |
-
# btn_search = gr.Button("🔍 Tìm kiếm ngay", variant="primary")
|
| 120 |
-
|
| 121 |
-
# with gr.Column(scale=2):
|
| 122 |
-
# out_search = gr.Code(label="Kết quả trả về (JSON)", language="json")
|
| 123 |
-
|
| 124 |
-
# # Cập nhật inputs truyền vào hàm search
|
| 125 |
-
# btn_search.click(
|
| 126 |
-
# search_document,
|
| 127 |
-
# inputs=[txt_query, slider_k, radio_type, slider_lambda],
|
| 128 |
-
# outputs=out_search
|
| 129 |
-
# )
|
| 130 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
with gr.Blocks(title="Qdrant Vector DB Demo") as demo:
|
| 133 |
gr.Markdown("# 🚀 Demo Qdrant Vector Search")
|
| 134 |
gr.Markdown("Tool test nhanh khả năng thêm dữ liệu và tìm kiếm ngữ nghĩa (Semantic Search).")
|
| 135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
print("Launching server on 0.0.0.0:7860...")
|
| 137 |
demo.launch(
|
| 138 |
server_name="0.0.0.0",
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import gradio as gr
|
| 4 |
+
|
| 5 |
+
from uuid import uuid4
|
| 6 |
+
from pprint import pprint
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
from qdrant_client import QdrantClient
|
| 9 |
+
from fastembed import TextEmbedding
|
| 10 |
+
from langchain_core.documents import Document
|
| 11 |
+
from src.utils.qdrant_vector_store import QdrantVectorStore, RetrievalMode
|
| 12 |
+
from src.utils.fastembed_manager import add_custom_embedding_model
|
| 13 |
+
from src.utils.fastembed_sparse import FastEmbedSparse
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
from qdrant_client import QdrantClient
|
| 18 |
+
from qdrant_client.http import models
|
| 19 |
+
load_dotenv()
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
COLLECTION_NAME = "test_collection"
|
| 23 |
+
qdrant_api_key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.T97XMDCPTieAz5kVDkKtF0_HU_9BkFA71tH2j4WovkU"
|
| 24 |
+
qdrant_endpoint = "https://9ea9b30f-4284-455b-bbae-65e4e458ed35.europe-west3-0.gcp.cloud.qdrant.io"
|
| 25 |
+
qdrant_client = QdrantClient(
|
| 26 |
+
url=qdrant_endpoint,
|
| 27 |
+
api_key=qdrant_api_key,
|
| 28 |
+
prefer_grpc=True,
|
| 29 |
+
)
|
| 30 |
+
sparse_embeddings = FastEmbedSparse(model_name="Qdrant/BM25")
|
| 31 |
+
embedding = add_custom_embedding_model(
|
| 32 |
+
model_name="models/Vietnamese_Embedding_OnnX_Quantized",
|
| 33 |
+
source_model="Mint1456/Vietnamese_Embedding_OnnX_Quantized",
|
| 34 |
+
dim=1024,
|
| 35 |
+
source_file="model.onnx"
|
| 36 |
+
)
|
| 37 |
+
client = QdrantVectorStore(
|
| 38 |
+
client=qdrant_client,
|
| 39 |
+
collection_name=COLLECTION_NAME,
|
| 40 |
+
embedding=embedding,
|
| 41 |
+
sparse_embedding=sparse_embeddings,
|
| 42 |
+
retrieval_mode=RetrievalMode.HYBRID,
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
def search_document(query, top_k, search_type, slider_lambda):
|
| 46 |
+
if not query.strip():
|
| 47 |
+
return "⚠️ Enter query to look up!"
|
| 48 |
+
try:
|
| 49 |
+
if search_type == "Default":
|
| 50 |
+
hits = client.similarity_search_with_score(query=query,k=top_k)
|
| 51 |
+
else:
|
| 52 |
+
|
| 53 |
+
hits = client.max_marginal_relevance_search_with_score(query=query, k=top_k, lambda_mult=slider_lambda)
|
| 54 |
+
except Exception as e:
|
| 55 |
+
print("error", e)
|
| 56 |
+
|
| 57 |
+
total_found = len(hits)
|
| 58 |
+
if total_found == 0:
|
| 59 |
+
return json.dumps([], indent=2)
|
| 60 |
+
|
| 61 |
+
# Nếu tìm được 10 mà đòi 15 -> chỉ lấy 10. Nếu tìm được 100 mà đòi 15 -> lấy 15
|
| 62 |
+
safe_k = min(top_k, total_found)
|
| 63 |
+
results = []
|
| 64 |
+
for i in range(safe_k):
|
| 65 |
+
hit = hits[i]
|
| 66 |
+
if hit[0].metadata.get('parent_chunking', None) is not None:
|
| 67 |
+
content = hit[0].metadata['parent_chunking']
|
| 68 |
+
elif hit[0].metadata.get('type', None) == "intro":
|
| 69 |
+
content = hit[0].page_content
|
| 70 |
+
else:
|
| 71 |
+
content = None
|
| 72 |
+
results.append({
|
| 73 |
+
"Score": round(hit[1], 4),
|
| 74 |
+
"Content": content,
|
| 75 |
+
# "Metadata:": {k: v for k, v in hit[0].metadata.items() if k != "page_content"}
|
| 76 |
+
})
|
| 77 |
|
| 78 |
+
return json.dumps(results, indent=2, ensure_ascii=False)
|
| 79 |
+
|
| 80 |
+
# --- GIAO DIỆN GRADIO ---
|
| 81 |
+
|
| 82 |
with gr.Blocks(title="Qdrant Vector DB Demo") as demo:
|
| 83 |
gr.Markdown("# 🚀 Demo Qdrant Vector Search")
|
| 84 |
gr.Markdown("Tool test nhanh khả năng thêm dữ liệu và tìm kiếm ngữ nghĩa (Semantic Search).")
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
with gr.Tab("2. Tìm Kiếm (Search)"):
|
| 88 |
+
with gr.Row():
|
| 89 |
+
with gr.Column(scale=1):
|
| 90 |
+
txt_query = gr.Textbox(label="Câu truy vấn", placeholder="Ví dụ: Tìm về một số thông tin trên website Bệnh Viện Tâm Anh", lines=2)
|
| 91 |
+
gr.Examples(
|
| 92 |
+
examples=[
|
| 93 |
+
"Rủi ro khi khâu cổ tử cung",
|
| 94 |
+
"Biến chứng của tràn dịch phổi",
|
| 95 |
+
"Triệu chứng của viêm phế quản",
|
| 96 |
+
"Phòng ngừa đau tim"
|
| 97 |
+
],
|
| 98 |
+
inputs=txt_query,
|
| 99 |
+
label="Ví dụ mẫu (Click để chọn)"
|
| 100 |
+
)
|
| 101 |
+
# Component mới: Chọn thuật toán
|
| 102 |
+
radio_type = gr.Radio(
|
| 103 |
+
choices=["Default", "MMR"],
|
| 104 |
+
value="Default",
|
| 105 |
+
label="Search Type",
|
| 106 |
+
info="Default: Giống nhất | MMR: Đa dạng kết quả"
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
# Component mới: Slider cho MMR
|
| 110 |
+
# visible=False mặc định, sẽ hiện khi chọn MMR (nếu bạn muốn làm xịn, ở đây để luôn True cho dễ)
|
| 111 |
+
slider_lambda = gr.Slider(
|
| 112 |
+
minimum=0.0, maximum=1.0, value=0.5, step=0.1,
|
| 113 |
+
label="Độ đa dạng (Lambda)",
|
| 114 |
+
info="1.0 = Chính xác nhất (như Default), 0.0 = Đa dạng nhất"
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
slider_k = gr.Slider(minimum=1, maximum=20, value=3, step=1, label="Số lượng kết quả (Top K)")
|
| 118 |
+
|
| 119 |
+
btn_search = gr.Button("🔍 Tìm kiếm ngay", variant="primary")
|
| 120 |
+
|
| 121 |
+
with gr.Column(scale=2):
|
| 122 |
+
out_search = gr.Code(label="Kết quả trả về (JSON)", language="json")
|
| 123 |
+
|
| 124 |
+
# Cập nhật inputs truyền vào hàm search
|
| 125 |
+
btn_search.click(
|
| 126 |
+
search_document,
|
| 127 |
+
inputs=[txt_query, slider_k, radio_type, slider_lambda],
|
| 128 |
+
outputs=out_search
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
print("Launching server on 0.0.0.0:7860...")
|
| 133 |
demo.launch(
|
| 134 |
server_name="0.0.0.0",
|
pyproject.toml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "hf-test"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
description = "Add your description here"
|
| 5 |
+
readme = "README.md"
|
| 6 |
+
requires-python = ">=3.13"
|
| 7 |
+
dependencies = [
|
| 8 |
+
"fast-json-repair>=0.2.0",
|
| 9 |
+
"fastembed>=0.3.0",
|
| 10 |
+
"gradio>=6.5.1",
|
| 11 |
+
"langchain>=1.2.9",
|
| 12 |
+
"langchain-community>=0.4.1",
|
| 13 |
+
"qdrant-client>=1.16.2",
|
| 14 |
+
"spaces>=0.47.0",
|
| 15 |
+
]
|
requirements.txt
CHANGED
|
@@ -2,3 +2,6 @@ fast-json-repair>=0.2.0
|
|
| 2 |
fastembed>=0.3.0
|
| 3 |
spaces
|
| 4 |
gradio
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
fastembed>=0.3.0
|
| 3 |
spaces
|
| 4 |
gradio
|
| 5 |
+
langchain>=1.2.9
|
| 6 |
+
langchain-community>=0.4.1
|
| 7 |
+
qdrant-client>=1.16.2
|