Commit Graph

1088 Commits

Author SHA1 Message Date
ajaysi
ca725b77e7 refactor(phase2): add provider-aware tracking and fill missing subscription usage tracking
Changes:
1. helpers.py (_track_image_operation_usage): Map provider name to DB columns
   dynamically (stability→stability_calls, wavespeed→wavespeed_calls, etc.)
   instead of hardcoding stability_calls/stability_cost.

2. upscale_service.py: Added _track_image_operation_usage() call after
   successful Stability upscale completion.

3. control_service.py: Added _track_image_operation_usage() call after
   successful Stability control operation completion.

4. edit_service.py: Added _track_image_operation_usage() call after
   successful Stability edit operation (remove_background, inpaint,
   outpaint, search_replace, search_recolor, relight).

Previously only Create Studio and Face Swap tracked usage. Now all five
studios correctly decrement subscription limits.
2026-05-14 09:11:51 +05:30
ajaysi
bc311cfdf6 refactor(phase1): extract image generation helpers, edit, face_swap into separate modules + fix subscription bugs
Extracted from main_image_generation.py (1002->591 lines):
- image_generation/helpers.py: _validate_image_operation, _track_image_operation_usage
- image_generation/edit.py: generate_image_edit (with _get_edit_provider)
- image_generation/face_swap.py: generate_face_swap (with _get_face_swap_provider)

Main image_generation.py now imports and re-exports from these modules.
All existing imports (api/images.py, step4_asset_routes.py, studio services) continue to work unchanged.

Bug fixes included:
1. generate_image_edit: Added missing 'return result' (was returning None!)
2. generate_image_edit: Added missing _track_image_operation_usage call
3. generate_face_swap: Removed duplicate dead tracking code after return statement
2026-05-14 09:11:51 +05:30
ajaysi
6c740ee63f docs(01-code-splitting): complete Phase 1 - MUI icon optimization and roadmap update
- Phase 1 complete: all 3 plans executed
- MUI icon barrel imports eliminated (111 files)
- ROADMAP.md updated: Phase 1 marked complete, consolidated Phase 3 & 4
- STATE.md updated: reflects actual progress and decisions
2026-05-14 09:11:51 +05:30
ajaysi
05e84d6089 fix(01-code-splitting): convert StoryWriter, YouTubeCreator MUI icons
- Converted barrel imports to individual imports across 22 files
- StoryWriter (3), YouTubeCreator (19)
2026-05-14 09:11:51 +05:30
ajaysi
f46465cd97 fix(01-code-splitting): convert PodcastMaker, ProductMarketing, Research, Scheduler, SEO, shared MUI icons
- Converted barrel imports to individual imports across 44 files
- Covers CreateStep, ScriptEditor, RenderQueue, ProductMarketing, Scheduler, SEO, shared components
2026-05-14 09:11:51 +05:30
ajaysi
ebdd1edfa0 fix(01-code-splitting): convert PodcastMaker AnalysisPanel MUI icons
- Converted barrel imports to individual imports across 18 AnalysisPanel files
- AnalysisPanel.tsx (12 icons), AnalysisTabNav.tsx (9 icons)
2026-05-14 09:11:51 +05:30
ajaysi
45bd1eada9 fix(01-code-splitting): convert ImageStudio, Landing, LinkedIn, MainDashboard, OnboardingWizard MUI icons
- Converted barrel imports to individual imports across 14 files
- Most complex: VoiceAvatarPlaceholder (22 icons), FeatureShowcase (8), TestPersonaModal (9)
2026-05-14 09:11:51 +05:30
ajaysi
ef7b3d2b49 fix(01-code-splitting): convert billing, blog, content-planning, error-boundary, pricing, alerts MUI icons
- Converted barrel imports to individual imports across 8 files
- Affected files: billing (2), BlogWriter (1), ContentPlanningDashboard (2), ErrorBoundary (1), Pricing (1), AlertsBadge (1)
2026-05-14 09:11:50 +05:30
ajaysi
98cfb03cf7 fix(01-code-splitting): convert BillingPage MUI icons to individual imports
- Converted 1 barrel import (Refresh) to per-file default import
2026-05-14 09:11:50 +05:30
ajaysi
993000a540 fix(01-code-splitting): convert SchedulerDashboard MUI icons to individual imports
- Converted 7 barrel imports (Refresh, Schedule, CheckCircle, PlayArrow, Pause, TrendingUp, AccessTime) to per-file default imports
2026-05-14 09:11:50 +05:30
ajaysi
b3e2f4382c fix(01-code-splitting): convert SubscriptionExpiredModal MUI icons to individual imports
- Converted 3 barrel imports (CreditCard, Warning, ArrowForward) to per-file default imports
2026-05-14 09:11:50 +05:30
ajaysi
638e785ad4 fix(01-code-splitting): convert SubscriptionGuard MUI icons to individual imports
- Converted 2 barrel imports (Lock, Upgrade) to per-file default imports
2026-05-14 09:11:50 +05:30
ajaysi
98a1cc91a2 fix(01-code-splitting): convert ErrorBoundary MUI icons to individual imports
- Converted 5 barrel imports (ErrorOutline, Refresh, Home, ExpandMore, BugReport) to per-file default imports
- No JSX changes needed (aliases already matched variable names)
2026-05-14 09:11:50 +05:30
ajaysi
ab827e9ab9 feat(01-code-splitting): add feature gating with ALWRITY_ENABLED_FEATURES
- Create FeatureRoute.tsx wrapper component for route-level feature gating
- Add FEATURE_KEYS constant map to demoMode.ts for type-safe feature references
- Wrap 47 feature-specific routes with <FeatureRoute> in App.tsx
- Core routes (dashboard, billing, pricing, auth callbacks) remain ungated
- Disabled features redirect to /dashboard and never load their lazy chunks
- Main bundle: +259 bytes (FeatureRoute is a lightweight component)

