feat: add UUID generation for request tracking and update PostgreSQL schema

This commit is contained in:
Praveen Thirumurugan
2025-10-18 02:22:52 +05:30
parent ee0e5033ec
commit 0a69232257
4 changed files with 51 additions and 25 deletions

View File

@@ -27,9 +27,7 @@ export const MODEL_COSTS: Record<string, CostConfig> = {
You can add more models to the `MODEL_COSTS` object to support your specific LLM providers.
## 📊 Database Table Schema
Before running the proxy, you need to create the table in the database.
## 📊 PostgreSQL Table Schema
```sql
CREATE TABLE IF NOT EXISTS <DATABASE_TABLE> (
@@ -46,10 +44,19 @@ CREATE TABLE IF NOT EXISTS <DATABASE_TABLE> (
request_body JSONB,
response_body JSONB,
response_status INTEGER,
provider_url VARCHAR(500)
provider_url VARCHAR(500),
client_ip INET,
user_agent TEXT,
request_size INTEGER,
response_size INTEGER,
stream BOOLEAN,
temperature REAL,
max_tokens INTEGER,
request_id UUID
);
CREATE INDEX IF NOT EXISTS idx_<DATABASE_TABLE>_timestamp ON <DATABASE_TABLE> (timestamp);
CREATE INDEX IF NOT EXISTS idx_<DATABASE_TABLE>_request_id ON <DATABASE_TABLE> (request_id);
```
## 🚀 Quick Start
@@ -124,24 +131,6 @@ The corresponding database entry will include:
- Response time metrics
- Complete request/response bodies for audit purposes
## 🔧 Advanced Features
### Custom Cost Models
Extend the `cost.ts` file to support your specific pricing models:
```typescript
export const MODEL_COSTS: Record<string, CostConfig> = {
"gpt-4": { input: 0.03, cached: 0.015, output: 0.06 },
"claude-3": { input: 0.025, cached: 0.0125, output: 0.125 },
"custom-model": { input: 0.01, cached: 0.005, output: 0.02 },
};
```
### Database Integration
The proxy automatically logs all requests to your PostgreSQL database with comprehensive metadata for analysis and reporting.
## 🛡️ Security
- Bearer token authentication required

24
package-lock.json generated
View File

@@ -7,9 +7,12 @@
"": {
"name": "llm-proxy-server",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@types/uuid": "^10.0.0",
"dotenv": "^17.2.3",
"pg": "^8.16.3"
"pg": "^8.16.3",
"uuid": "^13.0.0"
},
"devDependencies": {
"@types/node": "^24.8.1",
@@ -124,6 +127,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/uuid": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
"license": "MIT"
},
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
@@ -935,6 +944,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/uuid": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist-node/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",

View File

@@ -37,7 +37,9 @@
"typescript": "^5.9.3"
},
"dependencies": {
"@types/uuid": "^10.0.0",
"dotenv": "^17.2.3",
"pg": "^8.16.3"
"pg": "^8.16.3",
"uuid": "^13.0.0"
}
}

View File

@@ -6,6 +6,7 @@ import "dotenv/config";
import http, { IncomingMessage, ServerResponse } from "http";
import { TextDecoder } from "util";
import { Pool } from "pg";
import { v4 as uuidv4 } from "uuid";
import { calculateCost } from "./cost";
@@ -24,6 +25,10 @@ const pool = new Pool({
});
// --- Helper functions ---
function generateRequestId(): string {
return uuidv4();
}
function setCors(res: ServerResponse) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With");
@@ -189,7 +194,15 @@ const server = http.createServer(async (req, res) => {
request_body: requestJson,
response_body: responseBody,
response_status: upstreamRes.status,
provider_url: UPSTREAM_URL
provider_url: UPSTREAM_URL,
client_ip: req.socket?.remoteAddress || null,
user_agent: req.headers["user-agent"] || null,
request_size: bodyBuf.length,
response_size: Buffer.from(JSON.stringify(responseBody)).length,
stream: contentType.includes("text/event-stream"),
temperature: requestJson?.temperature || null,
max_tokens: requestJson?.max_tokens || null,
request_id: generateRequestId(),
};
logToPG(logData).catch(err => console.error("PG log error:", err));