Files
researchChat/lib/config.js
T
nico b740ce1316 DeepSeek V4.1 Flash: native Bilderkennung, GLM/OpenRouter entfernt
- deepseek-flash als einziges Modell mit Vision, Preise aktualisiert
- OpenRouter/GLM samt Code, Config und Env-Variablen entfernt
- Legacy-Modell-IDs in Sessions werden automatisch migriert
- browse lädt Produktbilder lokal nach dashboards/ (Dedupe + Cleanup)
- Vision-Prompt: Workflow für visuelle Produktsuche, max. ~5 Screenshots
2026-10-05 12:55:31 +02:00

114 lines
3.9 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const webpush = require('web-push');
const ENV_PATH = path.join(__dirname, '..', '.env');
function loadEnv() {
const env = {};
if (fs.existsSync(ENV_PATH)) {
for (const line of fs.readFileSync(ENV_PATH, 'utf8').split('\n')) {
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
if (m && !line.trim().startsWith('#')) env[m[1]] = m[2].replace(/^["']|["']$/g, '');
}
}
return env;
}
function saveEnv(env) {
const lines = [];
for (const [k, v] of Object.entries(env)) lines.push(`${k}=${v}`);
fs.writeFileSync(ENV_PATH, lines.join('\n') + '\n', 'utf8');
}
function ensure(key, generator) {
if (process.env[key] || env[key]) return process.env[key] || env[key];
const value = generator();
env[key] = value;
saveEnv(env);
return value;
}
const env = loadEnv();
function ensureVapidPair() {
if ((process.env.VAPID_PUBLIC_KEY || env.VAPID_PUBLIC_KEY) && (process.env.VAPID_PRIVATE_KEY || env.VAPID_PRIVATE_KEY)) {
return {
publicKey: process.env.VAPID_PUBLIC_KEY || env.VAPID_PUBLIC_KEY,
privateKey: process.env.VAPID_PRIVATE_KEY || env.VAPID_PRIVATE_KEY,
};
}
const pair = webpush.generateVAPIDKeys();
env.VAPID_PUBLIC_KEY = pair.publicKey;
env.VAPID_PRIVATE_KEY = pair.privateKey;
saveEnv(env);
return pair;
}
const vapid = ensureVapidPair();
const config = {
port: Number(process.env.PORT || env.PORT || 3000),
apiKey: process.env.DEEPSEEK_API_KEY || env.DEEPSEEK_API_KEY || '',
appPassword: process.env.APP_PASSWORD || env.APP_PASSWORD || '',
model: process.env.MODEL || env.MODEL || 'deepseek-flash',
thinking: process.env.THINKING || env.THINKING || 'enabled',
maxTokens: Number(process.env.MAX_TOKENS || env.MAX_TOKENS || 64000),
baseUrl: process.env.DEEPSEEK_BASE_URL || env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com',
loginMaxAttempts: Number(process.env.LOGIN_MAX_ATTEMPTS || env.LOGIN_MAX_ATTEMPTS || 5),
loginLockMinutes: Number(process.env.LOGIN_LOCK_MINUTES || env.LOGIN_LOCK_MINUTES || 5),
nominatimEmail: process.env.NOMINATIM_EMAIL || env.NOMINATIM_EMAIL || '',
osrmUrl: process.env.OSRM_URL || env.OSRM_URL || 'https://router.project-osrm.org',
sessionSecret: ensure('SESSION_SECRET', () => crypto.randomBytes(32).toString('hex')),
vapidPublicKey: vapid.publicKey,
vapidPrivateKey: vapid.privateKey,
};
const envOr = (key, def) => process.env[key] || env[key] || def;
// ---------------------------------------------------------------------------
// Modell-Registry: DeepSeek V4.1 Flash (Text + Vision/Bilderkennung)
// ---------------------------------------------------------------------------
const MODELS = [
{
id: 'deepseek-flash',
label: 'DeepSeek V4.1 Flash',
provider: 'deepseek',
vision: true,
// Max. Output laut Doku: 384K
maxTokens: 300000,
reasoningEffort: () => envOr('DEEPSEEK_REASONING_EFFORT', 'max'),
// Liefer-Runde des Dashboards: Denken komplett aus, Budget gehört dem HTML
deliveryEffort: 'none',
// Peak-Preise laut Docs (USD pro 1M Tokens; Off-Peak ist halb so teuer)
prices: { inputCacheHit: 0.006, inputCacheMiss: 0.3, output: 1.2 },
},
];
/** Registry inkl. benutzerdefiniertem Modell aus der Env (MODEL), falls nicht bekannt. */
function getModels() {
if (MODELS.some((m) => m.id === config.model)) return MODELS;
return [
...MODELS,
{
id: config.model,
label: config.model,
provider: 'deepseek',
vision: false,
maxTokens: config.maxTokens,
reasoningEffort: () => envOr('DEEPSEEK_REASONING_EFFORT', 'max'),
prices: { inputCacheHit: 0.006, inputCacheMiss: 0.3, output: 1.2 },
},
];
}
/** Modell per ID auflösen (Fallback: Default-Modell aus Env). */
function getModel(id) {
const models = getModels();
return models.find((m) => m.id === id) || models.find((m) => m.id === config.model) || models[0];
}
module.exports = { config, MODELS, getModels, getModel };