Shirpi commited on
Commit
9f6a49b
·
verified ·
1 Parent(s): 073f3d3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -28
app.py CHANGED
@@ -31,32 +31,31 @@ def save_db(db):
31
  except: pass
32
  user_db = load_db()
33
 
34
- # --- 🧠 SYSTEM INSTRUCTION ---
35
  SYSTEM_INSTRUCTION = """
36
  ROLE: You are "Student's AI", a coding tutor.
37
- RULES: Format code in Markdown (```python). Explain in Tanglish.
 
 
 
 
 
38
  """
39
 
40
- # --- 🧬 DYNAMIC MODEL FINDER ---
41
  def get_working_model(key):
42
  """
43
  Asks Google: 'What models are available for this key?'
44
- Returns the best available model name.
45
  """
46
  genai.configure(api_key=key)
47
  try:
48
- # Get list of all models
49
  models = list(genai.list_models())
50
 
51
- # Priority list (Try to find these first)
52
- preferred_order = [
53
- "generateContent", # We need models that support this method
54
- ]
55
-
56
- # Filter models that support chat
57
  chat_models = [m for m in models if 'generateContent' in m.supported_generation_methods]
58
 
59
- # Look for Flash first, then Pro, then anything else
60
  for m in chat_models:
61
  if "flash" in m.name.lower() and "1.5" in m.name: return m.name
62
  for m in chat_models:
@@ -64,7 +63,7 @@ def get_working_model(key):
64
  for m in chat_models:
65
  if "pro" in m.name.lower() and "1.0" in m.name: return m.name
66
 
67
- # If no specific preference found, just take the first working one
68
  if chat_models:
69
  return chat_models[0].name
70
 
@@ -76,7 +75,7 @@ def get_working_model(key):
76
  def generate_with_retry(prompt, history_messages=[]):
77
  global current_key_index
78
 
79
- if not API_KEYS: return "🚨 API Keys Missing."
80
 
81
  # History Format
82
  formatted_history = []
@@ -86,7 +85,7 @@ def generate_with_retry(prompt, history_messages=[]):
86
 
87
  log_messages = []
88
 
89
- # RETRY LOGIC
90
  for i in range(len(API_KEYS)):
91
  key = API_KEYS[current_key_index]
92
 
@@ -123,32 +122,87 @@ HTML_TEMPLATE = """
123
  <meta charset="UTF-8">
124
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
125
  <title>Student's AI</title>
126
- <link href="[https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css](https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css)" rel="stylesheet">
127
  <style>
128
  :root { --bg: #000; --sidebar: #0a0a0a; --header: rgba(0,0,0,0.9); --user-bg: #222; --text: #ececec; }
129
  body, html { margin: 0; padding: 0; height: 100%; width: 100%; background: var(--bg); color: var(--text); font-family: sans-serif; overflow: hidden; }
130
- pre { background: #161616; border: 1px solid #333; padding: 15px; overflow-x: auto; color: #e6edf3; }
131
  #app-container { display: flex; flex-direction: column; height: 100%; }
 
 
 
 
 
132
  #chat-box { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 20px; }
133
- .msg { padding: 10px 15px; border-radius: 10px; max-width: 85%; line-height: 1.5; }
134
- .user-msg { align-self: flex-end; background: #222; }
135
- .ai-msg { align-self: flex-start; }
136
- .input-wrap { padding: 15px; background: #000; border-top: 1px solid #333; display: flex; gap: 10px; }
137
- input { flex: 1; padding: 10px; border-radius: 20px; border: 1px solid #333; background: #111; color: #fff; }
138
- button { padding: 10px 20px; border-radius: 20px; border: none; background: #fff; cursor: pointer; }
 
 
 
 
 
 
139
  </style>
140
  </head>
141
  <body>
 
 
 
 
 
 
 
142
  <div id="app-container">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  <div id="chat-box"></div>
144
  <div class="input-wrap">
145
- <input id="input" placeholder="Type here..." onkeydown="if(event.key==='Enter') send()">
146
  <button onclick="send()">Send</button>
147
  </div>
148
  </div>
149
  <script>
150
  let currentChatId = null;
151
- let currentUser = localStorage.getItem("user") || "User";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
  async function send() {
154
  const input = document.getElementById('input');
@@ -161,7 +215,7 @@ HTML_TEMPLATE = """
161
 
