mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Add Gemini option
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
IfcOpenShell AI Assistant
|
||||
=========================
|
||||
|
||||
A web-based client-side (pyodide + OpenAI, Anthropic, or OpenRouter API) model interrogation and generation API based on: ifcedit, ifcquery and ifcmcp (ifcopenshell-mcp) packaged in a HTML+JS application.
|
||||
A web-based client-side (pyodide + OpenAI, Anthropic, Gemini, or OpenRouter API) model interrogation and generation API based on: ifcedit, ifcquery and ifcmcp (ifcopenshell-mcp) packaged in a HTML+JS application.
|
||||
|
||||
### Setup instructions
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
function getChatCompletionsUrl(baseURL) {
|
||||
const root = (baseURL || "https://api.openai.com/v1").replace(/\/+$/, "");
|
||||
return `${root}/chat/completions`;
|
||||
}
|
||||
|
||||
export async function chat({ apiKey, model, messages, tools }) {
|
||||
const res = await fetch("https://api.openai.com/v1/chat/completions", {
|
||||
export async function chat({ apiKey, baseURL, model, messages, tools }) {
|
||||
const res = await fetch(getChatCompletionsUrl(baseURL), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
function getChatCompletionsUrl(baseURL) {
|
||||
const root = (baseURL || "https://openrouter.ai/api/v1").replace(/\/+$/, "");
|
||||
return `${root}/chat/completions`;
|
||||
}
|
||||
|
||||
export async function chat({ apiKey, model, messages, tools }) {
|
||||
const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
|
||||
export async function chat({ apiKey, baseURL, model, messages, tools }) {
|
||||
const res = await fetch(getChatCompletionsUrl(baseURL), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
||||
+44
-1
@@ -8,6 +8,9 @@ const PROVIDERS = {
|
||||
api: openaiApi,
|
||||
apiKeyLabel: "OpenAI API key",
|
||||
apiKeyPlaceholder: "sk-...",
|
||||
baseUrlLabel: "Base URL",
|
||||
baseUrlPlaceholder: "https://api.openai.com/v1",
|
||||
baseUrlDefault: "https://api.openai.com/v1",
|
||||
models: [
|
||||
{
|
||||
value: "gpt-5",
|
||||
@@ -38,10 +41,35 @@ const PROVIDERS = {
|
||||
},
|
||||
],
|
||||
},
|
||||
gemini: {
|
||||
api: openaiApi,
|
||||
apiKeyLabel: "Gemini API key",
|
||||
apiKeyPlaceholder: "AIza...",
|
||||
baseUrlLabel: "Base URL",
|
||||
baseUrlPlaceholder: "https://generativelanguage.googleapis.com/v1beta/openai/",
|
||||
baseUrlDefault: "https://generativelanguage.googleapis.com/v1beta/openai/",
|
||||
models: [
|
||||
{
|
||||
value: "gemini-3-flash-preview",
|
||||
label: "gemini-3-flash-preview"
|
||||
},
|
||||
{
|
||||
value: "gemini-2.5-flash",
|
||||
label: "gemini-2.5-flash"
|
||||
},
|
||||
{
|
||||
value: "gemini-2.5-pro",
|
||||
label: "gemini-2.5-pro"
|
||||
},
|
||||
],
|
||||
},
|
||||
openrouter: {
|
||||
api: openrouterApi,
|
||||
apiKeyLabel: "OpenRouter API key",
|
||||
apiKeyPlaceholder: "sk-or-v1-...",
|
||||
baseUrlLabel: "Base URL",
|
||||
baseUrlPlaceholder: "https://openrouter.ai/api/v1",
|
||||
baseUrlDefault: "https://openrouter.ai/api/v1",
|
||||
models: [
|
||||
{
|
||||
value: "openai/gpt-oss-20b",
|
||||
@@ -79,6 +107,9 @@ const sendBtn = $("send");
|
||||
const inputEl = $("input");
|
||||
const apiKeyEl = $("apiKey");
|
||||
const apiKeyLabelEl = $("apiKeyLabel");
|
||||
const baseUrlRowEl = $("baseUrlRow");
|
||||
const baseUrlLabelEl = $("baseUrlLabel");
|
||||
const baseUrlEl = $("baseUrl");
|
||||
const modelEl = $("model");
|
||||
const providerEl = $("provider");
|
||||
const ifcFileEl = $("ifcFile");
|
||||
@@ -89,6 +120,15 @@ function onProviderChange() {
|
||||
const provider = PROVIDERS[providerEl.value];
|
||||
apiKeyLabelEl.innerHTML = `${provider.apiKeyLabel}<span class="small">stored in browser memory; only sent to provider servers</span>`;
|
||||
apiKeyEl.placeholder = provider.apiKeyPlaceholder;
|
||||
baseUrlRowEl.hidden = !provider.baseUrlDefault;
|
||||
if (provider.baseUrlDefault) {
|
||||
baseUrlLabelEl.innerHTML = `${provider.baseUrlLabel}<span class="small">override the API endpoint for OpenAI-compatible providers</span>`;
|
||||
baseUrlEl.placeholder = provider.baseUrlPlaceholder;
|
||||
baseUrlEl.value = provider.baseUrlDefault;
|
||||
} else {
|
||||
baseUrlEl.value = "";
|
||||
baseUrlEl.placeholder = "";
|
||||
}
|
||||
modelEl.innerHTML = provider.models.map(m => `<option value="${m.value}">${m.label}</option>`).join("");
|
||||
}
|
||||
|
||||
@@ -251,13 +291,16 @@ async function runAgentTurn(userText) {
|
||||
const apiKey = apiKeyEl.value.trim();
|
||||
if (!apiKey) throw new Error("Missing API key");
|
||||
|
||||
const { chat } = PROVIDERS[providerEl.value].api;
|
||||
const provider = PROVIDERS[providerEl.value];
|
||||
const { chat } = provider.api;
|
||||
const baseURL = provider.baseUrlDefault ? baseUrlEl.value.trim() : undefined;
|
||||
|
||||
messages.push({ role: "user", content: userText });
|
||||
|
||||
for (let i = 0; i < 64; i++) {
|
||||
const response = await chat({
|
||||
apiKey,
|
||||
baseURL,
|
||||
model: modelEl.value,
|
||||
messages: [{ role: "system", content: SYSTEM_INSTRUCTIONS }, ...messages],
|
||||
tools,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<select id="provider" style="width: 100%;">
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="anthropic">Anthropic (Claude)</option>
|
||||
<option value="gemini">Gemini</option>
|
||||
<option value="openrouter">OpenRouter</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -31,6 +32,11 @@
|
||||
<input id="apiKey" type="password" placeholder="sk-..." autocomplete="off" style="width: 100%;" />
|
||||
</div>
|
||||
|
||||
<div class="row" id="baseUrlRow">
|
||||
<label id="baseUrlLabel">Base URL<span class="small">override the API endpoint for OpenAI-compatible providers</span></label>
|
||||
<input id="baseUrl" type="text" placeholder="https://api.openai.com/v1" autocomplete="off" style="width: 100%;" />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="row" style="margin-bottom: 10px;">
|
||||
|
||||
Reference in New Issue
Block a user