-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRJ_Recommendation_System.py
More file actions
119 lines (92 loc) · 3.44 KB
/
RJ_Recommendation_System.py
File metadata and controls
119 lines (92 loc) · 3.44 KB
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
RadioJavan - Minimal CLI
Takes only a song title and returns 10 recommendations.
Example usage:
python radiojavan_cli_min.py "Song Name"
"""
import argparse
import difflib
import os
import pickle
import sys
from typing import Tuple, Optional, List
import pandas as pd
CSV_PATH = "./models/data/RadioJavan_Top.csv"
MODEL_PATH = "./models/fainal_model/model.pkl" # same as your model path
def load_data(csv_path: str, model_path: str):
if not os.path.exists(csv_path):
print(f"[Error] CSV file not found: {csv_path}", file=sys.stderr)
sys.exit(2)
if not os.path.exists(model_path):
print(f"[Error] Model (pickle) file not found: {model_path}", file=sys.stderr)
sys.exit(2)
try:
df = pd.read_csv(csv_path)
except Exception as e:
print(f"[Error] Failed to read CSV: {e}", file=sys.stderr)
sys.exit(2)
df = df.drop_duplicates()
try:
with open(model_path, "rb") as f:
similarity = pickle.load(f)
except Exception as e:
print(f"[Error] Failed to load model: {e}", file=sys.stderr)
sys.exit(2)
indices = pd.Series(df.index, index=df["musicName"]).drop_duplicates()
return df, indices, similarity
def resolve_title(
raw_title: str, df: pd.DataFrame, max_suggestions: int = 7
) -> Tuple[Optional[str], List[str]]:
names = pd.unique(df["musicName"].astype(str))
lower_map = {name.lower(): name for name in names}
if raw_title.lower() in lower_map:
return lower_map[raw_title.lower()], []
suggestions = difflib.get_close_matches(
raw_title, names.tolist(), n=max_suggestions, cutoff=0.6
)
return None, suggestions
def radio_javan_recommendation(
title: str, df: pd.DataFrame, indices: pd.Series, similarity
) -> pd.DataFrame:
index = indices[title]
similarity_scores = list(enumerate(list(similarity[index])))
similarity_scores = sorted(similarity_scores, key=lambda x: x[1], reverse=True)
similarity_scores = similarity_scores[1 : 10 + 1] # top 10 results
target_indices = [i for i, _ in similarity_scores]
out = df[["musicName", "artistName"]].iloc[target_indices].copy()
out.insert(0, "rank", range(1, len(out) + 1))
return out
def main():
parser = argparse.ArgumentParser(
prog="radiojavan_cli_min",
description="Takes only a song title and returns 10 recommendations.",
)
parser.add_argument("title", type=str, help="Song title (preferably in quotes)")
args = parser.parse_args()
df, indices, similarity = load_data(CSV_PATH, MODEL_PATH)
matched, suggestions = resolve_title(args.title, df)
if matched is None:
if suggestions:
matched = suggestions[0]
print(
f'[Info] Exact title not found. Closest match selected: "{matched}"',
file=sys.stderr,
)
else:
print(f'[Error] Title not found: "{args.title}"', file=sys.stderr)
sys.exit(1)
try:
recs = radio_javan_recommendation(matched, df, indices, similarity)
except KeyError:
print(
"[Error] The selected title is not present in the index mapping. "
"Make sure the CSV and model are aligned.",
file=sys.stderr,
)
sys.exit(2)
with pd.option_context("display.max_colwidth", None):
print(recs.to_string(index=False))
if __name__ == "__main__":
main()