Spaces:
Running
Running
// 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 chatWebsocketUrl = "wss://sydney.bing.com/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", | |
}, | |
}); | |
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", | |
"trffovrd", | |
"h3toppfp3", | |
"forcerep", | |
"cpcttl1d", | |
"dv3sugg", | |
]; | |
if (variant == "Balanced") { | |
optionsSets.push("galileo"); | |
optionsSets.push("glprompt"); | |
} else if (variant == "Creative") { | |
optionsSets.push("h3imaginative"); | |
optionsSets.push("gencontentv3"); | |
} 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}`; | |
return fetch("https://www.bing.com/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", | |
"x-forwarded-for": "1.1.1.1", | |
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 | |