Spaces:
Sleeping
Sleeping
| # from flask import Flask, request, jsonify | |
| # from flask_cors import CORS | |
| # import os | |
| # # Prevent native runtime conflicts between TensorFlow's and PyTorch's bundled | |
| # # protobuf / OpenMP libraries, which can cause a silent segfault (exit 139) | |
| # # when both libraries are loaded in the same process. | |
| # os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python" | |
| # os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" | |
| # os.environ["OMP_NUM_THREADS"] = "1" | |
| # import pickle | |
| # import numpy as np | |
| # import re | |
| # import random | |
| # # import spaces | |
| # # Import sentence-transformers (and its PyTorch dependency) BEFORE TensorFlow. | |
| # # Whichever loads its native protobuf/OpenMP runtime first tends to avoid the | |
| # # conflict that causes the segfault. | |
| # print("Step 0a: Importing SentenceTransformer...") | |
| # from sentence_transformers import SentenceTransformer, util | |
| # print("Step 0a done: sentence-transformers imported OK") | |
| # print("Step 0: Importing TensorFlow / Keras...") | |
| # from tensorflow.keras.models import load_model | |
| # from tensorflow.keras.preprocessing.sequence import pad_sequences | |
| # print("Step 0 done: TensorFlow imported OK") | |
| # app = Flask(__name__) | |
| # CORS(app) # Zaroori hai! Isse Vercel (alag domain) se API call allow hogi | |
| # # ---------------------------- | |
| # # Load all saved files | |
| # # ---------------------------- | |
| # print("Loading model and data... please wait") | |
| # print("Step 1: Loading LSTM model (chatbot_lstm.h5)...") | |
| # model_lstm = load_model("chatbot_lstm.h5") | |
| # print("Step 1 done: LSTM model loaded OK") | |
| # print("Step 2: Loading tokenizer.pickle...") | |
| # with open("tokenizer.pickle", "rb") as f: | |
| # tokenizer = pickle.load(f) | |
| # print("Step 2 done") | |
| # print("Step 3: Loading label_encoder.pickle...") | |
| # with open("label_encoder.pickle", "rb") as f: | |
| # label_encoder = pickle.load(f) | |
| # print("Step 3 done") | |
| # print("Step 4: Loading responses_dict.pickle...") | |
| # with open("responses_dict.pickle", "rb") as f: | |
| # responses_dict = pickle.load(f) | |
| # print("Step 4 done") | |
| # print("Step 5: Loading intent_keywords.pickle...") | |
| # with open("intent_keywords.pickle", "rb") as f: | |
| # intent_keywords = pickle.load(f) | |
| # print("Step 5 done") | |
| # print("Step 6: Loading pattern_embeddings.pickle...") | |
| # with open("pattern_embeddings.pickle", "rb") as f: | |
| # pattern_embeddings = pickle.load(f) | |
| # print("Step 6 done") | |
| # print("Step 7: Loading semantic_pattern_to_intent.pickle...") | |
| # with open("semantic_pattern_to_intent.pickle", "rb") as f: | |
| # semantic_pattern_to_intent = pickle.load(f) | |
| # print("Step 7 done") | |
| # print("Step 8: Loading SentenceTransformer('all-MiniLM-L6-v2')...") | |
| # embedder = SentenceTransformer('all-MiniLM-L6-v2') | |
| # print("Step 8 done: embedder loaded OK") | |
| # max_len = 25 # training ke waqt jo value use ki thi wahi yahan bhi rakhna | |
| # print("Everything loaded successfully!") | |
| # # ---------------------------- | |
| # # Typo fix + text cleaning | |
| # # ---------------------------- | |
| # typo_fix = { | |
| # 'hlo': 'hello', 'helo': 'hello', 'hii': 'hi', 'hey': 'hi', | |
| # 'thanx': 'thanks', 'thnx': 'thanks', 'thx': 'thanks', | |
| # 'plz': 'please', 'pls': 'please', 'u': 'you', 'ur': 'your', | |
| # 'r': 'are', 'wat': 'what', 'wht': 'what', 'y': 'why' | |
| # } | |
| # def clean_text(text): | |
| # text = text.lower().strip() | |
| # words = text.split() | |
| # words = [typo_fix.get(w, w) for w in words] | |
| # text = " ".join(words) | |
| # text = re.sub(r"[^a-zA-Z0-9\s']", " ", text) | |
| # text = re.sub(r"\s+", " ", text).strip() | |
| # return text | |
| # # ---------------------------- | |
| # # Prediction layers | |
| # # ---------------------------- | |
| # def predict_lstm_raw(text): | |
| # seq = tokenizer.texts_to_sequences([text]) | |
| # padded = pad_sequences(seq, maxlen=max_len, padding='post') | |
| # pred = model_lstm.predict(padded, verbose=0)[0] | |
| # idx = int(np.argmax(pred)) | |
| # return label_encoder.inverse_transform([idx])[0], float(pred[idx]) | |
| # def predict_keyword(text): | |
| # query_words = set(text.split()) | |
| # scores = {} | |
| # for intent, keywords in intent_keywords.items(): | |
| # overlap = len(query_words & keywords) | |
| # if overlap > 0: | |
| # scores[intent] = overlap | |
| # if not scores: | |
| # return None, 0 | |
| # best_intent = max(scores, key=scores.get) | |
| # return best_intent, scores[best_intent] | |
| # def predict_semantic(text, threshold=0.45): | |
| # query_embedding = embedder.encode(text, convert_to_tensor=True) | |
| # scores = util.cos_sim(query_embedding, pattern_embeddings)[0] | |
| # best_idx = int(scores.argmax()) | |
| # best_score = float(scores[best_idx]) | |
| # if best_score < threshold: | |
| # return None, best_score | |
| # return semantic_pattern_to_intent[best_idx], best_score | |
| # def predict_intent_final(user_text): | |
| # text = clean_text(user_text) | |
| # lstm_intent, lstm_conf = predict_lstm_raw(text) | |
| # sem_intent, sem_score = predict_semantic(text) | |
| # kw_intent, kw_score = predict_keyword(text) | |
| # if sem_intent is not None and lstm_intent == sem_intent: | |
| # return lstm_intent, "LSTM+Semantic Agree", (lstm_conf + sem_score) / 2 | |
| # if sem_intent is not None and sem_score >= 0.5: | |
| # return sem_intent, "Semantic", sem_score | |
| # if kw_intent is not None and kw_score >= 1: | |
| # return kw_intent, "Keyword", kw_score | |
| # if lstm_conf >= 0.9: | |
| # return lstm_intent, "LSTM-only (risky)", lstm_conf | |
| # return None, "None", 0 | |
| # # @spaces.GPU # Not needed on CPU basic hardware — leave commented/removed | |
| # def chatbot_response(user_text): | |
| # intent, source, confidence = predict_intent_final(user_text) | |
| # if intent is None: | |
| # return "Sorry, mujhe samajh nahi aaya. Kya aap admission, fees, courses, ya contact details ke baare mein pooch rahe hain?" | |
| # return random.choice(responses_dict[intent]) | |
| # # ---------------------------- | |
| # # Routes | |
| # # ---------------------------- | |
| # @app.route("/", methods=["GET"]) | |
| # def health_check(): | |
| # return jsonify({"status": "ILS Chatbot API is running!"}) | |
| # @app.route("/chat", methods=["POST"]) | |
| # def chat(): | |
| # try: | |
| # user_message = request.json.get("message", "") | |
| # if not user_message.strip(): | |
| # return jsonify({"response": "Kuch toh likho!"}) | |
| # response = chatbot_response(user_message) | |
| # return jsonify({"response": response}) | |
| # except Exception as e: | |
| # # Surface real errors instead of letting the process crash silently | |
| # print(f"Error in /chat: {e}") | |
| # return jsonify({"response": "Kuch technical issue ho gaya, thodi der baad try karo."}), 500 | |
| # if __name__ == "__main__": | |
| # app.run(host="0.0.0.0", port=7860) | |
| from flask import Flask, request, jsonify | |
| from flask_cors import CORS | |
| import os | |
| # Prevent native runtime conflicts between TensorFlow's and PyTorch's bundled | |
| # protobuf / OpenMP libraries, which can cause a silent segfault (exit 139) | |
| # when both libraries are loaded in the same process. | |
| os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python" | |
| os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" | |
| os.environ["OMP_NUM_THREADS"] = "1" | |
| import pickle | |
| import numpy as np | |
| import re | |
| import random | |
| from huggingface_hub import hf_hub_download | |
| # --- CORRECT CONFIGURATION --- | |
| STORAGE_REPO_ID = "jarvis0852/path-ils-bot" | |
| # Import sentence-transformers (and its PyTorch dependency) BEFORE TensorFlow. | |
| print("Step 0a: Importing SentenceTransformer...") | |
| from sentence_transformers import SentenceTransformer, util | |
| print("Step 0a done: sentence-transformers imported OK") | |
| print("Step 0: Importing TensorFlow / Keras...") | |
| from tensorflow.keras.models import load_model | |
| from tensorflow.keras.preprocessing.sequence import pad_sequences | |
| print("Step 0 done: TensorFlow imported OK") | |
| app = Flask(__name__) | |
| CORS(app) | |
| # Helper function to dynamically fetch files from your large repository | |
| def fetch_from_hub(filename): | |
| print(f"Fetching {filename} from storage repository...") | |
| return hf_hub_download(repo_id=STORAGE_REPO_ID, filename=filename) | |
| # ---------------------------- | |
| # Load all saved files from Hub | |
| # ---------------------------- | |
| print("Loading model and data... please wait") | |
| print("Step 1: Loading LSTM model (chatbot_lstm.h5)...") | |
| lstm_path = fetch_from_hub("chatbot_lstm.h5") | |
| model_lstm = load_model(lstm_path) | |
| print("Step 1 done: LSTM model loaded OK") | |
| print("Step 2: Loading tokenizer.pickle...") | |
| # NOTE: Make sure "tokenizer.pickle" is uploaded to jarvis0852/path-ils-bot! | |
| tokenizer_path = fetch_from_hub("tokenizer.pickle") | |
| with open(tokenizer_path, "rb") as f: | |
| tokenizer = pickle.load(f) | |
| print("Step 2 done") | |
| print("Step 3: Loading label_encoder.pickle...") | |
| le_path = fetch_from_hub("label_encoder.pickle") | |
| with open(le_path, "rb") as f: | |
| label_encoder = pickle.load(f) | |
| print("Step 3 done") | |
| print("Step 4: Loading responses_dict.pickle...") | |
| resp_path = fetch_from_hub("responses_dict.pickle") | |
| with open(resp_path, "rb") as f: | |
| responses_dict = pickle.load(f) | |
| print("Step 4 done") | |
| print("Step 5: Loading intent_keywords.pickle...") | |
| kw_path = fetch_from_hub("intent_keywords.pickle") | |
| with open(kw_path, "rb") as f: | |
| intent_keywords = pickle.load(f) | |
| print("Step 5 done") | |
| print("Step 6: Loading pattern_embeddings.pickle...") | |
| embed_path = fetch_from_hub("pattern_embeddings.pickle") | |
| # --- FIX FOR CUDA TO CPU DESERIALIZATION ERROR --- | |
| import torch | |
| torch.serialization._validate_device = lambda location, backend_name: torch.device('cpu') | |
| # ------------------------------------------------ | |
| with open(embed_path, "rb") as f: | |
| pattern_embeddings = pickle.load(f) | |
| print("Step 6 done") | |
| print("Step 7: Loading semantic_pattern_to_intent.pickle...") | |
| sem_path = fetch_from_hub("semantic_pattern_to_intent.pickle") | |
| with open(sem_path, "rb") as f: | |
| semantic_pattern_to_intent = pickle.load(f) | |
| print("Step 7 done") | |
| print("Step 8: Loading SentenceTransformer('all-MiniLM-L6-v2')...") | |
| embedder = SentenceTransformer('all-MiniLM-L6-v2') | |
| print("Step 8 done: embedder loaded OK") | |
| max_len = 25 | |
| print("Everything loaded successfully!") | |
| # ---------------------------- | |
| # Typo fix + text cleaning | |
| # ---------------------------- | |
| typo_fix = { | |
| 'hlo': 'hello', 'helo': 'hello', 'hii': 'hi', 'hey': 'hi', | |
| 'thanx': 'thanks', 'thnx': 'thanks', 'thx': 'thanks', | |
| 'plz': 'please', 'pls': 'please', 'u': 'you', 'ur': 'your', | |
| 'r': 'are', 'wat': 'what', 'wht': 'what', 'y': 'why' | |
| } | |
| def clean_text(text): | |
| text = text.lower().strip() | |
| words = text.split() | |
| words = [typo_fix.get(w, w) for w in words] | |
| text = " ".join(words) | |
| text = re.sub(r"[^a-zA-Z0-9\s']", " ", text) | |
| text = re.sub(r"\s+", " ", text).strip() | |
| return text | |
| # ---------------------------- | |
| # Prediction layers | |
| # ---------------------------- | |
| def predict_lstm_raw(text): | |
| seq = tokenizer.texts_to_sequences([text]) | |
| padded = pad_sequences(seq, maxlen=max_len, padding='post') | |
| pred = model_lstm.predict(padded, verbose=0)[0] | |
| idx = int(np.argmax(pred)) | |
| return label_encoder.inverse_transform([idx])[0], float(pred[idx]) | |
| def predict_keyword(text): | |
| query_words = set(text.split()) | |
| scores = {} | |
| for intent, keywords in intent_keywords.items(): | |
| overlap = len(query_words & keywords) | |
| if overlap > 0: | |
| scores[intent] = overlap | |
| if not scores: | |
| return None, 0 | |
| best_intent = max(scores, key=scores.get) | |
| return best_intent, scores[best_intent] | |
| def predict_semantic(text, threshold=0.45): | |
| query_embedding = embedder.encode(text, convert_to_tensor=True) | |
| scores = util.cos_sim(query_embedding, pattern_embeddings)[0] | |
| best_idx = int(scores.argmax()) | |
| best_score = float(scores[best_idx]) | |
| if best_score < threshold: | |
| return None, best_score | |
| return semantic_pattern_to_intent[best_idx], best_score | |
| def predict_intent_final(user_text): | |
| text = clean_text(user_text) | |
| lstm_intent, lstm_conf = predict_lstm_raw(text) | |
| sem_intent, sem_score = predict_semantic(text) | |
| kw_intent, kw_score = predict_keyword(text) | |
| if sem_intent is not None and lstm_intent == sem_intent: | |
| return lstm_intent, "LSTM+Semantic Agree", (lstm_conf + sem_score) / 2 | |
| if sem_intent is not None and sem_score >= 0.5: | |
| return sem_intent, "Semantic", sem_score | |
| if kw_intent is not None and kw_score >= 1: | |
| return kw_intent, "Keyword", kw_score | |
| if lstm_conf >= 0.9: | |
| return lstm_intent, "LSTM-only (risky)", lstm_conf | |
| return None, "None", 0 | |
| def chatbot_response(user_text): | |
| intent, source, confidence = predict_intent_final(user_text) | |
| if intent is None: | |
| return "Sorry, mujhe samajh nahi aaya. Kya aap admission, fees, courses, ya contact details ke baare mein pooch rahe hain?" | |
| return random.choice(responses_dict[intent]) | |
| # ---------------------------- | |
| # Routes | |
| # ---------------------------- | |
| def health_check(): | |
| return jsonify({"status": "ILS Chatbot API is running!"}) | |
| def chat(): | |
| try: | |
| user_message = request.json.get("message", "") | |
| if not user_message.strip(): | |
| return jsonify({"response": "Kuch toh likho!"}) | |
| response = chatbot_response(user_message) | |
| return jsonify({"response": response}) | |
| except Exception as e: | |
| print(f"Error in /chat: {e}") | |
| return jsonify({"response": "Kuch technical issue ho gaya, thodi der baad try karo."}), 500 | |
| if __name__ == "__main__": | |
| app.run(host="0.0.0.0", port=7860) | |