From 1b23f57d6c945db5e81c7f5f0e670a86a838e3fe Mon Sep 17 00:00:00 2001 From: hermes Date: Wed, 17 Jun 2026 04:34:35 +0000 Subject: [PATCH] chore: add diagnostic and seeding scripts - Add script to generate bcrypt admin password hash. - Add script to seed sample articles for local development. - Add Kimi/Moonshot API diagnostic scripts (SDK and direct curl). --- scripts/generate-admin-hash.ts | 10 +++ scripts/seed-sample-articles.ts | 136 ++++++++++++++++++++++++++++++++ scripts/test-kimi-curl.ts | 37 +++++++++ scripts/test-kimi.ts | 27 +++++++ 4 files changed, 210 insertions(+) create mode 100644 scripts/generate-admin-hash.ts create mode 100644 scripts/seed-sample-articles.ts create mode 100644 scripts/test-kimi-curl.ts create mode 100644 scripts/test-kimi.ts diff --git a/scripts/generate-admin-hash.ts b/scripts/generate-admin-hash.ts new file mode 100644 index 0000000..853af8e --- /dev/null +++ b/scripts/generate-admin-hash.ts @@ -0,0 +1,10 @@ +import bcrypt from 'bcryptjs'; + +async function main() { + const password = process.argv[2] || 'admin'; + const hash = await bcrypt.hash(password, 10); + console.log(`Password: ${password}`); + console.log(`Hash: ${hash}`); +} + +main(); diff --git a/scripts/seed-sample-articles.ts b/scripts/seed-sample-articles.ts new file mode 100644 index 0000000..612940d --- /dev/null +++ b/scripts/seed-sample-articles.ts @@ -0,0 +1,136 @@ +import { PrismaClient, Bias, ArticleStatus } from '@prisma/client'; + +const prisma = new PrismaClient(); + +const samples = [ + { + title: 'Progressive Lawmakers Push for Expanded Healthcare Coverage', + summary: + 'A coalition of progressive lawmakers introduced a sweeping healthcare bill aimed at expanding Medicaid coverage and lowering prescription drug prices. Supporters argue the plan is a necessary step toward universal coverage, while critics warn of rising federal costs.', + url: 'https://example.com/progressive-healthcare', + sourceApiCode: 'newsapi', + sourceName: 'Progressive Daily', + primaryBias: Bias.LEFT, + politicalTags: ['liberal'], + rankScore: 8.5, + credibilityScore: 7, + status: ArticleStatus.PUBLISHED, + topics: ['healthcare', 'policy', 'congress'], + publishedAt: new Date(Date.now() - 1000 * 60 * 60 * 2), + }, + { + title: 'Senate Reaches Bipartisan Deal on Infrastructure Spending', + summary: + 'Senators from both parties announced a long-awaited infrastructure agreement, pledging billions for roads, bridges, and broadband. Analysts say the compromise reflects a rare moment of cooperation on Capitol Hill.', + url: 'https://example.com/bipartisan-infrastructure', + sourceApiCode: 'gnews', + sourceName: 'National Wire', + primaryBias: Bias.CENTER, + politicalTags: ['moderate'], + rankScore: 8.2, + credibilityScore: 8, + status: ArticleStatus.PUBLISHED, + topics: ['infrastructure', 'bipartisanship', 'senate'], + publishedAt: new Date(Date.now() - 1000 * 60 * 60 * 4), + }, + { + title: 'Conservatives Warn Against Federal Overreach in Education Policy', + summary: + 'Conservative leaders pushed back against new federal education guidelines, arguing that local school districts should retain control over curriculum and staffing decisions. The debate highlights ongoing tensions between state and federal authority.', + url: 'https://example.com/conservative-education', + sourceApiCode: 'websearch', + sourceName: 'Conservative Review', + primaryBias: Bias.RIGHT, + politicalTags: ['conservative'], + rankScore: 7.8, + credibilityScore: 6, + status: ArticleStatus.PUBLISHED, + topics: ['education', 'states rights', 'policy'], + publishedAt: new Date(Date.now() - 1000 * 60 * 60 * 6), + }, + { + title: 'Climate Activists Call for Faster Transition Away from Fossil Fuels', + summary: + 'Environmental groups staged demonstrations across major cities, demanding accelerated action to reduce carbon emissions and end new fossil fuel projects.', + url: 'https://example.com/climate-activists', + sourceApiCode: 'newsapi', + sourceName: 'Green Times', + primaryBias: Bias.LEFT, + politicalTags: ['liberal'], + rankScore: 7.5, + credibilityScore: 7, + status: ArticleStatus.PUBLISHED, + topics: ['climate', 'activism', 'energy'], + publishedAt: new Date(Date.now() - 1000 * 60 * 60 * 8), + }, + { + title: 'Federal Reserve Holds Interest Rates Steady Amid Inflation Concerns', + summary: + 'The Federal Reserve announced it would hold interest rates steady as policymakers continue to assess inflation trends and labor market strength.', + url: 'https://example.com/fed-rates', + sourceApiCode: 'gnews', + sourceName: 'Market Watch', + primaryBias: Bias.CENTER, + politicalTags: ['moderate'], + rankScore: 8.0, + credibilityScore: 9, + status: ArticleStatus.PUBLISHED, + topics: ['economy', 'federal reserve', 'inflation'], + publishedAt: new Date(Date.now() - 1000 * 60 * 60 * 10), + }, + { + title: 'New Tax Proposal Faces Opposition from Business Groups', + summary: + 'A proposed corporate tax increase drew sharp criticism from business groups, who argue it would hurt competitiveness and slow job growth.', + url: 'https://example.com/tax-proposal-business', + sourceApiCode: 'websearch', + sourceName: 'Business Journal', + primaryBias: Bias.RIGHT, + politicalTags: ['conservative'], + rankScore: 7.2, + credibilityScore: 7, + status: ArticleStatus.PUBLISHED, + topics: ['taxes', 'business', 'economy'], + publishedAt: new Date(Date.now() - 1000 * 60 * 60 * 12), + }, +]; + +async function main() { + for (const sample of samples) { + const source = await prisma.source.upsert({ + where: { apiCode: sample.sourceApiCode }, + update: {}, + create: { apiCode: sample.sourceApiCode, name: sample.sourceName }, + }); + + await prisma.article.upsert({ + where: { url: sample.url }, + update: {}, + create: { + title: sample.title, + summary: sample.summary, + url: sample.url, + sourceId: source.id, + primaryBias: sample.primaryBias, + politicalTags: JSON.stringify(sample.politicalTags), + rankScore: sample.rankScore, + credibilityScore: sample.credibilityScore, + status: sample.status, + topics: JSON.stringify(sample.topics), + publishedAt: sample.publishedAt, + rawData: '{}', + }, + }); + } + + console.log(`Seeded ${samples.length} sample articles.`); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/scripts/test-kimi-curl.ts b/scripts/test-kimi-curl.ts new file mode 100644 index 0000000..734dfd8 --- /dev/null +++ b/scripts/test-kimi-curl.ts @@ -0,0 +1,37 @@ +import { getActiveKey } from '../src/lib/api-keys'; + +async function main() { + const key = await getActiveKey('KIMI'); + if (!key) { + console.log('No active KIMI key found'); + return; + } + + const model = process.env.KIMI_MODEL || 'moonshot-v1-8k'; + const url = process.env.KIMI_API_URL || 'https://api.moonshot.cn/v1'; + + console.log('Key length:', key.length); + console.log('Key starts with:', key.slice(0, 6)); + console.log('API URL:', url); + console.log('Model:', model); + console.log(''); + + const res = await fetch(`${url}/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${key}`, + }, + body: JSON.stringify({ + model, + messages: [{ role: 'user', content: 'Say hello' }], + temperature: 0.2, + }), + }); + + const body = await res.text(); + console.log('Status:', res.status); + console.log('Body:', body); +} + +main().catch(console.error); diff --git a/scripts/test-kimi.ts b/scripts/test-kimi.ts new file mode 100644 index 0000000..d70380e --- /dev/null +++ b/scripts/test-kimi.ts @@ -0,0 +1,27 @@ +import { getActiveKey } from '../src/lib/api-keys'; +import { getAiClient, getAiModel } from '../src/lib/ai/client'; + +async function main() { + const key = await getActiveKey('KIMI'); + if (!key) { + console.log('No active KIMI key found'); + return; + } + console.log('Found active KIMI key. Length:', key.length); + console.log('API URL:', process.env.KIMI_API_URL || 'https://api.moonshot.cn/v1'); + console.log('Model:', process.env.KIMI_MODEL || 'moonshot-v1-8k'); + + try { + const client = await getAiClient(); + const res = await client.chat.completions.create({ + model: getAiModel(), + messages: [{ role: 'user', content: 'Say hello' }], + }); + console.log('SUCCESS:', res.choices[0]?.message?.content); + } catch (err: any) { + console.error('FAILED:', err.status, err.message); + if (err.error) console.error('API error:', err.error); + } +} + +main().catch(console.error);