File size: 6,091 Bytes
cb87184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c215aac
 
cb87184
c215aac
 
 
 
 
 
 
 
 
 
 
 
cb87184
c215aac
cb87184
 
 
c215aac
cb87184
 
 
c215aac
cb87184
 
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
120
121
122
123

from collections import defaultdict
from difflib import SequenceMatcher

# NOTE: You must define search_reviews, filter_relevant, metadata, etc.

def similar(a, b):
    return SequenceMatcher(None, a, b).ratio()

def keyword_match_reviews(query, metadata):
    query = query.strip().replace("؟", "")
    keywords = set(query.split())
    results = []
    for row in metadata:
        prof = str(row["professor"])
        course = str(row["course"])
        for k in keywords:
            if k in prof or k in course or similar(k, prof) > 0.7 or similar(k, course) > 0.7:
                results.append(row)
                break
    return results

def relevance_score(row, query):
    score = 0
    if row["professor"] in query:
        score += 2
    if row["course"] in query:
        score += 2
    if row["professor"].split()[0] in query:
        score += 1
    if row["course"].split()[0] in query:
        score += 1
    return score

def build_strict_context(reviews, user_question):
    prof_match_scores = defaultdict(int)
    course_match_scores = defaultdict(int)
    for r in reviews:
        prof_sim = similar(user_question, r["professor"])
        course_sim = similar(user_question, r["course"])
        if prof_sim > 0.6:
            prof_match_scores[r["professor"]] += prof_sim
        if course_sim > 0.6:
            course_match_scores[r["course"]] += course_sim

    best_prof = max(prof_match_scores, key=prof_match_scores.get, default="")
    best_course = max(course_match_scores, key=course_match_scores.get, default="")

    if best_prof and best_course:
        filtered = [r for r in reviews if similar(best_prof, r["professor"]) > 0.85 and similar(best_course, r["course"]) > 0.85]
    elif best_course:
        filtered = [r for r in reviews if similar(best_course, r["course"]) > 0.85]
    elif best_prof:
        filtered = [r for r in reviews if similar(best_prof, r["professor"]) > 0.85]
    else:
        filtered = reviews

    result = f"👨‍🏫 استاد: {best_prof or '[نامشخص]'} — 📚 درس: {best_course or '[نامشخص]'}\\n💬 نظرات:\\n"
    for i, r in enumerate(filtered, 1):
        result += f"{i}. {r['comment'].strip()}\\n🔗 لینک: {r['link']}\\n\\n"
    return result

def truncate_reviews_to_fit(reviews, max_chars=127000):
    total = 0
    final = []
    for r in reviews:
        size = len(r["comment"])
        if total + size > max_chars:
            break
        final.append(r)
        total += size
    return final

def answer_question(user_question, model):
    print(f"\\n🧠 Starting debug for question: {user_question}")
    retrieved = search_reviews(user_question, top_k=100)
    print(f"🔍 FAISS returned {len(retrieved)} raw rows")
    retrieved = filter_relevant(retrieved, user_question)
    print(f"✅ After filter_relevant(): {len(retrieved)} rows")
    keyword_hits = keyword_match_reviews(user_question, metadata)
    print(f"🔠 Keyword hits found: {len(keyword_hits)}")
    existing_links = set(r["link"] for r in retrieved)
    added = 0
    for r in keyword_hits:
        if r["link"] not in existing_links:
            retrieved.append(r)
            added += 1
    print(f"➕ Added {added} unique fallback keyword rows")
    print(f"📊 Total before truncation: {len(retrieved)}")
    if not retrieved:
        return "❌ هیچ تجربه‌ای در مورد سوال شما در داده‌های کانال یافت نشد."
    retrieved.sort(key=lambda r: relevance_score(r, user_question), reverse=True)
    retrieved = truncate_reviews_to_fit(retrieved)
    print(f"✂️ After truncation: {len(retrieved)} rows")
    context = build_strict_context(retrieved, user_question)
    print("📝 Sample context sent to Gemini:\\n", context[:1000], "\\n...")
    prompt = f"""شما یک دستیار هوشمند انتخاب واحد هستید که فقط و فقط بر اساس نظرات واقعی دانشجویان از کانال @IAUCourseExp پاسخ می‌دهید. کار شما کمک به دانشجویان برای انتخاب استاد و درس، بر اساس تجربیات ثبت‌شده در این کانال است.



❗ قوانین مهم:

- فقط از داده‌های همین نظرات استفاده کن. هیچ اطلاعات اضافی، حدسی یا اینترنتی استفاده نکن.

- اگر هیچ نظری درباره سؤال وجود ندارد، فقط بگو: «هیچ تجربه‌ای دربارهٔ این مورد در کانال ثبت نشده است.»

- سوالات دانشجو می‌توانند از انواع مختلف باشند:

  • بررسی یک استاد خاص

  • مقایسه چند استاد برای یک درس

  • معرفی بهترین یا بدترین استادهای یک درس

  • تحلیل نظر کلی دانشجویان درمورد یک درس خاص

  بنابراین آماده باش که با توجه به داده‌ها به هر نوع سوال، دقیق و قابل اعتماد پاسخ بدهی.

- همه‌ی نظرات مربوط به سوال را بررسی کن (نه فقط یکی یا دو تا) و به‌صورت فهرست‌وار یا خلاصه‌شده تحلیلشان کن.

- برای هر نظر، لینک تلگرام مربوطه را نیز حتماً ذکر کن.

- در پایان پاسخ، نتیجه‌گیری نهایی خود را بنویس: آیا این استاد برای این درس توصیه می‌شود یا نه — فقط بر اساس همین نظرات.

- در انتها حتماً بنویس:

📊 این پاسخ بر اساس بررسی {len(retrieved)} نظر دانشجویی نوشته شده است.



🔎 سوال دانشجو:

{user_question}



📄 نظرات دانشجویان (برگرفته از کانال تجربیات انتخاب واحد):

{context}



📘 پاسخ نهایی:

"""
    response = model.generate_content(prompt)
    return response.text