Closes Phase 1 Plan 01-02
2026-05-14 09:11:50 +05:30
ajaysi
8ee042bd2c feat(01-code-splitting): convert 31+ route components to React.lazy
- Replace all 31+ static route component imports in App.tsx with React.lazy() dynamic imports
- Add LazyLoadingFallback.tsx shared component for Suspense fallback
- Wrap <Routes> with <Suspense> for chunk loading states
- Handle named exports (ImageStudio, VideoStudio, ProductMarketing, StoryProjectList) with .then() wrapper
- Main bundle reduced from 8.42MB to 2.50MB (70% reduction)
- 190+ chunk files created for on-demand loading per route

Closes Phase 1 Plan 01-01
2026-05-14 09:11:50 +05:30
Diksha
4df1adfbe2 fix(backend): add missing matplotlib dependency for podcast composer
The podcast B-roll composer imports matplotlib for chart rendering, so adding it to backend requirements prevents import failures in fresh setups.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 22:28:19 +05:30
ي
020b237e57 Reuse campaign-creator persistence pattern for backlink campaigns 2026-05-11 15:09:17 +05:30
ajaysi
3f984e8d0c feat(podcast): add pre-estimate endpoint, enhance cost estimator with multi-model support, cleanup alpha pricing seeding
- Add POST /podcast/pre-estimate endpoint for cost estimation before analysis
- Enhance cost_estimator.py with multi-model support (gemini, audio, voice clone, image, video)
- Add detailed cost breakdown (llm, audio, media costs + per-phase breakdown)
- Remove redundant pricing seeding from init_alpha_subscription_tiers.py
- Add SSOT pricing via PricingService.initialize_default_pricing()
- Update TopicUrlInput tooltip to show estimate details
- Add debug logging for pricing seeding and pre-estimate
- Clean up verbose podcast mode debug logs in app.py
2026-05-06 15:29:12 +05:30
ajaysi
a7d2ef1c09 feat(podcast): add Get Trending Topics modal to podcast topic input
Frontend Changes:
- Added TrendingTopicsModal with tabs (Interest Chart, Regions, Related Topics, Related Queries)
- Reuses existing TrendsChart component from Research module
- Clickable chips for related topics/queries that populate the topic input
- Added 'Get Trending Topics' green button next to 'Enhance Topic With AI'
- Responsive layout: buttons stack on mobile, side-by-side on desktop
- Wired up modal state in CreateModal
- Backend endpoint and podcastApi method committed in prior push
2026-04-24 20:52:23 +05:30
ajaysi
fc47445181 fix(voice-clone): persist clone info in localStorage, auto-merge into project knobs, fix clone ID detection in CreateModal
- Move voice clone cache from module-level memory to localStorage
  so it survives page refresh and works across browser tabs
- VoiceAvatarPlaceholder now syncs clone result to localStorage
  immediately after creation (both design and clone paths)
- usePodcastProjectState auto-merges voice clone cache into project
  knobs when loading a project (fills gap for projects created
  before voice clone or when voice clone was created after)
- CreateModal now detects voice clone IDs by prefix (vc_*) not
  just by VOICE_CLONE_ID constant, fixing the mismatch where
  VoiceSelector passes the actual clone ID but CreateModal
  expected the placeholder ID
- AudioRegenerateModal is intentionally per-scene override and
  does not write back to knobs (by design)
