mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-08 23:06:03 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75af631c17 | ||
|
|
04dd4fce68 | ||
|
|
2776a95a40 | ||
|
|
dc93b37fd6 | ||
|
|
6502a64cab | ||
|
|
2c3fdb4fdc |
@@ -23,7 +23,10 @@ class LarkConfigMigration(migration.Migration):
|
|||||||
"enable": False,
|
"enable": False,
|
||||||
"app_id": "cli_abcdefgh",
|
"app_id": "cli_abcdefgh",
|
||||||
"app_secret": "XXXXXXXXXX",
|
"app_secret": "XXXXXXXXXX",
|
||||||
"bot_name": "LangBot"
|
"bot_name": "LangBot",
|
||||||
|
"enable-webhook": False,
|
||||||
|
"port": 2285,
|
||||||
|
"encrypt-key": "xxxxxxxxx"
|
||||||
})
|
})
|
||||||
|
|
||||||
await self.ap.platform_cfg.dump_config()
|
await self.ap.platform_cfg.dump_config()
|
||||||
|
|||||||
31
pkg/core/migrations/m030_lark_config_cmpl.py
Normal file
31
pkg/core/migrations/m030_lark_config_cmpl.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .. import migration
|
||||||
|
|
||||||
|
|
||||||
|
@migration.migration_class("lark-config-cmpl", 30)
|
||||||
|
class LarkConfigCmplMigration(migration.Migration):
|
||||||
|
"""迁移"""
|
||||||
|
|
||||||
|
async def need_migrate(self) -> bool:
|
||||||
|
"""判断当前环境是否需要运行此迁移"""
|
||||||
|
|
||||||
|
for adapter in self.ap.platform_cfg.data['platform-adapters']:
|
||||||
|
if adapter['adapter'] == 'lark':
|
||||||
|
if 'enable-webhook' not in adapter:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
"""执行迁移"""
|
||||||
|
for adapter in self.ap.platform_cfg.data['platform-adapters']:
|
||||||
|
if adapter['adapter'] == 'lark':
|
||||||
|
if 'enable-webhook' not in adapter:
|
||||||
|
adapter['enable-webhook'] = False
|
||||||
|
if 'port' not in adapter:
|
||||||
|
adapter['port'] = 2285
|
||||||
|
if 'encrypt-key' not in adapter:
|
||||||
|
adapter['encrypt-key'] = "xxxxxxxxx"
|
||||||
|
|
||||||
|
await self.ap.platform_cfg.dump_config()
|
||||||
@@ -10,10 +10,9 @@ from ..migrations import m010_ollama_requester_config, m011_command_prefix_confi
|
|||||||
from ..migrations import m015_gitee_ai_config, m016_dify_service_api, m017_dify_api_timeout_params, m018_xai_config, m019_zhipuai_config
|
from ..migrations import m015_gitee_ai_config, m016_dify_service_api, m017_dify_api_timeout_params, m018_xai_config, m019_zhipuai_config
|
||||||
from ..migrations import m020_wecom_config, m021_lark_config, m022_lmstudio_config, m023_siliconflow_config, m024_discord_config, m025_gewechat_config
|
from ..migrations import m020_wecom_config, m021_lark_config, m022_lmstudio_config, m023_siliconflow_config, m024_discord_config, m025_gewechat_config
|
||||||
from ..migrations import m026_qqofficial_config, m027_wx_official_account_config, m028_aliyun_requester_config
|
from ..migrations import m026_qqofficial_config, m027_wx_official_account_config, m028_aliyun_requester_config
|
||||||
|
from ..migrations import m029_dashscope_app_api_config, m030_lark_config_cmpl
|
||||||
|
|
||||||
|
|
||||||
from ..migrations import m029_dashscope_app_api_config
|
|
||||||
|
|
||||||
@stage.stage_class("MigrationStage")
|
@stage.stage_class("MigrationStage")
|
||||||
class MigrationStage(stage.BootingStage):
|
class MigrationStage(stage.BootingStage):
|
||||||
"""迁移阶段
|
"""迁移阶段
|
||||||
|
|||||||
@@ -11,10 +11,16 @@ import base64
|
|||||||
import uuid
|
import uuid
|
||||||
import json
|
import json
|
||||||
import datetime
|
import datetime
|
||||||
|
import hashlib
|
||||||
|
import base64
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import lark_oapi.ws.exception
|
import lark_oapi.ws.exception
|
||||||
|
import quart
|
||||||
|
from flask import jsonify
|
||||||
from lark_oapi.api.im.v1 import *
|
from lark_oapi.api.im.v1 import *
|
||||||
|
from lark_oapi.api.verification.v1 import GetVerificationRequest
|
||||||
|
|
||||||
from .. import adapter
|
from .. import adapter
|
||||||
from ...pipeline.longtext.strategies import forward
|
from ...pipeline.longtext.strategies import forward
|
||||||
@@ -25,6 +31,28 @@ from ..types import entities as platform_entities
|
|||||||
from ...utils import image
|
from ...utils import image
|
||||||
|
|
||||||
|
|
||||||
|
class AESCipher(object):
|
||||||
|
def __init__(self, key):
|
||||||
|
self.bs = AES.block_size
|
||||||
|
self.key=hashlib.sha256(AESCipher.str_to_bytes(key)).digest()
|
||||||
|
@staticmethod
|
||||||
|
def str_to_bytes(data):
|
||||||
|
u_type = type(b"".decode('utf8'))
|
||||||
|
if isinstance(data, u_type):
|
||||||
|
return data.encode('utf8')
|
||||||
|
return data
|
||||||
|
@staticmethod
|
||||||
|
def _unpad(s):
|
||||||
|
return s[:-ord(s[len(s) - 1:])]
|
||||||
|
def decrypt(self, enc):
|
||||||
|
iv = enc[:AES.block_size]
|
||||||
|
cipher = AES.new(self.key, AES.MODE_CBC, iv)
|
||||||
|
return self._unpad(cipher.decrypt(enc[AES.block_size:]))
|
||||||
|
def decrypt_string(self, enc):
|
||||||
|
enc = base64.b64decode(enc)
|
||||||
|
return self.decrypt(enc).decode('utf8')
|
||||||
|
|
||||||
|
|
||||||
class LarkMessageConverter(adapter.MessageConverter):
|
class LarkMessageConverter(adapter.MessageConverter):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -288,12 +316,57 @@ class LarkMessageSourceAdapter(adapter.MessageSourceAdapter):
|
|||||||
] = {}
|
] = {}
|
||||||
|
|
||||||
config: dict
|
config: dict
|
||||||
|
quart_app: quart.Quart
|
||||||
ap: app.Application
|
ap: app.Application
|
||||||
|
|
||||||
def __init__(self, config: dict, ap: app.Application):
|
def __init__(self, config: dict, ap: app.Application):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.ap = ap
|
self.ap = ap
|
||||||
|
self.quart_app = quart.Quart(__name__)
|
||||||
|
|
||||||
|
@self.quart_app.route('/lark/callback', methods=['POST'])
|
||||||
|
async def lark_callback():
|
||||||
|
try:
|
||||||
|
data = await quart.request.json
|
||||||
|
|
||||||
|
if 'encrypt' in data:
|
||||||
|
cipher = AESCipher(self.config['encrypt-key'])
|
||||||
|
data = cipher.decrypt_string(data['encrypt'])
|
||||||
|
data = json.loads(data)
|
||||||
|
|
||||||
|
type = data.get("type")
|
||||||
|
if type is None :
|
||||||
|
context = EventContext(data)
|
||||||
|
type = context.header.event_type
|
||||||
|
|
||||||
|
if 'url_verification' == type:
|
||||||
|
print(data.get("challenge"))
|
||||||
|
# todo 验证verification token
|
||||||
|
return {
|
||||||
|
"challenge": data.get("challenge")
|
||||||
|
}
|
||||||
|
context = EventContext(data)
|
||||||
|
type = context.header.event_type
|
||||||
|
p2v1 = P2ImMessageReceiveV1()
|
||||||
|
p2v1.header = context.header
|
||||||
|
event = P2ImMessageReceiveV1Data()
|
||||||
|
event.message = EventMessage(context.event['message'])
|
||||||
|
event.sender = EventSender(context.event['sender'])
|
||||||
|
p2v1.event = event
|
||||||
|
p2v1.schema = context.schema
|
||||||
|
if 'im.message.receive_v1' == type:
|
||||||
|
try:
|
||||||
|
event = await self.event_converter.target2yiri(p2v1, self.api_client)
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if event.__class__ in self.listeners:
|
||||||
|
await self.listeners[event.__class__](event, self)
|
||||||
|
|
||||||
|
return {"code": 200, "message": "ok"}
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
|
return {"code": 500, "message": "error"}
|
||||||
|
|
||||||
async def on_message(event: lark_oapi.im.v1.P2ImMessageReceiveV1):
|
async def on_message(event: lark_oapi.im.v1.P2ImMessageReceiveV1):
|
||||||
|
|
||||||
@@ -392,16 +465,29 @@ class LarkMessageSourceAdapter(adapter.MessageSourceAdapter):
|
|||||||
self.listeners.pop(event_type)
|
self.listeners.pop(event_type)
|
||||||
|
|
||||||
async def run_async(self):
|
async def run_async(self):
|
||||||
try:
|
port = self.config['port']
|
||||||
await self.bot._connect()
|
enable_webhook = self.config['enable-webhook']
|
||||||
except lark_oapi.ws.exception.ClientException as e:
|
|
||||||
raise e
|
|
||||||
except Exception as e:
|
|
||||||
await self.bot._disconnect()
|
|
||||||
if self.bot._auto_reconnect:
|
|
||||||
await self.bot._reconnect()
|
|
||||||
else:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
|
if not enable_webhook:
|
||||||
|
try:
|
||||||
|
await self.bot._connect()
|
||||||
|
except lark_oapi.ws.exception.ClientException as e:
|
||||||
|
raise e
|
||||||
|
except Exception as e:
|
||||||
|
await self.bot._disconnect()
|
||||||
|
if self.bot._auto_reconnect:
|
||||||
|
await self.bot._reconnect()
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
else:
|
||||||
|
async def shutdown_trigger_placeholder():
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
await self.quart_app.run_task(
|
||||||
|
host='0.0.0.0',
|
||||||
|
port=port,
|
||||||
|
shutdown_trigger=shutdown_trigger_placeholder,
|
||||||
|
)
|
||||||
async def kill(self) -> bool:
|
async def kill(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ class WecomEventConverter:
|
|||||||
)
|
)
|
||||||
elif event.type == "image":
|
elif event.type == "image":
|
||||||
friend = platform_entities.Friend(
|
friend = platform_entities.Friend(
|
||||||
id=event.user_id,
|
id=f"u{event.user_id}",
|
||||||
nickname=str(event.agent_id),
|
nickname=str(event.agent_id),
|
||||||
remark="",
|
remark="",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
semantic_version = "v3.4.7.1"
|
semantic_version = "v3.4.7.2"
|
||||||
|
|
||||||
debug_mode = False
|
debug_mode = False
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,10 @@
|
|||||||
"enable": false,
|
"enable": false,
|
||||||
"app_id": "cli_abcdefgh",
|
"app_id": "cli_abcdefgh",
|
||||||
"app_secret": "XXXXXXXXXX",
|
"app_secret": "XXXXXXXXXX",
|
||||||
"bot_name": "LangBot"
|
"bot_name": "LangBot",
|
||||||
|
"enable-webhook": false,
|
||||||
|
"port": 2285,
|
||||||
|
"encrypt-key": "xxxxxxxxx"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"adapter": "discord",
|
"adapter": "discord",
|
||||||
|
|||||||
@@ -252,6 +252,21 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "飞书的bot_name"
|
"description": "飞书的bot_name"
|
||||||
|
},
|
||||||
|
"enable-webhook": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "是否启用webhook模式"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "设置监听的端口,开启callback event时需要设置",
|
||||||
|
"default": 2285
|
||||||
|
},
|
||||||
|
"encrypt-key": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "设置加密密钥"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user