fix: support new auth for forefront
このコミットが含まれているのは:
コミット
1938c0cfa5
|
@ -4,10 +4,10 @@ import tlsClient from 'tls-client';
|
||||||
|
|
||||||
import {Chat, ChatOptions, Request, Response, ResponseStream} from "../base";
|
import {Chat, ChatOptions, Request, Response, ResponseStream} from "../base";
|
||||||
import {Email} from '../../utils/email';
|
import {Email} from '../../utils/email';
|
||||||
import axios, {AxiosInstance, CreateAxiosDefaults} from "axios";
|
import axios, {AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults} from "axios";
|
||||||
import {v4} from "uuid";
|
import {v4} from "uuid";
|
||||||
import es from "event-stream";
|
import es from "event-stream";
|
||||||
import {parseJSON} from "../../utils";
|
import {encryptWithAes256Cbc, parseJSON} from "../../utils";
|
||||||
|
|
||||||
interface ForefrontRequest extends Request {
|
interface ForefrontRequest extends Request {
|
||||||
options?: {
|
options?: {
|
||||||
|
@ -38,14 +38,18 @@ interface ChatCompletionChunk {
|
||||||
interface ForefrontSessionInfo {
|
interface ForefrontSessionInfo {
|
||||||
agent: string;
|
agent: string;
|
||||||
token: string;
|
token: string;
|
||||||
|
sessionID: string;
|
||||||
|
userID: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Forefront extends Chat {
|
export class Forefront extends Chat {
|
||||||
private client: AxiosInstance | undefined;
|
private client: AxiosInstance | undefined;
|
||||||
|
private session: ForefrontSessionInfo | undefined;
|
||||||
|
|
||||||
constructor(options?: ChatOptions) {
|
constructor(options?: ChatOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
this.client = undefined;
|
this.client = undefined;
|
||||||
|
this.session = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ask(req: ForefrontRequest): Promise<Response> {
|
public async ask(req: ForefrontRequest): Promise<Response> {
|
||||||
|
@ -54,6 +58,10 @@ export class Forefront extends Chat {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
res.text.pipe(es.split(/\r?\n\r?\n/)).pipe(es.map(async (chunk: any, cb: any) => {
|
res.text.pipe(es.split(/\r?\n\r?\n/)).pipe(es.map(async (chunk: any, cb: any) => {
|
||||||
const str = chunk.replace('data: ', '');
|
const str = chunk.replace('data: ', '');
|
||||||
|
if (!str || str === '[DONE]') {
|
||||||
|
cb(null, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const data = parseJSON(str, {}) as ChatCompletionChunk;
|
const data = parseJSON(str, {}) as ChatCompletionChunk;
|
||||||
if (!data.choices) {
|
if (!data.choices) {
|
||||||
cb(null, '');
|
cb(null, '');
|
||||||
|
@ -62,6 +70,9 @@ export class Forefront extends Chat {
|
||||||
const [{delta: {content}}] = data.choices;
|
const [{delta: {content}}] = data.choices;
|
||||||
cb(null, content);
|
cb(null, content);
|
||||||
})).on('data', (data) => {
|
})).on('data', (data) => {
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
text += data;
|
text += data;
|
||||||
}).on('close', () => {
|
}).on('close', () => {
|
||||||
resolve({text, other: res.other});
|
resolve({text, other: res.other});
|
||||||
|
@ -74,7 +85,7 @@ export class Forefront extends Chat {
|
||||||
if (!this.client) {
|
if (!this.client) {
|
||||||
await this.initClient();
|
await this.initClient();
|
||||||
}
|
}
|
||||||
if (!this.client) {
|
if (!this.client || !this.session) {
|
||||||
throw new Error('hava not created account');
|
throw new Error('hava not created account');
|
||||||
}
|
}
|
||||||
const {
|
const {
|
||||||
|
@ -91,12 +102,15 @@ export class Forefront extends Chat {
|
||||||
messagePersona: defaultPersona,
|
messagePersona: defaultPersona,
|
||||||
model: model,
|
model: model,
|
||||||
};
|
};
|
||||||
|
const base64Data = Buffer.from(this.session.userID + defaultPersona + chatId).toString('base64');
|
||||||
|
const encryptedSignature = encryptWithAes256Cbc(base64Data, this.session.sessionID);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.client?.post(
|
const response = await this.client?.post(
|
||||||
'https://chat-server.tenant-forefront-default.knative.chi.coreweave.com/chat',
|
'https://streaming.tenant-forefront-default.knative.chi.coreweave.com/chat', jsonData,
|
||||||
jsonData,
|
{
|
||||||
{responseType: 'stream'}
|
responseType: 'stream', headers: {'x-signature': encryptedSignature}
|
||||||
|
} as AxiosRequestConfig
|
||||||
);
|
);
|
||||||
return {text: response.data};
|
return {text: response.data};
|
||||||
} catch (e) {// session will expire very fast, I cannot know what reason
|
} catch (e) {// session will expire very fast, I cannot know what reason
|
||||||
|
@ -106,6 +120,7 @@ export class Forefront extends Chat {
|
||||||
|
|
||||||
async initClient() {
|
async initClient() {
|
||||||
let hisSession = await this.createToken();
|
let hisSession = await this.createToken();
|
||||||
|
this.session = hisSession;
|
||||||
this.client = axios.create({
|
this.client = axios.create({
|
||||||
headers: {
|
headers: {
|
||||||
'authority': 'chat-server.tenant-forefront-default.knative.chi.coreweave.com',
|
'authority': 'chat-server.tenant-forefront-default.knative.chi.coreweave.com',
|
||||||
|
@ -170,6 +185,8 @@ export class Forefront extends Chat {
|
||||||
const validateRes = await session.get(validateURL)
|
const validateRes = await session.get(validateURL)
|
||||||
const loginRes = await session.get('https://clerk.forefront.ai/v1/client?_clerk_js_version=4.38.4');
|
const loginRes = await session.get('https://clerk.forefront.ai/v1/client?_clerk_js_version=4.38.4');
|
||||||
const token = (loginRes.data as any).response.sessions[0].last_active_token.jwt;
|
const token = (loginRes.data as any).response.sessions[0].last_active_token.jwt;
|
||||||
return {token, agent};
|
const sessionID = (loginRes.data as any).response.sessions[0].id
|
||||||
|
const userID = (loginRes.data as any).response.sessions[0].user.id
|
||||||
|
return {token, agent, sessionID, userID};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,18 @@ export function parseJSON(str: string, defaultObj: any): any | undefined {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(str)
|
return JSON.parse(str)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(str,e);
|
console.error(str, e);
|
||||||
return defaultObj;
|
return defaultObj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function encryptWithAes256Cbc(data: string, key: string):string {
|
||||||
|
const hash = crypto.createHash('sha256').update(key).digest();
|
||||||
|
const iv = crypto.randomBytes(16);
|
||||||
|
const cipher = crypto.createCipheriv('aes-256-cbc', hash, iv);
|
||||||
|
|
||||||
|
let encryptedData = cipher.update(data, 'utf-8', 'hex');
|
||||||
|
encryptedData += cipher.final('hex');
|
||||||
|
|
||||||
|
return iv.toString('hex') + encryptedData;
|
||||||
|
}
|
||||||
|
|
読み込み中…
新しいイシューから参照