168 lines
6.6 KiB
JavaScript
168 lines
6.6 KiB
JavaScript
import { BASE_API_URL, API_KEY } from './config.js';
|
|
import { showAlert } from './shared_functions.js';
|
|
|
|
/**
|
|
* Generic fetch wrapper for API calls
|
|
* @param {string} endpoint API endpoint (e.g., '/api/auth/me')
|
|
* @param {object} options Fetch options (method, headers, body)
|
|
* @param {boolean} includeAuthHeader Add Authorization header?
|
|
* @returns {Promise<any>} Parsed JSON response or throws error
|
|
*/
|
|
async function fetchApi(endpoint, options = {}, includeAuthHeader = true) {
|
|
const url = `${BASE_API_URL}${endpoint}`;
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
...options.headers,
|
|
};
|
|
|
|
if (includeAuthHeader) {
|
|
const token = localStorage.getItem('token');
|
|
if (token) {
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
} else {
|
|
// Handle cases where token is expected but missing (e.g., redirect to login)
|
|
console.warn('Auth token missing for API call:', endpoint);
|
|
// Optionally throw an error or redirect here
|
|
// window.location.href = 'index.html';
|
|
// throw new Error('Authentication token not found.');
|
|
}
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(url, { ...options, headers });
|
|
|
|
if (!response.ok) {
|
|
let errorData;
|
|
try {
|
|
errorData = await response.json();
|
|
} catch (e) {
|
|
// If response is not JSON
|
|
errorData = { message: response.statusText };
|
|
}
|
|
console.error(`API Error ${response.status}:`, errorData);
|
|
const error = new Error(errorData.message || `HTTP error! status: ${response.status}`);
|
|
error.status = response.status;
|
|
error.data = errorData;
|
|
throw error;
|
|
}
|
|
|
|
// Handle responses with no content (e.g., DELETE)
|
|
if (response.status === 204) {
|
|
return null;
|
|
}
|
|
|
|
return await response.json();
|
|
|
|
} catch (error) {
|
|
console.error(`Fetch error for ${url}:`, error);
|
|
// Re-throw generic network errors or specific API errors
|
|
if (error instanceof TypeError && error.message.includes('Failed to fetch')) {
|
|
throw new Error(`Network Error: Could not connect to API (${url}).`);
|
|
}
|
|
throw error; // Re-throw API errors or other exceptions
|
|
}
|
|
}
|
|
|
|
|
|
// --- Specific API Functions ---
|
|
|
|
export async function getUserData() {
|
|
return await fetchApi('/api/auth/me', { method: 'GET' });
|
|
}
|
|
|
|
export async function getAdminData() {
|
|
return await fetchApi('/api/auth/admin', { method: 'GET' });
|
|
}
|
|
|
|
export async function getAllUsers() {
|
|
return await fetchApi('/api/auth/users', { method: 'GET' });
|
|
}
|
|
|
|
export async function deleteUserById(userId) {
|
|
return await fetchApi(`/api/auth/user/${userId}`, { method: 'DELETE' });
|
|
}
|
|
|
|
export async function getAvailableModels() {
|
|
// Note: OpenAI endpoints might not require the Bearer token if using a proxy/backend key
|
|
const requiresAuth = !API_KEY.startsWith('YOUR_'); // Simple check if a real key seems present
|
|
const headers = requiresAuth ? { 'Authorization': `Bearer ${API_KEY}` } : {};
|
|
try {
|
|
// Using BASE_API_URL assumes your proxy handles the /v1 path
|
|
const data = await fetchApi('/v1/models', { method: 'GET', headers }, false); // Auth header likely not needed here if backend handles it
|
|
// Return the first model ID, or handle multiple models if needed
|
|
return data?.data?.[0]?.id || 'default-model-id'; // Provide a fallback
|
|
} catch (error) {
|
|
console.error("Error fetching models:", error);
|
|
showAlert("Fehler beim Abrufen der Modelle vom Server.", "error");
|
|
throw error; // Allow caller to handle
|
|
}
|
|
|
|
}
|
|
|
|
export async function streamChatCompletion(messages, systemPrompt, model) {
|
|
const body = {
|
|
model: model,
|
|
messages: [{ role: "system", content: systemPrompt }, ...messages],
|
|
stream: true,
|
|
temperature: 0.5, // Adjust temperature as needed
|
|
};
|
|
const requiresAuth = !API_KEY.startsWith('YOUR_');
|
|
const headers = requiresAuth ? { 'Authorization': `Bearer ${API_KEY}` } : {};
|
|
|
|
// This needs to return the raw Response object to handle the stream
|
|
try {
|
|
const response = await fetch(`${BASE_API_URL}/v1/chat/completions`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', ...headers },
|
|
body: JSON.stringify(body)
|
|
});
|
|
|
|
if (!response.ok || !response.body) {
|
|
let errorData;
|
|
try { errorData = await response.json(); } catch (e) { errorData = { message: response.statusText }; }
|
|
console.error(`API Error ${response.status}:`, errorData);
|
|
const error = new Error(errorData.message || `HTTP error! status: ${response.status}`);
|
|
error.status = response.status;
|
|
throw error;
|
|
}
|
|
return response; // Return the raw response for stream handling
|
|
|
|
} catch (error) {
|
|
console.error(`Fetch stream error:`, error);
|
|
if (error instanceof TypeError && error.message.includes('Failed to fetch')) {
|
|
throw new Error(`Network Error: Could not connect to API (${BASE_API_URL}).`);
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function tokenizePrompt(promptMessages, systemPrompt, model) {
|
|
// Format messages array into the specific string format expected by your /tokenize endpoint
|
|
const formatArrayToCustomString = (array) => {
|
|
return '[' +
|
|
array.map(dict => '{' + Object.entries(dict).map(([key, value]) => `'${key}':'${value.replace(/'/g, "\\'")}'`).join(', ') + '}') // Escape single quotes in values
|
|
.join(', ') +
|
|
']';
|
|
};
|
|
|
|
const messages = [{ role: "system", content: systemPrompt }, ...promptMessages];
|
|
const formattedString = `"${formatArrayToCustomString(messages)}"`; // Wrap in double quotes as per your example
|
|
|
|
const body = {
|
|
model: model,
|
|
prompt: formattedString,
|
|
add_special_tokens: true // Assuming this is correct for your backend
|
|
};
|
|
const requiresAuth = !API_KEY.startsWith('YOUR_');
|
|
const headers = requiresAuth ? { 'Authorization': `Bearer ${API_KEY}` } : {};
|
|
|
|
try {
|
|
// Assuming /tokenize is relative to BASE_API_URL
|
|
return await fetchApi('/tokenize', { method: 'POST', body: JSON.stringify(body), headers }, false);
|
|
} catch (error) {
|
|
console.error("Error tokenizing prompt:", error);
|
|
showAlert("Fehler bei der Token-Berechnung.", "error");
|
|
// Return a default structure or re-throw
|
|
return { count: 0, max_model_len: 4096 }; // Example fallback
|
|
}
|
|
} |