UNPKG

bing-chat-patch

Version:

Node.js client for the unofficial Bing Chat API.

265 lines (263 loc) 9.27 kB
// src/bing-chat.ts import crypto from "node:crypto"; import WebSocket from "ws"; // src/fetch.ts var fetch = globalThis.fetch; if (typeof fetch !== "function") { throw new Error("Invalid environment: global fetch not defined"); } // src/bing-chat.ts var terminalChar = ""; var BingChat = class { constructor(opts) { const { cookie, debug = false } = opts; this._cookie = cookie; this._debug = !!debug; if (!this._cookie) { throw new Error("Bing cookie is required"); } } /** * Sends a message to Bing Chat, waits for the response to resolve, and returns * the response. * * If you want to receive a stream of partial responses, use `opts.onProgress`. * * @param message - The prompt message to send * @param opts.conversationId - Optional ID of a conversation to continue (defaults to a random UUID) * @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated * * @returns The response from Bing Chat */ async sendMessage(text, opts = {}) { const { invocationId = "1", onProgress, locale = "en-US", market = "en-US", region = "US", location, messageType = "Chat", variant = "Balanced" } = opts; let { conversationId, clientId, conversationSignature } = opts; const isStartOfSession = !(conversationId && clientId && conversationSignature); if (isStartOfSession) { const conversation = await this.createConversation(); conversationId = conversation.conversationId; clientId = conversation.clientId; conversationSignature = conversation.conversationSignature; } const result = { author: "bot", id: crypto.randomUUID(), conversationId, clientId, conversationSignature, invocationId: `${parseInt(invocationId, 10) + 1}`, text: "" }; const responseP = new Promise( async (resolve, reject) => { const host = process.env.BING_HOST ?? "sydney.bing.com"; const chatWebsocketUrl = `wss://${host}/sydney/ChatHub`; const ws = new WebSocket(chatWebsocketUrl, { perMessageDeflate: false, headers: { "accept-language": "en-US,en;q=0.9", "cache-control": "no-cache", "pragma": "no-cache", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" } }); let isFulfilled = false; function cleanup() { ws.close(); ws.removeAllListeners(); } ws.on("error", (error) => { console.warn("WebSocket error:", error); cleanup(); if (!isFulfilled) { isFulfilled = true; reject(new Error(`WebSocket error: ${error.toString()}`)); } }); ws.on("close", () => { }); ws.on("open", () => { ws.send(`{"protocol":"json","version":1}${terminalChar}`); }); let stage = 0; ws.on("message", (data) => { var _a, _b; const objects = data.toString().split(terminalChar); const messages = objects.map((object) => { try { return JSON.parse(object); } catch (error) { return object; } }).filter(Boolean); if (!messages.length) { return; } if (stage === 0) { ws.send(`{"type":6}${terminalChar}`); const traceId = crypto.randomBytes(16).toString("hex"); const locationStr = location ? `lat:${location.lat};long:${location.lng};re=${location.re || "1000m"};` : void 0; const optionsSets = [ "nlu_direct_response_filter", "deepleo", "enable_debug_commands", "disable_emoji_spoken_text", "responsible_ai_policy_235", "enablemm" ]; if (variant == "Balanced") { optionsSets.push("galileo"); } else { optionsSets.push("clgalileo"); if (variant == "Creative") { optionsSets.push("h3imaginative"); } else if (variant == "Precise") { optionsSets.push("h3precise"); } } const params = { arguments: [ { source: "cib", optionsSets, allowedMessageTypes: [ "Chat", "InternalSearchQuery", "InternalSearchResult", "InternalLoaderMessage", "RenderCardRequest", "AdsQuery", "SemanticSerp" ], sliceIds: [], traceId, isStartOfSession, message: { locale, market, region, location: locationStr, author: "user", inputMethod: "Keyboard", messageType, text }, conversationSignature, participant: { id: clientId }, conversationId } ], invocationId, target: "chat", type: 4 }; if (this._debug) { console.log(chatWebsocketUrl, JSON.stringify(params, null, 2)); } ws.send(`${JSON.stringify(params)}${terminalChar}`); ++stage; return; } for (const message of messages) { if (message.type === 1) { const update = message; const msg = (_a = update.arguments[0].messages) == null ? void 0 : _a[0]; if (!msg) continue; if (!msg.messageType) { result.author = msg.author; result.text = msg.text; result.detail = msg; onProgress == null ? void 0 : onProgress(result); } } else if (message.type === 2) { const response = message; if (this._debug) { console.log("RESPONSE", JSON.stringify(response, null, 2)); } const validMessages = (_b = response.item.messages) == null ? void 0 : _b.filter( (m) => !m.messageType ); const lastMessage = validMessages == null ? void 0 : validMessages[(validMessages == null ? void 0 : validMessages.length) - 1]; if (lastMessage) { result.conversationId = response.item.conversationId; result.conversationExpiryTime = response.item.conversationExpiryTime; result.author = lastMessage.author; result.text = lastMessage.text; result.detail = lastMessage; if (!isFulfilled) { isFulfilled = true; resolve(result); } } } else if (message.type === 3) { if (!isFulfilled) { isFulfilled = true; resolve(result); } cleanup(); return; } else { } } }); } ); return responseP; } async createConversation() { const requestId = crypto.randomUUID(); const cookie = this._cookie.includes(";") ? this._cookie : `_U=${this._cookie}`; const host = process.env.BING_HOST ?? "www.bing.com"; return fetch(`https://${host}/turing/conversation/create`, { headers: { accept: "application/json", "accept-language": "en-US,en;q=0.9", "content-type": "application/json", "sec-ch-ua": '"Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"', "sec-ch-ua-arch": '"x86"', "sec-ch-ua-bitness": '"64"', "sec-ch-ua-full-version": '"109.0.1518.78"', "sec-ch-ua-full-version-list": '"Not_A Brand";v="99.0.0.0", "Microsoft Edge";v="109.0.1518.78", "Chromium";v="109.0.5414.120"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-model": "", "sec-ch-ua-platform": '"macOS"', "sec-ch-ua-platform-version": '"12.6.0"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "x-edge-shopping-flag": "1", "x-ms-client-request-id": requestId, "x-ms-useragent": "azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.0 OS/MacIntel", cookie }, referrer: "https://www.bing.com/search", referrerPolicy: "origin-when-cross-origin", body: null, method: "GET", mode: "cors", credentials: "include" }).then((res) => { if (res.ok) { return res.json(); } else { throw new Error( `unexpected HTTP error createConversation ${res.status}: ${res.statusText}` ); } }); } }; export { BingChat }; //# sourceMappingURL=index.js.map