355 lines
11 KiB
TypeScript
355 lines
11 KiB
TypeScript
export type OracleCanvasView =
|
|
| 'pipeline'
|
|
| 'team_performance'
|
|
| 'account_timeline'
|
|
| 'lead_map'
|
|
| 'calendar_tasks';
|
|
|
|
export interface OracleQueryPayload {
|
|
prompt: string;
|
|
history: Array<{ role: 'user' | 'assistant'; content: string }>;
|
|
mode: 'cot-rag';
|
|
preferredView?: OracleCanvasView;
|
|
}
|
|
|
|
export interface PipelineCardData {
|
|
id: string;
|
|
name: string;
|
|
company: string;
|
|
value: string;
|
|
avatar: string;
|
|
}
|
|
|
|
export interface TeamMemberData {
|
|
id: string;
|
|
name: string;
|
|
dealsClosed: number;
|
|
revenueGenerated: string;
|
|
avatar: string;
|
|
}
|
|
|
|
export interface TimelineEvent {
|
|
id: string;
|
|
type: 'email' | 'meeting' | 'call';
|
|
title: string;
|
|
when: string;
|
|
summary: string;
|
|
}
|
|
|
|
export interface CalendarEventData {
|
|
id: string;
|
|
day: string;
|
|
time: string;
|
|
title: string;
|
|
suggested?: boolean;
|
|
}
|
|
|
|
export interface OracleQueryResult {
|
|
view: OracleCanvasView;
|
|
insight: string;
|
|
summary: string;
|
|
payload: {
|
|
pipeline?: Record<string, PipelineCardData[]>;
|
|
revenueSeries?: Array<{ month: string; revenue: number; goal: number }>;
|
|
quotaAttainment?: number;
|
|
team?: TeamMemberData[];
|
|
account?: {
|
|
name: string;
|
|
totalDealValue: string;
|
|
primaryContact: string;
|
|
industry: string;
|
|
contacts: Array<{ name: string; role: string; avatar: string }>;
|
|
timeline: TimelineEvent[];
|
|
};
|
|
map?: {
|
|
region: string;
|
|
pins: Array<{
|
|
id: string;
|
|
label: string;
|
|
x: number;
|
|
y: number;
|
|
temperature: 'cold' | 'warm' | 'hot';
|
|
count?: number;
|
|
}>;
|
|
};
|
|
calendar?: {
|
|
weekLabel: string;
|
|
events: CalendarEventData[];
|
|
tasks: Array<{ id: string; title: string; subtitle: string; due: string }>;
|
|
};
|
|
};
|
|
}
|
|
|
|
export const DEFAULT_ORACLE_RESULT: OracleQueryResult = {
|
|
view: 'pipeline',
|
|
insight: 'Pipeline Velocity: Average deal cycle is 21 days, 10% faster than Q3.',
|
|
summary: 'Pipeline view generated for Q4 by stage.',
|
|
payload: {
|
|
pipeline: {
|
|
'New Leads': [
|
|
{
|
|
id: 'n1',
|
|
name: 'Elena Rostova',
|
|
company: 'Rostova Ventures',
|
|
value: '$120k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
id: 'n2',
|
|
name: 'Mary Iluskimon',
|
|
company: 'Nexloop',
|
|
value: '$130k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1554151228-14d9def656e4?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
],
|
|
Qualified: [
|
|
{
|
|
id: 'q1',
|
|
name: 'Etlena Roya',
|
|
company: 'Mianaperson',
|
|
value: '$120k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
id: 'q2',
|
|
name: 'Silver Rostova',
|
|
company: 'Silverline Co',
|
|
value: '$130k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1542206395-9feb3edaa68d?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
],
|
|
'Proposal Sent': [
|
|
{
|
|
id: 'p1',
|
|
name: 'Magulanta Senneciton',
|
|
company: 'Senneciton',
|
|
value: '$140k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
id: 'p2',
|
|
name: 'Minatie Ganrison',
|
|
company: 'Ganrison Group',
|
|
value: '$130k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
],
|
|
Negotiation: [
|
|
{
|
|
id: 'g1',
|
|
name: 'Jomath Bilotmberg',
|
|
company: 'Biotmberg',
|
|
value: '$130k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
id: 'g2',
|
|
name: 'Josen Oateliars',
|
|
company: 'Oateliars',
|
|
value: '$100k',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|
|
|
|
const VIEW_TO_PROMPT: Record<OracleCanvasView, string> = {
|
|
pipeline: 'Show me a pipeline view by stage for Q4.',
|
|
team_performance: "What's the performance of the sales team this month?",
|
|
account_timeline: "Find all contacts at 'Apex Innovations' and their recent activity.",
|
|
lead_map: 'Give me a map of all leads in California.',
|
|
calendar_tasks: 'Schedule a follow-up with the top 3 high-value leads.',
|
|
};
|
|
|
|
export function mockOracleResultForPrompt(prompt: string): OracleQueryResult {
|
|
const text = prompt.toLowerCase();
|
|
if (text.includes('performance') || text.includes('team')) {
|
|
return {
|
|
view: 'team_performance',
|
|
insight: 'Team is on track to exceed monthly quota by 15%.',
|
|
summary: 'Performance dashboard for current month.',
|
|
payload: {
|
|
revenueSeries: [
|
|
{ month: 'Jan', revenue: 10, goal: 20 },
|
|
{ month: 'Feb', revenue: 30, goal: 35 },
|
|
{ month: 'Mar', revenue: 28, goal: 40 },
|
|
{ month: 'Sep', revenue: 52, goal: 55 },
|
|
{ month: 'Oct', revenue: 56, goal: 60 },
|
|
{ month: 'Nov', revenue: 74, goal: 70 },
|
|
{ month: 'Dec', revenue: 88, goal: 80 },
|
|
],
|
|
quotaAttainment: 85,
|
|
team: [
|
|
{
|
|
id: 't1',
|
|
name: 'Elena Rostova',
|
|
dealsClosed: 12,
|
|
revenueGenerated: '$1.2M',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
id: 't2',
|
|
name: 'Etlena Roya',
|
|
dealsClosed: 12,
|
|
revenueGenerated: '$1.2M',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
id: 't3',
|
|
name: 'Minatie Ganrison',
|
|
dealsClosed: 13,
|
|
revenueGenerated: '$1.2M',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
id: 't4',
|
|
name: 'Josen Oateliars',
|
|
dealsClosed: 18,
|
|
revenueGenerated: '$0.8M',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
],
|
|
},
|
|
};
|
|
}
|
|
if (text.includes('apex') || text.includes('activity') || text.includes('contacts')) {
|
|
return {
|
|
view: 'account_timeline',
|
|
insight: "Action: Schedule a check-in call with Apex's CEO regarding the proposal.",
|
|
summary: 'Account history and associated contacts for Apex Innovations.',
|
|
payload: {
|
|
account: {
|
|
name: 'Apex Innovations',
|
|
totalDealValue: '$4.5M',
|
|
primaryContact: 'Elena Rostova, CEO',
|
|
industry: 'Technology',
|
|
contacts: [
|
|
{
|
|
name: 'Elena Rostova',
|
|
role: 'CEO',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
name: 'Mary Iluskimon',
|
|
role: 'COO',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1554151228-14d9def656e4?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
{
|
|
name: 'Entin Veenos',
|
|
role: 'VP Finance',
|
|
avatar:
|
|
'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&w=80&q=80',
|
|
},
|
|
],
|
|
timeline: [
|
|
{
|
|
id: 'a1',
|
|
type: 'email',
|
|
title: 'Email Sent',
|
|
when: 'Today, 10:30 AM',
|
|
summary: 'Proposal Follow-up',
|
|
},
|
|
{
|
|
id: 'a2',
|
|
type: 'meeting',
|
|
title: 'Meeting',
|
|
when: 'Yesterday, 2:00 PM',
|
|
summary: 'Q4 Strategy',
|
|
},
|
|
{
|
|
id: 'a3',
|
|
type: 'call',
|
|
title: 'Call Logged',
|
|
when: 'Yesterday, 6:20 PM',
|
|
summary: 'Discussed pricing',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
if (text.includes('map') || text.includes('california') || text.includes('geographic')) {
|
|
return {
|
|
view: 'lead_map',
|
|
insight: 'Insight: 60% of high-value leads are concentrated in the Bay Area.',
|
|
summary: 'Geographic lead distribution in California.',
|
|
payload: {
|
|
map: {
|
|
region: 'California',
|
|
pins: [
|
|
{ id: 'm1', label: 'SF', x: 26, y: 32, temperature: 'warm', count: 24 },
|
|
{ id: 'm2', label: 'Oakland', x: 29, y: 35, temperature: 'cold', count: 19 },
|
|
{ id: 'm3', label: 'San Jose', x: 32, y: 42, temperature: 'hot' },
|
|
{ id: 'm4', label: 'LA', x: 44, y: 78, temperature: 'warm', count: 8 },
|
|
{ id: 'm5', label: 'San Diego', x: 46, y: 88, temperature: 'cold' },
|
|
{ id: 'm6', label: 'Sacramento', x: 36, y: 28, temperature: 'hot' },
|
|
],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
if (text.includes('schedule') || text.includes('calendar') || text.includes('follow-up')) {
|
|
return {
|
|
view: 'calendar_tasks',
|
|
insight:
|
|
"Scheduling: Proposed times minimize conflicts and align with contact's preferred hours.",
|
|
summary: 'Weekly calendar and follow-up actions generated.',
|
|
payload: {
|
|
calendar: {
|
|
weekLabel: 'Week 21',
|
|
events: [
|
|
{ id: 'c1', day: 'Mon', time: '10:00', title: 'Elena Rostova' },
|
|
{ id: 'c2', day: 'Tue', time: '12:00', title: 'Appointments' },
|
|
{ id: 'c3', day: 'Wed', time: '13:00', title: 'Follow-up', suggested: true },
|
|
{ id: 'c4', day: 'Thu', time: '14:00', title: 'Meeting' },
|
|
{ id: 'c5', day: 'Fri', time: '12:00', title: 'Follow-up', suggested: true },
|
|
],
|
|
tasks: [
|
|
{ id: 'k1', title: 'Follow-up', subtitle: 'Elena Rostova', due: 'Due Today' },
|
|
{ id: 'k2', title: 'Prepare Proposal', subtitle: 'Apex Innovations', due: 'Due Tomorrow' },
|
|
{ id: 'k3', title: 'Confirm Slot', subtitle: 'Mr. Kapoor', due: 'Due Today' },
|
|
],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
return DEFAULT_ORACLE_RESULT;
|
|
}
|
|
|
|
export async function queryOracle(payload: OracleQueryPayload): Promise<OracleQueryResult> {
|
|
const endpoint = import.meta.env.VITE_ORACLE_QUERY_URL;
|
|
if (!endpoint) {
|
|
if (payload.preferredView) {
|
|
return mockOracleResultForPrompt(VIEW_TO_PROMPT[payload.preferredView]);
|
|
}
|
|
return mockOracleResultForPrompt(payload.prompt);
|
|
}
|
|
|
|
const response = await fetch(endpoint, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Oracle query failed with ${response.status}`);
|
|
}
|
|
|
|
return (await response.json()) as OracleQueryResult;
|
|
}
|