Skip to main content

ChatGPT 工具包,支持多模态对话(gpt-4o)、连续对话、流式对话(逐字显示)、对话存档与载入、对话回滚、对话伪造、轮询 api_key 池、群聊多角色模拟、在命令行对话、限制历史消息数量、异步请求。

Project description

项目描述

ChatGPT 工具包,支持多模态对话(gpt-4o)、连续对话、流式对话(逐字显示)、对话存档与载入、对话回滚、对话伪造、轮询 api_key 池、群聊多角色模拟、在命令行对话、限制历史消息数量、异步请求。

作者

江南雨上

主页 | Github | PyPi | 微信 | 邮箱 | 捐赠

Bug提交、功能提议

你可以通过 Github-Issues微信 与我联系。

安装

pip install openai2

获取api_key

获取链接1

获取链接2

教程

导入

from openai2 import Chat

创建对话

api_key = 'api_key'  # 更换成自己的api_key

Tony = Chat(api_key=api_key, model="gpt-3.5-turbo")
Lucy = Chat(api_key=api_key, model="gpt-3.5-turbo")  # 每个实例可使用 相同 或者 不同 的api_key

对话

Tony.request('自然数50的后面是几?')  # >>> '51'
Lucy.request('自然数100的后面是几?')  # >>> '101'

Tony.request('再往后是几?')  # >>> '52'
Lucy.request('再往后是几?')  # >>> '102'

Tony.request('再往后呢?')  # >>> '53'
Lucy.request('再往后呢?')  # >>> '103'

流式对话 (查看演示 👈)

for answer in Lucy.stream_request('世界上最大的海洋是哪个?'):
    print(answer)













异步对话

import asyncio
from openai2 import Chat

Tony = Chat(api_key=api_key, model="gpt-3.5-turbo")

async def main():
    answer = await Tony.async_request('世界上最大的海洋是哪个')
    print(answer)

asyncio.run(main())  # >>> '世界上最大的海洋是太平洋。'

异步流式对话

async for answer in Tony.async_stream_request('世界上最大的海洋是哪个?'):
    print(answer)













多模态对话(gpt-4o)

import pathlib
from openai2 import Chat, Multimodal_Part


Bruce = Chat(api_key='sk-jg93...', model="gpt-4o")


pic = pathlib.Path(rf'C:\鼠标.jpeg').read_bytes()

answer = Bruce.request(

    '下面这张图片里画了什么?',
  
    Multimodal_Part.jpeg(pic)
)

print(answer)  # >>> '这张图片里画了一个鼠标。'

注:

1、Multimodal_Part 除了 jpeg 方法以外,还有 png、text 等方法。

2、对于 str 型对象,以下这两种写法是等价的:Bruce.request(..., '这张图片里画了什么', ...)Bruce.request(..., Multimodal_Part.text('这张图片里画了什么'), ...)

3、多模态对话支持同步对话、异步对话、同步流式对话、异步流式对话…… 相对于普通对话,唯一的区别就是支持多模态。

4、目前已知支持多模态对话的模型有:gpt-4o、gpt-4o-mini、gpt-4o-2024-05-13、gpt-4o-mini-2024-07-18。

对话回滚

Anna = Chat(api_key=api_key, model="gpt-3.5-turbo")

Anna.request('自然数1的后面是几?')  # >>> 2
Anna.request('再往后是几?')  # >>> 3
Anna.request('再往后呢?')  # >>> 4
Anna.request('再往后呢?')  # >>> 5
Anna.request('再往后呢?')  # >>> 6
Anna.request('再往后呢?')  # >>> 7
Anna.request('再往后呢?')  # >>> 8

# 回滚1轮对话
Anna.rollback()  # >>> [user]:再往后呢? [assistant]:7

# 再回滚3轮对话
Anna.rollback(n=3)  # >>> [user]:再往后呢? [assistant]:4

Anna.request('再往后呢?')  # >>> 5

注:

1、执行 Anna.rollback(n=x) 可回滚 x 轮对话。

