mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-31 17:19:56 +08:00
feat(core): handle AI subscription for pro models (#13682)
<img width="576" height="251" alt="截屏2025-09-30 14 55 20" src="https://github.com/user-attachments/assets/947a4ab3-8b34-434d-94a6-afb5dad3d32c" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added “Subscribe to AI” action across chat experiences (panel, content, composer, input, playground, peek view) that launches an in-app checkout flow. - Chat content now refreshes subscription status when opened; desktop chat pages wire the subscription action for seamless checkout. - **Style** - Polished hover state for the subscription icon in chat preferences. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -137,6 +137,9 @@ export class ChatPanel extends SignalWatcher(
|
||||
@property({ attribute: false })
|
||||
accessor aiModelService!: AIModelService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onAISubscribe!: () => Promise<void>;
|
||||
|
||||
@state()
|
||||
accessor session: CopilotChatHistoryFragment | null | undefined;
|
||||
|
||||
@@ -462,6 +465,7 @@ export class ChatPanel extends SignalWatcher(
|
||||
.peekViewService=${this.peekViewService}
|
||||
.subscriptionService=${this.subscriptionService}
|
||||
.aiModelService=${this.aiModelService}
|
||||
.onAISubscribe=${this.onAISubscribe}
|
||||
.onEmbeddingProgressChange=${this.onEmbeddingProgressChange}
|
||||
.onContextChange=${this.onContextChange}
|
||||
.width=${this.sidebarWidth}
|
||||
|
||||
+4
@@ -149,6 +149,9 @@ export class AIChatComposer extends SignalWatcher(
|
||||
@property({ attribute: false })
|
||||
accessor aiModelService!: AIModelService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onAISubscribe!: () => Promise<void>;
|
||||
|
||||
@state()
|
||||
accessor chips: ChatChip[] = [];
|
||||
|
||||
@@ -200,6 +203,7 @@ export class AIChatComposer extends SignalWatcher(
|
||||
.notificationService=${this.notificationService}
|
||||
.subscriptionService=${this.subscriptionService}
|
||||
.aiModelService=${this.aiModelService}
|
||||
.onAISubscribe=${this.onAISubscribe}
|
||||
.portalContainer=${this.portalContainer}
|
||||
.onChatSuccess=${this.onChatSuccess}
|
||||
.trackOptions=${this.trackOptions}
|
||||
|
||||
@@ -192,6 +192,9 @@ export class AIChatContent extends SignalWatcher(
|
||||
@property({ attribute: false })
|
||||
accessor subscriptionService!: SubscriptionService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onAISubscribe!: () => Promise<void>;
|
||||
|
||||
@state()
|
||||
accessor chatContextValue: ChatContextValue = DEFAULT_CHAT_CONTEXT_VALUE;
|
||||
|
||||
@@ -381,6 +384,9 @@ export class AIChatContent extends SignalWatcher(
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
// revalidate subscription to get the latest status
|
||||
this.subscriptionService.subscription.revalidate();
|
||||
|
||||
this._disposables.add(
|
||||
AIProvider.slots.actions.subscribe(({ event }) => {
|
||||
const { status } = this.chatContextValue;
|
||||
@@ -472,6 +478,7 @@ export class AIChatContent extends SignalWatcher(
|
||||
.aiToolsConfigService=${this.aiToolsConfigService}
|
||||
.subscriptionService=${this.subscriptionService}
|
||||
.aiModelService=${this.aiModelService}
|
||||
.onAISubscribe=${this.onAISubscribe}
|
||||
.trackOptions=${{
|
||||
where: 'chat-panel',
|
||||
control: 'chat-send',
|
||||
|
||||
@@ -377,6 +377,9 @@ export class AIChatInput extends SignalWatcher(
|
||||
@property({ attribute: false })
|
||||
accessor aiModelService!: AIModelService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onAISubscribe!: () => Promise<void>;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor isRootSession: boolean = true;
|
||||
|
||||
@@ -534,6 +537,7 @@ export class AIChatInput extends SignalWatcher(
|
||||
.notificationService=${this.notificationService}
|
||||
.subscriptionService=${this.subscriptionService}
|
||||
.aiModelService=${this.aiModelService}
|
||||
.onAISubscribe=${this.onAISubscribe}
|
||||
></chat-input-preference>
|
||||
${status === 'transmitting' || status === 'loading'
|
||||
? html`<button
|
||||
|
||||
+7
-1
@@ -72,6 +72,9 @@ export class ChatInputPreference extends SignalWatcher(
|
||||
.ai-model-prefix svg {
|
||||
color: ${unsafeCSSVarV2('icon/activated')};
|
||||
}
|
||||
.ai-model-postfix svg:hover {
|
||||
color: ${unsafeCSSVarV2('icon/activated')};
|
||||
}
|
||||
.ai-model-version {
|
||||
font-size: 12px;
|
||||
color: ${unsafeCSSVarV2('text/tertiary')};
|
||||
@@ -119,6 +122,9 @@ export class ChatInputPreference extends SignalWatcher(
|
||||
@property({ attribute: false })
|
||||
accessor aiModelService!: AIModelService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onAISubscribe!: () => Promise<void>;
|
||||
|
||||
model = computed(() => {
|
||||
const modelId = this.aiModelService.modelId.value;
|
||||
const activeModel = this.aiModelService.models.value.find(
|
||||
@@ -161,7 +167,7 @@ export class ChatInputPreference extends SignalWatcher(
|
||||
</div>
|
||||
`,
|
||||
postfix: html`
|
||||
<div>
|
||||
<div class="ai-model-postfix" @click=${this.onAISubscribe}>
|
||||
${model.isPro && !isSubscribed ? LockIcon() : undefined}
|
||||
</div>
|
||||
`,
|
||||
|
||||
@@ -182,6 +182,9 @@ export class PlaygroundChat extends SignalWatcher(
|
||||
@property({ attribute: false })
|
||||
accessor aiToolsConfigService!: AIToolsConfigService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onAISubscribe: (() => Promise<void>) | undefined;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor addChat!: () => Promise<void>;
|
||||
|
||||
@@ -374,6 +377,7 @@ export class PlaygroundChat extends SignalWatcher(
|
||||
.aiToolsConfigService=${this.aiToolsConfigService}
|
||||
.affineWorkspaceDialogService=${this.affineWorkspaceDialogService}
|
||||
.affineFeatureFlagService=${this.affineFeatureFlagService}
|
||||
.onAISubscribe=${this.onAISubscribe}
|
||||
></ai-chat-composer>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import type {
|
||||
AIDraftService,
|
||||
AIToolsConfigService,
|
||||
} from '@affine/core/modules/ai-button';
|
||||
import type { AIModelService } from '@affine/core/modules/ai-button/services/models';
|
||||
import type { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import type {
|
||||
@@ -622,6 +624,9 @@ export class AIChatBlockPeekView extends LitElement {
|
||||
}}
|
||||
.portalContainer=${this.parentElement}
|
||||
.reasoningConfig=${this.reasoningConfig}
|
||||
.subscriptionService=${this.subscriptionService}
|
||||
.aiModelService=${this.aiModelService}
|
||||
.onAISubscribe=${this.onAISubscribe}
|
||||
></ai-chat-composer>
|
||||
</div> `;
|
||||
}
|
||||
@@ -659,6 +664,15 @@ export class AIChatBlockPeekView extends LitElement {
|
||||
@property({ attribute: false })
|
||||
accessor aiToolsConfigService!: AIToolsConfigService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor aiModelService!: AIModelService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor subscriptionService!: SubscriptionService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor onAISubscribe!: () => Promise<void>;
|
||||
|
||||
@state()
|
||||
accessor _historyMessages: ChatMessage[] = [];
|
||||
|
||||
@@ -697,7 +711,10 @@ export const AIChatBlockPeekViewTemplate = (
|
||||
affineFeatureFlagService: FeatureFlagService,
|
||||
affineWorkspaceDialogService: WorkspaceDialogService,
|
||||
aiDraftService: AIDraftService,
|
||||
aiToolsConfigService: AIToolsConfigService
|
||||
aiToolsConfigService: AIToolsConfigService,
|
||||
subscriptionService: SubscriptionService,
|
||||
aiModelService: AIModelService,
|
||||
onAISubscribe: (() => Promise<void>) | undefined
|
||||
) => {
|
||||
return html`<ai-chat-block-peek-view
|
||||
.blockModel=${blockModel}
|
||||
@@ -710,5 +727,8 @@ export const AIChatBlockPeekViewTemplate = (
|
||||
.affineWorkspaceDialogService=${affineWorkspaceDialogService}
|
||||
.aiDraftService=${aiDraftService}
|
||||
.aiToolsConfigService=${aiToolsConfigService}
|
||||
.subscriptionService=${subscriptionService}
|
||||
.aiModelService=${aiModelService}
|
||||
.onAISubscribe=${onAISubscribe}
|
||||
></ai-chat-block-peek-view>`;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user