You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
3.8 KiB

// 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<MessageHistory> {
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<Reply> {
if (!this.characterInternalId)
this.characterInternalId = (
await this.#client.fetchCharacterInfo(this.characterId)
).participant__user__username;
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);
}
}