- trends.py handler added for podcast topic trend analysis
2026-04-24 20:36:35 +05:30
ajaysi
d518365c87 fix: add missing budget_cap argument to create_project in update_project handler 2026-04-24 15:47:42 +05:30
ajaysi
ba94ee30bc feat(phase-4): UI/UX improvements for Podcast Maker Write phase
Frontend Changes:
- Add scene numbering badge (1/N) next to scene titles
- Add inline status chips (Complete, Audio, Image, Voice, Why Script)
- Professional AI-like gradient styling for all chips with shadows
- Remove Script Editor header and 'Why This Script Format?' collapsible
- Move Voice and Why Script info to per-scene chips
- Make scene section mobile-responsive (responsive layout, button sizing)
- Rename 'B-Roll Charts' to 'Podcast Charts' with accordion (collapsed by default)
- Add sceneIndex prop to SceneEditor for scene numbering
- Enhanced accessibility with keyboard navigation and focus states

Backend Changes:
- Audio handler improvements
- B-roll handler enhancements
- Script handler updates
- B-roll composer and service improvements
- Removed temporary broll_temp files

Technical:
- Full mobile responsiveness for scene cards
- Gradient chip styling: vibrant colors with white text and shadows
- Non-breaking approval/generation flow preserved
- TypeScript compatibility maintained
2026-04-24 15:44:09 +05:30
ajaysi
8b79099b15 Fix preflight NameError, clean up debug logs, remove redundant voice button, fix Tooltip warning 2026-04-22 16:10:27 +05:30
ajaysi
fbbfe81ed7 Fix voice clone: use absolute API URL for audio (not relative) so requests hit Render backend instead of Vercel SPA 2026-04-22 15:00:54 +05:30
ajaysi
d7319c981e Add debug logging to WaveSpeed speech generator for qwen3 voice clone 2026-04-22 13:19:32 +05:30
ajaysi
3c4965462a Add debug logging to asset serving to see file content 2026-04-22 12:56:48 +05:30
ajaysi
26ccb2f609 Add debug logging for voice clone preview audio bytes 2026-04-22 12:41:11 +05:30
ajaysi
cbd68fa43f Fix voice clone NotSupportedError and improve subscription services 2026-04-22 12:27:51 +05:30
ajaysi
641143a7d6 fix: use aiApiClient for voice clone/design (180s timeout instead of 60s) 2026-04-22 11:38:15 +05:30
ajaysi
dd7f8515a4 debug: add logging for asset path resolution 2026-04-22 11:23:24 +05:30
ajaysi
5e205d52cd fix: add comprehensive logging for voice clone debugging
- Backend: change logger.info to logger.warning for production logs
- Frontend: add console logs in brandAssets.ts createVoiceClone
- Frontend: add token auth and audio error logs in VoiceAvatarPlaceholder
- Log token fetching, authenticated URL, audio duration
2026-04-22 09:58:20 +05:30
ajaysi
b9f2123ce9 debug: add more logging for voice clone audio format detection 2026-04-22 09:34:44 +05:30
ajaysi
00f46ecbed fix: add preload=auto and key to Generated AI Voice Preview audio element 2026-04-22 09:06:00 +05:30
ajaysi
973dd501fe fix: PrimaryButton ref warning + research modal close race condition 2026-04-22 08:48:35 +05:30
ajaysi
efff72f4bd fix: create avatars subdirectory before saving avatar upload 2026-04-22 08:29:37 +05:30
ajaysi
913e59a0a8 fix: voice clone preview audio authentication + MIME type fixes
- Restore auth on assets_serving.py using get_current_user_with_query_token
  (supports ?token= query param for <audio> elements)
- Add proper MIME type detection on asset serving (fixes NotSupportedError)
- Use storage_paths for path resolution in assets_serving.py
- VoiceSelector: append auth token to preview URLs for /api/ endpoints
- VoiceAvatarPlaceholder: add authenticatedAudioUrl state with async token
  resolution so <audio> elements get ?token= query param
- TestPersonaModal: same auth token pattern for voice preview audio
2026-04-22 08:04:55 +05:30
ajaysi
02d13716f3 fix: voice clone preview audio not playing + avatar upload 500 + asset serving
- Fix voice clone preview saved as .wav regardless of actual format (MP3/WebM
  content from WaveSpeed was saved with .wav extension causing NotSupportedError)
- Add detect_audio_format() and ensure_audio_extension() to media_utils
- Fix assets_serving.py: use storage_paths for root resolution, add proper
  MIME types to FileResponse, add auth via query token for <audio> elements
- Fix assets_serving.py: add path traversal security check
- Fix step4_asset_routes.py: use get_user_workspace() instead of WORKSPACE_DIR,
  detect actual audio format before saving preview
- Fix get_db() in database.py: raise HTTPException(401) instead of raw Exception,
  catch engine creation failures with HTTPException(503)
- Fix avatar.py: add auth error handling, diagnostic logging for path resolution,
  graceful DB save degradation
