Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for OpenRouter API requests using OPENROUTER_TOKEN #14

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cofounder/api/.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ PORT = 667
OPENAI_API_KEY = "REPLACE_WITH_OPENAI_KEY"
ANTHROPIC_API_KEY = "REPLACE_WITH_ANTHROPIC_KEY"
COFOUNDER_API_KEY = "REPLACE_WITH_COFOUNDER.OPENINTERFACE.AI_KEY"
OPENROUTER_TOKEN = "REPLACE_WITH_OPENROUTER_TOKEN"

# llm, can be 'ANTHROPIC' (for claude sonnet 3.5) or 'OPENAI' (uses diff. models for diff. passes)
# make sure there are matching api keys
Expand All @@ -29,4 +30,4 @@ DESIGNER_DESIGN_SYSTEM = "presets/shadcn" #"presets/shadcn"
SWARM_ENABLE = TRUE

# OPTIONAL
COFOUNDER_NICKNAME = "Cofounder"
COFOUNDER_NICKNAME = "Cofounder"
5 changes: 5 additions & 0 deletions cofounder/api/utils/anthropic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Anthropic from "@anthropic-ai/sdk";
import dotenv from "dotenv";
import openrouter from "./openrouter.js"; // Import the new openrouter module
dotenv.config();
const anthropic = new Anthropic();

Expand Down Expand Up @@ -66,6 +67,10 @@ async function inference({
messages,
stream = process.stdout,
}) {
if (process.env.OPENROUTER_TOKEN) {
return openrouter.inference({ model, messages, stream });
}

// messages are in openai format , need conversion
const converted = await _convertFromOpenaiFormat({ messages });
// console.dir({ "debug:utils:anthropic": {messages : converted.messages} } , {depth:null})
Expand Down
2 changes: 2 additions & 0 deletions cofounder/api/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import firebase from "@/utils/firebase.js";
import storage from "@/utils/storage.js";
import load from "@/utils/load.js";
import anthropic from "@/utils/anthropic.js";
import openrouter from "@/utils/openrouter.js";

export default {
parsers,
Expand All @@ -16,4 +17,5 @@ export default {
firebase,
storage,
load,
openrouter,
};
6 changes: 6 additions & 0 deletions cofounder/api/utils/openai.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from "fs";
import OpenAI from "openai";
import dotenv from "dotenv";
import openrouter from "./openrouter.js"; // Import the new openrouter module
dotenv.config();

let openai;
Expand All @@ -17,6 +18,10 @@ async function inference({
messages,
stream = process.stdout,
}) {
if (process.env.OPENROUTER_TOKEN) {
return openrouter.inference({ model, messages, stream });
}

const streaming = await openai.chat.completions.create({
model,
messages,
Expand Down Expand Up @@ -55,6 +60,7 @@ async function inference({
usage: { model, ...usage },
};
}

async function vectorize({
texts,
model = process.env.EMBEDDING_MODEL || `text-embedding-3-small`,
Expand Down
58 changes: 58 additions & 0 deletions cofounder/api/utils/openrouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import fetch from "node-fetch";

async function inference({ model, messages, stream = process.stdout }) {
const response = await fetch("https://api.openrouter.ai/v1/chat/completions", {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL should be just https://openrouter.ai/v1/chat/completions

https://openrouter.ai/docs/quick-start

method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.OPENROUTER_TOKEN}`,
},
body: JSON.stringify({
model,
messages,
stream: true,
}),
});

if (!response.ok) {
throw new Error(`OpenRouter API request failed: ${response.statusText}`);
}

const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let text = "";
let usage = {};
let cutoff_reached = false;
let chunks_buffer = "";
let chunks_iterator = 0;
const chunks_every = 5;

while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
text += chunk;
chunks_buffer += chunk;
chunks_iterator++;
if (stream?.cutoff) {
if (!cutoff_reached && text.includes(stream.cutoff)) {
cutoff_reached = true;
}
}
if (!(chunks_iterator % chunks_every)) {
stream.write(!cutoff_reached ? chunks_buffer : " ...");
chunks_buffer = "";
}
}

stream.write(`\n`);

return {
text,
usage: { model, ...usage },
};
}

export default {
inference,
};