refactor: replace better-sqlite3 with lowdb for request details storage
- Removed better-sqlite3 dependency and implemented lowdb for JSON-based storage. - Updated observability settings handling and configuration retrieval. - Cleaned up unused observability settings UI components in ProfilePage. - Adjusted contributors badge display in README for better visibility.
This commit is contained in:
@@ -223,24 +223,6 @@ export default function ProfilePage() {
|
||||
}
|
||||
};
|
||||
|
||||
const updateObservabilitySetting = async (key, value) => {
|
||||
const numValue = parseInt(value);
|
||||
if (isNaN(numValue) || numValue < 1) return;
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/settings", {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ [key]: numValue }),
|
||||
});
|
||||
if (res.ok) {
|
||||
setSettings(prev => ({ ...prev, [key]: numValue }));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed to update ${key}:`, err);
|
||||
}
|
||||
};
|
||||
|
||||
const updateObservabilityEnabled = async (enabled) => {
|
||||
try {
|
||||
const res = await fetch("/api/settings", {
|
||||
@@ -623,102 +605,18 @@ export default function ProfilePage() {
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold">Observability</h3>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium">Enable Observability</p>
|
||||
<p className="text-sm text-text-muted">
|
||||
Turn request detail recording on/off globally
|
||||
</p>
|
||||
</div>
|
||||
<Toggle
|
||||
checked={observabilityEnabled}
|
||||
onChange={updateObservabilityEnabled}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={cn("flex flex-col gap-4", !observabilityEnabled && "opacity-60")}>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium">Max Records</p>
|
||||
<p className="text-sm text-text-muted">
|
||||
Maximum request detail records to keep (older records are auto-deleted)
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
min="100"
|
||||
max="10000"
|
||||
step="100"
|
||||
value={settings.observabilityMaxRecords || 1000}
|
||||
onChange={(e) => updateObservabilitySetting("observabilityMaxRecords", parseInt(e.target.value))}
|
||||
disabled={loading || !observabilityEnabled}
|
||||
className="w-28 text-center"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium">Batch Size</p>
|
||||
<p className="text-sm text-text-muted">
|
||||
Number of items to accumulate before writing to database (higher = better performance)
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
min="5"
|
||||
max="100"
|
||||
step="5"
|
||||
value={settings.observabilityBatchSize || 20}
|
||||
onChange={(e) => updateObservabilitySetting("observabilityBatchSize", parseInt(e.target.value))}
|
||||
disabled={loading || !observabilityEnabled}
|
||||
className="w-28 text-center"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium">Flush Interval (ms)</p>
|
||||
<p className="text-sm text-text-muted">
|
||||
Maximum time to wait before flushing buffer (prevents data loss during low traffic)
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
min="1000"
|
||||
max="30000"
|
||||
step="1000"
|
||||
value={settings.observabilityFlushIntervalMs || 5000}
|
||||
onChange={(e) => updateObservabilitySetting("observabilityFlushIntervalMs", parseInt(e.target.value))}
|
||||
disabled={loading || !observabilityEnabled}
|
||||
className="w-28 text-center"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium">Max JSON Size (KB)</p>
|
||||
<p className="text-sm text-text-muted">
|
||||
Maximum size for each JSON field (request/response) before truncation
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
min="100"
|
||||
max="10240"
|
||||
step="100"
|
||||
value={settings.observabilityMaxJsonSize || 1024}
|
||||
onChange={(e) => updateObservabilitySetting("observabilityMaxJsonSize", parseInt(e.target.value))}
|
||||
disabled={loading || !observabilityEnabled}
|
||||
className="w-28 text-center"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-text-muted italic pt-2 border-t border-border/50">
|
||||
Current: Keeps {settings.observabilityMaxRecords || 1000} records, batches every {settings.observabilityBatchSize || 20} requests, max {settings.observabilityMaxJsonSize || 1024}KB per field
|
||||
</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium">Enable Observability</p>
|
||||
<p className="text-sm text-text-muted">
|
||||
Record request details for inspection in the logs view
|
||||
</p>
|
||||
</div>
|
||||
<Toggle
|
||||
checked={observabilityEnabled}
|
||||
onChange={updateObservabilityEnabled}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getRequestDetailsDb } from "@/lib/requestDetailsDb";
|
||||
import { getRequestDetails } from "@/lib/requestDetailsDb";
|
||||
import { getProviderNodes } from "@/lib/localDb";
|
||||
import { AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
|
||||
|
||||
@@ -9,46 +9,26 @@ import { AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
|
||||
*/
|
||||
export async function GET() {
|
||||
try {
|
||||
const db = await getRequestDetailsDb();
|
||||
const { details } = await getRequestDetails({ pageSize: 9999 });
|
||||
|
||||
const stmt = db.prepare(`
|
||||
SELECT DISTINCT provider
|
||||
FROM request_details
|
||||
WHERE provider IS NOT NULL AND provider != ''
|
||||
ORDER BY provider ASC
|
||||
`);
|
||||
// Extract unique providers
|
||||
const providerIds = [...new Set(details.map(r => r.provider).filter(Boolean))].sort();
|
||||
|
||||
const rows = stmt.all();
|
||||
|
||||
// Fetch all provider nodes to get names for custom providers
|
||||
const providerNodes = await getProviderNodes();
|
||||
const nodeMap = {};
|
||||
for (const node of providerNodes) {
|
||||
nodeMap[node.id] = node.name;
|
||||
}
|
||||
|
||||
const providers = rows.map(row => {
|
||||
const providerId = row.provider;
|
||||
|
||||
// Try to find name from various sources
|
||||
const providers = providerIds.map(providerId => {
|
||||
let name = providerId;
|
||||
|
||||
// 1. Check if it's a custom provider node
|
||||
if (nodeMap[providerId]) {
|
||||
name = nodeMap[providerId];
|
||||
}
|
||||
// 2. Check predefined providers
|
||||
else {
|
||||
} else {
|
||||
const providerConfig = getProviderByAlias(providerId) || AI_PROVIDERS[providerId];
|
||||
if (providerConfig?.name) {
|
||||
name = providerConfig.name;
|
||||
}
|
||||
if (providerConfig?.name) name = providerConfig.name;
|
||||
}
|
||||
|
||||
return {
|
||||
id: providerId,
|
||||
name
|
||||
};
|
||||
return { id: providerId, name };
|
||||
});
|
||||
|
||||
return NextResponse.json({ providers });
|
||||
|
||||
Reference in New Issue
Block a user