2026-04-22 07:24:28 +05:30
ajaysi
c5d625945f fix: centralize ROOT_DIR resolution, fix workspace path on Render.com, cleanup legacy paths
- Upgrade utils/storage_paths.py with robust find_repo_root() (env var override + validation + fallback)
- Remove broken _find_root() from podcast/constants.py, import from storage_paths instead
- Fix ROOT_DIR resolving to backend/ instead of project root (caused avatar upload 500s on Render.com)
- Fix video_combination_service.py default output dir (was writing to data/media instead of workspace)
- Add deprecation comments to global data/media constants in media_utils.py
- Pass user_id through resolve_media_path for tenant-scoped podcast resolution
- Add ALWRITY_ROOT_DIR env var support for explicit production overrides
- Log warning when get_podcast_media_dir called without user_id
- Use OperationButton with cost display for scene action buttons
2026-04-22 06:28:45 +05:30
ajaysi
6e9c11744c fix: WebM/Opus audio duration shows zero - add durationchange listener and preload=auto 2026-04-22 06:10:15 +05:30
ajaysi
b1ca29f7f7 fix: workspace-aware media resolution + production-ready logging
- load_podcast_image_bytes now accepts user_id for workspace-aware resolution
- Video and avatar handlers pass user_id to image loading
- Strip JWT tokens from console logs (dev-only verbose logging)
- Guard debug logs behind NODE_ENV===development in SceneCard, useRenderQueue, SubscriptionContext, mediaCache
- Add devLogger utility
2026-04-21 21:19:40 +05:30
ajaysi
91b2f996fd feat: voice clone audio generation + podcast workspace architecture
- Voice clone integration: When user selects voice clone in Write phase,
  backend uses their uploaded voice sample + scene script text to generate
  audio via qwen3/minimax/cosyvoice voice clone APIs
- Multi-tenant workspace storage: All podcast assets (audio, video, images,
  charts) now use workspace-specific directories per user
- Chart preview improvements: Card-based B-Roll charts UI with thumbnails,
  takeaway text, and action buttons; public endpoint for image serving
- Voice clone caching: In-memory LRU cache for voice samples (avoids
  re-downloading per scene); frontend caches voice clone metadata
- Thread pool for voice clone: Audio generation uses ThreadPoolExecutor to
  avoid blocking the FastAPI event loop
- Auto-detect voice clone IDs (vc_*, MY_VOICE_CLONE) to route correctly
- DB fallback for voice sample URL: Fetches from ContentAsset if not passed
- Fixed API URL resolution for chart previews
- Fixed GlassyCard DOM warnings for motion props
- Fixed ScriptGenerationProgressView syntax error
- Fixed usePodcastWorkflow scriptData reference
2026-04-21 19:38:50 +05:30
ajaysi
7637babd7d Add detailed logging for project update debugging 2026-04-20 16:01:13 +05:30
ajaysi
1deed48484 Enforce required fields: topic, avatar, voice, duration, speakers, podcastMode
- Updated canSubmit to require all fields: topic, presenter avatar, voice selection, duration, speakers, and podcast mode
- Removed audio_only exception - avatar now required for all modes
- Updated tooltip message in CreateActions
2026-04-20 15:59:26 +05:30
ajaysi
afdbc78779 Add detailed logging for voice clone debugging in production 2026-04-20 15:46:11 +05:30
ajaysi
294c64877d Enhance voice clone UI: gradient border, professional title, advanced options toggle
- Reduced script text to ~60% (more concise)
- Added gradient border styling on script card
- Improved title styling (uppercase, letter-spacing)
- Added Settings icon button to toggle advanced options
- Advanced options (Clone Engine, Custom Voice ID, Model, etc.) now hidden by default
2026-04-20 14:17:30 +05:30
ajaysi
4a4b8c5a24 Fix voice clone preview URL not matching saved file
The save_file_safely function may add a UUID suffix to the filename if there's
a collision, but the preview URL was being constructed using the original
filename instead of the actual saved filename. Now uses saved_preview_path.name.
2026-04-20 14:08:43 +05:30
ajaysi
625dd550d3 Fix production issues: add matplotlib dep, fix get_db calls, resolve ESLint
- Add matplotlib>=3.7.0 to requirements-podcast.txt (B-roll requires it)
- Fix research.py and exa_provider.py using get_session_for_user() instead of broken Depends(get_db)
- Fix BrollInfoPanel.tsx: call useScriptEditor hook unconditionally
- Add debug logging to avatar endpoint for troubleshooting
2026-04-20 12:55:25 +05:30
ajaysi
7f7279f903 Merge remote-tracking branch 'origin/codex/task-title-3y5pbt' 2026-04-20 08:47:19 +05:30
ي
e68c289901 Harden audio-only script flow and mode propagation 2026-04-20 08:44:46 +05:30
ajaysi
f748c081c2 Merge remote-tracking branch 'origin/codex/task-title' 2026-04-20 08:40:16 +05:30