ok
This commit is contained in:
parent
d3dd8686fe
commit
79342c0c3e
17 changed files with 1586 additions and 214 deletions
|
|
@ -7,7 +7,11 @@ export async function GET() {
|
|||
const settings = await getSettings();
|
||||
// Don't return the password hash to the client
|
||||
const { password, ...safeSettings } = settings;
|
||||
return NextResponse.json(safeSettings);
|
||||
|
||||
// Add ENABLE_REQUEST_LOGS from env
|
||||
const enableRequestLogs = process.env.ENABLE_REQUEST_LOGS === "true";
|
||||
|
||||
return NextResponse.json({ ...safeSettings, enableRequestLogs });
|
||||
} catch (error) {
|
||||
console.log("Error getting settings:", error);
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
|
|
|
|||
42
src/app/api/translator/load/route.js
Normal file
42
src/app/api/translator/load/route.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export async function GET(request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const file = searchParams.get("file");
|
||||
|
||||
if (!file) {
|
||||
return NextResponse.json({ success: false, error: "File parameter required" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Security: only allow specific filenames
|
||||
const allowedFiles = [
|
||||
"1_req_client.json",
|
||||
"2_req_source.json",
|
||||
"3_req_openai.json",
|
||||
"4_req_target.json",
|
||||
"5_res_provider.txt"
|
||||
];
|
||||
|
||||
if (!allowedFiles.includes(file)) {
|
||||
return NextResponse.json({ success: false, error: "Invalid file name" }, { status: 400 });
|
||||
}
|
||||
|
||||
const logsDir = path.join(process.cwd(), "logs", "translator");
|
||||
const filePath = path.join(logsDir, file);
|
||||
|
||||
// Check if file exists
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return NextResponse.json({ success: false, error: "File not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
|
||||
return NextResponse.json({ success: true, content });
|
||||
} catch (error) {
|
||||
console.error("Error loading file:", error);
|
||||
return NextResponse.json({ success: false, error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
41
src/app/api/translator/save/route.js
Normal file
41
src/app/api/translator/save/route.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export async function POST(request) {
|
||||
try {
|
||||
const { file, content } = await request.json();
|
||||
|
||||
if (!file || content === undefined) {
|
||||
return NextResponse.json({ success: false, error: "File and content required" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Security: only allow specific filenames
|
||||
const allowedFiles = [
|
||||
"1_req_client.json",
|
||||
"2_req_source.json",
|
||||
"3_req_openai.json",
|
||||
"4_req_target.json",
|
||||
"5_res_provider.txt"
|
||||
];
|
||||
|
||||
if (!allowedFiles.includes(file)) {
|
||||
return NextResponse.json({ success: false, error: "Invalid file name" }, { status: 400 });
|
||||
}
|
||||
|
||||
const logsDir = path.join(process.cwd(), "logs", "translator");
|
||||
|
||||
// Create directory if not exists
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
fs.mkdirSync(logsDir, { recursive: true });
|
||||
}
|
||||
|
||||
const filePath = path.join(logsDir, file);
|
||||
fs.writeFileSync(filePath, content, "utf-8");
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error("Error saving file:", error);
|
||||
return NextResponse.json({ success: false, error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
68
src/app/api/translator/send/route.js
Normal file
68
src/app/api/translator/send/route.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { buildProviderUrl, buildProviderHeaders } from "open-sse/services/provider.js";
|
||||
import { getProviderConnections } from "@/lib/localDb.js";
|
||||
|
||||
export async function POST(request) {
|
||||
try {
|
||||
const { provider, body } = await request.json();
|
||||
|
||||
if (!provider || !body) {
|
||||
return NextResponse.json({ success: false, error: "Provider and body required" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Get provider credentials from database
|
||||
const connections = await getProviderConnections({ provider });
|
||||
const connection = connections.find(c => c.isActive !== false);
|
||||
|
||||
if (!connection) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `No active connection found for provider: ${provider}. Available connections: ${connections.length}`
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
const credentials = {
|
||||
apiKey: connection.apiKey,
|
||||
accessToken: connection.accessToken,
|
||||
refreshToken: connection.refreshToken,
|
||||
copilotToken: connection.copilotToken,
|
||||
projectId: connection.projectId,
|
||||
providerSpecificData: connection.providerSpecificData
|
||||
};
|
||||
|
||||
// Build URL and headers using provider service
|
||||
const url = buildProviderUrl(provider, body.model || "test-model", true, { baseUrlIndex: 0 });
|
||||
console.log("🚀 ~ POST ~ url:", url)
|
||||
const headers = buildProviderHeaders(provider, credentials, true, body);
|
||||
console.log("🚀 ~ POST ~ headers:", headers)
|
||||
|
||||
// Send request to provider
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.log("🚀 ~ POST ~ errorText:", errorText)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Provider error: ${response.status} ${response.statusText}`,
|
||||
details: errorText
|
||||
}, { status: response.status });
|
||||
}
|
||||
|
||||
// Return streaming response
|
||||
return new Response(response.body, {
|
||||
headers: {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive"
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error sending request:", error);
|
||||
return NextResponse.json({ success: false, error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
115
src/app/api/translator/translate/route.js
Normal file
115
src/app/api/translator/translate/route.js
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { detectFormat, getTargetFormat, buildProviderUrl, buildProviderHeaders } from "open-sse/services/provider.js";
|
||||
import { translateRequest } from "open-sse/translator/index.js";
|
||||
import { FORMATS } from "open-sse/translator/formats.js";
|
||||
import { getProviderConnections } from "@/lib/localDb.js";
|
||||
|
||||
export async function POST(request) {
|
||||
try {
|
||||
const { step, provider, body } = await request.json();
|
||||
|
||||
if (!step || !provider || !body) {
|
||||
return NextResponse.json({ success: false, error: "Step, provider, and body required" }, { status: 400 });
|
||||
}
|
||||
|
||||
let result;
|
||||
|
||||
switch (step) {
|
||||
case 1: {
|
||||
// Step 1: Client → Source (detect format)
|
||||
// Return format: { timestamp, endpoint, headers, body }
|
||||
const actualBody = body.body || body;
|
||||
const sourceFormat = detectFormat(actualBody);
|
||||
|
||||
result = {
|
||||
timestamp: body.timestamp || new Date().toISOString(),
|
||||
endpoint: body.endpoint || "/v1/messages",
|
||||
headers: body.headers || {},
|
||||
body: actualBody,
|
||||
_detectedFormat: sourceFormat
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
// Step 2: Source → OpenAI
|
||||
// Return format: { timestamp, headers: {}, body }
|
||||
const actualBody = body.body || body;
|
||||
const sourceFormat = detectFormat(actualBody);
|
||||
const targetFormat = FORMATS.OPENAI;
|
||||
const model = actualBody.model || "test-model";
|
||||
const translated = translateRequest(sourceFormat, targetFormat, model, actualBody, true, null, provider);
|
||||
|
||||
result = {
|
||||
timestamp: new Date().toISOString(),
|
||||
headers: {},
|
||||
body: translated
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
// Step 3: OpenAI → Target
|
||||
// Return format: { timestamp, body }
|
||||
const actualBody = body.body || body;
|
||||
const sourceFormat = FORMATS.OPENAI;
|
||||
const targetFormat = getTargetFormat(provider);
|
||||
const model = actualBody.model || "test-model";
|
||||
const translated = translateRequest(sourceFormat, targetFormat, model, actualBody, true, null, provider);
|
||||
|
||||
result = {
|
||||
timestamp: new Date().toISOString(),
|
||||
body: translated
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
// Step 4: Build final request with real URL and headers
|
||||
// Return format: { timestamp, url, headers, body }
|
||||
const actualBody = body.body || body;
|
||||
const model = actualBody.model || "test-model";
|
||||
|
||||
// Get provider credentials
|
||||
const connections = await getProviderConnections({ provider });
|
||||
const connection = connections.find(c => c.isActive !== false);
|
||||
|
||||
if (!connection) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `No active connection found for provider: ${provider}`
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
const credentials = {
|
||||
apiKey: connection.apiKey,
|
||||
accessToken: connection.accessToken,
|
||||
refreshToken: connection.refreshToken,
|
||||
copilotToken: connection.copilotToken,
|
||||
projectId: connection.projectId,
|
||||
providerSpecificData: connection.providerSpecificData
|
||||
};
|
||||
|
||||
// Build URL and headers
|
||||
const url = buildProviderUrl(provider, model, true, { baseUrlIndex: 0 });
|
||||
const headers = buildProviderHeaders(provider, credentials, true, actualBody);
|
||||
|
||||
result = {
|
||||
timestamp: new Date().toISOString(),
|
||||
url: url,
|
||||
headers: headers,
|
||||
body: actualBody
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return NextResponse.json({ success: false, error: "Invalid step" }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, result });
|
||||
} catch (error) {
|
||||
console.error("Error translating:", error);
|
||||
return NextResponse.json({ success: false, error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue