Created
December 4, 2023 23:32
-
-
Save awakenedhaggis/bd9dbf2421325117f7e5c20f62e1c99f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Name: Kagi FastGPT | |
// Description: Query FastGPT by Kagi | |
// Author: Phil Duncan | |
import '@johnlindquist/kit'; | |
/** A full {@link https://help.kagi.com/kagi/api/fastgpt.html#fastgpt-answer | FastGPT Answer} object */ | |
interface Answer { | |
meta: Meta; | |
data: Data; | |
} | |
interface Data { | |
// LLM response | |
output: string; | |
// Number of tokens used | |
tokens: number; | |
// References used in output, in order | |
references: Reference[]; | |
} | |
interface Meta { | |
id: string; | |
// Location of server | |
node: string; | |
// Time in ms for a response | |
ms: number; | |
// Remaining balance | |
api_balance: number; | |
} | |
interface Reference { | |
title: string; | |
// Short text from reference | |
snippet: string; | |
url: string; | |
} | |
/** | |
* Additional non-required | |
* {@link https://help.kagi.com/kagi/api/fastgpt.html#parameters | Parameters} | |
* | |
* @requires query | |
*/ | |
interface Parameters { | |
/** Main query sent to FastGPT */ | |
query: string; | |
/** Whether to allow cached requests & responses. (default true) */ | |
cache?: boolean; | |
/** @deprecated Parameter is out of service, and may be removed */ | |
web_search?: boolean; | |
} | |
let url = 'https://kagi.com/api/v0/fastgpt'; | |
const key = await env('KAGI_API_KEY', { | |
hint: `Generate your <a href=https://kagi.com/settings?p=api>api key</a>`, | |
secret: true, | |
shortcuts: [ | |
{ | |
name: 'Generate Key at Kagi.com', | |
key: `${cmd}+g`, | |
bar: 'left', | |
onPress: () => { | |
open('https://kagi.com/settings?p=api'); | |
}, | |
}, | |
], | |
}); | |
let lastQuery: string; | |
let currentAnswer: Answer; | |
async function callFastGPT(params: Parameters): Promise<Answer> { | |
const request = await fetch(url, { | |
method: 'POST', | |
headers: { | |
Accept: 'application/json', | |
'Content-Type': 'application/json', | |
Authorization: `Bot ${key}`, | |
}, | |
body: JSON.stringify({ | |
...params, | |
}), | |
}); | |
if (!request.ok) handleError(request.statusText, 'RequestApi'); | |
const response: Answer = await request.json(); | |
return response; | |
} | |
async function addToChat(answer: Answer) { | |
//Replace loading text with reponse | |
chat.setMessage(-1, md(currentAnswer.data.output)); | |
// List all references | |
currentAnswer.data.references.forEach((reference, index) => { | |
chat.addMessage(`<a href="${reference.url}">[${index + 1}] ${reference.title}</a>`); | |
}); | |
} | |
function handleError(message: string, initiator?: string) { | |
const errorPrefix = initiator ? `[${initiator}]` : '[Error]'; | |
warn(errorPrefix, message); | |
} | |
await chat({ | |
shortcuts: [ | |
{ | |
name: 'Close', | |
key: `${cmd}+w`, | |
onPress: () => { | |
process.exit(); | |
}, | |
bar: 'left', | |
}, | |
{ | |
name: 'Regenerate Answer', | |
key: `${cmd}+r`, | |
onPress: async () => { | |
if (!lastQuery) return handleError('No query to regenerate'); | |
chat.addMessage('...'); | |
const newAnswer = await callFastGPT({ | |
query: lastQuery, | |
cache: false, | |
}); | |
addToChat(newAnswer); | |
}, | |
bar: 'left', | |
}, | |
], | |
onSubmit: async (query) => { | |
lastQuery = query; | |
chat.addMessage('...'); | |
currentAnswer = await callFastGPT({ | |
query, | |
}); | |
addToChat(currentAnswer); | |
setHint( | |
`Remaining Balance: ${currentAnswer.meta.api_balance} <a href="https://kagi.com/settings?p=billing_api">top up?</a>`, | |
); | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment