PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.1.1
Fluent Support – Helpdesk & Customer Support Ticket System v2.1.1
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
fluent-support / app / Services / Integrations / FluentBot / FluentBotHelper.php

FluentBotHelper.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.1.1, at app/Services/Integrations/FluentBot/FluentBotHelper.php

277 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace FluentSupport\App\Services\Integrations\FluentBot;
3
4 use FluentSupport\App\Models\Meta;
5 use FluentSupport\App\Services\Integrations\FluentBot\FluentBotAPI;
6 use FluentSupport\Framework\Support\Arr;
7 use FluentSupport\App\Services\Helper;
8 use WP_Error;
9 class FluentBotHelper
10 {
11 const BASE_URL = 'https://dash.fluentbot.ai/api';
12
13 const ENDPOINTS = [
14 'default' => '/responses',
15 'ticket_reply' => '/chat/fs',
16 ];
17
18 public function generateStreamResponse($prompt, $ticket, $productId, $conversationId = null)
19 {
20 $prompt = apply_filters('fluent_support/generate_response', $prompt, $ticket);
21 $payload = [
22 'ticket_conversation' => $this->getTicketMessages($ticket),
23 'source' => 'fluent_support',
24 'prompt' => $prompt,
25 'stream' => true,
26 'chat_id' => $conversationId ?? null,
27 ];
28 return $this->makeStreamAPICall($payload, $prompt, $ticket->id, 'ticket_reply', $productId);
29 }
30
31 public function modifyResponse($prompt, $selectedText, $ticketId)
32 {
33 $prompt = apply_filters('fluent_support/modify_selected_text', $prompt);
34 $payload = [
35 'message' => "Instruction: {$prompt} Now apply this to the given text: {$selectedText}",
36 ];
37
38 return $this->makeAPICall($payload, $prompt, $ticketId);
39 }
40
41 public function generateTicketSummary($ticket)
42 {
43 $prompt = 'Provide a summary of the ticket from the customer\'s perspective. Each step should start with "-". Break it down into concise steps, with a maximum of 6 steps. Each step should be within 6 words per line. Use full stops for separation.';
44 $prompt = apply_filters('fluent_support/generate_ticket_summary', $prompt);
45
46 $messages = $this->getSimpleTicketMessages($ticket);
47 $payload = [
48 'message' => "Instruction: {$prompt} Ticket Data: " . json_encode($messages),
49 ];
50
51 return $this->makeAPICall($payload, $prompt, $ticket->id);
52 }
53
54 public function generateTicketTone($ticket)
55 {
56 $prompt = 'What is the tone of this ticket? Is it positive, negative, or neutral? Provide a response with a single word.';
57 $prompt = apply_filters('fluent_support/find_customer_sentiment', $prompt);
58
59 $messages = $this->getSimpleTicketMessages($ticket);
60 $payload = [
61 'message' => "Instruction: {$prompt} Ticket Data: " . json_encode($messages),
62 ];
63
64 return $this->makeAPICall($payload, $prompt, $ticket->id);
65 }
66
67 public function getPresetPrompts(string $type): array
68 {
69 if ($type === 'modifyResponse') {
70 return $this->getModifyResponsePresets();
71 }
72
73 if ($type === 'createResponse') {
74 return $this->getCreateResponsePresets();
75 }
76
77 return [];
78 }
79
80 private function makeAPICall(array $payload, string $prompt, int $ticketId, string $type = 'default', $productId = null )
81 {
82 $apiUrl = static::BASE_URL . static::ENDPOINTS[$type];
83
84 $credentials = $this->resolveApiCredentials($productId);
85
86 if (is_wp_error($credentials)) {
87 return $credentials;
88 }
89
90 // Use bot_id instead of botId for the new API
91 $payload['bot_id'] = $credentials['botId'];
92
93 $api = new FluentBotAPI($apiUrl);
94 $result = $api->makeRequest($ticketId, $prompt, $payload);
95
96 // For ticket_reply endpoint, return the full result with chat_id
97 // For other endpoints, return just the content for backward compatibility
98 if ($type === 'ticket_reply' && is_array($result) && isset($result['content'])) {
99 return $result;
100 } elseif (is_array($result) && isset($result['content'])) {
101 return $result['content'];
102 }
103
104 return $result;
105 }
106
107 private function makeStreamAPICall(array $payload, string $prompt, int $ticketId, string $type = 'default', $productId = null)
108 {
109 $apiUrl = static::BASE_URL . static::ENDPOINTS[$type];
110
111 $credentials = $this->resolveApiCredentials($productId);
112
113 if (is_wp_error($credentials)) {
114 echo "data: " . json_encode(['error' => $credentials->get_error_message()]) . "\n\n";
115 return;
116 }
117
118 // Use bot_id instead of botId for the new API
119 $payload['bot_id'] = $credentials['botId'];
120
121 $api = new FluentBotAPI($apiUrl);
122 $api->makeStreamRequest($ticketId, $prompt, $payload);
123 }
124
125 private function resolveApiCredentials($productId)
126 {
127 $meta = Meta::where([
128 'object_type' => 'fluent_bot_settings',
129 'object_id' => 1,
130 'key' => '_fs_fluent_bot_config'
131 ])->first();
132
133 $config = $meta ? Helper::safeUnserialize($meta->value) : [];
134
135 $botId = $config['generalBotId'] ?? '';
136
137 if ($productId && !empty($config['productMappings']) && is_array($config['productMappings'])) {
138 foreach ($config['productMappings'] as $mapping) {
139 if ((int)$mapping['productId'] === (int)$productId) {
140 $botId = $mapping['botId'] ?? $botId;
141 break;
142 }
143 }
144 }
145
146 if (!$botId) {
147 return new \WP_Error(
148 'missing_bot_credentials',
149 __('Bot ID is not set for this product.', 'fluent-support')
150 );
151 }
152
153 return [
154 'botId' => $botId
155 ];
156 }
157
158 private function getTicketMessages($ticket): array
159 {
160 $messages = [];
161 $ticketArray = $ticket->toArray();
162
163 if (!empty($ticketArray['content'])) {
164 $messages[] = [
165 'role' => 'customer',
166 'message' => $this->cleanText($ticketArray['content']),
167 ];
168 }
169
170 foreach (Arr::get($ticketArray, 'responses', []) as $response) {
171 $role = Arr::get($response, 'person.person_type') === 'customer' ? 'customer' : 'support_agent';
172 $messages[] = [
173 'role' => $role,
174 'message' => $this->cleanText(Arr::get($response, 'content', '')),
175 ];
176 }
177
178 return $messages;
179 }
180
181 private function getSimpleTicketMessages($ticket): array
182 {
183 $messages = [];
184 $ticketArray = $ticket->toArray();
185
186 if (!empty($ticketArray['content'])) {
187 $messages[] = [
188 'role' => 'visitor',
189 'message' => $this->cleanText($ticketArray['content']),
190 ];
191 }
192
193 foreach (Arr::get($ticketArray, 'responses', []) as $response) {
194 $role = Arr::get($response, 'person.person_type') === 'customer' ? 'visitor' : 'ai';
195 $messages[] = [
196 'role' => $role,
197 'message' => $this->cleanText(Arr::get($response, 'content', '')),
198 ];
199 }
200
201 return $messages;
202 }
203
204
205
206 private function cleanText(string $text): string
207 {
208 return trim(strip_tags($text));
209 }
210
211 private function getModifyResponsePresets(): array
212 {
213 $presets = [
214 [
215 'label' => 'Improve Writing',
216 'text' => 'shorten',
217 'description' => 'Use AI to refine the text by removing unnecessary words and making it more concise while retaining the original meaning and key information.'
218 ],
219 [
220 'label' => 'Fix Spelling & Grammar',
221 'text' => 'lengthen',
222 'description' => 'Apply AI to correct any spelling and grammatical errors in the text, ensuring it is free of mistakes and reads professionally.'
223 ],
224 [
225 'label' => 'Make Shorter',
226 'text' => 'friendly',
227 'description' => 'AI will modify the text to make it shorter and more casual, making it suitable for informal or friendly communication.'
228 ],
229 [
230 'label' => 'Make Longer',
231 'text' => 'professional',
232 'description' => 'Enhance the text by adding more details and using refined language to make it more formal and detailed, appropriate for professional settings.'
233 ],
234 [
235 'label' => 'Simplify Language',
236 'text' => 'simplify',
237 'description' => 'Utilize AI to simplify complex phrases and terminology, making the text easier to read and understand for a general audience.'
238 ]
239 ];
240
241 return apply_filters('fluent_support/get_modify_response_preset_prompts', $presets);
242 }
243
244 private function getCreateResponsePresets(): array
245 {
246 $presets = [
247 [
248 'label' => 'Request More Information',
249 'text' => 'requestInfo',
250 'description' => 'Ask the customer to provide additional details or clarification about the issue they reported. This helps in gathering more information to resolve the issue effectively.'
251 ],
252 [
253 'label' => 'Acknowledge Issue',
254 'text' => 'acknowledgeIssue',
255 'description' => 'Confirm receipt of the customer\'s issue and reassure them that it is being investigated. This demonstrates that their concern is being taken seriously.'
256 ],
257 [
258 'label' => 'Provide Solution',
259 'text' => 'provideSolution',
260 'description' => 'Offer a comprehensive solution or resolution to the problem described by the customer. This should address their concerns and provide actionable steps to resolve the issue.'
261 ],
262 [
263 'label' => 'Follow Up',
264 'text' => 'followUp',
265 'description' => 'Reach out to the customer after a solution has been provided to ensure that their issue has been resolved to their satisfaction. This helps in confirming the resolution and maintaining good customer relations.'
266 ],
267 [
268 'label' => 'Close Ticket',
269 'text' => 'closeTicket',
270 'description' => 'Notify the customer that their ticket will be closed as the issue has been resolved. Ensure that all their concerns are addressed before closing the ticket.'
271 ]
272 ];
273
274 return apply_filters('fluent_support/get_create_response_preset_prompts', $presets);
275 }
276 }
277