diff --git a/packages/backend/server/schema.gql b/packages/backend/server/schema.gql deleted file mode 100644 index af2711c283..0000000000 --- a/packages/backend/server/schema.gql +++ /dev/null @@ -1,1767 +0,0 @@ -# ------------------------------------------------------ -# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) -# ------------------------------------------------------ - -input AddContextCategoryInput { - categoryId: String! - contextId: String! - docs: [String!] - type: ContextCategories! -} - -input AddContextDocInput { - contextId: String! - docId: String! -} - -input AddContextFileInput { - blobId: String! - contextId: String! -} - -enum AiJobStatus { - claimed - failed - finished - pending - running -} - -type AlreadyInSpaceDataType { - spaceId: String! -} - -type BlobNotFoundDataType { - blobId: String! - spaceId: String! -} - -enum ChatHistoryOrder { - asc - desc -} - -type ChatMessage { - attachments: [String!] - content: String! - createdAt: DateTime! - id: ID - params: JSON - role: String! -} - -enum ContextCategories { - Collection - Tag -} - -enum ContextEmbedStatus { - failed - finished - processing -} - -type ContextMatchedDocChunk { - chunk: SafeInt! - content: String! - distance: Float - docId: String! -} - -type ContextMatchedFileChunk { - chunk: SafeInt! - content: String! - distance: Float - fileId: String! -} - -type ContextWorkspaceEmbeddingStatus { - embedded: SafeInt! - total: SafeInt! -} - -type Copilot { - audioTranscription(jobId: String): [TranscriptionResultType!]! - - """Get the context list of a session""" - contexts(contextId: String, sessionId: String): [CopilotContext!]! - histories(docId: String, options: QueryChatHistoriesInput): [CopilotHistories!]! - - """Get the quota of the user in the workspace""" - quota: CopilotQuota! - - """Get the session id list in the workspace""" - sessionIds(docId: String, options: QueryChatSessionsInput): [String!]! @deprecated(reason: "Use `sessions` instead") - - """Get the session list in the workspace""" - sessions(docId: String, options: QueryChatSessionsInput): [CopilotSessionType!]! - workspaceId: ID -} - -type CopilotContext { - """list collections in context""" - collections: [CopilotContextCategory!]! - - """list files in context""" - docs: [CopilotContextDoc!]! - - """list files in context""" - files: [CopilotContextFile!]! - id: ID! - - """match file in context""" - matchFiles(content: String!, limit: SafeInt, threshold: Float): [ContextMatchedFileChunk!]! - - """match workspace docs""" - matchWorkspaceDocs(content: String!, limit: SafeInt, threshold: Float): [ContextMatchedDocChunk!]! - - """list tags in context""" - tags: [CopilotContextCategory!]! - workspaceId: String! -} - -type CopilotContextCategory { - createdAt: SafeInt! - docs: [CopilotDocType!]! - id: ID! - type: ContextCategories! -} - -type CopilotContextDoc { - createdAt: SafeInt! - error: String - id: ID! - status: ContextEmbedStatus -} - -type CopilotContextFile { - blobId: String! - chunkSize: SafeInt! - createdAt: SafeInt! - error: String - id: ID! - name: String! - status: ContextEmbedStatus! -} - -type CopilotContextFileNotSupportedDataType { - fileName: String! - message: String! -} - -type CopilotDocNotFoundDataType { - docId: String! -} - -type CopilotDocType { - createdAt: SafeInt! - id: ID! - status: ContextEmbedStatus -} - -type CopilotFailedToMatchContextDataType { - content: String! - contextId: String! - message: String! -} - -type CopilotFailedToModifyContextDataType { - contextId: String! - message: String! -} - -type CopilotHistories { - """An mark identifying which view to use to display the session""" - action: String - createdAt: DateTime! - messages: [ChatMessage!]! - sessionId: String! - - """The number of tokens used in the session""" - tokens: Int! -} - -type CopilotInvalidContextDataType { - contextId: String! -} - -type CopilotMessageNotFoundDataType { - messageId: String! -} - -enum CopilotModels { - DallE3 - Gpt4Omni - Gpt4Omni0806 - Gpt4OmniMini - Gpt4OmniMini0718 - TextEmbedding3Large - TextEmbedding3Small - TextEmbeddingAda002 - TextModerationLatest - TextModerationStable -} - -input CopilotPromptConfigInput { - frequencyPenalty: Float - jsonMode: Boolean - presencePenalty: Float - temperature: Float - topP: Float -} - -type CopilotPromptConfigType { - frequencyPenalty: Float - jsonMode: Boolean - presencePenalty: Float - temperature: Float - topP: Float -} - -input CopilotPromptMessageInput { - content: String! - params: JSON - role: CopilotPromptMessageRole! -} - -enum CopilotPromptMessageRole { - assistant - system - user -} - -type CopilotPromptMessageType { - content: String! - params: JSON - role: CopilotPromptMessageRole! -} - -type CopilotPromptNotFoundDataType { - name: String! -} - -type CopilotPromptType { - action: String - config: CopilotPromptConfigType - messages: [CopilotPromptMessageType!]! - model: String! - name: String! -} - -type CopilotProviderSideErrorDataType { - kind: String! - message: String! - provider: String! -} - -type CopilotQuota { - limit: SafeInt - used: SafeInt! -} - -type CopilotSessionType { - id: ID! - parentSessionId: ID - promptName: String! -} - -input CreateChatMessageInput { - attachments: [String!] - blobs: [Upload!] - content: String - params: JSON - sessionId: String! -} - -input CreateChatSessionInput { - docId: String! - - """The prompt name to use for the session""" - promptName: String! - workspaceId: String! -} - -input CreateCheckoutSessionInput { - args: JSONObject - coupon: String - idempotencyKey: String - plan: SubscriptionPlan = Pro - recurring: SubscriptionRecurring = Yearly - successCallbackLink: String! - variant: SubscriptionVariant -} - -input CreateCopilotPromptInput { - action: String - config: CopilotPromptConfigInput - messages: [CopilotPromptMessageInput!]! - model: CopilotModels! - name: String! -} - -input CreateUserInput { - email: String! - name: String -} - -type CredentialsRequirementType { - password: PasswordLimitsType! -} - -""" -A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. -""" -scalar DateTime - -type DeleteAccount { - success: Boolean! -} - -input DeleteSessionInput { - docId: String! - sessionIds: [String!]! - workspaceId: String! -} - -type DocActionDeniedDataType { - action: String! - docId: String! - spaceId: String! -} - -type DocHistoryNotFoundDataType { - docId: String! - spaceId: String! - timestamp: Int! -} - -type DocHistoryType { - editor: EditorType - id: String! - timestamp: DateTime! - workspaceId: String! -} - -"""Doc mode""" -enum DocMode { - edgeless - page -} - -type DocNotFoundDataType { - docId: String! - spaceId: String! -} - -type DocPermissions { - Doc_Copy: Boolean! - Doc_Delete: Boolean! - Doc_Duplicate: Boolean! - Doc_Properties_Read: Boolean! - Doc_Properties_Update: Boolean! - Doc_Publish: Boolean! - Doc_Read: Boolean! - Doc_Restore: Boolean! - Doc_TransferOwner: Boolean! - Doc_Trash: Boolean! - Doc_Update: Boolean! - Doc_Users_Manage: Boolean! - Doc_Users_Read: Boolean! -} - -"""User permission in doc""" -enum DocRole { - Editor - External - Manager - None - Owner - Reader -} - -type DocType { - defaultRole: DocRole! - - """paginated doc granted users list""" - grantedUsersList(pagination: PaginationInput!): PaginatedGrantedDocUserType! - id: String! - mode: PublicDocMode! - permissions: DocPermissions! - public: Boolean! - workspaceId: String! -} - -type DocUpdateBlockedDataType { - docId: String! - spaceId: String! -} - -type EditorType { - avatarUrl: String - name: String! -} - -union ErrorDataUnion = AlreadyInSpaceDataType | BlobNotFoundDataType | CopilotContextFileNotSupportedDataType | CopilotDocNotFoundDataType | CopilotFailedToMatchContextDataType | CopilotFailedToModifyContextDataType | CopilotInvalidContextDataType | CopilotMessageNotFoundDataType | CopilotPromptNotFoundDataType | CopilotProviderSideErrorDataType | DocActionDeniedDataType | DocHistoryNotFoundDataType | DocNotFoundDataType | DocUpdateBlockedDataType | ExpectToGrantDocUserRolesDataType | ExpectToRevokeDocUserRolesDataType | ExpectToUpdateDocUserRoleDataType | GraphqlBadRequestDataType | HttpRequestErrorDataType | InvalidEmailDataType | InvalidHistoryTimestampDataType | InvalidLicenseUpdateParamsDataType | InvalidOauthCallbackCodeDataType | InvalidPasswordLengthDataType | InvalidRuntimeConfigTypeDataType | MemberNotFoundInSpaceDataType | MentionUserDocAccessDeniedDataType | MissingOauthQueryParameterDataType | NotInSpaceDataType | QueryTooLongDataType | RuntimeConfigNotFoundDataType | SameSubscriptionRecurringDataType | SpaceAccessDeniedDataType | SpaceNotFoundDataType | SpaceOwnerNotFoundDataType | SpaceShouldHaveOnlyOneOwnerDataType | SubscriptionAlreadyExistsDataType | SubscriptionNotExistsDataType | SubscriptionPlanNotFoundDataType | UnknownOauthProviderDataType | UnsupportedClientVersionDataType | UnsupportedSubscriptionPlanDataType | ValidationErrorDataType | VersionRejectedDataType | WorkspaceMembersExceedLimitToDowngradeDataType | WorkspacePermissionNotFoundDataType | WrongSignInCredentialsDataType - -enum ErrorNames { - ACCESS_DENIED - ACTION_FORBIDDEN - ACTION_FORBIDDEN_ON_NON_TEAM_WORKSPACE - ALREADY_IN_SPACE - AUTHENTICATION_REQUIRED - BAD_REQUEST - BLOB_NOT_FOUND - BLOB_QUOTA_EXCEEDED - CANNOT_DELETE_ALL_ADMIN_ACCOUNT - CANNOT_DELETE_OWN_ACCOUNT - CANT_UPDATE_ONETIME_PAYMENT_SUBSCRIPTION - CAN_NOT_BATCH_GRANT_DOC_OWNER_PERMISSIONS - CAN_NOT_REVOKE_YOURSELF - CAPTCHA_VERIFICATION_FAILED - COPILOT_ACTION_TAKEN - COPILOT_CONTEXT_FILE_NOT_SUPPORTED - COPILOT_DOCS_NOT_FOUND - COPILOT_DOC_NOT_FOUND - COPILOT_EMBEDDING_UNAVAILABLE - COPILOT_FAILED_TO_CREATE_MESSAGE - COPILOT_FAILED_TO_GENERATE_TEXT - COPILOT_FAILED_TO_MATCH_CONTEXT - COPILOT_FAILED_TO_MODIFY_CONTEXT - COPILOT_INVALID_CONTEXT - COPILOT_MESSAGE_NOT_FOUND - COPILOT_PROMPT_INVALID - COPILOT_PROMPT_NOT_FOUND - COPILOT_PROVIDER_SIDE_ERROR - COPILOT_QUOTA_EXCEEDED - COPILOT_SESSION_DELETED - COPILOT_SESSION_NOT_FOUND - COPILOT_TRANSCRIPTION_JOB_EXISTS - CUSTOMER_PORTAL_CREATE_FAILED - DOC_ACTION_DENIED - DOC_DEFAULT_ROLE_CAN_NOT_BE_OWNER - DOC_HISTORY_NOT_FOUND - DOC_IS_NOT_PUBLIC - DOC_NOT_FOUND - DOC_UPDATE_BLOCKED - EARLY_ACCESS_REQUIRED - EMAIL_ALREADY_USED - EMAIL_TOKEN_NOT_FOUND - EMAIL_VERIFICATION_REQUIRED - EXPECT_TO_GRANT_DOC_USER_ROLES - EXPECT_TO_PUBLISH_DOC - EXPECT_TO_REVOKE_DOC_USER_ROLES - EXPECT_TO_REVOKE_PUBLIC_DOC - EXPECT_TO_UPDATE_DOC_USER_ROLE - FAILED_TO_CHECKOUT - FAILED_TO_SAVE_UPDATES - FAILED_TO_UPSERT_SNAPSHOT - GRAPHQL_BAD_REQUEST - HTTP_REQUEST_ERROR - INTERNAL_SERVER_ERROR - INVALID_APP_CONFIG - INVALID_AUTH_STATE - INVALID_CHECKOUT_PARAMETERS - INVALID_EMAIL - INVALID_EMAIL_TOKEN - INVALID_HISTORY_TIMESTAMP - INVALID_LICENSE_SESSION_ID - INVALID_LICENSE_TO_ACTIVATE - INVALID_LICENSE_UPDATE_PARAMS - INVALID_OAUTH_CALLBACK_CODE - INVALID_OAUTH_CALLBACK_STATE - INVALID_PASSWORD_LENGTH - INVALID_RUNTIME_CONFIG_TYPE - INVALID_SUBSCRIPTION_PARAMETERS - LICENSE_NOT_FOUND - LICENSE_REVEALED - LINK_EXPIRED - MAILER_SERVICE_IS_NOT_CONFIGURED - MEMBER_NOT_FOUND_IN_SPACE - MEMBER_QUOTA_EXCEEDED - MENTION_USER_DOC_ACCESS_DENIED - MENTION_USER_ONESELF_DENIED - MISSING_OAUTH_QUERY_PARAMETER - NETWORK_ERROR - NOTIFICATION_NOT_FOUND - NOT_FOUND - NOT_IN_SPACE - NO_COPILOT_PROVIDER_AVAILABLE - OAUTH_ACCOUNT_ALREADY_CONNECTED - OAUTH_STATE_EXPIRED - OWNER_CAN_NOT_LEAVE_WORKSPACE - PASSWORD_REQUIRED - QUERY_TOO_LONG - RUNTIME_CONFIG_NOT_FOUND - SAME_EMAIL_PROVIDED - SAME_SUBSCRIPTION_RECURRING - SIGN_UP_FORBIDDEN - SPACE_ACCESS_DENIED - SPACE_NOT_FOUND - SPACE_OWNER_NOT_FOUND - SPACE_SHOULD_HAVE_ONLY_ONE_OWNER - STORAGE_QUOTA_EXCEEDED - SUBSCRIPTION_ALREADY_EXISTS - SUBSCRIPTION_EXPIRED - SUBSCRIPTION_HAS_BEEN_CANCELED - SUBSCRIPTION_HAS_NOT_BEEN_CANCELED - SUBSCRIPTION_NOT_EXISTS - SUBSCRIPTION_PLAN_NOT_FOUND - TOO_MANY_REQUEST - UNKNOWN_OAUTH_PROVIDER - UNSPLASH_IS_NOT_CONFIGURED - UNSUPPORTED_CLIENT_VERSION - UNSUPPORTED_SUBSCRIPTION_PLAN - USER_AVATAR_NOT_FOUND - USER_NOT_FOUND - VALIDATION_ERROR - VERSION_REJECTED - WORKSPACE_ID_REQUIRED_FOR_TEAM_SUBSCRIPTION - WORKSPACE_ID_REQUIRED_TO_UPDATE_TEAM_SUBSCRIPTION - WORKSPACE_LICENSE_ALREADY_EXISTS - WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE - WORKSPACE_PERMISSION_NOT_FOUND - WRONG_SIGN_IN_CREDENTIALS - WRONG_SIGN_IN_METHOD -} - -type ExpectToGrantDocUserRolesDataType { - docId: String! - spaceId: String! -} - -type ExpectToRevokeDocUserRolesDataType { - docId: String! - spaceId: String! -} - -type ExpectToUpdateDocUserRoleDataType { - docId: String! - spaceId: String! -} - -enum FeatureType { - AIEarlyAccess - Admin - EarlyAccess - FreePlan - LifetimeProPlan - ProPlan - TeamPlan - UnlimitedCopilot - UnlimitedWorkspace -} - -input ForkChatSessionInput { - docId: String! - - """ - Identify a message in the array and keep it with all previous messages into a forked session. - """ - latestMessageId: String! - sessionId: String! - workspaceId: String! -} - -input GrantDocUserRolesInput { - docId: String! - role: DocRole! - userIds: [String!]! - workspaceId: String! -} - -type GrantedDocUserType { - role: DocRole! - user: WorkspaceUserType! -} - -type GrantedDocUserTypeEdge { - cursor: String! - node: GrantedDocUserType! -} - -type GraphqlBadRequestDataType { - code: String! - message: String! -} - -type HttpRequestErrorDataType { - message: String! -} - -input ImportUsersInput { - users: [CreateUserInput!]! -} - -type InvalidEmailDataType { - email: String! -} - -type InvalidHistoryTimestampDataType { - timestamp: String! -} - -type InvalidLicenseUpdateParamsDataType { - reason: String! -} - -type InvalidOauthCallbackCodeDataType { - body: String! - status: Int! -} - -type InvalidPasswordLengthDataType { - max: Int! - min: Int! -} - -type InvalidRuntimeConfigTypeDataType { - get: String! - key: String! - want: String! -} - -type InvitationAcceptedNotificationBodyType { - """ - The user who created the notification, maybe null when user is deleted or sent by system - """ - createdByUser: PublicUserType - inviteId: ID! - - """The type of the notification""" - type: NotificationType! - workspace: NotificationWorkspaceType -} - -type InvitationBlockedNotificationBodyType { - """ - The user who created the notification, maybe null when user is deleted or sent by system - """ - createdByUser: PublicUserType - inviteId: ID! - - """The type of the notification""" - type: NotificationType! - workspace: NotificationWorkspaceType -} - -type InvitationNotificationBodyType { - """ - The user who created the notification, maybe null when user is deleted or sent by system - """ - createdByUser: PublicUserType - inviteId: ID! - - """The type of the notification""" - type: NotificationType! - workspace: NotificationWorkspaceType -} - -type InvitationReviewApprovedNotificationBodyType { - """ - The user who created the notification, maybe null when user is deleted or sent by system - """ - createdByUser: PublicUserType - inviteId: ID! - - """The type of the notification""" - type: NotificationType! - workspace: NotificationWorkspaceType -} - -type InvitationReviewDeclinedNotificationBodyType { - """ - The user who created the notification, maybe null when user is deleted or sent by system - """ - createdByUser: PublicUserType - - """The type of the notification""" - type: NotificationType! - workspace: NotificationWorkspaceType -} - -type InvitationReviewRequestNotificationBodyType { - """ - The user who created the notification, maybe null when user is deleted or sent by system - """ - createdByUser: PublicUserType - inviteId: ID! - - """The type of the notification""" - type: NotificationType! - workspace: NotificationWorkspaceType -} - -type InvitationType { - """Invitee information""" - invitee: WorkspaceUserType! - - """Invitation status in workspace""" - status: WorkspaceMemberStatus - - """User information""" - user: WorkspaceUserType! - - """Workspace information""" - workspace: InvitationWorkspaceType! -} - -type InvitationWorkspaceType { - """Base64 encoded avatar""" - avatar: String! - id: ID! - - """Workspace name""" - name: String! -} - -type InviteLink { - """Invite link expire time""" - expireTime: DateTime! - - """Invite link""" - link: String! -} - -type InviteResult { - email: String! - - """Invite id, null if invite record create failed""" - inviteId: String - - """Invite email sent success""" - sentSuccess: Boolean! -} - -type InviteUserType { - """User accepted""" - accepted: Boolean! @deprecated(reason: "Use `status` instead") - - """User avatar url""" - avatarUrl: String - - """User email verified""" - createdAt: DateTime @deprecated(reason: "useless") - - """User is disabled""" - disabled: Boolean - - """User email""" - email: String - - """User email verified""" - emailVerified: Boolean - - """User password has been set""" - hasPassword: Boolean - id: ID! - - """Invite id""" - inviteId: String! - - """User name""" - name: String - - """User permission in workspace""" - permission: Permission! @deprecated(reason: "Use role instead") - - """User role in workspace""" - role: Permission! - - """Member invite status in workspace""" - status: WorkspaceMemberStatus! -} - -enum InvoiceStatus { - Draft - Open - Paid - Uncollectible - Void -} - -type InvoiceType { - amount: Int! - createdAt: DateTime! - currency: String! - id: String @deprecated(reason: "removed") - lastPaymentError: String - link: String - plan: SubscriptionPlan @deprecated(reason: "removed") - reason: String! - recurring: SubscriptionRecurring @deprecated(reason: "removed") - status: InvoiceStatus! - updatedAt: DateTime! -} - -""" -The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). -""" -scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") - -""" -The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). -""" -scalar JSONObject @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") - -type License { - expiredAt: DateTime - installedAt: DateTime! - quantity: Int! - recurring: SubscriptionRecurring! - validatedAt: DateTime! -} - -type LimitedUserType { - """User email""" - email: String! - - """User password has been set""" - hasPassword: Boolean -} - -input ListUserInput { - first: Int = 20 - skip: Int = 0 -} - -type ListedBlob { - createdAt: String! - key: String! - mime: String! - size: Int! -} - -input ManageUserInput { - """User email""" - email: String - - """User name""" - name: String -} - -type MemberNotFoundInSpaceDataType { - spaceId: String! -} - -input MentionDocInput { - """The block id in the doc""" - blockId: String - - """The element id in the doc""" - elementId: String - id: String! - mode: DocMode! - title: String! -} - -type MentionDocType { - blockId: String - elementId: String - id: String! - mode: DocMode! - title: String! -} - -input MentionInput { - doc: MentionDocInput! - userId: String! - workspaceId: String! -} - -type MentionNotificationBodyType { - """ - The user who created the notification, maybe null when user is deleted or sent by system - """ - createdByUser: PublicUserType - doc: MentionDocType! - - """The type of the notification""" - type: NotificationType! - workspace: NotificationWorkspaceType -} - -type MentionUserDocAccessDeniedDataType { - docId: String! -} - -type MissingOauthQueryParameterDataType { - name: String! -} - -type Mutation { - acceptInviteById(inviteId: String!, sendAcceptMail: Boolean @deprecated(reason: "never used"), workspaceId: String!): Boolean! - activateLicense(license: String!, workspaceId: String!): License! - - """add a category to context""" - addContextCategory(options: AddContextCategoryInput!): CopilotContextCategory! - - """add a doc to context""" - addContextDoc(options: AddContextDocInput!): CopilotContextDoc! - - """add a file to context""" - addContextFile(content: Upload!, options: AddContextFileInput!): CopilotContextFile! - addWorkspaceFeature(feature: FeatureType!, workspaceId: String!): Boolean! - approveMember(userId: String!, workspaceId: String!): Boolean! - - """Ban an user""" - banUser(id: String!): UserType! - cancelSubscription(idempotencyKey: String @deprecated(reason: "use header `Idempotency-Key`"), plan: SubscriptionPlan = Pro, workspaceId: String): SubscriptionType! - changeEmail(email: String!, token: String!): UserType! - changePassword(newPassword: String!, token: String!, userId: String): Boolean! - claimAudioTranscription(jobId: String!): TranscriptionResultType - - """Cleanup sessions""" - cleanupCopilotSession(options: DeleteSessionInput!): [String!]! - - """Create change password url""" - createChangePasswordUrl(callbackUrl: String!, userId: String!): String! - - """Create a subscription checkout link of stripe""" - createCheckoutSession(input: CreateCheckoutSessionInput!): String! - - """Create a context session""" - createCopilotContext(sessionId: String!, workspaceId: String!): String! - - """Create a chat message""" - createCopilotMessage(options: CreateChatMessageInput!): String! - - """Create a copilot prompt""" - createCopilotPrompt(input: CreateCopilotPromptInput!): CopilotPromptType! - - """Create a chat session""" - createCopilotSession(options: CreateChatSessionInput!): String! - - """Create a stripe customer portal to manage payment methods""" - createCustomerPortal: String! - createInviteLink(expireTime: WorkspaceInviteLinkExpireTime!, workspaceId: String!): InviteLink! - createSelfhostWorkspaceCustomerPortal(workspaceId: String!): String! - - """Create a new user""" - createUser(input: CreateUserInput!): UserType! - - """Create a new workspace""" - createWorkspace(init: Upload): WorkspaceType! - deactivateLicense(workspaceId: String!): Boolean! - deleteAccount: DeleteAccount! - deleteBlob(hash: String @deprecated(reason: "use parameter [key]"), key: String, permanently: Boolean! = false, workspaceId: String!): Boolean! - - """Delete a user account""" - deleteUser(id: String!): DeleteAccount! - deleteWorkspace(id: String!): Boolean! - - """Reenable an banned user""" - enableUser(id: String!): UserType! - - """Create a chat session""" - forkCopilotSession(options: ForkChatSessionInput!): String! - generateLicenseKey(sessionId: String!): String! - grantDocUserRoles(input: GrantDocUserRolesInput!): Boolean! - grantMember(permission: Permission!, userId: String!, workspaceId: String!): Boolean! - - """import users""" - importUsers(input: ImportUsersInput!): [UserImportResultType!]! - invite(email: String!, permission: Permission @deprecated(reason: "never used"), sendInviteMail: Boolean @deprecated(reason: "never used"), workspaceId: String!): String! - inviteBatch(emails: [String!]!, sendInviteMail: Boolean @deprecated(reason: "never used"), workspaceId: String!): [InviteResult!]! - leaveWorkspace(sendLeaveMail: Boolean, workspaceId: String!, workspaceName: String @deprecated(reason: "no longer used")): Boolean! - - """mention user in a doc""" - mentionUser(input: MentionInput!): ID! - publishDoc(docId: String!, mode: PublicDocMode = Page, workspaceId: String!): DocType! - publishPage(mode: PublicDocMode = Page, pageId: String!, workspaceId: String!): DocType! @deprecated(reason: "use publishDoc instead") - - """queue workspace doc embedding""" - queueWorkspaceEmbedding(docId: [String!]!, workspaceId: String!): Boolean! - - """mark notification as read""" - readNotification(id: String!): Boolean! - recoverDoc(guid: String!, timestamp: DateTime!, workspaceId: String!): DateTime! - releaseDeletedBlobs(workspaceId: String!): Boolean! - - """Remove user avatar""" - removeAvatar: RemoveAvatar! - - """remove a category from context""" - removeContextCategory(options: RemoveContextCategoryInput!): Boolean! - - """remove a doc from context""" - removeContextDoc(options: RemoveContextDocInput!): Boolean! - - """remove a file from context""" - removeContextFile(options: RemoveContextFileInput!): Boolean! - removeWorkspaceFeature(feature: FeatureType!, workspaceId: String!): Boolean! - resumeSubscription(idempotencyKey: String @deprecated(reason: "use header `Idempotency-Key`"), plan: SubscriptionPlan = Pro, workspaceId: String): SubscriptionType! - revoke(userId: String!, workspaceId: String!): Boolean! - revokeDocUserRoles(input: RevokeDocUserRoleInput!): Boolean! - revokeInviteLink(workspaceId: String!): Boolean! - revokePublicDoc(docId: String!, workspaceId: String!): DocType! - revokePublicPage(docId: String!, workspaceId: String!): DocType! @deprecated(reason: "use revokePublicDoc instead") - sendChangeEmail(callbackUrl: String!, email: String): Boolean! - sendChangePasswordEmail(callbackUrl: String!, email: String @deprecated(reason: "fetched from signed in user")): Boolean! - sendSetPasswordEmail(callbackUrl: String!, email: String @deprecated(reason: "fetched from signed in user")): Boolean! - sendVerifyChangeEmail(callbackUrl: String!, email: String!, token: String!): Boolean! - sendVerifyEmail(callbackUrl: String!): Boolean! - setBlob(blob: Upload!, workspaceId: String!): String! - submitAudioTranscription(blob: Upload!, blobId: String!, workspaceId: String!): TranscriptionResultType - - """update app configuration""" - updateAppConfig(updates: [UpdateAppConfigInput!]!): JSONObject! - - """Update a copilot prompt""" - updateCopilotPrompt(messages: [CopilotPromptMessageInput!]!, name: String!): CopilotPromptType! - - """Update a chat session""" - updateCopilotSession(options: UpdateChatSessionInput!): String! - updateDocDefaultRole(input: UpdateDocDefaultRoleInput!): Boolean! - updateDocUserRole(input: UpdateDocUserRoleInput!): Boolean! - updateProfile(input: UpdateUserInput!): UserType! - - """Update user settings""" - updateSettings(input: UpdateUserSettingsInput!): Boolean! - updateSubscriptionRecurring(idempotencyKey: String @deprecated(reason: "use header `Idempotency-Key`"), plan: SubscriptionPlan = Pro, recurring: SubscriptionRecurring!, workspaceId: String): SubscriptionType! - - """Update an user""" - updateUser(id: String!, input: ManageUserInput!): UserType! - - """update user enabled feature""" - updateUserFeatures(features: [FeatureType!]!, id: String!): [FeatureType!]! - - """Update workspace""" - updateWorkspace(input: UpdateWorkspaceInput!): WorkspaceType! - - """Upload user avatar""" - uploadAvatar(avatar: Upload!): UserType! - verifyEmail(token: String!): Boolean! -} - -type NotInSpaceDataType { - spaceId: String! -} - -"""Notification level""" -enum NotificationLevel { - Default - High - Low - Min - None -} - -type NotificationObjectType { - """Just a placeholder to export UnionNotificationBodyType, don't use it""" - _placeholderForUnionNotificationBodyType: UnionNotificationBodyType! - - """ - The body of the notification, different types have different fields, see UnionNotificationBodyType - """ - body: JSONObject! - - """The created at time of the notification""" - createdAt: DateTime! - id: ID! - - """The level of the notification""" - level: NotificationLevel! - - """Whether the notification has been read""" - read: Boolean! - - """The type of the notification""" - type: NotificationType! - - """The updated at time of the notification""" - updatedAt: DateTime! -} - -type NotificationObjectTypeEdge { - cursor: String! - node: NotificationObjectType! -} - -"""Notification type""" -enum NotificationType { - Invitation - InvitationAccepted - InvitationBlocked - InvitationRejected - InvitationReviewApproved - InvitationReviewDeclined - InvitationReviewRequest - Mention -} - -type NotificationWorkspaceType { - """Workspace avatar url""" - avatarUrl: String - id: ID! - - """Workspace name""" - name: String! -} - -enum OAuthProviderType { - GitHub - Google - OIDC -} - -type PageInfo { - endCursor: String - hasNextPage: Boolean! - hasPreviousPage: Boolean! - startCursor: String -} - -type PaginatedGrantedDocUserType { - edges: [GrantedDocUserTypeEdge!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type PaginatedNotificationObjectType { - edges: [NotificationObjectTypeEdge!]! - pageInfo: PageInfo! - totalCount: Int! -} - -input PaginationInput { - """returns the elements in the list that come after the specified cursor.""" - after: String - - """returns the first n elements from the list.""" - first: Int = 10 - - """ignore the first n elements from the list.""" - offset: Int = 0 -} - -type PasswordLimitsType { - maxLength: Int! - minLength: Int! -} - -"""User permission in workspace""" -enum Permission { - Admin - Collaborator - External - Owner -} - -"""The mode which the public doc default in""" -enum PublicDocMode { - Edgeless - Page -} - -type PublicUserType { - avatarUrl: String - id: String! - name: String! -} - -type Query { - """get the whole app configuration""" - appConfig: JSONObject! - collectAllBlobSizes: WorkspaceBlobSizes! @deprecated(reason: "use `user.quotaUsage` instead") - - """Get current user""" - currentUser: UserType - error(name: ErrorNames!): ErrorDataUnion! - - """send workspace invitation""" - getInviteInfo(inviteId: String!): InvitationType! - - """Get is admin of workspace""" - isAdmin(workspaceId: String!): Boolean! @deprecated(reason: "use WorkspaceType[role] instead") - - """Get is owner of workspace""" - isOwner(workspaceId: String!): Boolean! @deprecated(reason: "use WorkspaceType[role] instead") - - """List all copilot prompts""" - listCopilotPrompts: [CopilotPromptType!]! - prices: [SubscriptionPrice!]! - - """Get public user by id""" - publicUserById(id: String!): PublicUserType - - """query workspace embedding status""" - queryWorkspaceEmbeddingStatus(workspaceId: String!): ContextWorkspaceEmbeddingStatus! - - """server config""" - serverConfig: ServerConfigType! - - """Get user by email""" - user(email: String!): UserOrLimitedUser - - """Get user by email for admin""" - userByEmail(email: String!): UserType - - """Get user by id""" - userById(id: String!): UserType! - - """List registered users""" - users(filter: ListUserInput!): [UserType!]! - - """Get users count""" - usersCount: Int! - - """Get workspace by id""" - workspace(id: String!): WorkspaceType! - - """Get workspace role permissions""" - workspaceRolePermissions(id: String!): WorkspaceRolePermissions! @deprecated(reason: "use WorkspaceType[permissions] instead") - - """Get all accessible workspaces for current user""" - workspaces: [WorkspaceType!]! -} - -input QueryChatHistoriesInput { - action: Boolean - fork: Boolean - limit: Int - messageOrder: ChatHistoryOrder - sessionId: String - sessionOrder: ChatHistoryOrder - skip: Int - withPrompt: Boolean -} - -input QueryChatSessionsInput { - action: Boolean -} - -type QueryTooLongDataType { - max: Int! -} - -type ReleaseVersionType { - changelog: String! - publishedAt: DateTime! - url: String! - version: String! -} - -type RemoveAvatar { - success: Boolean! -} - -input RemoveContextCategoryInput { - categoryId: String! - contextId: String! - type: ContextCategories! -} - -input RemoveContextDocInput { - contextId: String! - docId: String! -} - -input RemoveContextFileInput { - contextId: String! - fileId: String! -} - -input RevokeDocUserRoleInput { - docId: String! - userId: String! - workspaceId: String! -} - -type RuntimeConfigNotFoundDataType { - key: String! -} - -""" -The `SafeInt` scalar type represents non-fractional signed whole numeric values that are considered safe as defined by the ECMAScript specification. -""" -scalar SafeInt @specifiedBy(url: "https://www.ecma-international.org/ecma-262/#sec-number.issafeinteger") - -type SameSubscriptionRecurringDataType { - recurring: String! -} - -type ServerConfigType { - """fetch latest available upgradable release of server""" - availableUpgrade: ReleaseVersionType - - """Features for user that can be configured""" - availableUserFeatures: [FeatureType!]! - - """server base url""" - baseUrl: String! - - """credentials requirement""" - credentialsRequirement: CredentialsRequirementType! - - """enabled server features""" - features: [ServerFeature!]! - - """whether server has been initialized""" - initialized: Boolean! - - """server identical name could be shown as badge on user interface""" - name: String! - oauthProviders: [OAuthProviderType!]! - - """server type""" - type: ServerDeploymentType! - - """server version""" - version: String! -} - -enum ServerDeploymentType { - Affine - Selfhosted -} - -enum ServerFeature { - Captcha - Copilot - OAuth - Payment -} - -type SpaceAccessDeniedDataType { - spaceId: String! -} - -type SpaceNotFoundDataType { - spaceId: String! -} - -type SpaceOwnerNotFoundDataType { - spaceId: String! -} - -type SpaceShouldHaveOnlyOneOwnerDataType { - spaceId: String! -} - -type SubscriptionAlreadyExistsDataType { - plan: String! -} - -type SubscriptionNotExistsDataType { - plan: String! -} - -enum SubscriptionPlan { - AI - Enterprise - Free - Pro - SelfHosted - SelfHostedTeam - Team -} - -type SubscriptionPlanNotFoundDataType { - plan: String! - recurring: String! -} - -type SubscriptionPrice { - amount: Int - currency: String! - lifetimeAmount: Int - plan: SubscriptionPlan! - type: String! - yearlyAmount: Int -} - -enum SubscriptionRecurring { - Lifetime - Monthly - Yearly -} - -enum SubscriptionStatus { - Active - Canceled - Incomplete - IncompleteExpired - PastDue - Paused - Trialing - Unpaid -} - -type SubscriptionType { - canceledAt: DateTime - createdAt: DateTime! - end: DateTime - id: String @deprecated(reason: "removed") - nextBillAt: DateTime - - """ - The 'Free' plan just exists to be a placeholder and for the type convenience of frontend. - There won't actually be a subscription with plan 'Free' - """ - plan: SubscriptionPlan! - recurring: SubscriptionRecurring! - start: DateTime! - status: SubscriptionStatus! - trialEnd: DateTime - trialStart: DateTime - updatedAt: DateTime! - variant: SubscriptionVariant -} - -enum SubscriptionVariant { - EA - Onetime -} - -type TranscriptionItemType { - end: String! - speaker: String! - start: String! - transcription: String! -} - -type TranscriptionResultType { - id: ID! - status: AiJobStatus! - summary: String - transcription: [TranscriptionItemType!] -} - -union UnionNotificationBodyType = InvitationAcceptedNotificationBodyType | InvitationBlockedNotificationBodyType | InvitationNotificationBodyType | InvitationReviewApprovedNotificationBodyType | InvitationReviewDeclinedNotificationBodyType | InvitationReviewRequestNotificationBodyType | MentionNotificationBodyType - -type UnknownOauthProviderDataType { - name: String! -} - -type UnsupportedClientVersionDataType { - clientVersion: String! - requiredVersion: String! -} - -type UnsupportedSubscriptionPlanDataType { - plan: String! -} - -input UpdateAppConfigInput { - key: String! - module: String! - value: JSON! -} - -input UpdateChatSessionInput { - """The prompt name to use for the session""" - promptName: String! - sessionId: String! -} - -input UpdateDocDefaultRoleInput { - docId: String! - role: DocRole! - workspaceId: String! -} - -input UpdateDocUserRoleInput { - docId: String! - role: DocRole! - userId: String! - workspaceId: String! -} - -input UpdateUserInput { - """User name""" - name: String -} - -input UpdateUserSettingsInput { - """Receive invitation email""" - receiveInvitationEmail: Boolean - - """Receive mention email""" - receiveMentionEmail: Boolean -} - -input UpdateWorkspaceInput { - """Enable AI""" - enableAi: Boolean - - """Enable url previous when sharing""" - enableUrlPreview: Boolean - id: ID! - - """is Public workspace""" - public: Boolean -} - -"""The `Upload` scalar type represents a file upload.""" -scalar Upload - -type UserImportFailedType { - email: String! - error: String! -} - -union UserImportResultType = UserImportFailedType | UserType - -union UserOrLimitedUser = LimitedUserType | UserType - -type UserQuotaHumanReadableType { - blobLimit: String! - copilotActionLimit: String! - historyPeriod: String! - memberLimit: String! - name: String! - storageQuota: String! - usedStorageQuota: String! -} - -type UserQuotaType { - blobLimit: SafeInt! - copilotActionLimit: Int - historyPeriod: SafeInt! - humanReadable: UserQuotaHumanReadableType! - memberLimit: Int! - name: String! - storageQuota: SafeInt! - usedStorageQuota: SafeInt! -} - -type UserQuotaUsageType { - storageQuota: SafeInt! @deprecated(reason: "use `UserQuotaType['usedStorageQuota']` instead") -} - -type UserSettingsType { - """Receive invitation email""" - receiveInvitationEmail: Boolean! - - """Receive mention email""" - receiveMentionEmail: Boolean! -} - -type UserType { - """User avatar url""" - avatarUrl: String - copilot(workspaceId: String): Copilot! - - """User email verified""" - createdAt: DateTime @deprecated(reason: "useless") - - """User is disabled""" - disabled: Boolean! - - """User email""" - email: String! - - """User email verified""" - emailVerified: Boolean! - - """Enabled features of a user""" - features: [FeatureType!]! - - """User password has been set""" - hasPassword: Boolean - id: ID! - - """Get user invoice count""" - invoiceCount: Int! - invoices(skip: Int, take: Int = 8): [InvoiceType!]! - - """User name""" - name: String! - - """Get user notification count""" - notificationCount: Int! - - """Get current user notifications""" - notifications(pagination: PaginationInput!): PaginatedNotificationObjectType! - quota: UserQuotaType! - quotaUsage: UserQuotaUsageType! - - """Get user settings""" - settings: UserSettingsType! - subscriptions: [SubscriptionType!]! - token: tokenType! @deprecated(reason: "use [/api/auth/sign-in?native=true] instead") -} - -type ValidationErrorDataType { - errors: String! -} - -type VersionRejectedDataType { - serverVersion: String! - version: String! -} - -type WorkspaceBlobSizes { - size: SafeInt! -} - -"""Workspace invite link expire time""" -enum WorkspaceInviteLinkExpireTime { - OneDay - OneMonth - OneWeek - ThreeDays -} - -"""Member invite status in workspace""" -enum WorkspaceMemberStatus { - Accepted - NeedMoreSeat - NeedMoreSeatAndReview - Pending - UnderReview -} - -type WorkspaceMembersExceedLimitToDowngradeDataType { - limit: Int! -} - -type WorkspacePageMeta { - createdAt: DateTime! - createdBy: EditorType - updatedAt: DateTime! - updatedBy: EditorType -} - -type WorkspacePermissionNotFoundDataType { - spaceId: String! -} - -type WorkspacePermissions { - Workspace_Administrators_Manage: Boolean! - Workspace_Blobs_List: Boolean! - Workspace_Blobs_Read: Boolean! - Workspace_Blobs_Write: Boolean! - Workspace_Copilot: Boolean! - Workspace_CreateDoc: Boolean! - Workspace_Delete: Boolean! - Workspace_Organize_Read: Boolean! - Workspace_Payment_Manage: Boolean! - Workspace_Properties_Create: Boolean! - Workspace_Properties_Delete: Boolean! - Workspace_Properties_Read: Boolean! - Workspace_Properties_Update: Boolean! - Workspace_Read: Boolean! - Workspace_Settings_Read: Boolean! - Workspace_Settings_Update: Boolean! - Workspace_Sync: Boolean! - Workspace_TransferOwner: Boolean! - Workspace_Users_Manage: Boolean! - Workspace_Users_Read: Boolean! -} - -type WorkspaceQuotaHumanReadableType { - blobLimit: String! - historyPeriod: String! - memberCount: String! - memberLimit: String! - name: String! - storageQuota: String! - storageQuotaUsed: String! -} - -type WorkspaceQuotaType { - blobLimit: SafeInt! - historyPeriod: SafeInt! - humanReadable: WorkspaceQuotaHumanReadableType! - memberCount: Int! - memberLimit: Int! - name: String! - storageQuota: SafeInt! - usedSize: SafeInt! @deprecated(reason: "use `usedStorageQuota` instead") - usedStorageQuota: SafeInt! -} - -type WorkspaceRolePermissions { - permissions: WorkspacePermissions! - role: Permission! -} - -type WorkspaceType { - """List blobs of workspace""" - blobs: [ListedBlob!]! - - """Blobs size of workspace""" - blobsSize: Int! - - """Workspace created date""" - createdAt: DateTime! - - """Get get with given id""" - doc(docId: String!): DocType! - - """Enable AI""" - enableAi: Boolean! - - """Enable url previous when sharing""" - enableUrlPreview: Boolean! - histories(before: DateTime, guid: String!, take: Int): [DocHistoryType!]! - id: ID! - - """is current workspace initialized""" - initialized: Boolean! - - """invite link for workspace""" - inviteLink: InviteLink - - """Get user invoice count""" - invoiceCount: Int! - invoices(skip: Int, take: Int = 8): [InvoiceType!]! - - """The selfhost license of the workspace""" - license: License - - """member count of workspace""" - memberCount: Int! - - """Members of workspace""" - members(query: String, skip: Int, take: Int): [InviteUserType!]! - - """Owner of workspace""" - owner: UserType! - - """Cloud page metadata of workspace""" - pageMeta(pageId: String!): WorkspacePageMeta! - - """map of action permissions""" - permissions: WorkspacePermissions! - - """is Public workspace""" - public: Boolean! - - """Get public docs of a workspace""" - publicDocs: [DocType!]! - - """Get public page of a workspace by page id.""" - publicPage(pageId: String!): DocType @deprecated(reason: "use [WorkspaceType.doc] instead") - publicPages: [DocType!]! @deprecated(reason: "use [WorkspaceType.publicDocs] instead") - - """quota of workspace""" - quota: WorkspaceQuotaType! - - """Role of current signed in user in workspace""" - role: Permission! - - """The team subscription of the workspace, if exists.""" - subscription: SubscriptionType - - """if workspace is team workspace""" - team: Boolean! -} - -type WorkspaceUserType { - avatarUrl: String - email: String! - id: String! - name: String! -} - -type WrongSignInCredentialsDataType { - email: String! -} - -type tokenType { - refresh: String! - sessionToken: String - token: String! -} \ No newline at end of file diff --git a/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md b/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md index 3c67be6eae..a3f684c57c 100644 --- a/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md +++ b/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md @@ -54,3 +54,37 @@ Generated by [AVA](https://avajs.dev). id: 'docId1', }, ] + +## should be able to transcript + +> should submit audio transcription job + + [ + { + status: 'running', + }, + ] + +> should claim audio transcription job + + [ + { + status: 'claimed', + summary: '[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]', + title: '[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]', + transcription: [ + { + end: '00:00:45', + speaker: 'A', + start: '00:00:30', + transcription: 'Hello, everyone.', + }, + { + end: '00:01:10', + speaker: 'B', + start: '00:00:46', + transcription: 'Hi, thank you for joining the meeting today.', + }, + ], + }, + ] diff --git a/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.snap b/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.snap index ae9951c74e..bfbd97bfeb 100644 Binary files a/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.snap and b/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.snap differ diff --git a/packages/backend/server/src/__tests__/copilot.e2e.ts b/packages/backend/server/src/__tests__/copilot.e2e.ts index 885c02173a..9a2030956d 100644 --- a/packages/backend/server/src/__tests__/copilot.e2e.ts +++ b/packages/backend/server/src/__tests__/copilot.e2e.ts @@ -19,6 +19,7 @@ import { MockEmbeddingClient } from '../plugins/copilot/context/embedding'; import { prompts, PromptService } from '../plugins/copilot/prompt'; import { CopilotProviderFactory, + GeminiProvider, OpenAIProvider, } from '../plugins/copilot/providers'; import { CopilotStorage } from '../plugins/copilot/storage'; @@ -35,10 +36,12 @@ import { addContextDoc, addContextFile, array2sse, + audioTranscription, chatWithImages, chatWithText, chatWithTextStream, chatWithWorkflow, + claimAudioTranscription, cleanObject, createCopilotContext, createCopilotMessage, @@ -50,6 +53,7 @@ import { matchFiles, matchWorkspaceDocs, sse2array, + submitAudioTranscription, textToEventStream, unsplashSearch, updateCopilotSession, @@ -96,6 +100,7 @@ test.before(async t => { }, }); m.overrideProvider(OpenAIProvider).useClass(MockCopilotProvider); + m.overrideProvider(GeminiProvider).useClass(MockCopilotProvider); }, }); @@ -868,3 +873,44 @@ test('should be able to manage context', async t => { t.is(result[0].docId, docId, 'should match doc id'); } }); + +test('should be able to transcript', async t => { + const { app } = t.context; + + const { id: workspaceId } = await createWorkspace(app); + + Sinon.stub(app.get(GeminiProvider), 'generateText').resolves( + '[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]' + ); + + const job = await submitAudioTranscription( + app, + workspaceId, + 'blobId', + 'test.mp3', + Buffer.from([1, 1]) + ); + t.snapshot( + cleanObject([job], ['id']), + 'should submit audio transcription job' + ); + t.truthy(job.id, 'should have job id'); + + // wait for processing + { + let { status } = (await audioTranscription(app, workspaceId, job.id)) || {}; + + while (status !== 'finished') { + await new Promise(resolve => setTimeout(resolve, 1000)); + ({ status } = (await audioTranscription(app, workspaceId, job.id)) || {}); + } + } + + { + const result = await claimAudioTranscription(app, job.id); + t.snapshot( + cleanObject([result], ['id']), + 'should claim audio transcription job' + ); + } +}); diff --git a/packages/backend/server/src/__tests__/copilot.spec.ts b/packages/backend/server/src/__tests__/copilot.spec.ts index e3e7e57b9d..31595ba811 100644 --- a/packages/backend/server/src/__tests__/copilot.spec.ts +++ b/packages/backend/server/src/__tests__/copilot.spec.ts @@ -27,6 +27,7 @@ import { import { CitationParser } from '../plugins/copilot/providers/perplexity'; import { ChatSessionService } from '../plugins/copilot/session'; import { CopilotStorage } from '../plugins/copilot/storage'; +import { CopilotTranscriptionService } from '../plugins/copilot/transcript'; import { CopilotChatTextExecutor, CopilotWorkflowService, @@ -57,6 +58,7 @@ const test = ava as TestFn<{ event: EventBus; context: CopilotContextService; prompt: PromptService; + transcript: CopilotTranscriptionService; factory: CopilotProviderFactory; session: ChatSessionService; jobs: CopilotContextDocJob; @@ -100,25 +102,30 @@ test.before(async t => { const auth = module.get(AuthService); const db = module.get(PrismaClient); const event = module.get(EventBus); - const context = module.get(CopilotContextService); const prompt = module.get(PromptService); const factory = module.get(CopilotProviderFactory); + const session = module.get(ChatSessionService); const workflow = module.get(CopilotWorkflowService); - const jobs = module.get(CopilotContextDocJob); const storage = module.get(CopilotStorage); + const context = module.get(CopilotContextService); + const jobs = module.get(CopilotContextDocJob); + const transcript = module.get(CopilotTranscriptionService); + t.context.module = module; t.context.auth = auth; t.context.db = db; t.context.event = event; - t.context.context = context; t.context.prompt = prompt; t.context.factory = factory; t.context.session = session; t.context.workflow = workflow; - t.context.jobs = jobs; t.context.storage = storage; + t.context.context = context; + t.context.jobs = jobs; + t.context.transcript = transcript; + t.context.executors = { image: module.get(CopilotChatImageExecutor), text: module.get(CopilotChatTextExecutor), diff --git a/packages/backend/server/src/__tests__/mocks/copilot.mock.ts b/packages/backend/server/src/__tests__/mocks/copilot.mock.ts index 751b03a97f..885029e99e 100644 --- a/packages/backend/server/src/__tests__/mocks/copilot.mock.ts +++ b/packages/backend/server/src/__tests__/mocks/copilot.mock.ts @@ -21,6 +21,7 @@ export class MockCopilotProvider extends OpenAIProvider { 'lcm-sd15-i2i', 'clarity-upscaler', 'imageutils/rembg', + 'gemini-2.5-pro-exp-03-25', ]; override readonly capabilities = [ diff --git a/packages/backend/server/src/__tests__/utils/copilot.ts b/packages/backend/server/src/__tests__/utils/copilot.ts index 46cfcfbaa8..0f2178ee0c 100644 --- a/packages/backend/server/src/__tests__/utils/copilot.ts +++ b/packages/backend/server/src/__tests__/utils/copilot.ts @@ -330,6 +330,149 @@ export async function listContextDocAndFiles( return { docs, files }; } +export async function submitAudioTranscription( + app: TestingApp, + workspaceId: string, + blobId: string, + fileName: string, + content: Buffer +): Promise<{ id: string; status: string }> { + const res = await app + .POST('/graphql') + .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) + .field( + 'operations', + JSON.stringify({ + query: ` + mutation submitAudioTranscription($blob: Upload!, $blobId: String!, $workspaceId: String!) { + submitAudioTranscription(blob: $blob, blobId: $blobId, workspaceId: $workspaceId) { + id + status + } + } + `, + variables: { + blob: null, + blobId, + workspaceId, + }, + }) + ) + .field('map', JSON.stringify({ '0': ['variables.blob'] })) + .attach('0', content, { + filename: fileName, + contentType: 'application/octet-stream', + }) + .expect(200); + + return res.body.data.submitAudioTranscription; +} + +export async function retryAudioTranscription( + app: TestingApp, + workspaceId: string, + jobId: string +): Promise<{ id: string; status: string }> { + const res = await app.gql( + ` + mutation retryAudioTranscription($workspaceId: String!, $jobId: String!) { + retryAudioTranscription(workspaceId: $workspaceId, jobId: $jobId) { + id + status + } + } + `, + { workspaceId, jobId } + ); + + return res.retryAudioTranscription; +} + +export async function claimAudioTranscription( + app: TestingApp, + jobId: string +): Promise<{ + id: string; + status: string; + title: string | null; + summary: string | null; + transcription: + | { + speaker: string; + start: number; + end: number; + transcription: string; + }[] + | null; +}> { + const res = await app.gql( + ` + mutation claimAudioTranscription($jobId: String!) { + claimAudioTranscription(jobId: $jobId) { + id + status + title + summary + transcription { + speaker + start + end + transcription + } + } + } + `, + { jobId } + ); + + return res.claimAudioTranscription; +} + +export async function audioTranscription( + app: TestingApp, + workspaceId: string, + jobId: string +): Promise<{ + id: string; + status: string; + title: string | null; + summary: string | null; + transcription: + | { + speaker: string; + start: number; + end: number; + transcription: string; + }[] + | null; +}> { + const res = await app.gql( + ` + query audioTranscription($workspaceId: String!, $jobId: String!) { + currentUser { + copilot(workspaceId: $workspaceId) { + audioTranscription(jobId: $jobId) { + id + status + title + summary + transcription { + speaker + start + end + transcription + } + } + } + } + } + `, + { workspaceId, jobId } + ); + + return res.currentUser?.copilot?.audioTranscription; +} + export async function createCopilotMessage( app: TestingApp, sessionId: string,