mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-03-28 14:56:24 +01:00
direct ollama requests
This commit is contained in:
parent
65865530b6
commit
ed617c2304
6 changed files with 40 additions and 95 deletions
|
@ -8,7 +8,7 @@ This project allows an AI model to write/execute code on your computer that may
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- [OpenAI API Subscription](https://openai.com/blog/openai-api), [Gemini API Subscription](https://aistudio.google.com/app/apikey), [Anthropic API Subscription](https://docs.anthropic.com/claude/docs/getting-access-to-claude), or any service compatible with the OpenAI API format (such as [Ollama](https://ollama.com/download))
|
- [OpenAI API Subscription](https://openai.com/blog/openai-api), [Gemini API Subscription](https://aistudio.google.com/app/apikey), [Anthropic API Subscription](https://docs.anthropic.com/claude/docs/getting-access-to-claude), or [Ollama Installed](https://ollama.com/download)
|
||||||
- [Minecraft Java Edition](https://www.minecraft.net/en-us/store/minecraft-java-bedrock-edition-pc)
|
- [Minecraft Java Edition](https://www.minecraft.net/en-us/store/minecraft-java-bedrock-edition-pc)
|
||||||
- [Node.js](https://nodejs.org/) (at least v14)
|
- [Node.js](https://nodejs.org/) (at least v14)
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ Add one of these environment variables:
|
||||||
|
|
||||||
⭐[How do I add the API key as an environment variable?](https://phoenixnap.com/kb/windows-set-environment-variable)⭐
|
⭐[How do I add the API key as an environment variable?](https://phoenixnap.com/kb/windows-set-environment-variable)⭐
|
||||||
|
|
||||||
If you use Ollama, to install the models used by default (generation and embedding), execute the following script:
|
If you use Ollama, to install the models used by default (generation and embedding), execute the following terminal command:
|
||||||
`ollama pull mistral:instruct && ollama pull nomic-embed-text`
|
`ollama pull phi3 && ollama pull nomic-embed-text`
|
||||||
|
|
||||||
Then, clone/download this repository
|
Then, clone/download this repository
|
||||||
|
|
||||||
|
@ -38,8 +38,6 @@ Run `node main.js`
|
||||||
|
|
||||||
You can configure the agent's name, model, and prompts in their profile like `andy.json`.
|
You can configure the agent's name, model, and prompts in their profile like `andy.json`.
|
||||||
|
|
||||||
You can configure local service in `local-config.json`.
|
|
||||||
|
|
||||||
You can configure project details in `settings.json`.
|
You can configure project details in `settings.json`.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"url": "http://localhost:11434",
|
|
||||||
"api_key": "ollama",
|
|
||||||
"embedding_model": "nomic-embed-text"
|
|
||||||
}
|
|
4
main.js
4
main.js
|
@ -1,7 +1,7 @@
|
||||||
import { AgentProcess } from './src/process/agent-process.js';
|
import { AgentProcess } from './src/process/agent-process.js';
|
||||||
|
|
||||||
let profile = './radley.json';
|
let profile = './andy.json';
|
||||||
let load_memory = false;
|
let load_memory = false;
|
||||||
let init_message = 'Say hello world and your name. Do NOT use any command yet, nor make any comment about that fact.';
|
let init_message = 'Say hello world and your name.';
|
||||||
|
|
||||||
new AgentProcess().start(profile, load_memory, init_message);
|
new AgentProcess().start(profile, load_memory, init_message);
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "radley",
|
"name": "radley",
|
||||||
|
|
||||||
"model": "local[mistral:instruct]",
|
"model": "llama3",
|
||||||
|
|
||||||
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$STATS\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
|
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer('playername', 3)'. This is extremely important to me, take a deep breath and have fun :)\n$STATS\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,8 @@ export class Prompter {
|
||||||
this.model = new GPT(model_name);
|
this.model = new GPT(model_name);
|
||||||
else if (model_name.includes('claude'))
|
else if (model_name.includes('claude'))
|
||||||
this.model = new Claude(model_name);
|
this.model = new Claude(model_name);
|
||||||
else if (model_name.includes('local'))
|
|
||||||
this.model = new Local(model_name);
|
|
||||||
else
|
else
|
||||||
throw new Error('Unknown model ' + model_name);
|
this.model = new Local(model_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
getName() {
|
||||||
|
|
|
@ -1,69 +1,25 @@
|
||||||
import OpenAIApi from 'openai';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { readFileSync } from 'fs';
|
|
||||||
|
|
||||||
let localSettings = JSON.parse(readFileSync('./local-config.json', 'utf8'));
|
|
||||||
|
|
||||||
function getContentInBrackets(str) {
|
|
||||||
const startIndex = str.indexOf("[");
|
|
||||||
const endIndex = str.indexOf("]");
|
|
||||||
|
|
||||||
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
||||||
return str.substring(startIndex + 1, endIndex);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Local {
|
export class Local {
|
||||||
constructor(model_name) {
|
constructor(model_name) {
|
||||||
this.model_name = getContentInBrackets(model_name);
|
this.model_name = model_name;
|
||||||
let localConfig = null;
|
this.embedding_model = 'nomic-embed-text';
|
||||||
localSettings["url"] = localSettings["url"].replace("/v1", "");
|
this.url = 'http://localhost:11434';
|
||||||
|
this.chat_endpoint = '/api/chat';
|
||||||
if (this.model_name == "") {
|
this.embedding_endpoint = '/api/embeddings';
|
||||||
throw new Error('Model is not specified! Please ensure you input the model in the following format: ollama[model]. For example, for Mistral instruct, use: ollama[mistral:instruct]');
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.get(localSettings["url"]).then(response => {
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
localConfig = {
|
|
||||||
baseURL: `${localSettings["url"]}/v1`,
|
|
||||||
apiKey: localSettings["api_key"],
|
|
||||||
};
|
|
||||||
|
|
||||||
this.openai = new OpenAIApi(localConfig);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`Error relating the endpoint: ${response.status}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendRequest(turns, systemMessage, stop_seq='***') {
|
async sendRequest(turns, systemMessage) {
|
||||||
|
|
||||||
let messages = [{'role': 'system', 'content': systemMessage}].concat(turns);
|
let messages = [{'role': 'system', 'content': systemMessage}].concat(turns);
|
||||||
|
|
||||||
let res = null;
|
let res = null;
|
||||||
try {
|
try {
|
||||||
console.log(`Awaiting local response... (model: ${this.model_name})`)
|
console.log(`Awaiting local response... (model: ${this.model_name})`)
|
||||||
console.log('Messages:', messages);
|
console.log('Messages:', messages);
|
||||||
let completion = await this.openai.chat.completions.create({
|
res = await this.send(this.chat_endpoint, {model: this.model_name, messages: messages, stream: false});
|
||||||
model: this.model_name,
|
if (res)
|
||||||
messages: messages,
|
res = res['message']['content'];
|
||||||
stop: stop_seq,
|
|
||||||
});
|
|
||||||
if (completion.choices[0].finish_reason == 'length')
|
|
||||||
throw new Error('Context length exceeded');
|
|
||||||
console.log('Received.')
|
|
||||||
res = completion.choices[0].message.content;
|
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
if ((err.message == 'Context length exceeded' || err.code == 'context_length_exceeded') && turns.length > 1) {
|
if (err.message.toLowerCase().includes('context length') && turns.length > 1) {
|
||||||
console.log('Context length exceeded, trying again with shorter context.');
|
console.log('Context length exceeded, trying again with shorter context.');
|
||||||
return await sendRequest(turns.slice(1), systemMessage, stop_seq);
|
return await sendRequest(turns.slice(1), systemMessage, stop_seq);
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,31 +31,29 @@ export class Local {
|
||||||
}
|
}
|
||||||
|
|
||||||
async embed(text) {
|
async embed(text) {
|
||||||
|
let body = {model: this.embedding_model, prompt: text};
|
||||||
try {
|
let res = await this.send(this.embedding_endpoint, body);
|
||||||
if (localSettings["api_key"] == "ollama") { //Embedding if it is Ollama (temporary)
|
return res['embedding']
|
||||||
const response = await axios.post(`${localSettings["url"]}/api/embeddings`, {
|
|
||||||
model: localSettings["embedding_model"],
|
|
||||||
prompt: text
|
|
||||||
});
|
|
||||||
return response.data.embedding;
|
|
||||||
}
|
|
||||||
|
|
||||||
const embedding = await this.openai.embeddings.create({
|
|
||||||
model: localSettings["embedding_model"],
|
|
||||||
input: text,
|
|
||||||
encoding_format: "float",
|
|
||||||
});
|
|
||||||
return embedding.data[0].embedding;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log('Error embedding text:', error.response ? error.response.data : error.message);
|
|
||||||
return Array(1).fill().map(() => Math.random());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async send(endpoint, body) {
|
||||||
|
const url = new URL(endpoint, this.url);
|
||||||
|
let method = 'POST';
|
||||||
|
let headers = new Headers();
|
||||||
|
const request = new Request(url, {method, headers, body: JSON.stringify(body)});
|
||||||
|
let data = null;
|
||||||
|
try {
|
||||||
|
const res = await fetch(request);
|
||||||
|
if (res.ok) {
|
||||||
|
data = await res.json();
|
||||||
|
} else {
|
||||||
|
throw new Error(`Ollama Status: ${res.status}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to send Ollama request.');
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue