File size: 3,953 Bytes
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

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>;
}

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

export const rulingService = {
  async getApiUrl(): Promise<string> {
    // Get API URL from storage or use default
    let API_URL = "http://localhost:8000";
    const storedUrl = storage.get<string>(STORAGE_KEYS.API_ENDPOINT);
    
    if (storedUrl) {
      API_URL = storedUrl;
    } else {
      // Set default if not found
      storage.set(STORAGE_KEYS.API_ENDPOINT, API_URL);
    }
    
    return API_URL;
  },
  
  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();
      
      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 rulings:", error);
      const errorMessage = error instanceof Error ? error.message : "Failed to query rulings";
      toast.error(errorMessage);
      throw error;
    }
  },
  
  async generateTitle(query: string): Promise<TitleResponse> {
    try {
      const API_URL = await this.getApiUrl();
      
      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" };
    }
  }
};