mtornani Claude Sonnet 4.6 commited on
Commit
2eb5f65
·
1 Parent(s): a953437

fix: restore COMPONENTS init block + session_manager DB persistence + Gunicorn config

Browse files

app.py:
- Restore accidentally-removed COMPONENTS initialization block
(knowledge_manager, session_manager, orchestrator, editor, batch_manager)
- session_manager now initialized with knowledge_manager.store -> DB-backed
session state survives worker restarts via SQLite on /data
- Remove activation route + LICENSE ENFORCEMENT middleware (HF bypasses anyway)
- Remove license_manager import (dead on HF Spaces)

Procfile:
- workers 2 threads 4 timeout 120 -> workers 1 threads 8 timeout 300
- Single process: all threads share project_progress dict (no state split)
- 8 threads: handles concurrent requests during 60s generation tasks
- 300s timeout: covers full generation cycle without Gunicorn killing worker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (2) hide show
  1. Procfile +1 -1
  2. app.py +37 -74
Procfile CHANGED
@@ -1,2 +1,2 @@
1
- web: gunicorn app:app --bind 0.0.0.0:$PORT --workers 2 --threads 4 --timeout 120
2
 
 
1
+ web: gunicorn app:app --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 300
2
 
app.py CHANGED
@@ -294,85 +294,48 @@ def broadcast_log(level: str, message: str, source: str = "system"):
294
  # SSE handler rimosso perché instabile su alcuni sistemi
295
  log_stream_handler = None
296
 
297
- from license_manager import licenser
298
-
299
  # =============================================================================
300
- # LICENSE ENFORCEMENT MIDDLEWARE
301
  # =============================================================================
302
 
303
- @app.before_request
304
- def check_system_activation():
305
- """
306
- Verifica l'attivazione della licenza prima di ogni richiesta.
307
- Controlla sia la validità della chiave che la scadenza temporale.
308
- Esclude rotte di login, static e la pagina di attivazione stessa.
309
- Su HF Spaces (SPACE_ID presente) bypassa il controllo licenza.
310
- """
311
- # HF Spaces deployment: no license required
312
- if os.environ.get("SPACE_ID"):
313
- return
314
- allowed_routes = ["activation", "static", "auth.login", "auth.logout"]
315
- if request.endpoint in allowed_routes or not request.endpoint:
316
- return
317
-
318
- license_status = licenser.get_license_status()
319
-
320
- if not license_status["valid"]:
321
- if license_status.get("expired"):
322
- flash(license_status["message"], "error")
323
- if request.endpoint != "activation":
324
- return redirect(url_for("activation"))
325
-
326
- @app.route("/activation", methods=["GET", "POST"])
327
- def activation():
328
- """Pagina di blocco e attivazione licenza"""
329
- machine_code = licenser.get_machine_code()
330
-
331
- if request.method == "POST":
332
- email = request.form.get("email")
333
- key = request.form.get("key")
334
-
335
- if licenser.verify_license(key, email):
336
- # Salva licenza con scadenza (default 365 giorni, perpetua se 0)
337
- duration_days = request.form.get("duration_days", type=int) or 365
338
- licenser.save_license(email, key, duration_days=duration_days)
339
-
340
- # Auto-creazione utente se non esiste
341
- from auth_manager import bcrypt, User
342
- from flask_login import login_user
343
-
344
- existing_user = knowledge_manager.store.get_user_by_email(email)
345
- if not existing_user:
346
- # Genera password temporanea basata su parte della license key
347
- temp_password = key[:8] # Primi 8 caratteri della chiave
348
- password_hash = bcrypt.generate_password_hash(temp_password).decode('utf-8')
349
-
350
- # Crea utente con ruolo 'manager' e crediti iniziali
351
- user_id = knowledge_manager.store.create_user(
352
- email=email,
353
- password_hash=password_hash,
354
- full_name="", # L'utente può aggiornarlo dopo
355
- role="manager" # Ruolo di default per clienti con licenza
356
- )
357
- # Assegna crediti iniziali (es. 10 piani)
358
- knowledge_manager.store.update_user_credits(user_id, 10)
359
-
360
- # Recupera l'utente appena creato
361
- existing_user = knowledge_manager.store.get_user_by_email(email)
362
-
363
- flash(f"Account creato! Password temporanea: {temp_password} (cambiala nelle impostazioni)", "success")
364
 
365
- # Auto-login dell'utente
366
- if existing_user:
367
- user = User(existing_user)
368
- login_user(user)
 
 
 
369
 
370
- flash("Sistema Attivato con Successo!", "success")
371
- return redirect(url_for("index"))
372
- else:
373
- flash("Chiave di Licenza non valida per questo PC.", "error")
374
-
375
- return render_template("activation.html", machine_code=machine_code)
376
 
377
  # =============================================================================
378
  # LEGAL & GDPR
 
294
  # SSE handler rimosso perché instabile su alcuni sistemi
295
  log_stream_handler = None
296
 
 
 
297
  # =============================================================================
298
+ # COMPONENTI (inizializzazione con gestione errori)
299
  # =============================================================================
300
 
301
+ # FileSearchManager (Gemini RAG)
302
+ try:
303
+ file_search_manager = FileSearchManager()
304
+ file_search_store_name = file_search_manager.get_store_name()
305
+ except Exception as e:
306
+ logger.warning(f"FileSearchManager non disponibile: {e}")
307
+ file_search_manager = None
308
+ file_search_store_name = None
309
+
310
+ # Knowledge manager (DB + RAG)
311
+ knowledge_manager = KnowledgeManager(file_search_manager=file_search_manager)
312
+
313
+ # Session Manager persistente su SQLite /data
314
+ from session_manager import init_session_manager
315
+ session_manager = init_session_manager(store=knowledge_manager.store)
316
+
317
+ # Auth
318
+ init_auth(app, knowledge_manager.store)
319
+
320
+ # Multi-Agent Orchestrator (Gemma primary, Gemini Flash fallback)
321
+ orchestrator = MultiAgentOrchestrator(
322
+ knowledge_store=knowledge_manager,
323
+ file_search_store_name=file_search_store_name,
324
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
+ # Componenti base
327
+ researcher = WebResearcher()
328
+ research_aggregator = ResearchAggregator()
329
+ docx_exporter = ProfessionalDocxExporter()
330
+ html_exporter = ChunkedHTMLExporter()
331
+ editor = PostProductionEditor()
332
+ batch_manager = BatchReviewManager()
333
 
334
+ # Sistema strutturato v6.0
335
+ structured_orchestrator = StructuredOrchestrator(
336
+ file_search_store_name=file_search_store_name,
337
+ knowledge_store=knowledge_manager,
338
+ )
 
339
 
340
  # =============================================================================
341
  # LEGAL & GDPR