From 8891b196ba1eb8c886117dd12f671d60d48d0bbb Mon Sep 17 00:00:00 2001 From: abearxiong Date: Mon, 5 May 2025 22:41:18 +0800 Subject: [PATCH] temp --- package.json | 4 +- packages/social-prompts/kevisual.json | 14 +++++ packages/social-prompts/package.json | 14 +++++ packages/social-prompts/tsconfig.json | 15 +++++ packages/social-prompts/xhs/answer.ts | 34 ++++++++++++ packages/xhs-core/src/index.js | 10 +++- packages/xhs/src/libs/modules/get-note.ts | 68 +++++++++++++++++++++++ packages/xhs/src/libs/xhs.ts | 7 ++- packages/xhs/src/test/query/get-note.ts | 10 ++-- pnpm-lock.yaml | 26 ++++----- src/task/routes/mention.ts | 61 ++++++++++++++------ src/test/ai.ts | 27 +++++++++ 12 files changed, 249 insertions(+), 41 deletions(-) create mode 100644 packages/social-prompts/kevisual.json create mode 100644 packages/social-prompts/package.json create mode 100644 packages/social-prompts/tsconfig.json create mode 100644 packages/social-prompts/xhs/answer.ts create mode 100644 packages/xhs/src/libs/modules/get-note.ts create mode 100644 src/test/ai.ts diff --git a/package.json b/package.json index 0c07d30..df7cd88 100644 --- a/package.json +++ b/package.json @@ -46,9 +46,10 @@ "devDependencies": { "@kevisual/ai-center": "^0.0.3", "@kevisual/app-assistant": "workspace:*", - "@kevisual/xhs": "workspace:*", + "@kevisual/social-prompts": "workspace:*", "@kevisual/types": "^0.0.9", "@kevisual/use-config": "^1.0.12", + "@kevisual/xhs": "workspace:*", "@types/bun": "^1.2.11", "@types/crypto-js": "^4.2.2", "@types/formidable": "^3.4.5", @@ -58,6 +59,7 @@ "commander": "^13.1.0", "concurrently": "^9.1.2", "cross-env": "^7.0.3", + "dotenv": "^16.5.0", "inquire": "^0.4.8", "ioredis": "^5.6.1", "nodemon": "^3.1.10", diff --git a/packages/social-prompts/kevisual.json b/packages/social-prompts/kevisual.json new file mode 100644 index 0000000..3089a61 --- /dev/null +++ b/packages/social-prompts/kevisual.json @@ -0,0 +1,14 @@ +{ + "$vars": { + "root": "https://kevisual.cn/root/ai" + }, + "registry": { + "root": "https://kevisual.cn/root/ai" + }, + "match": { + "./xhs/answer.ts": { + "url": "${root}/xhs/answer.ts" + }, + "./kevisual.json": {} + } +} \ No newline at end of file diff --git a/packages/social-prompts/package.json b/packages/social-prompts/package.json new file mode 100644 index 0000000..958dde5 --- /dev/null +++ b/packages/social-prompts/package.json @@ -0,0 +1,14 @@ +{ + "name": "@kevisual/social-prompts", + "version": "0.0.1", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "abearxiong (https://www.xiongxiao.me)", + "license": "MIT", + "packageManager": "pnpm@10.10.0", + "type": "module" +} diff --git a/packages/social-prompts/tsconfig.json b/packages/social-prompts/tsconfig.json new file mode 100644 index 0000000..0acd4de --- /dev/null +++ b/packages/social-prompts/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@kevisual/types/json/backend.json", + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@/*": [ + "src/*" + ] + } + }, + "include": [ + "xhs/**/*.ts", + ], + "exclude": [], +} \ No newline at end of file diff --git a/packages/social-prompts/xhs/answer.ts b/packages/social-prompts/xhs/answer.ts new file mode 100644 index 0000000..b7f3348 --- /dev/null +++ b/packages/social-prompts/xhs/answer.ts @@ -0,0 +1,34 @@ +export const answer = [ + { + role: 'system', + content: `你是一个小红书的内容回答问题的助手,用户提供一条笔记的信息,属于内容的上下文,和用户提供的问题,你需要给出一个简短的回答,回答要简洁明了,符合小红书的风格。 + 要求: + 1. 不能包函链接,如果包函链接,把对应的链接的字符 "." 替换为魔法字符 "点",比如 https://www.baidu.com 替换为 https://www点baidu点com + 2. 言语中不能包函文档类型,比如md格式,只需要对应的文本的内容 + 3. 只返回给我最后的结果,不需要思考过程 + + 例子: + 笔记内容是:我有一个问题,我有一个网页的html的内容,不知道怎么打开 + 用户:介绍一下怎么用vscode打开html网页 + + 回答: + 首先打开vscode,然后把html文件拖到vscode中,就可以打开了,或者直接在vscode中打开html文件,点击右上角的预览按钮,就可以预览网页了。 + + 现在可以开始了。 + `, + }, +]; + +export const createQuestion = (question: string, note: string, answers: any[] = []) => { + return [ + ...answers, + { + role: 'assistant', + content: `上下文的内参考的内容是: ${note}`, + }, + { + role: 'user', + content: `用户: ${question}`, + }, + ]; +}; diff --git a/packages/xhs-core/src/index.js b/packages/xhs-core/src/index.js index f509134..dcd6944 100644 --- a/packages/xhs-core/src/index.js +++ b/packages/xhs-core/src/index.js @@ -344,7 +344,7 @@ class XhsClient { const state = stateMatch[1].replace(/undefined/g, '""'); if (state !== '{}') { const noteDict = transformJsonKeys(JSON.parse(state)); - return noteDict.note.note_detail_map[noteId].note; + return { code: 0, data: noteDict.note.note_detail_map[noteId].note }; } } @@ -355,8 +355,12 @@ class XhsClient { throw new DataFetchError(html); } catch (error) { console.error('Error fetching note:', error); - fs.writeFileSync('a.html', html); - throw error; + return { + code: 500, + msg: '请求失败', + error: error.message, + data: null, + }; } } /** diff --git a/packages/xhs/src/libs/modules/get-note.ts b/packages/xhs/src/libs/modules/get-note.ts new file mode 100644 index 0000000..273e2f6 --- /dev/null +++ b/packages/xhs/src/libs/modules/get-note.ts @@ -0,0 +1,68 @@ +import { XhsClient, Result } from '../xhs.ts'; +interface ImageInfo { + image_scene: string; + url: string; +} + +interface ImageItem { + file_id: string; + height: number; + width: number; + url: string; + trace_id: string; + url_pre: string; + stream: Record; // 空对象类型 + info_list: ImageInfo[]; + url_default: string; + live_photo: boolean; +} + +interface AtUser { + xsec_token: string; + user_id: string; + nickname: string; +} + +interface User { + user_id: string; + nickname: string; + avatar: string; + xsec_token: string; +} + +interface InteractInfo { + collected_count: string; + comment_count: string; + share_count: string; + followed: boolean; + relation: string; + liked: boolean; + liked_count: string; + collected: boolean; +} + +interface ShareInfo { + un_share: boolean; +} + +interface NoteData { + xsec_token: string; + desc: string; + user: User; + interact_info: InteractInfo; + tag_list: never[]; // 空数组类型 + at_user_list: AtUser[]; + ip_location: string; + share_info: ShareInfo; + note_id: string; + type: string; + title: string; + image_list: ImageItem[]; + time: number; + last_update_time: number; +} +export const getNote = async function (id: string, x: string) { + const that = this as XhsClient; + const res = await that.getNoteByIdFromHtml(id, x); + return res as Result; +}; diff --git a/packages/xhs/src/libs/xhs.ts b/packages/xhs/src/libs/xhs.ts index b894454..595595a 100644 --- a/packages/xhs/src/libs/xhs.ts +++ b/packages/xhs/src/libs/xhs.ts @@ -2,6 +2,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 { getNote } from './modules/get-note.ts'; export type Result = { code: number; // 0: success msg?: string; @@ -211,7 +212,8 @@ export class XhsClient extends XhsClientBase { try { const response = await this.post(uri, data, { sign: this.sign.bind(this) }); - return response['items'][0]['node_card']; + // return response['items'][0]['node_card']; + return response; } catch (error) { console.log(error); } @@ -221,7 +223,7 @@ export class XhsClient extends XhsClientBase { * @param comment * @returns */ - async postComment(comment: { note_id: string; comment_id?: string; content: string; images_info?: any, images?: string[] }) { + async postComment(comment: { note_id: string; comment_id?: string; content: string; images_info?: any; images?: string[] }) { const uri = '/api/sns/web/v1/comment/post'; try { const data = { @@ -249,6 +251,7 @@ export class XhsClient extends XhsClientBase { console.log(error); } } + getNote = getNote; } type UnreadCount = { diff --git a/packages/xhs/src/test/query/get-note.ts b/packages/xhs/src/test/query/get-note.ts index 56f2834..bf47446 100644 --- a/packages/xhs/src/test/query/get-note.ts +++ b/packages/xhs/src/test/query/get-note.ts @@ -1,5 +1,5 @@ import { xhsServices, program } from '../common.ts'; - +import util from 'node:util'; // client.getNoteComments() @@ -8,7 +8,7 @@ import { xhsServices, program } from '../common.ts'; // }); const getNoteById = async () => { const client = xhsServices.getClient(); - client.getNoteById('67dcc34e000000000602a8eb', 'ABuYS8Xb1o08DlRmMLIabdqnW0OKnLR9nMpDGq5bVRdvk').then((res) => { + client.getNoteById('68136dab0000000007034c46', 'LByEmonX8WfJ9ebpAowVbOZX9Xh8T0Qkjil5KRFqDD6LM').then((res) => { console.log(res); }); }; @@ -16,8 +16,8 @@ const getNote = async () => { const id = '68136dab0000000007034c46'; const x = 'LByEmonX8WfJ9ebpAowVbOZX9Xh8T0Qkjil5KRFqDD6LM='; const client = xhsServices.getClient(); - client.getNoteByIdFromHtml(id, x).then((res) => { - console.log(res); + client.getNote(id, x).then((res) => { + console.log(util.inspect(res, { depth: null })); }); }; program @@ -32,4 +32,4 @@ program .description('get note by id') .action(async () => { getNoteById(); - }); \ No newline at end of file + }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2705b91..44c22b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,13 +10,13 @@ importers: dependencies: '@kevisual/code-center-module': specifier: 0.0.18 - version: 0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.13)(@kevisual/use-config@1.0.12(dotenv@16.5.0))(ioredis@5.6.1)(pg@8.15.6)(sequelize@6.37.7(pg@8.15.6)) + version: 0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.13)(@kevisual/use-config@1.0.14(dotenv@16.5.0))(ioredis@5.6.1)(pg@8.15.6)(sequelize@6.37.7(pg@8.15.6)) '@kevisual/router': specifier: 0.0.13 version: 0.0.13 '@kevisual/use-config': specifier: ^1.0.12 - version: 1.0.12(dotenv@16.5.0) + version: 1.0.14(dotenv@16.5.0) cookie: specifier: ^1.0.2 version: 1.0.2 @@ -39,6 +39,9 @@ importers: '@kevisual/app-assistant': specifier: workspace:* version: link:packages/app-assistant + '@kevisual/social-prompts': + specifier: workspace:* + version: link:packages/social-prompts '@kevisual/types': specifier: ^0.0.9 version: 0.0.9 @@ -72,6 +75,9 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 + dotenv: + specifier: ^16.5.0 + version: 16.5.0 inquire: specifier: ^0.4.8 version: 0.4.8 @@ -110,6 +116,8 @@ importers: specifier: ^5.51.1 version: 5.51.1 + packages/social-prompts: {} + packages/xhs: dependencies: '@kevisual/db': @@ -236,11 +244,6 @@ packages: '@kevisual/types@0.0.9': resolution: {integrity: sha512-SDJ7GMbOx7Ghz2kreHqym56ccAJS3t93y+NS0+afTLxcq2+cKcoEy2F8WXEv0mnJ6EsDp5AbA7Jv5TZA1Jbc3A==} - '@kevisual/use-config@1.0.12': - resolution: {integrity: sha512-PNoZqj6vdhv6DvjRMNwoGH9HJupm7QvjkvtCEYW2ryK7J8sI73r2ThCl4OEbXdRYVgl1EeK/e2IJh0Rf51bVwA==} - peerDependencies: - dotenv: ^16.4.7 - '@kevisual/use-config@1.0.14': resolution: {integrity: sha512-U4fmPFJre+Ph+hdg+EKVaRGxdpD4T4ZoOz5QLEyC6o3ekg8NC4n1i7Myo1ektqATyoG9Y0q/bJdOhiJwnLEt4g==} peerDependencies: @@ -2100,11 +2103,11 @@ snapshots: '@kevisual/auth@1.0.5': {} - '@kevisual/code-center-module@0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.13)(@kevisual/use-config@1.0.12(dotenv@16.5.0))(ioredis@5.6.1)(pg@8.15.6)(sequelize@6.37.7(pg@8.15.6))': + '@kevisual/code-center-module@0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.13)(@kevisual/use-config@1.0.14(dotenv@16.5.0))(ioredis@5.6.1)(pg@8.15.6)(sequelize@6.37.7(pg@8.15.6))': dependencies: '@kevisual/auth': 1.0.5 '@kevisual/router': 0.0.13 - '@kevisual/use-config': 1.0.12(dotenv@16.5.0) + '@kevisual/use-config': 1.0.14(dotenv@16.5.0) ioredis: 5.6.1 nanoid: 5.1.5 pg: 8.15.6 @@ -2136,11 +2139,6 @@ snapshots: '@kevisual/types@0.0.9': {} - '@kevisual/use-config@1.0.12(dotenv@16.5.0)': - dependencies: - '@kevisual/load': 0.0.6 - dotenv: 16.5.0 - '@kevisual/use-config@1.0.14(dotenv@16.5.0)': dependencies: '@kevisual/load': 0.0.6 diff --git a/src/task/routes/mention.ts b/src/task/routes/mention.ts index 4f48d83..86369cf 100644 --- a/src/task/routes/mention.ts +++ b/src/task/routes/mention.ts @@ -19,7 +19,6 @@ taskApp if (res.code === 200) { const data = res.body; const unread_count = data.unread_count; - console.log('unread_count====', data); if (unread_count > 0) { queue.add( 'mention', @@ -69,21 +68,26 @@ taskApp console.log('queryMention', util.inspect(data, { depth: 10 })); for (let i = 0; i < data.length; i++) { const item = data[i]; - const note_id = item.note_id; - const xsec_token = item.xsec_token; - const comment_id = item.comment.comment_id; - const content = item.comment?.content || 'test'; - const postData = { - note_id, - content, - comment_id, - }; - const res = await xhsApp.call({ - path: 'mention', - key: 'addComment', - payload: postData, - }); - console.log('addComment', postData, 'res', res.body); + queue.add( + 'mention-ai', + { + path: 'task', + key: 'ai', + payload: { + data: item, + }, + }, + { + attempts: 3, + delay: 0, + removeOnComplete: true, + removeOnFail: { + age: 24 * 3600, // keep up to 24 hours + }, + }, + ); + console.log('add mention task', item); + await sleep(200); } } const postRead = await xhsApp.call({ @@ -98,3 +102,28 @@ taskApp }; }) .addTo(taskApp); + +taskApp + .route({ + path: 'task', + key: 'ai', + }) + .define(async (ctx) => { + const data = ctx.query.data; + const note_id = data.note_id; + const xsec_token = data.xsec_token; + const comment_id = data.comment.comment_id; + const content = data.comment?.content || 'test'; + const postData = { + note_id, + content, + comment_id, + }; + const res = await xhsApp.call({ + path: 'mention', + key: 'addComment', + payload: postData, + }); + console.log('addComment', postData, 'res', res.body); + }) + .addTo(taskApp); diff --git a/src/test/ai.ts b/src/test/ai.ts new file mode 100644 index 0000000..2b1f62c --- /dev/null +++ b/src/test/ai.ts @@ -0,0 +1,27 @@ +import { ProviderManager, SiliconFlowProvider } from '@kevisual/ai-center'; +import dotenv from 'dotenv'; +import util from 'node:util'; +dotenv.config(); +import { createQuestion, answer } from '@kevisual/social-prompts/xhs/answer.ts'; +const pm = new SiliconFlowProvider({ + model: 'Qwen/Qwen3-32B', + apiKey: process.env.SILICONFLOW_API_KEY, +}); + +const main = async () => { + const usage = await pm.getUsageInfo(); + console.log('usage', usage); +}; + +// main(); +const ques = async () => { + // const msg = createQuestion('介绍一下如何安装node,在mac当中', '前端的node如何安装环境', answer); + const msg = createQuestion('介绍一下如何安装node,在mac当中', '前端的node如何安装环境', answer); + console.log('msg', msg); + const res = await pm.chat(msg); + console.log(util.inspect(res.choices, { depth: null })); + const ans = res.choices[0].message.content; + console.log('ans', ans, ans.length); +}; + +ques();