Compare commits

...
Author SHA1 Message Date
Muhsin Keloth b8f23256d2 feat: complete pre fill title and description 2024-05-30 13:35:58 +05:30
Muhsin Keloth 5556881f08 feat: add summary prompt 2024-05-29 14:52:24 +05:30
6 changed files with 106 additions and 16 deletions
@@ -29,6 +29,7 @@ class OpenAIAPI extends ApiClient {
'summarize',
'reply_suggestion',
'label_suggestion',
'summary_with_title',
];
/**
@@ -12,20 +12,25 @@
:error="nameError"
@input="v$.title.$touch"
/>
<label>
{{ $t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.DESCRIPTION.LABEL') }}
<textarea
v-model="formState.description"
:style="{ ...inputStyles, padding: '8px 12px' }"
rows="3"
class="text-sm"
:placeholder="
$t(
'INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.DESCRIPTION.PLACEHOLDER'
)
"
/>
</label>
<div class="editor-wrap">
<label>
{{
$t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.DESCRIPTION.LABEL')
}}
</label>
<div>
<woot-message-editor
v-model="formState.description"
class="message-editor"
:style="{ ...inputStyles, padding: '8px 12px' }"
:placeholder="
$t(
'INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.DESCRIPTION.PLACEHOLDER'
)
"
/>
</div>
</div>
<label :class="{ error: v$.teamId.$error }">
{{ $t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.TEAM.LABEL') }}
<select
@@ -107,7 +112,9 @@ import { useI18n } from 'dashboard/composables/useI18n';
import { useAlert } from 'dashboard/composables';
import LinearAPI from 'dashboard/api/integrations/linear';
import validations from './validations';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import { parseLinearAPIErrorResponse } from 'dashboard/store/utils/api';
import { inject } from 'vue';
const props = defineProps({
accountId: {
@@ -253,5 +260,13 @@ const createIssue = async () => {
}
};
onMounted(getTeams);
onMounted(() => {
getTeams();
if (inject('suggestedTitle')) {
formState.title = inject('suggestedTitle');
}
if (inject('suggestedSummary')) {
formState.description = inject('suggestedSummary');
}
});
</script>
@@ -47,6 +47,7 @@ import { useI18n } from 'dashboard/composables/useI18n';
import LinearAPI from 'dashboard/api/integrations/linear';
import CreateOrLinkIssue from './CreateOrLinkIssue.vue';
import Issue from './Issue.vue';
import OpenAPI from 'dashboard/api/integrations/openapi';
import { parseLinearAPIErrorResponse } from 'dashboard/store/utils/api';
defineComponent({
@@ -63,6 +64,9 @@ const props = defineProps({
const getters = useStoreGetters();
const { t } = useI18n();
const suggestedTitle = ref('');
const suggestedSummary = ref('');
const linkedIssue = ref(null);
const shouldShow = ref(false);
const shouldShowPopup = ref(false);
@@ -70,18 +74,46 @@ const isUnlinking = ref(false);
provide('isUnlinking', isUnlinking);
provide('suggestedTitle', suggestedTitle);
provide('suggestedSummary', suggestedSummary);
const currentAccountId = getters.getCurrentAccountId;
const conversation = computed(() =>
getters.getConversationById.value(props.conversationId)
);
const appIntegrations = getters['integrations/getAppIntegrations'];
const aiIntegration = computed(() => {
return appIntegrations.value.find(
integration => integration.id === 'openai' && !!integration.hooks.length
)?.hooks[0];
});
const isAIIntegrationEnabled = computed(() => !!aiIntegration.value);
const tooltipText = computed(() => {
return linkedIssue.value === null
? t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK_BUTTON')
: null;
});
const suggestTitleAndSummary = async () => {
try {
const response = await OpenAPI.processEvent({
type: 'summary_with_title',
hookId: aiIntegration.value.id,
conversationId: props.conversationId,
});
const { message } = response.data;
const messageObject = JSON.parse(message);
const { title = '', description = '' } = messageObject;
suggestedTitle.value = title;
suggestedSummary.value = description;
} catch (error) {
// Since this is a non-critical operation, we don't want to show an alert to the user
}
};
const loadLinkedIssue = async () => {
linkedIssue.value = null;
try {
@@ -137,5 +169,8 @@ watch(
onMounted(() => {
loadLinkedIssue();
if (isAIIntegrationEnabled.value) {
suggestTitleAndSummary();
}
});
</script>
@@ -1,6 +1,6 @@
module Enterprise::Integrations::OpenaiProcessorService
ALLOWED_EVENT_NAMES = %w[rephrase summarize reply_suggestion label_suggestion fix_spelling_grammar shorten expand
make_friendly make_formal simplify].freeze
make_friendly make_formal simplify summary_with_title].freeze
CACHEABLE_EVENTS = %w[label_suggestion].freeze
def reply_suggestion_message
@@ -74,6 +74,17 @@ module Enterprise::Integrations::OpenaiProcessorService
}.to_json
end
def summarize_with_title
{
model: self.class::GPT_MODEL,
messages: [
{ role: 'system',
content: prompt_from_file('summary_with_title', enterprise: true) },
{ role: 'user', content: conversation_messages }
]
}.to_json
end
def label_suggestion_body
return unless label_suggestions_enabled?
@@ -0,0 +1,24 @@
As an AI-powered summarization tool, your task is to condense lengthy interactions between customer support agents and customers into a brief title and description. The objective is to provide a quick overview, enabling any agent, even those without prior context, to grasp the essence of the conversation promptly.
Make sure you strongly adhere to the following rules when generating the title and description:
1. **Title**
- Be brief and concise, ideally 5-10 words.
- Capture the main issue or request of the customer.
- Highlight key points using **bold** for important words.
2. **Description**
- Summarize the conversation in approximately 100 words, formatted as multiple small paragraphs that are easy to read.
- Describe the customer's intent in around 30 words.
- Remove information that is not directly relevant to the customer's problem or the agent's solution. For example, personal anecdotes, small talk, etc.
- Don't include segments of the conversation that didn't contribute meaningful content, like greetings or farewell.
- Highlight key points using **bold** for important words.
- Use markdown syntax to format any included code, using backticks.
- If there are unresolved issues or outstanding questions, include them in a "Follow-up Items" section.
Output the response in the following JSON format:
{
"title": "<GENERATED_TITLE>",
"description": "<GENERATED_DESCRIPTION>"
}
@@ -9,6 +9,10 @@ class Integrations::Openai::ProcessorService < Integrations::OpenaiBaseService
make_api_call(summarize_body)
end
def summary_with_title_message
make_api_call(summarize_with_title)
end
def rephrase_message
make_api_call(build_api_call_body("#{AGENT_INSTRUCTION} Please rephrase the following response. " \
"#{LANGUAGE_INSTRUCTION}"))