2、Anna.rollback() 相当于 Anna.rollback(n=1)

轮询 api_key 池

from openai2 import Chat, AKPool

AK1 = 'sk-ug8w...'
AK2 = AKPool(['sk-mf40...', 'sk-m6g7...', ...])
AK3 = AKPool(['sk-affe...', 'sk-fam4...', ...])

Duke = Chat(api_key=AK1, model="gpt-3.5-turbo")  # 令 Duke 使用固定的 api_key

Carl = Chat(api_key=AK2, model="gpt-3.5-turbo")  # 令 Carl 和 Denny 使用同一个'api_key池', 系统将自动充分利用每个api_key
Denny = Chat(api_key=AK2, model="gpt-3.5-turbo")

Chris = Chat(api_key=AK3, model="gpt-3.5-turbo")  # 令 Chris 使用独立的'api_key池'

注:允许(而非不允许)同一个 api_key 投放到不同的 api_key 池中,但每个 api_key 池都是独立调度,不会互相通信。

重置 api_key

AK5 = 'sk-jg93...'
AK6 = AKPool(['sk-vb7l...', 'sk-d3lv...'])
...

Carl.reset_api_key(AK5)  # 重置 api_key
Carl.reset_api_key(AK6)  # 再次重置 api_key
...

对话导出与导入

对话导出

Ariel = Chat(api_key=api_key, model="gpt-3.5-turbo")

Ariel.request('自然数1的后面是几?')  # >>> 2
Ariel.request('再往后是几?')  # >>> 3

Ariel.fetch_messages()
# 返回:
# [
#     {'role': 'user', 'content': '自然数1的后面是几?'},
#     {'role': 'assistant', 'content': '2'},
#     {'role': 'user', 'content': '再往后是几?'},
#     {'role': 'assistant', 'content': '3'}
# ]

对话存档

你可以把导出的对话持久化保存:

import json
from pathlib import Path

record = Ariel.fetch_messages()
record = json.dumps(record, ensure_ascii=False)
Path('record.json').write_text(record, encoding="utf8")

对话导入

导出的对话可以再导入到其它对话中:

record = Ariel.fetch_messages()

Jenny = Chat(api_key=api_key, model="gpt-3.5-turbo")
Jenny.add_dialogs(*record)

Jenny.request('再往后呢?')  # >>> 4

导出的对话也可以再导入到原对话中,但这样做会在原对话中产生重复的历史消息。

对话伪造

利用对话导入功能,可以伪造对话:

from openai2 import Chat, user_msg, assistant_msg

Mickey = Chat(api_key=api_key, model="gpt-3.5-turbo")

Mickey.add_dialogs(
    user_msg('请问1+1=几?'),  # 等价于 {"role": "user", "content": '请问1+1=几?'}
    assistant_msg('1+1=10'),  # 等价于 {"role": "assistant", "content": '1+1=10'}
    {"role": "user", "content": '那10+10=几?'},
    {"role": "assistant", "content": '10+10=你大爷, 你提的这些问题真弱智!'},
)

answer = Mickey.request('哦吼, 你还敢骂我呀?')
print(answer)  # >>> 非常抱歉,我刚才的回答有些不适当。1+1=2, 10+10=20。非常抱歉给你带来困扰!

注:对话导出与导入可以穿插在对话中的任何时刻。

群聊多角色模拟

import json
from openai2 import GroupChat

api_key = '...'  # 更换成自己的 api_key
group = GroupChat(api_key=api_key, model="gpt-3.5-turbo")

# 设置角色
group.roles['苏轼'] = '宋朝诗人,他的词风格独特,既有儒家的教诲,又有生活的乐趣。'
group.roles['李清照'] = '宋代著名的女词人,其词句优美,情感真挚。'
group.roles['杜甫'] = '唐朝著名诗人。'