162
  // Loading
163
  const loadId = "load-"+Date.now();
164
- chatBox.innerHTML += `<div id="${loadId}" class="msg ai-msg">Checking Models...</div>`;
165
  chatBox.scrollTop = chatBox.scrollHeight;
166
 
167
  try {
@@ -180,6 +234,44 @@ HTML_TEMPLATE = """
180
  }
181
  chatBox.scrollTop = chatBox.scrollHeight;
182
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  </script>
184
  </body>
185
  </html>
@@ -194,7 +286,7 @@ def new_chat():
194
  user = request.json.get("username")
195
  if user not in user_db: user_db[user] = {}
196
  nid = str(uuid.uuid4())
197
- user_db[user][nid] = {"title": "New", "messages": []}
198
  save_db(user_db)
199
  return jsonify({"chat_id": nid})
200
 
@@ -211,7 +303,8 @@ def chat():
211
  # CALL DYNAMIC GENERATOR
212
  reply = generate_with_retry(msg, user_db[u][cid]["messages"][:-1])
213
 
214
- if "FAILED" in reply:
 
215
  formatted_html = reply
216
  else:
217
  formatted_html = markdown.markdown(reply, extensions=['fenced_code'])
 
31
  except: pass
32
  user_db = load_db()
33
 
34
+ # --- 🧠 SYSTEM INSTRUCTION (UPDATED FOR ENGLISH DEFAULT) ---
35
  SYSTEM_INSTRUCTION = """
36
  ROLE: You are "Student's AI", a coding tutor.
37
+
38
+ RULES:
39
+ 1. **DEFAULT LANGUAGE:** Always explain in **ENGLISH** unless the user explicitly asks for Tamil or Tanglish.
40
+ 2. **CODE FORMAT:** Always format code inside Markdown blocks (```python ... ```).
41
+ 3. **CLARITY:** Keep explanations simple, short, and beginner-friendly.
42
+ 4. **NO HINDI:** Do not use Hindi. Use only English or Tamil/Tanglish when requested.
43
  """
44
 
45
+ # --- 🧬 DYNAMIC MODEL FINDER (The Magic Fix) ---
46
  def get_working_model(key):
47
  """
48
  Asks Google: 'What models are available for this key?'
49
+ Returns the best available model name to avoid 404 errors.
50
  """
51
  genai.configure(api_key=key)
52
  try:
 
53
  models = list(genai.list_models())
54
 
55
+ # Filter models that support chat generation
 
 
 
 
 
56
  chat_models = [m for m in models if 'generateContent' in m.supported_generation_methods]
57
 
58
+ # Priority Logic: Try to find Flash -> Pro 1.5 -> Pro 1.0
59
  for m in chat_models:
60
  if "flash" in m.name.lower() and "1.5" in m.name: return m.name
61
  for m in chat_models:
 
63
  for m in chat_models:
64
  if "pro" in m.name.lower() and "1.0" in m.name: return m.name
65
 
66
+ # Fallback: Take the first available chat model
67
  if chat_models:
68
  return chat_models[0].name
69
 
 
75
  def generate_with_retry(prompt, history_messages=[]):
76
  global current_key_index
77
 
78
+ if not API_KEYS: return "🚨 API Keys Missing. Please check Secrets."
79
 
80
  # History Format
81
  formatted_history = []
 
85
 
86
  log_messages = []
87
 
88
+ # RETRY LOGIC (Keys + Dynamic Model)
89
  for i in range(len(API_KEYS)):
90
  key = API_KEYS[current_key_index]
91
 
 
122
  <meta charset="UTF-8">
123
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
124
  <title>Student's AI</title>
125
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
126
  <style>
127
  :root { --bg: #000; --sidebar: #0a0a0a; --header: rgba(0,0,0,0.9); --user-bg: #222; --text: #ececec; }
128
  body, html { margin: 0; padding: 0; height: 100%; width: 100%; background: var(--bg); color: var(--text); font-family: sans-serif; overflow: hidden; }
129
+ pre { background: #161616; border: 1px solid #333; padding: 15px; overflow-x: auto; color: #e6edf3; border-radius: 8px; }
130
  #app-container { display: flex; flex-direction: column; height: 100%; }
131
+ header { height: 60px; padding: 0 20px; background: var(--header); border-bottom: 1px solid #222; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; z-index: 50; }
132
+ #sidebar { position: fixed; inset: 0; width: 280px; background: var(--sidebar); border-right: 1px solid #222; transform: translateX(-100%); transition: 0.3s; z-index: 100; padding: 20px; display: flex; flex-direction: column; }
133
+ #sidebar.open { transform: translateX(0); }
134
+ .overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.7); z-index: 90; display: none; }
135
+ .overlay.active { display: block; }
136
  #chat-box { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 20px; }
137
+ .msg { padding: 12px 18px; border-radius: 10px; max-width: 85%; line-height: 1.6; }
138
+ .user-msg { align-self: flex-end; background: #222; color: #fff; }
139
+ .ai-msg { align-self: flex-start; color: #ececec; }
140
+ .input-wrap { padding: 15px; background: #000; border-top: 1px solid #333; display: flex; gap: 10px; z-index: 60; }
141
+ input { flex: 1; padding: 12px; border-radius: 25px; border: 1px solid #333; background: #111; color: #fff; outline: none; }
142
+ button { padding: 10px 20px; border-radius: 25px; border: none; background: #fff; font-weight: bold; cursor: pointer; }
143
+
144
+ /* Login Styles */
145
+ #login-overlay { position: fixed; inset: 0; z-index: 2000; background: #000; display: flex; flex-direction: column; align-items: center; justify-content: center; }
146
+ .login-box { width: 90%; max-width: 350px; padding: 30px; background: #111; border: 1px solid #333; border-radius: 15px; text-align: center; }
147
+ .login-input { width: 100%; padding: 12px; background: #000; border: 1px solid #333; color: #fff; border-radius: 8px; margin-bottom: 15px; text-align: center; }
148
+ .login-btn { width: 100%; padding: 12px; background: #fff; color: #000; border: none; border-radius: 8px; font-weight: bold; cursor: pointer; }
149
  </style>
150
  </head>
151
  <body>
152
+ <div id="login-overlay">
153
+ <div class="login-box">
154
+ <h2 style="color:#fff;">Student's AI</h2>
155
+ <input type="text" id="username-input" class="login-input" placeholder="Enter Name" autocomplete="off">
156
+ <button onclick="handleLogin()" class="login-btn">Start</button>
157
+ </div>
158
+ </div>
159
  <div id="app-container">
160
+ <div class="overlay" id="overlay" onclick="toggleSidebar()"></div>
161
+ <div id="sidebar">
162
+ <div style="padding-bottom:20px; border-bottom:1px solid #222; margin-bottom:20px; font-weight:bold; display:flex; gap:10px; align-items:center;">
163
+ <div id="avatar" style="width:35px; height:35px; background:#333; border-radius:50%; display:flex; align-items:center; justify-content:center;">U</div>
164
+ <span id="display-name">User</span>
165
+ </div>
166
+ <div style="background:#fff; color:#000; padding:12px; border-radius:8px; text-align:center; font-weight:bold; cursor:pointer;" onclick="newChat()">+ New Chat</div>
167
+ <div style="flex:1; overflow-y:auto; margin-top:20px;" id="history-list"></div>
168
+ <div style="margin-top:20px; color:#ff5555; cursor:pointer; text-align:center;" onclick="handleLogout()">Log Out</div>
169
+ </div>
170
+ <header>
171
+ <i class="fas fa-bars" style="color:#fff; font-size:20px; cursor:pointer;" onclick="toggleSidebar()"></i>
172
+ <div style="font-weight:bold; font-size:18px; color:#fff;">Student's AI</div>
173
+ <div style="width:20px;"></div>
174
+ </header>
175
  <div id="chat-box"></div>
176
  <div class="input-wrap">
177
+ <input id="input" placeholder="Ask a coding question..." onkeydown="if(event.key==='Enter') send()">
178
  <button onclick="send()">Send</button>
179
  </div>
180
  </div>
181
  <script>
182
  let currentChatId = null;
183
+ let currentUser = null;
184
+
185
+ function checkLogin() {
186
+ const stored = localStorage.getItem("student_ai_user");
187
+ if (stored) { currentUser = stored; showApp(); } else { document.getElementById("login-overlay").style.display = "flex"; }
188
+ }
189
+ function handleLogin() {
190
+ const name = document.getElementById("username-input").value.trim();
191
+ if(name) { localStorage.setItem("student_ai_user", name); currentUser = name; showApp(); }
192
+ }
193
+ function handleLogout() { localStorage.removeItem("student_ai_user"); location.reload(); }
194
+
195
+ function showApp() {
196
+ document.getElementById("login-overlay").style.display = "none";
197
+ document.getElementById("app-container").style.display = "flex";
198
+ document.getElementById("display-name").innerText = currentUser;
199
+ document.getElementById("avatar").innerText = currentUser[0].toUpperCase();
200
+ loadHistory();
201
+ if(!currentChatId) {
202
+ const box = document.getElementById("chat-box");
203
+ if(box.innerHTML.trim() === "") { box.innerHTML = `<div class="msg ai-msg"><strong>Welcome ${currentUser}!</strong><br>I am ready. Ask me any code.</div>`; }
204
+ }
205
+ }
206
 
207
  async function send() {
208
  const input = document.getElementById('input');
 
215
 
216
  // Loading
217
  const loadId = "load-"+Date.now();
218
+ chatBox.innerHTML += `<div id="${loadId}" class="msg ai-msg">Thinking...</div>`;
219
  chatBox.scrollTop = chatBox.scrollHeight;
220
 
221
  try {
 
234
  }
235
  chatBox.scrollTop = chatBox.scrollHeight;
236
  }
237
+
238
+ async function loadHistory() {
239
+ try {
240
+ const res = await fetch('/get_history', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ username: currentUser }) });
241
+ const data = await res.json();
242
+ const list = document.getElementById("history-list"); list.innerHTML = "";
243
+ if(data.chats) Object.keys(data.chats).reverse().forEach(cid => { list.innerHTML += `<div style="padding:10px; color:#888; cursor:pointer;" onclick="loadChat('${cid}')"><i class="fas fa-comment"></i> ${data.chats[cid].title}</div>`; });
244
+ } catch(e) {}
245
+ }
246
+ async function newChat() {
247
+ try {
248
+ const res = await fetch('/new_chat', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ username: currentUser }) });
249
+ const data = await res.json(); currentChatId = data.chat_id;
250
+ document.getElementById('chat-box').innerHTML = '';
251
+ loadHistory();
252
+ document.getElementById('sidebar').classList.remove('open');
253
+ document.getElementById('overlay').classList.remove('active');
254
+ } catch(e) {}
255
+ }
256
+ async function loadChat(cid) {
257
+ currentChatId = cid;
258
+ const res = await fetch('/get_chat', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ username: currentUser, chat_id: cid }) });
259
+ const data = await res.json();
260
+ const box = document.getElementById('chat-box'); box.innerHTML = '';
261
+ data.messages.forEach(msg => {
262
+ const cls = msg.role === 'user' ? 'user-msg' : 'ai-msg';
263
+ box.innerHTML += `<div class="msg ${cls}">${msg.content}</div>`;
264
+ });
265
+ document.getElementById('sidebar').classList.remove('open');
266
+ document.getElementById('overlay').classList.remove('active');
267
+ box.scrollTop = box.scrollHeight;
268
+ }
269
+ function toggleSidebar() {
270
+ document.getElementById('sidebar').classList.toggle('open');
271
+ document.getElementById('overlay').classList.toggle('active');
272
+ }
273
+
274
+ checkLogin();
275
  </script>
276
  </body>
277
  </html>
 
286
  user = request.json.get("username")
287
  if user not in user_db: user_db[user] = {}
288
  nid = str(uuid.uuid4())
289
+ user_db[user][nid] = {"title": "New Chat", "messages": []}
290
  save_db(user_db)
291
  return jsonify({"chat_id": nid})
292
 
 
303
  # CALL DYNAMIC GENERATOR
304
  reply = generate_with_retry(msg, user_db[u][cid]["messages"][:-1])
305
 
306
+ # Error Handling for Display
307
+ if "FAILED" in reply or "Missing" in reply:
308
  formatted_html = reply
309
  else:
310
  formatted_html = markdown.markdown(reply, extensions=['fenced_code'])