admin08077 commited on
Commit
e253bc0
·
verified ·
1 Parent(s): 39a2130

Upload 4 files

Browse files
services/api.ts ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ InternalAccount,
3
+ CitiTransaction,
4
+ CustomerProfileResponse,
5
+ AuthResponse,
6
+ UserSession,
7
+ AccountsGroupDetailsList
8
+ } from '../types/index';
9
+
10
+ // Unified mock account data consistent with Citi OpenAPI structures
11
+ const MOCK_ACCOUNTS_LIST: InternalAccount[] = [
12
+ {
13
+ id: 'citi_acc_99201',
14
+ productName: 'Corporate Mastery Checking',
15
+ accountNickname: 'Main Ops Node',
16
+ displayAccountNumber: 'XXXXXX9594',
17
+ currency: 'USD',
18
+ status: 'ACTIVE',
19
+ currentBalance: 1245000.50,
20
+ availableBalance: 1240000.00,
21
+ institutionName: 'Citi US',
22
+ connectionId: 'CITI-G-001'
23
+ },
24
+ {
25
+ id: 'citi_acc_44102',
26
+ productName: 'Elite Treasury Savings',
27
+ displayAccountNumber: 'XXXXXX1022',
28
+ currency: 'USD',
29
+ status: 'ACTIVE',
30
+ currentBalance: 5200450.00,
31
+ availableBalance: 5200450.00,
32
+ institutionName: 'Citi US',
33
+ connectionId: 'CITI-G-002'
34
+ }
35
+ ];
36
+
37
+ export const apiClient = {
38
+ auth: {
39
+ async me(): Promise<AuthResponse> {
40
+ const user = localStorage.getItem('lumina_user');
41
+ return user ? { isAuthenticated: true, user: JSON.parse(user) } : { isAuthenticated: false, user: null };
42
+ },
43
+ async register(username: string, password: string) {
44
+ const users = JSON.parse(localStorage.getItem('lumina_registry') || '{}');
45
+ if (users[username]) return { success: false, error: 'Identity already exists.' };
46
+ users[username] = { password, role: 'Root Admin' };
47
+ localStorage.setItem('lumina_registry', JSON.stringify(users));
48
+ return { success: true };
49
+ },
50
+ async login(username: string, password?: string) {
51
+ const users = JSON.parse(localStorage.getItem('lumina_registry') || '{"alex":{"password":"password123","role":"Root Admin"}}');
52
+ if (users[username] && users[username].password === password) {
53
+ const user = { id: 'USR-1', name: username, role: users[username].role, lastLogin: new Date().toISOString() };
54
+ localStorage.setItem('lumina_user', JSON.stringify(user));
55
+ return { success: true, user };
56
+ }
57
+ return { success: false, error: 'Identity rejected credentials.' };
58
+ },
59
+ async logout() {
60
+ localStorage.removeItem('lumina_user');
61
+ return { success: true };
62
+ }
63
+ },
64
+ chat: {
65
+ async getHistory() {
66
+ return JSON.parse(localStorage.getItem('lumina_chat_history') || '[]');
67
+ },
68
+ async saveMessage(role: string, content: string) {
69
+ const history = JSON.parse(localStorage.getItem('lumina_chat_history') || '[]');
70
+ history.push({ id: Date.now(), role, content, timestamp: new Date().toISOString() });
71
+ localStorage.setItem('lumina_chat_history', JSON.stringify(history));
72
+ }
73
+ },
74
+ async getRegistryNodes(): Promise<InternalAccount[]> {
75
+ return MOCK_ACCOUNTS_LIST;
76
+ },
77
+ async getRegistryDetails(): Promise<AccountsGroupDetailsList> {
78
+ return {
79
+ accountGroupDetails: [
80
+ {
81
+ accountGroup: "CHECKING",
82
+ checkingAccountsDetails: MOCK_ACCOUNTS_LIST.filter(a => a.productName.includes('Checking')).map(a => ({
83
+ accountId: a.id,
84
+ productName: a.productName,
85
+ displayAccountNumber: a.displayAccountNumber,
86
+ currencyCode: a.currency,
87
+ accountStatus: a.status as 'ACTIVE',
88
+ currentBalance: a.currentBalance,
89
+ availableBalance: a.availableBalance,
90
+ accountDescription: a.productName,
91
+ balanceType: 'ASSET'
92
+ }))
93
+ }
94
+ ]
95
+ };
96
+ },
97
+ async getTransactions(accountId: string): Promise<CitiTransaction[]> {
98
+ return [
99
+ {
100
+ accountId,
101
+ currencyCode: 'USD',
102
+ transactionAmount: -25000.00,
103
+ transactionDate: new Date().toISOString().split('T')[0],
104
+ transactionDescription: 'QUANTUM_COMPUTE_Q3_ALLOCATION',
105
+ transactionId: 'TXN_C_' + Math.random().toString(36).substring(7).toUpperCase(),
106
+ transactionStatus: 'POSTED',
107
+ transactionType: 'PAYMENT',
108
+ displayAccountNumber: 'XXXXXX9594'
109
+ },
110
+ {
111
+ accountId,
112
+ currencyCode: 'USD',
113
+ transactionAmount: 14200.50,
114
+ transactionDate: new Date().toISOString().split('T')[0],
115
+ transactionDescription: 'NODE_ALPHA_INCENTIVE_PAYOUT',
116
+ transactionId: 'TXN_C_' + Math.random().toString(36).substring(7).toUpperCase(),
117
+ transactionStatus: 'POSTED',
118
+ transactionType: 'CREDIT',
119
+ displayAccountNumber: 'XXXXXX9594'
120
+ }
121
+ ];
122
+ },
123
+ async getStatements(): Promise<any> {
124
+ return {
125
+ statements: [
126
+ { statementId: 'STMT-001', statementDate: '2024-03-01', productFamily: 'Checking', accountId: 'citi_acc_99201' },
127
+ { statementId: 'STMT-002', statementDate: '2024-02-01', productFamily: 'Checking', accountId: 'citi_acc_99201' }
128
+ ]
129
+ };
130
+ },
131
+ async getStatementDetails(id: string): Promise<any> {
132
+ return {
133
+ dataPayload: JSON.stringify({
134
+ encryptedPayload: {
135
+ header: { alg: 'RSA-OAEP-4096', typ: 'JWT' },
136
+ iv: 'q7x2...m9l0',
137
+ data: 'base64_payload_artifact'
138
+ }
139
+ })
140
+ };
141
+ },
142
+ async getCustomerProfile(accountId: string): Promise<CustomerProfileResponse> {
143
+ return {
144
+ customer: { firstName: 'Alex', lastName: 'Rivera', title: 'Mx.', companyName: 'Lumina Quantum Systems' },
145
+ contacts: {
146
+ emails: ['a.rivera@luminaquantum.io'],
147
+ addresses: [{ addressLine1: '401 Quantum Drive', city: 'Palo Alto', region: 'CA', postalCode: '94304', country: 'US', type: 'BUSINESS' }],
148
+ phones: [{ type: 'CELL', country: '1', number: '9542312002' }]
149
+ }
150
+ };
151
+ }
152
+ };
services/cryptoService.ts ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import { CoinMarketData, CoinDetail, GlobalData, TrendingCoin, SearchResult } from '../types/index.ts';
3
+
4
+ const COINGECKO_BASE = 'https://api.coingecko.com/api/v3';
5
+
6
+ export interface MarketChartData {
7
+ prices: [number, number][];
8
+ market_caps: [number, number][];
9
+ total_volumes: [number, number][];
10
+ }
11
+
12
+ const MOCK_MARKETS: CoinMarketData[] = [
13
+ { id: 'bitcoin', symbol: 'btc', name: 'Bitcoin', image: 'https://assets.coingecko.com/coins/images/1/large/bitcoin.png', current_price: 64231.50, market_cap: 1260000000000, market_cap_rank: 1, fully_diluted_valuation: 1350000000000, total_volume: 35000000000, high_24h: 65000, low_24h: 63000, price_change_24h: 1231, price_change_percentage_24h: 1.95, market_cap_change_24h: 24000000000, market_cap_change_percentage_24h: 1.9, circulating_supply: 19600000, total_supply: 21000000, max_supply: 21000000, ath: 73000, ath_change_percentage: -12, ath_date: '2024-03-14', atl: 67, atl_change_percentage: 95000, atl_date: '2013-07-06', roi: null, last_updated: new Date().toISOString(), sparkline_in_7d: { price: [63000, 63500, 64000, 63800, 64500, 65000, 64231] } },
14
+ { id: 'ethereum', symbol: 'eth', name: 'Ethereum', image: 'https://assets.coingecko.com/coins/images/279/large/ethereum.png', current_price: 3450.20, market_cap: 415000000000, market_cap_rank: 2, fully_diluted_valuation: 415000000000, total_volume: 15000000000, high_24h: 3550, low_24h: 3350, price_change_24h: 50, price_change_percentage_24h: 1.45, market_cap_change_24h: 5000000000, market_cap_change_percentage_24h: 1.4, circulating_supply: 120000000, total_supply: 120000000, max_supply: null, ath: 4878, ath_change_percentage: -29, ath_date: '2021-11-10', atl: 0.42, atl_change_percentage: 820000, atl_date: '2015-10-20', roi: null, last_updated: new Date().toISOString(), sparkline_in_7d: { price: [3300, 3350, 3400, 3380, 3450, 3500, 3450] } },
15
+ { id: 'solana', symbol: 'sol', name: 'Solana', image: 'https://assets.coingecko.com/coins/images/4128/large/solana.png', current_price: 145.50, market_cap: 65000000000, market_cap_rank: 5, fully_diluted_valuation: 82000000000, total_volume: 4000000000, high_24h: 155, low_24h: 140, price_change_24h: -5, price_change_percentage_24h: -3.2, market_cap_change_24h: -2000000000, market_cap_change_percentage_24h: -3.1, circulating_supply: 445000000, total_supply: 570000000, max_supply: null, ath: 259, ath_change_percentage: -44, ath_date: '2021-11-06', atl: 0.50, atl_change_percentage: 29000, atl_date: '2020-05-11', roi: null, last_updated: new Date().toISOString(), sparkline_in_7d: { price: [150, 155, 152, 148, 145, 146, 145] } }
16
+ ];
17
+
18
+ export const cryptoService = {
19
+ ping: async () => {
20
+ try {
21
+ const res = await fetch(`${COINGECKO_BASE}/ping`, { mode: 'cors' });
22
+ return res.ok;
23
+ } catch {
24
+ return false;
25
+ }
26
+ },
27
+
28
+ getMarkets: async (vsCurrency: string = 'usd', perPage: number = 10, page: number = 1): Promise<CoinMarketData[]> => {
29
+ try {
30
+ const res = await fetch(
31
+ `${COINGECKO_BASE}/coins/markets?vs_currency=${vsCurrency}&order=market_cap_desc&per_page=${perPage}&page=${page}&sparkline=true&price_change_percentage=24h,7d`,
32
+ { mode: 'cors' }
33
+ );
34
+ if (!res.ok) throw new Error('Market data fetch failed');
35
+ return await res.json();
36
+ } catch (error) {
37
+ console.warn("Crypto API unavailable, using simulated node data", error);
38
+ return MOCK_MARKETS.slice(0, perPage);
39
+ }
40
+ },
41
+
42
+ getCoinById: async (id: string): Promise<CoinDetail | null> => {
43
+ try {
44
+ const res = await fetch(`${COINGECKO_BASE}/coins/${id}?localization=false&tickers=true&market_data=true&community_data=true&developer_data=true&sparkline=true`, { mode: 'cors' });
45
+ if (!res.ok) throw new Error('Coin details fetch failed');
46
+ return await res.json();
47
+ } catch (error) {
48
+ console.warn(`Details for ${id} unavailable`, error);
49
+ const mock = MOCK_MARKETS.find(m => m.id === id) as any;
50
+ if (mock) {
51
+ return {
52
+ ...mock,
53
+ description: { en: `Institutional-grade ledger summary for ${mock.name}. Handshake verified.` },
54
+ links: { homepage: ['#'], blockchain_site: ['#'], official_forum_url: [], chat_url: [], announcement_url: [], twitter_screen_name: '', facebook_username: '', bitcointalk_thread_identifier: null, telegram_channel_identifier: '', subreddit_url: '', repos_url: { github: [], bitbucket: [] } },
55
+ genesis_date: '2009-01-03',
56
+ sentiment_votes_up_percentage: 85,
57
+ sentiment_votes_down_percentage: 15
58
+ };
59
+ }
60
+ return null;
61
+ }
62
+ },
63
+
64
+ getMarketChart: async (id: string, days: string = '7', vsCurrency: string = 'usd'): Promise<MarketChartData | null> => {
65
+ try {
66
+ const res = await fetch(`${COINGECKO_BASE}/coins/${id}/market_chart?vs_currency=${vsCurrency}&days=${days}`, { mode: 'cors' });
67
+ if (!res.ok) throw new Error('Market chart fetch failed');
68
+ return await res.json();
69
+ } catch (error) {
70
+ console.warn(`Chart data for ${id} unavailable`, error);
71
+ const mock = MOCK_MARKETS.find(m => m.id === id);
72
+ if (mock) {
73
+ const now = Date.now();
74
+ const prices: [number, number][] = mock.sparkline_in_7d!.price.map((p, i) => [now - (7 - i) * 86400000, p]);
75
+ return { prices, market_caps: [], total_volumes: [] };
76
+ }
77
+ return null;
78
+ }
79
+ },
80
+
81
+ getGlobal: async (): Promise<GlobalData | null> => {
82
+ try {
83
+ const res = await fetch(`${COINGECKO_BASE}/global`, { mode: 'cors' });
84
+ if (!res.ok) throw new Error('Global data fetch failed');
85
+ const data = await res.json();
86
+ return data.data;
87
+ } catch (error) {
88
+ console.warn("Global market metrics unavailable", error);
89
+ return {
90
+ active_cryptocurrencies: 12400,
91
+ upcoming_icos: 0,
92
+ ongoing_icos: 42,
93
+ ended_icos: 3401,
94
+ markets: 900,
95
+ total_market_cap: { usd: 2400000000000 },
96
+ total_volume: { usd: 85000000000 },
97
+ market_cap_percentage: { btc: 52.1, eth: 17.2 },
98
+ market_cap_change_percentage_24h_usd: 1.2,
99
+ updated_at: Date.now() / 1000
100
+ };
101
+ }
102
+ },
103
+
104
+ getTrending: async (): Promise<TrendingCoin[]> => {
105
+ try {
106
+ const res = await fetch(`${COINGECKO_BASE}/search/trending`, { mode: 'cors' });
107
+ if (!res.ok) throw new Error('Trending fetch failed');
108
+ const data = await res.json();
109
+ return data.coins;
110
+ } catch (error) {
111
+ console.warn("Trending data unavailable", error);
112
+ return MOCK_MARKETS.map((m, i) => ({
113
+ item: {
114
+ id: m.id,
115
+ coin_id: i,
116
+ name: m.name,
117
+ symbol: m.symbol,
118
+ market_cap_rank: m.market_cap_rank,
119
+ thumb: m.image,
120
+ small: m.image,
121
+ large: m.image,
122
+ slug: m.id,
123
+ price_btc: 1,
124
+ score: i,
125
+ data: {
126
+ price: m.current_price,
127
+ price_btc: '1',
128
+ price_change_percentage_24h: { usd: m.price_change_percentage_24h },
129
+ market_cap: m.market_cap.toString(),
130
+ total_volume: m.total_volume.toString(),
131
+ sparkline: ''
132
+ }
133
+ }
134
+ }));
135
+ }
136
+ },
137
+
138
+ search: async (query: string): Promise<SearchResult | null> => {
139
+ try {
140
+ const res = await fetch(`${COINGECKO_BASE}/search?query=${query}`, { mode: 'cors' });
141
+ if (!res.ok) throw new Error('Search failed');
142
+ return await res.json();
143
+ } catch (error) {
144
+ console.warn(`Search for ${query} unavailable`, error);
145
+ return {
146
+ coins: MOCK_MARKETS.filter(m => m.name.toLowerCase().includes(query.toLowerCase())).map(m => ({
147
+ id: m.id,
148
+ name: m.name,
149
+ api_symbol: m.symbol,
150
+ symbol: m.symbol,
151
+ market_cap_rank: m.market_cap_rank,
152
+ thumb: m.image,
153
+ large: m.image
154
+ })),
155
+ exchanges: [],
156
+ nfts: [],
157
+ categories: []
158
+ };
159
+ }
160
+ }
161
+ };
services/geminiService.ts ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import { GoogleGenAI, Type, Modality } from "@google/genai";
3
+ import { SimulationResult, AIInsight } from "../types/index";
4
+
5
+ // Direct initialization as per instructions
6
+ const getAI = () => new GoogleGenAI({ apiKey: process.env.API_KEY as string });
7
+
8
+ export { Type, Modality };
9
+
10
+ export const TTS_LANGUAGES = [
11
+ { name: 'English', code: 'en' }, { name: 'French', code: 'fr' }, { name: 'German', code: 'de' },
12
+ { name: 'Spanish', code: 'es' }, { name: 'Portuguese', code: 'pt' }, { name: 'Chinese', code: 'zh' },
13
+ { name: 'Japanese', code: 'ja' }, { name: 'Korean', code: 'ko' }, { name: 'Hindi', code: 'hi' },
14
+ ];
15
+
16
+ export const TTS_VOICES = [
17
+ { name: 'Zephyr', style: 'Bright' }, { name: 'Puck', style: 'Upbeat' }, { name: 'Charon', style: 'Informative' },
18
+ { name: 'Kore', style: 'Firm' }, { name: 'Fenrir', style: 'Excitable' }, { name: 'Leda', style: 'Youthful' }
19
+ ];
20
+
21
+ function decodeBase64(base64: string) {
22
+ const binaryString = atob(base64);
23
+ const bytes = new Uint8Array(binaryString.length);
24
+ for (let i = 0; i < binaryString.length; i++) {
25
+ bytes[i] = binaryString.charCodeAt(i);
26
+ }
27
+ return bytes;
28
+ }
29
+
30
+ async function decodeAudioData(data: Uint8Array, ctx: AudioContext, sampleRate: number, numChannels: number): Promise<AudioBuffer> {
31
+ const byteLen = data.byteLength - (data.byteLength % 2);
32
+ const dataInt16 = new Int16Array(data.buffer, 0, byteLen / 2);
33
+ const frameCount = dataInt16.length / numChannels;
34
+ const buffer = ctx.createBuffer(numChannels, frameCount, sampleRate);
35
+ for (let channel = 0; channel < numChannels; channel++) {
36
+ const channelData = buffer.getChannelData(channel);
37
+ for (let i = 0; i < frameCount; i++) {
38
+ channelData[i] = dataInt16[i * numChannels + channel] / 32768.0;
39
+ }
40
+ }
41
+ return buffer;
42
+ }
43
+
44
+ let audioContext: AudioContext | null = null;
45
+ export const getAudioContext = () => {
46
+ if (!audioContext) {
47
+ audioContext = new (window.AudioContext || (window as any).webkitAudioContext)({ sampleRate: 24000 });
48
+ }
49
+ return audioContext;
50
+ };
51
+
52
+ // fix: Added support for multi-speaker synthesis and updated config type signature
53
+ export const synthesizeSpeech = async (config: {
54
+ text: string,
55
+ voiceName: string,
56
+ directorNotes?: string,
57
+ multiSpeaker?: { speaker1: string, voice1: string, speaker2: string, voice2: string }
58
+ }) => {
59
+ try {
60
+ const ai = getAI();
61
+ const promptText = config.directorNotes ? `${config.directorNotes} ${config.text}` : config.text;
62
+
63
+ // fix: Define speechConfig based on presence of multi-speaker configuration
64
+ const speechConfig: any = config.multiSpeaker ? {
65
+ multiSpeakerVoiceConfig: {
66
+ speakerVoiceConfigs: [
67
+ {
68
+ speaker: config.multiSpeaker.speaker1,
69
+ voiceConfig: { prebuiltVoiceConfig: { voiceName: config.multiSpeaker.voice1 } }
70
+ },
71
+ {
72
+ speaker: config.multiSpeaker.speaker2,
73
+ voiceConfig: { prebuiltVoiceConfig: { voiceName: config.multiSpeaker.voice2 } }
74
+ }
75
+ ]
76
+ }
77
+ } : {
78
+ voiceConfig: { prebuiltVoiceConfig: { voiceName: config.voiceName } }
79
+ };
80
+
81
+ const response = await ai.models.generateContent({
82
+ model: "gemini-2.5-flash-preview-tts",
83
+ contents: [{ parts: [{ text: promptText }] }],
84
+ config: {
85
+ responseModalities: [Modality.AUDIO],
86
+ speechConfig
87
+ }
88
+ });
89
+ const base64Audio = response.candidates?.[0]?.content?.parts?.[0]?.inlineData?.data;
90
+ if (base64Audio) {
91
+ const ctx = getAudioContext();
92
+ if (ctx.state === 'suspended') await ctx.resume();
93
+ const audioBuffer = await decodeAudioData(decodeBase64(base64Audio), ctx, 24000, 1);
94
+ const source = ctx.createBufferSource();
95
+ source.buffer = audioBuffer;
96
+ source.connect(ctx.destination);
97
+ source.start();
98
+ return true;
99
+ }
100
+ } catch (error) {
101
+ console.error("Advanced Synthesis failure:", error);
102
+ }
103
+ return false;
104
+ };
105
+
106
+ export const speakText = async (text: string) => synthesizeSpeech({ text, voiceName: 'Zephyr' });
107
+
108
+ export const callGemini = async (model: string, contents: any, config: any = {}) => {
109
+ const ai = getAI();
110
+ const normalizedContents = typeof contents === 'string' ? [{ parts: [{ text: contents }] }] :
111
+ (Array.isArray(contents) ? contents : [contents]);
112
+ return await ai.models.generateContent({
113
+ model: model || 'gemini-3-flash-preview',
114
+ contents: normalizedContents,
115
+ config
116
+ });
117
+ };
118
+
119
+ export const processVoiceCommand = async (command: string) => {
120
+ try {
121
+ const prompt = `You are the Lumina Neural Parser. Analyze: "${command}". Extract amount, recipient, category. Return ONLY JSON: { "action": "SEND_MONEY", "amount": number, "recipient": string, "category": string, "narration": "Confirming dispatch..." }`;
122
+ const response = await callGemini('gemini-3-flash-preview', prompt, { responseMimeType: "application/json" });
123
+ return JSON.parse(response.text || '{}');
124
+ } catch (error) {
125
+ return { action: "ERROR", narration: "Communication link unstable." };
126
+ }
127
+ };
128
+
129
+ export const getFinancialAdviceStream = async (query: string, context: any) => {
130
+ const ai = getAI();
131
+ return await ai.models.generateContentStream({
132
+ model: 'gemini-3-flash-preview',
133
+ contents: [{ parts: [{ text: `Context: ${JSON.stringify(context)}. User Query: ${query}` }] }],
134
+ config: { systemInstruction: "You are the Lumina Quantum Financial Advisor. Be professional, concise, and technically accurate." }
135
+ });
136
+ };
137
+
138
+ // fix: Implemented getSystemIntelligenceFeed missing in services/geminiService.ts
139
+ export const getSystemIntelligenceFeed = async (): Promise<AIInsight[]> => {
140
+ try {
141
+ const ai = getAI();
142
+ const response = await ai.models.generateContent({
143
+ model: 'gemini-3-flash-preview',
144
+ contents: [{ parts: [{ text: "Generate 4 brief institutional financial intelligence alerts for a quantum ledger. Format as JSON array: [{title, description, severity: 'INFO'|'CRITICAL'}]" }] }],
145
+ config: { responseMimeType: "application/json" }
146
+ });
147
+ return JSON.parse(response.text || '[]');
148
+ } catch (error) {
149
+ console.error("Intelligence feed failure:", error);
150
+ return [
151
+ { id: '1', title: "Node Sync Active", description: "All global registry nodes reporting stable parity.", severity: "INFO" }
152
+ ];
153
+ }
154
+ };
155
+
156
+ export const runSimulationForecast = async (prompt: string): Promise<SimulationResult> => {
157
+ try {
158
+ const ai = getAI();
159
+ const response = await ai.models.generateContent({
160
+ model: 'gemini-3-flash-preview',
161
+ contents: [{ parts: [{ text: `Perform financial simulation for: ${prompt}. Return JSON.` }] }],
162
+ config: { responseMimeType: "application/json" }
163
+ });
164
+ return JSON.parse(response.text || '{}');
165
+ } catch (error) {
166
+ return { outcomeNarrative: "Simulation failed.", projectedValue: 0, confidenceScore: 0, status: "ERROR", simulationId: "ERR_A1" };
167
+ }
168
+ };
169
+
170
+ export const getPortfolioSuggestions = async (context: any) => {
171
+ try {
172
+ const ai = getAI();
173
+ const response = await ai.models.generateContent({
174
+ model: 'gemini-3-flash-preview',
175
+ contents: [{ parts: [{ text: `Strategize for: ${JSON.stringify(context)}. Return 3 strategies as JSON array.` }] }],
176
+ config: { responseMimeType: "application/json" }
177
+ });
178
+ return JSON.parse(response.text || '[]');
179
+ } catch {
180
+ return [];
181
+ }
182
+ };
services/nftService.ts ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import { callGemini } from "./geminiService";
3
+
4
+ export interface GeneratedNFT {
5
+ name: string;
6
+ description: string;
7
+ imageUrl: string;
8
+ traits: Array<{ trait_type: string; value: string | number }>;
9
+ }
10
+
11
+ export const nftService = {
12
+ /**
13
+ * Synthesizes an NFT image using Gemini 2.5 Flash Image via Backend
14
+ */
15
+ generateImage: async (prompt: string): Promise<string | null> => {
16
+ try {
17
+ const response = await callGemini(
18
+ 'gemini-2.5-flash-image',
19
+ {
20
+ parts: [{ text: `High-fidelity digital art NFT, institutional futuristic style, 4k, cinematic lighting: ${prompt}` }],
21
+ },
22
+ {
23
+ imageConfig: { aspectRatio: "1:1" }
24
+ }
25
+ );
26
+
27
+ // Extract the image from candidates
28
+ if (response.candidates && response.candidates[0]?.content?.parts) {
29
+ for (const part of response.candidates[0].content.parts) {
30
+ if (part.inlineData) {
31
+ return `data:image/png;base64,${part.inlineData.data}`;
32
+ }
33
+ }
34
+ }
35
+ return null;
36
+ } catch (error) {
37
+ console.error("Image Synthesis Failed:", error);
38
+ return null;
39
+ }
40
+ },
41
+
42
+ /**
43
+ * Generates high-lore metadata using Gemini 3 Flash
44
+ */
45
+ generateMetadata: async (imagePrompt: string): Promise<Partial<GeneratedNFT>> => {
46
+ try {
47
+ const response = await callGemini(
48
+ 'gemini-3-flash-preview',
49
+ `Generate a name, institutional description, and 3-4 rarity traits for an NFT based on this theme: ${imagePrompt}. Return ONLY JSON with keys: name, description, traits (array of {trait_type, value}).`,
50
+ { responseMimeType: "application/json" }
51
+ );
52
+
53
+ const text = response.text || '{}';
54
+ return JSON.parse(text);
55
+ } catch (error) {
56
+ console.error("Metadata Generation Failed:", error);
57
+ return {
58
+ name: "Quantum Relic",
59
+ description: "An encrypted digital artifact from the Lumina Ledger.",
60
+ traits: [{ trait_type: "Rarity", value: "Classified" }]
61
+ };
62
+ }
63
+ },
64
+
65
+ /**
66
+ * Simulated OpenSea Minting sequence
67
+ */
68
+ mintToOpenSea: async (nft: GeneratedNFT, openSeaKey: string, walletAddress: string) => {
69
+ const steps = [
70
+ "Initializing secure tunnel to OpenSea Indexer...",
71
+ `Authenticating via API Key: ${openSeaKey.substring(0, 4)}****`,
72
+ "Pinning assets to IPFS (InterPlanetary File System)...",
73
+ "Requesting wallet signature for contract 0x7892...B002",
74
+ "Broadcasting transaction to Ethereum Mainnet...",
75
+ "Waiting for block confirmation...",
76
+ `Asset Indexed Successfully. TokenID: ${Math.floor(Math.random() * 100000)}`
77
+ ];
78
+
79
+ return steps;
80
+ }
81
+ };