mirror of
https://github.com/langbot-app/LangBot.git
synced 2025-11-25 11:29:39 +08:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a10d3213fd | ||
|
|
f52a0eb02f | ||
|
|
1ea8da69a2 | ||
|
|
5bbc38a7a3 | ||
|
|
aa433bd5ab | ||
|
|
2c5933da0b | ||
|
|
77bc6fbf59 | ||
|
|
701cb7be40 | ||
|
|
ab8d77c968 | ||
|
|
6c03fe678a | ||
|
|
41b30238c3 | ||
|
|
aa768459c0 | ||
|
|
28014512f7 | ||
|
|
f9a99eed66 | ||
|
|
461b574e09 | ||
|
|
36c192ff6b | ||
|
|
101625965c | ||
|
|
83177a3416 | ||
|
|
c3904786e1 | ||
|
|
b31c34905a | ||
|
|
41cbe91870 | ||
|
|
872b16b779 | ||
|
|
9f3cc9c293 | ||
|
|
2d148c4970 | ||
|
|
0869b57741 | ||
|
|
af225aa18f | ||
|
|
06f3c5d32b | ||
|
|
4e71a08b57 | ||
|
|
bf5ebc9245 | ||
|
|
fba81582ab | ||
|
|
b4645168f9 | ||
|
|
d00c68e329 | ||
|
|
cb636b96bf | ||
|
|
12468b5b15 | ||
|
|
6a5414b5fd |
5
.github/workflows/sync-wiki.yml
vendored
5
.github/workflows/sync-wiki.yml
vendored
@@ -1,11 +1,6 @@
|
||||
name: Update Wiki
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'res/wiki/**'
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
80
.github/workflows/test-pr.yml
vendored
Normal file
80
.github/workflows/test-pr.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: Test Pull Request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ready_for_review]
|
||||
paths:
|
||||
# 任何py文件改动都会触发
|
||||
- '**.py'
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
# 允许手动触发
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
perform-test:
|
||||
runs-on: ubuntu-latest
|
||||
# 如果事件为pull_request_review且review状态为approved,则执行
|
||||
if: >
|
||||
github.event_name == 'pull_request' ||
|
||||
(github.event_name == 'pull_request_review' && github.event.review.state == 'APPROVED') ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'issue_comment' && github.event.issue.pull_request != '' && contains(github.event.comment.body, '/test') && github.event.comment.user.login == 'RockChinQ')
|
||||
steps:
|
||||
# 签出测试工程仓库代码
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# 仓库地址
|
||||
repository: RockChinQ/qcg-tester
|
||||
# 仓库路径
|
||||
path: qcg-tester
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cd qcg-tester
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Get PR details
|
||||
id: get-pr
|
||||
if: github.event_name == 'issue_comment'
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: GET /repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set PR source branch as env variable
|
||||
if: github.event_name == 'issue_comment'
|
||||
run: |
|
||||
PR_SOURCE_BRANCH=$(echo '${{ steps.get-pr.outputs.data }}' | jq -r '.head.ref')
|
||||
echo "BRANCH=$PR_SOURCE_BRANCH" >> $GITHUB_ENV
|
||||
|
||||
- name: Set PR Branch as bash env
|
||||
if: github.event_name != 'issue_comment'
|
||||
run: |
|
||||
echo "BRANCH=${{ github.head_ref }}" >> $GITHUB_ENV
|
||||
- name: Set OpenAI API Key from Secrets
|
||||
run: |
|
||||
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" >> $GITHUB_ENV
|
||||
- name: Set OpenAI Reverse Proxy URL from Secrets
|
||||
run: |
|
||||
echo "OPENAI_REVERSE_PROXY=${{ secrets.OPENAI_REVERSE_PROXY }}" >> $GITHUB_ENV
|
||||
- name: Run test
|
||||
run: |
|
||||
cd qcg-tester
|
||||
python main.py
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
run: |
|
||||
cd qcg-tester/resource/QChatGPT
|
||||
curl -Os https://uploader.codecov.io/latest/linux/codecov
|
||||
chmod +x codecov
|
||||
./codecov -t ${{ secrets.CODECOV_TOKEN }}
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -31,4 +31,5 @@ claude.json
|
||||
bard.json
|
||||
/*yaml
|
||||
!/docker-compose.yaml
|
||||
res/instance_id.json
|
||||
res/instance_id.json
|
||||
.DS_Store
|
||||
|
||||
13
README.md
13
README.md
@@ -14,8 +14,11 @@
|
||||
<img src="https://img.shields.io/docker/pulls/rockchin/qchatgpt?color=blue" alt="docker pull">
|
||||
</a>
|
||||

|
||||
<img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python">
|
||||
<a href="https://codecov.io/gh/RockChinQ/QChatGPT" >
|
||||
<img src="https://codecov.io/gh/RockChinQ/QChatGPT/graph/badge.svg?token=pjxYIL2kbC"/>
|
||||
</a>
|
||||
<br/>
|
||||
<img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python">
|
||||
<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=66-aWvn8cbP4c1ut_1YYkvvGVeEtyTH8&authKey=pTaKBK5C%2B8dFzQ4XlENf6MHTCLaHnlKcCRx7c14EeVVlpX2nRSaS8lJm8YeM4mCU&noverify=0&group_code=195992197">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/%E5%AE%98%E6%96%B9%E7%BE%A4-195992197-purple">
|
||||
</a>
|
||||
@@ -29,6 +32,8 @@
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Linux%E9%83%A8%E7%BD%B2%E8%A7%86%E9%A2%91-208647">
|
||||
</a>
|
||||
|
||||
## 使用文档
|
||||
|
||||
<a href="https://qchatgpt.rockchin.top">项目主页</a> |
|
||||
<a href="https://qchatgpt.rockchin.top/posts/feature.html">功能介绍</a> |
|
||||
<a href="https://qchatgpt.rockchin.top/posts/deploy/">部署文档</a> |
|
||||
@@ -36,5 +41,11 @@
|
||||
<a href="https://qchatgpt.rockchin.top/posts/plugin/intro.html">插件介绍</a> |
|
||||
<a href="https://github.com/RockChinQ/QChatGPT/issues/new?assignees=&labels=%E7%8B%AC%E7%AB%8B%E6%8F%92%E4%BB%B6&projects=&template=submit-plugin.yml&title=%5BPlugin%5D%3A+%E8%AF%B7%E6%B1%82%E7%99%BB%E8%AE%B0%E6%96%B0%E6%8F%92%E4%BB%B6">提交插件</a>
|
||||
|
||||
## 相关链接
|
||||
|
||||
<a href="https://github.com/RockChinQ/qcg-installer">安装器源码</a> |
|
||||
<a href="https://github.com/RockChinQ/qcg-tester">测试工程源码</a> |
|
||||
<a href="https://github.com/the-lazy-me/QChatGPT-Wiki">官方文档储存库</a>
|
||||
|
||||
<img alt="回复效果(带有联网插件)" src="https://qchatgpt.rockchin.top/assets/image/QChatGPT-1211.png" width="500px"/>
|
||||
</div>
|
||||
|
||||
@@ -180,7 +180,7 @@ Plugin [usage](https://github.com/RockChinQ/QChatGPT/wiki/%E6%8F%92%E4%BB%B6%E4%
|
||||
|
||||
在`tests/plugin_examples`目录下,将其整个目录复制到`plugins`目录下即可使用
|
||||
|
||||
- `cmdcn` - 主程序指令中文形式
|
||||
- `cmdcn` - 主程序命令中文形式
|
||||
- `hello_plugin` - 在收到消息`hello`时回复相应消息
|
||||
- `urlikethisijustsix` - 收到冒犯性消息时回复相应消息
|
||||
|
||||
@@ -189,7 +189,7 @@ Plugin [usage](https://github.com/RockChinQ/QChatGPT/wiki/%E6%8F%92%E4%BB%B6%E4%
|
||||
欢迎提交新的插件
|
||||
|
||||
- [revLibs](https://github.com/RockChinQ/revLibs) - 将ChatGPT网页版接入此项目,关于[官方接口和网页版有什么区别](https://github.com/RockChinQ/QChatGPT/wiki/%E5%AE%98%E6%96%B9%E6%8E%A5%E5%8F%A3%E4%B8%8EChatGPT%E7%BD%91%E9%A1%B5%E7%89%88)
|
||||
- [Switcher](https://github.com/RockChinQ/Switcher) - 支持通过指令切换使用的模型
|
||||
- [Switcher](https://github.com/RockChinQ/Switcher) - 支持通过命令切换使用的模型
|
||||
- [hello_plugin](https://github.com/RockChinQ/hello_plugin) - `hello_plugin` 的储存库形式,插件开发模板
|
||||
- [dominoar/QChatPlugins](https://github.com/dominoar/QchatPlugins) - dominoar编写的诸多新功能插件(语音输出、Ranimg、屏蔽词规则等)
|
||||
- [dominoar/QCP-NovelAi](https://github.com/dominoar/QCP-NovelAi) - NovelAI 故事叙述与绘画
|
||||
|
||||
@@ -78,13 +78,13 @@ openai_config = {
|
||||
# passive:仅当api-key超额时才会切换api-key
|
||||
switch_strategy = "active"
|
||||
|
||||
# [必需] 管理员QQ号,用于接收报错等通知及执行管理员级别指令
|
||||
# [必需] 管理员QQ号,用于接收报错等通知及执行管理员级别命令
|
||||
# 支持多个管理员,可以使用list形式设置,例如:
|
||||
# admin_qq = [12345678, 87654321]
|
||||
admin_qq = 0
|
||||
|
||||
# 情景预设(机器人人格)
|
||||
# 每个会话的预设信息,影响所有会话,无视指令重置
|
||||
# 每个会话的预设信息,影响所有会话,无视命令重置
|
||||
# 可以通过这个字段指定某些情况的回复,可直接用自然语言描述指令
|
||||
# 例如:
|
||||
# default_prompt = "如果我之后想获取帮助,请你说“输入!help获取帮助”"
|
||||
@@ -98,14 +98,14 @@ admin_qq = 0
|
||||
# "en-dict": "我想让你充当英英词典,对于给出的英文单词,你要给出其中文意思以及英文解释,并且给出一个例句,此外不要有其他反馈。",
|
||||
# }
|
||||
#
|
||||
# 在使用期间即可通过指令:
|
||||
# 在使用期间即可通过命令:
|
||||
# !reset [名称]
|
||||
# 来使用指定的情景预设重置会话
|
||||
# 例如:
|
||||
# !reset linux-terminal
|
||||
# 若不指定名称,则使用默认情景预设
|
||||
#
|
||||
# 也可以使用指令:
|
||||
# 也可以使用命令:
|
||||
# !default <名称>
|
||||
# 将指定的情景预设设置为默认情景预设
|
||||
# 例如:
|
||||
@@ -165,7 +165,7 @@ response_rules = {
|
||||
# 符合此规则的消息将不会被响应
|
||||
# 支持消息前缀匹配及正则表达式匹配
|
||||
# 此设置优先级高于response_rules
|
||||
# 用以过滤mirai等其他层级的指令
|
||||
# 用以过滤mirai等其他层级的命令
|
||||
# @see https://github.com/RockChinQ/QChatGPT/issues/165
|
||||
ignore_rules = {
|
||||
"prefix": ["/"],
|
||||
@@ -200,7 +200,7 @@ encourage_sponsor_at_start = True
|
||||
# 每次向OpenAI接口发送对话记录上下文的字符数
|
||||
# 最大不超过(4096 - max_tokens)个字符,max_tokens为下方completion_api_params中的max_tokens
|
||||
# 注意:较大的prompt_submit_length会导致OpenAI账户额度消耗更快
|
||||
prompt_submit_length = 2048
|
||||
prompt_submit_length = 3072
|
||||
|
||||
# 是否在token超限报错时自动重置会话
|
||||
# 可在tips.py中编辑提示语
|
||||
@@ -230,13 +230,6 @@ auto_reset = True
|
||||
# "gpt-3.5-turbo-0301", # legacy
|
||||
#
|
||||
# Completions接口:
|
||||
# "text-davinci-003", # legacy
|
||||
# "text-davinci-002", # legacy
|
||||
# "code-davinci-002", # legacy
|
||||
# "code-cushman-001", # legacy
|
||||
# "text-curie-001", # legacy
|
||||
# "text-babbage-001", # legacy
|
||||
# "text-ada-001", # legacy
|
||||
# "gpt-3.5-turbo-instruct",
|
||||
#
|
||||
# 具体请查看OpenAI的文档: https://beta.openai.com/docs/api-reference/completions/create
|
||||
@@ -369,8 +362,8 @@ rate_limit_strategy = "drop"
|
||||
upgrade_dependencies = False
|
||||
|
||||
# 是否上报统计信息
|
||||
# 用于统计机器人的使用情况,不会收集任何用户信息
|
||||
# 仅上报时间、字数使用量、绘图使用量,其他信息不会上报
|
||||
# 用于统计机器人的使用情况,数据不公开,不会收集任何敏感信息。
|
||||
# 仅实例识别UUID、上报时间、字数使用量、绘图使用量、插件使用情况、用户信息,其他信息不会上报
|
||||
report_usage = True
|
||||
|
||||
# 日志级别
|
||||
|
||||
12
main.py
12
main.py
@@ -175,10 +175,6 @@ async def start_process(first_time_init=False):
|
||||
except Exception as e:
|
||||
print("更新openai库失败:{}, 请忽略或自行更新".format(e))
|
||||
|
||||
# 初始化文字转图片
|
||||
from pkg.utils import text2img
|
||||
text2img.initialize()
|
||||
|
||||
known_exception_caught = False
|
||||
try:
|
||||
try:
|
||||
@@ -186,12 +182,16 @@ async def start_process(first_time_init=False):
|
||||
sh = reset_logging()
|
||||
pkg.utils.context.context['logger_handler'] = sh
|
||||
|
||||
# 初始化文字转图片
|
||||
from pkg.utils import text2img
|
||||
text2img.initialize()
|
||||
|
||||
# 检查是否设置了管理员
|
||||
if cfg['admin_qq'] == 0:
|
||||
# logging.warning("未设置管理员QQ,管理员权限指令及运行告警将无法使用,如需设置请修改config.py中的admin_qq字段")
|
||||
# logging.warning("未设置管理员QQ,管理员权限命令及运行告警将无法使用,如需设置请修改config.py中的admin_qq字段")
|
||||
while True:
|
||||
try:
|
||||
cfg['admin_qq'] = int(input("未设置管理员QQ,管理员权限指令及运行告警将无法使用,请输入管理员QQ号: "))
|
||||
cfg['admin_qq'] = int(input("未设置管理员QQ,管理员权限命令及运行告警将无法使用,请输入管理员QQ号: "))
|
||||
# 写入到文件
|
||||
|
||||
# 读取文件
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"baidu_secret_key": "",
|
||||
"inappropriate_message_tips": "[百度云]请珍惜机器人,当前返回内容不合规",
|
||||
"encourage_sponsor_at_start": true,
|
||||
"prompt_submit_length": 2048,
|
||||
"prompt_submit_length": 3072,
|
||||
"auto_reset": true,
|
||||
"completion_api_params": {
|
||||
"model": "gpt-3.5-turbo",
|
||||
|
||||
@@ -21,7 +21,7 @@ class DataGatherer:
|
||||
|
||||
以key值md5为key,{
|
||||
"text": {
|
||||
"text-davinci-003": 文字量:int,
|
||||
"gpt-3.5-turbo": 文字量:int,
|
||||
},
|
||||
"image": {
|
||||
"256x256": 图片数量:int,
|
||||
@@ -37,27 +37,6 @@ class DataGatherer:
|
||||
except:
|
||||
pass
|
||||
|
||||
def report_to_server(self, subservice_name: str, count: int):
|
||||
"""向中央服务器报告使用量
|
||||
|
||||
只会报告此次请求的使用量,不会报告总量。
|
||||
不包含除版本号、使用类型、使用量以外的任何信息,仅供开发者分析使用情况。
|
||||
"""
|
||||
|
||||
def thread_func():
|
||||
|
||||
try:
|
||||
config = context.get_config_manager().data
|
||||
if not config['report_usage']:
|
||||
return
|
||||
res = requests.get("http://reports.rockchin.top:18989/usage?service_name=qchatgpt.{}&version={}&count={}&msg_source={}".format(subservice_name, self.version_str, count, config['msg_source_adapter']))
|
||||
if res.status_code != 200 or res.text != "ok":
|
||||
logging.warning("report to server failed, status_code: {}, text: {}".format(res.status_code, res.text))
|
||||
except:
|
||||
return
|
||||
|
||||
threading.Thread(target=thread_func).start()
|
||||
|
||||
def get_usage(self, key_md5):
|
||||
return self.usage[key_md5] if key_md5 in self.usage else {}
|
||||
|
||||
@@ -79,8 +58,6 @@ class DataGatherer:
|
||||
self.usage[key_md5]["text"][model] += length
|
||||
self.dump_to_db()
|
||||
|
||||
self.report_to_server("text", length)
|
||||
|
||||
def report_image_model_usage(self, size):
|
||||
"""调用方报告图片模型请求图片使用量"""
|
||||
|
||||
@@ -98,8 +75,6 @@ class DataGatherer:
|
||||
self.usage[key_md5]["image"][size] += 1
|
||||
self.dump_to_db()
|
||||
|
||||
self.report_to_server("image", 1)
|
||||
|
||||
def get_text_length_of_key(self, key):
|
||||
"""获取指定api-key (明文) 的文字总使用量(本地记录)"""
|
||||
key_md5 = hashlib.md5(key.encode('utf-8')).hexdigest()
|
||||
|
||||
@@ -8,7 +8,7 @@ from ..utils import context
|
||||
# __current__ = "default"
|
||||
# """当前默认使用的情景预设的名称
|
||||
|
||||
# 由管理员使用`!default <名称>`指令切换
|
||||
# 由管理员使用`!default <名称>`命令切换
|
||||
# """
|
||||
|
||||
# __prompts_from_files__ = {}
|
||||
|
||||
@@ -32,16 +32,9 @@ class KeysManager:
|
||||
return hashlib.md5(self.using_key.encode('utf-8')).hexdigest()
|
||||
|
||||
def __init__(self, api_key):
|
||||
|
||||
if type(api_key) is dict:
|
||||
self.api_key = api_key
|
||||
elif type(api_key) is str:
|
||||
self.api_key = {
|
||||
"default": api_key
|
||||
}
|
||||
elif type(api_key) is list:
|
||||
for i in range(len(api_key)):
|
||||
self.api_key[str(i)] = api_key[i]
|
||||
|
||||
assert type(api_key) == dict
|
||||
self.api_key = api_key
|
||||
# 从usage中删除未加载的api-key的记录
|
||||
# 不删了,也许会运行时添加曾经有记录的api-key
|
||||
|
||||
|
||||
@@ -13,13 +13,6 @@ from ..openai.api import completion as api_completion
|
||||
from ..openai.api import chat_completion as api_chat_completion
|
||||
|
||||
COMPLETION_MODELS = {
|
||||
"text-davinci-003", # legacy
|
||||
"text-davinci-002", # legacy
|
||||
"code-davinci-002", # legacy
|
||||
"code-cushman-001", # legacy
|
||||
"text-curie-001", # legacy
|
||||
"text-babbage-001", # legacy
|
||||
"text-ada-001", # legacy
|
||||
"gpt-3.5-turbo-instruct",
|
||||
}
|
||||
|
||||
|
||||
@@ -25,34 +25,6 @@ class SessionOfflineStatus:
|
||||
EXPLICITLY_CLOSED = 'explicitly_closed'
|
||||
|
||||
|
||||
# 重置session.prompt
|
||||
def reset_session_prompt(session_name, prompt):
|
||||
# 备份原始数据
|
||||
bak_path = 'logs/{}-{}.bak'.format(
|
||||
session_name,
|
||||
time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
)
|
||||
f = open(bak_path, 'w+')
|
||||
f.write(prompt)
|
||||
f.close()
|
||||
# 生成新数据
|
||||
config = context.get_config_manager().data
|
||||
prompt = [
|
||||
{
|
||||
'role': 'system',
|
||||
'content': config['default_prompt']['default'] if type(config['default_prompt']) == dict else config['default_prompt']
|
||||
}
|
||||
]
|
||||
# 警告
|
||||
logging.warning(
|
||||
"""
|
||||
用户[{}]的数据已被重置,有可能是因为数据版本过旧或存储错误
|
||||
原始数据将备份在:
|
||||
{}""".format(session_name, bak_path)
|
||||
) # 为保证多行文本格式正确故无缩进
|
||||
return prompt
|
||||
|
||||
|
||||
# 从数据加载session
|
||||
def load_sessions():
|
||||
"""从数据库加载sessions"""
|
||||
@@ -70,12 +42,10 @@ def load_sessions():
|
||||
temp_session.name = session_name
|
||||
temp_session.create_timestamp = session_data[session_name]['create_timestamp']
|
||||
temp_session.last_interact_timestamp = session_data[session_name]['last_interact_timestamp']
|
||||
try:
|
||||
temp_session.prompt = json.loads(session_data[session_name]['prompt'])
|
||||
temp_session.token_counts = json.loads(session_data[session_name]['token_counts'])
|
||||
except Exception:
|
||||
temp_session.prompt = reset_session_prompt(session_name, session_data[session_name]['prompt'])
|
||||
temp_session.persistence()
|
||||
|
||||
temp_session.prompt = json.loads(session_data[session_name]['prompt'])
|
||||
temp_session.token_counts = json.loads(session_data[session_name]['token_counts'])
|
||||
|
||||
temp_session.default_prompt = json.loads(session_data[session_name]['default_prompt']) if \
|
||||
session_data[session_name]['default_prompt'] else []
|
||||
|
||||
@@ -493,12 +463,10 @@ class Session:
|
||||
|
||||
self.create_timestamp = last_one['create_timestamp']
|
||||
self.last_interact_timestamp = last_one['last_interact_timestamp']
|
||||
try:
|
||||
self.prompt = json.loads(last_one['prompt'])
|
||||
self.token_counts = json.loads(last_one['token_counts'])
|
||||
except json.decoder.JSONDecodeError:
|
||||
self.prompt = reset_session_prompt(self.name, last_one['prompt'])
|
||||
self.persistence()
|
||||
|
||||
self.prompt = json.loads(last_one['prompt'])
|
||||
self.token_counts = json.loads(last_one['token_counts'])
|
||||
|
||||
self.default_prompt = json.loads(last_one['default_prompt']) if last_one['default_prompt'] else []
|
||||
|
||||
self.just_switched_to_exist_session = True
|
||||
@@ -514,12 +482,10 @@ class Session:
|
||||
|
||||
self.create_timestamp = next_one['create_timestamp']
|
||||
self.last_interact_timestamp = next_one['last_interact_timestamp']
|
||||
try:
|
||||
self.prompt = json.loads(next_one['prompt'])
|
||||
self.token_counts = json.loads(next_one['token_counts'])
|
||||
except json.decoder.JSONDecodeError:
|
||||
self.prompt = reset_session_prompt(self.name, next_one['prompt'])
|
||||
self.persistence()
|
||||
|
||||
self.prompt = json.loads(next_one['prompt'])
|
||||
self.token_counts = json.loads(next_one['token_counts'])
|
||||
|
||||
self.default_prompt = json.loads(next_one['default_prompt']) if next_one['default_prompt'] else []
|
||||
|
||||
self.just_switched_to_exist_session = True
|
||||
|
||||
@@ -576,7 +576,3 @@ class PluginHost:
|
||||
)
|
||||
|
||||
return event_context
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
@@ -35,18 +35,18 @@ PersonNormalMessageReceived = "person_normal_message_received"
|
||||
"""
|
||||
|
||||
PersonCommandSent = "person_command_sent"
|
||||
"""判断为应该处理的私聊指令时触发
|
||||
"""判断为应该处理的私聊命令时触发
|
||||
kwargs:
|
||||
launcher_type: str 发起对象类型(group/person)
|
||||
launcher_id: int 发起对象ID(群号/QQ号)
|
||||
sender_id: int 发送者ID(QQ号)
|
||||
command: str 指令
|
||||
command: str 命令
|
||||
params: list[str] 参数列表
|
||||
text_message: str 完整指令文本
|
||||
text_message: str 完整命令文本
|
||||
is_admin: bool 是否为管理员
|
||||
|
||||
returns (optional):
|
||||
alter: str 修改后的完整指令文本
|
||||
alter: str 修改后的完整命令文本
|
||||
reply: list 回复消息组件列表
|
||||
"""
|
||||
|
||||
@@ -64,18 +64,18 @@ GroupNormalMessageReceived = "group_normal_message_received"
|
||||
"""
|
||||
|
||||
GroupCommandSent = "group_command_sent"
|
||||
"""判断为应该处理的群聊指令时触发
|
||||
"""判断为应该处理的群聊命令时触发
|
||||
kwargs:
|
||||
launcher_type: str 发起对象类型(group/person)
|
||||
launcher_id: int 发起对象ID(群号/QQ号)
|
||||
sender_id: int 发送者ID(QQ号)
|
||||
command: str 指令
|
||||
command: str 命令
|
||||
params: list[str] 参数列表
|
||||
text_message: str 完整指令文本
|
||||
text_message: str 完整命令文本
|
||||
is_admin: bool 是否为管理员
|
||||
|
||||
returns (optional):
|
||||
alter: str 修改后的完整指令文本
|
||||
alter: str 修改后的完整命令文本
|
||||
reply: list 回复消息组件列表
|
||||
"""
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ __tree_index__: dict[str, list] = {}
|
||||
|
||||
结构:
|
||||
{
|
||||
'pkg.qqbot.cmds.cmd1.CommandCmd1': 'cmd1', # 顶级指令
|
||||
'pkg.qqbot.cmds.cmd1.CommandCmd1': 'cmd1', # 顶级命令
|
||||
'pkg.qqbot.cmds.cmd1.CommandCmd1_1': 'cmd1.cmd1-1', # 类名: 节点路径
|
||||
'pkg.qqbot.cmds.cmd2.CommandCmd2': 'cmd2',
|
||||
'pkg.qqbot.cmds.cmd2.CommandCmd2_1': 'cmd2.cmd2-1',
|
||||
@@ -83,79 +83,79 @@ __tree_index__: dict[str, list] = {}
|
||||
class Context:
|
||||
"""命令执行上下文"""
|
||||
command: str
|
||||
"""顶级指令文本"""
|
||||
"""顶级命令文本"""
|
||||
|
||||
crt_command: str
|
||||
"""当前子指令文本"""
|
||||
"""当前子命令文本"""
|
||||
|
||||
params: list
|
||||
"""完整参数列表"""
|
||||
|
||||
crt_params: list
|
||||
"""当前子指令参数列表"""
|
||||
"""当前子命令参数列表"""
|
||||
|
||||
session_name: str
|
||||
"""会话名"""
|
||||
|
||||
text_message: str
|
||||
"""指令完整文本"""
|
||||
"""命令完整文本"""
|
||||
|
||||
launcher_type: str
|
||||
"""指令发起者类型"""
|
||||
"""命令发起者类型"""
|
||||
|
||||
launcher_id: int
|
||||
"""指令发起者ID"""
|
||||
"""命令发起者ID"""
|
||||
|
||||
sender_id: int
|
||||
"""指令发送者ID"""
|
||||
"""命令发送者ID"""
|
||||
|
||||
is_admin: bool
|
||||
"""[过时]指令发送者是否为管理员"""
|
||||
"""[过时]命令发送者是否为管理员"""
|
||||
|
||||
privilege: int
|
||||
"""指令发送者权限等级"""
|
||||
"""命令发送者权限等级"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.__dict__.update(kwargs)
|
||||
|
||||
|
||||
class AbstractCommandNode:
|
||||
"""指令抽象类"""
|
||||
"""命令抽象类"""
|
||||
|
||||
parent: type
|
||||
"""父指令类"""
|
||||
"""父命令类"""
|
||||
|
||||
name: str
|
||||
"""指令名"""
|
||||
"""命令名"""
|
||||
|
||||
description: str
|
||||
"""指令描述"""
|
||||
"""命令描述"""
|
||||
|
||||
usage: str
|
||||
"""指令用法"""
|
||||
"""命令用法"""
|
||||
|
||||
aliases: list[str]
|
||||
"""指令别名"""
|
||||
"""命令别名"""
|
||||
|
||||
privilege: int
|
||||
"""指令权限等级, 权限大于等于此值的用户才能执行指令"""
|
||||
"""命令权限等级, 权限大于等于此值的用户才能执行命令"""
|
||||
|
||||
@classmethod
|
||||
def process(cls, ctx: Context) -> tuple[bool, list]:
|
||||
"""指令处理函数
|
||||
"""命令处理函数
|
||||
|
||||
:param ctx: 指令执行上下文
|
||||
:param ctx: 命令执行上下文
|
||||
|
||||
:return: (是否执行, 回复列表(若执行))
|
||||
|
||||
若未执行,将自动以下一个参数查找并执行子指令
|
||||
若未执行,将自动以下一个参数查找并执行子命令
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def help(cls) -> str:
|
||||
"""获取指令帮助信息"""
|
||||
return '指令: {}\n描述: {}\n用法: \n{}\n别名: {}\n权限: {}'.format(
|
||||
"""获取命令帮助信息"""
|
||||
return '命令: {}\n描述: {}\n用法: \n{}\n别名: {}\n权限: {}'.format(
|
||||
cls.name,
|
||||
cls.description,
|
||||
cls.usage,
|
||||
@@ -172,11 +172,11 @@ class AbstractCommandNode:
|
||||
aliases: list[str] = None,
|
||||
privilege: int = 0
|
||||
):
|
||||
"""注册指令
|
||||
"""注册命令
|
||||
|
||||
:param cls: 指令类
|
||||
:param name: 指令名
|
||||
:param parent: 父指令类
|
||||
:param cls: 命令类
|
||||
:param name: 命令名
|
||||
:param parent: 父命令类
|
||||
"""
|
||||
global __command_list__, __tree_index__
|
||||
|
||||
@@ -191,7 +191,7 @@ class AbstractCommandNode:
|
||||
logging.debug("cls: {}, name: {}, parent: {}".format(cls, name, parent))
|
||||
|
||||
if parent is None:
|
||||
# 顶级指令注册
|
||||
# 顶级命令注册
|
||||
__command_list__[name] = {
|
||||
'description': cls.description,
|
||||
'usage': cls.usage,
|
||||
@@ -208,9 +208,9 @@ class AbstractCommandNode:
|
||||
path = __tree_index__[parent.__module__ + '.' + parent.__name__]
|
||||
|
||||
parent_node = __command_list__[path]
|
||||
# 链接父子指令
|
||||
# 链接父子命令
|
||||
__command_list__[path]['sub'].append(name)
|
||||
# 注册子指令
|
||||
# 注册子命令
|
||||
__command_list__[path + '.' + name] = {
|
||||
'description': cls.description,
|
||||
'usage': cls.usage,
|
||||
@@ -229,18 +229,18 @@ class AbstractCommandNode:
|
||||
|
||||
|
||||
class CommandPrivilegeError(Exception):
|
||||
"""指令权限不足或不存在异常"""
|
||||
"""命令权限不足或不存在异常"""
|
||||
pass
|
||||
|
||||
|
||||
# 传入Context对象,广搜命令树,返回执行结果
|
||||
# 若命令被处理,返回reply列表
|
||||
# 若命令未被处理,继续执行下一级指令
|
||||
# 若命令未被处理,继续执行下一级命令
|
||||
# 若命令不存在,报异常
|
||||
def execute(context: Context) -> list:
|
||||
"""执行指令
|
||||
"""执行命令
|
||||
|
||||
:param ctx: 指令执行上下文
|
||||
:param ctx: 命令执行上下文
|
||||
|
||||
:return: 回复列表
|
||||
"""
|
||||
@@ -249,7 +249,7 @@ def execute(context: Context) -> list:
|
||||
# 拷贝ctx
|
||||
ctx: Context = copy.deepcopy(context)
|
||||
|
||||
# 从树取出顶级指令
|
||||
# 从树取出顶级命令
|
||||
node = __command_list__
|
||||
|
||||
path = ctx.command
|
||||
@@ -257,7 +257,7 @@ def execute(context: Context) -> list:
|
||||
while True:
|
||||
try:
|
||||
node = __command_list__[path]
|
||||
logging.debug('执行指令: {}'.format(path))
|
||||
logging.debug('执行命令: {}'.format(path))
|
||||
|
||||
# 检查权限
|
||||
if ctx.privilege < node['privilege']:
|
||||
@@ -278,7 +278,7 @@ def execute(context: Context) -> list:
|
||||
|
||||
|
||||
def register_all():
|
||||
"""启动时调用此函数注册所有指令
|
||||
"""启动时调用此函数注册所有命令
|
||||
|
||||
递归处理pkg.qqbot.cmds包下及其子包下所有模块的所有继承于AbstractCommand的类
|
||||
"""
|
||||
@@ -304,7 +304,7 @@ def register_all():
|
||||
else:
|
||||
m = __import__(module.__name__ + '.' + item.name, fromlist=[''])
|
||||
# for name, cls in inspect.getmembers(m, inspect.isclass):
|
||||
# # 检查是否为指令类
|
||||
# # 检查是否为命令类
|
||||
# if cls.__module__ == m.__name__ and issubclass(cls, AbstractCommandNode) and cls != AbstractCommandNode:
|
||||
# cls.register(cls, cls.name, cls.parent)
|
||||
|
||||
@@ -313,7 +313,7 @@ def register_all():
|
||||
|
||||
|
||||
def apply_privileges():
|
||||
"""读取cmdpriv.json并应用指令权限"""
|
||||
"""读取cmdpriv.json并应用命令权限"""
|
||||
# 读取内容
|
||||
json_str = ""
|
||||
with open('cmdpriv.json', 'r', encoding="utf-8") as f:
|
||||
|
||||
@@ -38,9 +38,6 @@ class PluginCommand(aamgr.AbstractCommandNode):
|
||||
|
||||
reply = [reply_str]
|
||||
return True, reply
|
||||
elif ctx.params[0].startswith("http"):
|
||||
reply = ["[bot]err: 此命令已弃用,请使用 !plugin get <插件仓库地址> 进行安装"]
|
||||
return True, reply
|
||||
else:
|
||||
return False, []
|
||||
|
||||
@@ -68,7 +65,7 @@ class PluginGetCommand(aamgr.AbstractCommandNode):
|
||||
def closure():
|
||||
try:
|
||||
plugin_host.install_plugin(ctx.crt_params[0])
|
||||
pkg.utils.context.get_qqbot_manager().notify_admin("插件安装成功,请发送 !reload 指令重载插件")
|
||||
pkg.utils.context.get_qqbot_manager().notify_admin("插件安装成功,请发送 !reload 命令重载插件")
|
||||
except Exception as e:
|
||||
logging.error("插件安装失败:{}".format(e))
|
||||
pkg.utils.context.get_qqbot_manager().notify_admin("插件安装失败:{}".format(e))
|
||||
@@ -149,7 +146,7 @@ class PluginDelCommand(aamgr.AbstractCommandNode):
|
||||
unin_path = plugin_host.uninstall_plugin(plugin_name)
|
||||
reply = ["[bot]已删除插件: {} ({}), 请发送 !reload 重载插件".format(plugin_name, unin_path)]
|
||||
else:
|
||||
reply = ["[bot]err:未找到插件: {}, 请使用!plugin指令查看插件列表".format(plugin_name)]
|
||||
reply = ["[bot]err:未找到插件: {}, 请使用!plugin命令查看插件列表".format(plugin_name)]
|
||||
|
||||
return True, reply
|
||||
|
||||
@@ -195,7 +192,7 @@ class PluginOnOffCommand(aamgr.AbstractCommandNode):
|
||||
plugin_switch.dump_switch()
|
||||
reply = ["[bot]已{}插件: {}".format("启用" if new_status else "禁用", plugin_name)]
|
||||
else:
|
||||
reply = ["[bot]err:未找到插件: {}, 请使用!plugin指令查看插件列表".format(plugin_name)]
|
||||
reply = ["[bot]err:未找到插件: {}, 请使用!plugin命令查看插件列表".format(plugin_name)]
|
||||
|
||||
return True, reply
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@ class DefaultCommand(aamgr.AbstractCommandNode):
|
||||
reply_str += "\n当前默认情景预设:{}\n".format(dprompt.mode_inst().get_using_name())
|
||||
reply_str += "请使用 !default set <情景预设名称> 来设置默认情景预设"
|
||||
reply = [reply_str]
|
||||
elif params[0] != "set":
|
||||
reply = ["[bot]err: 已弃用,请使用!default set <情景预设名称> 来设置默认情景预设"]
|
||||
else:
|
||||
return False, []
|
||||
|
||||
@@ -69,7 +67,5 @@ class DefaultSetCommand(aamgr.AbstractCommandNode):
|
||||
reply = ["[bot]已设置默认情景预设为:{}".format(full_name)]
|
||||
except Exception as e:
|
||||
reply = ["[bot]err: {}".format(e)]
|
||||
else:
|
||||
reply = ["[bot]err: 仅管理员可设置默认情景预设"]
|
||||
|
||||
return True, reply
|
||||
|
||||
@@ -31,7 +31,7 @@ class ListCommand(aamgr.AbstractCommandNode):
|
||||
|
||||
results = pkg.openai.session.get_session(session_name).list_history(page=page)
|
||||
if len(results) == 0:
|
||||
reply = ["[bot]第{}页没有历史会话".format(page)]
|
||||
reply_str = "[bot]第{}页没有历史会话".format(page)
|
||||
else:
|
||||
reply_str = "[bot]历史会话 第{}页:\n".format(page)
|
||||
current = -1
|
||||
@@ -39,12 +39,9 @@ class ListCommand(aamgr.AbstractCommandNode):
|
||||
# 时间(使用create_timestamp转换) 序号 部分内容
|
||||
datetime_obj = datetime.datetime.fromtimestamp(results[i]['create_timestamp'])
|
||||
msg = ""
|
||||
try:
|
||||
msg = json.loads(results[i]['prompt'])
|
||||
except json.decoder.JSONDecodeError:
|
||||
msg = pkg.openai.session.reset_session_prompt(session_name, results[i]['prompt'])
|
||||
# 持久化
|
||||
pkg.openai.session.get_session(session_name).persistence()
|
||||
|
||||
msg = json.loads(results[i]['prompt'])
|
||||
|
||||
if len(msg) >= 2:
|
||||
reply_str += "#{} 创建:{} {}\n".format(i + page * 10,
|
||||
datetime_obj.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
|
||||
@@ -15,7 +15,7 @@ class ResendCommand(aamgr.AbstractCommandNode):
|
||||
from ....openai import session as openai_session
|
||||
from ....utils import context
|
||||
from ....qqbot import message
|
||||
import config
|
||||
|
||||
session_name = ctx.session_name
|
||||
reply = []
|
||||
|
||||
@@ -24,6 +24,8 @@ class ResendCommand(aamgr.AbstractCommandNode):
|
||||
|
||||
mgr = context.get_qqbot_manager()
|
||||
|
||||
config = context.get_config_manager().data
|
||||
|
||||
reply = message.process_normal_message(to_send, mgr, config,
|
||||
ctx.launcher_type, ctx.launcher_id,
|
||||
ctx.sender_id)
|
||||
|
||||
@@ -68,8 +68,10 @@ def config_operation(cmd, params):
|
||||
else:
|
||||
cfg_mgr.data[cfg_entry_path[0]] = cfg_value
|
||||
reply = ["[bot]配置项{}修改成功".format(cfg_name)]
|
||||
except AttributeError:
|
||||
except KeyError:
|
||||
reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
||||
except NameError:
|
||||
reply = ["[bot]err:值{}不合法(字符串需要使用双引号包裹)".format(cfg_value)]
|
||||
except ValueError:
|
||||
reply = ["[bot]err:未找到配置项 {}".format(cfg_name)]
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ from .. import aamgr
|
||||
@aamgr.AbstractCommandNode.register(
|
||||
parent=None,
|
||||
name="cmd",
|
||||
description="显示指令列表",
|
||||
usage="!cmd\n!cmd <指令名称>",
|
||||
description="显示命令列表",
|
||||
usage="!cmd\n!cmd <命令名称>",
|
||||
aliases=[],
|
||||
privilege=1
|
||||
)
|
||||
@@ -17,15 +17,15 @@ class CmdCommand(aamgr.AbstractCommandNode):
|
||||
reply = []
|
||||
|
||||
if len(ctx.params) == 0:
|
||||
reply_str = "[bot]当前所有指令:\n\n"
|
||||
reply_str = "[bot]当前所有命令:\n\n"
|
||||
|
||||
# 遍历顶级指令
|
||||
# 遍历顶级命令
|
||||
for key in command_list:
|
||||
command = command_list[key]
|
||||
if command['parent'] is None:
|
||||
reply_str += "!{} - {}\n".format(key, command['description'])
|
||||
|
||||
reply_str += "\n请使用 !cmd <指令名称> 来查看指令的详细信息"
|
||||
reply_str += "\n请使用 !cmd <命令名称> 来查看命令的详细信息"
|
||||
|
||||
reply = [reply_str]
|
||||
else:
|
||||
@@ -33,7 +33,7 @@ class CmdCommand(aamgr.AbstractCommandNode):
|
||||
if command_name in command_list:
|
||||
reply = [command_list[command_name]['cls'].help()]
|
||||
else:
|
||||
reply = ["[bot]指令 {} 不存在".format(command_name)]
|
||||
reply = ["[bot]命令 {} 不存在".format(command_name)]
|
||||
|
||||
return True, reply
|
||||
|
||||
@@ -13,7 +13,7 @@ class HelpCommand(aamgr.AbstractCommandNode):
|
||||
@classmethod
|
||||
def process(cls, ctx: aamgr.Context) -> tuple[bool, list]:
|
||||
import tips
|
||||
reply = ["[bot] "+tips.help_message + "\n请输入 !cmd 查看指令列表"]
|
||||
reply = ["[bot] "+tips.help_message + "\n请输入 !cmd 查看命令列表"]
|
||||
|
||||
# 警告config.help_message过时
|
||||
import config
|
||||
|
||||
@@ -13,7 +13,6 @@ class UsageCommand(aamgr.AbstractCommandNode):
|
||||
@classmethod
|
||||
def process(cls, ctx: aamgr.Context) -> tuple[bool, list]:
|
||||
import config
|
||||
import pkg.utils.credit as credit
|
||||
import pkg.utils.context
|
||||
|
||||
reply = []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 指令处理模块
|
||||
# 命令处理模块
|
||||
import logging
|
||||
|
||||
from ..qqbot.cmds import aamgr as cmdmgr
|
||||
@@ -9,7 +9,7 @@ def process_command(session_name: str, text_message: str, mgr, config: dict,
|
||||
reply = []
|
||||
try:
|
||||
logging.info(
|
||||
"[{}]发起指令:{}".format(session_name, text_message[:min(20, len(text_message))] + (
|
||||
"[{}]发起命令:{}".format(session_name, text_message[:min(20, len(text_message))] + (
|
||||
"..." if len(text_message) > 20 else "")))
|
||||
|
||||
cmd = text_message[1:].strip().split(' ')[0]
|
||||
@@ -42,7 +42,7 @@ def process_command(session_name: str, text_message: str, mgr, config: dict,
|
||||
|
||||
return reply
|
||||
except Exception as e:
|
||||
mgr.notify_admin("{}指令执行失败:{}".format(session_name, e))
|
||||
mgr.notify_admin("{}命令执行失败:{}".format(session_name, e))
|
||||
logging.exception(e)
|
||||
reply = ["[bot]err:{}".format(e)]
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ def process_message(launcher_type: str, launcher_id: int, text_message: str, mes
|
||||
processing.append(session_name)
|
||||
try:
|
||||
msg_type = ''
|
||||
if text_message.startswith('!') or text_message.startswith("!"): # 指令
|
||||
if text_message.startswith('!') or text_message.startswith("!"): # 命令
|
||||
msg_type = 'command'
|
||||
# 触发插件事件
|
||||
args = {
|
||||
|
||||
@@ -17,14 +17,10 @@ def get_limitation(session_name: str) -> int:
|
||||
"""获取会话的限制次数"""
|
||||
config = context.get_config_manager().data
|
||||
|
||||
if type(config['rate_limitation']) == dict:
|
||||
# 如果被指定了
|
||||
if session_name in config['rate_limitation']:
|
||||
return config['rate_limitation'][session_name]
|
||||
else:
|
||||
return config['rate_limitation']["default"]
|
||||
elif type(config['rate_limitation']) == int:
|
||||
return config['rate_limitation']
|
||||
if session_name in config['rate_limitation']:
|
||||
return config['rate_limitation'][session_name]
|
||||
else:
|
||||
return config['rate_limitation']["default"]
|
||||
|
||||
|
||||
def add_usage(session_name: str):
|
||||
|
||||
@@ -182,7 +182,8 @@ class NakuruProjectAdapter(adapter_model.MessageSourceAdapter):
|
||||
headers={
|
||||
'Authorization': "Bearer " + config['nakuru_config']['token'] if 'token' in config['nakuru_config']else ""
|
||||
},
|
||||
timeout=5
|
||||
timeout=5,
|
||||
proxies=None
|
||||
)
|
||||
if resp.status_code == 403:
|
||||
logging.error("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .. import apigroup
|
||||
from ... import context
|
||||
|
||||
|
||||
class V2MainDataAPI(apigroup.APIGroup):
|
||||
@@ -9,6 +10,12 @@ class V2MainDataAPI(apigroup.APIGroup):
|
||||
def __init__(self, prefix: str):
|
||||
super().__init__(prefix+"/main")
|
||||
|
||||
def do(self, *args, **kwargs):
|
||||
config = context.get_config_manager().data
|
||||
if not config['report_usage']:
|
||||
return None
|
||||
return super().do(*args, **kwargs)
|
||||
|
||||
def post_update_record(
|
||||
self,
|
||||
spent_seconds: int,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .. import apigroup
|
||||
from ... import context
|
||||
|
||||
|
||||
class V2PluginDataAPI(apigroup.APIGroup):
|
||||
@@ -9,6 +10,12 @@ class V2PluginDataAPI(apigroup.APIGroup):
|
||||
def __init__(self, prefix: str):
|
||||
super().__init__(prefix+"/plugin")
|
||||
|
||||
def do(self, *args, **kwargs):
|
||||
config = context.get_config_manager().data
|
||||
if not config['report_usage']:
|
||||
return None
|
||||
return super().do(*args, **kwargs)
|
||||
|
||||
def post_install_record(
|
||||
self,
|
||||
plugin: dict
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .. import apigroup
|
||||
from ... import context
|
||||
|
||||
|
||||
class V2UsageDataAPI(apigroup.APIGroup):
|
||||
@@ -8,6 +9,12 @@ class V2UsageDataAPI(apigroup.APIGroup):
|
||||
|
||||
def __init__(self, prefix: str):
|
||||
super().__init__(prefix+"/usage")
|
||||
|
||||
def do(self, *args, **kwargs):
|
||||
config = context.get_config_manager().data
|
||||
if not config['report_usage']:
|
||||
return None
|
||||
return super().do(*args, **kwargs)
|
||||
|
||||
def post_query_record(
|
||||
self,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,19 +0,0 @@
|
||||
# OpenAI账号免费额度剩余查询
|
||||
import requests
|
||||
|
||||
def fetch_credit_data(api_key: str, http_proxy: str) -> dict:
|
||||
"""OpenAI账号免费额度剩余查询"""
|
||||
proxies = {
|
||||
"http":http_proxy,
|
||||
"https":http_proxy
|
||||
} if http_proxy is not None else None
|
||||
|
||||
resp = requests.get(
|
||||
url="https://api.openai.com/dashboard/billing/credit_grants",
|
||||
headers={
|
||||
"Authorization": "Bearer {}".format(api_key),
|
||||
},
|
||||
proxies=proxies
|
||||
)
|
||||
|
||||
return resp.json()
|
||||
@@ -28,10 +28,6 @@ def init_runtime_log_file():
|
||||
if not os.path.exists("logs"):
|
||||
os.mkdir("logs")
|
||||
|
||||
# 检查本目录是否有qchatgpt.log,若有,移动到logs目录
|
||||
if os.path.exists("qchatgpt.log"):
|
||||
shutil.move("qchatgpt.log", "logs/qchatgpt.legacy.log")
|
||||
|
||||
log_file_name = "logs/qchatgpt-%s.log" % time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ def reload_all(notify=True):
|
||||
import main
|
||||
main.stop()
|
||||
|
||||
# 删除所有已注册的指令
|
||||
# 删除所有已注册的命令
|
||||
import pkg.qqbot.cmds.aamgr as cmdsmgr
|
||||
cmdsmgr.__command_list__ = {}
|
||||
cmdsmgr.__tree_index__ = {}
|
||||
|
||||
@@ -11,6 +11,8 @@ from ..utils import context
|
||||
text_render_font: ImageFont = None
|
||||
|
||||
def initialize():
|
||||
global text_render_font
|
||||
logging.debug("初始化文字转图片模块...")
|
||||
config = context.get_config_manager().data
|
||||
|
||||
if config['blob_message_strategy'] == "image": # 仅在启用了image时才加载字体
|
||||
@@ -37,6 +39,8 @@ def initialize():
|
||||
traceback.print_exc()
|
||||
logging.error("加载字体文件失败({}),更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。".format(use_font))
|
||||
config['blob_message_strategy'] = "forward"
|
||||
|
||||
logging.debug("字体文件加载完成。")
|
||||
|
||||
|
||||
def indexNumber(path=''):
|
||||
@@ -119,6 +123,8 @@ def compress_image(infile, outfile='', kb=100, step=20, quality=90):
|
||||
def text_to_image(text_str: str, save_as="temp.png", width=800):
|
||||
global text_render_font
|
||||
|
||||
logging.debug("正在将文本转换为图片...")
|
||||
|
||||
text_str = text_str.replace("\t", " ")
|
||||
|
||||
# 分行
|
||||
@@ -128,9 +134,13 @@ def text_to_image(text_str: str, save_as="temp.png", width=800):
|
||||
final_lines = []
|
||||
|
||||
text_width = width-80
|
||||
|
||||
logging.debug("lines: {}, text_width: {}".format(lines, text_width))
|
||||
for line in lines:
|
||||
logging.debug(type(text_render_font))
|
||||
# 如果长了就分割
|
||||
line_width = text_render_font.getlength(line)
|
||||
logging.debug("line_width: {}".format(line_width))
|
||||
if line_width < text_width:
|
||||
final_lines.append(line)
|
||||
continue
|
||||
@@ -160,7 +170,7 @@ def text_to_image(text_str: str, save_as="temp.png", width=800):
|
||||
img = Image.new('RGBA', (width, max(280, len(final_lines) * 35 + 65)), (255, 255, 255, 255))
|
||||
draw = ImageDraw.Draw(img, mode='RGBA')
|
||||
|
||||
|
||||
logging.debug("正在绘制图片...")
|
||||
# 绘制正文
|
||||
line_number = 0
|
||||
offset_x = 20
|
||||
@@ -192,7 +202,7 @@ def text_to_image(text_str: str, save_as="temp.png", width=800):
|
||||
|
||||
line_number += 1
|
||||
|
||||
|
||||
logging.debug("正在保存图片...")
|
||||
img.save(save_as)
|
||||
|
||||
return save_as
|
||||
|
||||
@@ -25,18 +25,6 @@ def check_dulwich_closure():
|
||||
raise Exception("dulwich模块未安装,请查看 https://github.com/RockChinQ/QChatGPT/issues/77")
|
||||
|
||||
|
||||
def pull_latest(repo_path: str) -> bool:
|
||||
"""拉取最新代码"""
|
||||
check_dulwich_closure()
|
||||
|
||||
from dulwich import porcelain
|
||||
|
||||
repo = porcelain.open_repo(repo_path)
|
||||
porcelain.pull(repo)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def is_newer(new_tag: str, old_tag: str):
|
||||
"""判断版本是否更新,忽略第四位版本和第一位版本"""
|
||||
if new_tag == old_tag:
|
||||
@@ -254,35 +242,6 @@ def get_current_version_info() -> str:
|
||||
return "未知版本"
|
||||
|
||||
|
||||
def get_commit_id_and_time_and_msg() -> str:
|
||||
"""获取当前提交id和时间和提交信息"""
|
||||
check_dulwich_closure()
|
||||
|
||||
from dulwich import porcelain
|
||||
|
||||
repo = porcelain.open_repo('.')
|
||||
|
||||
for entry in repo.get_walker():
|
||||
tz = datetime.timezone(datetime.timedelta(hours=entry.commit.commit_timezone // 3600))
|
||||
dt = datetime.datetime.fromtimestamp(entry.commit.commit_time, tz)
|
||||
return str(entry.commit.id)[2:9] + " " + dt.strftime('%Y-%m-%d %H:%M:%S') + " [" + str(entry.commit.message, encoding="utf-8").strip()+"]"
|
||||
|
||||
|
||||
def get_current_commit_id() -> str:
|
||||
"""检查是否有新版本"""
|
||||
check_dulwich_closure()
|
||||
|
||||
from dulwich import porcelain
|
||||
|
||||
repo = porcelain.open_repo('.')
|
||||
current_commit_id = ""
|
||||
for entry in repo.get_walker():
|
||||
current_commit_id = str(entry.commit.id)[2:-1]
|
||||
break
|
||||
|
||||
return current_commit_id
|
||||
|
||||
|
||||
def is_new_version_available() -> bool:
|
||||
"""检查是否有新版本"""
|
||||
# 从github获取release列表
|
||||
|
||||
@@ -14,7 +14,7 @@ rate_limit_drop_tip = "本分钟对话次数超过限速次数,此对话被丢
|
||||
# 若设置为空字符串,则不发送提示信息
|
||||
message_drop_tip = "[bot]当前有一条消息正在处理,请等待处理完成"
|
||||
|
||||
# 指令!help帮助消息
|
||||
# 命令 !help帮助消息
|
||||
help_message = """此机器人通过调用大型语言模型生成回复,不具有情感。
|
||||
你可以用自然语言与其交流,回复的消息中[GPT]开头的为模型生成的语言,[bot]开头的为程序提示。
|
||||
欢迎到github.com/RockChinQ/QChatGPT 给个star"""
|
||||
@@ -24,10 +24,10 @@ reply_message = "[bot]err:请求超时"
|
||||
# 群聊消息超时提示
|
||||
replys_message = "[bot]err:请求超时"
|
||||
|
||||
# 指令权限不足提示
|
||||
# 命令权限不足提示
|
||||
command_admin_message = "[bot]err:权限不足: "
|
||||
# 指令无效提示
|
||||
command_err_message = "[bot]err:指令不存在:"
|
||||
# 命令无效提示
|
||||
command_err_message = "[bot]err:命令不存在:"
|
||||
|
||||
# 会话重置提示
|
||||
command_reset_message = "[bot]会话已重置"
|
||||
|
||||
Reference in New Issue
Block a user