Spaces:
Runtime error
Runtime error
update
Browse files
src/similarity_model/__pycache__/semantic_search.cpython-313.pyc
CHANGED
|
Binary files a/src/similarity_model/__pycache__/semantic_search.cpython-313.pyc and b/src/similarity_model/__pycache__/semantic_search.cpython-313.pyc differ
|
|
|
src/similarity_model/semantic_search.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
| 1 |
-
# src/semantic_search.py
|
| 2 |
-
|
| 3 |
import re
|
| 4 |
import ast
|
| 5 |
import logging
|
|
@@ -15,25 +13,17 @@ from Data.database.sql_connector import (
|
|
| 15 |
load_preprocessed_projects
|
| 16 |
)
|
| 17 |
|
| 18 |
-
# =====================================================
|
| 19 |
-
# Logging
|
| 20 |
-
# =====================================================
|
| 21 |
logging.basicConfig(
|
| 22 |
level=logging.INFO,
|
| 23 |
format="%(asctime)s | %(levelname)s | %(message)s"
|
| 24 |
)
|
| 25 |
logger = logging.getLogger(__name__)
|
| 26 |
|
| 27 |
-
# =====================================================
|
| 28 |
-
# Config
|
| 29 |
-
# =====================================================
|
| 30 |
DEFAULT_MODEL = "all-MiniLM-L6-v2"
|
| 31 |
|
| 32 |
TITLE_COL = "project_title"
|
| 33 |
TECH_COL = "technologies"
|
| 34 |
|
| 35 |
-
# Resolve paths relative to the project root (3 levels up from this file:
|
| 36 |
-
# src/similarity_model/semantic_search.py -> src/similarity_model -> src -> project root)
|
| 37 |
_PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
| 38 |
|
| 39 |
INDEX_PATH = _PROJECT_ROOT / "models" / "faiss_index.bin"
|
|
@@ -43,9 +33,6 @@ EMBED_PATH = _PROJECT_ROOT / "models" / "project_embeddings.npy"
|
|
| 43 |
TOP_K = 20
|
| 44 |
MIN_SCORE = 0.35
|
| 45 |
|
| 46 |
-
# =====================================================
|
| 47 |
-
# Text Helpers
|
| 48 |
-
# =====================================================
|
| 49 |
def normalize_text(text: str) -> str:
|
| 50 |
"""
|
| 51 |
Normalize user query to match preprocessing style.
|
|
@@ -61,23 +48,17 @@ def normalize_text(text: str) -> str:
|
|
| 61 |
|
| 62 |
return text
|
| 63 |
|
| 64 |
-
|
| 65 |
def tokenize(text: str) -> set:
|
| 66 |
"""
|
| 67 |
Tokenize normalized text.
|
| 68 |
"""
|
| 69 |
return set(normalize_text(text).split())
|
| 70 |
|
| 71 |
-
|
| 72 |
-
# =====================================================
|
| 73 |
-
# Cached Loaders
|
| 74 |
-
# =====================================================
|
| 75 |
@lru_cache(maxsize=1)
|
| 76 |
def load_model():
|
| 77 |
logger.info(f"Loading model: {DEFAULT_MODEL}")
|
| 78 |
return SentenceTransformer(DEFAULT_MODEL)
|
| 79 |
|
| 80 |
-
|
| 81 |
@lru_cache(maxsize=1)
|
| 82 |
def load_faiss_index():
|
| 83 |
if not INDEX_PATH.exists():
|
|
@@ -86,7 +67,6 @@ def load_faiss_index():
|
|
| 86 |
logger.info("Loading FAISS index...")
|
| 87 |
return faiss.read_index(str(INDEX_PATH))
|
| 88 |
|
| 89 |
-
|
| 90 |
@lru_cache(maxsize=1)
|
| 91 |
def load_metadata():
|
| 92 |
|
|
@@ -98,7 +78,6 @@ def load_metadata():
|
|
| 98 |
|
| 99 |
return df.reset_index(drop=True)
|
| 100 |
|
| 101 |
-
|
| 102 |
@lru_cache(maxsize=1)
|
| 103 |
def load_embeddings():
|
| 104 |
if not EMBED_PATH.exists():
|
|
@@ -107,10 +86,6 @@ def load_embeddings():
|
|
| 107 |
logger.info("Loading embeddings...")
|
| 108 |
return np.load(str(EMBED_PATH))
|
| 109 |
|
| 110 |
-
|
| 111 |
-
# =====================================================
|
| 112 |
-
# Core Result Builder
|
| 113 |
-
# =====================================================
|
| 114 |
def build_results(
|
| 115 |
df: pd.DataFrame,
|
| 116 |
ids,
|
|
@@ -133,8 +108,7 @@ def build_results(
|
|
| 133 |
final_score = float(score)
|
| 134 |
|
| 135 |
# ---------------------------------------------
|
| 136 |
-
|
| 137 |
-
# ---------------------------------------------
|
| 138 |
if query_words:
|
| 139 |
|
| 140 |
title_words = tokenize(row[TITLE_COL])
|
|
@@ -149,8 +123,7 @@ def build_results(
|
|
| 149 |
if overlap > 0:
|
| 150 |
final_score += 0.02 * overlap
|
| 151 |
|
| 152 |
-
|
| 153 |
-
final_score = min(final_score, 1.0)
|
| 154 |
|
| 155 |
if final_score < min_score:
|
| 156 |
continue
|
|
@@ -174,10 +147,6 @@ def build_results(
|
|
| 174 |
.reset_index(drop=True)
|
| 175 |
)
|
| 176 |
|
| 177 |
-
|
| 178 |
-
# =====================================================
|
| 179 |
-
# Search by Free Text
|
| 180 |
-
# =====================================================
|
| 181 |
def search_by_text(
|
| 182 |
query_text: str,
|
| 183 |
k: int = TOP_K,
|
|
@@ -206,10 +175,6 @@ def search_by_text(
|
|
| 206 |
min_score=min_score
|
| 207 |
)
|
| 208 |
|
| 209 |
-
|
| 210 |
-
# =====================================================
|
| 211 |
-
# Search Similar to Existing Project
|
| 212 |
-
# =====================================================
|
| 213 |
def search_by_project_id(
|
| 214 |
project_id: int,
|
| 215 |
k: int = TOP_K,
|
|
@@ -270,10 +235,6 @@ def search_by_project_id(
|
|
| 270 |
|
| 271 |
return pd.DataFrame(rows)
|
| 272 |
|
| 273 |
-
|
| 274 |
-
# =====================================================
|
| 275 |
-
# Compare Two Ideas
|
| 276 |
-
# =====================================================
|
| 277 |
def compare_two_ideas(
|
| 278 |
text_a: str,
|
| 279 |
text_b: str
|
|
@@ -293,33 +254,3 @@ def compare_two_ideas(
|
|
| 293 |
score = float(np.dot(vecs[0], vecs[1]))
|
| 294 |
|
| 295 |
return round(score, 4)
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
# =====================================================
|
| 299 |
-
# Example Run
|
| 300 |
-
# =====================================================
|
| 301 |
-
if __name__ == "__main__":
|
| 302 |
-
|
| 303 |
-
print("\n=== Search by Text ===")
|
| 304 |
-
print(
|
| 305 |
-
search_by_text(
|
| 306 |
-
"mobile app for expense tracking using flutter",
|
| 307 |
-
k=5
|
| 308 |
-
)
|
| 309 |
-
)
|
| 310 |
-
|
| 311 |
-
print("\n=== Similar Projects ===")
|
| 312 |
-
print(
|
| 313 |
-
search_by_project_id(
|
| 314 |
-
project_id=0,
|
| 315 |
-
k=5
|
| 316 |
-
)
|
| 317 |
-
)
|
| 318 |
-
|
| 319 |
-
print("\n=== Compare Two Ideas ===")
|
| 320 |
-
print(
|
| 321 |
-
compare_two_ideas(
|
| 322 |
-
"AI Medical Chatbot",
|
| 323 |
-
"Healthcare Assistant with AI"
|
| 324 |
-
)
|
| 325 |
-
)
|
|
|
|
|
|
|
|
|
|
| 1 |
import re
|
| 2 |
import ast
|
| 3 |
import logging
|
|
|
|
| 13 |
load_preprocessed_projects
|
| 14 |
)
|
| 15 |
|
|
|
|
|
|
|
|
|
|
| 16 |
logging.basicConfig(
|
| 17 |
level=logging.INFO,
|
| 18 |
format="%(asctime)s | %(levelname)s | %(message)s"
|
| 19 |
)
|
| 20 |
logger = logging.getLogger(__name__)
|
| 21 |
|
|
|
|
|
|
|
|
|
|
| 22 |
DEFAULT_MODEL = "all-MiniLM-L6-v2"
|
| 23 |
|
| 24 |
TITLE_COL = "project_title"
|
| 25 |
TECH_COL = "technologies"
|
| 26 |
|
|
|
|
|
|
|
| 27 |
_PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
| 28 |
|
| 29 |
INDEX_PATH = _PROJECT_ROOT / "models" / "faiss_index.bin"
|
|
|
|
| 33 |
TOP_K = 20
|
| 34 |
MIN_SCORE = 0.35
|
| 35 |
|
|
|
|
|
|
|
|
|
|
| 36 |
def normalize_text(text: str) -> str:
|
| 37 |
"""
|
| 38 |
Normalize user query to match preprocessing style.
|
|
|
|
| 48 |
|
| 49 |
return text
|
| 50 |
|
|
|
|
| 51 |
def tokenize(text: str) -> set:
|
| 52 |
"""
|
| 53 |
Tokenize normalized text.
|
| 54 |
"""
|
| 55 |
return set(normalize_text(text).split())
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
@lru_cache(maxsize=1)
|
| 58 |
def load_model():
|
| 59 |
logger.info(f"Loading model: {DEFAULT_MODEL}")
|
| 60 |
return SentenceTransformer(DEFAULT_MODEL)
|
| 61 |
|
|
|
|
| 62 |
@lru_cache(maxsize=1)
|
| 63 |
def load_faiss_index():
|
| 64 |
if not INDEX_PATH.exists():
|
|
|
|
| 67 |
logger.info("Loading FAISS index...")
|
| 68 |
return faiss.read_index(str(INDEX_PATH))
|
| 69 |
|
|
|
|
| 70 |
@lru_cache(maxsize=1)
|
| 71 |
def load_metadata():
|
| 72 |
|
|
|
|
| 78 |
|
| 79 |
return df.reset_index(drop=True)
|
| 80 |
|
|
|
|
| 81 |
@lru_cache(maxsize=1)
|
| 82 |
def load_embeddings():
|
| 83 |
if not EMBED_PATH.exists():
|
|
|
|
| 86 |
logger.info("Loading embeddings...")
|
| 87 |
return np.load(str(EMBED_PATH))
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
def build_results(
|
| 90 |
df: pd.DataFrame,
|
| 91 |
ids,
|
|
|
|
| 108 |
final_score = float(score)
|
| 109 |
|
| 110 |
# ---------------------------------------------
|
| 111 |
+
# ---------------------------------------------
|
|
|
|
| 112 |
if query_words:
|
| 113 |
|
| 114 |
title_words = tokenize(row[TITLE_COL])
|
|
|
|
| 123 |
if overlap > 0:
|
| 124 |
final_score += 0.02 * overlap
|
| 125 |
|
| 126 |
+
final_score = min(final_score, 1.0)
|
|
|
|
| 127 |
|
| 128 |
if final_score < min_score:
|
| 129 |
continue
|
|
|
|
| 147 |
.reset_index(drop=True)
|
| 148 |
)
|
| 149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
def search_by_text(
|
| 151 |
query_text: str,
|
| 152 |
k: int = TOP_K,
|
|
|
|
| 175 |
min_score=min_score
|
| 176 |
)
|
| 177 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
def search_by_project_id(
|
| 179 |
project_id: int,
|
| 180 |
k: int = TOP_K,
|
|
|
|
| 235 |
|
| 236 |
return pd.DataFrame(rows)
|
| 237 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
def compare_two_ideas(
|
| 239 |
text_a: str,
|
| 240 |
text_b: str
|
|
|
|
| 254 |
score = float(np.dot(vecs[0], vecs[1]))
|
| 255 |
|
| 256 |
return round(score, 4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|