# 添加角色历史对话
group.add_dialog(speaker='苏轼', audiences=['李清照'], remark='你好呀')
group.add_dialog(speaker='李清照', audiences=['苏轼'], remark='好久不见, 你最近在忙什么?')
group.add_dialog(speaker='杜甫', audiences=['苏轼'], remark='上次托你帮我写的那首《茅屋为秋风所破歌》写好了吗?')

# 让 ChatGPT 模拟角色发言
answer = group.request([
    ('苏轼', ['李清照']),  # 第 1 个元素表示说话人, 第 2 个元素表示对谁说话. 由于一个人可以同时对多个人说话, 因此第 2 个元素为列表
    ('苏轼', ['杜甫']),
])

try:
    print( json.loads(answer) )
except:
    print(answer)

# 返回:
[
    {
        "speaker": "苏轼",
        "audiences": "李清照",
        "remark": "最近我在写一首新的诗,题目是《听雨》"
    },
    {
        "speaker": "苏轼",
        "audiences": "杜甫",
        "remark": "那首《茅屋为秋风所破歌》已经写好啦,我在信里寄给你了,请查收"
    }
]

限制历史消息数量

限制历史消息数量

随着对话次数越来越多,最终上下文长度就会超出 openai 接口限定的最大 token 数量,此时可使用 msg_max_count 参数来限制历史消息数量。当消息数量超出 msg_max_count 后,程序会自动移除最早的记录,使消息数量减少到恰好等于 msg_max_count 。

msg_max_count = 6  # 最多保留6条历史消息

Ariel = Chat(api_key=api_key, model="gpt-3.5-turbo", msg_max_count=msg_max_count)

Ariel.request('英国的首都是什么?')  # >>> '伦敦'
Ariel.request('日本首都是什么?')  # >>> '东京'
Ariel.request('意大利的首都是什么?')  # >>> '罗马'
Ariel.request('美国的首都是什么?')  # >>> '华盛顿'
Ariel.request('世界上国土面积最大的国家是哪个?')  # >>> '俄罗斯'
Ariel.request('法国的首都叫什么?')  # >>> '巴黎'
Ariel.request('青蛙的幼体叫什么?')  # >>> '蝌蚪'
Ariel.request('世界上最大的海洋是什么?')  # >>> '太平洋'

Ariel.fetch_messages()

# 返回:
# [
#     {'role': 'user', 'content': '法国的首都叫什么?'},
#     {'role': 'assistant', 'content': '巴黎'},
#     {'role': 'user', 'content': '青蛙的幼体叫什么?'},
#     {'role': 'assistant', 'content': '蝌蚪'},
#     {'role': 'user', 'content': '世界上最大的海洋是什么?'},
#     {'role': 'assistant', 'content': '太平洋'}
# ]

锁定消息

当程序自动移除消息记录时,也许我们希望某些消息不要被移除,此时可将这些消息锁定。

msg_max_count = 6

Ariel = Chat(api_key=api_key, model="gpt-3.5-turbo", msg_max_count=msg_max_count)

Ariel.request('英国的首都是什么?')  # >>> '伦敦'
Ariel.request('日本首都是什么?')  # >>> '东京'
Ariel.request('意大利的首都是什么?')  # >>> '罗马'

此时共有 6 条消息记录:

消息 正序索引 逆序索引
英国的首都是什么? 0 -6
伦敦 1 -5
日本首都是什么? 2 -4
东京 3 -3
意大利的首都是什么? 4 -2
罗马 5 -1

锁定索引为 0、-2、-1 的消息:

Ariel.pin_messages(0, -2, -1)  # 索引无须按顺序填写: pin_messages(0, 1, 2) 与 pin_messages(0, 2, 1) 等价.

继续请求:

Ariel.request('美国的首都是什么?')  # >>> '华盛顿'

由于设置了 msg_max_count = 6,此时共有 6 条消息记录:

消息 正序索引 逆序索引 锁定状态
英国的首都是什么? 0 -6 已锁定
东京 1 -5 -
意大利的首都是什么? 2 -4 已锁定
罗马 3 -3 已锁定
美国的首都是什么? 4 -2 -
华盛顿 5 -1 -

