decharge-scout 2.5.6 β 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +18 -0
- package/.env.example +12 -1
- package/README.md +93 -29
- package/dashboard/api/alpha.js +167 -0
- package/dashboard/api/submit.js +23 -0
- package/dashboard/lib/migration-alpha-contributions.sql +185 -0
- package/dashboard/public/index.html +236 -0
- package/index.js +200 -89
- package/package.json +8 -3
- package/src/energy-data.js +264 -8
- package/src/local-alpha.js +325 -0
- package/src/smart-pricing.js +251 -0
- package/src/weather-data.js +117 -0
package/.env
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# EIA API Key (Required - Get from https://www.eia.gov/opendata/register.php)
|
|
2
|
+
EIA_API_KEY=w0FzlyIlSkmb0Rw8H8IpxssShajZkQp9eT2sAZ0V
|
|
3
|
+
|
|
4
|
+
# Solana Configuration
|
|
5
|
+
SOLANA_NETWORK=devnet
|
|
6
|
+
SOLANA_RPC_URL=https://api.devnet.solana.com
|
|
7
|
+
|
|
8
|
+
# Mock Oracle Escrow Address (Replace with your test wallet for demo)
|
|
9
|
+
ORACLE_ESCROW_ADDRESS=YourDevWalletPublicKeyHere
|
|
10
|
+
|
|
11
|
+
# Dashboard API (Optional - for testing dashboard integration)
|
|
12
|
+
DASHBOARD_API_URL=http://localhost:3000/submit
|
|
13
|
+
|
|
14
|
+
# Stake Amount (in SOL)
|
|
15
|
+
STAKE_AMOUNT=0.01
|
|
16
|
+
|
|
17
|
+
# Premium Feature Price (in SOL)
|
|
18
|
+
PREMIUM_PRICE=0.001
|
package/.env.example
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Energy Data API Keys
|
|
2
|
+
# Choose ONE based on your location (FREE options available!):
|
|
3
|
+
#
|
|
4
|
+
# πΊπΈ USA (FREE): EIA API - Get from https://www.eia.gov/opendata/register.php
|
|
2
5
|
EIA_API_KEY=your_eia_api_key_here
|
|
6
|
+
#
|
|
7
|
+
# πͺπΊ Europe (FREE): ENTSO-E - Get from https://transparency.entsoe.eu/
|
|
8
|
+
ENTSOE_API_KEY=your_entsoe_api_key_here
|
|
9
|
+
#
|
|
10
|
+
# π¬π§ UK (NO KEY NEEDED): Carbon Intensity API is completely FREE!
|
|
11
|
+
#
|
|
12
|
+
# π Global (PAID): Electricity Maps - Get from https://www.electricitymaps.com/
|
|
13
|
+
ELECTRICITY_MAPS_API_KEY=your_electricity_maps_api_key_here
|
|
3
14
|
|
|
4
15
|
# Solana Configuration
|
|
5
16
|
SOLANA_NETWORK=devnet
|
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# π Global Energy Scout
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Weather-powered intelligent energy price forecasting with Solana blockchain integration.**
|
|
4
|
+
|
|
5
|
+
This CLI tool uses **real-time weather data** to simulate energy grid pricing globally, helping you find the cheapest EV charging windows. No expensive APIs needed - completely FREE weather-based simulation that works worldwide!
|
|
4
6
|
|
|
5
7
|
## π Quick Install
|
|
6
8
|
|
|
@@ -14,22 +16,47 @@ Then run: `decharge-scout`
|
|
|
14
16
|
|
|
15
17
|
[See more installation options β](ONE_COMMAND_INSTALL.md)
|
|
16
18
|
|
|
17
|
-
## Features
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- **
|
|
21
|
-
-
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
19
|
+
## β¨ Features
|
|
20
|
+
|
|
21
|
+
### π€οΈ **Weather-Powered Simulation** (NEW!)
|
|
22
|
+
- **FREE** real-time weather data from Open-Meteo API (no key required!)
|
|
23
|
+
- Simulates energy pricing based on:
|
|
24
|
+
- π‘οΈ **Temperature** (AC/heating demand)
|
|
25
|
+
- π¨ **Wind speed** (renewable energy availability)
|
|
26
|
+
- βοΈ **Solar radiation** (solar energy generation)
|
|
27
|
+
- π **Time-of-day** patterns (peak/off-peak)
|
|
28
|
+
- **50+ regional pricing models** (US, EU, IN, BR, JP, AU, etc.)
|
|
29
|
+
- Intelligent insights explaining **why** certain times are cheaper
|
|
30
|
+
|
|
31
|
+
### π§ **Smart Optimization**
|
|
32
|
+
- Finds the cheapest 1-hour EV charging window in next 24 hours
|
|
33
|
+
- Shows weather conditions at optimal time
|
|
34
|
+
- Calculates potential savings (%)
|
|
35
|
+
- Regional peak/off-peak pattern matching
|
|
36
|
+
|
|
37
|
+
### π **Local Alpha Contribution**
|
|
38
|
+
- Share your local grid knowledge (e.g., "7-9PM peak in Lagos")
|
|
39
|
+
- Earn bonus points for contributing
|
|
40
|
+
- Community-driven peak time database
|
|
41
|
+
|
|
42
|
+
### βοΈ **Blockchain Integration**
|
|
43
|
+
- Submits results to Solana devnet with anti-spam staking
|
|
44
|
+
- Points system for successful submissions
|
|
45
|
+
- x402 micropayments for premium features (optional)
|
|
46
|
+
|
|
47
|
+
### πΊοΈ **Global Coverage**
|
|
48
|
+
- Works **anywhere in the world**
|
|
49
|
+
- Auto-detects location via IP
|
|
50
|
+
- Custom location override supported
|
|
51
|
+
- Dashboard-ready structured output
|
|
26
52
|
|
|
27
53
|
## Prerequisites
|
|
28
54
|
|
|
29
55
|
- Node.js v20 or higher
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
56
|
+
- **NO API KEYS REQUIRED!** π
|
|
57
|
+
- Uses FREE Open-Meteo weather API (no registration needed)
|
|
58
|
+
- Works globally without any paid subscriptions
|
|
59
|
+
- At least 0.02 SOL in your devnet wallet for staking + fees (auto-airdropped in setup)
|
|
33
60
|
|
|
34
61
|
## Installation
|
|
35
62
|
|
|
@@ -233,19 +260,47 @@ decharge-scout/
|
|
|
233
260
|
|
|
234
261
|
## API Data Sources
|
|
235
262
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
- Endpoint
|
|
243
|
-
- Provides
|
|
244
|
-
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
-
|
|
263
|
+
The CLI uses **smart routing** to automatically choose the best FREE API based on your location!
|
|
264
|
+
|
|
265
|
+
### π FREE APIs (Recommended!)
|
|
266
|
+
|
|
267
|
+
#### πΊπΈ EIA API (US-only, FREE)
|
|
268
|
+
- **Coverage**: United States only (ERCOT, CAISO, NYISO, PJM, MISO, ISNE)
|
|
269
|
+
- **Endpoint**: `https://api.eia.gov/v2/electricity/rto/region-data/data/`
|
|
270
|
+
- **Provides**: Real-time demand and pricing for US grid regions
|
|
271
|
+
- **Get Key**: FREE at https://www.eia.gov/opendata/register.php
|
|
272
|
+
- **Auto-used for**: Texas, California, New York, etc.
|
|
273
|
+
|
|
274
|
+
#### πͺπΊ ENTSO-E (Europe, FREE)
|
|
275
|
+
- **Coverage**: All European countries
|
|
276
|
+
- **Endpoint**: `https://web-api.tp.entsoe.eu/api`
|
|
277
|
+
- **Provides**: Day-ahead electricity prices and demand forecasts
|
|
278
|
+
- **Get Key**: FREE at https://transparency.entsoe.eu/
|
|
279
|
+
- **Auto-used for**: Germany, France, Spain, Italy, Poland, Netherlands, Belgium, Austria
|
|
280
|
+
- **Registration**: Free account required, instant approval
|
|
281
|
+
|
|
282
|
+
#### π¬π§ UK Carbon Intensity (UK, FREE - No key needed!)
|
|
283
|
+
- **Coverage**: United Kingdom only
|
|
284
|
+
- **Endpoint**: `https://api.carbonintensity.org.uk`
|
|
285
|
+
- **Provides**: Real-time carbon intensity and price forecasts
|
|
286
|
+
- **Get Key**: No key needed! Completely open API
|
|
287
|
+
- **Auto-used for**: UK locations (works out of the box!)
|
|
288
|
+
|
|
289
|
+
### π° PAID API (Global fallback)
|
|
290
|
+
|
|
291
|
+
#### π Electricity Maps (GLOBAL, PAID)
|
|
292
|
+
- **Coverage**: Global (India, EU, UK, Australia, US, and more)
|
|
293
|
+
- **Endpoint**: `https://api.electricitymaps.com/v3/carbon-intensity/forecast`
|
|
294
|
+
- **Provides**: Carbon intensity forecasts and grid data for 200+ zones
|
|
295
|
+
- **Get Key**: Paid API at https://www.electricitymaps.com/
|
|
296
|
+
- **Auto-used for**: India, Australia, and regions not covered by free APIs
|
|
297
|
+
- **Pricing**: Expensive - use only if free options don't cover your region
|
|
298
|
+
|
|
299
|
+
### π Mock Data (FREE - Always available!)
|
|
300
|
+
- **Coverage**: Worldwide
|
|
301
|
+
- **Generated**: Locally using realistic pricing patterns
|
|
302
|
+
- **Auto-used**: When no API keys are configured or all APIs fail
|
|
303
|
+
- **Perfect for**: Testing, demos, and development
|
|
249
304
|
|
|
250
305
|
## Points System
|
|
251
306
|
|
|
@@ -264,8 +319,17 @@ decharge-scout/
|
|
|
264
319
|
|
|
265
320
|
## Troubleshooting
|
|
266
321
|
|
|
267
|
-
### "EIA_API_KEY not
|
|
268
|
-
|
|
322
|
+
### "EIA_API_KEY not configured" or "No energy data API keys configured"
|
|
323
|
+
Choose an API based on your location:
|
|
324
|
+
- **US users**: Get FREE EIA API key from https://www.eia.gov/opendata/register.php
|
|
325
|
+
- **International users**: Get Electricity Maps API key from https://www.electricitymaps.com/
|
|
326
|
+
- **Testing**: Press Enter to skip and use mock data
|
|
327
|
+
|
|
328
|
+
Add your key to `.env`:
|
|
329
|
+
```
|
|
330
|
+
EIA_API_KEY=your_key_here # For US
|
|
331
|
+
ELECTRICITY_MAPS_API_KEY=your_key_here # For global
|
|
332
|
+
```
|
|
269
333
|
|
|
270
334
|
### "Insufficient balance"
|
|
271
335
|
Fund your devnet wallet:
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel API Endpoint - Alpha Contributions
|
|
3
|
+
*
|
|
4
|
+
* GET /api/alpha - Get verified alpha contributions
|
|
5
|
+
* POST /api/alpha - Submit new alpha contribution
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createClient } from '@supabase/supabase-js';
|
|
9
|
+
|
|
10
|
+
export const config = {
|
|
11
|
+
runtime: 'edge',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default async function handler(req) {
|
|
15
|
+
// CORS headers
|
|
16
|
+
const headers = {
|
|
17
|
+
'Access-Control-Allow-Origin': '*',
|
|
18
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
19
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Handle OPTIONS request for CORS
|
|
24
|
+
if (req.method === 'OPTIONS') {
|
|
25
|
+
return new Response(null, { status: 200, headers });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Initialize Supabase client
|
|
29
|
+
const supabase = createClient(
|
|
30
|
+
process.env.SUPABASE_URL,
|
|
31
|
+
process.env.SUPABASE_ANON_KEY
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// GET - Retrieve alpha contributions
|
|
35
|
+
if (req.method === 'GET') {
|
|
36
|
+
try {
|
|
37
|
+
const url = new URL(req.url);
|
|
38
|
+
const location = url.searchParams.get('location');
|
|
39
|
+
const verified = url.searchParams.get('verified') === 'true';
|
|
40
|
+
const minConfidence = parseFloat(url.searchParams.get('min_confidence') || '0');
|
|
41
|
+
|
|
42
|
+
let query = supabase
|
|
43
|
+
.from('alpha_contributions')
|
|
44
|
+
.select('*')
|
|
45
|
+
.order('created_at', { ascending: false })
|
|
46
|
+
.limit(100);
|
|
47
|
+
|
|
48
|
+
// Apply filters
|
|
49
|
+
if (location) {
|
|
50
|
+
query = query.ilike('location', `%${location}%`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (verified) {
|
|
54
|
+
query = query.eq('verified', true);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (minConfidence > 0) {
|
|
58
|
+
query = query.gte('confidence', minConfidence);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { data, error } = await query;
|
|
62
|
+
|
|
63
|
+
if (error) throw error;
|
|
64
|
+
|
|
65
|
+
// Get statistics
|
|
66
|
+
const { data: stats } = await supabase
|
|
67
|
+
.from('alpha_by_location')
|
|
68
|
+
.select('*')
|
|
69
|
+
.order('verified_count', { ascending: false })
|
|
70
|
+
.limit(10);
|
|
71
|
+
|
|
72
|
+
return new Response(
|
|
73
|
+
JSON.stringify({
|
|
74
|
+
contributions: data || [],
|
|
75
|
+
statistics: stats || [],
|
|
76
|
+
total: data?.length || 0,
|
|
77
|
+
timestamp: new Date().toISOString(),
|
|
78
|
+
}),
|
|
79
|
+
{ status: 200, headers }
|
|
80
|
+
);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error('Alpha GET error:', error);
|
|
83
|
+
return new Response(
|
|
84
|
+
JSON.stringify({
|
|
85
|
+
error: 'Failed to fetch alpha contributions',
|
|
86
|
+
message: error.message,
|
|
87
|
+
}),
|
|
88
|
+
{ status: 500, headers }
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// POST - Submit alpha contribution
|
|
94
|
+
if (req.method === 'POST') {
|
|
95
|
+
try {
|
|
96
|
+
const data = await req.json();
|
|
97
|
+
|
|
98
|
+
// Validate required fields
|
|
99
|
+
if (!data.agent_name || !data.location || !data.contribution) {
|
|
100
|
+
return new Response(
|
|
101
|
+
JSON.stringify({ error: 'Missing required fields' }),
|
|
102
|
+
{ status: 400, headers }
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const { contribution } = data;
|
|
107
|
+
|
|
108
|
+
// Validate contribution structure
|
|
109
|
+
if (
|
|
110
|
+
typeof contribution.startHour !== 'number' ||
|
|
111
|
+
typeof contribution.endHour !== 'number' ||
|
|
112
|
+
!contribution.type ||
|
|
113
|
+
contribution.startHour < 0 ||
|
|
114
|
+
contribution.startHour > 23 ||
|
|
115
|
+
contribution.endHour < 0 ||
|
|
116
|
+
contribution.endHour > 23
|
|
117
|
+
) {
|
|
118
|
+
return new Response(
|
|
119
|
+
JSON.stringify({ error: 'Invalid contribution data' }),
|
|
120
|
+
{ status: 400, headers }
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Insert alpha contribution
|
|
125
|
+
const { data: insertedData, error: insertError } = await supabase
|
|
126
|
+
.from('alpha_contributions')
|
|
127
|
+
.insert({
|
|
128
|
+
agent_name: data.agent_name,
|
|
129
|
+
location: data.location,
|
|
130
|
+
contribution_type: contribution.type,
|
|
131
|
+
start_hour: contribution.startHour,
|
|
132
|
+
end_hour: contribution.endHour,
|
|
133
|
+
verified: data.verified || false,
|
|
134
|
+
confidence: data.confidence || 0.5,
|
|
135
|
+
verification_reasons: data.verificationReasons || [],
|
|
136
|
+
timestamp: new Date(data.timestamp || Date.now()).toISOString(),
|
|
137
|
+
})
|
|
138
|
+
.select()
|
|
139
|
+
.single();
|
|
140
|
+
|
|
141
|
+
if (insertError) throw insertError;
|
|
142
|
+
|
|
143
|
+
return new Response(
|
|
144
|
+
JSON.stringify({
|
|
145
|
+
success: true,
|
|
146
|
+
message: 'Alpha contribution submitted successfully',
|
|
147
|
+
contribution: insertedData,
|
|
148
|
+
}),
|
|
149
|
+
{ status: 200, headers }
|
|
150
|
+
);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error('Alpha POST error:', error);
|
|
153
|
+
return new Response(
|
|
154
|
+
JSON.stringify({
|
|
155
|
+
error: 'Failed to submit alpha contribution',
|
|
156
|
+
message: error.message,
|
|
157
|
+
}),
|
|
158
|
+
{ status: 500, headers }
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return new Response(
|
|
164
|
+
JSON.stringify({ error: 'Method not allowed' }),
|
|
165
|
+
{ status: 405, headers }
|
|
166
|
+
);
|
|
167
|
+
}
|
package/dashboard/api/submit.js
CHANGED
|
@@ -65,6 +65,29 @@ export default async function handler(req) {
|
|
|
65
65
|
|
|
66
66
|
if (submissionError) throw submissionError;
|
|
67
67
|
|
|
68
|
+
// Handle alpha contribution if present
|
|
69
|
+
if (data.alpha_contribution) {
|
|
70
|
+
const alpha = data.alpha_contribution;
|
|
71
|
+
const { error: alphaError } = await supabase
|
|
72
|
+
.from('alpha_contributions')
|
|
73
|
+
.insert({
|
|
74
|
+
agent_name: data.agent_name,
|
|
75
|
+
location: data.location,
|
|
76
|
+
contribution_type: alpha.type,
|
|
77
|
+
start_hour: alpha.startHour,
|
|
78
|
+
end_hour: alpha.endHour,
|
|
79
|
+
verified: alpha.verified || false,
|
|
80
|
+
confidence: alpha.confidence || 0.5,
|
|
81
|
+
verification_reasons: alpha.verificationReasons || [],
|
|
82
|
+
timestamp: new Date(data.timestamp).toISOString(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Don't fail the entire request if alpha submission fails
|
|
86
|
+
if (alphaError) {
|
|
87
|
+
console.warn('Alpha contribution failed:', alphaError);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
68
91
|
// Update agent heartbeat (upsert)
|
|
69
92
|
const { error: heartbeatError } = await supabase
|
|
70
93
|
.from('agent_heartbeat')
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
-- DeCharge Scout Dashboard - Alpha Contributions Migration
|
|
2
|
+
-- Add this to your Supabase database to support verified local alpha contributions
|
|
3
|
+
|
|
4
|
+
-- ============================================================================
|
|
5
|
+
-- TABLE: alpha_contributions
|
|
6
|
+
-- Stores verified local knowledge contributions from agents
|
|
7
|
+
-- ============================================================================
|
|
8
|
+
CREATE TABLE IF NOT EXISTS alpha_contributions (
|
|
9
|
+
id SERIAL PRIMARY KEY,
|
|
10
|
+
agent_name VARCHAR(255) NOT NULL,
|
|
11
|
+
location VARCHAR(255) NOT NULL,
|
|
12
|
+
contribution_type VARCHAR(20) NOT NULL CHECK (contribution_type IN ('peak', 'cheap', 'general')),
|
|
13
|
+
start_hour INTEGER NOT NULL CHECK (start_hour >= 0 AND start_hour <= 23),
|
|
14
|
+
end_hour INTEGER NOT NULL CHECK (end_hour >= 0 AND end_hour <= 23),
|
|
15
|
+
|
|
16
|
+
-- Verification fields
|
|
17
|
+
verified BOOLEAN DEFAULT FALSE,
|
|
18
|
+
confidence DECIMAL(4, 3) CHECK (confidence >= 0 AND confidence <= 1),
|
|
19
|
+
verification_reasons TEXT[],
|
|
20
|
+
|
|
21
|
+
-- Metadata
|
|
22
|
+
timestamp TIMESTAMP NOT NULL,
|
|
23
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
24
|
+
|
|
25
|
+
-- Indexes for performance
|
|
26
|
+
CONSTRAINT valid_hour_range CHECK (start_hour <= end_hour)
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
-- Indexes for efficient querying
|
|
30
|
+
CREATE INDEX idx_alpha_location ON alpha_contributions(location);
|
|
31
|
+
CREATE INDEX idx_alpha_verified ON alpha_contributions(verified);
|
|
32
|
+
CREATE INDEX idx_alpha_confidence ON alpha_contributions(confidence DESC);
|
|
33
|
+
CREATE INDEX idx_alpha_created_at ON alpha_contributions(created_at DESC);
|
|
34
|
+
CREATE INDEX idx_alpha_type ON alpha_contributions(contribution_type);
|
|
35
|
+
|
|
36
|
+
-- ============================================================================
|
|
37
|
+
-- VIEW: Verified Alpha Contributions (high confidence only)
|
|
38
|
+
-- ============================================================================
|
|
39
|
+
CREATE OR REPLACE VIEW verified_alpha_contributions AS
|
|
40
|
+
SELECT
|
|
41
|
+
id,
|
|
42
|
+
agent_name,
|
|
43
|
+
location,
|
|
44
|
+
contribution_type,
|
|
45
|
+
start_hour,
|
|
46
|
+
end_hour,
|
|
47
|
+
confidence,
|
|
48
|
+
verification_reasons,
|
|
49
|
+
timestamp,
|
|
50
|
+
created_at
|
|
51
|
+
FROM alpha_contributions
|
|
52
|
+
WHERE verified = TRUE AND confidence >= 0.6
|
|
53
|
+
ORDER BY confidence DESC, created_at DESC;
|
|
54
|
+
|
|
55
|
+
-- ============================================================================
|
|
56
|
+
-- VIEW: Alpha Contributions Summary by Location
|
|
57
|
+
-- ============================================================================
|
|
58
|
+
CREATE OR REPLACE VIEW alpha_by_location AS
|
|
59
|
+
SELECT
|
|
60
|
+
location,
|
|
61
|
+
COUNT(*) as total_contributions,
|
|
62
|
+
COUNT(CASE WHEN verified = TRUE THEN 1 END) as verified_count,
|
|
63
|
+
AVG(confidence) as avg_confidence,
|
|
64
|
+
MAX(created_at) as latest_contribution
|
|
65
|
+
FROM alpha_contributions
|
|
66
|
+
WHERE created_at > NOW() - INTERVAL '30 days'
|
|
67
|
+
GROUP BY location
|
|
68
|
+
ORDER BY verified_count DESC, total_contributions DESC;
|
|
69
|
+
|
|
70
|
+
-- ============================================================================
|
|
71
|
+
-- VIEW: Peak Hours Analysis (most commonly reported)
|
|
72
|
+
-- ============================================================================
|
|
73
|
+
CREATE OR REPLACE VIEW peak_hours_analysis AS
|
|
74
|
+
WITH hour_counts AS (
|
|
75
|
+
SELECT
|
|
76
|
+
location,
|
|
77
|
+
generate_series(start_hour, end_hour) as hour,
|
|
78
|
+
confidence,
|
|
79
|
+
contribution_type
|
|
80
|
+
FROM alpha_contributions
|
|
81
|
+
WHERE contribution_type = 'peak'
|
|
82
|
+
AND verified = TRUE
|
|
83
|
+
AND created_at > NOW() - INTERVAL '30 days'
|
|
84
|
+
)
|
|
85
|
+
SELECT
|
|
86
|
+
location,
|
|
87
|
+
hour,
|
|
88
|
+
COUNT(*) as report_count,
|
|
89
|
+
AVG(confidence) as avg_confidence,
|
|
90
|
+
COUNT(*) * AVG(confidence) as weighted_score
|
|
91
|
+
FROM hour_counts
|
|
92
|
+
GROUP BY location, hour
|
|
93
|
+
HAVING COUNT(*) >= 2 -- At least 2 reports
|
|
94
|
+
ORDER BY location, weighted_score DESC;
|
|
95
|
+
|
|
96
|
+
-- ============================================================================
|
|
97
|
+
-- FUNCTION: Get Alpha Insights for Location
|
|
98
|
+
-- ============================================================================
|
|
99
|
+
CREATE OR REPLACE FUNCTION get_alpha_insights(
|
|
100
|
+
p_location VARCHAR(255),
|
|
101
|
+
p_min_confidence DECIMAL DEFAULT 0.6
|
|
102
|
+
)
|
|
103
|
+
RETURNS TABLE (
|
|
104
|
+
contribution_type VARCHAR(20),
|
|
105
|
+
start_hour INTEGER,
|
|
106
|
+
end_hour INTEGER,
|
|
107
|
+
confidence DECIMAL(4, 3),
|
|
108
|
+
report_count BIGINT,
|
|
109
|
+
latest_report TIMESTAMP
|
|
110
|
+
) AS $$
|
|
111
|
+
BEGIN
|
|
112
|
+
RETURN QUERY
|
|
113
|
+
SELECT
|
|
114
|
+
ac.contribution_type,
|
|
115
|
+
ac.start_hour,
|
|
116
|
+
ac.end_hour,
|
|
117
|
+
AVG(ac.confidence)::DECIMAL(4, 3) as confidence,
|
|
118
|
+
COUNT(*) as report_count,
|
|
119
|
+
MAX(ac.created_at) as latest_report
|
|
120
|
+
FROM alpha_contributions ac
|
|
121
|
+
WHERE ac.location ILIKE '%' || p_location || '%'
|
|
122
|
+
AND ac.verified = TRUE
|
|
123
|
+
AND ac.confidence >= p_min_confidence
|
|
124
|
+
AND ac.created_at > NOW() - INTERVAL '30 days'
|
|
125
|
+
GROUP BY ac.contribution_type, ac.start_hour, ac.end_hour
|
|
126
|
+
ORDER BY report_count DESC, confidence DESC
|
|
127
|
+
LIMIT 10;
|
|
128
|
+
END;
|
|
129
|
+
$$ LANGUAGE plpgsql;
|
|
130
|
+
|
|
131
|
+
-- ============================================================================
|
|
132
|
+
-- FUNCTION: Calculate Contribution Quality Score
|
|
133
|
+
-- ============================================================================
|
|
134
|
+
CREATE OR REPLACE FUNCTION calculate_contribution_quality(
|
|
135
|
+
p_agent_name VARCHAR(255)
|
|
136
|
+
)
|
|
137
|
+
RETURNS TABLE (
|
|
138
|
+
agent_name VARCHAR(255),
|
|
139
|
+
total_contributions BIGINT,
|
|
140
|
+
verified_contributions BIGINT,
|
|
141
|
+
avg_confidence DECIMAL(4, 3),
|
|
142
|
+
quality_score DECIMAL(6, 2)
|
|
143
|
+
) AS $$
|
|
144
|
+
BEGIN
|
|
145
|
+
RETURN QUERY
|
|
146
|
+
SELECT
|
|
147
|
+
p_agent_name::VARCHAR(255),
|
|
148
|
+
COUNT(*)::BIGINT as total_contributions,
|
|
149
|
+
COUNT(CASE WHEN verified = TRUE THEN 1 END)::BIGINT as verified_contributions,
|
|
150
|
+
AVG(confidence)::DECIMAL(4, 3) as avg_confidence,
|
|
151
|
+
(
|
|
152
|
+
(COUNT(CASE WHEN verified = TRUE THEN 1 END)::DECIMAL / NULLIF(COUNT(*), 0)) * 100 +
|
|
153
|
+
(AVG(confidence) * 100)
|
|
154
|
+
)::DECIMAL(6, 2) as quality_score
|
|
155
|
+
FROM alpha_contributions
|
|
156
|
+
WHERE agent_name = p_agent_name;
|
|
157
|
+
END;
|
|
158
|
+
$$ LANGUAGE plpgsql;
|
|
159
|
+
|
|
160
|
+
-- ============================================================================
|
|
161
|
+
-- COMMENTS for documentation
|
|
162
|
+
-- ============================================================================
|
|
163
|
+
COMMENT ON TABLE alpha_contributions IS 'Stores verified local energy pricing knowledge from agents';
|
|
164
|
+
COMMENT ON COLUMN alpha_contributions.verified IS 'TRUE if contribution matches actual pricing data';
|
|
165
|
+
COMMENT ON COLUMN alpha_contributions.confidence IS 'Confidence score 0-1, higher means better match with actual data';
|
|
166
|
+
COMMENT ON COLUMN alpha_contributions.verification_reasons IS 'Array of reasons explaining verification result';
|
|
167
|
+
|
|
168
|
+
-- ============================================================================
|
|
169
|
+
-- Sample queries for testing
|
|
170
|
+
-- ============================================================================
|
|
171
|
+
|
|
172
|
+
-- Get all verified contributions for a location
|
|
173
|
+
-- SELECT * FROM verified_alpha_contributions WHERE location ILIKE '%mumbai%';
|
|
174
|
+
|
|
175
|
+
-- Get alpha insights for a specific location
|
|
176
|
+
-- SELECT * FROM get_alpha_insights('Mumbai', 0.7);
|
|
177
|
+
|
|
178
|
+
-- Get contribution quality for an agent
|
|
179
|
+
-- SELECT * FROM calculate_contribution_quality('Agent-X8DOAO');
|
|
180
|
+
|
|
181
|
+
-- Get peak hours analysis
|
|
182
|
+
-- SELECT * FROM peak_hours_analysis WHERE location ILIKE '%india%';
|
|
183
|
+
|
|
184
|
+
-- Get alpha summary by location
|
|
185
|
+
-- SELECT * FROM alpha_by_location ORDER BY verified_count DESC LIMIT 10;
|