@lastbrain/module-ai 2.0.26 → 2.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -1
- package/dist/ai.build.config.d.ts.map +1 -1
- package/dist/ai.build.config.js +508 -9
- package/dist/api/admin/ai-provider-models/[id].d.ts +18 -0
- package/dist/api/admin/ai-provider-models/[id].d.ts.map +1 -0
- package/dist/api/admin/ai-provider-models/[id].js +58 -0
- package/dist/api/admin/ai-provider-models.d.ts +20 -0
- package/dist/api/admin/ai-provider-models.d.ts.map +1 -0
- package/dist/api/admin/ai-provider-models.js +26 -0
- package/dist/api/admin/ai-providers/[key].d.ts +18 -0
- package/dist/api/admin/ai-providers/[key].d.ts.map +1 -0
- package/dist/api/admin/ai-providers/[key].js +55 -0
- package/dist/api/admin/ai-providers.d.ts +20 -0
- package/dist/api/admin/ai-providers.d.ts.map +1 -0
- package/dist/api/admin/ai-providers.js +26 -0
- package/dist/api/admin/billing-analytics.d.ts +43 -0
- package/dist/api/admin/billing-analytics.d.ts.map +1 -0
- package/dist/api/admin/billing-analytics.js +144 -0
- package/dist/api/admin/global-ai-settings.d.ts +14 -0
- package/dist/api/admin/global-ai-settings.d.ts.map +1 -0
- package/dist/api/admin/global-ai-settings.js +63 -0
- package/dist/api/admin/token-packs/[id].d.ts.map +1 -1
- package/dist/api/admin/token-packs/[id].js +3 -2
- package/dist/api/admin/token-packs.d.ts.map +1 -1
- package/dist/api/admin/token-packs.js +3 -2
- package/dist/api/admin/user-monthly-details.d.ts +49 -0
- package/dist/api/admin/user-monthly-details.d.ts.map +1 -0
- package/dist/api/admin/user-monthly-details.js +140 -0
- package/dist/api/admin/user-quota.d.ts +21 -0
- package/dist/api/admin/user-quota.d.ts.map +1 -0
- package/dist/api/admin/user-quota.js +59 -0
- package/dist/api/admin/user-token/[id].d.ts.map +1 -1
- package/dist/api/admin/user-token/[id].js +2 -1
- package/dist/api/admin/user-token.d.ts +5 -2
- package/dist/api/admin/user-token.d.ts.map +1 -1
- package/dist/api/admin/user-token.js +91 -17
- package/dist/api/admin/user-usage-by-model.d.ts +22 -0
- package/dist/api/admin/user-usage-by-model.d.ts.map +1 -0
- package/dist/api/admin/user-usage-by-model.js +78 -0
- package/dist/api/admin/user-wallet-analytics.d.ts +15 -0
- package/dist/api/admin/user-wallet-analytics.d.ts.map +1 -0
- package/dist/api/admin/user-wallet-analytics.js +67 -0
- package/dist/api/admin/wallet-repair/route.d.ts +30 -0
- package/dist/api/admin/wallet-repair/route.d.ts.map +1 -0
- package/dist/api/admin/wallet-repair/route.js +63 -0
- package/dist/api/auth/ai-model-settings.d.ts +21 -0
- package/dist/api/auth/ai-model-settings.d.ts.map +1 -0
- package/dist/api/auth/ai-model-settings.js +86 -0
- package/dist/api/auth/ai-settings.d.ts +17 -0
- package/dist/api/auth/ai-settings.d.ts.map +1 -0
- package/dist/api/auth/ai-settings.js +87 -0
- package/dist/api/auth/api-keys/[id].d.ts +17 -0
- package/dist/api/auth/api-keys/[id].d.ts.map +1 -0
- package/dist/api/auth/api-keys/[id].js +66 -0
- package/dist/api/auth/api-keys.d.ts +19 -0
- package/dist/api/auth/api-keys.d.ts.map +1 -0
- package/dist/api/auth/api-keys.js +94 -0
- package/dist/api/auth/create-checkout.d.ts +1 -1
- package/dist/api/auth/create-checkout.d.ts.map +1 -1
- package/dist/api/auth/create-checkout.js +8 -6
- package/dist/api/auth/generate-image.d.ts +2 -2
- package/dist/api/auth/generate-image.d.ts.map +1 -1
- package/dist/api/auth/generate-image.js +404 -104
- package/dist/api/auth/generate-text.d.ts +3 -2
- package/dist/api/auth/generate-text.d.ts.map +1 -1
- package/dist/api/auth/generate-text.js +130 -58
- package/dist/api/auth/process-ocr.d.ts +9 -0
- package/dist/api/auth/process-ocr.d.ts.map +1 -0
- package/dist/api/auth/process-ocr.js +43 -0
- package/dist/api/auth/prompts/stats.d.ts +14 -0
- package/dist/api/auth/prompts/stats.d.ts.map +1 -0
- package/dist/api/auth/prompts/stats.js +46 -0
- package/dist/api/auth/prompts.d.ts +26 -0
- package/dist/api/auth/prompts.d.ts.map +1 -0
- package/dist/api/auth/prompts.js +175 -0
- package/dist/api/auth/token-balance.d.ts +26 -0
- package/dist/api/auth/token-balance.d.ts.map +1 -0
- package/dist/api/auth/token-balance.js +47 -0
- package/dist/api/auth/token-checkout.d.ts.map +1 -1
- package/dist/api/auth/token-checkout.js +22 -4
- package/dist/api/auth/token-packs.d.ts.map +1 -1
- package/dist/api/auth/token-packs.js +2 -1
- package/dist/api/auth/usage-by-model.d.ts +25 -0
- package/dist/api/auth/usage-by-model.d.ts.map +1 -0
- package/dist/api/auth/usage-by-model.js +95 -0
- package/dist/api/auth/usage.d.ts +26 -0
- package/dist/api/auth/usage.d.ts.map +1 -0
- package/dist/api/auth/usage.js +127 -0
- package/dist/api/auth/user-tokens.d.ts.map +1 -1
- package/dist/api/auth/user-tokens.js +36 -2
- package/dist/api/auth/wallet/route.d.ts +17 -0
- package/dist/api/auth/wallet/route.d.ts.map +1 -0
- package/dist/api/auth/wallet/route.js +68 -0
- package/dist/api/auth/wallet.d.ts +16 -0
- package/dist/api/auth/wallet.d.ts.map +1 -0
- package/dist/api/auth/wallet.js +71 -0
- package/dist/api/public/gateway-models.d.ts +25 -0
- package/dist/api/public/gateway-models.d.ts.map +1 -0
- package/dist/api/public/gateway-models.js +49 -0
- package/dist/api/public/pricing-summary.d.ts +46 -0
- package/dist/api/public/pricing-summary.d.ts.map +1 -0
- package/dist/api/public/pricing-summary.js +70 -0
- package/dist/api/public/prompts/[id]/stats.d.ts +15 -0
- package/dist/api/public/prompts/[id]/stats.d.ts.map +1 -0
- package/dist/api/public/prompts/[id]/stats.js +37 -0
- package/dist/api/public/prompts/[id]/view.d.ts +15 -0
- package/dist/api/public/prompts/[id]/view.d.ts.map +1 -0
- package/dist/api/public/prompts/[id]/view.js +41 -0
- package/dist/api/public/prompts/slug/[slug].d.ts +15 -0
- package/dist/api/public/prompts/slug/[slug].d.ts.map +1 -0
- package/dist/api/public/prompts/slug/[slug].js +40 -0
- package/dist/api/public/prompts/user/[username].d.ts +17 -0
- package/dist/api/public/prompts/user/[username].d.ts.map +1 -0
- package/dist/api/public/prompts/user/[username].js +51 -0
- package/dist/api/public/prompts.d.ts +15 -0
- package/dist/api/public/prompts.d.ts.map +1 -0
- package/dist/api/public/prompts.js +45 -0
- package/dist/api/public/token-packs.d.ts +11 -0
- package/dist/api/public/token-packs.d.ts.map +1 -0
- package/dist/api/public/token-packs.js +25 -0
- package/dist/api/public/token-pricing.d.ts +44 -0
- package/dist/api/public/token-pricing.d.ts.map +1 -0
- package/dist/api/public/token-pricing.js +168 -0
- package/dist/api/public/v1/_lib/artifacts.d.ts +52 -0
- package/dist/api/public/v1/_lib/artifacts.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/artifacts.js +217 -0
- package/dist/api/public/v1/_lib/auth.d.ts +43 -0
- package/dist/api/public/v1/_lib/auth.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/auth.js +108 -0
- package/dist/api/public/v1/_lib/errors.d.ts +17 -0
- package/dist/api/public/v1/_lib/errors.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/errors.js +16 -0
- package/dist/api/public/v1/_lib/log.d.ts +29 -0
- package/dist/api/public/v1/_lib/log.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/log.js +68 -0
- package/dist/api/public/v1/_lib/quota.d.ts +24 -0
- package/dist/api/public/v1/_lib/quota.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/quota.js +118 -0
- package/dist/api/public/v1/_lib/router.d.ts +54 -0
- package/dist/api/public/v1/_lib/router.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/router.js +119 -0
- package/dist/api/public/v1/connect.d.ts +20 -0
- package/dist/api/public/v1/connect.d.ts.map +1 -0
- package/dist/api/public/v1/connect.js +119 -0
- package/dist/api/public/v1/doc.d.ts +239 -0
- package/dist/api/public/v1/doc.d.ts.map +1 -0
- package/dist/api/public/v1/doc.js +253 -0
- package/dist/api/public/v1/history/[id].d.ts +92 -0
- package/dist/api/public/v1/history/[id].d.ts.map +1 -0
- package/dist/api/public/v1/history/[id].js +176 -0
- package/dist/api/public/v1/history.d.ts +30 -0
- package/dist/api/public/v1/history.d.ts.map +1 -0
- package/dist/api/public/v1/history.js +142 -0
- package/dist/api/public/v1/image-ai.d.ts +24 -0
- package/dist/api/public/v1/image-ai.d.ts.map +1 -0
- package/dist/api/public/v1/image-ai.js +233 -0
- package/dist/api/public/v1/prompts.d.ts +19 -0
- package/dist/api/public/v1/prompts.d.ts.map +1 -0
- package/dist/api/public/v1/prompts.js +107 -0
- package/dist/api/public/v1/provider.d.ts +16 -0
- package/dist/api/public/v1/provider.d.ts.map +1 -0
- package/dist/api/public/v1/provider.js +130 -0
- package/dist/api/public/v1/purchase.d.ts +11 -0
- package/dist/api/public/v1/purchase.d.ts.map +1 -0
- package/dist/api/public/v1/purchase.js +18 -0
- package/dist/api/public/v1/status.d.ts +35 -0
- package/dist/api/public/v1/status.d.ts.map +1 -0
- package/dist/api/public/v1/status.js +163 -0
- package/dist/api/public/v1/text-ai.d.ts +26 -0
- package/dist/api/public/v1/text-ai.d.ts.map +1 -0
- package/dist/api/public/v1/text-ai.js +239 -0
- package/dist/api/public/webhook.d.ts.map +1 -1
- package/dist/api/public/webhook.js +50 -39
- package/dist/api/track-usage.d.ts +12 -0
- package/dist/api/track-usage.d.ts.map +1 -0
- package/dist/api/track-usage.js +37 -0
- package/dist/components/Doc.d.ts.map +1 -1
- package/dist/components/Doc.js +1 -1
- package/dist/components/DocUsageCustom.js +6 -6
- package/dist/components/admin/UserTokenTab.d.ts.map +1 -1
- package/dist/components/admin/UserTokenTab.js +170 -23
- package/dist/components/auth/AuthDashboardAi.d.ts +2 -0
- package/dist/components/auth/AuthDashboardAi.d.ts.map +1 -0
- package/dist/components/auth/AuthDashboardAi.js +53 -0
- package/dist/docs/REFACTORING_BILLING_GUIDE.d.ts +277 -0
- package/dist/docs/REFACTORING_BILLING_GUIDE.d.ts.map +1 -0
- package/dist/docs/REFACTORING_BILLING_GUIDE.js +276 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/scripts/migrate-tokens-to-wallet.d.ts +13 -0
- package/dist/scripts/migrate-tokens-to-wallet.d.ts.map +1 -0
- package/dist/scripts/migrate-tokens-to-wallet.js +165 -0
- package/dist/server/__tests__/billing.test.d.ts +5 -0
- package/dist/server/__tests__/billing.test.d.ts.map +1 -0
- package/dist/server/__tests__/billing.test.js +223 -0
- package/dist/server/ai-client.d.ts +59 -0
- package/dist/server/ai-client.d.ts.map +1 -0
- package/dist/server/ai-client.js +111 -0
- package/dist/server/ai-generation-service.d.ts +66 -0
- package/dist/server/ai-generation-service.d.ts.map +1 -0
- package/dist/server/ai-generation-service.js +274 -0
- package/dist/server/billing.d.ts +200 -0
- package/dist/server/billing.d.ts.map +1 -0
- package/dist/server/billing.js +488 -0
- package/dist/server/gateway-service.d.ts +13 -0
- package/dist/server/gateway-service.d.ts.map +1 -0
- package/dist/server/gateway-service.js +161 -0
- package/dist/server/global-settings.d.ts +16 -0
- package/dist/server/global-settings.d.ts.map +1 -0
- package/dist/server/global-settings.js +42 -0
- package/dist/server/model-filter.d.ts +25 -0
- package/dist/server/model-filter.d.ts.map +1 -0
- package/dist/server/model-filter.js +240 -0
- package/dist/server/ocr.d.ts +39 -0
- package/dist/server/ocr.d.ts.map +1 -0
- package/dist/server/ocr.js +280 -0
- package/dist/server/openai-client.d.ts +19 -0
- package/dist/server/openai-client.d.ts.map +1 -0
- package/dist/server/openai-client.js +26 -0
- package/dist/server/pricing-config.d.ts +18 -0
- package/dist/server/pricing-config.d.ts.map +1 -0
- package/dist/server/pricing-config.js +94 -0
- package/dist/server/pricing-validator.d.ts +41 -0
- package/dist/server/pricing-validator.d.ts.map +1 -0
- package/dist/server/pricing-validator.js +113 -0
- package/dist/server/pricing.d.ts +121 -0
- package/dist/server/pricing.d.ts.map +1 -0
- package/dist/server/pricing.js +225 -0
- package/dist/server/quota.d.ts +66 -0
- package/dist/server/quota.d.ts.map +1 -0
- package/dist/server/quota.js +538 -0
- package/dist/server/wallet-repair.d.ts +32 -0
- package/dist/server/wallet-repair.d.ts.map +1 -0
- package/dist/server/wallet-repair.js +189 -0
- package/dist/server.d.ts +13 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +87 -16
- package/dist/sitemap/handlers/prompts.d.ts +6 -0
- package/dist/sitemap/handlers/prompts.d.ts.map +1 -0
- package/dist/sitemap/handlers/prompts.js +72 -0
- package/dist/sitemap/handlers/users.d.ts +6 -0
- package/dist/sitemap/handlers/users.d.ts.map +1 -0
- package/dist/sitemap/handlers/users.js +80 -0
- package/dist/sitemap/manifest.d.ts +8 -0
- package/dist/sitemap/manifest.d.ts.map +1 -0
- package/dist/sitemap/manifest.js +27 -0
- package/dist/types/gateway.d.ts +40 -0
- package/dist/types/gateway.d.ts.map +1 -0
- package/dist/types/gateway.js +4 -0
- package/dist/types/quota.d.ts +74 -0
- package/dist/types/quota.d.ts.map +1 -0
- package/dist/types/quota.js +11 -0
- package/dist/utils/date.d.ts +7 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +17 -0
- package/dist/web/admin/AdminTokenPacksPage.js +1 -1
- package/dist/web/admin/BillingAnalyticsPage.d.ts +2 -0
- package/dist/web/admin/BillingAnalyticsPage.d.ts.map +1 -0
- package/dist/web/admin/BillingAnalyticsPage.js +141 -0
- package/dist/web/admin/GlobalAISettingsPage.d.ts +2 -0
- package/dist/web/admin/GlobalAISettingsPage.d.ts.map +1 -0
- package/dist/web/admin/GlobalAISettingsPage.js +93 -0
- package/dist/web/admin/UserTokenPage.d.ts.map +1 -1
- package/dist/web/admin/UserTokenPage.js +20 -7
- package/dist/web/auth/AISettingsPage.d.ts +2 -0
- package/dist/web/auth/AISettingsPage.d.ts.map +1 -0
- package/dist/web/auth/AISettingsPage.js +258 -0
- package/dist/web/auth/APIKeysPage.d.ts +2 -0
- package/dist/web/auth/APIKeysPage.d.ts.map +1 -0
- package/dist/web/auth/APIKeysPage.js +154 -0
- package/dist/web/auth/HistoryPage.d.ts +2 -0
- package/dist/web/auth/HistoryPage.d.ts.map +1 -0
- package/dist/web/auth/HistoryPage.js +279 -0
- package/dist/web/auth/PromptsPage.d.ts +5 -0
- package/dist/web/auth/PromptsPage.d.ts.map +1 -0
- package/dist/web/auth/PromptsPage.js +137 -0
- package/dist/web/auth/TokenPage.d.ts.map +1 -1
- package/dist/web/auth/TokenPage.js +88 -31
- package/dist/web/auth/UsageAndTokensPage.d.ts +2 -0
- package/dist/web/auth/UsageAndTokensPage.d.ts.map +1 -0
- package/dist/web/auth/UsageAndTokensPage.js +157 -0
- package/dist/web/auth/UsagePage.d.ts +2 -0
- package/dist/web/auth/UsagePage.d.ts.map +1 -0
- package/dist/web/auth/UsagePage.js +62 -0
- package/dist/web/auth/components/ApiKeyFilterSelect.d.ts +13 -0
- package/dist/web/auth/components/ApiKeyFilterSelect.d.ts.map +1 -0
- package/dist/web/auth/components/ApiKeyFilterSelect.js +16 -0
- package/dist/web/auth/components/ModelUsageTable.d.ts +19 -0
- package/dist/web/auth/components/ModelUsageTable.d.ts.map +1 -0
- package/dist/web/auth/components/ModelUsageTable.js +37 -0
- package/dist/web/auth/components/PurchaseButton.d.ts +7 -0
- package/dist/web/auth/components/PurchaseButton.d.ts.map +1 -0
- package/dist/web/auth/components/PurchaseButton.js +13 -0
- package/dist/web/auth/components/TokenHistoryCard.d.ts +20 -0
- package/dist/web/auth/components/TokenHistoryCard.d.ts.map +1 -0
- package/dist/web/auth/components/TokenHistoryCard.js +76 -0
- package/dist/web/auth/components/TokenKpiGrid.d.ts +24 -0
- package/dist/web/auth/components/TokenKpiGrid.d.ts.map +1 -0
- package/dist/web/auth/components/TokenKpiGrid.js +38 -0
- package/dist/web/auth/components/UsageByDayChart.d.ts +11 -0
- package/dist/web/auth/components/UsageByDayChart.d.ts.map +1 -0
- package/dist/web/auth/components/UsageByDayChart.js +32 -0
- package/dist/web/auth/components/UsageByModelBarChart.d.ts +12 -0
- package/dist/web/auth/components/UsageByModelBarChart.d.ts.map +1 -0
- package/dist/web/auth/components/UsageByModelBarChart.js +32 -0
- package/dist/web/auth/components/WalletStatusCard.d.ts +9 -0
- package/dist/web/auth/components/WalletStatusCard.d.ts.map +1 -0
- package/dist/web/auth/components/WalletStatusCard.js +50 -0
- package/dist/web/components/ImageGenerative.d.ts +3 -1
- package/dist/web/components/ImageGenerative.d.ts.map +1 -1
- package/dist/web/components/ImageGenerative.js +139 -52
- package/dist/web/components/TextareaGenerative.d.ts +3 -1
- package/dist/web/components/TextareaGenerative.d.ts.map +1 -1
- package/dist/web/components/TextareaGenerative.js +10 -5
- package/dist/web/public/PromptDetailPage.d.ts +25 -0
- package/dist/web/public/PromptDetailPage.d.ts.map +1 -0
- package/dist/web/public/PromptDetailPage.js +71 -0
- package/dist/web/public/PromptDetailPageServer.d.ts +15 -0
- package/dist/web/public/PromptDetailPageServer.d.ts.map +1 -0
- package/dist/web/public/PromptDetailPageServer.js +68 -0
- package/dist/web/public/PublicPromptsPage.d.ts +5 -0
- package/dist/web/public/PublicPromptsPage.d.ts.map +1 -0
- package/dist/web/public/PublicPromptsPage.js +110 -0
- package/dist/web/public/PurchaseTokensPage.d.ts +2 -0
- package/dist/web/public/PurchaseTokensPage.d.ts.map +1 -0
- package/dist/web/public/PurchaseTokensPage.js +98 -0
- package/dist/web/public/UserAvatar.d.ts +13 -0
- package/dist/web/public/UserAvatar.d.ts.map +1 -0
- package/dist/web/public/UserAvatar.js +13 -0
- package/dist/web/public/UserDetailPageServer.d.ts +15 -0
- package/dist/web/public/UserDetailPageServer.d.ts.map +1 -0
- package/dist/web/public/UserDetailPageServer.js +31 -0
- package/dist/web/public/UserPromptsPage.d.ts +9 -0
- package/dist/web/public/UserPromptsPage.d.ts.map +1 -0
- package/dist/web/public/UserPromptsPage.js +112 -0
- package/dist/web/public/UserPromptsPageServer.d.ts +15 -0
- package/dist/web/public/UserPromptsPageServer.d.ts.map +1 -0
- package/dist/web/public/UserPromptsPageServer.js +31 -0
- package/package.json +18 -9
- package/supabase/migrations/20251125000000_ai_tokens.sql +7 -0
- package/supabase/migrations/20260123100002_user_token_quota_monthly copy.sql +173 -0
- package/supabase/migrations/20260128100003_update_and_add_table.sql +368 -0
- package/supabase/migrations/20260128120000_seed_providers_models.sql +78 -0
- package/supabase/migrations/20260128131405_add_api_key_id_to_ledgers.sql +41 -0
- package/supabase/migrations/20260128140000_ai_artifacts_storage.sql +99 -0
- package/supabase/migrations/20260128140002_ai_user_settings.sql +57 -0
- package/supabase/migrations/20260128150000_drop_ai_user_settings.sql +21 -0
- package/supabase/migrations/20260128160000_wallet_billing_system.sql +192 -0
- package/supabase/migrations/20260128160001_wallet_rpc_functions.sql +165 -0
- package/supabase/migrations/20260128170000_add_pack_coef_to_token_packs.sql +30 -0
- package/supabase/migrations/20260129120000_wallet_view_rpc.sql +41 -0
- package/supabase/migrations/20260129220003_update_pack_margins.sql +31 -0
- package/supabase/migrations/20260129330004_ai_user_prompts.sql +151 -0
- package/supabase/migrations/20260129330005_ai_prompts_ip_tracking.sql +92 -0
- package/supabase/migrations/20260129330006_ai_prompts_slug.sql +64 -0
- package/supabase/migrations/20260129330007_ai_prompts_view_slug.sql +26 -0
- package/supabase/migrations/20260129440000_ai_prompts_view_username.sql +33 -0
- package/supabase/migrations/20260129450000_ai_prompts_add_lang.sql +40 -0
- package/supabase/migrations/20260131000000_extract_model_prompt_in_ledger.sql +92 -0
- package/supabase/migrations/20260131140000_fix_duplicate_purchases.sql +64 -0
- package/supabase/migrations/20260201120000_module-ai_default_models.sql +63 -0
- package/supabase/migrations/20260201130000_module-ai_remove_provider_tables.sql +17 -0
- package/supabase/migrations-down/20251217120000_user_token_quota_monthly.sql +34 -0
- package/supabase/migrations-down/20260128131405_add_api_key_id_to_ledgers.sql +25 -0
|
@@ -1,38 +1,77 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { getSupabaseServerClient } from "@lastbrain/core/server";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
return openai;
|
|
13
|
-
}
|
|
3
|
+
import { textAI } from "../../server/ai-client";
|
|
4
|
+
import { logger } from "@lastbrain/core";
|
|
5
|
+
import { computeAndDebitAIUsage, computeProviderCostUsd, getWalletState, } from "../../server/billing";
|
|
6
|
+
import { isModelEnabled } from "../../server/model-filter";
|
|
7
|
+
import { validateTextPricing } from "../../server/pricing-validator";
|
|
8
|
+
import { getDefaultTextModel } from "../../server/global-settings";
|
|
14
9
|
export async function POST(request) {
|
|
15
10
|
try {
|
|
16
|
-
const
|
|
11
|
+
const MAX_CHARS = 1200;
|
|
12
|
+
const supabaseAuth = await getSupabaseServerClient();
|
|
17
13
|
// Vérifier l'authentification
|
|
18
|
-
const { data: { user }, } = await
|
|
14
|
+
const { data: { user }, } = await supabaseAuth.auth.getUser();
|
|
19
15
|
// L'utilisateur est déjà authentifié grâce au middleware
|
|
20
16
|
const body = await request.json();
|
|
21
|
-
|
|
17
|
+
// Get default model from global settings if not provided
|
|
18
|
+
const defaultModel = await getDefaultTextModel();
|
|
19
|
+
const { prompt, promptUser, model = defaultModel, // Use global default instead of hardcoded
|
|
20
|
+
context, maxTokens = 3000, temperature = 0.7, actionType = "generate-text", // Default to generate-text if not specified
|
|
21
|
+
} = body;
|
|
22
22
|
if (!prompt) {
|
|
23
23
|
return NextResponse.json({ error: "Le prompt est requis" }, { status: 400 });
|
|
24
24
|
}
|
|
25
|
+
if (promptUser) {
|
|
26
|
+
logger.info("promptUser length:", promptUser.length);
|
|
27
|
+
}
|
|
28
|
+
if (promptUser && promptUser.length > MAX_CHARS) {
|
|
29
|
+
return NextResponse.json({ error: "Prompt trop long max 1200 caractères" }, { status: 400 });
|
|
30
|
+
}
|
|
25
31
|
if (!user) {
|
|
26
32
|
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
|
|
27
33
|
}
|
|
28
|
-
//
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
// Build model string: "openai/model" or use full if already formatted
|
|
35
|
+
const fullModel = model.includes("/") ? model : `openai/${model}`;
|
|
36
|
+
// Parse provider/model from fullModel
|
|
37
|
+
const [provider, modelName] = fullModel.includes("/")
|
|
38
|
+
? fullModel.split("/", 2)
|
|
39
|
+
: ["openai", fullModel];
|
|
40
|
+
// Skip model check for recipe and image generation (always allowed)
|
|
41
|
+
const isRecipeAction = actionType === "generate-recipe-text";
|
|
42
|
+
// Get model pricing via model-filter (BEFORE generation to check credits)
|
|
43
|
+
// For recipes, bypass user settings and use default pricing
|
|
44
|
+
const filterResult = isRecipeAction
|
|
45
|
+
? {
|
|
46
|
+
allowed: true,
|
|
47
|
+
model: {
|
|
48
|
+
pricing: {
|
|
49
|
+
input: 0.15 / 1000000, // $0.15 per 1M tokens (gpt-4o-mini default)
|
|
50
|
+
output: 0.6 / 1000000, // $0.60 per 1M tokens
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
: await isModelEnabled(user.id, fullModel);
|
|
55
|
+
if (!filterResult.allowed) {
|
|
56
|
+
logger.warn(`[generate-text] Model ${fullModel} not allowed for user ${user.id}`);
|
|
57
|
+
return NextResponse.json({ error: "Modèle non autorisé" }, { status: 403 });
|
|
58
|
+
}
|
|
59
|
+
// Prepare pricing for wallet billing
|
|
60
|
+
const pricingValidation = validateTextPricing(filterResult.model?.pricing, fullModel);
|
|
61
|
+
if (!pricingValidation.valid) {
|
|
62
|
+
return NextResponse.json({ error: pricingValidation.error }, { status: 503 });
|
|
63
|
+
}
|
|
64
|
+
const pricing = pricingValidation.pricing;
|
|
65
|
+
// Get current wallet state
|
|
66
|
+
const wallet = await getWalletState(user.id);
|
|
67
|
+
// PRE-CHECK: Simple check - user must have credits (> 0)
|
|
68
|
+
// The real debit with minimums will be computed post-generation
|
|
69
|
+
if (!wallet.walletProviderBudgetUsd ||
|
|
70
|
+
wallet.walletProviderBudgetUsd <= 0) {
|
|
71
|
+
logger.warn(`[generate-text] No credits for user ${user.id}: wallet=$${wallet.walletProviderBudgetUsd}`);
|
|
72
|
+
return NextResponse.json({ error: "Crédits insuffisants pour cette opération" }, { status: 402 });
|
|
35
73
|
}
|
|
74
|
+
logger.info(`[generate-text] Pre-check passed for user ${user.id}: wallet=$${wallet.walletProviderBudgetUsd.toFixed(6)}`);
|
|
36
75
|
// Construire les messages
|
|
37
76
|
const messages = [
|
|
38
77
|
{
|
|
@@ -50,56 +89,89 @@ export async function POST(request) {
|
|
|
50
89
|
role: "user",
|
|
51
90
|
content: prompt,
|
|
52
91
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const completion = await
|
|
56
|
-
|
|
57
|
-
|
|
92
|
+
logger.info(`[AI] Generating text with model: ${fullModel}`);
|
|
93
|
+
// Call our simplified AI client
|
|
94
|
+
const completion = await textAI({
|
|
95
|
+
prompt,
|
|
96
|
+
model: fullModel,
|
|
97
|
+
system: "Tu es un assistant IA qui aide à générer du texte de qualité.",
|
|
98
|
+
maxTokens,
|
|
58
99
|
temperature,
|
|
59
|
-
max_tokens: maxTokens,
|
|
60
100
|
});
|
|
61
|
-
const generatedText = completion.
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (model.includes("gpt-4o-mini")) {
|
|
68
|
-
cost =
|
|
69
|
-
(inputTokens / 1_000_000) * 0.15 + (outputTokens / 1_000_000) * 0.6;
|
|
70
|
-
}
|
|
71
|
-
else if (model.includes("gpt-4o")) {
|
|
72
|
-
cost = (inputTokens / 1_000_000) * 2.5 + (outputTokens / 1_000_000) * 10;
|
|
73
|
-
}
|
|
74
|
-
else if (model.includes("gpt-4")) {
|
|
75
|
-
cost = (inputTokens / 1_000_000) * 30 + (outputTokens / 1_000_000) * 60;
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
cost = (tokensUsed / 1_000_000) * 2; // Fallback
|
|
79
|
-
}
|
|
80
|
-
// Déduire les tokens utilisés
|
|
81
|
-
const tokenResult = await deductTokens(user.id, tokensUsed, model, prompt, {
|
|
101
|
+
const generatedText = completion.text || "";
|
|
102
|
+
const inputTokens = completion.usage?.promptTokens || 0;
|
|
103
|
+
const outputTokens = completion.usage?.completionTokens || 0;
|
|
104
|
+
const tokensUsedFromAI = completion.usage?.totalTokens || 0;
|
|
105
|
+
// Prepare usage for actual billing (from API response)
|
|
106
|
+
const actualUsage = {
|
|
82
107
|
inputTokens,
|
|
83
108
|
outputTokens,
|
|
84
|
-
|
|
85
|
-
|
|
109
|
+
};
|
|
110
|
+
// Compute actual provider cost from API usage
|
|
111
|
+
const actualProviderCost = computeProviderCostUsd(actualUsage, pricing);
|
|
112
|
+
// Compute and debit using centralized billing logic
|
|
113
|
+
const billingResult = computeAndDebitAIUsage({
|
|
114
|
+
userId: user.id,
|
|
115
|
+
actionType: actionType, // Use the actionType from request (default: "generate-text")
|
|
116
|
+
providerCostUsd: actualProviderCost,
|
|
117
|
+
wallet,
|
|
118
|
+
metadata: {
|
|
119
|
+
model: modelName,
|
|
120
|
+
provider,
|
|
121
|
+
endpoint: "generate-text",
|
|
122
|
+
inputTokens,
|
|
123
|
+
outputTokens,
|
|
124
|
+
prompt: prompt.substring(0, 32),
|
|
125
|
+
generatedText: generatedText.substring(0, 500),
|
|
126
|
+
},
|
|
86
127
|
});
|
|
87
|
-
if (
|
|
128
|
+
// Check if billing failed (insufficient credits post-check)
|
|
129
|
+
if (!billingResult.success) {
|
|
130
|
+
logger.error(`[generate-text] Billing failed for user ${user.id}: ${billingResult.error}`, {
|
|
131
|
+
providerCost: actualProviderCost,
|
|
132
|
+
walletSellValue: wallet.walletSellValueUsd,
|
|
133
|
+
walletProviderBudget: wallet.walletProviderBudgetUsd,
|
|
134
|
+
});
|
|
88
135
|
return NextResponse.json({
|
|
89
|
-
error:
|
|
90
|
-
}, { status:
|
|
136
|
+
error: billingResult.error || "Crédits insuffisants pour cette opération",
|
|
137
|
+
}, { status: 402 } // Payment Required
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
// Record consumption in database (ledger)
|
|
141
|
+
const supabase = await getSupabaseServerClient();
|
|
142
|
+
const { error: ledgerError } = await supabase.rpc("record_token_consumption", {
|
|
143
|
+
p_user_id: user.id,
|
|
144
|
+
p_debit_tokens: 0, // Calculated by wallet system
|
|
145
|
+
p_provider_cost_usd: billingResult.providerCostUsd || 0,
|
|
146
|
+
p_sell_usd: billingResult.sellCostUsd || 0,
|
|
147
|
+
p_margin_usd: billingResult.marginUsd || 0,
|
|
148
|
+
p_meta: {
|
|
149
|
+
model: modelName,
|
|
150
|
+
provider,
|
|
151
|
+
endpoint: "generate-text",
|
|
152
|
+
inputTokens,
|
|
153
|
+
outputTokens,
|
|
154
|
+
prompt: prompt.substring(0, 32),
|
|
155
|
+
generatedText: generatedText.substring(0, 500),
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
if (ledgerError) {
|
|
159
|
+
logger.error("[generate-text] Failed to record in ledger:", ledgerError);
|
|
160
|
+
// Continue anyway - billing logic already validated
|
|
91
161
|
}
|
|
162
|
+
logger.info(`[generate-text] Text generation completed: cost=$${billingResult.providerCostUsd?.toFixed(6)}, sell=$${billingResult.sellCostUsd?.toFixed(6)}, margin=${billingResult.marginPercent?.toFixed(1)}%`);
|
|
92
163
|
return NextResponse.json({
|
|
93
164
|
text: generatedText,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
165
|
+
model: modelName,
|
|
166
|
+
provider,
|
|
167
|
+
inputTokens,
|
|
168
|
+
outputTokens,
|
|
97
169
|
});
|
|
98
170
|
}
|
|
99
171
|
catch (error) {
|
|
100
|
-
|
|
172
|
+
logger.error("Erreur de génération:", error);
|
|
101
173
|
if (error.code === "insufficient_quota") {
|
|
102
|
-
return NextResponse.json({ error: "Quota
|
|
174
|
+
return NextResponse.json({ error: "Quota IA dépassé. Contactez l'administrateur." }, { status: 503 });
|
|
103
175
|
}
|
|
104
176
|
return NextResponse.json({ error: error.message || "Erreur lors de la génération" }, { status: 500 });
|
|
105
177
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
/**
|
|
3
|
+
* POST /api/ai/process-ocr
|
|
4
|
+
* Process OCR using OpenAI Vision with proper token debit
|
|
5
|
+
*/
|
|
6
|
+
export declare function POST(request: NextRequest): Promise<NextResponse<{
|
|
7
|
+
error: string | undefined;
|
|
8
|
+
}> | NextResponse<import("../../server").ProcessOCRResponse>>;
|
|
9
|
+
//# sourceMappingURL=process-ocr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-ocr.d.ts","sourceRoot":"","sources":["../../../src/api/auth/process-ocr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgBxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;8DAqD9C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getSupabaseServerClient } from "@lastbrain/core/server";
|
|
3
|
+
import { processOCRWithTokens } from "../../server/ocr";
|
|
4
|
+
/**
|
|
5
|
+
* POST /api/ai/process-ocr
|
|
6
|
+
* Process OCR using OpenAI Vision with proper token debit
|
|
7
|
+
*/
|
|
8
|
+
export async function POST(request) {
|
|
9
|
+
try {
|
|
10
|
+
const supabase = await getSupabaseServerClient();
|
|
11
|
+
// Verify authentication
|
|
12
|
+
const { data: { user }, } = await supabase.auth.getUser();
|
|
13
|
+
if (!user) {
|
|
14
|
+
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
|
|
15
|
+
}
|
|
16
|
+
const body = await request.json();
|
|
17
|
+
const { files, mode, prompt, extractionSchema } = body;
|
|
18
|
+
if (!files || files.length === 0) {
|
|
19
|
+
return NextResponse.json({ error: "Aucun fichier à traiter" }, { status: 400 });
|
|
20
|
+
}
|
|
21
|
+
if (!prompt) {
|
|
22
|
+
return NextResponse.json({ error: "Le prompt est requis" }, { status: 400 });
|
|
23
|
+
}
|
|
24
|
+
// Process OCR with token debit
|
|
25
|
+
const result = await processOCRWithTokens({
|
|
26
|
+
userId: user.id,
|
|
27
|
+
files,
|
|
28
|
+
mode,
|
|
29
|
+
prompt,
|
|
30
|
+
extractionSchema,
|
|
31
|
+
allowOverdraft: false,
|
|
32
|
+
});
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
const status = result.error?.includes("insuffisant") ? 402 : 500;
|
|
35
|
+
return NextResponse.json({ error: result.error }, { status });
|
|
36
|
+
}
|
|
37
|
+
return NextResponse.json(result);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const err = error;
|
|
41
|
+
return NextResponse.json({ error: err.message || "Erreur lors du traitement OCR" }, { status: 500 });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Increment prompt stats
|
|
3
|
+
* POST /api/ai/auth/prompts/stats
|
|
4
|
+
*/
|
|
5
|
+
import type { NextRequest } from "next/server";
|
|
6
|
+
import { NextResponse } from "next/server";
|
|
7
|
+
export declare function POST(req: NextRequest): Promise<NextResponse<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
error: string;
|
|
10
|
+
}> | NextResponse<{
|
|
11
|
+
success: boolean;
|
|
12
|
+
message: string;
|
|
13
|
+
}>>;
|
|
14
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../../src/api/auth/prompts/stats.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,wBAAsB,IAAI,CAAC,GAAG,EAAE,WAAW;;;;;;IA+D1C"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Increment prompt stats
|
|
3
|
+
* POST /api/ai/auth/prompts/stats
|
|
4
|
+
*/
|
|
5
|
+
import { NextResponse } from "next/server";
|
|
6
|
+
import { getSupabaseServiceClient } from "@lastbrain/core/server";
|
|
7
|
+
import { logger } from "@lastbrain/core";
|
|
8
|
+
export async function POST(req) {
|
|
9
|
+
try {
|
|
10
|
+
const supabase = getSupabaseServiceClient();
|
|
11
|
+
// Get authenticated user
|
|
12
|
+
const { data: { user }, error: authError, } = await supabase.auth.getUser();
|
|
13
|
+
if (authError || !user) {
|
|
14
|
+
return NextResponse.json({ success: false, error: "Unauthorized" }, { status: 401 });
|
|
15
|
+
}
|
|
16
|
+
const body = await req.json();
|
|
17
|
+
const { prompt_id, stat_type } = body;
|
|
18
|
+
if (!prompt_id || !stat_type) {
|
|
19
|
+
return NextResponse.json({ success: false, error: "Missing prompt_id or stat_type" }, { status: 400 });
|
|
20
|
+
}
|
|
21
|
+
// Validate stat_type
|
|
22
|
+
if (!["views", "used", "picked"].includes(stat_type)) {
|
|
23
|
+
return NextResponse.json({
|
|
24
|
+
success: false,
|
|
25
|
+
error: "Invalid stat_type. Must be views, used, or picked",
|
|
26
|
+
}, { status: 400 });
|
|
27
|
+
}
|
|
28
|
+
// Call function to increment stat
|
|
29
|
+
const { error } = await supabase.rpc("increment_prompt_stat", {
|
|
30
|
+
p_prompt_id: prompt_id,
|
|
31
|
+
p_stat_type: stat_type,
|
|
32
|
+
});
|
|
33
|
+
if (error) {
|
|
34
|
+
logger.error("Failed to increment prompt stat:", error);
|
|
35
|
+
return NextResponse.json({ success: false, error: "Failed to increment stat" }, { status: 500 });
|
|
36
|
+
}
|
|
37
|
+
return NextResponse.json({
|
|
38
|
+
success: true,
|
|
39
|
+
message: `${stat_type} incremented`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger.error("Prompt stat increment error:", error);
|
|
44
|
+
return NextResponse.json({ success: false, error: "Internal server error" }, { status: 500 });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET/POST/PUT/DELETE /api/ai/auth/prompts
|
|
3
|
+
* CRUD for user's AI prompts
|
|
4
|
+
*/
|
|
5
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
6
|
+
export declare function GET(request: NextRequest): Promise<NextResponse<{
|
|
7
|
+
prompts: any[];
|
|
8
|
+
}> | NextResponse<{
|
|
9
|
+
error: any;
|
|
10
|
+
}>>;
|
|
11
|
+
export declare function POST(request: NextRequest): Promise<NextResponse<{
|
|
12
|
+
prompt: any;
|
|
13
|
+
}> | NextResponse<{
|
|
14
|
+
error: any;
|
|
15
|
+
}>>;
|
|
16
|
+
export declare function PUT(request: NextRequest): Promise<NextResponse<{
|
|
17
|
+
prompt: any;
|
|
18
|
+
}> | NextResponse<{
|
|
19
|
+
error: any;
|
|
20
|
+
}>>;
|
|
21
|
+
export declare function DELETE(request: NextRequest): Promise<NextResponse<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
}> | NextResponse<{
|
|
24
|
+
error: any;
|
|
25
|
+
}>>;
|
|
26
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/api/auth/prompts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKxD,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;IA8D7C;AAGD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IA6D9C;AAGD,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;IAsD7C;AAGD,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW;;;;IAuChD"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET/POST/PUT/DELETE /api/ai/auth/prompts
|
|
3
|
+
* CRUD for user's AI prompts
|
|
4
|
+
*/
|
|
5
|
+
import { NextResponse } from "next/server";
|
|
6
|
+
import { getSupabaseServerClient } from "@lastbrain/core/server";
|
|
7
|
+
import { logger } from "@lastbrain/core";
|
|
8
|
+
// GET - List user's prompts
|
|
9
|
+
export async function GET(request) {
|
|
10
|
+
try {
|
|
11
|
+
const supabase = await getSupabaseServerClient();
|
|
12
|
+
const { data: { user }, error: authError, } = await supabase.auth.getUser();
|
|
13
|
+
if (authError || !user) {
|
|
14
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
15
|
+
}
|
|
16
|
+
const { searchParams } = new URL(request.url);
|
|
17
|
+
const type = searchParams.get("type"); // 'text' or 'image'
|
|
18
|
+
const favorite = searchParams.get("favorite") === "true";
|
|
19
|
+
let query = supabase
|
|
20
|
+
.from("user_prompt")
|
|
21
|
+
.select(`
|
|
22
|
+
*,
|
|
23
|
+
prompt_stats (
|
|
24
|
+
views,
|
|
25
|
+
used_count,
|
|
26
|
+
picked_count
|
|
27
|
+
)
|
|
28
|
+
`)
|
|
29
|
+
.eq("owner_id", user.id)
|
|
30
|
+
.order("favorite", { ascending: false })
|
|
31
|
+
.order("created_at", { ascending: false });
|
|
32
|
+
if (type) {
|
|
33
|
+
query = query.eq("type", type);
|
|
34
|
+
}
|
|
35
|
+
if (favorite) {
|
|
36
|
+
query = query.eq("favorite", true);
|
|
37
|
+
}
|
|
38
|
+
const { data: prompts, error } = await query;
|
|
39
|
+
if (error) {
|
|
40
|
+
logger.error("[prompts] GET error:", error);
|
|
41
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
42
|
+
}
|
|
43
|
+
// Flatten stats into prompt object
|
|
44
|
+
const promptsWithStats = prompts?.map((p) => ({
|
|
45
|
+
...p,
|
|
46
|
+
views: p.prompt_stats?.[0]?.views || 0,
|
|
47
|
+
used_count: p.prompt_stats?.[0]?.used_count || 0,
|
|
48
|
+
picked_count: p.prompt_stats?.[0]?.picked_count || 0,
|
|
49
|
+
prompt_stats: undefined, // Remove nested object
|
|
50
|
+
}));
|
|
51
|
+
return NextResponse.json({ prompts: promptsWithStats });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
logger.error("[prompts] GET unexpected error:", error);
|
|
55
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// POST - Create new prompt
|
|
59
|
+
export async function POST(request) {
|
|
60
|
+
try {
|
|
61
|
+
const supabase = await getSupabaseServerClient();
|
|
62
|
+
const { data: { user }, error: authError, } = await supabase.auth.getUser();
|
|
63
|
+
if (authError || !user) {
|
|
64
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
65
|
+
}
|
|
66
|
+
const body = await request.json();
|
|
67
|
+
const { title, content, type, is_public = false, favorite = false, tags = [], } = body;
|
|
68
|
+
if (!title || !content || !type) {
|
|
69
|
+
return NextResponse.json({ error: "Missing required fields: title, content, type" }, { status: 400 });
|
|
70
|
+
}
|
|
71
|
+
if (!["text", "image"].includes(type)) {
|
|
72
|
+
return NextResponse.json({ error: "Invalid type. Must be 'text' or 'image'" }, { status: 400 });
|
|
73
|
+
}
|
|
74
|
+
const { data: prompt, error } = await supabase
|
|
75
|
+
.from("user_prompt")
|
|
76
|
+
.insert({
|
|
77
|
+
owner_id: user.id,
|
|
78
|
+
title,
|
|
79
|
+
content,
|
|
80
|
+
type,
|
|
81
|
+
is_public,
|
|
82
|
+
favorite,
|
|
83
|
+
tags,
|
|
84
|
+
})
|
|
85
|
+
.select()
|
|
86
|
+
.single();
|
|
87
|
+
if (error) {
|
|
88
|
+
logger.error("[prompts] POST error:", error);
|
|
89
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
90
|
+
}
|
|
91
|
+
return NextResponse.json({ prompt }, { status: 201 });
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
logger.error("[prompts] POST unexpected error:", error);
|
|
95
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// PUT - Update prompt
|
|
99
|
+
export async function PUT(request) {
|
|
100
|
+
try {
|
|
101
|
+
const supabase = await getSupabaseServerClient();
|
|
102
|
+
const { data: { user }, error: authError, } = await supabase.auth.getUser();
|
|
103
|
+
if (authError || !user) {
|
|
104
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
105
|
+
}
|
|
106
|
+
const body = await request.json();
|
|
107
|
+
const { id, title, content, type, is_public, favorite, tags, lang } = body;
|
|
108
|
+
if (!id) {
|
|
109
|
+
return NextResponse.json({ error: "Missing required field: id" }, { status: 400 });
|
|
110
|
+
}
|
|
111
|
+
const updates = {};
|
|
112
|
+
if (title !== undefined)
|
|
113
|
+
updates.title = title;
|
|
114
|
+
if (content !== undefined)
|
|
115
|
+
updates.content = content;
|
|
116
|
+
if (type !== undefined)
|
|
117
|
+
updates.type = type;
|
|
118
|
+
if (is_public !== undefined)
|
|
119
|
+
updates.is_public = is_public;
|
|
120
|
+
if (favorite !== undefined)
|
|
121
|
+
updates.favorite = favorite;
|
|
122
|
+
if (tags !== undefined)
|
|
123
|
+
updates.tags = tags;
|
|
124
|
+
if (lang)
|
|
125
|
+
updates.lang = lang;
|
|
126
|
+
const { data: prompt, error } = await supabase
|
|
127
|
+
.from("user_prompt")
|
|
128
|
+
.update(updates)
|
|
129
|
+
.eq("id", id)
|
|
130
|
+
.eq("owner_id", user.id)
|
|
131
|
+
.select()
|
|
132
|
+
.single();
|
|
133
|
+
if (error) {
|
|
134
|
+
logger.error("[prompts] PUT error:", error);
|
|
135
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
136
|
+
}
|
|
137
|
+
if (!prompt) {
|
|
138
|
+
return NextResponse.json({ error: "Prompt not found" }, { status: 404 });
|
|
139
|
+
}
|
|
140
|
+
return NextResponse.json({ prompt });
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
logger.error("[prompts] PUT unexpected error:", error);
|
|
144
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// DELETE - Delete prompt
|
|
148
|
+
export async function DELETE(request) {
|
|
149
|
+
try {
|
|
150
|
+
const supabase = await getSupabaseServerClient();
|
|
151
|
+
const { data: { user }, error: authError, } = await supabase.auth.getUser();
|
|
152
|
+
if (authError || !user) {
|
|
153
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
154
|
+
}
|
|
155
|
+
const { searchParams } = new URL(request.url);
|
|
156
|
+
const id = searchParams.get("id");
|
|
157
|
+
if (!id) {
|
|
158
|
+
return NextResponse.json({ error: "Missing required parameter: id" }, { status: 400 });
|
|
159
|
+
}
|
|
160
|
+
const { error } = await supabase
|
|
161
|
+
.from("user_prompt")
|
|
162
|
+
.delete()
|
|
163
|
+
.eq("id", id)
|
|
164
|
+
.eq("owner_id", user.id);
|
|
165
|
+
if (error) {
|
|
166
|
+
logger.error("[prompts] DELETE error:", error);
|
|
167
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
168
|
+
}
|
|
169
|
+
return NextResponse.json({ success: true });
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
logger.error("[prompts] DELETE unexpected error:", error);
|
|
173
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /api/ai/auth/token-balance
|
|
3
|
+
* Returns combined token balance: quota + purchased tokens
|
|
4
|
+
*/
|
|
5
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
6
|
+
export declare function GET(request: NextRequest): Promise<NextResponse<{
|
|
7
|
+
quota: {
|
|
8
|
+
hasQuota: boolean;
|
|
9
|
+
plan: import("../..").PlanType;
|
|
10
|
+
effectiveQuota: number;
|
|
11
|
+
usedQuota: number;
|
|
12
|
+
remainingQuota: number;
|
|
13
|
+
periodStart: string | null;
|
|
14
|
+
periodEnd: string | null;
|
|
15
|
+
isActive: boolean;
|
|
16
|
+
};
|
|
17
|
+
purchased: {
|
|
18
|
+
balance: number;
|
|
19
|
+
totalAdded: number;
|
|
20
|
+
totalUsed: number;
|
|
21
|
+
};
|
|
22
|
+
balance: number;
|
|
23
|
+
}> | NextResponse<{
|
|
24
|
+
error: any;
|
|
25
|
+
}>>;
|
|
26
|
+
//# sourceMappingURL=token-balance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-balance.d.ts","sourceRoot":"","sources":["../../../src/api/auth/token-balance.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMxD,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;;;;;;;;;;IA+C7C"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /api/ai/auth/token-balance
|
|
3
|
+
* Returns combined token balance: quota + purchased tokens
|
|
4
|
+
*/
|
|
5
|
+
import { NextResponse } from "next/server";
|
|
6
|
+
import { getSupabaseServerClient } from "@lastbrain/core/server";
|
|
7
|
+
import { getUserQuotaStatus } from "../../server/quota";
|
|
8
|
+
import { getTokenBalance, getTokenStats } from "../../server";
|
|
9
|
+
import { logger } from "@lastbrain/core";
|
|
10
|
+
export async function GET(request) {
|
|
11
|
+
try {
|
|
12
|
+
const supabase = await getSupabaseServerClient();
|
|
13
|
+
// Auth check
|
|
14
|
+
const { data: { user }, error: authError, } = await supabase.auth.getUser();
|
|
15
|
+
if (authError || !user) {
|
|
16
|
+
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
|
|
17
|
+
}
|
|
18
|
+
// Get quota status
|
|
19
|
+
const quotaStatus = await getUserQuotaStatus(user.id);
|
|
20
|
+
// Get purchased tokens balance
|
|
21
|
+
const purchasedBalance = await getTokenBalance(user.id);
|
|
22
|
+
const purchasedStats = await getTokenStats(user.id);
|
|
23
|
+
return NextResponse.json({
|
|
24
|
+
quota: {
|
|
25
|
+
hasQuota: quotaStatus.hasQuota,
|
|
26
|
+
plan: quotaStatus.plan,
|
|
27
|
+
effectiveQuota: quotaStatus.effectiveQuota,
|
|
28
|
+
usedQuota: quotaStatus.usedQuota,
|
|
29
|
+
remainingQuota: quotaStatus.remainingQuota,
|
|
30
|
+
periodStart: quotaStatus.periodStart,
|
|
31
|
+
periodEnd: quotaStatus.periodEnd,
|
|
32
|
+
isActive: quotaStatus.isActive,
|
|
33
|
+
},
|
|
34
|
+
purchased: {
|
|
35
|
+
balance: purchasedBalance,
|
|
36
|
+
totalAdded: purchasedStats.totalPurchased + purchasedStats.totalGifted,
|
|
37
|
+
totalUsed: purchasedStats.totalUsed,
|
|
38
|
+
},
|
|
39
|
+
// For backward compatibility
|
|
40
|
+
balance: purchasedBalance,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
logger.error("[GET /api/ai/auth/token-balance] Error:", error);
|
|
45
|
+
return NextResponse.json({ error: error.message || "Erreur serveur" }, { status: 500 });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-checkout.d.ts","sourceRoot":"","sources":["../../../src/api/auth/token-checkout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"token-checkout.d.ts","sourceRoot":"","sources":["../../../src/api/auth/token-checkout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IAuF9C"}
|