Spaces:
Sleeping
Sleeping
File size: 3,812 Bytes
2a5d15a c86876a 2a5d15a 6737a45 2a5d15a | 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 146 147 148 149 150 151 152 153 154 155 156 | /**
* FinBot API Client
* =================
* Connects the Next.js frontend to the IRIS API proxy.
* The proxy forwards to FastAPI when available and serves validated cached
* Investor Relations responses when the backend process is warming up.
*/
export const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || '/api/proxy';
export interface Source {
id: number;
doc_name: string;
page: number;
support: string;
image_url?: string;
}
export interface KPIRow {
metric: string;
current: string;
previous: string;
change: string;
interpretation: string;
direction: 'positive' | 'negative' | 'neutral';
period?: string;
value?: string;
}
export interface Driver {
title: string;
detail: string;
}
export interface VisualItem {
id: string;
page: number;
image_url: string;
alt: string;
}
export interface ChatResponse {
response_type: 'ir_response' | 'unsupported' | 'insufficient';
question: string;
executive_summary?: string;
sources: Source[];
financial_kpis: KPIRow[];
key_drivers_summary?: string;
key_drivers: Driver[];
visual_evidence: VisualItem[];
latency_ms: number;
model_used: string;
}
export interface Document {
doc_id: string;
name: string;
doc_type: string;
period: string;
institution?: string;
total_pages: number;
status: string;
filename: string;
chunks_indexed?: number;
tables_indexed?: number;
colpali_pages?: number;
pagemap_file?: string;
page_section_map?: Record<string, string>;
page_metadata_map?: Record<string, {
slide: number;
section: string;
mapping_items: string[];
kpis: string[];
kpi_tags: string[];
description: string;
period: string;
synonyms: string[];
visual_layout: string;
}>;
retrieval_config?: string;
}
/** Check if the backend is reachable */
export async function checkBackendHealth(): Promise<boolean> {
try {
const res = await fetch(`${BACKEND_URL}/api/health`, {
signal: AbortSignal.timeout(2000),
});
return res.ok;
} catch {
return false;
}
}
/** Submit a question to the RAG pipeline */
export async function submitQuestion(
question: string,
docIds: string[],
): Promise<ChatResponse> {
const res = await fetch(`${BACKEND_URL}/api/chat/query`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question, doc_ids: docIds }),
signal: AbortSignal.timeout(120_000), // ColPali can take time
});
if (!res.ok) {
const err = await res.text();
throw new Error(`Backend error ${res.status}: ${err}`);
}
return res.json();
}
/** Get list of indexed documents */
export async function fetchDocuments(): Promise<Document[]> {
const res = await fetch(`${BACKEND_URL}/api/documents/`, {
signal: AbortSignal.timeout(5000),
});
if (!res.ok) throw new Error('Failed to fetch documents');
return res.json();
}
/** Get the URL for a page image (rendered PDF page) */
export function getPageImageUrl(docId: string, pageNumber: number): string {
return `${BACKEND_URL}/api/visuals/${docId}/${pageNumber}`;
}
/** Normalize legacy static page URLs to the backend visual route. */
export function normalizePageImageUrl(
imageUrl: string | undefined,
fallbackDocId: string,
fallbackPage: number,
): string {
if (!imageUrl) {
return getPageImageUrl(fallbackDocId, fallbackPage);
}
const legacyPageMatch = imageUrl.match(
/\/pages\/([^/]+)\/pages\/page_(\d{4})(?:_[^/.]+)?\.png$/,
);
if (legacyPageMatch) {
return getPageImageUrl(legacyPageMatch[1], Number.parseInt(legacyPageMatch[2], 10));
}
if (imageUrl.startsWith('/api/visuals/')) {
return `${BACKEND_URL}${imageUrl}`;
}
if (imageUrl.startsWith('/')) {
return `${BACKEND_URL}${imageUrl}`;
}
return imageUrl;
}
|