PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.15
Yatra – Travel Booking & Tour Operator Software v3.0.15
3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 All 83 releases
yatra / resources / js / api / ai-api.ts

ai-api.ts in Yatra – Travel Booking & Tour Operator Software 3.0.15, at resources/js/api/ai-api.ts

422 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { apiClient } from "../lib/api-client";
2
3 export interface AiKeyStatus {
4 configured: boolean;
5 hint: string;
6 }
7
8 export interface AiProvider {
9 id: string;
10 label: string;
11 default_model: string;
12 models: Array<{ id: string; label: string }>;
13 }
14
15 export interface AiLicenseInfo {
16 is_agency?: boolean;
17 tier?: string;
18 plan_name?: string;
19 price_id?: number | string | null;
20 }
21
22 export interface AiChatLimits {
23 per_trip_day: number;
24 per_ip_hour: number;
25 per_session: number;
26 per_session_booking: number;
27 max_message_chars: number;
28 history_turns: number;
29 }
30
31 export interface AiChatLimitMeta {
32 default: number;
33 min: number;
34 max: number;
35 }
36
37 export interface AiMeta {
38 is_pro_active: boolean;
39 is_ai_eligible: boolean;
40 is_module_enabled: boolean;
41 license: AiLicenseInfo;
42 providers: AiProvider[];
43 keys: Record<string, AiKeyStatus>;
44 allowed_tasks: string[];
45 upgrade_url: string;
46 license_page_url: string;
47 trip_chat_enabled?: boolean;
48 trip_chat_limits?: AiChatLimits;
49 trip_chat_limits_schema?: Record<keyof AiChatLimits, AiChatLimitMeta>;
50 }
51
52 export interface AiBrandVoice {
53 tone: string;
54 examples: string[];
55 forbidden: string[];
56 required: string[];
57 language: string;
58 default_provider: string;
59 default_model: string;
60 }
61
62 export interface AiGenerateResponse {
63 text: string;
64 provider: string;
65 model: string;
66 prompt_tokens: number;
67 completion_tokens: number;
68 }
69
70 export interface AiUsageBucket {
71 prompt: number;
72 completion: number;
73 calls: number;
74 tasks: Record<string, number>;
75 }
76
77 export interface AiUsageSummary {
78 current_month: string;
79 months: Record<string, Record<string, AiUsageBucket>>;
80 totals: { prompt: number; completion: number; calls: number };
81 }
82
83 /* -------------------------------------------------------------------------- */
84 /* Operations AI (Phase A) */
85 /* -------------------------------------------------------------------------- */
86
87 export interface AiDigestMetrics {
88 today_date: string;
89 enquiries_unresponded_count: string;
90 enquiries_oldest_waiting_hours: string;
91 recent_enquiries_block: string;
92 bookings_payment_pending_count: string;
93 bookings_departing_soon_count: string;
94 departing_soon_block: string;
95 high_value_pending_block: string;
96 }
97
98 export type AiDigestState =
99 | "ready"
100 | "all_caught_up"
101 | "no_api_key"
102 | "module_disabled"
103 | "upgrade_required"
104 | "error";
105
106 export interface AiDigest {
107 text: string;
108 metrics: AiDigestMetrics;
109 has_material: boolean;
110 generated_at: number;
111 cached: boolean;
112 state: AiDigestState;
113 error?: string;
114 }
115
116 export type EnquiryReplyVariant = "fresh" | "warmer" | "shorter";
117
118 /**
119 * One row in the Prompts settings list — covers single-shot prompt
120 * templates (trip-description, enquiry-reply, etc.) AND the new
121 * multi-step agent system prompts (agent-trip-chat, agent-trip-
122 * creation, agent-itinerary, agent-email-template). The `description`
123 * field is operator-facing: explains WHERE the prompt applies in
124 * the product, so the editor knows what they're about to change.
125 */
126 export interface AiPromptRow {
127 task: string;
128 category: string;
129 label: string;
130 /** One-line operator-facing explanation of where the prompt
131 * applies. Empty string when no description is registered. */
132 description?: string;
133 default: {
134 system: string;
135 user: string;
136 max_tokens: number;
137 temperature: number;
138 };
139 override: {
140 system: string;
141 user: string;
142 max_tokens: number | null;
143 temperature: number | null;
144 };
145 has_override: boolean;
146 }
147
148 export interface AiPromptOverridePayload {
149 system?: string;
150 user?: string;
151 max_tokens?: number | null;
152 temperature?: number | null;
153 }
154
155 export interface EnquiryReplyOptions {
156 variant?: EnquiryReplyVariant;
157 current_value?: string;
158 include_sensitive?: boolean;
159 }
160
161 export const aiApi = {
162 meta: () => apiClient.get("/ai/meta") as Promise<AiMeta>,
163 generate: (
164 task: string,
165 context: Record<string, unknown>,
166 options: Record<string, unknown> = {},
167 ) =>
168 apiClient.post("/ai/generate", {
169 task,
170 context,
171 options,
172 }) as Promise<AiGenerateResponse>,
173 improve: (
174 task: string,
175 currentValue: string,
176 options: Record<string, unknown> = {},
177 ) =>
178 apiClient.post("/ai/improve", {
179 task,
180 current_value: currentValue,
181 options,
182 }) as Promise<AiGenerateResponse>,
183 getBrandVoice: () =>
184 apiClient.get("/ai/brand-voice") as Promise<{ data: AiBrandVoice }>,
185 saveBrandVoice: (data: AiBrandVoice) =>
186 apiClient.put("/ai/brand-voice", data) as Promise<{
187 data: AiBrandVoice;
188 message: string;
189 }>,
190 setKey: (provider: string, apiKey: string) =>
191 apiClient.post(`/ai/keys/${encodeURIComponent(provider)}`, {
192 api_key: apiKey,
193 }) as Promise<{
194 keys: Record<string, AiKeyStatus>;
195 message: string;
196 }>,
197 deleteKey: (provider: string) =>
198 apiClient.delete(`/ai/keys/${encodeURIComponent(provider)}`) as Promise<{
199 keys: Record<string, AiKeyStatus>;
200 message: string;
201 }>,
202 testKey: (provider: string) =>
203 apiClient.post(
204 `/ai/keys/${encodeURIComponent(provider)}/test`,
205 {},
206 ) as Promise<{
207 ok: boolean;
208 message: string;
209 }>,
210 getUsage: () =>
211 apiClient.get("/ai/usage") as Promise<{ data: AiUsageSummary }>,
212
213 // Operations AI
214 draftEnquiryReply: (enquiryId: number, opts: EnquiryReplyOptions = {}) =>
215 apiClient.post(
216 `/ai/enquiry/${encodeURIComponent(String(enquiryId))}/draft-reply`,
217 {
218 variant: opts.variant ?? "fresh",
219 current_value: opts.current_value ?? "",
220 include_sensitive: opts.include_sensitive ?? false,
221 },
222 ) as Promise<AiGenerateResponse>,
223 getDashboardDigest: () =>
224 apiClient.get("/ai/dashboard/digest") as Promise<{ data: AiDigest }>,
225 /**
226 * AI customer summary — 3-line operator-facing snapshot
227 * (status / history, last trip, operationally-relevant notes).
228 * Sensitive fields (medical / dietary / notes) only flow when
229 * `include_sensitive` is true.
230 */
231 getCustomerSummary: (customerId: number, includeSensitive = false) =>
232 apiClient.post(
233 `/ai/customer/${encodeURIComponent(String(customerId))}/summary`,
234 { include_sensitive: includeSensitive },
235 ) as Promise<{
236 data: {
237 text: string;
238 generated_at: number;
239 customer_id: number;
240 sensitive_included: boolean;
241 };
242 }>,
243 refreshDashboardDigest: () =>
244 apiClient.post("/ai/dashboard/digest/refresh", {}) as Promise<{
245 data: AiDigest;
246 }>,
247
248 // Prompt overrides
249 listPrompts: () =>
250 apiClient.get("/ai/prompts") as Promise<{ data: AiPromptRow[] }>,
251 savePromptOverride: (task: string, override: AiPromptOverridePayload) =>
252 apiClient.put(
253 `/ai/prompts/${encodeURIComponent(task)}`,
254 override,
255 ) as Promise<{
256 task: string;
257 override: AiPromptOverridePayload;
258 has_override: boolean;
259 message: string;
260 }>,
261 resetPrompt: (task: string) =>
262 apiClient.delete(`/ai/prompts/${encodeURIComponent(task)}`) as Promise<{
263 task: string;
264 message: string;
265 }>,
266 resetAllPrompts: () =>
267 apiClient.delete("/ai/prompts") as Promise<{ message: string }>,
268
269 // Public chat toggle
270 setTripChatEnabled: (enabled: boolean) =>
271 apiClient.put("/ai/trip-chat-toggle", { enabled }) as Promise<{
272 enabled: boolean;
273 message: string;
274 }>,
275 setTripChatLimits: (patch: Partial<AiChatLimits>) =>
276 apiClient.put("/ai/trip-chat-limits", patch) as Promise<{
277 limits: AiChatLimits;
278 message: string;
279 }>,
280
281 /**
282 * Trip Creation agent — generates every section in one coherent
283 * agent run instead of N parallel single-shot calls. Replaces the
284 * old fire-10-parallel-`generate()` design in the wizard.
285 *
286 * Response shape:
287 * { wizard_session_id, sections: { description, short_description,
288 * trip_details, what_makes_special, trip_story, highlights,
289 * included_items, excluded_items, cancellation_policy, faqs,
290 * itinerary, starting_location, ending_location,
291 * accommodation_type, meta_title, meta_description },
292 * missing[], tool_trace[], prompt_tokens, completion_tokens, … }
293 */
294 wizardCreateTrip: (setup: Record<string, unknown>) =>
295 apiClient.post("/ai/wizard/trip", { setup }) as Promise<{
296 wizard_session_id: string;
297 text: string;
298 sections: Record<string, unknown>;
299 missing: string[];
300 tool_trace: Array<{ name: string; args: Record<string, unknown> }>;
301 prompt_tokens: number;
302 completion_tokens: number;
303 provider: string;
304 model: string;
305 turns: number;
306 }>,
307
308 /**
309 * Regenerate one wizard section, keeping the others. The agent
310 * reads the existing sections so the new one stays consistent.
311 */
312 wizardRegenSection: (
313 section: string,
314 setup: Record<string, unknown>,
315 sections: Record<string, unknown>,
316 guidance = "",
317 ) =>
318 apiClient.post("/ai/wizard/trip/section", {
319 section,
320 setup,
321 sections,
322 guidance,
323 }) as Promise<{
324 section: string;
325 content: unknown;
326 tool_trace: Array<{ name: string; args: Record<string, unknown> }>;
327 prompt_tokens: number;
328 completion_tokens: number;
329 provider: string;
330 model: string;
331 }>,
332
333 /**
334 * Generate a {subject, body} pair for an email template. Caller
335 * passes the template_key + catalog metadata + the operator's
336 * tone/extra-context. The agent references only the merge tags
337 * supplied in `merge_tags`.
338 */
339 generateEmailTemplate: (request: {
340 template_key: string;
341 template_name?: string;
342 template_description?: string;
343 recipient_type?: "customer" | "admin";
344 merge_tags?: string[];
345 current_subject?: string;
346 current_body?: string;
347 tone?: string;
348 extra_context?: string;
349 }) =>
350 apiClient.post("/ai/email-template/generate", request) as Promise<{
351 subject: string;
352 body: string;
353 provider: string;
354 model: string;
355 prompt_tokens: number;
356 completion_tokens: number;
357 turns: number;
358 }>,
359
360 // Standalone itinerary builder
361 draftItinerary: (
362 tripId: number,
363 extraContextOrSetup: string | Record<string, unknown> = "",
364 ) =>
365 apiClient.post(
366 `/ai/itinerary/${encodeURIComponent(String(tripId))}/draft`,
367 typeof extraContextOrSetup === "string"
368 ? { extra_context: extraContextOrSetup }
369 : { setup: extraContextOrSetup },
370 ) as Promise<{
371 text: string;
372 days: Array<{
373 day: number;
374 day_title: string;
375 description: string;
376 activities?: Array<{
377 title: string;
378 description?: string;
379 item_type?: string;
380 item_name?: string;
381 start_time?: string;
382 end_time?: string;
383 duration?: string;
384 location?: string;
385 }>;
386 }>;
387 trip: { id: number; name: string; duration_days: number };
388 prompt_tokens: number;
389 completion_tokens: number;
390 }>,
391 applyItinerary: (
392 tripId: number,
393 days: Array<{
394 day: number;
395 day_title: string;
396 description: string;
397 activities?: Array<{
398 title: string;
399 description?: string;
400 item_type?: string;
401 item_name?: string;
402 start_time?: string;
403 end_time?: string;
404 duration?: string;
405 location?: string;
406 }>;
407 }>,
408 replace: boolean,
409 ) =>
410 apiClient.post(
411 `/ai/itinerary/${encodeURIComponent(String(tripId))}/apply`,
412 {
413 days,
414 replace,
415 },
416 ) as Promise<{
417 created: Array<{ id: number; day: number; day_title: string }>;
418 count: number;
419 message: string;
420 }>,
421 };
422