diff --git a/app/javascript/dashboard/api/captain/editor.js b/app/javascript/dashboard/api/captain/editor.js new file mode 100644 index 000000000..9071ab4d1 --- /dev/null +++ b/app/javascript/dashboard/api/captain/editor.js @@ -0,0 +1,113 @@ +/* global axios */ +import ApiClient from '../ApiClient'; + +/** + * A client for the Captain Editor API. + * @extends ApiClient + */ +class EditorAPI extends ApiClient { + /** + * Creates a new EditorAPI instance. + */ + constructor() { + super('captain/editor', { accountScoped: true }); + } + + /** + * Processes an event using the Captain Editor API. + * @param {Object} options - The options for the event. + * @param {string} [options.type='improve'] - The type of event to process. + * @param {string} [options.content] - The content of the event. + * @param {string} [options.conversationId] - The ID of the conversation to process the event for. + * @param {AbortSignal} [signal] - AbortSignal to cancel the request. + * @returns {Promise} A promise that resolves with the result of the event processing. + */ + processEvent({ type = 'improve', content, conversationId }, signal) { + // Route to appropriate endpoint based on type + if (type === 'summarize') { + return this.summarize(conversationId, signal); + } + + if (type === 'reply_suggestion') { + return this.replySuggestion(conversationId, signal); + } + + if (type === 'label_suggestion') { + return this.labelSuggestion(conversationId, signal); + } + + // All other types are rewrite operations + return this.rewrite({ content, operation: type, conversationId }, signal); + } + + /** + * Rewrites content with a specific operation. + * @param {Object} options - The rewrite options. + * @param {string} options.content - The content to rewrite. + * @param {string} options.operation - The rewrite operation (fix_spelling_grammar, casual, professional, etc). + * @param {string} [options.conversationId] - The conversation ID for context (required for 'improve'). + * @param {AbortSignal} [signal] - AbortSignal to cancel the request. + * @returns {Promise} A promise that resolves with the rewritten content. + */ + rewrite({ content, operation, conversationId }, signal) { + return axios.post( + `${this.url}/rewrite`, + { + content, + operation, + conversation_display_id: conversationId, + }, + { signal } + ); + } + + /** + * Summarizes a conversation. + * @param {string} conversationId - The conversation ID to summarize. + * @param {AbortSignal} [signal] - AbortSignal to cancel the request. + * @returns {Promise} A promise that resolves with the summary. + */ + summarize(conversationId, signal) { + return axios.post( + `${this.url}/summarize`, + { + conversation_display_id: conversationId, + }, + { signal } + ); + } + + /** + * Gets a reply suggestion for a conversation. + * @param {string} conversationId - The conversation ID. + * @param {AbortSignal} [signal] - AbortSignal to cancel the request. + * @returns {Promise} A promise that resolves with the reply suggestion. + */ + replySuggestion(conversationId, signal) { + return axios.post( + `${this.url}/reply_suggestion`, + { + conversation_display_id: conversationId, + }, + { signal } + ); + } + + /** + * Gets label suggestions for a conversation. + * @param {string} conversationId - The conversation ID. + * @param {AbortSignal} [signal] - AbortSignal to cancel the request. + * @returns {Promise} A promise that resolves with label suggestions. + */ + labelSuggestion(conversationId, signal) { + return axios.post( + `${this.url}/label_suggestion`, + { + conversation_display_id: conversationId, + }, + { signal } + ); + } +} + +export default new EditorAPI(); diff --git a/app/javascript/dashboard/api/integrations/openapi.js b/app/javascript/dashboard/api/integrations/openapi.js deleted file mode 100644 index 3fcf241ee..000000000 --- a/app/javascript/dashboard/api/integrations/openapi.js +++ /dev/null @@ -1,81 +0,0 @@ -/* global axios */ - -import ApiClient from '../ApiClient'; - -/** - * Represents the data object for a OpenAI hook. - * @typedef {Object} ConversationMessageData - * @property {string} [tone] - The tone of the message. - * @property {string} [content] - The content of the message. - * @property {string} [conversation_display_id] - The display ID of the conversation (optional). - */ - -/** - * A client for the OpenAI API. - * @extends ApiClient - */ -class OpenAIAPI extends ApiClient { - /** - * Creates a new OpenAIAPI instance. - */ - constructor() { - super('integrations', { accountScoped: true }); - - /** - * The conversation events supported by the API. - * @type {string[]} - */ - this.conversation_events = [ - 'summarize', - 'reply_suggestion', - 'label_suggestion', - ]; - - /** - * The message events supported by the API. - * @type {string[]} - */ - this.message_events = ['rephrase']; - } - - /** - * Processes an event using the OpenAI API. - * @param {Object} options - The options for the event. - * @param {string} [options.type='rephrase'] - The type of event to process. - * @param {string} [options.content] - The content of the event. - * @param {string} [options.tone] - The tone of the event. - * @param {string} [options.conversationId] - The ID of the conversation to process the event for. - * @param {string} options.hookId - The ID of the hook to use for processing the event. - * @returns {Promise} A promise that resolves with the result of the event processing. - */ - processEvent({ type = 'rephrase', content, tone, conversationId, hookId }) { - /** - * @type {ConversationMessageData} - */ - let data = { - tone, - content, - }; - - // Always include conversation_display_id when available for session tracking - if (conversationId) { - data.conversation_display_id = conversationId; - } - - // For conversation-level events, only send conversation_display_id - if (this.conversation_events.includes(type)) { - data = { - conversation_display_id: conversationId, - }; - } - - return axios.post(`${this.url}/hooks/${hookId}/process_event`, { - event: { - name: type, - data, - }, - }); - } -} - -export default new OpenAIAPI(); diff --git a/app/javascript/dashboard/assets/scss/_next-colors.scss b/app/javascript/dashboard/assets/scss/_next-colors.scss index f23c01d42..4d7975a32 100644 --- a/app/javascript/dashboard/assets/scss/_next-colors.scss +++ b/app/javascript/dashboard/assets/scss/_next-colors.scss @@ -94,6 +94,19 @@ --gray-11: 100 100 100; --gray-12: 32 32 32; + --violet-1: 253 252 254; + --violet-2: 250 248 255; + --violet-3: 244 240 254; + --violet-4: 235 228 255; + --violet-5: 225 217 255; + --violet-6: 212 202 254; + --violet-7: 194 178 248; + --violet-8: 169 153 236; + --violet-9: 110 86 207; + --violet-10: 100 84 196; + --violet-11: 101 85 183; + --violet-12: 47 38 95; + --background-color: 253 253 253; --text-blue: 8 109 224; --border-container: 236 236 236; @@ -209,6 +222,19 @@ --gray-11: 180 180 180; --gray-12: 238 238 238; + --violet-1: 20 17 31; + --violet-2: 27 21 37; + --violet-3: 41 31 67; + --violet-4: 50 37 85; + --violet-5: 60 46 105; + --violet-6: 71 56 135; + --violet-7: 86 70 151; + --violet-8: 110 86 171; + --violet-9: 110 86 207; + --violet-10: 125 109 217; + --violet-11: 169 153 236; + --violet-12: 226 221 254; + --background-color: 18 18 19; --border-strong: 52 52 52; --border-weak: 38 38 42; diff --git a/app/javascript/dashboard/components/widgets/AIAssistanceModal.vue b/app/javascript/dashboard/components/widgets/AIAssistanceModal.vue index 04bba8f59..3cd945208 100644 --- a/app/javascript/dashboard/components/widgets/AIAssistanceModal.vue +++ b/app/javascript/dashboard/components/widgets/AIAssistanceModal.vue @@ -48,7 +48,7 @@ export default { this.$emit('close'); }, - async generateAIContent(type = 'rephrase') { + async generateAIContent(type = 'improve') { this.isGenerating = true; this.generatedContent = await this.processEvent(type); this.isGenerating = false; diff --git a/app/javascript/dashboard/components/widgets/AttachmentsPreview.vue b/app/javascript/dashboard/components/widgets/AttachmentsPreview.vue index 75afb5263..c924dd65d 100644 --- a/app/javascript/dashboard/components/widgets/AttachmentsPreview.vue +++ b/app/javascript/dashboard/components/widgets/AttachmentsPreview.vue @@ -46,11 +46,11 @@ const fileName = file => {