File size: 4,319 Bytes
22b1735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1904e4c
22b1735
 
 
 
 
1904e4c
22b1735
 
 
 
1904e4c
22b1735
 
1904e4c
22b1735
 
 
 
 
 
 
 
 
 
1904e4c
 
 
 
 
 
22b1735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1904e4c
 
22b1735
 
 
 
 
 
 
 
 
1904e4c
 
 
 
 
22b1735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

import { toast } from "@/components/ui/sonner";
import { storage, STORAGE_KEYS } from "@/lib/storage";

// Define types matching our API
export interface SourceMetadata {
  source?: string;
  ruling_date?: string;
  [key: string]: string | undefined;
}

export interface RetrievedSource {
  content_snippet: string;
  metadata?: SourceMetadata;
}

export interface QueryResponse {
  answer: string;
  retrieved_sources?: RetrievedSource[];
}

export interface TitleResponse {
  title: string;
}

export interface Message {
  role: "user" | "assistant" | "system";
  content: string;
}

export interface QueryRequest {
  query: string;
  chat_history?: Message[];
  filters?: Record<string, any>;
  regenerate?: boolean;
}

// Add a delay function for better UX when showing loading states
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

export const apiService = {
  async getApiUrl(): Promise<string> {
    const storedUrl = storage.get<string>(STORAGE_KEYS.API_ENDPOINT);
    
    if (storedUrl) {
      return storedUrl;
    } else {
      // Set default if not found
      return null;
    }
  },
  
  async queryRulings(request: QueryRequest): Promise<QueryResponse> {
    try {
      // Add a slight delay to make loading states more visible for demo purposes
      await delay(1000);

      const API_URL = await this.getApiUrl();
      
      if (!API_URL) {
        return {
          answer: "<think>The user hasn't configured an API endpoint yet. I should provide a helpful response.</think>\n\nIt looks like you haven't configured the API endpoint yet. Please go to Settings and enter your API URL to connect to your data source."
        };
      }
      
      const response = await fetch(`${API_URL}/query`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(request),
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        const errorMessage = errorData.detail || `Error: ${response.status} ${response.statusText}`;
        toast.error(errorMessage);
        throw new Error(errorMessage);
      }

      const result = await response.json();
      
      // Store sources in storage for later use on sources page
      if (result.retrieved_sources && result.retrieved_sources.length > 0) {
        // Get existing sources or initialize empty array
        const existingSources = storage.get<RetrievedSource[]>(STORAGE_KEYS.SOURCES) || [];
        
        // Merge new sources, avoid duplicates based on content
        const updatedSources = [...existingSources];
        
        result.retrieved_sources.forEach((source: RetrievedSource) => {
          const exists = existingSources.some(
            existing => existing.content_snippet === source.content_snippet
          );
          
          if (!exists) {
            updatedSources.push(source);
          }
        });
        
        // Store updated sources
        storage.set(STORAGE_KEYS.SOURCES, updatedSources);
      }

      return result;
    } catch (error) {
      console.error("Failed to query AI:", error);
      const errorMessage = error instanceof Error ? error.message : "Failed to get a response";
      toast.error(errorMessage);
      throw error;
    }
  },
  
  async generateTitle(query: string): Promise<TitleResponse> {
    try {
      const API_URL = await this.getApiUrl();
      
      // If no API URL is configured, return a generic title
      if (!API_URL) {
        return { title: query.slice(0, 30) + (query.length > 30 ? '...' : '') };
      }
      
      const response = await fetch(`${API_URL}/generate-title`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ query }),
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        const errorMessage = errorData.detail || `Error: ${response.status} ${response.statusText}`;
        throw new Error(errorMessage);
      }

      return await response.json();
    } catch (error) {
      console.error("Failed to generate title:", error);
      // Return a default title instead of throwing
      return { title: "New Chat" };
    }
  }
};