File size: 4,052 Bytes
b9a685a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import pandas as pd
import numpy as np
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import gradio as gr

# Step 1: Load the CSV file
df = pd.read_csv('./White-Stride-Red-68.csv')

# Step 2: Filter out rows where the 'detail_โครงการ' column is NaN or an empty string
text_column = 'detail_โครงการ'
df_filtered = df[df[text_column].notna() & df[text_column].str.strip().ne('')]

# Reset index to ensure we have a unique identifier for each row
df_filtered = df_filtered.reset_index()  # 'index' becomes a column now

# Step 3: Extract the text column for embeddings
texts = df_filtered[text_column].astype(str).tolist()

# Keep the entire DataFrame rows as a list of dictionaries
rows = df_filtered.to_dict('records')

# **New Step**: Split texts into chunks of up to 500 characters
chunks = []
chunk_rows = []

for idx, text in enumerate(texts):
    # Split text into chunks of up to 500 characters
    text_chunks = [text[i:i+500] for i in range(0, len(text), 500)]
    # For each chunk, store the chunk and its corresponding row
    for chunk in text_chunks:
        chunks.append(chunk)
        chunk_rows.append(rows[idx])

# Step 4: Load the pre-trained model
model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')

# Step 5: Generate embeddings for all text chunks
embeddings = model.encode(chunks, show_progress_bar=True)

# Step 6: Define the semantic search function
def semantic_search(query, embeddings, chunks, chunk_rows, top_n=50):
    # Generate embedding for the query
    query_embedding = model.encode([query])
    
    # Compute cosine similarities
    similarities = cosine_similarity(query_embedding, embeddings)[0]
    
    # Get the indices of the chunks sorted by similarity
    sorted_indices = np.argsort(similarities)[::-1]
    
    # Collect top_n unique results based on the original row
    results = []
    seen_row_ids = set()
    for idx in sorted_indices:
        row = chunk_rows[idx]
        row_id = row['index']  # Unique identifier for the row
        if row_id not in seen_row_ids:
            seen_row_ids.add(row_id)
            results.append((row, similarities[idx]))
            if len(results) >= top_n:
                break
    return results

# Step 7: Create the Gradio interface
def search_interface(query):
    # Perform the search
    results = semantic_search(query, embeddings, chunks, chunk_rows)
    
    # Specify the columns to display
    columns_to_display = ['ชื่อกระทรวง', 'งบประมาณปี68', 'ชื่อสำนักงาน', 'งบประมาณปี68_สำนักงาน', 'ชื่อโครงการ', 'งบประมาณ_โครงการ']
    
    # Prepare the output
    output = ""
    for row, score in results:
        output += f"**Score:** {score:.4f}\n\n"
        
        # Display only specified columns and skip NaNs
        for key, value in row.items():
            if key in columns_to_display and not pd.isna(value):
                output += f"**{key}:** {value}\n\n"
                
        # Display 'detail_โครงการ' if 'ชื่อโครงการ' or 'งบประมาณ_โครงการ' is NaN
        if pd.isna(row.get('ชื่อโครงการ')) or pd.isna(row.get('งบประมาณ_โครงการ')):
            output += f"**detail_โครงการ:** {row.get('detail_โครงการ')}\n\n"
        output += "---\n\n"
    
    return output

iface = gr.Interface(
    fn=search_interface,
    inputs=gr.Textbox(lines=2, placeholder='Enter your search query here...'),
    outputs="markdown",
    title="Semantic Search Application",
    description="Enter a search query to find the most relevant entries from the dataset.",
)

if __name__ == "__main__":
    iface.launch(share=True)