nonebot-adapter-qq 1.6.4__tar.gz → 1.6.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/PKG-INFO +1 -1
  2. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/bot.py +59 -34
  3. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/event.py +1 -1
  4. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/message.py +75 -1
  5. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/models/qq.py +60 -1
  6. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/pyproject.toml +2 -2
  7. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/LICENSE +0 -0
  8. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/README.md +0 -0
  9. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/__init__.py +0 -0
  10. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/adapter.py +0 -0
  11. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/compat.py +0 -0
  12. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/config.py +0 -0
  13. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/exception.py +0 -0
  14. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/models/__init__.py +0 -0
  15. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/models/common.py +0 -0
  16. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/models/guild.py +0 -0
  17. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/models/payload.py +0 -0
  18. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/permission.py +0 -0
  19. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/store.py +0 -0
  20. {nonebot_adapter_qq-1.6.4 → nonebot_adapter_qq-1.6.5}/nonebot/adapters/qq/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nonebot-adapter-qq
3
- Version: 1.6.4
3
+ Version: 1.6.5
4
4
  Summary: QQ adapter for nonebot2
5
5
  License: MIT
6
6
  Keywords: bot,qq,qqbot,qqguild
@@ -63,12 +63,15 @@ from .models import (
63
63
  Guild,
64
64
  Media,
65
65
  Member,
66
+ MessageActionButton,
66
67
  MessageArk,
67
68
  MessageEmbed,
68
69
  MessageKeyboard,
69
70
  MessageMarkdown,
71
+ MessagePromptKeyboard,
70
72
  MessageReference,
71
73
  MessageSetting,
74
+ MessageStream,
72
75
  PatchGuildRoleReturn,
73
76
  PinsMessage,
74
77
  PostC2CFilesReturn,
@@ -316,6 +319,12 @@ class Bot(BaseBot):
316
319
  kwargs["message_reference"] = reference[-1].data["reference"]
317
320
  if keyboard := (message["keyboard"] or None):
318
321
  kwargs["keyboard"] = keyboard[-1].data["keyboard"]
322
+ if stream := (message["stream"] or None):
323
+ kwargs["stream"] = stream[-1].data["stream"]
324
+ if prompt_keyboard := (message["prompt_keyboard"] or None):
325
+ kwargs["prompt_keyboard"] = prompt_keyboard[-1].data["prompt_keyboard"]
326
+ if action_button := (message["action_button"] or None):
327
+ kwargs["action_button"] = action_button[-1].data["action_button"]
319
328
  return kwargs
320
329
 
321
330
  @staticmethod
@@ -402,7 +411,12 @@ class Bot(BaseBot):
402
411
  msg_type = 4
403
412
  elif kwargs.get("ark"):
404
413
  msg_type = 3
405
- elif kwargs.get("markdown") or kwargs.get("keyboard"):
414
+ elif (
415
+ kwargs.get("markdown")
416
+ or kwargs.get("keyboard")
417
+ or kwargs.get("prompt_keyboard")
418
+ or kwargs.get("action_button")
419
+ ):
406
420
  msg_type = 2
407
421
  elif (
408
422
  message["image"]
@@ -1668,6 +1682,9 @@ class Bot(BaseBot):
1668
1682
  embed: Optional[MessageEmbed] = None,
1669
1683
  image: None = None,
1670
1684
  message_reference: None = None,
1685
+ stream: Optional[MessageStream] = None,
1686
+ prompt_keyboard: Optional[MessagePromptKeyboard] = None,
1687
+ action_button: Optional[MessageActionButton] = None,
1671
1688
  event_id: Optional[str] = None,
1672
1689
  msg_id: Optional[str] = None,
1673
1690
  msg_seq: Optional[int] = None,
@@ -1682,42 +1699,50 @@ class Bot(BaseBot):
1682
1699
  elif timestamp is None:
1683
1700
  timestamp = int(datetime.now(timezone.utc).timestamp())
1684
1701
 
1702
+ json_data = exclude_none(
1703
+ {
1704
+ "msg_type": msg_type,
1705
+ "content": content,
1706
+ "markdown": (
1707
+ markdown.dict(exclude_none=True) if markdown is not None else None
1708
+ ),
1709
+ "keyboard": (
1710
+ keyboard.dict(exclude_none=True) if keyboard is not None else None
1711
+ ),
1712
+ "media": (media.dict(exclude_none=True) if media is not None else None),
1713
+ "ark": ark.dict(exclude_none=True) if ark is not None else None,
1714
+ "embed": (embed.dict(exclude_none=True) if embed is not None else None),
1715
+ "image": image,
1716
+ "message_reference": (
1717
+ message_reference.dict(exclude_none=True)
1718
+ if message_reference is not None
1719
+ else None
1720
+ ),
1721
+ "stream": (
1722
+ stream.dict(exclude_none=True, exclude_unset=True)
1723
+ if stream is not None
1724
+ else None
1725
+ ),
1726
+ "prompt_keyboard": (
1727
+ prompt_keyboard.dict(exclude_none=True, exclude_unset=True)
1728
+ if prompt_keyboard is not None
1729
+ else None
1730
+ ),
1731
+ "action_button": (
1732
+ action_button.dict(exclude_none=True)
1733
+ if action_button is not None
1734
+ else None
1735
+ ),
1736
+ "event_id": event_id,
1737
+ "msg_id": msg_id,
1738
+ "msg_seq": msg_seq,
1739
+ "timestamp": timestamp,
1740
+ }
1741
+ )
1685
1742
  request = Request(
1686
1743
  "POST",
1687
1744
  self.adapter.get_api_base().joinpath("v2", "users", openid, "messages"),
1688
- json=exclude_none(
1689
- {
1690
- "msg_type": msg_type,
1691
- "content": content,
1692
- "markdown": (
1693
- markdown.dict(exclude_none=True)
1694
- if markdown is not None
1695
- else None
1696
- ),
1697
- "keyboard": (
1698
- keyboard.dict(exclude_none=True)
1699
- if keyboard is not None
1700
- else None
1701
- ),
1702
- "media": (
1703
- media.dict(exclude_none=True) if media is not None else None
1704
- ),
1705
- "ark": ark.dict(exclude_none=True) if ark is not None else None,
1706
- "embed": (
1707
- embed.dict(exclude_none=True) if embed is not None else None
1708
- ),
1709
- "image": image,
1710
- "message_reference": (
1711
- message_reference.dict(exclude_none=True)
1712
- if message_reference is not None
1713
- else None
1714
- ),
1715
- "event_id": event_id,
1716
- "msg_id": msg_id,
1717
- "msg_seq": msg_seq,
1718
- "timestamp": timestamp,
1719
- }
1720
- ),
1745
+ json=json_data,
1721
1746
  )
1722
1747
  return type_validate_python(PostC2CMessagesReturn, await self._request(request))
1723
1748
 
@@ -356,7 +356,7 @@ class DirectMessageDeleteEvent(MessageDeleteEvent):
356
356
 
357
357
 
358
358
  class QQMessageEvent(MessageEvent, QQMessage):
359
- _reply_seq: int = -1
359
+ _reply_seq: int = 0
360
360
 
361
361
  @override
362
362
  def get_message(self) -> Message:
@@ -3,7 +3,7 @@ from dataclasses import dataclass
3
3
  from io import BytesIO
4
4
  from pathlib import Path
5
5
  import re
6
- from typing import TYPE_CHECKING, Optional, TypedDict, Union, overload
6
+ from typing import TYPE_CHECKING, Literal, Optional, TypedDict, Union, overload
7
7
  from typing_extensions import Self, override
8
8
 
9
9
  from nonebot.adapters import Message as BaseMessage
@@ -13,11 +13,14 @@ from nonebot.compat import type_validate_python
13
13
  from .models import Attachment as QQAttachment
14
14
  from .models import Message as GuildMessage
15
15
  from .models import (
16
+ MessageActionButton,
16
17
  MessageArk,
17
18
  MessageEmbed,
18
19
  MessageKeyboard,
19
20
  MessageMarkdown,
21
+ MessagePromptKeyboard,
20
22
  MessageReference,
23
+ MessageStream,
21
24
  QQMessage,
22
25
  )
23
26
  from .utils import escape, unescape
@@ -148,6 +151,35 @@ class MessageSegment(BaseMessageSegment["Message"]):
148
151
  },
149
152
  )
