Spaces:
Sleeping
Sleeping
| import axios from 'axios'; | |
| import { MOCK_TICKETS } from './mockData'; | |
| import { API_CONFIG } from '../config'; | |
| const USE_MOCK = true; | |
| const API_BASE_URL = API_CONFIG.BACKEND_URL; | |
| const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); | |
| // Safe helper to get data from storage or default | |
| const getStorage = (key, defaultData) => { | |
| try { | |
| const stored = localStorage.getItem(key); | |
| if (!stored) { | |
| setStorage(key, defaultData); | |
| return defaultData; | |
| } | |
| return JSON.parse(stored); | |
| } catch (error) { | |
| console.warn(`[Storage Error] Failed to read or parse '${key}':`, error); | |
| return defaultData; | |
| } | |
| }; | |
| // Safe helper to set data and handle QuotaExceeded | |
| const setStorage = (key, data) => { | |
| try { | |
| localStorage.setItem(key, JSON.stringify(data)); | |
| } catch (error) { | |
| console.warn(`[Storage Error] Failed to write '${key}'. Possible quota exceeded:`, error); | |
| // If quota exceeded, we could trim the data, but for now we fail gracefully. | |
| } | |
| }; | |
| export const api = { | |
| // Login and Signup have been fully migrated to Supabase via authStore.js | |
| // Ensure that no component tries to use api.login or api.signup anymore. | |
| getTickets: async () => { | |
| if (USE_MOCK) { | |
| await delay(500); | |
| return getStorage('tickets', MOCK_TICKETS); | |
| } | |
| }, | |
| createTicket: async (ticketData) => { | |
| if (USE_MOCK) { | |
| await delay(800); | |
| const tickets = getStorage('tickets', MOCK_TICKETS); | |
| const newTicket = { | |
| ticket_id: "TCKT-" + Math.floor(Math.random() * 10000), | |
| status: 'Open', | |
| createdAt: new Date().toISOString(), | |
| ...ticketData, | |
| messages: [ | |
| { | |
| sender: 'user', | |
| message: ticketData.description || ticketData.summary || '', | |
| timestamp: new Date().toISOString() | |
| } | |
| ] | |
| }; | |
| tickets.unshift(newTicket); // Add to beginning | |
| setStorage('tickets', tickets); | |
| return { data: newTicket }; | |
| } | |
| }, | |
| predictTicket: async (issueText, imageBase64 = "") => { | |
| try { | |
| // ALWAYS call the real backend for prediction if possible | |
| const response = await axios.post(`${API_BASE_URL}/ai/analyze_ticket`, { | |
| text: issueText, | |
| image_base64: imageBase64, | |
| image_text: "" | |
| }); | |
| const result = response.data; | |
| // Map backend response to frontend format | |
| return { | |
| data: { | |
| ticket_id: "TCKT-" + Math.floor(Math.random() * 10000), | |
| category: result.category, | |
| subcategory: result.subcategory, | |
| priority: result.priority, | |
| assigned_team: result.assigned_team, | |
| auto_resolve: result.auto_resolve, | |
| routing_confidence: result.confidence, | |
| duplicate_probability: result.duplicate_ticket.similarity, | |
| duplicate_ticket: result.duplicate_ticket.duplicate_ticket_id, | |
| summary: result.summary, | |
| entities: result.entities, | |
| reasoning: result.reasoning, | |
| decision_factors: result.decision_factors, | |
| image_description: result.image_description, | |
| ocr_text: result.ocr_text | |
| } | |
| }; | |
| } catch (error) { | |
| console.error("AI Backend Error, falling back to mock:", error); | |
| // Fallback to mock logic if backend fails | |
| await delay(1000); | |
| return { | |
| data: { | |
| ticket_id: "TCKT-MOCK-" + Math.floor(Math.random() * 10000), | |
| category: "Hardware", | |
| priority: "Medium", | |
| assigned_team: "Hardware Support", | |
| auto_resolve: false, | |
| routing_confidence: 0.5, | |
| duplicate_probability: 0.0, | |
| summary: issueText.substring(0, 50) + "...", | |
| entities: [] | |
| } | |
| }; | |
| } | |
| }, | |
| logCorrection: async (correctionPayload) => { | |
| try { | |
| await axios.post(`${API_BASE_URL}/ai/log_correction`, correctionPayload); | |
| } catch (error) { | |
| // Non-fatal: log but don't break the UI flow | |
| console.warn("[Correction Log] Failed to save correction:", error); | |
| } | |
| } | |
| }; | |