mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-18 14:27:10 +00:00
feat: new bing (WIP)
This commit is contained in:
parent
8fc2ca5621
commit
4aa634b01c
2 changed files with 177 additions and 21 deletions
156
client/CopilotAIClient.js
Normal file
156
client/CopilotAIClient.js
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
import WebSocket from 'ws';
|
||||
|
||||
export class BingAIClient {
|
||||
constructor(baseUrl = 'wss://copilot.microsoft.com/c/api/chat') {
|
||||
this.baseUrl = baseUrl;
|
||||
this.ws = null;
|
||||
this.conversationId = null;
|
||||
this.currentMessageId = null;
|
||||
this.partialMessages = new Map();
|
||||
}
|
||||
|
||||
async sendMessage(text, options = {}) {
|
||||
// If conversationId is provided, use it, otherwise create a new one
|
||||
if (options.conversationId) {
|
||||
this.conversationId = options.conversationId;
|
||||
} else {
|
||||
this.conversationId = this._generateConversationId();
|
||||
}
|
||||
|
||||
// Connect WebSocket
|
||||
await this.connectWebSocket();
|
||||
|
||||
// Send the initial message or challenge response
|
||||
await this.sendInitialMessage();
|
||||
|
||||
// Send the text message
|
||||
const messagePayload = {
|
||||
event: 'send',
|
||||
conversationId: this.conversationId,
|
||||
content: [{ type: 'text', text }],
|
||||
mode: 'chat',
|
||||
context: { edge: 'NonContextual' },
|
||||
};
|
||||
|
||||
this.ws.send(JSON.stringify(messagePayload));
|
||||
|
||||
// Wait for the response and collect the full message
|
||||
const responseText = await this.collectResponse();
|
||||
return responseText;
|
||||
}
|
||||
|
||||
async connectWebSocket() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ws = new WebSocket(this.baseUrl);
|
||||
|
||||
this.ws.on('open', () => {
|
||||
console.log('WebSocket connection established.');
|
||||
resolve();
|
||||
});
|
||||
|
||||
this.ws.on('message', (data) => this.handleServerMessage(data));
|
||||
|
||||
this.ws.on('close', () => {
|
||||
console.log('WebSocket connection closed.');
|
||||
});
|
||||
|
||||
this.ws.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async sendInitialMessage() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ws.once('message', (data) => {
|
||||
const message = JSON.parse(data);
|
||||
if (message.event === 'challenge') {
|
||||
// Handle challenge by sending the challenge response
|
||||
this.handleChallenge(message)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
} else {
|
||||
resolve(); // Proceed if no challenge event
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async handleChallenge(challenge) {
|
||||
// Get the token by calling getTurnstile function (you need to define this function)
|
||||
const token = await this.getTurnstile(challenge.conversationId);
|
||||
|
||||
const challengeResponse = {
|
||||
event: 'challengeResponse',
|
||||
token: token,
|
||||
method: 'cloudflare',
|
||||
};
|
||||
|
||||
this.ws.send(JSON.stringify(challengeResponse));
|
||||
}
|
||||
|
||||
async collectResponse() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let fullResponse = '';
|
||||
|
||||
const checkMessageComplete = (messageId) => {
|
||||
// Wait for the complete message
|
||||
if (this.partialMessages.has(messageId) && this.partialMessages.get(messageId).done) {
|
||||
const completeMessage = this.partialMessages.get(messageId).text;
|
||||
resolve(completeMessage);
|
||||
}
|
||||
};
|
||||
|
||||
this.ws.on('message', (data) => {
|
||||
const message = JSON.parse(data);
|
||||
|
||||
switch (message.event) {
|
||||
case 'received':
|
||||
break;
|
||||
|
||||
case 'startMessage':
|
||||
this.currentMessageId = message.messageId;
|
||||
break;
|
||||
|
||||
case 'appendText':
|
||||
if (!this.partialMessages.has(message.messageId)) {
|
||||
this.partialMessages.set(message.messageId, { text: '', done: false });
|
||||
}
|
||||
|
||||
this.partialMessages.get(message.messageId).text += message.text;
|
||||
|
||||
// Check if this part is the last one
|
||||
if (message.partId === '0') {
|
||||
this.partialMessages.get(message.messageId).done = true;
|
||||
}
|
||||
|
||||
checkMessageComplete(message.messageId);
|
||||
break;
|
||||
|
||||
case 'partCompleted':
|
||||
break;
|
||||
|
||||
case 'done':
|
||||
checkMessageComplete(message.messageId);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn('Unexpected event:', message.event);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async getTurnstile(conversationId) {
|
||||
// This is a mock implementation, you should replace this with the actual logic
|
||||
// to interact with the turnstile system to get the token.
|
||||
// In a real-world scenario, this would involve making a request to some endpoint.
|
||||
return '0.EHn0JUxxxx';
|
||||
}
|
||||
|
||||
_generateConversationId() {
|
||||
return 'conversation-' + Math.random().toString(36).substring(2, 15);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,27 +95,27 @@ export default class SydneyAIClient {
|
|||
fetchOptions.headers.cookie = this.opts.cookies
|
||||
}
|
||||
// let hash = md5(this.opts.cookies || this.opts.userToken)
|
||||
let hash = crypto.createHash('md5').update(this.opts.cookies || this.opts.userToken).digest('hex')
|
||||
let proTag = await redis.get('CHATGPT:COPILOT_PRO_TAG:' + hash)
|
||||
if (!proTag) {
|
||||
let indexContentRes = await fetch('https://www.bing.com/chat', {
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0',
|
||||
Cookie: `_U=${this.opts.userToken}`
|
||||
}
|
||||
})
|
||||
let indexContent = await indexContentRes.text()
|
||||
if (indexContent?.includes('b_proTag')) {
|
||||
proTag = 'true'
|
||||
} else {
|
||||
proTag = 'false'
|
||||
}
|
||||
await redis.set('CHATGPT:COPILOT_PRO_TAG:' + hash, proTag, { EX: 7200 })
|
||||
}
|
||||
if (proTag === 'true') {
|
||||
logger.info('当前账户为copilot pro用户')
|
||||
this.pro = true
|
||||
}
|
||||
// let hash = crypto.createHash('md5').update(this.opts.cookies || this.opts.userToken).digest('hex')
|
||||
// let proTag = await redis.get('CHATGPT:COPILOT_PRO_TAG:' + hash)
|
||||
// if (!proTag) {
|
||||
// let indexContentRes = await fetch('https://www.bing.com/chat', {
|
||||
// headers: {
|
||||
// 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0',
|
||||
// Cookie: `_U=${this.opts.userToken}`
|
||||
// }
|
||||
// })
|
||||
// let indexContent = await indexContentRes.text()
|
||||
// if (indexContent?.includes('b_proTag')) {
|
||||
// proTag = 'true'
|
||||
// } else {
|
||||
// proTag = 'false'
|
||||
// }
|
||||
// await redis.set('CHATGPT:COPILOT_PRO_TAG:' + hash, proTag, { EX: 7200 })
|
||||
// }
|
||||
// if (proTag === 'true') {
|
||||
// logger.info('当前账户为copilot pro用户')
|
||||
// this.pro = true
|
||||
// }
|
||||
} else {
|
||||
fetchOptions.headers.cookie = initCk
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue