LovnishVerma commited on
Commit
8d70907
Β·
verified Β·
1 Parent(s): 63347ce

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +288 -0
app.py ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import google.generativeai as genai
2
+ from dotenv import load_dotenv
3
+ import logging
4
+ import os
5
+ import requests
6
+ from bs4 import BeautifulSoup
7
+ import time
8
+ from datetime import datetime
9
+ import gradio as gr
10
+
11
+ # ==========================================
12
+ # 1. SETUP & CONFIGURATION
13
+ # ==========================================
14
+ logging.basicConfig(
15
+ level=logging.INFO,
16
+ format='%(asctime)s - %(levelname)s - %(message)s'
17
+ )
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # Load API Key
21
+ load_dotenv()
22
+ api_key = os.getenv("GEMINI_API_KEY")
23
+ if not api_key:
24
+ raise ValueError("GEMINI_API_KEY is missing. Check your .env file.")
25
+
26
+ genai.configure(api_key=api_key)
27
+
28
+ # ==========================================
29
+ # 2. INTELLIGENT WEB SCRAPER
30
+ # ==========================================
31
+ def fetch_nielit_live_data():
32
+ """
33
+ Scrapes official NIELIT websites to create a real-time knowledge base.
34
+ Implements error handling and rate limiting.
35
+ """
36
+ target_urls = [
37
+ "https://nielit.ac.in/",
38
+ "https://www.nielit.gov.in/chandigarh/index.php"
39
+ ]
40
+
41
+ knowledge_base = f"### OFFICIAL LIVE DATA FROM NIELIT (Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}) ###\n"
42
+
43
+ headers = {
44
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
45
+ }
46
+
47
+ print("⚑ INTELLIGENCE SYSTEM: Scanning NIELIT websites for live data...")
48
+
49
+ for url in target_urls:
50
+ try:
51
+ print(f" πŸ“‘ Reading: {url}...")
52
+ response = requests.get(url, headers=headers, timeout=15)
53
+
54
+ if response.status_code == 200:
55
+ soup = BeautifulSoup(response.content, 'html.parser')
56
+
57
+ # Remove unwanted elements
58
+ for garbage in soup(["script", "style", "nav", "footer", "aside", "header"]):
59
+ garbage.extract()
60
+
61
+ # Extract text and clean whitespace
62
+ text = soup.get_text(separator=' ', strip=True)
63
+
64
+ # Clean up excessive whitespace
65
+ text = ' '.join(text.split())
66
+
67
+ # Limit to 8000 chars per site to fit context window efficiently
68
+ knowledge_base += f"\n--- SOURCE: {url} ---\n{text[:8000]}\n"
69
+ print(f" βœ… Successfully scraped {len(text[:8000])} characters")
70
+ else:
71
+ logger.warning(f" ❌ Failed to access {url}: Status {response.status_code}")
72
+
73
+ except requests.exceptions.Timeout:
74
+ logger.error(f" ⏱️ Timeout accessing {url}")
75
+ except requests.exceptions.RequestException as e:
76
+ logger.error(f" ❌ Connection error with {url}: {e}")
77
+ except Exception as e:
78
+ logger.error(f" ⚠️ Unexpected error with {url}: {e}")
79
+
80
+ # Rate limiting to be respectful
81
+ time.sleep(1)
82
+
83
+ return knowledge_base
84
+
85
+ # ==========================================
86
+ # 3. MODEL SELECTION (Auto-Upgrade)
87
+ # ==========================================
88
+ def get_best_available_model():
89
+ """
90
+ Automatically selects the best Gemini model available.
91
+ """
92
+ try:
93
+ available_models = [
94
+ m.name for m in genai.list_models()
95
+ if 'generateContent' in m.supported_generation_methods
96
+ ]
97
+
98
+ # Priority: Latest Flash -> Pro -> Legacy
99
+ priority_list = [
100
+ "models/gemini-1.5-flash-latest",
101
+ "models/gemini-1.5-flash",
102
+ "models/gemini-1.5-pro-latest",
103
+ "models/gemini-1.5-pro",
104
+ "models/gemini-pro"
105
+ ]
106
+
107
+ for model in priority_list:
108
+ if model in available_models:
109
+ print(f"🧠 MODEL SELECTED: {model}")
110
+ return model
111
+
112
+ # Fallback to first available
113
+ if available_models:
114
+ print(f"🧠 MODEL SELECTED (fallback): {available_models[0]}")
115
+ return available_models[0]
116
+ else:
117
+ raise Exception("No compatible models found")
118
+
119
+ except Exception as e:
120
+ logger.error(f"Model selection error: {e}")
121
+ return "models/gemini-pro"
122
+
123
+ # ==========================================
124
+ # 4. INITIALIZATION
125
+ # ==========================================
126
+ def initialize_bot():
127
+ """
128
+ Initializes the chatbot with scraped data and AI model.
129
+ """
130
+ print("\n" + "="*60)
131
+ print("πŸš€ INITIALIZING NIELIT CHATBOT...")
132
+ print("="*60)
133
+
134
+ # A. Build the Brain (Scrape once on startup)
135
+ nielit_data = fetch_nielit_live_data()
136
+
137
+ # B. Define the Persona
138
+ system_instruction = f"""You are the **Official AI Assistant for NIELIT Ropar/Chandigarh**.
139
+
140
+ You are professional, accurate, and helpful. Your responses should be clear and concise.
141
+
142
+ ### YOUR KNOWLEDGE BASE:
143
+ {nielit_data}
144
+
145
+ ### RESPONSE GUIDELINES:
146
+ 1. **Primary Source**: Answer based strictly on the Knowledge Base above
147
+ 2. **Accuracy**: If specific details (fees, dates, faculty names) aren't in the data, say:
148
+ "I couldn't find that specific information on the official website. Please visit nielit.ac.in or contact NIELIT directly for the most current details."
149
+ 3. **Helpful**: Provide relevant information and suggest where to find more details
150
+ 4. **Concise**: Keep answers focused and well-structured
151
+ 5. **Professional**: Maintain a helpful, educational tone
152
+
153
+ ### COMMON TOPICS TO ADDRESS:
154
+ - Courses and programs offered
155
+ - Admission procedures and eligibility
156
+ - Fee structure
157
+ - Important dates and deadlines
158
+ - Contact information
159
+ - Center locations
160
+ """
161
+
162
+ # C. Launch the Brain
163
+ model_name = get_best_available_model()
164
+ model = genai.GenerativeModel(
165
+ model_name=model_name,
166
+ system_instruction=system_instruction
167
+ )
168
+
169
+ print("\nβœ… INITIALIZATION COMPLETE")
170
+ print("="*60 + "\n")
171
+
172
+ return model
173
+
174
+ # Initialize the model globally
175
+ print("Starting bot initialization...")
176
+ MODEL = initialize_bot()
177
+
178
+ # ==========================================
179
+ # 5. CHAT FUNCTIONS FOR GRADIO
180
+ # ==========================================
181
+ def chat_response(message, history):
182
+ """
183
+ Processes user message and returns bot response.
184
+ Compatible with Gradio ChatInterface.
185
+ """
186
+ try:
187
+ response = MODEL.generate_content(
188
+ message,
189
+ generation_config=genai.types.GenerationConfig(
190
+ temperature=0.3,
191
+ max_output_tokens=800,
192
+ )
193
+ )
194
+ return response.text
195
+ except Exception as e:
196
+ logger.error(f"Error generating response: {e}")
197
+ return f"⚠️ I encountered an error processing your question. Please try rephrasing or ask something else."
198
+
199
+ # ==========================================
200
+ # 6. GRADIO INTERFACE
201
+ # ==========================================
202
+ def create_gradio_interface():
203
+ """
204
+ Creates and configures the Gradio chat interface.
205
+ """
206
+
207
+ # Custom CSS for styling
208
+ custom_css = """
209
+ .contain { max-width: 1200px; margin: auto; padding-top: 1.5rem; }
210
+ .avatar-container img { border-radius: 50%; }
211
+ footer {visibility: hidden}
212
+ """
213
+
214
+ # Check if bot.png exists
215
+ bot_avatar = "bot.png" if os.path.exists("bot.png") else None
216
+
217
+ # Create the chat interface
218
+ demo = gr.ChatInterface(
219
+ fn=chat_response,
220
+ title="πŸŽ“ NIELIT Ropar/Chandigarh - Official AI Assistant",
221
+ description="""
222
+ Welcome to the **NIELIT Chatbot**! Ask me anything about:
223
+ - πŸ“š Courses and Programs
224
+ - πŸ“ Admission Procedures
225
+ - πŸ’° Fee Structure
226
+ - πŸ“… Important Dates
227
+ - πŸ“ž Contact Information
228
+ - πŸ“ Center Locations
229
+
230
+ *Powered by Google Gemini AI with live website data*
231
+ """,
232
+ examples=[
233
+ "What courses are available at NIELIT?",
234
+ "How do I apply for admission?",
235
+ "What is the fee structure?",
236
+ "What are the eligibility criteria?",
237
+ "Where is NIELIT Chandigarh located?",
238
+ "Tell me about the institute"
239
+ ],
240
+ theme=gr.themes.Soft(
241
+ primary_hue="blue",
242
+ secondary_hue="slate",
243
+ ),
244
+ css=custom_css,
245
+ retry_btn="πŸ”„ Retry",
246
+ undo_btn="↩️ Undo",
247
+ clear_btn="πŸ—‘οΈ Clear",
248
+ submit_btn="Send πŸ“€",
249
+ chatbot=gr.Chatbot(
250
+ height=500,
251
+ avatar_images=(None, bot_avatar),
252
+ bubble_full_width=False,
253
+ show_copy_button=True,
254
+ ),
255
+ textbox=gr.Textbox(
256
+ placeholder="Type your question here...",
257
+ container=False,
258
+ scale=7
259
+ ),
260
+ )
261
+
262
+ return demo
263
+
264
+ # ==========================================
265
+ # 7. MAIN EXECUTION
266
+ # ==========================================
267
+ if __name__ == "__main__":
268
+ try:
269
+ print("\nπŸš€ Launching Gradio Interface...")
270
+
271
+ # Create and launch the interface
272
+ demo = create_gradio_interface()
273
+
274
+ # Launch with share=True to get a public link (optional)
275
+ demo.launch(
276
+ server_name="0.0.0.0", # Accessible from network
277
+ server_port=7860, # Default Gradio port
278
+ share=False, # Set to True for public link
279
+ show_error=True,
280
+ favicon_path="bot.png" if os.path.exists("bot.png") else None
281
+ )
282
+
283
+ except KeyboardInterrupt:
284
+ print("\n\nπŸ‘‹ Program interrupted. Goodbye!")
285
+ except Exception as e:
286
+ logger.error(f"Fatal error: {e}")
287
+ print(f"\n❌ A critical error occurred: {e}")
288
+ print("Please check your configuration and try again.")