Redfire-1234 commited on
Commit
ab33c20
·
verified ·
1 Parent(s): 5e2361b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -508
app.py CHANGED
@@ -561,511 +561,3 @@ if __name__ == "__main__":
561
  print(f"\n🚀 Starting server on port {port}...\n")
562
  app.run(host="0.0.0.0", port=port, debug=False)
563
 
564
- # import pickle
565
- # import faiss
566
- # from flask import Flask, request, jsonify, render_template_string
567
- # from sentence_transformers import SentenceTransformer
568
- # from transformers import AutoTokenizer, AutoModelForCausalLM
569
- # from huggingface_hub import hf_hub_download
570
- # import torch
571
- # import os
572
- # from functools import lru_cache
573
- # import hashlib
574
-
575
- # app = Flask(__name__)
576
-
577
- # print("=" * 50)
578
- # print("Loading models and data...")
579
- # print("=" * 50)
580
-
581
- # # ------------------------------
582
- # # Load embedding model (CPU)
583
- # # ------------------------------
584
- # embed_model = SentenceTransformer("all-MiniLM-L6-v2")
585
- # print("✓ Embedding model loaded")
586
-
587
- # # ------------------------------
588
- # # Download files from Hugging Face
589
- # # ------------------------------
590
- # REPO_ID = "Redfire-1234/pcb_tutor"
591
-
592
- # print("Downloading subject files from Hugging Face...")
593
-
594
- # # Download Biology files
595
- # bio_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="bio_chunks.pkl", repo_type="model")
596
- # faiss_bio_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_bio.bin", repo_type="model")
597
-
598
- # # Download Chemistry files
599
- # chem_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="chem_chunks.pkl", repo_type="model")
600
- # faiss_chem_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_chem.bin", repo_type="model")
601
-
602
- # # Download Physics files
603
- # phy_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="phy_chunks.pkl", repo_type="model")
604
- # faiss_phy_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_phy.bin", repo_type="model")
605
-
606
- # # Load all subjects into memory
607
- # SUBJECTS = {
608
- # "biology": {
609
- # "chunks": pickle.load(open(bio_chunks_path, "rb")),
610
- # "index": faiss.read_index(faiss_bio_path)
611
- # },
612
- # "chemistry": {
613
- # "chunks": pickle.load(open(chem_chunks_path, "rb")),
614
- # "index": faiss.read_index(faiss_chem_path)
615
- # },
616
- # "physics": {
617
- # "chunks": pickle.load(open(phy_chunks_path, "rb")),
618
- # "index": faiss.read_index(faiss_phy_path)
619
- # }
620
- # }
621
-
622
- # print(f"✓ Biology: {len(SUBJECTS['biology']['chunks'])} chunks loaded")
623
- # print(f"✓ Chemistry: {len(SUBJECTS['chemistry']['chunks'])} chunks loaded")
624
- # print(f"✓ Physics: {len(SUBJECTS['physics']['chunks'])} chunks loaded")
625
-
626
- # # ------------------------------
627
- # # Load LLM model (CPU) with optimizations
628
- # # ------------------------------
629
- # model_name = "Qwen/Qwen2.5-3B-Instruct"
630
- # print(f"Loading LLM: {model_name}")
631
- # tokenizer = AutoTokenizer.from_pretrained(model_name)
632
- # device = "cpu"
633
-
634
- # # OPTIMIZATION: Load model with better dtype for CPU
635
- # model = AutoModelForCausalLM.from_pretrained(
636
- # model_name,
637
- # torch_dtype=torch.float32,
638
- # low_cpu_mem_usage=True # Optimization: Better memory management
639
- # ).to(device)
640
-
641
- # # OPTIMIZATION: Set model to eval mode and optimize for inference
642
- # model.eval()
643
- # if hasattr(torch, 'set_num_threads'):
644
- # torch.set_num_threads(4) # Optimization: Use multiple CPU threads
645
-
646
- # print(f"✓ LLM loaded on {device}")
647
-
648
- # print("=" * 50)
649
- # print("All models loaded successfully!")
650
- # print("=" * 50)
651
-
652
- # # ------------------------------
653
- # # OPTIMIZATION: Add caching for MCQ generation
654
- # # ------------------------------
655
- # MCQ_CACHE = {}
656
- # MAX_CACHE_SIZE = 100
657
-
658
- # def get_cache_key(topic, subject, context_hash):
659
- # """Generate a unique cache key"""
660
- # return f"{subject}:{topic}:{context_hash}"
661
-
662
- # def cache_mcq(key, mcqs):
663
- # """Cache generated MCQs with size limit"""
664
- # if len(MCQ_CACHE) >= MAX_CACHE_SIZE:
665
- # # Remove oldest entry
666
- # MCQ_CACHE.pop(next(iter(MCQ_CACHE)))
667
- # MCQ_CACHE[key] = mcqs
668
-
669
- # # ------------------------------
670
- # # RAG Search in specific subject (optimized)
671
- # # ------------------------------
672
- # def rag_search(query, subject, k=5):
673
- # if subject not in SUBJECTS:
674
- # return None
675
-
676
- # chunks = SUBJECTS[subject]["chunks"]
677
- # index = SUBJECTS[subject]["index"]
678
-
679
- # # OPTIMIZATION: Encode query (already fast with sentence-transformers)
680
- # q_emb = embed_model.encode([query], show_progress_bar=False).astype("float32")
681
- # D, I = index.search(q_emb, k)
682
-
683
- # # Get the actual chunks
684
- # results = []
685
- # for idx in I[0]:
686
- # if idx < len(chunks):
687
- # results.append(chunks[idx])
688
-
689
- # return "\n\n".join(results)
690
-
691
- # # ------------------------------
692
- # # OPTIMIZED MCQ Generation with reduced tokens
693
- # # ------------------------------
694
- # def generate_mcqs(context, topic, subject):
695
- # # OPTIMIZATION: Check cache first
696
- # context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
697
- # cache_key = get_cache_key(topic, subject, context_hash)
698
-
699
- # if cache_key in MCQ_CACHE:
700
- # print("✓ Using cached MCQs")
701
- # return MCQ_CACHE[cache_key]
702
-
703
- # # OPTIMIZATION: Shortened prompt for faster generation
704
- # prompt = f"""You are a Class-12 {subject.title()} teacher creating MCQs.
705
- # Topic: "{topic}"
706
- # Context:
707
- # {context}
708
-
709
- # Generate exactly 5 MCQs in this format:
710
- # Q1. [Question]
711
- # A) [Option]
712
- # B) [Option]
713
- # C) [Option]
714
- # D) [Option]
715
- # Correct Answer: [Letter] - [Reason]
716
-
717
- # Rules: Make correct answer from context, realistic distractors.
718
- # Generate 5 MCQs:"""
719
-
720
- # # OPTIMIZATION: Reduced max_length for faster tokenization
721
- # inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1536).to(device)
722
-
723
- # # OPTIMIZATION: Use torch.no_grad() for inference (saves memory)
724
- # with torch.no_grad():
725
- # # OPTIMIZATION: Reduced max_new_tokens from 900 to 600 (sufficient for 5 MCQs)
726
- # # OPTIMIZATION: Reduced temperature from 0.15 to 0.1 (faster, more deterministic)
727
- # # OPTIMIZATION: Added num_beams=1 (greedy decoding, faster than sampling)
728
- # outputs = model.generate(
729
- # **inputs,
730
- # max_new_tokens=600, # Reduced from 900
731
- # temperature=0.1, # Reduced from 0.15
732
- # top_p=0.85, # Slightly adjusted
733
- # do_sample=True,
734
- # repetition_penalty=1.15,
735
- # pad_token_id=tokenizer.eos_token_id # Optimization: Explicit pad token
736
- # )
737
-
738
- # result = tokenizer.decode(outputs[0], skip_special_tokens=True)
739
-
740
- # # Extract only the generated MCQs
741
- # if "Generate 5 MCQs:" in result:
742
- # result = result.split("Generate 5 MCQs:")[-1].strip()
743
-
744
- # # OPTIMIZATION: Cache the result
745
- # cache_mcq(cache_key, result)
746
-
747
- # return result
748
-
749
- # def verify_and_correct_answers(mcqs_text, context):
750
- # """
751
- # This function is kept for future enhancements
752
- # """
753
- # return mcqs_text
754
-
755
- # # ------------------------------
756
- # # HTML UI (with improved loading message)
757
- # # ------------------------------
758
- # HTML_TEMPLATE = """
759
- # <!DOCTYPE html>
760
- # <html>
761
- # <head>
762
- # <title>Class 12 PCB MCQ Generator</title>
763
- # <style>
764
- # * { margin: 0; padding: 0; box-sizing: border-box; }
765
- # body {
766
- # font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
767
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
768
- # min-height: 100vh;
769
- # padding: 20px;
770
- # }
771
- # .container {
772
- # max-width: 900px;
773
- # margin: 0 auto;
774
- # background: white;
775
- # border-radius: 20px;
776
- # box-shadow: 0 20px 60px rgba(0,0,0,0.3);
777
- # overflow: hidden;
778
- # }
779
- # .header {
780
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
781
- # color: white;
782
- # padding: 30px;
783
- # text-align: center;
784
- # }
785
- # .header h1 { font-size: 2.5em; margin-bottom: 10px; }
786
- # .content { padding: 40px; }
787
- # .form-group {
788
- # margin-bottom: 25px;
789
- # }
790
- # label {
791
- # display: block;
792
- # font-weight: 600;
793
- # margin-bottom: 10px;
794
- # color: #333;
795
- # font-size: 16px;
796
- # }
797
- # select, input {
798
- # width: 100%;
799
- # padding: 15px;
800
- # border: 2px solid #e0e0e0;
801
- # border-radius: 10px;
802
- # font-size: 16px;
803
- # font-family: inherit;
804
- # transition: border-color 0.3s;
805
- # }
806
- # select:focus, input:focus {
807
- # outline: none;
808
- # border-color: #667eea;
809
- # }
810
- # button {
811
- # width: 100%;
812
- # padding: 18px;
813
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
814
- # color: white;
815
- # border: none;
816
- # border-radius: 10px;
817
- # font-size: 18px;
818
- # font-weight: 600;
819
- # cursor: pointer;
820
- # transition: all 0.3s;
821
- # }
822
- # button:hover {
823
- # transform: translateY(-2px);
824
- # box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
825
- # }
826
- # button:disabled {
827
- # background: #ccc;
828
- # cursor: not-allowed;
829
- # transform: none;
830
- # }
831
- # .result {
832
- # margin-top: 30px;
833
- # padding: 25px;
834
- # background: #f8f9fa;
835
- # border-radius: 10px;
836
- # border-left: 4px solid #667eea;
837
- # display: none;
838
- # }
839
- # .result.show { display: block; }
840
- # .result h3 {
841
- # color: #667eea;
842
- # margin-bottom: 20px;
843
- # font-size: 1.4em;
844
- # }
845
- # .mcq-content {
846
- # background: white;
847
- # padding: 25px;
848
- # border-radius: 8px;
849
- # white-space: pre-wrap;
850
- # line-height: 1.9;
851
- # font-size: 15px;
852
- # }
853
- # .loading {
854
- # text-align: center;
855
- # padding: 30px;
856
- # display: none;
857
- # }
858
- # .loading.show { display: block; }
859
- # .spinner {
860
- # border: 4px solid #f3f3f3;
861
- # border-top: 4px solid #667eea;
862
- # border-radius: 50%;
863
- # width: 50px;
864
- # height: 50px;
865
- # animation: spin 1s linear infinite;
866
- # margin: 0 auto 15px;
867
- # }
868
- # @keyframes spin {
869
- # 0% { transform: rotate(0deg); }
870
- # 100% { transform: rotate(360deg); }
871
- # }
872
- # .subject-tag {
873
- # display: inline-block;
874
- # padding: 5px 15px;
875
- # border-radius: 20px;
876
- # font-size: 13px;
877
- # font-weight: 600;
878
- # margin-right: 10px;
879
- # }
880
- # .bio { background: #d4edda; color: #155724; }
881
- # .chem { background: #d1ecf1; color: #0c5460; }
882
- # .phy { background: #f8d7da; color: #721c24; }
883
- # .optimization-badge {
884
- # background: #28a745;
885
- # color: white;
886
- # padding: 5px 12px;
887
- # border-radius: 15px;
888
- # font-size: 12px;
889
- # margin-left: 10px;
890
- # }
891
- # </style>
892
- # </head>
893
- # <body>
894
- # <div class="container">
895
- # <div class="header">
896
- # <h1>🎓 Class 12 PCB MCQ Generator</h1>
897
- # <p style="font-size: 1.1em; margin-bottom: 15px;">Generate practice MCQs from your textbooks <span class="optimization-badge">⚡ Optimized</span></p>
898
- # <div>
899
- # <span class="subject-tag bio">Biology</span>
900
- # <span class="subject-tag chem">Chemistry</span>
901
- # <span class="subject-tag phy">Physics</span>
902
- # </div>
903
- # </div>
904
-
905
- # <div class="content">
906
- # <div class="form-group">
907
- # <label for="subject">📚 Select Subject</label>
908
- # <select id="subject">
909
- # <option value="biology">Biology</option>
910
- # <option value="chemistry">Chemistry</option>
911
- # <option value="physics">Physics</option>
912
- # </select>
913
- # </div>
914
-
915
- # <div class="form-group">
916
- # <label for="topic">✏️ Enter Topic</label>
917
- # <input type="text" id="topic" placeholder="e.g., Mitochondria, Chemical Bonding, Newton's Laws">
918
- # </div>
919
-
920
- # <button onclick="generateMCQs()">🚀 Generate 5 MCQs</button>
921
-
922
- # <div class="loading" id="loading">
923
- # <div class="spinner"></div>
924
- # <p style="color: #666; font-size: 16px;">Generating MCQs... This may take 20-40 seconds</p>
925
- # <p style="color: #999; font-size: 13px; margin-top: 10px;">⚡ Optimized for faster generation</p>
926
- # </div>
927
-
928
- # <div class="result" id="result">
929
- # <h3>📝 Generated MCQs:</h3>
930
- # <div style="background: #fff3cd; padding: 12px; border-radius: 6px; margin-bottom: 15px; color: #856404; font-size: 14px;">
931
- # ⚠️ <strong>Note:</strong> AI-generated answers may occasionally be incorrect. Please verify answers using your textbook.
932
- # </div>
933
- # <div class="mcq-content" id="mcqContent"></div>
934
- # </div>
935
- # </div>
936
- # </div>
937
- # <script>
938
- # async function generateMCQs() {
939
- # const subject = document.getElementById('subject').value;
940
- # const topic = document.getElementById('topic').value.trim();
941
-
942
- # if (!topic) {
943
- # alert('⚠️ Please enter a topic!');
944
- # return;
945
- # }
946
-
947
- # const loading = document.getElementById('loading');
948
- # const result = document.getElementById('result');
949
- # const btn = document.querySelector('button');
950
-
951
- # loading.classList.add('show');
952
- # result.classList.remove('show');
953
- # btn.disabled = true;
954
- # btn.textContent = '⏳ Generating...';
955
-
956
- # try {
957
- # const response = await fetch('/generate', {
958
- # method: 'POST',
959
- # headers: {'Content-Type': 'application/json'},
960
- # body: JSON.stringify({subject, topic})
961
- # });
962
-
963
- # const data = await response.json();
964
-
965
- # if (data.error) {
966
- # alert('❌ Error: ' + data.error);
967
- # return;
968
- # }
969
-
970
- # document.getElementById('mcqContent').textContent = data.mcqs;
971
- # result.classList.add('show');
972
- # } catch (error) {
973
- # alert('❌ Error: ' + error.message);
974
- # } finally {
975
- # loading.classList.remove('show');
976
- # btn.disabled = false;
977
- # btn.textContent = '🚀 Generate 5 MCQs';
978
- # }
979
- # }
980
-
981
- # // Allow Enter key to submit
982
- # document.getElementById('topic').addEventListener('keypress', function(e) {
983
- # if (e.key === 'Enter') {
984
- # generateMCQs();
985
- # }
986
- # });
987
- # </script>
988
- # </body>
989
- # </html>
990
- # """
991
-
992
- # # ------------------------------
993
- # # Routes
994
- # # ------------------------------
995
- # @app.route("/")
996
- # def home():
997
- # return render_template_string(HTML_TEMPLATE)
998
-
999
- # @app.route("/generate", methods=["POST"])
1000
- # def generate():
1001
- # try:
1002
- # data = request.json
1003
- # subject = data.get("subject", "").lower()
1004
- # topic = data.get("topic", "")
1005
-
1006
- # if not topic:
1007
- # return jsonify({"error": "Topic is required"}), 400
1008
-
1009
- # if subject not in SUBJECTS:
1010
- # return jsonify({"error": "Invalid subject. Choose biology, chemistry, or physics."}), 400
1011
-
1012
- # print(f"\n🔍 Searching {subject} for topic: {topic}")
1013
-
1014
- # # Retrieve context from RAG
1015
- # context = rag_search(topic, subject, k=5)
1016
-
1017
- # if not context or len(context.strip()) < 50:
1018
- # return jsonify({"error": f"No relevant content found in {subject} for topic: {topic}"}), 404
1019
-
1020
- # print(f"✓ Found context ({len(context)} chars)")
1021
-
1022
- # # Generate MCQs (now with caching)
1023
- # print("🤖 Generating MCQs...")
1024
- # mcqs = generate_mcqs(context, topic, subject)
1025
-
1026
- # print("✓ MCQs generated successfully")
1027
-
1028
- # return jsonify({"mcqs": mcqs, "subject": subject})
1029
-
1030
- # except Exception as e:
1031
- # print(f"❌ Error in /generate: {e}")
1032
- # import traceback
1033
- # traceback.print_exc()
1034
- # return jsonify({"error": str(e)}), 500
1035
-
1036
- # @app.route("/health")
1037
- # def health():
1038
- # return jsonify({
1039
- # "status": "healthy",
1040
- # "subjects": {
1041
- # "biology": len(SUBJECTS["biology"]["chunks"]),
1042
- # "chemistry": len(SUBJECTS["chemistry"]["chunks"]),
1043
- # "physics": len(SUBJECTS["physics"]["chunks"])
1044
- # },
1045
- # "cache_size": len(MCQ_CACHE)
1046
- # })
1047
-
1048
- # # OPTIMIZATION: Add cache stats endpoint
1049
- # @app.route("/cache/stats")
1050
- # def cache_stats():
1051
- # return jsonify({
1052
- # "cached_topics": len(MCQ_CACHE),
1053
- # "max_cache_size": MAX_CACHE_SIZE,
1054
- # "cache_keys": list(MCQ_CACHE.keys())
1055
- # })
1056
-
1057
- # # OPTIMIZATION: Add cache clear endpoint (optional)
1058
- # @app.route("/cache/clear", methods=["POST"])
1059
- # def clear_cache():
1060
- # MCQ_CACHE.clear()
1061
- # return jsonify({"status": "Cache cleared"})
1062
-
1063
- # # ------------------------------
1064
- # # Run the App
1065
- # # ------------------------------
1066
- # if __name__ == "__main__":
1067
- # port = int(os.environ.get("PORT", 7860))
1068
- # print(f"\n🚀 Starting Flask on 0.0.0.0:{port}\n")
1069
- # app.run(host="0.0.0.0", port=port, debug=False)
1070
-
1071
-
 
561
  print(f"\n🚀 Starting server on port {port}...\n")
562
  app.run(host="0.0.0.0", port=port, debug=False)
563