pixelarraythirdparty 1.3.4__tar.gz → 1.3.6__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 (33) hide show
  1. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/PKG-INFO +1 -1
  2. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/__init__.py +8 -2
  3. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/custom_events/custom_events.py +33 -1
  4. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/project_dashboard/project_dashboard.py +20 -9
  5. pixelarraythirdparty-1.3.6/pixelarraythirdparty/support_chat/support_chat.py +157 -0
  6. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty.egg-info/PKG-INFO +1 -1
  7. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pyproject.toml +1 -1
  8. pixelarraythirdparty-1.3.4/pixelarraythirdparty/support_chat/support_chat.py +0 -29
  9. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/LICENSE +0 -0
  10. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/MANIFEST.in +0 -0
  11. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/client.py +0 -0
  12. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/cron/__init__.py +0 -0
  13. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/cron/cron.py +0 -0
  14. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/custom_events/__init__.py +0 -0
  15. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/feedback/__init__.py +0 -0
  16. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/feedback/feedback.py +0 -0
  17. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/order/__init__.py +0 -0
  18. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/order/order.py +0 -0
  19. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/product/__init__.py +0 -0
  20. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/product/product.py +0 -0
  21. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/project/__init__.py +0 -0
  22. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/project/project.py +0 -0
  23. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/project_dashboard/__init__.py +0 -0
  24. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/support_chat/__init__.py +0 -0
  25. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/unified_login/__init__.py +0 -0
  26. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/unified_login/unified_login.py +0 -0
  27. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/user/__init__.py +0 -0
  28. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty/user/user.py +0 -0
  29. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty.egg-info/SOURCES.txt +0 -0
  30. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty.egg-info/dependency_links.txt +0 -0
  31. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty.egg-info/requires.txt +0 -0
  32. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/pixelarraythirdparty.egg-info/top_level.txt +0 -0
  33. {pixelarraythirdparty-1.3.4 → pixelarraythirdparty-1.3.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixelarraythirdparty
3
- Version: 1.3.4
3
+ Version: 1.3.6
4
4
  Summary: PixelArray 第三方微服务客户端
5
5
  Author-email: Lu qi <qi.lu@pixelarrayai.com>
6
6
  License-Expression: MIT
@@ -16,11 +16,15 @@ PixelArray 第三方微服务客户端
16
16
  - project_dashboard: 项目看板(按 scope 查询 DNU/DAU/留存)
17
17
  """
18
18
 
19
- from .support_chat.support_chat import SupportChatManagerAsync
19
+ from .feedback.feedback import FeedbackManagerAsync
20
+ from .support_chat.support_chat import (
21
+ SupportChatManagerAsync,
22
+ build_staff_portal_session_url,
23
+ )
20
24
  from .custom_events.custom_events import CustomEventsManagerAsync
21
25
  from .project_dashboard.project_dashboard import ProjectDashboardManagerAsync
22
26
 
23
- __version__ = "1.3.4"
27
+ __version__ = "1.3.6"
24
28
  __author__ = "Lu qi"
25
29
  __email__ = "qi.lu@pixelarrayai.com"
26
30
 
@@ -35,7 +39,9 @@ __all__ = [
35
39
  "support_chat",
36
40
  "custom_events",
37
41
  "project_dashboard",
42
+ "FeedbackManagerAsync",
38
43
  "SupportChatManagerAsync",
44
+ "build_staff_portal_session_url",
39
45
  "CustomEventsManagerAsync",
40
46
  "ProjectDashboardManagerAsync",
41
47
  ]
@@ -62,6 +62,38 @@ class CustomEventsManagerAsync(AsyncClient):
62
62
  "POST", "/api/custom-events/definitions/create", json=body
63
63
  )
64
64
 
65
+ async def get_custom_event_common_field_schema(
66
+ self, project_name: str
67
+ ) -> Tuple[Dict[str, Any], bool]:
68
+ """
69
+ description:
70
+ 查询项目自定义事件公共维度(GET /api/custom-events/common-field-schema)
71
+ """
72
+ return await self._request(
73
+ "GET",
74
+ "/api/custom-events/common-field-schema",
75
+ params={"project_name": project_name},
76
+ )
77
+
78
+ async def update_custom_event_common_field_schema(
79
+ self,
80
+ project_name: str,
81
+ field_schema: List[Dict[str, Any]],
82
+ ) -> Tuple[Dict[str, Any], bool]:
83
+ """
84
+ description:
85
+ 更新项目公共维度;传空列表表示恢复服务端内置默认(POST /api/custom-events/common-field-schema/update)
86
+ parameters:
87
+ field_schema: 每项含 name、type、required、可选 nullable、description
88
+ """
89
+ body: Dict[str, Any] = {
90
+ "project_name": project_name,
91
+ "field_schema": field_schema or [],
92
+ }
93
+ return await self._request(
94
+ "POST", "/api/custom-events/common-field-schema/update", json=body
95
+ )
96
+
65
97
  async def report_custom_event(
66
98
  self,
67
99
  project_name: str,
@@ -71,7 +103,7 @@ class CustomEventsManagerAsync(AsyncClient):
71
103
  ) -> Tuple[Dict[str, Any], bool]:
72
104
  """
73
105
  description:
74
- 上报单条自定义事件日志(JSON 载荷须符合 Portal 中配置的 field_schema)
106
+ 上报单条自定义事件日志(有效载荷 = 项目公共维度 该事件 field_schema;未传的公共键由服务端补 null
75
107
  parameters:
76
108
  project_name(str): 项目名称(与 projects.name 一致)
77
109
  event_key(str): 事件键
@@ -12,6 +12,8 @@ def _resolve_dashboard_path(scope: str) -> Optional[str]:
12
12
  return "/api/project-dashboard/dashboard/dau"
13
13
  if s.upper() == "RETENTION" or s == "留存":
14
14
  return "/api/project-dashboard/dashboard/retention"
15
+ if s.upper() == "TOTAL_USERS" or s == "总用户":
16
+ return "/api/project-dashboard/dashboard/total-users"
15
17
  return None
16
18
 
17
19
 
@@ -28,13 +30,13 @@ class ProjectDashboardManagerAsync(AsyncClient):
28
30
  ) -> Tuple[Dict[str, Any], bool]:
29
31
  """
30
32
  description:
31
- 查询项目看板指标;scope 为 DNU、DAU、RETENTION 或中文「留存」。
33
+ 查询项目看板指标;scope 为 DNU、DAU、RETENTION、TOTAL_USERS 或中文「留存」「总用户」。
32
34
  parameters:
33
35
  project_name(str): 项目名称(与统一登录 project_name 一致)
34
36
  scope(str): DNU | DAU | RETENTION | 留存
35
37
  start_date(str, optional): 开始日期 YYYY-MM-DD;不传则服务端默认 T-7
36
38
  end_date(str, optional): 结束日期 YYYY-MM-DD;不传则服务端默认 T-0
37
- retention_days(str, optional): scope 为留存时有效;逗号分隔天数,如 2,7,14,20;不传则服务端默认
39
+ retention_days(str): scope 为留存时必填;逗号分隔天数,如 1,7,14,20
38
40
  return:
39
41
  data(dict): 成功时为 DauData / DnuData / RetentionData 结构(见接口文档)
40
42
  success(bool): 是否成功
@@ -42,14 +44,23 @@ class ProjectDashboardManagerAsync(AsyncClient):
42
44
  path = _resolve_dashboard_path(scope)
43
45
  if not path:
44
46
  return (
45
- {"message": "scope 无效,应为 DNU、DAU、RETENTION 或 留存"},
47
+ {"message": "scope 无效,应为 DNU、DAU、RETENTION、TOTAL_USERS 或 留存 / 总用户"},
48
+ False,
49
+ )
50
+ is_retention = "/retention" in path
51
+ is_total_users = "/total-users" in path
52
+ rd = (retention_days or "").strip()
53
+ if is_retention and not rd:
54
+ return (
55
+ {"message": "scope 为留存时须传入 retention_days(逗号分隔正整数,如 1,7,14)"},
46
56
  False,
47
57
  )
48
58
  params: Dict[str, Any] = {"project_name": project_name}
49
- if start_date:
50
- params["start_date"] = start_date
51
- if end_date:
52
- params["end_date"] = end_date
53
- if retention_days:
54
- params["retention_days"] = retention_days
59
+ if not is_total_users:
60
+ if start_date:
61
+ params["start_date"] = start_date
62
+ if end_date:
63
+ params["end_date"] = end_date
64
+ if rd:
65
+ params["retention_days"] = rd
55
66
  return await self._request("GET", path, params=params)
@@ -0,0 +1,157 @@
1
+ from typing import List, Optional
2
+
3
+ from pixelarraythirdparty.client import AsyncClient
4
+
5
+
6
+ def build_staff_portal_session_url(portal_base_url: str, session_id: int) -> str:
7
+ """
8
+ 拼接带会话 ID 的 Portal 客服管理页 URL,便于运营在浏览器中打开指定会话。
9
+ portal_base_url 为 Portal 站点根地址(与工单 ticket_url 所用域名一致,不含末尾斜杠亦可)。
10
+ """
11
+ base = (portal_base_url or "").strip().rstrip("/")
12
+ return f"{base}/support-chat-management?session_id={session_id}"
13
+
14
+
15
+ class SupportChatManagerAsync(AsyncClient):
16
+ async def create_support_chat_link(
17
+ self,
18
+ expires_in_hours: int = 24,
19
+ ):
20
+ """
21
+ description:
22
+ 创建在线客服临时会话链接。其它服务调用此接口后,将返回的 chat_url 下发给用户,
23
+ 用户打开链接即可与客服对话(无需登录)。链接有时效。
24
+ parameters:
25
+ expires_in_hours(int, optional): 链接有效小时数,默认 24,范围 1~720
26
+ return:
27
+ data(dict): 成功时包含
28
+ - chat_url(str): 客服聊天页完整 URL
29
+ - token(str): 会话 token
30
+ - session_id(int): 会话 ID
31
+ - expires_at(str): 过期时间
32
+ success(bool): 操作是否成功
33
+ """
34
+ payload = {"expires_in_hours": expires_in_hours}
35
+ data, success = await self._request(
36
+ "POST", "/api/support-chat/create-link", json=payload
37
+ )
38
+ if not success:
39
+ return data, False
40
+ return data, True
41
+
42
+ async def list_support_chat_sessions(
43
+ self,
44
+ page: int = 1,
45
+ page_size: int = 20,
46
+ ):
47
+ """
48
+ 客服端:分页查询会话列表(需 API Key)。返回每条含 unread_from_customer 等字段。
49
+ """
50
+ params = {"page": page, "page_size": page_size}
51
+ data, success = await self._request(
52
+ "GET", "/api/support-chat/sessions", params=params
53
+ )
54
+ if not success:
55
+ return data, False
56
+ return data, True
57
+
58
+ async def get_support_chat_messages(
59
+ self,
60
+ session_id: int,
61
+ since_id: Optional[int] = None,
62
+ ):
63
+ """
64
+ 客服端:拉取指定会话消息(轮询;需 API Key)。媒体消息含 media_url。
65
+ """
66
+ params: dict = {"session_id": session_id}
67
+ if since_id is not None:
68
+ params["since_id"] = since_id
69
+ data, success = await self._request(
70
+ "GET", "/api/support-chat/messages", params=params
71
+ )
72
+ if not success:
73
+ return data, False
74
+ return data, True
75
+
76
+ async def send_support_message(
77
+ self,
78
+ session_id: int,
79
+ content: str = "",
80
+ content_type: str = "text",
81
+ oss_path: Optional[str] = None,
82
+ mime_type: Optional[str] = None,
83
+ ):
84
+ """
85
+ 客服端:发送回复(文本或图片/视频,与 Portal 约定一致;需 API Key)。
86
+ """
87
+ payload = {
88
+ "session_id": session_id,
89
+ "content": content,
90
+ "content_type": content_type,
91
+ }
92
+ if oss_path is not None:
93
+ payload["oss_path"] = oss_path
94
+ if mime_type is not None:
95
+ payload["mime_type"] = mime_type
96
+ data, success = await self._request(
97
+ "POST", "/api/support-chat/send-message", json=payload
98
+ )
99
+ if not success:
100
+ return data, False
101
+ return data, True
102
+
103
+ async def mark_support_session_read(self, session_id: int):
104
+ """客服端:将用户发来且未读的消息标记为已读。"""
105
+ payload = {"session_id": session_id}
106
+ data, success = await self._request(
107
+ "POST", "/api/support-chat/mark-read", json=payload
108
+ )
109
+ if not success:
110
+ return data, False
111
+ return data, True
112
+
113
+ async def get_support_upload_presigned_url(
114
+ self,
115
+ session_id: int,
116
+ file_name: str,
117
+ file_type: str,
118
+ file_size: Optional[int] = None,
119
+ mime_type: Optional[str] = None,
120
+ ):
121
+ """客服端:获取 OSS 直传预签名(image | video)。"""
122
+ payload = {
123
+ "session_id": session_id,
124
+ "file_name": file_name,
125
+ "file_type": file_type,
126
+ }
127
+ if file_size is not None:
128
+ payload["file_size"] = file_size
129
+ if mime_type is not None:
130
+ payload["mime_type"] = mime_type
131
+ data, success = await self._request(
132
+ "POST", "/api/support-chat/upload/presigned-url", json=payload
133
+ )
134
+ if not success:
135
+ return data, False
136
+ return data, True
137
+
138
+ async def delete_support_chat_session(self, session_id: int):
139
+ """客服端:删除单个会话及消息与对应临时 token。"""
140
+ data, success = await self._request(
141
+ "DELETE", f"/api/support-chat/sessions/{session_id}"
142
+ )
143
+ if not success:
144
+ return data, False
145
+ return data, True
146
+
147
+ async def batch_delete_support_chat_sessions(self, session_ids: List[int]):
148
+ """客服端:批量删除会话。"""
149
+ if not session_ids:
150
+ return {"message": "请提供要删除的会话 ID 列表"}, False
151
+ payload = {"session_ids": session_ids}
152
+ data, success = await self._request(
153
+ "POST", "/api/support-chat/sessions/batch-delete", json=payload
154
+ )
155
+ if not success:
156
+ return data, False
157
+ return data, True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixelarraythirdparty
3
- Version: 1.3.4
3
+ Version: 1.3.6
4
4
  Summary: PixelArray 第三方微服务客户端
5
5
  Author-email: Lu qi <qi.lu@pixelarrayai.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pixelarraythirdparty"
7
- version = "1.3.4"
7
+ version = "1.3.6"
8
8
  authors = [
9
9
  {name = "Lu qi", email = "qi.lu@pixelarrayai.com"},
10
10
  ]
@@ -1,29 +0,0 @@
1
- from pixelarraythirdparty.client import AsyncClient
2
-
3
-
4
- class SupportChatManagerAsync(AsyncClient):
5
- async def create_support_chat_link(
6
- self,
7
- expires_in_hours: int = 24,
8
- ):
9
- """
10
- description:
11
- 创建在线客服临时会话链接。其它服务调用此接口后,将返回的 chat_url 下发给用户,
12
- 用户打开链接即可与客服对话(无需登录)。链接有时效。
13
- parameters:
14
- expires_in_hours(int, optional): 链接有效小时数,默认 24,范围 1~720
15
- return:
16
- data(dict): 成功时包含
17
- - chat_url(str): 客服聊天页完整 URL
18
- - token(str): 会话 token
19
- - session_id(int): 会话 ID
20
- - expires_at(str): 过期时间
21
- success(bool): 操作是否成功
22
- """
23
- payload = {"expires_in_hours": expires_in_hours}
24
- data, success = await self._request(
25
- "POST", "/api/support-chat/create-link", json=payload
26
- )
27
- if not success:
28
- return data, False
29
- return data, True