File size: 4,494 Bytes
0c591a7
 
 
3e0da39
 
0c591a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255d8a9
0c591a7
 
5766b78
0c591a7
 
255d8a9
 
 
 
33d2228
0c591a7
 
 
 
5766b78
0c591a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
de4ad41
0c591a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3e0da39
 
 
 
 
 
 
0c591a7
 
 
 
3e0da39
 
 
0c591a7
 
 
 
 
 
 
 
 
3e0da39
 
 
0c591a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { AnalysisResponse } from './types'

// In production (HF Spaces), API is served from same origin - use empty string
// In development, use localhost:8000 (8002 is used by financials cluster)
const API_BASE_URL = import.meta.env.VITE_API_URL ?? (import.meta.env.PROD ? '' : 'http://localhost:8000')

// Stock search types
export interface StockResult {
  symbol: string
  name: string
  exchange: string
  match_type: string
}

export interface StockSearchResponse {
  query: string
  results: StockResult[]
}

// Activity log entry
export interface ActivityLogEntry {
  timestamp: string
  step: string
  message: string
}

// Granular metric entry with optional temporal data
export interface MetricEntry {
  timestamp: string
  source: string   // "volatility", "valuation", "fundamentals", etc.
  metric: string   // "beta", "P/E", "revenue", etc.
  value: string | number
  // Temporal fields (from SEC EDGAR data)
  end_date?: string       // Fiscal period end date, e.g., "2023-09-30"
  fiscal_year?: number    // Fiscal year number, e.g., 2023
  form?: string           // SEC form type: "10-K" (annual) or "10-Q" (quarterly)
  data_source?: string    // Actual data source: "sec_edgar" or "yahoo_finance"
}

// MCP status for each server (partial = some data but with errors)
export interface MCPStatus {
  fundamentals: 'idle' | 'executing' | 'completed' | 'partial' | 'failed'
  valuation: 'idle' | 'executing' | 'completed' | 'partial' | 'failed'
  volatility: 'idle' | 'executing' | 'completed' | 'partial' | 'failed'
  macro: 'idle' | 'executing' | 'completed' | 'partial' | 'failed'
  news: 'idle' | 'executing' | 'completed' | 'partial' | 'failed'
  sentiment: 'idle' | 'executing' | 'completed' | 'partial' | 'failed'
}

// LLM provider status
export interface LLMStatus {
  groq: 'idle' | 'executing' | 'completed' | 'failed'
  gemini: 'idle' | 'executing' | 'completed' | 'failed'
  openrouter: 'idle' | 'executing' | 'completed' | 'failed'
}

// Workflow status with activity log and MCP status
export interface WorkflowStatus {
  status: 'starting' | 'running' | 'completed' | 'error' | 'aborted'
  current_step: 'input' | 'cache' | 'researcher' | 'analyzer' | 'critic' | 'output' | 'completed'
  revision_count: number
  score: number
  activity_log: ActivityLogEntry[]
  metrics: MetricEntry[]
  mcp_status: MCPStatus
  llm_status: LLMStatus
  provider_used?: string
  data_source?: string
  error?: string  // Error message for error/aborted states
}

export interface WorkflowStartResponse {
  workflow_id: string
}

// Search stocks by query
export async function searchStocks(query: string): Promise<StockSearchResponse> {
  const response = await fetch(`${API_BASE_URL}/api/stocks/search?q=${encodeURIComponent(query)}`)

  if (!response.ok) {
    throw new Error('Failed to search stocks')
  }

  return response.json()
}

// User API keys for LLM providers
export interface UserApiKeys {
  groq?: string
  gemini?: string
  openrouter?: string
}

// Start analysis with ticker support
export async function startAnalysis(
  companyName: string,
  ticker: string = '',
  strategyFocus: string = 'Competitive Position',
  skipCache: boolean = false,
  userApiKeys: UserApiKeys = {}
): Promise<WorkflowStartResponse> {
  const response = await fetch(`${API_BASE_URL}/analyze`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: companyName,
      ticker: ticker,
      strategy_focus: strategyFocus,
      skip_cache: skipCache,
      user_api_keys: userApiKeys
    }),
  })

  if (!response.ok) {
    throw new Error('Failed to start analysis')
  }

  return response.json()
}

export async function getWorkflowStatus(workflowId: string): Promise<WorkflowStatus> {
  const response = await fetch(`${API_BASE_URL}/workflow/${workflowId}/status`)

  if (!response.ok) {
    throw new Error('Failed to get workflow status')
  }

  return response.json()
}

export async function getWorkflowResult(workflowId: string): Promise<AnalysisResponse> {
  const response = await fetch(`${API_BASE_URL}/workflow/${workflowId}/result`)

  if (!response.ok) {
    throw new Error('Failed to get workflow result')
  }

  return response.json()
}

export async function checkHealth(): Promise<{ status: string; active_workflows?: number }> {
  const response = await fetch(`${API_BASE_URL}/health`)

  if (!response.ok) {
    throw new Error('API health check failed')
  }

  return response.json()
}