feat: update Bailian model and improve TypeScript configuration

- Changed Bailian model from 'qwen3-235b-a22b' to 'qwen-plus' in ai.ts
- Updated model references in bailianModel to use simplified names
- Modified tsconfig.json to set module to NodeNext, target to esnext, and adjusted paths for better module resolution
- Added new query-keys.ts file in xhs package to implement getNoteByKeyword functionality with command line interface
This commit is contained in:
2025-12-25 04:53:24 +08:00
parent 52d37d0679
commit 0d42e912f5
20 changed files with 772 additions and 593 deletions

View File

@@ -28,6 +28,12 @@ export const api: ApiInfo[] = [
needSign: true,
description: '获取@我的消息',
},
{
uri: '/api/sns/web/v1/search/notes',
method: 'POST',
needSign: true,
description: '通过关键词搜索笔记',
}
];
type ReturnApiInfo = {

View File

@@ -1,7 +1,7 @@
import { getApiInfo } from './xhs-api/api.ts';
import { XhsClient as XhsClientBase } from '@kevisual/xhs-core';
import { Mention, CommonentInfo, ResponseMession } from './xhs-type/mention.ts';
import { pick } from 'lodash-es';
import { method, pick } from 'lodash-es';
import { getNote } from './modules/get-note.ts';
export type Result<T> = {
code: number; // 0: success
@@ -14,6 +14,7 @@ type SignInfo = {
data: any;
a1: string;
web_session?: string;
method?: 'GET' | 'POST';
};
type SignResponse = {
a1: string;
@@ -27,10 +28,10 @@ type SignResponse = {
};
type SignOptions = {
signUrl?: string;
method?: 'GET' | 'POST';
};
export const getSign = async (signInfo: SignInfo, options?: SignOptions): Promise<SignResponse> => {
const { uri, data, a1, web_session } = signInfo;
// console.log('getSign', uri, data, a1, web_session);
const { uri, data, a1, method } = signInfo;
// let signUri = new URL(uri, 'http://light.xiongxiao.me:5006').pathname;
// signUri = '/api/sns/web/v2/user/me';
try {
@@ -48,7 +49,7 @@ export const getSign = async (signInfo: SignInfo, options?: SignOptions): Promis
uri: uri,
data,
a1,
web_session: web_session,
method: signInfo.method || 'POST',
}),
}).then((res) => res.json());
return signs as SignResponse;
@@ -92,6 +93,11 @@ export class XhsClient extends XhsClientBase {
case 'sign':
// console.log('sign', data);
break;
case 'post':
console.log('post', data);
break;
default:
break;
}
}
/**
@@ -158,7 +164,7 @@ export class XhsClient extends XhsClientBase {
const response = await this.get(url, { num, cursor }, { sign: this.sign.bind(this) });
return response as Result<ReturnData>;
}
async getComment(noteId: string, xsecToken?: string) {}
async getComment(noteId: string, xsecToken?: string) { }
/**
*
* @uri /api/sns/web/v1/you/mentions
@@ -183,23 +189,26 @@ export class XhsClient extends XhsClientBase {
if (apiInfo && !apiInfo?.needSign) {
return config || {};
}
const web_session = cookieDist['web_session'];
const a1 = cookieDist['a1'];
const res = await getSign({ uri, data, a1, web_session }, this.signConfig);
const _sign = res.sign;
const res = await getSign({ uri, data, a1, method: 'POST' }, this.signConfig);
console.log('sign response', res);
const _sign = res.sign
this.printResult('sign', { uri, apiInfo, res });
const xs = _sign?.['x-s'];
const xt = _sign?.['x-t'];
const b1 = _sign?.['b1'];
const newA1 = _sign?.['a1'];
const xsCommon = _sign?.['x-s-common'];
const xB3Traceid = _sign?.['x-b3-traceid'];
if (a1 !== newA1) {
this.setCookieMap({ a1: newA1 });
this.printResult('cookie change', a1);
}
// throw new Error('disable sign');
if (res && xs) {
headers['x-s'] = xs;
headers['x-t'] = xt;
// headers['x-s-common'] = this.getXCommon(a1, b1, xs, xt);
headers['x-s-common'] = xsCommon;
headers['x-b3-traceid'] = xB3Traceid;
config.headers = headers;
} else {
console.log('get sign error', res);
@@ -257,6 +266,21 @@ export class XhsClient extends XhsClientBase {
}
}
getNote = getNote;
async getNoteByKeyword(keyword: string, page?: number, pageSize?: number, sort?: string, noteType?: number): Promise<any> {
const uri = '/api/sns/web/v1/search/notes';
const data = {
keyword,
page: page || 1,
page_size: pageSize || 20,
sort: sort || SearchSortType.GENERAL,
note_type: noteType || SearchNoteType.ALL,
search_id: getSearchId(),
image_formats: ['jpg', 'webp', 'avif'],
ext_flags: []
};
const response = await this.post(uri, data, { sign: this.sign.bind(this) });
return response;
}
}
type UnreadCount = {
@@ -265,3 +289,29 @@ type UnreadCount = {
connections: number;
mentions: number;
};
function getSearchId() {
const e = BigInt(Date.now()) << 64n;
const t = Math.floor(Math.random() * 2147483647);
return base36encode(e + BigInt(t));
}
function base36encode(num: bigint): string {
return num.toString(36).toUpperCase();
}
const SearchSortType = Object.freeze({
// default
GENERAL: { value: "general" },
// most popular
MOST_POPULAR: { value: "popularity_descending" },
// Latest
LATEST: { value: "time_descending" }
});
const SearchNoteType = Object.freeze({
// default
ALL: { value: 0 },
// only video
VIDEO: { value: 1 },
// only image
IMAGE: { value: 2 }
});

View File

@@ -49,16 +49,16 @@ app
path: 'mention',
key: 'getNote',
description: '获取笔记',
validator: {
node_id: {
type: 'string',
required: true,
},
xsec_token: {
type: 'string',
required: true,
},
},
// validator: {
// node_id: {
// type: 'string',
// required: true,
// },
// xsec_token: {
// type: 'string',
// required: true,
// },
// },
isDebug: true,
})
.define(async (ctx) => {
@@ -108,13 +108,13 @@ app
.route({
path: 'mention',
key: 'getMention',
description: '获取提及列表',
validator: {
num: {
type: 'number',
required: true,
},
},
// description: '获取提及列表',
// validator: {
// num: {
// type: 'number',
// required: true,
// },
// },
})
.define(async (ctx) => {
const num = ctx.query.num;

View File

@@ -8,6 +8,9 @@ import './query/mention.ts'
import './query/unread.ts';
import './query/get-userinfo.ts';
import './query/get-connections.ts'
import './query/query-keys.ts';
program
.command('test')
.description('test command')

View File

@@ -1,6 +1,6 @@
import { xhsServices, app, xhsRootClient } from '../index.ts';
import { useConfig } from '@kevisual/use-config/env';
const config = useConfig();
export const config = useConfig();
import { program } from 'commander';
xhsRootClient.setCookie(config.XHS_ROOT_COOKIE || '');

View File

@@ -0,0 +1,29 @@
// getNoteByKeyword
import { xhsServices, program, config } from '../common.ts';
import util from 'node:util';
const getNoteByKeyword = async (keyword: string) => {
const client = xhsServices.getClient();
xhsServices.setSignConfig({
signUrl: config.XHS_API_SIGN_URL,
});
const res = await client.getNoteByKeyword(keyword).then((res) => {
console.log(util.inspect(res, { depth: null }));
return res;
});
console.log('type res', typeof res);
if (res.code === 0) {
console.log('total', res.data.total);
if (res.data.notes.length > 0) {
console.log('first note desc', res.data.notes[0].desc);
}
}
};
program
.command('get-note-by-keyword <keyword>')
.description('get note by keyword')
.action(async (keyword: string) => {
getNoteByKeyword(keyword);
});