fixes model initialization for mlx

This commit is contained in:
geoffsee
2025-06-18 13:30:38 -04:00
parent 38b364caeb
commit f1d7f52dbd
12 changed files with 127 additions and 81 deletions

View File

@@ -2,7 +2,6 @@ import React, { useEffect } from "react";
import { Stack } from "@chakra-ui/react"; import { Stack } from "@chakra-ui/react";
import Chat from "../../components/chat/Chat"; import Chat from "../../components/chat/Chat";
import clientChatStore from "../../stores/ClientChatStore"; import clientChatStore from "../../stores/ClientChatStore";
import { getModelFamily } from "../../components/chat/lib/SupportedModels";
// renders "/" // renders "/"
export default function IndexPage() { export default function IndexPage() {

View File

@@ -23,7 +23,7 @@ export const UserOptionsStoreModel = types
.split(";") .split(";")
.find((row) => row.startsWith("user_preferences")); .find((row) => row.startsWith("user_preferences"));
console.log(document.cookie.split(";")); // console.log(document.cookie.split(";"));
const newUserOptions = JSON.stringify({ const newUserOptions = JSON.stringify({
theme: self.theme, theme: self.theme,
@@ -46,7 +46,7 @@ export const UserOptionsStoreModel = types
.find((row) => row.startsWith("user_preferences")); .find((row) => row.startsWith("user_preferences"));
if (!userPreferencesCoookie) { if (!userPreferencesCoookie) {
console.log("No user preferences cookie found, creating one"); // console.log("No user preferences cookie found, creating one");
self.storeUserOptions(); self.storeUserOptions();
} }
@@ -60,20 +60,20 @@ export const UserOptionsStoreModel = types
window.addEventListener("scroll", () => { window.addEventListener("scroll", () => {
if (ClientChatStore.isLoading && self.followModeEnabled) { if (ClientChatStore.isLoading && self.followModeEnabled) {
console.log("scrolling"); // console.log("scrolling");
self.setFollowModeEnabled(false); self.setFollowModeEnabled(false);
} }
}); });
window.addEventListener("wheel", () => { window.addEventListener("wheel", () => {
if (ClientChatStore.isLoading && self.followModeEnabled) { if (ClientChatStore.isLoading && self.followModeEnabled) {
console.log("wheel"); // console.log("wheel");
self.setFollowModeEnabled(false); self.setFollowModeEnabled(false);
} }
}); });
window.addEventListener("touchmove", () => { window.addEventListener("touchmove", () => {
console.log("touchmove"); // console.log("touchmove");
if (ClientChatStore.isLoading && self.followModeEnabled) { if (ClientChatStore.isLoading && self.followModeEnabled) {
self.setFollowModeEnabled(false); self.setFollowModeEnabled(false);
} }

View File

@@ -12,7 +12,9 @@ interface Env {
// KV Bindings // KV Bindings
KV_STORAGE: KVNamespace; KV_STORAGE: KVNamespace;
// Text/Secrets // Text/Secrets
METRICS_HOST: string;
OPENAI_API_ENDPOINT: string; OPENAI_API_ENDPOINT: string;
OPENAI_API_KEY: string; OPENAI_API_KEY: string;
EVENTSOURCE_HOST: string; EVENTSOURCE_HOST: string;
@@ -24,4 +26,6 @@ interface Env {
CEREBRAS_API_KEY: string; CEREBRAS_API_KEY: string;
CLOUDFLARE_API_KEY: string; CLOUDFLARE_API_KEY: string;
CLOUDFLARE_ACCOUNT_ID: string; CLOUDFLARE_ACCOUNT_ID: string;
MLX_API_KEY: string;
OLLAMA_API_KEY: string;
} }

View File

@@ -17,11 +17,18 @@ configure_dev_vars() {
# Default URL is automatic but can be overridden for remote deployments # Default URL is automatic but can be overridden for remote deployments
if [[ "$endpoint_url" == *"11434"* ]]; then if [[ "$endpoint_url" == *"11434"* ]]; then
echo "OPENAI_API_ENDPOINT=http://localhost:11434" >> "${ENV_LOCAL_PATH}"
echo "OLLAMA_API_KEY=active" >> "${ENV_LOCAL_PATH}" echo "OLLAMA_API_KEY=active" >> "${ENV_LOCAL_PATH}"
echo "OPENAI_API_ENDPOINT=http://localhost:11434" >> "${DEV_VARS_PATH}"
echo "OLLAMA_API_KEY=active" >> "${DEV_VARS_PATH}" echo "OLLAMA_API_KEY=active" >> "${DEV_VARS_PATH}"
fi fi
if [[ "$endpoint_url" == *"10240"* ]]; then if [[ "$endpoint_url" == *"10240"* ]]; then
echo "OPENAI_API_ENDPOINT=http://localhost:10240/v1" >> "${ENV_LOCAL_PATH}"
echo "MLX_API_KEY=active" >> "${ENV_LOCAL_PATH}" echo "MLX_API_KEY=active" >> "${ENV_LOCAL_PATH}"
echo "OPENAI_API_ENDPOINT=http://localhost:10240/v1" >> "${DEV_VARS_PATH}"
echo "MLX_API_KEY=active" >> "${DEV_VARS_PATH}" echo "MLX_API_KEY=active" >> "${DEV_VARS_PATH}"
fi fi

View File

@@ -57,14 +57,15 @@ export function createRouter() {
// return documentService.handleGetDocument(r) // return documentService.handleGetDocument(r)
// }) // })
.all("/api/metrics/*", async (r, e, c) => { .all("/api/metrics*", async (r, e, c) => {
const { metricsService } = createRequestContext(e, c); const { metricsService } = createRequestContext(e, c);
return metricsService.handleMetricsRequest(r); return metricsService.handleMetricsRequest(r);
}) })
// renders the app // renders the app
.get('*', async (r, e, c) => { .get("^(?!/api/).*$", async (r, e, c) => {
const { assetService } = createRequestContext(e, c);
const { assetService } = createRequestContext(e, c);
console.log('Request received:', { url: r.url, headers: r.headers }); console.log('Request received:', { url: r.url, headers: r.headers });

View File

@@ -13,13 +13,13 @@ export class AssistantSdk {
userLocation = "", userLocation = "",
} = params; } = params;
// Handle both nested and flat few_shots structures // Handle both nested and flat few_shots structures
console.log('[DEBUG_LOG] few_shots:', JSON.stringify(few_shots)); // console.log('[DEBUG_LOG] few_shots:', JSON.stringify(few_shots));
let selectedFewshots = Utils.selectEquitably?.(few_shots); let selectedFewshots = Utils.selectEquitably?.(few_shots);
console.log('[DEBUG_LOG] selectedFewshots after Utils.selectEquitably:', JSON.stringify(selectedFewshots)); // console.log('[DEBUG_LOG] selectedFewshots after Utils.selectEquitably:', JSON.stringify(selectedFewshots));
if (!selectedFewshots) { if (!selectedFewshots) {
// If Utils.selectEquitably returns undefined, use few_shots directly // If Utils.selectEquitably returns undefined, use few_shots directly
selectedFewshots = few_shots; selectedFewshots = few_shots;
console.log('[DEBUG_LOG] selectedFewshots after fallback:', JSON.stringify(selectedFewshots)); // console.log('[DEBUG_LOG] selectedFewshots after fallback:', JSON.stringify(selectedFewshots));
} }
const sdkDate = new Date().toISOString(); const sdkDate = new Date().toISOString();
const [currentDate] = sdkDate.includes("T") ? sdkDate.split("T") : [sdkDate]; const [currentDate] = sdkDate.includes("T") ? sdkDate.split("T") : [sdkDate];

View File

@@ -35,8 +35,8 @@ export class ChatSdk {
const preprocessedContext = await ChatSdk.preprocess({ const preprocessedContext = await ChatSdk.preprocess({
messages, messages,
}); });
console.log(ctx.env) // console.log(ctx.env)
console.log(ctx.env.SERVER_COORDINATOR); // console.log(ctx.env.SERVER_COORDINATOR);
const objectId = ctx.env.SERVER_COORDINATOR.idFromName("stream-index"); const objectId = ctx.env.SERVER_COORDINATOR.idFromName("stream-index");
const durableObject = ctx.env.SERVER_COORDINATOR.get(objectId); const durableObject = ctx.env.SERVER_COORDINATOR.get(objectId);

View File

@@ -16,7 +16,7 @@ export class ProviderRepository {
openai: 'https://api.openai.com/v1/', openai: 'https://api.openai.com/v1/',
cerebras: 'https://api.cerebras.com/v1/', cerebras: 'https://api.cerebras.com/v1/',
ollama: "http://localhost:11434", ollama: "http://localhost:11434",
mlx: "http://localhost:10240", mlx: "http://localhost:10240/v1",
} }
static async getModelFamily(model, env: Env) { static async getModelFamily(model, env: Env) {
@@ -42,33 +42,41 @@ export class ProviderRepository {
for (let i = 0; i < envKeys.length; i++) { for (let i = 0; i < envKeys.length; i++) {
if (envKeys[i].endsWith('KEY')) { if (envKeys[i].endsWith('KEY')) {
const detectedProvider = envKeys[i].split('_')[0].toLowerCase(); const detectedProvider = envKeys[i].split('_')[0].toLowerCase();
switch (detectedProvider) { const detectedProviderValue = env[envKeys[i]];
case 'anthropic': if(detectedProviderValue) {
this.#providers.push({ console.log({detectedProviderValue});
name: 'anthropic', switch (detectedProvider) {
key: env.ANTHROPIC_API_KEY, case 'anthropic':
endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS['anthropic'] console.log({detectedProvider});
}); this.#providers.push({
break; name: 'anthropic',
case 'gemini': key: env.ANTHROPIC_API_KEY,
this.#providers.push({ endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS['anthropic']
name: 'google', });
key: env.GEMINI_API_KEY, break;
endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS['google'] case 'gemini':
}); console.log({detectedProvider});
break; this.#providers.push({
case 'cloudflare': name: 'google',
this.#providers.push({ key: env.GEMINI_API_KEY,
name: 'cloudflare', endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS['google']
key: env.CLOUDFLARE_API_KEY, });
endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS[detectedProvider].replace("{CLOUDFLARE_ACCOUNT_ID}", env.CLOUDFLARE_ACCOUNT_ID) break;
}) case 'cloudflare':
default: console.log({detectedProvider});
this.#providers.push({ this.#providers.push({
name: detectedProvider, name: 'cloudflare',
key: env[envKeys[i]], key: env.CLOUDFLARE_API_KEY,
endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS[detectedProvider] endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS[detectedProvider].replace("{CLOUDFLARE_ACCOUNT_ID}", env.CLOUDFLARE_ACCOUNT_ID)
}); })
default:
console.log({detectedProvider});
this.#providers.push({
name: detectedProvider,
key: env[envKeys[i]],
endpoint: ProviderRepository.OPENAI_COMPAT_ENDPOINTS[detectedProvider]
});
}
} }
} }
} }

View File

@@ -8,24 +8,32 @@ import DurableObjectLocal from "./ServerCoordinatorBun";
const router = Server.Router(); const router = Server.Router();
config({ path: ['./.env'] }) config({
path: ".env",
debug: true,
// defaults: {
// EVENTSOURCE_HOST: "https://eventsource.seemueller.io",
// }
})
export default { export default {
port: 3003, port: 3003,
fetch: async (request: RequestLike, env: { [key: string]: any; }, ctx: any) =>{ fetch: async (request: RequestLike, env: { [key: string]: any; }, ctx: any) =>{
console.log("[trace] request: ", request.method, request.url, "headers: ", request.headers.get("referer"), "body: ", request.body, "env: ", env, "ctx: ", ctx, "") // console.log("[trace] request: ", request.method, request.url, "headers: ", request.headers.get("referer"), "body: ", request.body, "env: ", env, "ctx: ", ctx, "")
env["SERVER_COORDINATOR"] = DurableObjectLocal env["SERVER_COORDINATOR"] = DurableObjectLocal;
env["ASSETS"] = assetHandler.ASSETS env["ASSETS"] = assetHandler.ASSETS;
env["EVENTSOURCE_HOST"] = process.env.EVENTSOURCE_HOST env["EVENTSOURCE_HOST"] = process.env.EVENTSOURCE_HOST;
env["GROQ_API_KEY"] = process.env.GROQ_API_KEY env["GROQ_API_KEY"] = process.env.GROQ_API_KEY;
env["ANTHROPIC_API_KEY"] = process.env.ANTHROPIC_API_KEY env["ANTHROPIC_API_KEY"] = process.env.ANTHROPIC_API_KEY;
env["FIREWORKS_API_KEY"] = process.env.FIREWORKS_API_KEY env["FIREWORKS_API_KEY"] = process.env.FIREWORKS_API_KEY;
env["XAI_API_KEY"] = process.env.XAI_API_KEY env["XAI_API_KEY"] = process.env.XAI_API_KEY;
env["CEREBRAS_API_KEY"] = process.env.CEREBRAS_API_KEY env["CEREBRAS_API_KEY"] = process.env.CEREBRAS_API_KEY;
env["CLOUDFLARE_API_KEY"] = process.env.CLOUDFLARE_API_KEY env["CLOUDFLARE_API_KEY"] = process.env.CLOUDFLARE_API_KEY;
env["CLOUDFLARE_ACCOUNT_ID"] = process.env.CLOUDFLARE_ACCOUNT_ID env["CLOUDFLARE_ACCOUNT_ID"] = process.env.CLOUDFLARE_ACCOUNT_ID;
env["KV_STORAGE"] = new BunSqliteKVNamespace({namespace: "open-gsio"}) env["MLX_API_KEY"] = process.env.MLX_API_KEY;
env["OLLAMA_API_KEY"] = process.env.OLLAMA_API_KEY;
env["KV_STORAGE"] = new BunSqliteKVNamespace({namespace: "open-gsio"});
try { try {

View File

@@ -126,31 +126,38 @@ const ChatService = types
// ----- Helpers ---------------------------------------------------------- // ----- Helpers ----------------------------------------------------------
const logger = console; const logger = console;
// ----- 1. Try cached value --------------------------------------------- const useCache = false;
try {
const cached = yield self.env.KV_STORAGE.get('supportedModels'); if(useCache) {
if (cached) { // ----- 1. Try cached value ---------------------------------------------
const parsed = JSON.parse(cached as string); try {
if (Array.isArray(parsed)) { const cached = yield self.env.KV_STORAGE.get('supportedModels');
logger.info('Cache hit returning supportedModels from KV'); if (cached) {
return new Response(JSON.stringify(parsed), { status: 200 }); const parsed = JSON.parse(cached as string);
if (Array.isArray(parsed) && parsed.length > 0) {
logger.info('Cache hit returning supportedModels from KV');
return new Response(JSON.stringify(parsed), { status: 200 });
}
logger.warn('Cache entry malformed refreshing');
} }
logger.warn('Cache entry malformed refreshing'); } catch (err) {
logger.error('Error reading/parsing supportedModels cache', err);
} }
} catch (err) {
logger.error('Error reading/parsing supportedModels cache', err);
} }
// ----- 2. Build fresh list --------------------------------------------- // ----- 2. Build fresh list ---------------------------------------------
const providerRepo = new ProviderRepository(self.env); const providerRepo = new ProviderRepository(self.env);
const providers = providerRepo.getProviders(); const providers = providerRepo.getProviders();
console.log({ providers })
const providerModels = new Map<string, any[]>(); const providerModels = new Map<string, any[]>();
const modelMeta = new Map<string, any>(); const modelMeta = new Map<string, any>();
for (const provider of providers) { for (const provider of providers) {
if (!provider.key) continue; if (!provider.key) continue;
logger.info(`Fetching models for provider «${provider.name}»`); logger.info(`Fetching models from «${provider.endpoint}»`);
const openai = new OpenAI({ apiKey: provider.key, baseURL: provider.endpoint }); const openai = new OpenAI({ apiKey: provider.key, baseURL: provider.endpoint });

View File

@@ -17,20 +17,32 @@ const MetricsService = types
}, },
handleMetricsRequest: flow(function* (request: Request) { handleMetricsRequest: flow(function* (request: Request) {
const url = new URL(request.url); const url = new URL(request.url);
const proxyUrl = `https://metrics.seemueller.io${url.pathname}${url.search}`; let proxyUrl = "";
if(self.env.METRICS_HOST) {
proxyUrl = new URL(`${self.env.METRICS_HOST}${url.pathname}${url.search}`).toString();
}
try { if(proxyUrl) {
const response = yield fetch(proxyUrl, { try {
const response = yield fetch(proxyUrl, {
method: request.method,
headers: request.headers,
body: ["GET", "HEAD"].includes(request.method) ? null : request.body,
redirect: "follow",
});
return response;
} catch (error) {
console.error("Failed to proxy metrics request:", error);
return new Response("metrics misconfigured", { status: 200 });
}
} else {
const event = {
method: request.method, method: request.method,
headers: request.headers, headers: request.headers,
body: ["GET", "HEAD"].includes(request.method) ? null : request.body, body: ["GET", "HEAD"].includes(request.method) ? null : request.body,
redirect: "follow", }
}); self.env.KV_STORAGE.put(`metrics_events::${crypto.randomUUID()}`, JSON.stringify(event));
return response;
} catch (error) {
console.error("Failed to proxy metrics request:", error);
return new Response("Failed to fetch metrics", { status: 500 });
} }
}), }),
})); }));

View File

@@ -39,7 +39,7 @@ const TransactionService = types
`https://wallets.seemueller.io${CreateWalletEndpoints[currency]}`, `https://wallets.seemueller.io${CreateWalletEndpoints[currency]}`,
); );
const walletResponse = await walletRequest.text(); const walletResponse = await walletRequest.text();
console.log({ walletRequest: walletResponse }); // console.log({ walletRequest: walletResponse });
const [address, privateKey, publicKey, phrase] = const [address, privateKey, publicKey, phrase] =
JSON.parse(walletResponse); JSON.parse(walletResponse);
@@ -56,12 +56,12 @@ const TransactionService = types
phrase, phrase,
}; };
console.log({ txRecord }); // console.log({ txRecord });
const key = `transactions::prepared::${txKey}`; const key = `transactions::prepared::${txKey}`;
await self.env.KV_STORAGE.put(key, JSON.stringify(txRecord)); await self.env.KV_STORAGE.put(key, JSON.stringify(txRecord));
console.log(`PREPARED TRANSACTION ${key}`); // console.log(`PREPARED TRANSACTION ${key}`);
return { return {
depositAddress: address, depositAddress: address,
@@ -72,7 +72,7 @@ const TransactionService = types
handleTransact: async function (request: Request) { handleTransact: async function (request: Request) {
try { try {
const raw = await request.text(); const raw = await request.text();
console.log({ raw }); // console.log({ raw });
const [action, ...payload] = raw.split(","); const [action, ...payload] = raw.split(",");
const response = await self.routeAction(action, payload); const response = await self.routeAction(action, payload);