mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.6 KiB
108 lines
3.6 KiB
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Agent setup helper: configures OpenRouter API key, model, and demo user.
|
|
*
|
|
* Usage:
|
|
* export DATABASE_URL="postgresql://user:ghostfolio-pg-dev@localhost:5432/ghostfolio-db?connect_timeout=300&sslmode=prefer"
|
|
* node scripts/agent-setup.mjs --openrouter-key=sk-or-... [--model=anthropic/claude-sonnet-4-20250514]
|
|
*/
|
|
|
|
import { PrismaClient } from '@prisma/client';
|
|
import { createHmac, randomBytes } from 'crypto';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
function getArg(name) {
|
|
const prefix = `--${name}=`;
|
|
const arg = process.argv.find((a) => a.startsWith(prefix));
|
|
return arg ? arg.slice(prefix.length) : undefined;
|
|
}
|
|
|
|
async function main() {
|
|
const openRouterKey = getArg('openrouter-key');
|
|
const model = getArg('model') || 'openai/gpt-4o-mini';
|
|
const salt = process.env.ACCESS_TOKEN_SALT || 'agentforge-dev-salt-2026';
|
|
|
|
if (!openRouterKey) {
|
|
console.error('Usage: node scripts/agent-setup.mjs --openrouter-key=sk-or-...');
|
|
process.exit(1);
|
|
}
|
|
|
|
await prisma.property.upsert({
|
|
where: { key: 'API_KEY_OPENROUTER' },
|
|
update: { value: openRouterKey },
|
|
create: { key: 'API_KEY_OPENROUTER', value: openRouterKey }
|
|
});
|
|
console.log(`Set API_KEY_OPENROUTER`);
|
|
|
|
await prisma.property.upsert({
|
|
where: { key: 'OPENROUTER_MODEL' },
|
|
update: { value: model },
|
|
create: { key: 'OPENROUTER_MODEL', value: model }
|
|
});
|
|
console.log(`Set OPENROUTER_MODEL = ${model}`);
|
|
|
|
let user = await prisma.user.findFirst({ where: { role: 'ADMIN' } });
|
|
if (!user) {
|
|
const securityToken = 'agentforge-demo-token';
|
|
const hash = createHmac('sha512', salt);
|
|
hash.update(securityToken);
|
|
const hashedToken = hash.digest('hex');
|
|
|
|
user = await prisma.user.create({
|
|
data: {
|
|
accessToken: hashedToken,
|
|
role: 'ADMIN',
|
|
provider: 'ANONYMOUS',
|
|
settings: {
|
|
create: {
|
|
settings: { baseCurrency: 'USD', locale: 'en-US', language: 'en' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
const account = await prisma.account.create({
|
|
data: { name: 'Demo Account', userId: user.id, balance: 10000, currency: 'USD' }
|
|
});
|
|
|
|
for (const { symbol, name, subClass, qty, price, date } of [
|
|
{ symbol: 'AAPL', name: 'Apple Inc.', subClass: 'STOCK', qty: 10, price: 185.50, date: '2025-01-15' },
|
|
{ symbol: 'MSFT', name: 'Microsoft Corporation', subClass: 'STOCK', qty: 5, price: 405.00, date: '2025-02-01' },
|
|
{ symbol: 'VTI', name: 'Vanguard Total Stock Market ETF', subClass: 'ETF', qty: 20, price: 240.00, date: '2025-03-10' }
|
|
]) {
|
|
let sp = await prisma.symbolProfile.findFirst({ where: { symbol, dataSource: 'YAHOO' } });
|
|
if (!sp) {
|
|
sp = await prisma.symbolProfile.create({
|
|
data: { symbol, dataSource: 'YAHOO', currency: 'USD', name, assetClass: 'EQUITY', assetSubClass: subClass }
|
|
});
|
|
}
|
|
await prisma.order.create({
|
|
data: {
|
|
userId: user.id,
|
|
accountId: account.id,
|
|
symbolProfileId: sp.id,
|
|
date: new Date(date),
|
|
fee: 0,
|
|
quantity: qty,
|
|
type: 'BUY',
|
|
unitPrice: price
|
|
}
|
|
});
|
|
}
|
|
console.log(`Created ADMIN user (id: ${user.id}) with demo portfolio (AAPL, MSFT, VTI)`);
|
|
console.log(`Security token: agentforge-demo-token`);
|
|
} else {
|
|
console.log(`ADMIN user already exists (id: ${user.id})`);
|
|
}
|
|
|
|
console.log('\nSetup complete! Start the API with:');
|
|
console.log(' npx nx serve api');
|
|
console.log('\nThen open: http://localhost:3333/api/v1/agent/chat');
|
|
console.log('Enter security token: agentforge-demo-token');
|
|
}
|
|
|
|
main()
|
|
.catch((e) => { console.error(e); process.exit(1); })
|
|
.finally(() => prisma.$disconnect());
|
|
|