Skip to content

Commit 7a4bc73

Browse files
authored
wechaty with langchain (#165)
* wechaty with langchain * wechaty with langchain * 0.11.48 * 0.11.49
1 parent d0f111e commit 7a4bc73

File tree

6 files changed

+179
-1
lines changed

6 files changed

+179
-1
lines changed

jekyll/_contributors/bestk.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
name: bestk
3+
site: https://github.com/bestk
4+
avatar: /assets/contributors/bestk/avatar.webp
5+
bio: java/node/python/golang
6+
twitter:
7+
---
8+
9+
普适程序员
10+
11+
## Contact me
12+
13+
- Github: <https://github.com/bestk>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
---
2+
title: "使用 wechaty langchain 部署私有 chatgpt"
3+
author: bestk
4+
categories: article
5+
tags:
6+
- chatgpt
7+
- langchain
8+
image: /assets/2023/07-wechaty-chat-with-langchain/logo.webp
9+
---
10+
11+
12+
WeChaty 是一个基于 Node.js 的开源微信机器人框架,而 LangChain 是一个用于部署私有化 GPT 模型的工具。通过结合 WeChaty 和 LangChain,你可以创建一个私有化的 GPT 机器人,使其在微信平台上运行。
13+
14+
Setup:
15+
16+
我们使用 `wechaty-puppet-wechat4u`
17+
18+
```Text
19+
package.json:
20+
"wechaty": "^1.20.2",
21+
"wechaty-puppet-wechat4u": "1.14.1"
22+
"langchain": "^0.0.102",
23+
"@pinecone-database/pinecone": "^0.1.6",
24+
"pdf-parse": "^1.1.1", // 篇幅原因这里只演示 pdf
25+
```
26+
27+
```javascript
28+
import { WechatyBuilder} from 'wechaty'
29+
30+
const wechaty = WechatyBuilder.build({
31+
name: 'wechaty-chatgpt',
32+
puppet: 'wechaty-puppet-wechat4u',
33+
puppetOptions: {
34+
uos: true,
35+
},
36+
});
37+
38+
```
39+
40+
设置 pinecone ,openai
41+
42+
```bash
43+
PROMPTLAYER_API_KEY=pl_... # PROMPTLAYER 是一个用于记录 api 调用时 prompt 与 response 的工具
44+
PINECONE_API_KEY=89e...
45+
PINECONE_ENVIRONMENT=us-west4-gcp-free
46+
PINECONE_INDEX=...
47+
```
48+
49+
以下代码为当接收到支持的文件对文件进行向量化成功后返回提示
50+
51+
```javascript
52+
wechaty.on('message', async message => {
53+
const contact = message.talker();
54+
currentAdminUser = contact.payload.alias === process.env.ADMIN
55+
const receiver = message.listener();
56+
let content = message.text().trim();
57+
const room = message.room();
58+
const target = room || contact;
59+
const isText = message.type() === wechaty.Message.Type.Text;
60+
const isAudio = message.type() === wechaty.Message.Type.Audio;
61+
const isFile = message.type() === wechaty.Message.Type.Attachment;
62+
63+
if (isFile) {
64+
const filebox = await message.toFileBox()
65+
if (supportFileType(filebox.mediaType)) {
66+
await saveFile(filebox)
67+
await loadDocuments()
68+
await send(room || contact, `${filebox.name} Embeddings 成功`)
69+
return
70+
}
71+
}
72+
})
73+
```
74+
75+
![image1.webp](/assets/2023/07-wechaty-chat-with-langchain/image1.webp)
76+
77+
langchain 相关代码
78+
79+
```javascript
80+
import { PineconeClient } from "@pinecone-database/pinecone";
81+
import dotenv from 'dotenv';
82+
import { VectorDBQAChain } from "langchain/chains";
83+
import { DirectoryLoader } from "langchain/document_loaders";
84+
import { DocxLoader } from "langchain/document_loaders/fs/docx";
85+
import { PDFLoader } from "langchain/document_loaders/fs/pdf";
86+
import { TextLoader } from "langchain/document_loaders/fs/text";
87+
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
88+
import { PromptLayerOpenAI } from "langchain/llms/openai";
89+
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
90+
import { PineconeStore } from "langchain/vectorstores";
91+
92+
dotenv.config();
93+
const client = new PineconeClient();
94+
95+
await client.init({
96+
apiKey: process.env.PINECONE_API_KEY,
97+
environment: process.env.PINECONE_ENVIRONMENT,
98+
});
99+
100+
const pineconeIndex = client.Index(process.env.PINECONE_INDEX);
101+
102+
103+
async function loadDocuments(directory = 'resource') {
104+
console.log('loadDocuments...')
105+
const loader = new DirectoryLoader(directory,
106+
{
107+
".pdf": (path) => new PDFLoader(path),
108+
".txt": (path) => new TextLoader(path),
109+
".doc": (path) => new DocxLoader(path),
110+
".docx": (path) => new DocxLoader(path),
111+
});
112+
// 将数据转成 document 对象,每个文件会作为一个 document
113+
const rawDocuments = await loader.load();
114+
console.log(`documents: ${rawDocuments.length}`);
115+
116+
// 初始化加载器
117+
const textSplitter = new RecursiveCharacterTextSplitter({ chunkSize: 500 });
118+
// 切割加载的 document
119+
const splitDocs = await textSplitter.splitDocuments(rawDocuments);
120+
121+
// 持久化数据
122+
// const docsearch = await Chroma.fromDocuments(splitDocs, embeddings, { collectionName: "private_doc" });
123+
// docsearch.persist();
124+
125+
126+
await PineconeStore.fromDocuments(splitDocs, new OpenAIEmbeddings(), {
127+
pineconeIndex,
128+
});
129+
console.log(`send to PineconeStore`);
130+
131+
}
132+
133+
134+
async function askDocument(question) {
135+
const llm = new PromptLayerOpenAI({ plTags: ["langchain-requests", "chatbot"] })
136+
// 初始化 openai 的 embeddings 对象
137+
138+
// 加载数据
139+
const vectorStore = await PineconeStore.fromExistingIndex(
140+
new OpenAIEmbeddings(),
141+
{ pineconeIndex }
142+
);
143+
144+
/* Search the vector DB independently with meta filters */
145+
const chain = VectorDBQAChain.fromLLM(llm, vectorStore, {
146+
k: 1,
147+
returnSourceDocuments: true,
148+
});
149+
const response = await chain.call({ query: question });
150+
console.log(response);
151+
152+
// const response = await vectorStore.similaritySearch(question, 1);
153+
// console.log(response);
154+
155+
return response.text
156+
}
157+
158+
function supportFileType(mediaType) {
159+
const types = ['doc', 'docx', , 'pdf', 'text']
160+
return types.filter(e => mediaType.includes(e)).length > 0
161+
}
162+
163+
164+
export { askDocument, loadDocuments, supportFileType };
165+
```
Binary file not shown.
Binary file not shown.
10.5 KB
Binary file not shown.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "wechaty-jekyll",
3-
"version": "0.11.47",
3+
"version": "0.11.49",
44
"description": "Wechaty Official Website for News, Blogs, Contributor Profiles",
55
"private": true,
66
"type": "module",

0 commit comments

Comments
 (0)