ziadmostafa commited on
Commit
d8bdc8d
·
1 Parent(s): e8b4723
app.py CHANGED
@@ -34,6 +34,10 @@ if IS_HUGGINGFACE:
34
  app.config["SESSION_COOKIE_SECURE"] = True
35
  app.config["SESSION_COOKIE_HTTPONLY"] = True
36
  app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
 
 
 
 
37
 
38
  Session(app)
39
 
@@ -44,6 +48,8 @@ MODEL_MAPPING = {
44
  "gemini-2.0-flash-thinking": "gemini-2.0-flash-thinking-exp-01-21"
45
  }
46
 
 
 
47
  def get_api_model_name(frontend_model_name):
48
  return MODEL_MAPPING.get(frontend_model_name, frontend_model_name)
49
 
@@ -56,18 +62,15 @@ def set_api_key():
56
  api_key = request.form.get("api_key")
57
  if not api_key:
58
  return jsonify({"success": False, "message": "API key is required"}), 400
59
-
60
  try:
61
  # Test the API key
62
  genai.configure(api_key=api_key)
63
  model = genai.GenerativeModel("gemini-2.0-pro-exp-02-05")
64
  response = model.generate_content("Say 'API key is valid'")
65
-
66
  # Store API key in session with permanent flag
67
  session.permanent = True
68
  session["api_key"] = api_key
69
  logger.info("API key successfully set and validated")
70
-
71
  return jsonify({"success": True})
72
  except Exception as e:
73
  logger.error(f"API key validation error: {str(e)}")
@@ -78,7 +81,6 @@ def generate_notebook_route():
78
  if "api_key" not in session:
79
  logger.warning("Generate notebook request without API key")
80
  return jsonify({"success": False, "message": "API key not set"}), 401
81
-
82
  # Handle both GET (for streaming) and POST requests
83
  if request.method == "GET":
84
  prompt = request.args.get("prompt")
@@ -100,14 +102,12 @@ def generate_notebook_route():
100
 
101
  try:
102
  genai.configure(api_key=session["api_key"])
103
-
104
  # OPTIMIZATION: If format_only is True, skip the AI call and just format the provided content
105
  if request.method == "POST" and format_only:
106
  # Use client-provided content as is (it's already the AI response)
107
  notebook_content = prompt
108
  notebook_json = format_notebook(notebook_content)
109
  notebook_info = extract_notebook_info(notebook_content)