150
153
 
154
+ @staticmethod
155
+ def stream(
156
+ state: Literal[1, 10, 11, 20],
157
+ _id: Optional[str],
158
+ index: int,
159
+ reset: Optional[bool] = None,
160
+ ) -> "Stream":
161
+ _data = {
162
+ "state": state,
163
+ "index": index,
164
+ }
165
+ if _id is not None:
166
+ _data["id"] = _id
167
+
168
+ if reset is not None:
169
+ _data["reset"] = reset
170
+
171
+ return Stream("stream", data={"stream": MessageStream(**_data)})
172
+
173
+ @staticmethod
174
+ def prompt_keyboard(prompt_keyboard: MessagePromptKeyboard) -> "PromptKeyboard":
175
+ return PromptKeyboard(
176
+ "prompt_keyboard", data={"prompt_keyboard": prompt_keyboard}
177
+ )
178
+
179
+ @staticmethod
180
+ def action_button(action_button: MessageActionButton) -> "ActionButton":
181
+ return ActionButton("action_button", data={"action_button": action_button})
182
+
151
183
  @override
152
184
  def __add__(
153
185
  self, other: Union[str, "MessageSegment", Iterable["MessageSegment"]]
@@ -445,6 +477,48 @@ SEGMENT_TYPE_MAP: dict[str, type[MessageSegment]] = {
445
477
  }
446
478
 
447
479
 
480
+ class _ActionButtonData(TypedDict):
481
+ action_button: MessageActionButton
482
+
483
+
484
+ @dataclass
485
+ class ActionButton(MessageSegment):
486
+ if TYPE_CHECKING:
487
+ data: _ActionButtonData
488
+
489
+ @override
490
+ def __str__(self) -> str:
491
+ return f"<action_button:{self.data['action_button']!r}>"
492
+
493
+
494
+ class _PromptKeyboardData(TypedDict):
495
+ prompt_keyboard: MessagePromptKeyboard
496
+
497
+
498
+ @dataclass
499
+ class PromptKeyboard(MessageSegment):
500
+ if TYPE_CHECKING:
501
+ data: _PromptKeyboardData
502
+
503
+ @override
504
+ def __str__(self) -> str:
505
+ return f"<prompt_keyboard:{self.data['prompt_keyboard']!r}>"
506
+
507
+
508
+ class _StreamData(TypedDict):
509
+ stream: MessageStream
510
+
511
+
512
+ @dataclass
513
+ class Stream(MessageSegment):
514
+ if TYPE_CHECKING:
515
+ data: _StreamData
516
+
517
+ @override
518
+ def __str__(self) -> str:
519
+ return f"<stream:{self.data['stream']!r}>"
520
+
521
+
448
522
  class Message(BaseMessage[MessageSegment]):
449
523
  @classmethod
450
524
  @override
@@ -1,5 +1,5 @@
1
1
  from datetime import datetime
2
- from typing import Optional
2
+ from typing import Literal, Optional
3
3
  from urllib.parse import urlparse
4
4
 
5
5
  from pydantic import BaseModel
@@ -77,16 +77,75 @@ class PostGroupMembersReturn(BaseModel):
77
77
  next_index: Optional[int] = None
78
78
 
79
79
 
80
+ class MessageActionButton(BaseModel):
81
+ template_id: Literal["1", "10"] = "1" # 待废弃字段!!!
82
+ callback_data: Optional[str] = None
83
+ feedback: Optional[bool] = None # 反馈按钮(赞踩按钮)
84
+ tts: Optional[bool] = None # TTS 语音播放按钮
85
+ re_generate: Optional[bool] = None # 重新生成按钮
86
+ stop_generate: Optional[bool] = None # 停止生成按钮
87
+
88
+
89
+ class PromptAction(BaseModel):
90
+ type: Literal[2] = 2
91
+
92
+
93
+ class PromptRenderData(BaseModel):
94
+ label: str
95
+ style: Literal[2] = 2
96
+
97
+
98
+ class PromptButton(BaseModel):
99
+ render_data: PromptRenderData
100
+ action: PromptAction
101
+
102
+
103
+ class PromptRow(BaseModel):
104
+ buttons: list[PromptButton]
105
+
106
+
107
+ class PromptContent(BaseModel):
108
+ rows: list[PromptRow]
109
+
110
+
111
+ class PromptKeyboardModel(BaseModel):
112
+ content: PromptContent
113
+
114
+
115
+ class MessagePromptKeyboard(BaseModel):
116
+ keyboard: PromptKeyboardModel
117
+
118
+
119
+ class MessageStream(BaseModel):
120
+ state: Literal[1, 10, 11, 20]
121
+ """1: 正文生成中, 10: 正文生成结束, 11: 引志消息生成中, 20: 引导消息生成结束。"""
122
+ id: Optional[str] = None
123
+ """第一条不用填写,第二条需要填写第一个分片返回的 msgID"""
124
+ index: int
125
+ """从 1 开始"""
126
+ reset: Optional[bool] = None
127
+ """只能用于流式消息没有发送完成时,reset 时 index 需要从 0 开始,需要填写流式 id"""
128
+
129
+
80
130
  __all__ = [
81
131
  "Attachment",
82
132
  "FriendAuthor",
83
133
  "GroupMember",
84
134
  "GroupMemberAuthor",
85
135
  "Media",
136
+ "MessageActionButton",
137
+ "MessagePromptKeyboard",
138
+ "MessageStream",
86
139
  "PostC2CFilesReturn",
87
140
  "PostC2CMessagesReturn",
88
141
  "PostGroupFilesReturn",
89
142
  "PostGroupMembersReturn",
90
143
  "PostGroupMessagesReturn",
144
+ "PromptAction",
145
+ "PromptButton",
146
+ "PromptContent",
147
+ "PromptKeyboardModel",
148
+ "PromptRenderData",
149
+ "PromptRow",
91
150
  "QQMessage",
92
151
  ]
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "nonebot-adapter-qq"
3
- version = "1.6.4"
3
+ version = "1.6.5"
4
4
  description = "QQ adapter for nonebot2"
5
5
  authors = ["yanyongyu <yyy@nonebot.dev>"]
6
6
  license = "MIT"
@@ -27,7 +27,7 @@ typing-extensions = ">=4.4.0, <5.0.0"
27
27
  pydantic = ">=1.10.0,<3.0.0,!=2.5.0,!=2.5.1"
28
28
 
29
29
  [tool.poetry.group.dev.dependencies]
30
- ruff = "^0.11.0"
30
+ ruff = "^0.12.0"
31
31
  nonemoji = "^0.1.3"
32
32
  pre-commit = "^4.0.0"
33
33