Commit graph

17 commits

Author SHA1 Message Date
Vadym Samoilenko
33272cc677 Allow document uploads (PDF, DOCX, TXT, etc.) as focus group assets
- Expand allowed file types from images-only to also include:
  PDF, DOCX, DOC, TXT, MD, CSV, XLSX, XLS, PPTX, PPT, RTF
- validate_asset_file: skip PIL validation for non-image files; 50MB limit for docs / 10MB for images
- Correct MIME type detection for document extensions
- Store asset_type: "document"|"image" in metadata
- ImageDescriptionService: text files → LLM summary; binary docs → label; images → existing multimodal flow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 17:08:30 +00:00
Vadym Samoilenko
4b47b334d7 Fix data isolation + conversation/decision 500 errors
Data isolation:
- GET /tasks/<id>: verify requesting user owns the task (403 if not)
- DELETE /tasks/<id>: same ownership check
- GET /tasks/status: add @jwt_required()
- GET /personas/<id>: add ownership check (403 if created_by != user)
- GET /focus-groups/<id>: add ownership check
- GET /focus-groups/<id>/messages: add ownership check
- POST/DELETE /focus-groups/<id>/participants: add ownership check

Fix conversation/decision 500:
- Convert POST /conversation/decision to async 202+background (was synchronous LLM → timed out / LLM errors → 500)
- Frontend polls waitForTaskResult for decision result before calling generateResponseAsync
- GET /conversation/insights: return empty insights (200) on LLM error instead of 500

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 17:02:10 +00:00
Vadym Samoilenko
1b387daacf Migrate task result delivery from WebSocket to HTTP polling
Backend:
- task_manager.py: add result/error/completed_at storage, TTL sweeper (5min), store_task_result() helper
- tasks.py: add GET /<task_id> endpoint returning stored result; cancel route stores 'cancelled' status
- __init__.py: start TTL sweeper on app startup
- All 8 bg functions: store result before emitting lightweight WS hint (no payload data)

Frontend:
- src/lib/taskPolling.ts: waitForTaskResult() — polls GET /tasks/{id} every 2s, WS hint triggers immediate poll, 5min timeout
- src/hooks/useTaskPolling.ts: drop-in replacement for useCancellableGeneration using polling
- Migrate 6 Promise-based WS listeners → waitForTaskResult() in DiscussionPanel, FocusGroupSession (×2), PersonaProfile, PersonaModificationModal, useDiscussionGuideGeneration
- Migrate 3 hook-based consumers → useTaskPolling in AIRecruiter, SyntheticUsers, BulkExportProgressModal

Fixes WS Promise leak: polling survives disconnects, background tabs, page reloads.
WS events retained as zero-payload hints for near-zero latency when connected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 16:46:58 +00:00
Vadym Samoilenko
c7034634e3 Fix all async LLM routes: bypass GCP 30s load balancer timeout
Convert 6 synchronous LLM routes to async 202+WebSocket pattern:
- generate-response (focus_group_ai): persona chat response
- generate-key-themes (focus_group_ai): discussion analysis
- modify-with-ai (personas): AI persona modification
- export-profile (personas): markdown profile export
- describe-asset (focus_groups): image AI description

Each route now returns 202 + task_id immediately, runs LLM in
asyncio background task, delivers result via WebSocket task_completed
event. Frontend listeners updated to wait for ws:task_completed
instead of HTTP response body.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 15:56:54 +00:00
Vadym Samoilenko
f4a587c4f7 Fix 500: add current_app import to focus_groups route
Missing import caused NameError when starting background discussion
guide generation task.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 15:35:29 +00:00
Vadym Samoilenko
d8a5d6643f Fix discussion guide 504: async flow + WebSocket delivery
- Backend: /generate-discussion-guide now returns task_id immediately (202)
  and runs generation as a background asyncio task, delivering the guide
  via WebSocket task_completed event (bypasses GCP LB 30s timeout)
- Frontend: useDiscussionGuideGeneration awaits ws:task_completed event
  to resolve the guide Promise instead of waiting on the HTTP response

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 15:32:08 +00:00
Vadym Samoilenko
6917518d11 Fix NameError: _fg_logger undefined in update_focus_group route
_fg_logger was used but never defined, causing a NameError on every
PUT /focus-groups/:id request that included llm_model (i.e. all autosave
and handleSubmit updates) — resulting in a 500 Internal Server Error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 15:26:08 +00:00
Vadym Samoilenko
3e1865edbd Apply Jintech security audit remediation (sprint 3) — 87/92 findings fixed
- Fix missing await on FocusGroup.get_messages() (N-L1)
- Replace time.sleep with asyncio.sleep in key_theme_service and focus_group_service (N-P10)
- Replace flask import with quart in focus_groups.py (N-S3)
- Add logger.error before all 500 returns in focus_groups.py (N-P6)
- Add logging to silent except blocks across routes (N-M10, N-M11)
- Add @rate_limit to 6 remaining AI endpoints (N-H4)
- Add --confirm flag to populate scripts before delete_many (S-H2)
- Remove hardcoded Azure ID fallbacks from msal_service.py and msalConfig.ts (A-M2, F-H4)
- Centralize make_serializable() in utils.py, remove duplicates from 3 route files (N-P7)
- Replace all datetime.utcnow() with datetime.now(timezone.utc) across entire backend (M-L2)
- AuthContext.tsx: only mark token validated on 200 success, not on non-401 errors (F-H2)
- Rename authType → auth_type in auth.py (N-S4)
- Add security_report.md and security_report.pdf with full 92-finding status

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:51:18 +00:00
Michael Clervi
893b537b67 changed permissions 2025-12-19 19:26:16 +00:00
michael
96b9bfeedd Add LLM-generated one-line summaries for focus groups in list view
- Create focus_group_summary_service.py to generate concise summaries
- Add prompt template for summary generation
- Integrate summary generation after discussion guide creation
- Display summary under focus group title in list view with fallback to description

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 08:51:28 -06:00
michael
e29d2a0bb9 made long actions cancellable (like persona generation, etc.), increased variety of persona generation with prompt changes and temperature variable, reduced length of key theme quotes, bug fixes 2025-09-10 16:24:05 -05:00
michael
6a40936508 major refactor of entire application - migrate sync -> async including pymongo -> motor, flask -> quart, google-generativeai -> google-genai 2025-08-27 15:20:56 -05:00
michael
8a5c50cacb refactored image/asset attachment to discussion guide and discussion messages to avoid back end filenames being displayed to user - use metadata system instead. Also added a detailed persona export to markdown. Also, bug fixes 2025-08-12 15:43:34 -05:00
michael
9a3baa9d97 converted message polling to websockets 2025-08-10 18:08:34 -05:00
michael
da8639aee8 fixed folders again, bug fixes for gpt-5, adjusted response length calculation, cosmetic UI changes, other bug fixes 2025-08-09 10:08:45 -05:00
michael
b649793013 added gpt-4.1 support among other things 2025-08-05 17:38:13 -05:00
michael
da7b2c0448 initial commit 2025-08-04 09:07:59 -05:00