Skip to content

Commit

Permalink
upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
DyAxy committed May 14, 2024
1 parent 5f61cba commit 70e71af
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 94 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ Python 版本需求 >= 3.9
## 现有功能
- 基于Crisp客服系统
- 自动推送文字、图片到指定聊天
- 自动基于关键词回复对应内容
- 支持回复后推送回对应客户
- 基于Telegram话题群将消息分栏

## 计划功能
- 回复图片功能(需要Crisp订阅)
Expand Down Expand Up @@ -38,6 +37,12 @@ python3 bot.py
3. 接着为你的bot设置一个username,但是一定要以bot结尾,例如:`v2board_bot`
4. 最后你就能得到bot的token了,看起来应该像这样:`123456789:gaefadklwdqojdoiqwjdiwqdo`

## 创建 Telegram Topic 群

1. 创建一个群聊,并将申请的 Bot 拉进去
2. 在管理群中,打开话题 (Topic),并将 Bot 设为管理员
3. 将 # 的话题设为置顶 (Pin)

## 申请 Crisp 以及 MarketPlace 插件

1. 注册 [https://app.crisp.chat/initiate/signup](https://app.crisp.chat/initiate/signup)
Expand Down
33 changes: 18 additions & 15 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,31 @@

async def onReply(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
msg = update.effective_message
website_id = config['crisp']['website']
if msg.reply_to_message.text is not None:
session_id = re.search(
'session_\w{8}(-\w{4}){3}-\w{12}', msg.reply_to_message.text).group()
elif msg.reply_to_message.caption is not None:
session_id = re.search(
'session_\w{8}(-\w{4}){3}-\w{12}', msg.reply_to_message.caption).group()
query = {
"type": "text",
"content": msg.text,
"from": "operator",
"origin": "chat"
}
client.website.send_message_in_conversation(website_id, session_id, query)

if msg.chat_id != config['bot']['groupId']:
return
for sessionId in context.bot_data:
if context.bot_data[sessionId]['topicId'] == msg.message_thread_id:
query = {
"type": "text",
"content": msg.text,
"from": "operator",
"origin": "chat"
}
client.website.send_message_in_conversation(
config['crisp']['website'],
sessionId,
query
)
return

def main():
try:
app = Application.builder().token(config['bot']['token']).defaults(Defaults(parse_mode='HTML')).build()
# 启动 Bot
if os.getenv('RUNNER_NAME') is not None:
return
app.add_handler(MessageHandler(filters.REPLY & filters.TEXT, onReply))
app.add_handler(MessageHandler(filters.TEXT, onReply))
app.job_queue.run_once(handler.exec,5,name='RTM')
app.run_polling(drop_pending_updates=True)
except Exception as error:
Expand Down
9 changes: 2 additions & 7 deletions config.yml.example
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
bot:
# Bot Token
token: 1234:1234567890abcdef
# 发送至,可以设置群或私聊
send_id:
- 0
- 0
# 发送至群
groupId: 0
crisp:
# 插件 ID
id:
# 插件秘钥
key:
# 网站 ID
website:
autoreply:
# 自动关键词回复,你可以复制成多行,每个关键词用 `|` 隔开即可,在 `:` 后输入自动回复内容
"在吗|你好": "欢迎使用客服系统,请等待客服回复你~"
133 changes: 63 additions & 70 deletions handler.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@

import bot
import json
import base64
import socketio
import requests
from telegram.ext import ContextTypes
from telegram import InlineKeyboardButton, InlineKeyboardMarkup

config = bot.config
client = bot.client
website_id = config["crisp"]["website"]

def getKey(content: str):
if len(config["autoreply"]) > 0:
for x in config["autoreply"]:
keyword = x.split("|")
for key in keyword:
if key in content:
return True, config["autoreply"][x]
return False, ""
groupId = config["bot"]["groupId"]
websiteId = config["crisp"]["website"]

async def sendTextMessage(message):
session_id = message["session_id"]
metas = client.website.get_conversation_metas(website_id, session_id)
def getMetas(sessionId):
metas = client.website.get_conversation_metas(websiteId, sessionId)

flow = ['📠<b>Crisp消息推送</b>','']
if len(metas["email"]) > 0:
Expand All @@ -34,52 +27,59 @@ async def sendTextMessage(message):
UsedTraffic = metas["data"]["UsedTraffic"]
AllTraffic = metas["data"]["AllTraffic"]
flow.append(f"🗒<b>流量信息</b>:{UsedTraffic} / {AllTraffic}")
if len(flow) > 2:
return '\n'.join(flow)
return '无额外信息'

async def createSession(data):
bot = callbackContext.bot
botData = callbackContext.bot_data
sessionId = data["session_id"]
session = botData.get(sessionId)

flow.append(f"🧾<b>消息内容</b>:{message['content']}")
result, autoreply = getKey(message["content"])
if result is True:
flow.append("")
flow.append(f"💡<b>自动回复</b>:{autoreply}")
query = {
"type": "text",
"content": autoreply,
"from": "operator",
"origin": "chat",
metas = getMetas(sessionId)
if session is None:
topic = await bot.create_forum_topic(
groupId,data["user"]["nickname"])
msg = await bot.send_message(
groupId,
metas,
message_thread_id=topic.message_thread_id
)
botData[sessionId] = {
'topicId': topic.message_thread_id,
'messageId': msg.message_id,
}
client.website.send_message_in_conversation(website_id, session_id, query)

flow.append("")
flow.append(f"🧷<b>Session</b>:<tg-spoiler>{session_id}</tg-spoiler>")

text = '\n'.join(flow)
for send_id in config["bot"]["send_id"]:
await callbackContext.bot.send_message(
chat_id=send_id, text=text)
client.website.mark_messages_read_in_conversation(
website_id,
session_id,
{"from": "user", "origin": "chat", "fingerprints": [message["fingerprint"]]},
)
else:
await bot.edit_message_text('加载中',groupId,session['messageId'])
await bot.edit_message_text(metas,groupId,session['messageId'])

async def sendImageMessage(message):
session_id = message["session_id"]
async def sendMessage(data):
bot = callbackContext.bot
botData = callbackContext.bot_data
sessionId = data["session_id"]
session = botData.get(sessionId)

flow = ['📠<b>Crisp消息推送</b>','']
flow.append("")
flow.append(f"🧷<b>Session</b>:<tg-spoiler>{session_id}</tg-spoiler>")
text = '\n'.join(flow)
client.website.mark_messages_read_in_conversation(websiteId,sessionId,
{"from": "user", "origin": "chat", "fingerprints": [data["fingerprint"]]}
)

for send_id in config["bot"]["send_id"]:
await callbackContext.bot.send_photo(
chat_id=send_id,
photo=message["content"]["url"],
caption=text
if data["type"] == "text":
flow = ['📠<b>消息推送</b>','']
flow.append(f"🧾<b>消息内容</b>:{data['content']}")
await bot.send_message(
groupId,
'\n'.join(flow),
message_thread_id=session["topicId"]
)
client.website.mark_messages_read_in_conversation(
website_id,
session_id,
{"from": "user", "origin": "chat", "fingerprints": [message["fingerprint"]]},
)
elif data["type"] == "file" and str(data["content"]["type"]).count("image") > 0:
await bot.send_photo(
groupId,
data["content"]["url"],
message_thread_id=session["topicId"]
)
else:
print("Unhandled Message Type : ", data["type"])

sio = socketio.AsyncClient(reconnection_attempts=5, logger=True)
# Def Event Handlers
Expand All @@ -104,15 +104,10 @@ async def disconnect():
print("Disconnected from server.")
@sio.on("message:send")
async def messageForward(data):
try:
if data["type"] == "text":
await sendTextMessage(data)
elif data["type"] == "file" and str(data["content"]["type"]).count("image") > 0:
await sendImageMessage(data)
else:
print("Unhandled Message Type : ", data["type"])
except Exception as err:
print(err)
if data["website_id"] != websiteId:
return
await createSession(data)
await sendMessage(data)

# Meow!
def getCrispConnectEndpoints():
Expand All @@ -126,17 +121,15 @@ def getCrispConnectEndpoints():
response = requests.request("GET", url, headers=headers, data=payload)
endPoint = json.loads(response.text).get("data").get("socket").get("app")
return endPoint

# Connecting to Crisp RTM(WSS) Server
async def start_server():
async def exec(context: ContextTypes.DEFAULT_TYPE):
global callbackContext
callbackContext = context
# await sendAllUnread()
await sio.connect(
getCrispConnectEndpoints(),
transports="websocket",
wait_timeout=10,
)
await sio.wait()

async def exec(context: ContextTypes.DEFAULT_TYPE):
global callbackContext
callbackContext = context
# await sendAllUnread()
await start_server()
await sio.wait()
6 changes: 6 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
a = {}
a['a'] = 1
a['b'] = 2

for i in a:
print(i)

0 comments on commit 70e71af

Please sign in to comment.