mirror of
https://github.com/Nikhil-Doye/workflow-builder.git
synced 2026-07-22 02:01:56 +02:00
Enhance OpenAI service with proxy support and error handling
- Introduced a method to retrieve an optional proxy base URL for production use, improving security by allowing API calls to be routed through a backend. - Updated error handling to provide clear messages when the API key is not configured or when the proxy is not set in production. - Refactored the web scraping processor to handle undefined configuration values more gracefully, ensuring default behaviors are maintained.
This commit is contained in:
@@ -9,11 +9,19 @@ const getApiKey = (): string => {
|
||||
);
|
||||
};
|
||||
|
||||
// Initialize OpenAI client for DeepSeek
|
||||
// Optional proxy base URL (recommended for production)
|
||||
const getProxyBaseUrl = (): string | null => {
|
||||
const fromStorage = localStorage.getItem("api_base_url");
|
||||
const fromEnv = process.env.REACT_APP_API_BASE;
|
||||
return fromStorage || fromEnv || null;
|
||||
};
|
||||
|
||||
// Initialize OpenAI client for DeepSeek (fallback-only; avoid in production)
|
||||
const openai = new OpenAI({
|
||||
apiKey: getApiKey(),
|
||||
baseURL: "https://api.deepseek.com/v1", // DeepSeek API endpoint
|
||||
dangerouslyAllowBrowser: true, // Only for development - in production, use a backend
|
||||
baseURL: "https://api.deepseek.com/v1",
|
||||
// Keep browser use only as a last-resort fallback during local dev
|
||||
dangerouslyAllowBrowser: true,
|
||||
});
|
||||
|
||||
export interface OpenAIConfig {
|
||||
@@ -36,29 +44,47 @@ export const callOpenAI = async (
|
||||
config: OpenAIConfig
|
||||
): Promise<OpenAIResponse> => {
|
||||
try {
|
||||
// Check if API key is configured
|
||||
const apiKey = getApiKey();
|
||||
if (
|
||||
!apiKey ||
|
||||
apiKey === "your_openai_api_key_here" ||
|
||||
apiKey === "your_deepseek_api_key_here"
|
||||
) {
|
||||
// Prefer secure proxy in production
|
||||
const proxyBase = getProxyBaseUrl();
|
||||
if (proxyBase) {
|
||||
const resp = await fetch(`${proxyBase.replace(/\/$/, "")}/llm/chat`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ prompt, config }),
|
||||
});
|
||||
|
||||
if (!resp.ok) {
|
||||
const text = await resp.text();
|
||||
throw new Error(`Proxy error: ${resp.status} ${text}`);
|
||||
}
|
||||
|
||||
const data = await resp.json();
|
||||
return {
|
||||
content: data.content || "",
|
||||
usage: data.usage,
|
||||
};
|
||||
}
|
||||
|
||||
// Fallback (dev only): direct browser call (keys are exposed!)
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
throw new Error(
|
||||
"DeepSeek API key not configured. Please configure your API key in the settings."
|
||||
"LLM proxy not configured. In production, configure REACT_APP_API_BASE or localStorage 'api_base_url' to a secure backend."
|
||||
);
|
||||
}
|
||||
|
||||
// Update the OpenAI client with the current API key
|
||||
openai.apiKey = apiKey;
|
||||
const apiKey = getApiKey();
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
"DeepSeek API key not configured. Set it in settings for local development, or configure a proxy for production."
|
||||
);
|
||||
}
|
||||
|
||||
openai.apiKey = apiKey;
|
||||
const response = await openai.chat.completions.create({
|
||||
model: config.model,
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: prompt,
|
||||
},
|
||||
],
|
||||
messages: [{ role: "user", content: prompt }],
|
||||
temperature: config.temperature,
|
||||
max_tokens: config.maxTokens || 1000,
|
||||
});
|
||||
@@ -90,20 +116,38 @@ export const generateEmbedding = async (
|
||||
text: string,
|
||||
model: string = "text-embedding-ada-002"
|
||||
): Promise<number[]> => {
|
||||
const apiKey = getApiKey();
|
||||
if (!apiKey || apiKey === "your_openai_api_key_here") {
|
||||
// Prefer secure proxy in production
|
||||
const proxyBase = getProxyBaseUrl();
|
||||
if (proxyBase) {
|
||||
const resp = await fetch(`${proxyBase.replace(/\/$/, "")}/llm/embeddings`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ text, model }),
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const textBody = await resp.text();
|
||||
throw new Error(`Proxy error: ${resp.status} ${textBody}`);
|
||||
}
|
||||
const data = await resp.json();
|
||||
return data.embedding as number[];
|
||||
}
|
||||
|
||||
// Fallback (dev only)
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
throw new Error(
|
||||
"OpenAI API key not configured. Please configure your API key in the settings."
|
||||
"Embedding proxy not configured. In production, configure REACT_APP_API_BASE or localStorage 'api_base_url' to a secure backend."
|
||||
);
|
||||
}
|
||||
|
||||
const apiKey = getApiKey();
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
"OpenAI API key not configured. Set it in settings for local development, or configure a proxy for production."
|
||||
);
|
||||
}
|
||||
|
||||
openai.apiKey = apiKey;
|
||||
|
||||
const response = await openai.embeddings.create({
|
||||
model,
|
||||
input: text,
|
||||
});
|
||||
|
||||
const response = await openai.embeddings.create({ model, input: text });
|
||||
return response.data[0].embedding;
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ export default async function webScrapingProcessor(
|
||||
const result = await scrapeWithFirecrawl({
|
||||
url: config.url,
|
||||
formats: config.formats || ["markdown"],
|
||||
onlyMainContent: config.onlyMainContent || true,
|
||||
onlyMainContent:
|
||||
config.onlyMainContent !== undefined ? config.onlyMainContent : true,
|
||||
maxLength: config.maxLength || 10000,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user