| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| import { post, get, requestStream } from './http.js';
|
| import config from './config.js';
|
|
|
| const API = config.siteBase;
|
|
|
| const HEADERS = {
|
| 'Origin': config.siteBase,
|
| 'Referer': `${config.siteBase}/app/chat`,
|
| 'Accept-Language': 'en',
|
| };
|
|
|
| |
| |
| |
|
|
| export async function createContext(cookies, model, title = 'API Chat') {
|
| const resp = await post(`${API}/api/message/context`, {
|
| title: title.substring(0, 150),
|
| chatModel: model,
|
| isInternational: true,
|
| }, {
|
| cookies,
|
| headers: HEADERS,
|
| });
|
|
|
| if (!resp.ok) {
|
| const body = resp.text();
|
| throw Object.assign(new Error(`创建上下文失败 (${resp.status}): ${body.substring(0, 200)}`), {
|
| statusCode: resp.status,
|
| });
|
| }
|
|
|
| const data = resp.json();
|
| return { chatId: data.id, cookies: resp.cookies };
|
| }
|
|
|
| |
| |
| |
|
|
| export async function sendMessageStreaming(cookies, chatId, text, model) {
|
| const resp = await requestStream(`${API}/api/message/streaming`, {
|
| method: 'POST',
|
| body: {
|
| text,
|
| chatId,
|
| withPotentialQuestions: false,
|
| model,
|
| from: 1,
|
| },
|
| cookies,
|
| headers: {
|
| ...HEADERS,
|
| 'Accept': 'text/event-stream',
|
| },
|
| });
|
|
|
| if (!resp.ok) {
|
|
|
| let errBody = '';
|
| resp.stream.setEncoding('utf8');
|
| for await (const chunk of resp.stream) errBody += chunk;
|
| throw Object.assign(new Error(`流式请求失败 (${resp.status}): ${errBody.substring(0, 200)}`), {
|
| statusCode: resp.status,
|
| });
|
| }
|
|
|
| resp.stream.setEncoding('utf8');
|
| return { stream: resp.stream, cookies: resp.cookies };
|
| }
|
|
|
| |
| |
|
|
| export async function sendMessage(cookies, chatId, text, model) {
|
| const resp = await post(`${API}/api/message`, {
|
| text,
|
| chatId,
|
| withPotentialQuestions: true,
|
| model,
|
| from: 1,
|
| isInternational: true,
|
| }, {
|
| cookies,
|
| headers: HEADERS,
|
| });
|
|
|
| if (!resp.ok) {
|
| throw Object.assign(new Error(`消息发送失败 (${resp.status}): ${resp.text().substring(0, 200)}`), {
|
| statusCode: resp.status,
|
| });
|
| }
|
|
|
| return { data: resp.json(), cookies: resp.cookies };
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export async function sendMultiChunkStreaming(cookies, chatId, chunks, model) {
|
| let currentCookies = cookies;
|
|
|
|
|
| for (let i = 0; i < chunks.length - 1; i++) {
|
| console.log(`[Chat] 发送上下文消息 ${i + 1}/${chunks.length - 1} (${chunks[i].length} 字符)`);
|
|
|
|
|
| const resp = await requestStream(`${API}/api/message/streaming`, {
|
| method: 'POST',
|
| body: {
|
| text: chunks[i],
|
| chatId,
|
| withPotentialQuestions: false,
|
| model,
|
| from: 1,
|
| },
|
| cookies: currentCookies,
|
| headers: {
|
| ...HEADERS,
|
| 'Accept': 'text/event-stream',
|
| },
|
| });
|
|
|
| if (resp.cookies) currentCookies = resp.cookies;
|
|
|
| if (!resp.ok) {
|
| let errBody = '';
|
| resp.stream.setEncoding('utf8');
|
| for await (const chunk of resp.stream) errBody += chunk;
|
| throw Object.assign(
|
| new Error(`上下文消息 ${i + 1} 失败 (${resp.status}): ${errBody.substring(0, 200)}`),
|
| { statusCode: resp.status },
|
| );
|
| }
|
|
|
|
|
| resp.stream.setEncoding('utf8');
|
| for await (const _chunk of resp.stream) { }
|
| }
|
|
|
|
|
| const lastChunk = chunks[chunks.length - 1];
|
| console.log(`[Chat] 发送最终消息 (${lastChunk.length} 字符)`);
|
|
|
| const resp = await requestStream(`${API}/api/message/streaming`, {
|
| method: 'POST',
|
| body: {
|
| text: lastChunk,
|
| chatId,
|
| withPotentialQuestions: false,
|
| model,
|
| from: 1,
|
| },
|
| cookies: currentCookies,
|
| headers: {
|
| ...HEADERS,
|
| 'Accept': 'text/event-stream',
|
| },
|
| });
|
|
|
| if (resp.cookies) currentCookies = resp.cookies;
|
|
|
| if (!resp.ok) {
|
| let errBody = '';
|
| resp.stream.setEncoding('utf8');
|
| for await (const chunk of resp.stream) errBody += chunk;
|
| throw Object.assign(
|
| new Error(`流式请求失败 (${resp.status}): ${errBody.substring(0, 200)}`),
|
| { statusCode: resp.status },
|
| );
|
| }
|
|
|
| resp.stream.setEncoding('utf8');
|
| return { stream: resp.stream, cookies: currentCookies };
|
| }
|
|
|
| |
| |
| |
|
|
| export async function getQuota(cookies) {
|
| try {
|
| const resp = await get(`${API}/api/user/answers-count/v2`, {
|
| cookies,
|
| headers: HEADERS,
|
| });
|
| if (!resp.ok) return null;
|
| const data = resp.json();
|
|
|
|
|
| let remaining = null;
|
| if (typeof data === 'object' && data !== null) {
|
|
|
| for (const key of ['freeAnswersCount', 'answersCount', 'remaining', 'count', 'free']) {
|
| if (typeof data[key] === 'number') {
|
| remaining = data[key];
|
| break;
|
| }
|
| }
|
|
|
| if (remaining === null) {
|
| for (const val of Object.values(data)) {
|
| if (typeof val === 'number' && val >= 0) {
|
| remaining = val;
|
| break;
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
| if (remaining === null) {
|
| console.log(`[Quota] API 返回未知格式: ${JSON.stringify(data)}`);
|
| }
|
|
|
| return { remaining, raw: data };
|
| } catch {
|
| return null;
|
| }
|
| }
|
|
|
| |
| |
|
|
| export async function getUserInfo(cookies) {
|
| try {
|
| const resp = await get(`${API}/api/user`, {
|
| cookies,
|
| headers: HEADERS,
|
| });
|
| if (!resp.ok) return null;
|
| return resp.json();
|
| } catch {
|
| return null;
|
| }
|
| }
|
|
|