| import json
|
| import re
|
| from sklearn.feature_extraction.text import TfidfVectorizer
|
| from sklearn.metrics.pairwise import cosine_similarity
|
| import numpy as np
|
| import gradio as gr
|
|
|
|
|
| CONTACT_NUMBER = "+91-8977513427"
|
|
|
|
|
| FILE_PATH = 'final_merged_course_data.json'
|
| FULL_COURSE_DATA = {}
|
|
|
| def load_data():
|
| global FULL_COURSE_DATA
|
| try:
|
| with open(FILE_PATH, 'r') as f:
|
| FULL_COURSE_DATA = json.load(f)
|
| print(f"Course data loaded successfully from {FILE_PATH}!")
|
| except FileNotFoundError:
|
| print(f"Error: {FILE_PATH} not found. Please ensure it's in the same directory as this script.")
|
| FULL_COURSE_DATA = {}
|
| except json.JSONDecodeError as e:
|
| print(f"Error decoding JSON from {FILE_PATH}: {e}")
|
| FULL_COURSE_DATA = {}
|
| except Exception as e:
|
| print(f"An unexpected error occurred during data loading: {e}")
|
| FULL_COURSE_DATA = {}
|
|
|
|
|
| load_data()
|
|
|
|
|
|
|
|
|
| STOP_WORDS_FOR_MATCHING = set([
|
| "a", "an", "the", "in", "for", "of", "on", "and", "or", "is", "what",
|
| "how", "much", "long", "tell", "me", "about", "my", "i", "to", "get",
|
| "know", "please", "can", "you", "any", "info", "information", "regarding",
|
| "want", "looking", "do", "have", "program", "programs", "details",
|
| "fee", "fees", "cost", "price", "duration", "length", "admission",
|
| "study", "course", "degree", "degrees", "bachelor", "master", "diploma",
|
| "honors", "with", "research", "general", "le", "pg", "post", "graduate",
|
| "doctorate", "philosophy", "semesters", "semester", "years", "year",
|
| "months", "month", "plus", "ne", "nep",
|
| "btech", "mtech", "b.tech", "m.tech", "b.com", "b.b.a", "b.c.a", "m.c.a",
|
| "b.sc", "m.sc", "ll.b", "ll.m", "d.voc", "b.voc", "ph.d", "b.lis", "m.lis",
|
| "d.lis", "b.p.e.s", "m.p.e.s", "mph", "bmlt", "brit", "bpt", "b.ph",
|
| "d.pharmacy", "b.pharmacy", "advacne", "b.a", "b.e", "bsc", "msc", "bba", "bcom",
|
| "engineering", "management", "science", "arts", "humanities", "social", "sciences",
|
| "technology", "agricultural", "agriculture", "yoga", "pharmacy", "law", "paramedical",
|
| "vocational", "phd", "library", "education", "journalism", "fashion",
|
| "executive", "e", "s", "hons"
|
| ])
|
|
|
|
|
| ABBREVIATION_MAP = {
|
| "cs": "computer science", "cse": "computer science engineering",
|
| "ai": "artificial intelligence", "ml": "machine learning",
|
| "it": "information technology", "hr": "human resource",
|
| "hrm": "human resource management", "scm": "supply chain management",
|
| "ib": "international business", "dm": "digital marketing",
|
| "ui": "user interface", "ux": "user experience",
|
| "vfx": "visual effects", "ar": "augmented reality", "vr": "virtual reality",
|
| "iot": "internet things", "mlt": "medical lab technology",
|
| "ott": "operation theater technology", "rit": "radiology imaginary technology",
|
| "ece": "electronics communication engineering", "eee": "electronics electrical engineering",
|
| "me": "mechanical engineering", "fshm": "fire safety hazard management",
|
| "bnys": "bachelor naturopathy yogic sciences", "dnys": "diploma naturopathy yogic sciences",
|
| "mpes": "physical education sports", "llis": "library information science",
|
| "jmc": "journalism mass communication", "pcm": "physics chemistry mathematics",
|
| "zbc": "zoology botany chemistry", "llm": "master laws"
|
| }
|
|
|
| def normalize_text_for_tfidf(text):
|
| """
|
| Cleans and normalizes text for TF-IDF.
|
| Removes punctuation, applies abbreviation map, removes stop words.
|
| Sorts unique words to create a canonical form.
|
| """
|
| if not isinstance(text, str):
|
| return ""
|
|
|
| text = re.sub(r'[^\w\s]', '', text).lower()
|
| text = re.sub(r'\s+', ' ', text).strip()
|
|
|
| words = []
|
| for word in text.split():
|
| words.append(ABBREVIATION_MAP.get(word, word))
|
| text = ' '.join(words)
|
|
|
| words = [word for word in text.split() if word not in STOP_WORDS_FOR_MATCHING]
|
|
|
| return ' '.join(sorted(list(set(words))))
|
|
|
|
|
|
|
| all_normalized_course_names_for_tfidf = []
|
|
|
| normalized_name_to_original_map = {}
|
|
|
| if FULL_COURSE_DATA:
|
| for category_key, courses_in_category in FULL_COURSE_DATA.get("indian", {}).items():
|
| for top_level_course_name, course_details_dict in courses_in_category.items():
|
|
|
|
|
| normalized_top_level = normalize_text_for_tfidf(top_level_course_name)
|
| if normalized_top_level:
|
| all_normalized_course_names_for_tfidf.append(normalized_top_level)
|
|
|
| if normalized_top_level not in normalized_name_to_original_map:
|
| normalized_name_to_original_map[normalized_top_level] = {
|
| "source_type": "top_level",
|
| "original_display_name": top_level_course_name,
|
| "details_dict_ref": course_details_dict
|
| }
|
|
|
|
|
| for specific_type_name, details in course_details_dict.items():
|
|
|
| full_course_variant_name_raw = f"{top_level_course_name} ({specific_type_name})" if specific_type_name != "General" else top_level_course_name
|
|
|
|
|
| normalized_variant = normalize_text_for_tfidf(full_course_variant_name_raw)
|
|
|
| if normalized_variant and normalized_variant not in normalized_name_to_original_map:
|
| all_normalized_course_names_for_tfidf.append(normalized_variant)
|
|
|
| normalized_name_to_original_map[normalized_variant] = {
|
| "source_type": "variant",
|
| "original_display_name": full_course_variant_name_raw,
|
| "details_ref": details
|
| }
|
|
|
|
|
| vectorizer = TfidfVectorizer(stop_words=None, ngram_range=(1, 2), min_df=1, max_df=0.9)
|
|
|
| course_tfidf_matrix = None
|
| if all_normalized_course_names_for_tfidf:
|
| course_tfidf_matrix = vectorizer.fit_transform(all_normalized_course_names_for_tfidf)
|
| print(f"TF-IDF model built with {len(all_normalized_course_names_for_tfidf)} unique normalized course names.")
|
| else:
|
| print("Warning: No normalized course names found to build TF-IDF model. Check data loading.")
|
|
|
|
|
|
|
| def get_course_details(user_query: str):
|
| """
|
| Retrieves admission fee and duration for a given user query.
|
| Uses TF-IDF vectorization and cosine similarity to find the best matching course.
|
| """
|
| if not FULL_COURSE_DATA or course_tfidf_matrix is None or not all_normalized_course_names_for_tfidf:
|
| return None
|
|
|
|
|
| normalized_user_query = normalize_text_for_tfidf(user_query)
|
|
|
| if not normalized_user_query:
|
| return None
|
|
|
| try:
|
| query_vector = vectorizer.transform([normalized_user_query])
|
| similarity_scores = cosine_similarity(query_vector, course_tfidf_matrix).flatten()
|
|
|
| best_match_index = np.argmax(similarity_scores)
|
| best_score = similarity_scores[best_match_index]
|
|
|
|
|
| SIMILARITY_THRESHOLD = 0.3
|
|
|
| if best_score < SIMILARITY_THRESHOLD:
|
| return None
|
|
|
|
|
| matched_normalized_name = all_normalized_course_names_for_tfidf[best_match_index]
|
| matched_data_info = normalized_name_to_original_map.get(matched_normalized_name)
|
|
|
| if matched_data_info:
|
| details = None
|
| display_name = matched_data_info["original_display_name"]
|
|
|
| if matched_data_info["source_type"] == "variant":
|
|
|
| details = matched_data_info["details_ref"]
|
| elif matched_data_info["source_type"] == "top_level":
|
|
|
| details_dict = matched_data_info["details_dict_ref"]
|
| details = details_dict.get("General") or next(iter(details_dict.values()), None)
|
|
|
| display_name = matched_data_info["original_display_name"]
|
| if details and details_dict.get("General") is None and len(details_dict) == 1:
|
|
|
| specific_type_name = list(details_dict.keys())[0]
|
| display_name = f"{matched_data_info['original_display_name']} ({specific_type_name})"
|
|
|
|
|
| if details:
|
| return {
|
| "course_name": display_name,
|
| "admission_fee": details.get("admission_fee"),
|
| "duration": details.get("duration")
|
| }
|
| except Exception as e:
|
| pass
|
|
|
| return None
|
|
|
| def process_user_query(user_message: str):
|
| """
|
| Main function to process user input and generate a response.
|
| Strictly provides admission fee, duration, and contact number.
|
| """
|
| user_message_lower = user_message.lower().strip()
|
|
|
|
|
| normalized_message_words_for_greeting = set(re.sub(r'[^\w\s]', '', user_message_lower).lower().split())
|
| greetings_keywords = {"hello", "hi", "hey"}
|
| if len(normalized_message_words_for_greeting.intersection(greetings_keywords)) > 0 and len(user_message_lower.split()) < 3:
|
| return (f"Hello there! I can tell you the admission fee and duration for specific courses. "
|
| f"What course are you interested in? For more details, please contact our admissions office at {CONTACT_NUMBER}.")
|
|
|
| details = get_course_details(user_message)
|
|
|
| if details:
|
| admission_fee = details.get("admission_fee", "not specified")
|
| duration = details.get("duration", "not specified")
|
|
|
|
|
| if isinstance(admission_fee, str) and admission_fee != "not specified":
|
| if not admission_fee.startswith('₹') and not admission_fee.startswith('$') and re.match(r'^[\d,\.]+$', admission_fee):
|
| admission_fee = f"₹{admission_fee}"
|
|
|
| return (f"The admission fee for {details['course_name']} is {admission_fee} "
|
| f"and the duration is {duration}. "
|
| f"For more details, please contact our admissions office at {CONTACT_NUMBER}.")
|
| else:
|
| return (f"I couldn't find details for the course you mentioned. "
|
| f"Please make sure you've typed the full and correct course name. "
|
| f"I can tell you the admission fee and duration. "
|
| f"For other inquiries, please contact our admissions office at {CONTACT_NUMBER}.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| import gradio as gr
|
|
|
|
|
| iface = gr.ChatInterface(
|
| fn=process_user_query,
|
| chatbot=gr.Chatbot(height=300),
|
| textbox=gr.Textbox(placeholder="Ask about a course, fee, or duration...", container=False, scale=7),
|
| theme="soft",
|
| examples=[
|
| "What is the admission fee for B.Tech. Computer Science & Engineering?",
|
| "How long is the Master of Business Administration Finance course?",
|
| "Cost of B.C.A. (Honors), B.C.A. (Honors with Research) General",
|
| "Fee for LL.B. General",
|
| "Tell me about PG Diploma Medical Lab Technology (MLT)",
|
| "What's the admission cost for MBA Project Management?",
|
| "Fee for B.Sc. Chemistry",
|
| "What's the fee for Rocket Science PhD?"
|
| ],
|
| title="Course Information AI Assistant",
|
| description="I can provide you with the admission fee and duration for specific courses. For other inquiries, please contact our admissions office.",
|
| clear_btn="Clear Chat",
|
| submit_btn="Send"
|
| )
|
|
|
|
|
|
|
|
|
| iface.launch(share=False) |