Skip to content

Commit

Permalink
Merge pull request 'dev' (#1) from dev into master
Browse files Browse the repository at this point in the history
  • Loading branch information
bigbrother666sh committed Aug 7, 2024
2 parents 312c15e + 3cf0a58 commit fd50cbd
Show file tree
Hide file tree
Showing 19 changed files with 692 additions and 509 deletions.
57 changes: 57 additions & 0 deletions About_WXbot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
### 运行命令

`docker run -itd --name wxbot -e WXBOT_ARGS="-q http://127.0.0.1:8080/qr_callback" -p 8066:8080 registry.cn-shanghai.aliyuncs.com/jwping/wxbot:v1.10.1-9-3.9.8.25`

【2024-07-07】亲测正常下载就行,无需特殊操作

以上命令参数不要改,尤其是端口映射,awada dm部分是写死的。

### 首次登录

首次运行需要用使用的微信号扫码登录下

`docker logs -f wxbot`

注意,如果你使用OrbStack,直接用软件界面打开container的日志,可能看不到二维码链接,所以要用系统自带的终端使用上述命令。

等待终端输出,直到看到 类似 “http://weixin.qq.com/x/QfOfkbfe_P5wdeKNjR7S” 这样的登录二维码链接信息,复制(**注意不要直接打开,那没用!**

使用二维码生成器,比如草料 https://cli.im/url

生成一个二维码,用需要的微信扫码登录(仅限个微)

直到logs出现 `Http Server Listen 0.0.0.0:8080` 那就好了,终端里面出现的任何报错信息都可以忽略,不影响正常使用。

好了 `ctrl+C` 退出 终端logs界面,之后终端直接关闭都行。

用作助理的个微小号建议把支付还有服务等都关闭,不要暴露敏感信息,**使用者请风险自担**

### 再次登录

在macOS或者linux上运行wxbot最适合成功后常开,不要频繁关闭打开,就放在那里就好,反正默认是静默运行,终端正常也不会输出什么信息的。

理论上,关掉container(包括电脑重启),再次启动会自动登录,此时只需要在微信手机端上点同意就行。

如果失败的话, 先运行 `docker logs -f wxbot` 看看是不是要重新登录。

如果看不到让你重新登录的二维码链接信息,尝试

`docker restart wxbot`

如果还不行,运行,

`docker rm -f wxbot`

然后用最开始那个运行命令再次创建container,放心image已经在本地,不会再次下载。

### 问题排查

首先logs界面里面出现的任何报错信息都可以忽略,只要有 `Http Server Listen 0.0.0.0:8080` 那就是正常的

每次启动(包括重启),最长需要5min才能出现 Http Server Listen 0.0.0.0:8080 或者二维码链接,期间任何报错信息都没所谓

如果在 Http Server Listen 0.0.0.0:8080 或者 二维码链接 之前长时间(大于等于5min)不出任何信息,那可能是出问题了。参考再次登录方案。

`Http Server Listen 0.0.0.0:8080` 之后基本终端界面就不会出新的消息了,这是正常的,这个时候其实可以退出logs,甚至关闭终端。

更多,请参考:https://github.com/jwping/wxbot?tab=readme-ov-file#linux%E4%B8%8Bdocker%E9%83%A8%E7%BD%B2
109 changes: 98 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,116 @@
# What's Awada

awada是wiseflow团队计划中 **“可在线自主学习的AI助理”** 开源项目
[wiseflow](https://github.com/TeamWiseFlow/wiseflow) 自发布以来,在开源社区内获得了不错的反响,这让我们在激动之余也不断思考它能与哪些具体的下游任务进行结合

[wiseflow](https://github.com/TeamWiseFlow/wiseflow)已经可以实现不断从网络(包括社交网络)中挖掘、提炼指定方向的知识,自然而然的,我们会想到将这种能力与AI Agent联合起来,这就是Awada项目的灵感!
我们的第一个想法就是既然wiseflow已经可以实现不断从网络(包括社交网络)中挖掘、提炼指定方向的知识,那么这是否可以作为AI助理(Agent)的动态知识库,即**赋予助理在线自主学习能力**

<img alt="scope" src="asset/2024H1Plan.png" width="960"/>
本项目就是这样一个示例,考虑到目前国内不管是工作还是日常,大家主要的信息获取渠道就是微信(包括关注的公众号、参与的微信群聊等),并且用户与助理最自然、最舒服的交流也是直接使用微信,因此我们将awada定义为
**基于微信的可在线自主学习的个人助理**

# 目前已经实现的效果

项目目前还很前期,仅实现了通过[wxbot](https://github.com/jwping/wxbot)连接微信客户端,通过wiseflow实现信息的自动提取和存储两个主要模块, 实际上应该大做文章的Agent模块目前还完全未动。

但是实现了一个简单的示例,可以每天从wiseflow数据库中摘取过去一天的信息并自动提炼整理成一份简报发给指定的用户。

整体效果如下:

<img alt="scope" src="asset/awada_demo.png" width="960"/>

# 声明

**任何对本项目代码的使用、阅读、拷贝、修改、分发以及整合都被视为完全阅读并理解、接受如下各项声明,并且以上行为的所有后果均为使用者本人承担,与awada、wiseflow项目作者、贡献者、运营者无关!**

- 1、awada为开源学习项目,仅限个人用户技术交流,请勿用作任何商业用途或实际生产用途;
- 2、微信接入方案来自开源项目 [wxbot](https://github.com/jwping/wxbot), 不能保证稳定性与安全性(目前没有安全稳定的个微接入方案),请风险自担(**建议使用微信小号接入,接入前关闭所有支付相关和服务功能**);
- 3、微信软件的各项产权等归属腾讯公司;
- 4、再说一遍,风险自担,责任自担,与我无关;
- 5、don't be evil。

# 操作说明(实现上图的效果)

## 1、启动 wiseflow (目前整个分析后端和数据库都依赖wiseflow,awada不会另外维护这部分代码)

具体见 [wiseflow README_CN.md](https://github.com/TeamWiseFlow/wiseflow/blob/master/README_CN.md)

## 2、 启动 wxbot (微信机器人部分依赖wxbot,awada永远不会维护这部分代码)

首先感谢wxbot项目作者 **jwping**

- windows用户

在这里下载对应版本微信客户端和wxbot-sidecar.exe:阿里网盘: https://www.aliyundrive.com/s/4eiNnE4hp4n 提取码: rt25

然后命令行运行

`.\wxbot-sidecar.exe -p 8066`

也可以参考 https://github.com/jwping/wxbot?tab=readme-ov-file#231%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%A4%BA%E4%BE%8B
在 wxbot-sidecar.exe 同级目录构建配置文件,文件内容只需要:

` {
"addr": "0.0.0.0:8066"
}`

这样之后就可以直接双击 wxbot-sidecar.exe 启动。

- mac/linux 用户

大神jwping很贴心的为我们准备了完整的 wine+微信客户端+wxbot-sidecar docker镜像,还上传到阿里云上了,所以使用起来也非常简单。

具体可以参考 [这里](./About_WXbot.md)

- 更多有关wxbot的问题请参考原repo

https://github.com/jwping/wxbot

作者写的很详细,尤其是接口部分,希望大家能够顺手给作者打个赏。【Awada项目完全技术交流定位,无需任何打赏和回馈】

## 3、启动awada程序

**建议使用conda创建虚拟环境**

```commandline
git clone [email protected]:TeamWiseFlow/awada.git
cd awada
conda create -n awada python=3.10
conda activate awada
pip install -r requirements.txt
python dm.py
python tasks.py
```

dm.py 是消息接收和处理脚本;

tasks.py 是每日简报生成和发送脚本,可以打开代码按需定制【发送时间、发送人列表以及消息格式等】,如无需要也可以不启动。

# Join Us

awada的开发预计会在数月内启动,如果您也对此灵感迫不及待,下面是我们拟采用的一些技术栈
长期来看,awada有希望凭借**在线自主学习能力**成为**最贴心的私人助理**或者是**精通某个领域的专家顾问**,不过这还有很多功能有待开发,如下是一个构思图

- 个微接入(初期我们先仅考虑接入微信平台,通过微信群聊、指定的公众号进行学习,同时用户通过微信与bot进行对话): https://github.com/jwping/wxbot
- 动态知识库(指定方向的知识挖掘、提炼与获取): https://github.com/TeamWiseFlow/wiseflow
- Agent 框架。 这部分可选择的很多,如下是我们推荐的一些,您也可以选择您熟悉的框架或自写:
<img alt="scope" src="asset/2024H1Plan.png" width="960"/>

当我最开始做这张图的时候,着实兴奋了好一阵,但无奈个人的时间精力总是有限,后续我还是会把主要精力花在wiseflow的升级和维护中(这也是awada的基础组件),而awada的Agent部分就留给开源社区的群策群力吧!

_如下是我前期考察过的一些非常优秀的项目,其实很适合借鉴整合:_
- https://github.com/danswer-ai/danswer 特别适合从大量文档中查找特定信息,自带角色管理
- https://github.com/getzep/zep 特别擅长长期记忆管理与召回
- https://github.com/embedchain 非常简洁的RAG方案,开箱即用
- https://github.com/RUC-NLPIR/FlashRAG?tab=readme-ov-file 更加专业的RAG工具箱
- https://github.com/filip-michalsky/SalesGPT 适合“目的域对话”的Agent,可以实现打电话哦
- https://github.com/infiniflow/ragflow 完备的文档解析,独特的文档智能算法

---
Agent部分的代码建议统一放在 [./agents](./agents) 文件夹中,其实目前的topnews和tasks也应该整合到这里。

**如果您愿意将您的开发贡献至本项目,我们将不胜感激!**🚀💖

**如果您愿意将您的开发贡献至本项目,我们将不胜感激!🚀💖**
# Citation

所有为本项目贡献代码的开发者将自动成为 Wiseflow 主项目的贡献者 (contributor) 🎉
如果您在相关工作中参考或引用了本项目的部分或全部,请注明如下信息:

基于 Wiseflow 的所有商业合作项目,均会面向 `Wiseflow contributor & core-maintainer` 发出专案邀请,项目收益将直接归属专案组 💼💰。
```
Author:Awada Team
https://github.com/TeamWiseFlow/awada
Licensed under Apache2.0
```
Binary file added asset/awada_demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 120 additions & 0 deletions dm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import asyncio
import websockets
import json
import requests


# 先简单的用硬代码方案指定监控的群聊和私聊信息源,后续可以改进
# 注意群聊写法,群号后面还必须带上 @chatroom
watching_list = ['49591466778@chatroom', 'wxid_tnv0hd5hj3rs11']


async def pipeline(input_data):
url = "http://127.0.0.1:8077/feed"
response = requests.post(url, json=input_data)
if response.status_code != 200:
print("Warning: Failed to send message. check wiseflow status")
print(response.text)


# 对应不同的数据结构,考虑后续维护升级可能,分成两个函数
async def get_public_msg(websocket_uri):
reconnect_attempts = 0
max_reconnect_attempts = 3
while True:
try:
async with websockets.connect(websocket_uri, max_size=10 * 1024 * 1024) as websocket:
while True:
response = await websocket.recv()
datas = json.loads(response)
for data in datas["data"]:
input_data = {
"user_id": data["StrTalker"],
"type": "publicMsg",
"content": data["Content"],
"addition": data["MsgSvrID"]
}
await pipeline(input_data)

except websockets.exceptions.ConnectionClosedError as e:
print(f"Connection closed with exception: {e}")
reconnect_attempts += 1
if reconnect_attempts <= max_reconnect_attempts:
print(f"Reconnecting attempt {reconnect_attempts}...")
await asyncio.sleep(1)
else:
print("Max reconnect attempts reached. Exiting.")
break
except Exception as e:
print(f"An unexpected error occurred: {e}")
break


async def get_general_msg(websocket_uri):
reconnect_attempts = 0
max_reconnect_attempts = 3
while True:
try:
async with websockets.connect(websocket_uri, max_size=10 * 1024 * 1024) as websocket:
while True:
response = await websocket.recv()
datas = json.loads(response)
print(datas)
print('\n')
for data in datas["data"]:
if data["IsSender"] == "1":
# 跳过自己发送的消息
continue
if data['StrTalker'] not in watching_list:
continue

# 目前仅处理文本消息和url(微信公众号分享卡片)两类消息
# 如需更多类型消息,请看 wxbot各类型信息原始json格式.txt
if data['Type'] == '1':
input_data = {
"user_id": data["StrTalker"],
"type": "text",
"content": data["StrContent"],
"addition": data["MsgSvrID"]
}
elif data['Type'] == '49':
if data['SubType'] != '5':
# 非文章形式的公众号消息,比如公众号发来的视频卡
continue
input_data = {
"user_id": data["StrTalker"],
"type": "url",
"content": data["Content"],
"addition": data["MsgSvrID"]
}
else:
continue
await pipeline(input_data)
except websockets.exceptions.ConnectionClosedError as e:
print(f"Connection closed with exception: {e}")
reconnect_attempts += 1
if reconnect_attempts <= max_reconnect_attempts:
print(f"Reconnecting attempt {reconnect_attempts}...")
await asyncio.sleep(1)
else:
print("Max reconnect attempts reached. Exiting.")
break
except Exception as e:
print(f"An unexpected error occurred: {e}")
break


async def main():
uri_general = "ws://127.0.0.1:8066/ws/generalMsg"
uri_public = "ws://127.0.0.1:8066/ws/publicMsg"

# 创建并行任务
task1 = asyncio.create_task(get_general_msg(uri_general))
task2 = asyncio.create_task(get_public_msg(uri_public))

# 等待所有任务完成
await asyncio.gather(task1, task2)


# 使用asyncio事件循环运行main coroutine
asyncio.run(main())
18 changes: 18 additions & 0 deletions general_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import os


def get_logger_level() -> str:
level_map = {
'silly': 'CRITICAL',
'verbose': 'DEBUG',
'info': 'INFO',
'warn': 'WARNING',
'error': 'ERROR',
}
level: str = os.environ.get('WS_LOG', 'info').lower()
if level not in level_map:
raise ValueError(
'WiseFlow LOG should support the values of `silly`, '
'`verbose`, `info`, `warn`, `error`'
)
return level_map.get(level, 'info')
Loading

0 comments on commit fd50cbd

Please sign in to comment.