继续执行:

Ariel.pin_messages(-2)  # 锁定'美国的首都是什么?'

Ariel.request('世界上国土面积最大的国家是哪个?')  # >>> '俄罗斯'
Ariel.request('法国的首都叫什么?')  # >>> '巴黎'
Ariel.request('青蛙的幼体叫什么?')  # >>> '蝌蚪'
Ariel.request('世界上最大的海洋是什么?')  # >>> '太平洋'

Ariel.fetch_messages()

# 返回:
# [
#     {'role': 'user', 'content': '英国的首都是什么?'},       # 被锁定的消息
#     {'role': 'user', 'content': '意大利的首都是什么?'},     # 被锁定的消息
#     {'role': 'assistant', 'content': '罗马'},               # 被锁定的消息
#     {'role': 'user', 'content': '美国的首都是什么?'},       # 被锁定的消息
#     {'role': 'user', 'content': '世界上最大的海洋是什么?'},
#     {'role': 'assistant', 'content': '太平洋'}
# ]

注:pin_messages 方法也允许传入“已锁定的消息”的索引,这使得当不确定某些消息的状态时,可以放心地将它们的索引传进去。

解锁消息

可使用 unpin_messages 方法将已锁定的消息解除锁定。

Ariel.unpin_messages(0, -2, -1)  # 解锁索引为 0、-2、-1 的消息

注:unpin_messages 方法也允许传入“未锁定的消息”的索引,这使得当不确定某些消息的状态时,可以放心地将它们的索引传进去。

更多方法

1、openai2.Chat 底层调用了 openai.OpenAI,支持 openai.OpenAI 的所有参数。

2、openai2.Chat.requestopenai2.Chat.stream_request 底层调用了 openai.OpenAI.chat.completions.create,支持 openai.OpenAI.chat.completions.create 的所有参数。

3、openai2.Chat.async_requestopenai2.Chat.async_stream_request 底层调用了 openai.AsyncOpenAI.chat.completions.create,支持 openai.AsyncOpenAI.chat.completions.create 的所有参数。

查看相关参数 👈

在命令行对话 (查看演示 👈)

openai2 add_apikey sk-T92mZYXHLWKt1234gtPKT3BlbkFJ
openai2 chat

指令集

指令 功能 说明
openai2  add_apikey  你的apikey 添加 1 个 apikey 如需添加多个,可执行多次
openai2  read_apikey 查看所有 apikey
openai2  clear_apikey 清除所有 apikey
openai2  chat 继续上次的对话
openai2  newchat 清空对话记录, 然后开始新对话

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openai2-1.7.9.tar.gz (19.7 kB view details)

Uploaded Source

Built Distribution

openai2-1.7.9-py2.py3-none-any.whl (10.1 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file openai2-1.7.9.tar.gz.

File metadata

  • Download URL: openai2-1.7.9.tar.gz
  • Upload date:
  • Size: 19.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.31.0

File hashes

Hashes for openai2-1.7.9.tar.gz
Algorithm Hash digest
SHA256 15107ba0adc4c1454775ffe81b6793fa7be5e932c5f07099de7d6f345e41ceb4
MD5 f90a632baa3674b136fa958519ad2d9a
BLAKE2b-256 09f0910f26f2056152ab60e67f28c290d29eef7199740fc2ab6b2accb8880028

See more details on using hashes here.

File details

Details for the file openai2-1.7.9-py2.py3-none-any.whl.

File metadata

  • Download URL: openai2-1.7.9-py2.py3-none-any.whl
  • Upload date:
  • Size: 10.1 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.31.0

File hashes

Hashes for openai2-1.7.9-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 1ad0bef74e12506f65ad16cbac30a20675b24570a3172e1137db0c34f9344333
MD5 aa6000c663d5b5cd6e27e338c4702604
BLAKE2b-256 76bfdce6d4512417c93e782b367fda763599aec05457451dae21c18204890a36

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page