110
-
111
  return jsonify({
112
  "success": True,
113
  "notebook": notebook_json,
@@ -121,7 +121,6 @@ def generate_notebook_route():
121
  notebook_content = generate_notebook(prompt, api_model_name)
122
  notebook_json = format_notebook(notebook_content)
123
  notebook_info = extract_notebook_info(notebook_content)
124
-
125
  return jsonify({
126
  "success": True,
127
  "notebook": notebook_json,
@@ -177,9 +176,8 @@ def edit_notebook_route():
177
  # Map the frontend model name to the API model name
178
  api_model_name = get_api_model_name(model_name)
179
 
180
- genai.configure(api_key=session["api_key"])
181
-
182
  try:
 
183
  if stream:
184
  return stream_notebook_edit(edit_prompt, notebook_json, api_model_name)
185
  else:
@@ -187,7 +185,6 @@ def edit_notebook_route():
187
  edited_content = edit_notebook(edit_prompt, notebook_json, api_model_name)
188
  notebook_json = format_notebook(edited_content)
189
  notebook_info = extract_notebook_info(edited_content)
190
-
191
  return jsonify({
192
  "success": True,
193
  "notebook": notebook_json,
@@ -195,13 +192,11 @@ def edit_notebook_route():
195
  "description": notebook_info["description"]
196
  })
197
  except Exception as e:
198
- app.logger.error(f"Error editing notebook: {str(e)}")
199
  return jsonify({"success": False, "message": str(e)}), 500
200
 
201
  @app.route("/download_notebook", methods=["POST"])
202
  def download_notebook():
203
- from flask import Response
204
-
205
  data = request.json
206
  notebook_json = data.get("notebook")
207
  filename = data.get("filename", f"notebook_{uuid.uuid4()}.ipynb")
@@ -217,10 +212,43 @@ def download_notebook():
217
  mimetype="application/json",
218
  headers={"Content-Disposition": f"attachment;filename={filename}"}
219
  )
220
-
221
  return response
222
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  if __name__ == "__main__":
224
- port = int(os.environ.get("PORT", 5000))
225
  debug_mode = os.environ.get("FLASK_ENV") == "development"
226
- app.run(host="0.0.0.0", port=port, debug=debug_mode)
 
 
34
  app.config["SESSION_COOKIE_SECURE"] = True
35
  app.config["SESSION_COOKIE_HTTPONLY"] = True
36
  app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
37
+ # Add more durable storage for Hugging Face
38
+ app.config["SESSION_FILE_THRESHOLD"] = 10 # Low threshold to ensure writes
39
+ # Important: Don't use large session lifetime on Hugging Face
40
+ app.config["PERMANENT_SESSION_LIFETIME"] = 60 * 60 * 24 # 1 day only
41
 
42
  Session(app)
43
 
 
48
  "gemini-2.0-flash-thinking": "gemini-2.0-flash-thinking-exp-01-21"
49
  }
50
 
51
+ global_api_key = None
52
+
53
  def get_api_model_name(frontend_model_name):
54
  return MODEL_MAPPING.get(frontend_model_name, frontend_model_name)
55
 
 
62
  api_key = request.form.get("api_key")
63
  if not api_key:
64
  return jsonify({"success": False, "message": "API key is required"}), 400
 
65
  try:
66
  # Test the API key
67
  genai.configure(api_key=api_key)
68
  model = genai.GenerativeModel("gemini-2.0-pro-exp-02-05")
69
  response = model.generate_content("Say 'API key is valid'")
 
70
  # Store API key in session with permanent flag
71
  session.permanent = True
72
  session["api_key"] = api_key
73
  logger.info("API key successfully set and validated")
 
74
  return jsonify({"success": True})
75
  except Exception as e:
76
  logger.error(f"API key validation error: {str(e)}")
 
81
  if "api_key" not in session:
82
  logger.warning("Generate notebook request without API key")
83
  return jsonify({"success": False, "message": "API key not set"}), 401
 
84
  # Handle both GET (for streaming) and POST requests
85
  if request.method == "GET":
86
  prompt = request.args.get("prompt")
 
102
 
103
  try:
104
  genai.configure(api_key=session["api_key"])
 
105
  # OPTIMIZATION: If format_only is True, skip the AI call and just format the provided content
106
  if request.method == "POST" and format_only:
107
  # Use client-provided content as is (it's already the AI response)
108
  notebook_content = prompt
109
  notebook_json = format_notebook(notebook_content)
110
  notebook_info = extract_notebook_info(notebook_content)
 
111
  return jsonify({
112
  "success": True,
113
  "notebook": notebook_json,
 
121
  notebook_content = generate_notebook(prompt, api_model_name)
122
  notebook_json = format_notebook(notebook_content)
123
  notebook_info = extract_notebook_info(notebook_content)
 
124
  return jsonify({
125
  "success": True,
126
  "notebook": notebook_json,
 
176
  # Map the frontend model name to the API model name
177
  api_model_name = get_api_model_name(model_name)
178
 
 
 
179
  try:
180
+ genai.configure(api_key=session["api_key"])
181
  if stream:
182
  return stream_notebook_edit(edit_prompt, notebook_json, api_model_name)
183
  else:
 
185
  edited_content = edit_notebook(edit_prompt, notebook_json, api_model_name)
186
  notebook_json = format_notebook(edited_content)
187
  notebook_info = extract_notebook_info(edited_content)
 
188
  return jsonify({
189
  "success": True,
190
  "notebook": notebook_json,
 
192
  "description": notebook_info["description"]
193
  })
194
  except Exception as e:
195
+ logger.error(f"Error editing notebook: {str(e)}", exc_info=True)
196
  return jsonify({"success": False, "message": str(e)}), 500
197
 
198
  @app.route("/download_notebook", methods=["POST"])
199
  def download_notebook():
 
 
200
  data = request.json
201
  notebook_json = data.get("notebook")
202
  filename = data.get("filename", f"notebook_{uuid.uuid4()}.ipynb")
 
212
  mimetype="application/json",
213
  headers={"Content-Disposition": f"attachment;filename={filename}"}
214
  )
 
215
  return response
216
 
217
+ @app.route("/session_test", methods=["GET"])
218
+ def session_test():
219
+ if "session_test" not in session:
220
+ session["session_test"] = True
221
+ is_new = True
222
+ else:
223
+ is_new = False
224
+
225
+ # Log the current session state
226
+ session_vars = list(session.keys()) if session else []
227
+ logger.info(f"Session check - variables: {session_vars}")
228
+
229
+ # Check if API key is available from URL parameter (fallback for HF)
230
+ api_key_param = request.args.get('api_key_param')
231
+ if api_key_param and "api_key" not in session:
232
+ global global_api_key
233
+ try:
234
+ # Validate it quickly before accepting
235
+ genai.configure(api_key=api_key_param)
236
+ model = genai.GenerativeModel("gemini-2.0-pro-exp-02-05")
237
+ # If no exception, store it
238
+ session["api_key"] = api_key_param
239
+ global_api_key = api_key_param
240
+ logger.info("API key set from URL parameter")
241
+ except Exception as e:
242
+ logger.error(f"Invalid API key from URL parameter: {str(e)}")
243
+
244
+ return jsonify({
245
+ "session_works": True,
246
+ "is_new_session": is_new,
247
+ "has_api_key": "api_key" in session,
248
+ "session_vars": session_vars
249
+ })
250
+
251
  if __name__ == "__main__":
 
252
  debug_mode = os.environ.get("FLASK_ENV") == "development"
253
+ port = int(os.environ.get("PORT", 5000))
254
+ app.run(host="0.0.0.0", port=port, debug=debug_mode)
flask_session/2029240f6d1128be89ddc32729463129 ADDED
Binary file (9 Bytes). View file
 
flask_session/45cc51dcfe7cf83166facbd1c993e325 ADDED
Binary file (86 Bytes). View file
 
static/js/main.js CHANGED
@@ -166,6 +166,9 @@ document.addEventListener('DOMContentLoaded', function() {
166
  // Store API key in localStorage as backup
167
  localStorage.setItem('notegenie_api_key', apiKey);
168
 
 
 
 
169
  if (document.querySelector('#apiKeyModal.show')) {
170
  showApiKeyFeedback('API key saved successfully!', 'success');
171
  setTimeout(() => {
@@ -302,12 +305,24 @@ document.addEventListener('DOMContentLoaded', function() {
302
  function createEventSource() {
303
  // Create a new event source with a unique timestamp to prevent caching
304
  const timestamp = Date.now();
 
 
 
 
 
 
 
 
 
 
 
 
305
  eventSource = new EventSource(`/generate_notebook?${new URLSearchParams({
306
  prompt: prompt,
307
  model: modelName,
308
  stream: true,
309
  t: timestamp // Add timestamp to prevent caching
310
- }).toString()}`);
311
 
312
  eventSource.onmessage = function(event) {
313
  // Update our last-activity timestamp
@@ -408,7 +423,17 @@ document.addEventListener('DOMContentLoaded', function() {
408
 
409
  // Check if it's an auth error (most likely API key not set)
410
  if (err.status === 401) {
411
- updateAiMessage(aiMessageId, '**Error: API key not set or invalid.** \n\nPlease click the API Key button in the top right corner to set your Google Gemini API key.');
 
 
 
 
 
 
 
 
 
 
412
  showApiKeyModal();
413
  } else {
414
  // Try to salvage what we have so far
 
166
  // Store API key in localStorage as backup
167
  localStorage.setItem('notegenie_api_key', apiKey);
168
 
169
+ // For Hugging Face, add a flag that API key was set in this session
170
+ sessionStorage.setItem('api_key_set', 'true');
171
+
172
  if (document.querySelector('#apiKeyModal.show')) {
173
  showApiKeyFeedback('API key saved successfully!', 'success');
174
  setTimeout(() => {
 
305
  function createEventSource() {
306
  // Create a new event source with a unique timestamp to prevent caching
307
  const timestamp = Date.now();
308
+
309
+ // On Hugging Face, add API key as URL parameter if stored (fallback mechanism)
310
+ let apiKeyParam = '';
311
+ if (window.location.hostname.includes('huggingface.co') ||
312
+ window.location.hostname.includes('hf.space')) {
313
+ const storedApiKey = localStorage.getItem('notegenie_api_key');
314
+ if (storedApiKey && !sessionStorage.getItem('api_key_tried_in_url')) {
315
+ apiKeyParam = `&api_key_param=${encodeURIComponent(storedApiKey)}`;
316
+ sessionStorage.setItem('api_key_tried_in_url', 'true');
317
+ }
318
+ }
319
+
320
  eventSource = new EventSource(`/generate_notebook?${new URLSearchParams({
321
  prompt: prompt,
322
  model: modelName,
323
  stream: true,
324
  t: timestamp // Add timestamp to prevent caching
325
+ }).toString()}${apiKeyParam}`);
326
 
327
  eventSource.onmessage = function(event) {
328
  // Update our last-activity timestamp
 
423
 
424
  // Check if it's an auth error (most likely API key not set)
425
  if (err.status === 401) {
426
+ // For Hugging Face: If we have an API key in storage but it's not being recognized
427
+ // in the session, show a special message
428
+ if ((window.location.hostname.includes('huggingface.co') ||
429
+ window.location.hostname.includes('hf.space')) &&
430
+ localStorage.getItem('notegenie_api_key') &&
431
+ sessionStorage.getItem('api_key_set')) {
432
+
433
+ updateAiMessage(aiMessageId, '**Error: Session issue with API key.** \n\nPlease try refreshing the page completely, then set your API key again.');
434
+ } else {
435
+ updateAiMessage(aiMessageId, '**Error: API key not set or invalid.** \n\nPlease click the API Key button in the top right corner to set your Google Gemini API key.');
436
+ }
437
  showApiKeyModal();
438
  } else {
439
  // Try to salvage what we have so far
templates/index.html CHANGED
@@ -229,5 +229,28 @@
229
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
230
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
231
  <script src="{{ url_for('static', filename='js/main.js') }}"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  </body>
233
  </html>
 
229
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
230
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
231
  <script src="{{ url_for('static', filename='js/main.js') }}"></script>
232
+
233
+ <!-- Hugging Face Spaces Session Check -->
234
+ <script>
235
+ if (window.location.hostname.includes('huggingface.co') || window.location.hostname.includes('hf.space')) {
236
+ console.log("Running on Hugging Face Spaces");
237
+ // Check if cookies are enabled
238
+ if (navigator.cookieEnabled) {
239
+ console.log("Cookies are enabled");
240
+ } else {
241
+ console.warn("Cookies are disabled - sessions won't work!");
242
+ }
243
+
244
+ // Add a hidden diagonstic endpoint
245
+ fetch('/session_check')
246
+ .then(response => response.json())
247
+ .then(data => {
248
+ console.log("Session check:", data);
249
+ })
250
+ .catch(err => {
251
+ console.error("Session check failed:", err);
252
+ });
253
+ }
254
+ </script>
255
  </body>
256
  </html>
utils/__pycache__/ai_helpers.cpython-39.pyc ADDED
Binary file (7.73 kB). View file
 
utils/__pycache__/notebook_helpers.cpython-39.pyc ADDED
Binary file (5.24 kB). View file
 
utils/ai_helpers.py CHANGED
@@ -115,8 +115,12 @@ def edit_notebook(edit_request, notebook_json, model_name="gemini-2.0-pro-exp-02
115
 
116
  return response.text
117
 
118
- def stream_notebook_generation(user_prompt, model_name="gemini-2.0-pro-exp-02-05"):
119
  """Stream notebook generation responses from Gemini API."""
 
 
 
 
120
  model = genai.GenerativeModel(model_name)
121
  enhanced_prompt = craft_notebook_prompt(user_prompt)
122
 
@@ -208,8 +212,12 @@ def stream_notebook_generation(user_prompt, model_name="gemini-2.0-pro-exp-02-05
208
  headers=headers
209
  )
210
 
211
- def stream_notebook_edit(edit_request, notebook_json, model_name="gemini-2.0-pro-exp-02-05"):
212
  """Stream notebook editing responses from Gemini API."""
 
 
 
 
213
  model = genai.GenerativeModel(model_name)
214
  enhanced_prompt = craft_edit_prompt(edit_request, notebook_json)
215
 
 
115
 
116
  return response.text
117
 
118
+ def stream_notebook_generation(user_prompt, model_name="gemini-2.0-pro-exp-02-05", api_key=None):
119
  """Stream notebook generation responses from Gemini API."""
120
+ # Configure the API with the key if provided
121
+ if api_key:
122
+ genai.configure(api_key=api_key)
123
+
124
  model = genai.GenerativeModel(model_name)
125
  enhanced_prompt = craft_notebook_prompt(user_prompt)
126
 
 
212
  headers=headers
213
  )
214
 
215
+ def stream_notebook_edit(edit_request, notebook_json, model_name="gemini-2.0-pro-exp-02-05", api_key=None):
216
  """Stream notebook editing responses from Gemini API."""
217
+ # Configure the API with the key if provided
218
+ if api_key:
219
+ genai.configure(api_key=api_key)
220
+
221
  model = genai.GenerativeModel(model_name)
222
  enhanced_prompt = craft_edit_prompt(edit_request, notebook_json)
223