1
0
Fork 0

Kudos counting for tsgames

This commit is contained in:
Pabloader 2026-02-16 18:52:34 +00:00
parent 0711d3b89a
commit a0b73eb306
5 changed files with 47 additions and 18 deletions

View File

@ -22,6 +22,11 @@
.info { .info {
margin: 0 8px; margin: 0 8px;
line-height: 36px; line-height: 36px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 16px;
} }
.buttons { .buttons {

View File

@ -12,9 +12,9 @@ import { ConnectionEditor } from "./connectionEditor";
import styles from './header.module.css'; import styles from './header.module.css';
export const Header = () => { export const Header = () => {
const { contextLength, promptTokens, modelName } = useContext(LLMContext); const { contextLength, promptTokens, modelName, spentKudos } = useContext(LLMContext);
const { const {
messages, connection, systemPrompt, lore, userPrompt, bannedWords, summarizePrompt, summaryEnabled, messages, connection, systemPrompt, lore, userPrompt, bannedWords, summarizePrompt, summaryEnabled, totalSpentKudos,
setSystemPrompt, setLore, setUserPrompt, addSwipe, setBannedWords, setInstruct, setSummarizePrompt, setSummaryEnabled, setConnection, setSystemPrompt, setLore, setUserPrompt, addSwipe, setBannedWords, setInstruct, setSummarizePrompt, setSummaryEnabled, setConnection,
} = useContext(StateContext); } = useContext(StateContext);
@ -62,7 +62,10 @@ export const Header = () => {
</button> </button>
</div> </div>
<div class={styles.info}> <div class={styles.info}>
{modelName} - {promptTokens} / {contextLength} <span>{modelName}</span>
<span>📃{promptTokens}/{contextLength}</span>
<span>💲{spentKudos}</span>
<span>💰{totalSpentKudos}</span>
</div> </div>
</div> </div>
<div class={styles.buttons}> <div class={styles.buttons}>

View File

@ -26,6 +26,7 @@ interface IContext {
hasToolCalls: boolean; hasToolCalls: boolean;
promptTokens: number; promptTokens: number;
contextLength: number; contextLength: number;
spentKudos: number;
} }
const MESSAGES_TO_KEEP = 10; const MESSAGES_TO_KEEP = 10;
@ -49,7 +50,7 @@ const processing = {
export const LLMContextProvider = ({ children }: { children?: any }) => { export const LLMContextProvider = ({ children }: { children?: any }) => {
const { const {
connection, messages, triggerNext, continueLast, lore, userPrompt, systemPrompt, bannedWords, summarizePrompt, summaryEnabled, connection, messages, triggerNext, continueLast, lore, userPrompt, systemPrompt, bannedWords, summarizePrompt, summaryEnabled,
setTriggerNext, setContinueLast, addMessage, editMessage, editSummary, setTriggerNext, setContinueLast, addMessage, editMessage, editSummary, setTotalSpentKudos,
} = useContext(StateContext); } = useContext(StateContext);
const generating = useBool(false); const generating = useBool(false);
@ -57,6 +58,7 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
const [contextLength, setContextLength] = useState(0); const [contextLength, setContextLength] = useState(0);
const [modelName, setModelName] = useState(''); const [modelName, setModelName] = useState('');
const [hasToolCalls, setHasToolCalls] = useState(false); const [hasToolCalls, setHasToolCalls] = useState(false);
const [spentKudos, setSpentKudos] = useState(0);
const isOnline = useMemo(() => contextLength > 0, [contextLength]); const isOnline = useMemo(() => contextLength > 0, [contextLength]);
@ -170,10 +172,15 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
try { try {
console.log('[LLM.generate]', prompt); console.log('[LLM.generate]', prompt);
yield* Connection.generate(connection, prompt, { setSpentKudos(0);
for await (const { text, cost } of Connection.generate(connection, prompt, {
...extraSettings, ...extraSettings,
banned_tokens: bannedWords.filter(w => w.trim()), banned_tokens: bannedWords.filter(w => w.trim()),
}); })) {
setSpentKudos(sk => sk + cost);
setTotalSpentKudos(sk => sk + cost);
yield text;
}
} catch (e) { } catch (e) {
if (e instanceof Error && e.name !== 'AbortError') { if (e instanceof Error && e.name !== 'AbortError') {
alert(e.message); alert(e.message);
@ -297,6 +304,7 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
hasToolCalls, hasToolCalls,
promptTokens, promptTokens,
contextLength, contextLength,
spentKudos,
}; };
const context = useMemo(() => rawContext, Object.values(rawContext)); const context = useMemo(() => rawContext, Object.values(rawContext));

View File

@ -1,5 +1,5 @@
import { createContext } from "preact"; import { createContext } from "preact";
import { useCallback, useEffect, useMemo, useState } from "preact/hooks"; import { useCallback, useEffect, useMemo, useState, type Dispatch, type StateUpdater } from "preact/hooks";
import { MessageTools, type IMessage } from "../tools/messages"; import { MessageTools, type IMessage } from "../tools/messages";
import { useInputState } from "@common/hooks/useInputState"; import { useInputState } from "@common/hooks/useInputState";
import { type IConnection } from "../tools/connection"; import { type IConnection } from "../tools/connection";
@ -15,6 +15,7 @@ interface IContext {
summaryEnabled: boolean; summaryEnabled: boolean;
bannedWords: string[]; bannedWords: string[];
messages: IMessage[]; messages: IMessage[];
totalSpentKudos: number;
// //
triggerNext: boolean; triggerNext: boolean;
continueLast: boolean; continueLast: boolean;
@ -36,6 +37,7 @@ interface IActions {
setSummarizePrompt: (prompt: string | Event) => void; setSummarizePrompt: (prompt: string | Event) => void;
setBannedWords: (words: string[]) => void; setBannedWords: (words: string[]) => void;
setSummaryEnabled: (summaryEnabled: boolean) => void; setSummaryEnabled: (summaryEnabled: boolean) => void;
setTotalSpentKudos: Dispatch<StateUpdater<number>>;
setTriggerNext: (triggerNext: boolean) => void; setTriggerNext: (triggerNext: boolean) => void;
setContinueLast: (continueLast: boolean) => void; setContinueLast: (continueLast: boolean) => void;
@ -91,6 +93,7 @@ Make sure to follow the world description and rules exactly. Avoid cliffhangers
summaryEnabled: true, summaryEnabled: true,
bannedWords: [], bannedWords: [],
messages: [], messages: [],
totalSpentKudos: 0,
triggerNext: false, triggerNext: false,
continueLast: false, continueLast: false,
}; };
@ -132,6 +135,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
const [bannedWords, setBannedWords] = useState<string[]>(loadedContext.bannedWords); const [bannedWords, setBannedWords] = useState<string[]>(loadedContext.bannedWords);
const [messages, setMessages] = useState(loadedContext.messages); const [messages, setMessages] = useState(loadedContext.messages);
const [summaryEnabled, setSummaryEnabled] = useState(loadedContext.summaryEnabled); const [summaryEnabled, setSummaryEnabled] = useState(loadedContext.summaryEnabled);
const [totalSpentKudos, setTotalSpentKudos] = useState(loadedContext.totalSpentKudos);
const connection = availableConnections[currentConnection] ?? DEFAULT_CONTEXT.availableConnections[0]; const connection = availableConnections[currentConnection] ?? DEFAULT_CONTEXT.availableConnections[0];
@ -164,6 +168,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
setTriggerNext, setTriggerNext,
setContinueLast, setContinueLast,
setTotalSpentKudos,
setBannedWords: (words) => setBannedWords(words.slice()), setBannedWords: (words) => setBannedWords(words.slice()),
setAvailableConnections: (connections) => setAvailableConnections(connections.slice()), setAvailableConnections: (connections) => setAvailableConnections(connections.slice()),
@ -252,6 +257,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
summaryEnabled, summaryEnabled,
bannedWords, bannedWords,
messages, messages,
totalSpentKudos,
// //
triggerNext, triggerNext,
continueLast, continueLast,

View File

@ -51,6 +51,7 @@ interface IHordeResult {
faulted: boolean; faulted: boolean;
done: boolean; done: boolean;
finished: number; finished: number;
kudos: number;
generations?: { generations?: {
text: string; text: string;
}[]; }[];
@ -88,7 +89,12 @@ export namespace Connection {
let abortController = new AbortController(); let abortController = new AbortController();
async function* generateKobold(url: string, prompt: string, extraSettings: IGenerationSettings = {}): AsyncGenerator<string> { export interface TextChunk {
text: string;
cost: number;
}
async function* generateKobold(url: string, prompt: string, extraSettings: IGenerationSettings = {}): AsyncGenerator<TextChunk> {
const sse = new SSE(`${url}/api/extra/generate/stream`, { const sse = new SSE(`${url}/api/extra/generate/stream`, {
payload: JSON.stringify({ payload: JSON.stringify({
...DEFAULT_GENERATION_SETTINGS, ...DEFAULT_GENERATION_SETTINGS,
@ -130,10 +136,10 @@ export namespace Connection {
while (!end || messages.length) { while (!end || messages.length) {
while (messages.length > 0) { while (messages.length > 0) {
const message = messages.shift(); const text = messages.shift();
if (message != null) { if (text != null) {
try { try {
yield message; yield { text, cost: 0 };
} catch { } } catch { }
} }
} }
@ -145,7 +151,7 @@ export namespace Connection {
sse.close(); sse.close();
} }
async function* generateHorde(connection: IHordeConnection, prompt: string, extraSettings: IGenerationSettings = {}): AsyncGenerator<string> { async function* generateHorde(connection: IHordeConnection, prompt: string, extraSettings: IGenerationSettings = {}): AsyncGenerator<TextChunk> {
if (!connection.model) { if (!connection.model) {
throw new Error('Horde not connected'); throw new Error('Horde not connected');
} }
@ -190,14 +196,14 @@ export namespace Connection {
} }
const { id } = await generateResponse.json() as { id: string }; const { id } = await generateResponse.json() as { id: string };
const request = async (method = 'GET'): Promise<string | null> => { const request = async (method = 'GET'): Promise<TextChunk | null> => {
const response = await fetch(`${AIHORDE}/api/v2/generate/text/status/${id}`, { method }); const response = await fetch(`${AIHORDE}/api/v2/generate/text/status/${id}`, { method });
if (response.ok && response.status < 400) { if (response.ok && response.status < 400) {
const result: IHordeResult = await response.json(); const result: IHordeResult = await response.json();
if (result.generations?.length === 1) { if (result.generations?.length === 1) {
const { text } = result.generations[0]; const { text } = result.generations[0];
return text; return { text, cost: result.kudos };
} }
} else { } else {
throw new Error(await response.text()); throw new Error(await response.text());
@ -206,16 +212,17 @@ export namespace Connection {
return null; return null;
}; };
const deleteRequest = async () => (await request('DELETE')) ?? ''; const deleteRequest = async () => (await request('DELETE')) ?? { text: '', cost: 0 };
let text: string | null = null; let text: string | null = null;
while (!text) { while (!text) {
try { try {
await delay(2500, { signal }); await delay(2500, { signal });
text = await request(); const response = await request();
if (text) { if (response?.text) {
text = response.text;
for (const sequence of requestData.params.stop_sequence) { for (const sequence of requestData.params.stop_sequence) {
const stopIdx = text.indexOf(sequence); const stopIdx = text.indexOf(sequence);
if (stopIdx >= 0) { if (stopIdx >= 0) {
@ -233,7 +240,7 @@ export namespace Connection {
} }
} }
yield unsloppedText; yield { text: unsloppedText, cost: response.cost };
requestData.prompt += unsloppedText; requestData.prompt += unsloppedText;