mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 12:08:01 +00:00
Fixes https://github.com/chatwoot/chatwoot/issues/8436 Fixes https://github.com/chatwoot/chatwoot/issues/9767 Fixes https://github.com/chatwoot/chatwoot/issues/10156 Fixes https://github.com/chatwoot/chatwoot/issues/6031 Fixes https://github.com/chatwoot/chatwoot/issues/5696 Fixes https://github.com/chatwoot/chatwoot/issues/9250 Fixes https://github.com/chatwoot/chatwoot/issues/9762 --------- Co-authored-by: Pranav <pranavrajs@gmail.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
204 lines
5.6 KiB
JavaScript
204 lines
5.6 KiB
JavaScript
import { computed, onMounted } from 'vue';
|
|
import {
|
|
useStore,
|
|
useStoreGetters,
|
|
useMapGetter,
|
|
} from 'dashboard/composables/store';
|
|
import { useAlert, useTrack } from 'dashboard/composables';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
|
import OpenAPI from 'dashboard/api/integrations/openapi';
|
|
|
|
/**
|
|
* Cleans and normalizes a list of labels.
|
|
* @param {string} labels - A comma-separated string of labels.
|
|
* @returns {string[]} An array of cleaned and unique labels.
|
|
*/
|
|
const cleanLabels = labels => {
|
|
return labels
|
|
.toLowerCase() // Set it to lowercase
|
|
.split(',') // split the string into an array
|
|
.filter(label => label.trim()) // remove any empty strings
|
|
.map(label => label.trim()) // trim the words
|
|
.filter((label, index, self) => self.indexOf(label) === index);
|
|
};
|
|
|
|
/**
|
|
* A composable function for AI-related operations in the dashboard.
|
|
* @returns {Object} An object containing AI-related methods and computed properties.
|
|
*/
|
|
export function useAI() {
|
|
const store = useStore();
|
|
const getters = useStoreGetters();
|
|
const { t } = useI18n();
|
|
|
|
/**
|
|
* Computed property for UI flags.
|
|
* @type {import('vue').ComputedRef<Object>}
|
|
*/
|
|
const uiFlags = computed(() => getters['integrations/getUIFlags'].value);
|
|
|
|
const appIntegrations = useMapGetter('integrations/getAppIntegrations');
|
|
const currentChat = useMapGetter('getSelectedChat');
|
|
const replyMode = useMapGetter('draftMessages/getReplyEditorMode');
|
|
|
|
/**
|
|
* Computed property for the AI integration.
|
|
* @type {import('vue').ComputedRef<Object|undefined>}
|
|
*/
|
|
const aiIntegration = computed(
|
|
() =>
|
|
appIntegrations.value.find(
|
|
integration => integration.id === 'openai' && !!integration.hooks.length
|
|
)?.hooks[0]
|
|
);
|
|
|
|
/**
|
|
* Computed property to check if AI integration is enabled.
|
|
* @type {import('vue').ComputedRef<boolean>}
|
|
*/
|
|
const isAIIntegrationEnabled = computed(() => !!aiIntegration.value);
|
|
|
|
/**
|
|
* Computed property to check if label suggestion feature is enabled.
|
|
* @type {import('vue').ComputedRef<boolean>}
|
|
*/
|
|
const isLabelSuggestionFeatureEnabled = computed(() => {
|
|
if (aiIntegration.value) {
|
|
const { settings = {} } = aiIntegration.value || {};
|
|
return settings.label_suggestion;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
/**
|
|
* Computed property to check if app integrations are being fetched.
|
|
* @type {import('vue').ComputedRef<boolean>}
|
|
*/
|
|
const isFetchingAppIntegrations = computed(() => uiFlags.value.isFetching);
|
|
|
|
/**
|
|
* Computed property for the hook ID.
|
|
* @type {import('vue').ComputedRef<string|undefined>}
|
|
*/
|
|
const hookId = computed(() => aiIntegration.value?.id);
|
|
|
|
/**
|
|
* Computed property for the conversation ID.
|
|
* @type {import('vue').ComputedRef<string|undefined>}
|
|
*/
|
|
const conversationId = computed(() => currentChat.value?.id);
|
|
|
|
/**
|
|
* Computed property for the draft key.
|
|
* @type {import('vue').ComputedRef<string>}
|
|
*/
|
|
const draftKey = computed(
|
|
() => `draft-${conversationId.value}-${replyMode.value}`
|
|
);
|
|
|
|
/**
|
|
* Computed property for the draft message.
|
|
* @type {import('vue').ComputedRef<string>}
|
|
*/
|
|
const draftMessage = computed(() =>
|
|
getters['draftMessages/get'].value(draftKey.value)
|
|
);
|
|
|
|
/**
|
|
* Fetches integrations if they haven't been loaded yet.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
const fetchIntegrationsIfRequired = async () => {
|
|
if (!appIntegrations.value.length) {
|
|
await store.dispatch('integrations/get');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Records analytics for AI-related events.
|
|
* @param {string} type - The type of event.
|
|
* @param {Object} payload - Additional data for the event.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
const recordAnalytics = async (type, payload) => {
|
|
const event = OPEN_AI_EVENTS[type.toUpperCase()];
|
|
if (event) {
|
|
useTrack(event, {
|
|
type,
|
|
...payload,
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetches label suggestions for the current conversation.
|
|
* @returns {Promise<string[]>} An array of suggested labels.
|
|
*/
|
|
const fetchLabelSuggestions = async () => {
|
|
if (!conversationId.value) return [];
|
|
|
|
try {
|
|
const result = await OpenAPI.processEvent({
|
|
type: 'label_suggestion',
|
|
hookId: hookId.value,
|
|
conversationId: conversationId.value,
|
|
});
|
|
|
|
const {
|
|
data: { message: labels },
|
|
} = result;
|
|
|
|
return cleanLabels(labels);
|
|
} catch {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Processes an AI event, such as rephrasing content.
|
|
* @param {string} [type='rephrase'] - The type of AI event to process.
|
|
* @returns {Promise<string>} The generated message or an empty string if an error occurs.
|
|
*/
|
|
const processEvent = async (type = 'rephrase') => {
|
|
try {
|
|
const result = await OpenAPI.processEvent({
|
|
hookId: hookId.value,
|
|
type,
|
|
content: draftMessage.value,
|
|
conversationId: conversationId.value,
|
|
});
|
|
const {
|
|
data: { message: generatedMessage },
|
|
} = result;
|
|
return generatedMessage;
|
|
} catch (error) {
|
|
const errorData = error.response.data.error;
|
|
const errorMessage =
|
|
errorData?.error?.message ||
|
|
t('INTEGRATION_SETTINGS.OPEN_AI.GENERATE_ERROR');
|
|
useAlert(errorMessage);
|
|
return '';
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
fetchIntegrationsIfRequired();
|
|
});
|
|
|
|
return {
|
|
draftMessage,
|
|
uiFlags,
|
|
appIntegrations,
|
|
currentChat,
|
|
replyMode,
|
|
isAIIntegrationEnabled,
|
|
isLabelSuggestionFeatureEnabled,
|
|
isFetchingAppIntegrations,
|
|
fetchIntegrationsIfRequired,
|
|
recordAnalytics,
|
|
fetchLabelSuggestions,
|
|
processEvent,
|
|
};
|
|
}
|