pygpt-net 2.6.27__py3-none-any.whl → 2.6.29__py3-none-any.whl
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.
- pygpt_net/CHANGELOG.txt +12 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +5 -1
- pygpt_net/controller/kernel/kernel.py +2 -0
- pygpt_net/controller/notepad/notepad.py +10 -1
- pygpt_net/controller/theme/common.py +2 -0
- pygpt_net/controller/theme/markdown.py +2 -0
- pygpt_net/controller/theme/theme.py +3 -0
- pygpt_net/controller/ui/tabs.py +5 -0
- pygpt_net/core/audio/backend/native.py +1 -3
- pygpt_net/core/command/command.py +2 -0
- pygpt_net/core/idx/llm.py +21 -3
- pygpt_net/core/render/web/helpers.py +13 -3
- pygpt_net/core/render/web/renderer.py +3 -3
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +27 -28
- pygpt_net/data/css/web-blocks.darkest.css +91 -0
- pygpt_net/data/css/web-chatgpt.css +7 -5
- pygpt_net/data/css/web-chatgpt.dark.css +5 -2
- pygpt_net/data/css/web-chatgpt.darkest.css +91 -0
- pygpt_net/data/css/web-chatgpt.light.css +8 -2
- pygpt_net/data/css/web-chatgpt_wide.css +7 -4
- pygpt_net/data/css/web-chatgpt_wide.dark.css +5 -2
- pygpt_net/data/css/web-chatgpt_wide.darkest.css +91 -0
- pygpt_net/data/css/web-chatgpt_wide.light.css +9 -6
- pygpt_net/data/themes/dark_darkest.css +31 -0
- pygpt_net/data/themes/dark_darkest.xml +10 -0
- pygpt_net/plugin/tuya/__init__.py +12 -0
- pygpt_net/plugin/tuya/config.py +256 -0
- pygpt_net/plugin/tuya/plugin.py +117 -0
- pygpt_net/plugin/tuya/worker.py +588 -0
- pygpt_net/plugin/wikipedia/__init__.py +12 -0
- pygpt_net/plugin/wikipedia/config.py +228 -0
- pygpt_net/plugin/wikipedia/plugin.py +114 -0
- pygpt_net/plugin/wikipedia/worker.py +430 -0
- pygpt_net/provider/core/config/patch.py +11 -0
- pygpt_net/ui/widget/tabs/output.py +2 -0
- pygpt_net/ui/widget/textarea/input.py +10 -7
- {pygpt_net-2.6.27.dist-info → pygpt_net-2.6.29.dist-info}/METADATA +50 -6
- {pygpt_net-2.6.27.dist-info → pygpt_net-2.6.29.dist-info}/RECORD +44 -31
- {pygpt_net-2.6.27.dist-info → pygpt_net-2.6.29.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.27.dist-info → pygpt_net-2.6.29.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.27.dist-info → pygpt_net-2.6.29.dist-info}/entry_points.txt +0 -0
|
@@ -55,10 +55,11 @@ p {{
|
|
|
55
55
|
|
|
56
56
|
/* cmd */
|
|
57
57
|
.cmd {{
|
|
58
|
-
font-family: '
|
|
58
|
+
font-family: 'Monaspace Neon';
|
|
59
59
|
text-decoration: none;
|
|
60
|
+
padding-top: 5px;
|
|
60
61
|
padding-bottom: 0px;
|
|
61
|
-
font-size: 0.
|
|
62
|
+
font-size: 0.75rem;
|
|
62
63
|
}}
|
|
63
64
|
|
|
64
65
|
/* lists, code */
|
|
@@ -245,12 +246,14 @@ code {{
|
|
|
245
246
|
color: gray;
|
|
246
247
|
}}
|
|
247
248
|
.tool-output .content {{
|
|
249
|
+
font-family: 'Monaspace Neon';
|
|
248
250
|
padding: 10px;
|
|
249
251
|
color: gray !important;
|
|
252
|
+
font-size: 0.75rem;
|
|
250
253
|
}}
|
|
251
254
|
.tool-output .toggle-cmd-output {{
|
|
252
255
|
cursor: pointer;
|
|
253
|
-
padding-top:
|
|
256
|
+
padding-top: 0px;
|
|
254
257
|
display: block;
|
|
255
258
|
color: gray;
|
|
256
259
|
}}
|
|
@@ -303,7 +306,7 @@ code {{
|
|
|
303
306
|
height: 150px;
|
|
304
307
|
margin: 0;
|
|
305
308
|
margin-bottom: 0px !important;
|
|
306
|
-
border-radius:
|
|
309
|
+
border-radius: 0;
|
|
307
310
|
width: auto;
|
|
308
311
|
}}
|
|
309
312
|
.extra-src-img-box .img-wrapper:hover {{
|
|
@@ -18,7 +18,7 @@ p {{
|
|
|
18
18
|
color: #fff;
|
|
19
19
|
}}
|
|
20
20
|
a {{
|
|
21
|
-
color: #
|
|
21
|
+
color: #b5c3cd !important;
|
|
22
22
|
}}
|
|
23
23
|
a:hover {{
|
|
24
24
|
color: #b8cad7 !important;
|
|
@@ -37,7 +37,7 @@ a:hover {{
|
|
|
37
37
|
color: #fff;
|
|
38
38
|
}}
|
|
39
39
|
.cmd {{
|
|
40
|
-
color: #4d4d4d;
|
|
40
|
+
color: #4d4d4d !important;
|
|
41
41
|
}}
|
|
42
42
|
.ts {{
|
|
43
43
|
color: #4d4d4d;
|
|
@@ -71,6 +71,9 @@ code {{
|
|
|
71
71
|
.name-user::before {{
|
|
72
72
|
background-color: silver;
|
|
73
73
|
}}
|
|
74
|
+
.tool-output .content {{
|
|
75
|
+
color: #4d4d4d !important;
|
|
76
|
+
}}
|
|
74
77
|
|
|
75
78
|
/* loader */
|
|
76
79
|
.lds-ring {{
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
body {{
|
|
2
|
+
color: #fff;
|
|
3
|
+
background-color: #202020;
|
|
4
|
+
}}
|
|
5
|
+
::-webkit-scrollbar {{
|
|
6
|
+
background: #1c1c1c;
|
|
7
|
+
}}
|
|
8
|
+
::-webkit-scrollbar-thumb {{
|
|
9
|
+
background: #282828;
|
|
10
|
+
}}
|
|
11
|
+
::-webkit-scrollbar-thumb:hover {{
|
|
12
|
+
background: #333333;
|
|
13
|
+
}}
|
|
14
|
+
::-webkit-scrollbar-corner {{
|
|
15
|
+
background: #232629;
|
|
16
|
+
}}
|
|
17
|
+
p {{
|
|
18
|
+
color: #fff;
|
|
19
|
+
}}
|
|
20
|
+
a {{
|
|
21
|
+
color: #b5c3cd !important;
|
|
22
|
+
}}
|
|
23
|
+
a:hover {{
|
|
24
|
+
color: #b8cad7 !important;
|
|
25
|
+
}}
|
|
26
|
+
.msg-user {{
|
|
27
|
+
background: #303030;
|
|
28
|
+
color: #fff;
|
|
29
|
+
}}
|
|
30
|
+
.msg-user p {{
|
|
31
|
+
color: #fff;
|
|
32
|
+
}}
|
|
33
|
+
.msg-bot {{
|
|
34
|
+
color: #fff;
|
|
35
|
+
}}
|
|
36
|
+
.msg-bot p {{
|
|
37
|
+
color: #fff;
|
|
38
|
+
}}
|
|
39
|
+
.cmd {{
|
|
40
|
+
color: #4d4d4d !important;
|
|
41
|
+
}}
|
|
42
|
+
.ts {{
|
|
43
|
+
color: #4d4d4d;
|
|
44
|
+
}}
|
|
45
|
+
.list {{
|
|
46
|
+
}}
|
|
47
|
+
code {{
|
|
48
|
+
color: {QTMATERIAL_PRIMARYLIGHTCOLOR};
|
|
49
|
+
}}
|
|
50
|
+
.code-header-wrapper {{
|
|
51
|
+
background-color: #303030;
|
|
52
|
+
}}
|
|
53
|
+
.code-header-action {{
|
|
54
|
+
color: silver !important;
|
|
55
|
+
}}
|
|
56
|
+
.code-header-action:hover {{
|
|
57
|
+
color: #fff;
|
|
58
|
+
}}
|
|
59
|
+
.code-header-action:hover img {{
|
|
60
|
+
filter: brightness(130%);
|
|
61
|
+
}}
|
|
62
|
+
.code-header-lang {{
|
|
63
|
+
color: #686868;
|
|
64
|
+
}}
|
|
65
|
+
.action-icons a:hover {{
|
|
66
|
+
filter: brightness(130%);
|
|
67
|
+
}}
|
|
68
|
+
.name-bot::before {{
|
|
69
|
+
background-color: {QTMATERIAL_PRIMARYLIGHTCOLOR};
|
|
70
|
+
}}
|
|
71
|
+
.name-user::before {{
|
|
72
|
+
background-color: silver;
|
|
73
|
+
}}
|
|
74
|
+
.tool-output .content {{
|
|
75
|
+
color: #4d4d4d !important;
|
|
76
|
+
}}
|
|
77
|
+
|
|
78
|
+
/* loader */
|
|
79
|
+
.lds-ring {{
|
|
80
|
+
color: #fff;
|
|
81
|
+
}}
|
|
82
|
+
.append_live {{
|
|
83
|
+
color: gray;
|
|
84
|
+
}}
|
|
85
|
+
|
|
86
|
+
.tips p {{
|
|
87
|
+
color: #5e5e5e;
|
|
88
|
+
}}
|
|
89
|
+
.msg-box .name-header.name-bot {{
|
|
90
|
+
color: #cfcfcf;
|
|
91
|
+
}}
|
|
@@ -18,9 +18,13 @@ p {{
|
|
|
18
18
|
color: #000;
|
|
19
19
|
}}
|
|
20
20
|
a {{
|
|
21
|
-
color: #
|
|
21
|
+
color: #2b4e67 !important;
|
|
22
|
+
}}
|
|
23
|
+
a:hover {{
|
|
24
|
+
color: #426f90 !important;
|
|
22
25
|
}}
|
|
23
26
|
.msg-user {{
|
|
27
|
+
background-color: #f3f3f3;
|
|
24
28
|
color: #000;
|
|
25
29
|
}}
|
|
26
30
|
.msg-user p {{
|
|
@@ -33,7 +37,7 @@ a {{
|
|
|
33
37
|
color: #000;
|
|
34
38
|
}}
|
|
35
39
|
.cmd {{
|
|
36
|
-
color: #
|
|
40
|
+
color: #888787 !important;
|
|
37
41
|
text-decoration: none;
|
|
38
42
|
}}
|
|
39
43
|
.ts {{
|
|
@@ -63,10 +67,6 @@ code {{
|
|
|
63
67
|
.code-header-lang {{
|
|
64
68
|
color: #5c5c5c;
|
|
65
69
|
}}
|
|
66
|
-
.msg-user {{
|
|
67
|
-
background-color: #f3f3f3;
|
|
68
|
-
color: #000;
|
|
69
|
-
}}
|
|
70
70
|
.name-bot::before {{
|
|
71
71
|
background-color: #6b6b6b;
|
|
72
72
|
}}
|
|
@@ -76,6 +76,9 @@ code {{
|
|
|
76
76
|
.action-icons a:hover {{
|
|
77
77
|
filter: brightness(60%);
|
|
78
78
|
}}
|
|
79
|
+
.tool-output .content {{
|
|
80
|
+
color: #888787 !important;
|
|
81
|
+
}}
|
|
79
82
|
|
|
80
83
|
/* loader */
|
|
81
84
|
.lds-ring {{
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
.layout-output-web {{
|
|
2
|
+
background-color: #202020 !important;
|
|
3
|
+
}}
|
|
4
|
+
QListView::item:selected,
|
|
5
|
+
QTreeView::item:selected {{
|
|
6
|
+
color: #ffffff;
|
|
7
|
+
selection-color: #ffffff;
|
|
8
|
+
}}
|
|
9
|
+
QComboBox::item:selected {{
|
|
10
|
+
color: #000;
|
|
11
|
+
selection-color: #000;
|
|
12
|
+
}}
|
|
13
|
+
QComboBox::item:disabled {{
|
|
14
|
+
color: #d1d2d2;
|
|
15
|
+
}}
|
|
16
|
+
QListView::item:selected:focus,
|
|
17
|
+
QComboBox::item:selected:focus,
|
|
18
|
+
QTreeView::item:selected:focus {{
|
|
19
|
+
color: #ffffff;
|
|
20
|
+
selection-color: #000000;
|
|
21
|
+
}}
|
|
22
|
+
QListView::item::disabled {{
|
|
23
|
+
color: #959595;
|
|
24
|
+
font-weight: bold;
|
|
25
|
+
}}
|
|
26
|
+
QMenuBar::item:selected {{
|
|
27
|
+
color: #000000;
|
|
28
|
+
}}
|
|
29
|
+
QMenu::item:selected {{
|
|
30
|
+
color: #000000;
|
|
31
|
+
}}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!--?xml version="1.0" encoding="UTF-8"?-->
|
|
2
|
+
<resources>
|
|
3
|
+
<color name="primaryColor">#ffffff</color>
|
|
4
|
+
<color name="primaryLightColor">#ffffff</color>
|
|
5
|
+
<color name="secondaryColor">#1b1b1b</color>
|
|
6
|
+
<color name="secondaryLightColor">#202020</color>
|
|
7
|
+
<color name="secondaryDarkColor">#202020</color>
|
|
8
|
+
<color name="primaryTextColor">#ffffff</color>
|
|
9
|
+
<color name="secondaryTextColor">#ffffff</color>
|
|
10
|
+
</resources>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ================================================== #
|
|
4
|
+
# This file is a part of PYGPT package #
|
|
5
|
+
# Website: https://pygpt.net #
|
|
6
|
+
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
+
# MIT License #
|
|
8
|
+
# Created By : Marcin Szczygliński #
|
|
9
|
+
# Updated Date: 2025.08.27 20:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from .plugin import *
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ================================================== #
|
|
4
|
+
# This file is a part of PYGPT package #
|
|
5
|
+
# Website: https://pygpt.net #
|
|
6
|
+
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
+
# MIT License #
|
|
8
|
+
# Created By : Marcin Szczygliński #
|
|
9
|
+
# Updated Date: 2025.08.27 20:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from pygpt_net.plugin.base.config import BaseConfig, BasePlugin
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Config(BaseConfig):
|
|
16
|
+
def __init__(self, plugin: BasePlugin = None, *args, **kwargs):
|
|
17
|
+
super(Config, self).__init__(plugin)
|
|
18
|
+
self.plugin = plugin
|
|
19
|
+
|
|
20
|
+
def from_defaults(self, plugin: BasePlugin = None):
|
|
21
|
+
# Endpoints / HTTP
|
|
22
|
+
plugin.add_option(
|
|
23
|
+
"api_base",
|
|
24
|
+
type="text",
|
|
25
|
+
value="https://openapi.tuyaeu.com",
|
|
26
|
+
label="API base",
|
|
27
|
+
description="Tuya API base (eu/us/cn/in: https://openapi.tuyaeu.com / tuyaus / tuyacn / tuyain).",
|
|
28
|
+
)
|
|
29
|
+
plugin.add_option(
|
|
30
|
+
"http_timeout",
|
|
31
|
+
type="int",
|
|
32
|
+
value=30,
|
|
33
|
+
label="HTTP timeout (s)",
|
|
34
|
+
description="Requests timeout in seconds.",
|
|
35
|
+
)
|
|
36
|
+
plugin.add_option(
|
|
37
|
+
"lang",
|
|
38
|
+
type="text",
|
|
39
|
+
value="en",
|
|
40
|
+
label="Language",
|
|
41
|
+
description="Language header (e.g., en, pl).",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Credentials
|
|
45
|
+
plugin.add_option(
|
|
46
|
+
"tuya_client_id",
|
|
47
|
+
type="text",
|
|
48
|
+
value="",
|
|
49
|
+
label="Tuya Client ID",
|
|
50
|
+
description="Client ID from Tuya IoT Platform Cloud project.",
|
|
51
|
+
secret=True,
|
|
52
|
+
)
|
|
53
|
+
plugin.add_option(
|
|
54
|
+
"tuya_client_secret",
|
|
55
|
+
type="text",
|
|
56
|
+
value="",
|
|
57
|
+
label="Tuya Client Secret",
|
|
58
|
+
description="Client secret from Tuya IoT Platform Cloud project.",
|
|
59
|
+
secret=True,
|
|
60
|
+
)
|
|
61
|
+
plugin.add_option(
|
|
62
|
+
"tuya_uid",
|
|
63
|
+
type="text",
|
|
64
|
+
value="",
|
|
65
|
+
label="Tuya UID (App Account)",
|
|
66
|
+
description="UID of linked Tuya App account (required for listing devices).",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Tokens (auto)
|
|
70
|
+
plugin.add_option(
|
|
71
|
+
"tuya_access_token",
|
|
72
|
+
type="textarea",
|
|
73
|
+
value="",
|
|
74
|
+
label="(auto) Access token",
|
|
75
|
+
description="Stored Tuya access token.",
|
|
76
|
+
secret=True,
|
|
77
|
+
)
|
|
78
|
+
plugin.add_option(
|
|
79
|
+
"tuya_refresh_token",
|
|
80
|
+
type="textarea",
|
|
81
|
+
value="",
|
|
82
|
+
label="(auto) Refresh token",
|
|
83
|
+
description="Stored Tuya refresh token (not always used).",
|
|
84
|
+
secret=True,
|
|
85
|
+
)
|
|
86
|
+
plugin.add_option(
|
|
87
|
+
"tuya_token_expires_in",
|
|
88
|
+
type="text",
|
|
89
|
+
value="",
|
|
90
|
+
label="(auto) Expires in (s)",
|
|
91
|
+
description="Token lifetime seconds.",
|
|
92
|
+
)
|
|
93
|
+
plugin.add_option(
|
|
94
|
+
"tuya_token_expire_at",
|
|
95
|
+
type="text",
|
|
96
|
+
value="0",
|
|
97
|
+
label="(auto) Expire at (epoch s)",
|
|
98
|
+
description="Timestamp when token is considered expired.",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Cache
|
|
102
|
+
plugin.add_option(
|
|
103
|
+
"tuya_cached_devices",
|
|
104
|
+
type="textarea",
|
|
105
|
+
value="[]",
|
|
106
|
+
label="(auto) Cached devices",
|
|
107
|
+
description="Cached devices for quick search.",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# ---------------- Commands ----------------
|
|
111
|
+
|
|
112
|
+
# Auth
|
|
113
|
+
plugin.add_cmd(
|
|
114
|
+
"tuya_set_keys",
|
|
115
|
+
instruction="Set Tuya Cloud credentials.",
|
|
116
|
+
params=[
|
|
117
|
+
{"name": "client_id", "type": "str", "required": True, "description": "Tuya Client ID"},
|
|
118
|
+
{"name": "client_secret", "type": "str", "required": True, "description": "Tuya Client Secret"},
|
|
119
|
+
],
|
|
120
|
+
enabled=True,
|
|
121
|
+
description="Auth: set keys",
|
|
122
|
+
tab="auth",
|
|
123
|
+
)
|
|
124
|
+
plugin.add_cmd(
|
|
125
|
+
"tuya_set_uid",
|
|
126
|
+
instruction="Set Tuya App Account UID (for listing devices).",
|
|
127
|
+
params=[
|
|
128
|
+
{"name": "uid", "type": "str", "required": True, "description": "UID of linked Tuya account"},
|
|
129
|
+
],
|
|
130
|
+
enabled=True,
|
|
131
|
+
description="Auth: set UID",
|
|
132
|
+
tab="auth",
|
|
133
|
+
)
|
|
134
|
+
plugin.add_cmd(
|
|
135
|
+
"tuya_token_get",
|
|
136
|
+
instruction="Obtain access token (grant_type=1).",
|
|
137
|
+
params=[],
|
|
138
|
+
enabled=True,
|
|
139
|
+
description="Auth: get token",
|
|
140
|
+
tab="auth",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Devices
|
|
144
|
+
plugin.add_cmd(
|
|
145
|
+
"tuya_devices_list",
|
|
146
|
+
instruction="List devices for UID.",
|
|
147
|
+
params=[
|
|
148
|
+
{"name": "uid", "type": "str", "required": False, "description": "Override UID (optional)"},
|
|
149
|
+
{"name": "page_no", "type": "int", "required": False, "description": "Page number (default 1)"},
|
|
150
|
+
{"name": "page_size", "type": "int", "required": False, "description": "Page size (default 100)"},
|
|
151
|
+
],
|
|
152
|
+
enabled=True,
|
|
153
|
+
description="Devices: list",
|
|
154
|
+
tab="devices",
|
|
155
|
+
)
|
|
156
|
+
plugin.add_cmd(
|
|
157
|
+
"tuya_device_get",
|
|
158
|
+
instruction="Get device info.",
|
|
159
|
+
params=[{"name": "device_id", "type": "str", "required": True, "description": "Device ID"}],
|
|
160
|
+
enabled=True,
|
|
161
|
+
description="Devices: get info",
|
|
162
|
+
tab="devices",
|
|
163
|
+
)
|
|
164
|
+
plugin.add_cmd(
|
|
165
|
+
"tuya_device_status",
|
|
166
|
+
instruction="Get device status (DP values).",
|
|
167
|
+
params=[{"name": "device_id", "type": "str", "required": True, "description": "Device ID"}],
|
|
168
|
+
enabled=True,
|
|
169
|
+
description="Devices: status",
|
|
170
|
+
tab="devices",
|
|
171
|
+
)
|
|
172
|
+
plugin.add_cmd(
|
|
173
|
+
"tuya_device_functions",
|
|
174
|
+
instruction="Get device supported functions (DP codes).",
|
|
175
|
+
params=[{"name": "device_id", "type": "str", "required": True, "description": "Device ID"}],
|
|
176
|
+
enabled=True,
|
|
177
|
+
description="Devices: functions",
|
|
178
|
+
tab="devices",
|
|
179
|
+
)
|
|
180
|
+
plugin.add_cmd(
|
|
181
|
+
"tuya_find_device",
|
|
182
|
+
instruction="Find device(s) by name (uses cached device list).",
|
|
183
|
+
params=[{"name": "name", "type": "str", "required": True, "description": "Substring match"}],
|
|
184
|
+
enabled=True,
|
|
185
|
+
description="Devices: find by name",
|
|
186
|
+
tab="devices",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Control
|
|
190
|
+
plugin.add_cmd(
|
|
191
|
+
"tuya_device_set",
|
|
192
|
+
instruction="Set a device DP value or multiple values.",
|
|
193
|
+
params=[
|
|
194
|
+
{"name": "device_id", "type": "str", "required": True, "description": "Device ID"},
|
|
195
|
+
{"name": "code", "type": "str", "required": False, "description": "DP code (if single)"},
|
|
196
|
+
{"name": "value", "type": "str", "required": False, "description": "Value for 'code'"},
|
|
197
|
+
{"name": "codes", "type": "dict", "required": False, "description": "Dict of {code: value}"},
|
|
198
|
+
],
|
|
199
|
+
enabled=True,
|
|
200
|
+
description="Control: set DP(s)",
|
|
201
|
+
tab="control",
|
|
202
|
+
)
|
|
203
|
+
plugin.add_cmd(
|
|
204
|
+
"tuya_device_send",
|
|
205
|
+
instruction="Send raw commands list to device.",
|
|
206
|
+
params=[
|
|
207
|
+
{"name": "device_id", "type": "str", "required": True, "description": "Device ID"},
|
|
208
|
+
{"name": "commands", "type": "list", "required": True, "description": "[{'code':'','value':..},...]"},
|
|
209
|
+
],
|
|
210
|
+
enabled=True,
|
|
211
|
+
description="Control: send commands",
|
|
212
|
+
tab="control",
|
|
213
|
+
)
|
|
214
|
+
plugin.add_cmd(
|
|
215
|
+
"tuya_device_on",
|
|
216
|
+
instruction="Turn device ON (guesses switch code if not provided).",
|
|
217
|
+
params=[
|
|
218
|
+
{"name": "device_id", "type": "str", "required": True, "description": "Device ID"},
|
|
219
|
+
{"name": "code", "type": "str", "required": False, "description": "Preferred switch code"},
|
|
220
|
+
],
|
|
221
|
+
enabled=True,
|
|
222
|
+
description="Control: on",
|
|
223
|
+
tab="control",
|
|
224
|
+
)
|
|
225
|
+
plugin.add_cmd(
|
|
226
|
+
"tuya_device_off",
|
|
227
|
+
instruction="Turn device OFF (guesses switch code if not provided).",
|
|
228
|
+
params=[
|
|
229
|
+
{"name": "device_id", "type": "str", "required": True, "description": "Device ID"},
|
|
230
|
+
{"name": "code", "type": "str", "required": False, "description": "Preferred switch code"},
|
|
231
|
+
],
|
|
232
|
+
enabled=True,
|
|
233
|
+
description="Control: off",
|
|
234
|
+
tab="control",
|
|
235
|
+
)
|
|
236
|
+
plugin.add_cmd(
|
|
237
|
+
"tuya_device_toggle",
|
|
238
|
+
instruction="Toggle device state (reads current boolean DP).",
|
|
239
|
+
params=[
|
|
240
|
+
{"name": "device_id", "type": "str", "required": True, "description": "Device ID"},
|
|
241
|
+
{"name": "code", "type": "str", "required": False, "description": "Preferred switch code"},
|
|
242
|
+
],
|
|
243
|
+
enabled=True,
|
|
244
|
+
description="Control: toggle",
|
|
245
|
+
tab="control",
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Sensors
|
|
249
|
+
plugin.add_cmd(
|
|
250
|
+
"tuya_sensors_read",
|
|
251
|
+
instruction="Read and normalize common sensor values.",
|
|
252
|
+
params=[{"name": "device_id", "type": "str", "required": True, "description": "Sensor device ID"}],
|
|
253
|
+
enabled=True,
|
|
254
|
+
description="Sensors: read",
|
|
255
|
+
tab="sensors",
|
|
256
|
+
)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ================================================== #
|
|
4
|
+
# This file is a part of PYGPT package #
|
|
5
|
+
# Website: https://pygpt.net #
|
|
6
|
+
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
+
# MIT License #
|
|
8
|
+
# Created By : Marcin Szczygliński #
|
|
9
|
+
# Updated Date: 2025.08.27 20:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from pygpt_net.plugin.base.plugin import BasePlugin
|
|
13
|
+
from pygpt_net.core.events import Event
|
|
14
|
+
from pygpt_net.item.ctx import CtxItem
|
|
15
|
+
|
|
16
|
+
from .config import Config
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Plugin(BasePlugin):
|
|
20
|
+
def __init__(self, *args, **kwargs):
|
|
21
|
+
super(Plugin, self).__init__(*args, **kwargs)
|
|
22
|
+
self.id = "tuya"
|
|
23
|
+
self.name = "Tuya (IoT)"
|
|
24
|
+
self.description = "Handle Tuya Smart Home devices via Tuya Cloud API."
|
|
25
|
+
self.prefix = "API"
|
|
26
|
+
self.order = 100
|
|
27
|
+
self.allowed_cmds = [
|
|
28
|
+
"tuya_set_keys",
|
|
29
|
+
"tuya_set_uid",
|
|
30
|
+
"tuya_token_get",
|
|
31
|
+
"tuya_devices_list",
|
|
32
|
+
"tuya_device_get",
|
|
33
|
+
"tuya_device_status",
|
|
34
|
+
"tuya_device_functions",
|
|
35
|
+
"tuya_find_device",
|
|
36
|
+
"tuya_device_set",
|
|
37
|
+
"tuya_device_send",
|
|
38
|
+
"tuya_device_on",
|
|
39
|
+
"tuya_device_off",
|
|
40
|
+
"tuya_device_toggle",
|
|
41
|
+
"tuya_sensors_read"
|
|
42
|
+
]
|
|
43
|
+
self.use_locale = False
|
|
44
|
+
self.worker = None
|
|
45
|
+
self.config = Config(self)
|
|
46
|
+
self.init_options()
|
|
47
|
+
|
|
48
|
+
def init_options(self):
|
|
49
|
+
"""Initialize options"""
|
|
50
|
+
self.config.from_defaults(self)
|
|
51
|
+
|
|
52
|
+
def handle(self, event: Event, *args, **kwargs):
|
|
53
|
+
"""
|
|
54
|
+
Handle dispatched event
|
|
55
|
+
|
|
56
|
+
:param event: event object
|
|
57
|
+
:param args: event args
|
|
58
|
+
:param kwargs: event kwargs
|
|
59
|
+
"""
|
|
60
|
+
name = event.name
|
|
61
|
+
data = event.data
|
|
62
|
+
ctx = event.ctx
|
|
63
|
+
|
|
64
|
+
if name == Event.CMD_SYNTAX:
|
|
65
|
+
self.cmd_syntax(data)
|
|
66
|
+
|
|
67
|
+
elif name == Event.CMD_EXECUTE:
|
|
68
|
+
self.cmd(
|
|
69
|
+
ctx,
|
|
70
|
+
data['commands'],
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def cmd_syntax(self, data: dict):
|
|
74
|
+
"""
|
|
75
|
+
Event: CMD_SYNTAX
|
|
76
|
+
|
|
77
|
+
:param data: event data dict
|
|
78
|
+
"""
|
|
79
|
+
for option in self.allowed_cmds:
|
|
80
|
+
if self.has_cmd(option):
|
|
81
|
+
data['cmd'].append(self.get_cmd(option)) # append command
|
|
82
|
+
|
|
83
|
+
def cmd(self, ctx: CtxItem, cmds: list):
|
|
84
|
+
"""
|
|
85
|
+
Event: CMD_EXECUTE
|
|
86
|
+
|
|
87
|
+
:param ctx: CtxItem
|
|
88
|
+
:param cmds: commands dict
|
|
89
|
+
"""
|
|
90
|
+
from .worker import Worker
|
|
91
|
+
|
|
92
|
+
is_cmd = False
|
|
93
|
+
my_commands = []
|
|
94
|
+
for item in cmds:
|
|
95
|
+
if item["cmd"] in self.allowed_cmds:
|
|
96
|
+
my_commands.append(item)
|
|
97
|
+
is_cmd = True
|
|
98
|
+
|
|
99
|
+
if not is_cmd:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
# set state: busy
|
|
103
|
+
self.cmd_prepare(ctx, my_commands)
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
worker = Worker()
|
|
107
|
+
worker.from_defaults(self)
|
|
108
|
+
worker.cmds = my_commands
|
|
109
|
+
worker.ctx = ctx
|
|
110
|
+
|
|
111
|
+
if not self.is_async(ctx):
|
|
112
|
+
worker.run()
|
|
113
|
+
return
|
|
114
|
+
worker.run_async()
|
|
115
|
+
|
|
116
|
+
except Exception as e:
|
|
117
|
+
self.error(e)
|