// deno-lint-ignore-file no-explicit-any import Client from "./Client.ts"; interface MessageHistory { messages: { id: number; text: string; src__name: string; src__user__username: string; src__user__id: number; tgt__user__id: number; src__is_human: boolean; src__character__avatar_file_name: string | null; is_alternative: boolean; image_rel_path: string; image_prompt_text: string; image_description_type: string; responsible_user__username: string | null; deleted: boolean | null; // This is probably a boolean??? src_char: { participant: { name: string }; avatar_file_name: string | null; }; }[]; has_more: boolean; next_page: number; } interface Reply { replies: { text: string; id: number; }[]; src_char: { participant: { name: string }; avatar_file_name: string; }; is_final_chunk: boolean; last_user_msg_id: number; } export default class Chat { #client: Client; public characterId: string; public characterInternalId: string; public historyId: string; constructor(client: Client, id: string, history: any) { this.#client = client; this.characterId = id; this.historyId = history.external_id; this.characterInternalId = history.participants.find( (participant: any) => participant.is_human === false ).user.username; } /** * Fetches message history * @returns Message history */ public async fetchMessageHistory(): Promise { const url = new URL("https://beta.character.ai/chat/history/msgs/user/"); url.searchParams.set("history_external_id", this.historyId); const res = await this.#client.fetch(url, { headers: { Authorization: `Token ${this.#client.token}`, Accept: "application/json", "Content-Type": "application/json", }, }); const messageHistory = await res.json(); return messageHistory; } /** * Sends a message to the character * @param message The message you want to send * @returns Object with replies */ public async sendMessage(message: string): Promise { const payload = { history_external_id: this.historyId, character_external_id: this.characterId, text: message, tgt: this.characterInternalId, ranking_method: "random", faux_chat: false, staging: false, model_server_address: null, override_prefix: null, override_rank: null, rank_candidates: null, filter_candidates: null, prefix_limit: null, prefix_token_limit: null, livetune_coeff: null, stream_params: null, enable_tti: true, initial_timeout: null, insert_beginning: null, translate_candidates: null, stream_every_n_steps: 16, chunks_to_pad: 8, is_proactive: false, }; const res = await this.#client.fetch( "https://beta.character.ai/chat/streaming/", { body: JSON.stringify(payload), method: "POST", headers: { Authorization: `Token ${this.#client.token}`, Accept: "application/json", "Content-Type": "application/json", }, } ); const reader = res.body?.getReader(); if (!reader) throw new Error("How."); // Let's hope no one ever sees this let reply = ""; while (true) { const { value, done } = await reader.read(); if (done) break; reply = new TextDecoder("utf-8").decode(value); } return JSON.parse(reply); } }