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.7.tar.gz (20.1 kB view details)

Uploaded Source

Built Distribution

openai2-1.7.7-py2.py3-none-any.whl (10.2 kB view details)

Uploaded Python 2 Python 3

File details

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

File metadata

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

File hashes

Hashes for openai2-1.7.7.tar.gz
Algorithm Hash digest
SHA256 f7cb9fc2856d6b37e0162f8191d05a3e8830b9d306b0527469b8b333ceab39c0
MD5 2040f51124bf4a0710d065d2fb56afa8
BLAKE2b-256 ff85ef1f064d34eadfc0a117d0023f7c1f4e589e3fee1a586b35e2082cbf46e6

See more details on using hashes here.

File details

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

File metadata

  • Download URL: openai2-1.7.7-py2.py3-none-any.whl
  • Upload date:
  • Size: 10.2 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.7-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 9daea153cb41fd138f7777b9aa7ca198bfa495a13ea399adcdaa82b8e5672276
MD5 029df44340c8243fbbf1b591e3e905c3
BLAKE2b-256 80248b757cd4788ba084ca0ad205b5ff9d092ed858a85611b76133ab2b555c53

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