Create ollama e2e test (#296)
This commit is contained in:
@@ -73,6 +73,13 @@ class PageObject {
|
|||||||
await this.page.getByText("test-model").click();
|
await this.page.getByText("test-model").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async selectTestOllamaModel() {
|
||||||
|
await this.page.getByRole("button", { name: "Model: Auto" }).click();
|
||||||
|
await this.page.getByText("Local models").click();
|
||||||
|
await this.page.getByText("Ollama", { exact: true }).click();
|
||||||
|
await this.page.getByText("Testollama", { exact: true }).click();
|
||||||
|
}
|
||||||
|
|
||||||
async setUpTestProvider() {
|
async setUpTestProvider() {
|
||||||
await this.page.getByText("Add custom providerConnect to").click();
|
await this.page.getByText("Add custom providerConnect to").click();
|
||||||
// Fill out provider dialog
|
// Fill out provider dialog
|
||||||
@@ -201,6 +208,7 @@ export const test = base.extend<{
|
|||||||
const latestBuild = findLatestBuild();
|
const latestBuild = findLatestBuild();
|
||||||
// parse the directory and find paths and other info
|
// parse the directory and find paths and other info
|
||||||
const appInfo = parseElectronApp(latestBuild);
|
const appInfo = parseElectronApp(latestBuild);
|
||||||
|
process.env.OLLAMA_HOST = "http://localhost:3500/ollama";
|
||||||
process.env.E2E_TEST_BUILD = "true";
|
process.env.E2E_TEST_BUILD = "true";
|
||||||
// This is just a hack to avoid the AI setup screen.
|
// This is just a hack to avoid the AI setup screen.
|
||||||
process.env.OPENAI_API_KEY = "sk-test";
|
process.env.OPENAI_API_KEY = "sk-test";
|
||||||
|
|||||||
7
e2e-tests/ollama.spec.ts
Normal file
7
e2e-tests/ollama.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { test } from "./helpers/test_helper";
|
||||||
|
|
||||||
|
test("send message to ollama", async ({ po }) => {
|
||||||
|
await po.selectTestOllamaModel();
|
||||||
|
await po.sendPrompt("hi");
|
||||||
|
await po.snapshotMessages();
|
||||||
|
});
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
- paragraph: hi
|
||||||
|
- paragraph: ollamachunkollamachunk
|
||||||
|
- button "Retry":
|
||||||
|
- img
|
||||||
@@ -4,7 +4,7 @@ import { LocalModelListResponse, LocalModel } from "../ipc_types";
|
|||||||
|
|
||||||
const logger = log.scope("ollama_handler");
|
const logger = log.scope("ollama_handler");
|
||||||
|
|
||||||
const OLLAMA_API_URL = "http://localhost:11434";
|
const OLLAMA_API_URL = process.env.OLLAMA_HOST || "http://localhost:11434";
|
||||||
|
|
||||||
interface OllamaModel {
|
interface OllamaModel {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ function getRegularModelClient(
|
|||||||
case "ollama": {
|
case "ollama": {
|
||||||
// Ollama typically runs locally and doesn't require an API key in the same way
|
// Ollama typically runs locally and doesn't require an API key in the same way
|
||||||
const provider = createOllama({
|
const provider = createOllama({
|
||||||
baseURL: providerConfig.apiBaseUrl,
|
baseURL: process.env.OLLAMA_HOST,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
modelClient: {
|
modelClient: {
|
||||||
|
|||||||
@@ -56,8 +56,89 @@ app.get("/health", (req, res) => {
|
|||||||
res.send("OK");
|
res.send("OK");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Ollama-specific endpoints
|
||||||
|
app.get("/ollama/api/tags", (req, res) => {
|
||||||
|
const ollamaModels = {
|
||||||
|
models: [
|
||||||
|
{
|
||||||
|
name: "testollama",
|
||||||
|
modified_at: "2024-05-01T10:00:00.000Z",
|
||||||
|
size: 4700000000,
|
||||||
|
digest: "abcdef123456",
|
||||||
|
details: {
|
||||||
|
format: "gguf",
|
||||||
|
family: "llama",
|
||||||
|
families: ["llama"],
|
||||||
|
parameter_size: "8B",
|
||||||
|
quantization_level: "Q4_0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "codellama:7b",
|
||||||
|
modified_at: "2024-04-25T12:30:00.000Z",
|
||||||
|
size: 3800000000,
|
||||||
|
digest: "fedcba654321",
|
||||||
|
details: {
|
||||||
|
format: "gguf",
|
||||||
|
family: "llama",
|
||||||
|
families: ["llama", "codellama"],
|
||||||
|
parameter_size: "7B",
|
||||||
|
quantization_level: "Q5_K_M",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
console.log("* Sending fake Ollama models");
|
||||||
|
res.json(ollamaModels);
|
||||||
|
});
|
||||||
|
|
||||||
let globalCounter = 0;
|
let globalCounter = 0;
|
||||||
|
|
||||||
|
app.post("/ollama/chat", (req, res) => {
|
||||||
|
// Tell the client we’re going to stream NDJSON
|
||||||
|
res.setHeader("Content-Type", "application/x-ndjson");
|
||||||
|
res.setHeader("Cache-Control", "no-cache");
|
||||||
|
|
||||||
|
// Chunk #1 – partial answer
|
||||||
|
const firstChunk = {
|
||||||
|
model: "llama3.2",
|
||||||
|
created_at: "2023-08-04T08:52:19.385406455-07:00",
|
||||||
|
message: {
|
||||||
|
role: "assistant",
|
||||||
|
content: "ollamachunk",
|
||||||
|
images: null,
|
||||||
|
},
|
||||||
|
done: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Chunk #2 – final answer + metrics
|
||||||
|
const secondChunk = {
|
||||||
|
model: "llama3.2",
|
||||||
|
created_at: "2023-08-04T19:22:45.499127Z",
|
||||||
|
message: {
|
||||||
|
role: "assistant",
|
||||||
|
content: "",
|
||||||
|
},
|
||||||
|
done: true,
|
||||||
|
total_duration: 4883583458,
|
||||||
|
load_duration: 1334875,
|
||||||
|
prompt_eval_count: 26,
|
||||||
|
prompt_eval_duration: 342546000,
|
||||||
|
eval_count: 282,
|
||||||
|
eval_duration: 4535599000,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the first object right away
|
||||||
|
res.write(JSON.stringify(firstChunk) + "\n");
|
||||||
|
res.write(JSON.stringify(firstChunk) + "\n");
|
||||||
|
|
||||||
|
// …and the second one a moment later to mimic streaming
|
||||||
|
setTimeout(() => {
|
||||||
|
res.write(JSON.stringify(secondChunk) + "\n");
|
||||||
|
res.end(); // Close the HTTP stream
|
||||||
|
}, 300); // 300 ms delay – tweak as you like
|
||||||
|
});
|
||||||
|
|
||||||
// Handle POST requests to /v1/chat/completions
|
// Handle POST requests to /v1/chat/completions
|
||||||
app.post("/v1/chat/completions", (req, res) => {
|
app.post("/v1/chat/completions", (req, res) => {
|
||||||
const { stream = false, messages = [] } = req.body;
|
const { stream = false, messages = [] } = req.body;
|
||||||
@@ -188,7 +269,7 @@ app.post("/v1/chat/completions", (req, res) => {
|
|||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
}, 1);
|
}, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
|
|||||||
Reference in New Issue
Block a user