pygpt-net 2.6.26__py3-none-any.whl → 2.6.28__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 +10 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +5 -1
- pygpt_net/controller/access/voice.py +3 -5
- pygpt_net/controller/audio/audio.py +9 -6
- pygpt_net/controller/audio/ui.py +263 -0
- pygpt_net/controller/chat/common.py +17 -1
- pygpt_net/controller/kernel/kernel.py +2 -0
- pygpt_net/controller/notepad/notepad.py +10 -1
- pygpt_net/controller/theme/markdown.py +2 -0
- pygpt_net/controller/theme/theme.py +4 -1
- pygpt_net/controller/ui/tabs.py +5 -0
- pygpt_net/core/audio/backend/native.py +114 -82
- pygpt_net/core/audio/backend/pyaudio.py +16 -19
- pygpt_net/core/audio/backend/pygame.py +12 -15
- pygpt_net/core/audio/capture.py +10 -9
- pygpt_net/core/audio/context.py +3 -6
- pygpt_net/core/command/command.py +2 -0
- pygpt_net/core/render/web/helpers.py +13 -3
- pygpt_net/core/render/web/renderer.py +3 -3
- pygpt_net/data/config/config.json +7 -5
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +24 -10
- 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/locale/locale.de.ini +2 -0
- pygpt_net/data/locale/locale.en.ini +2 -0
- pygpt_net/data/locale/locale.es.ini +2 -0
- pygpt_net/data/locale/locale.fr.ini +2 -0
- pygpt_net/data/locale/locale.it.ini +2 -0
- pygpt_net/data/locale/locale.pl.ini +3 -1
- pygpt_net/data/locale/locale.uk.ini +2 -0
- pygpt_net/data/locale/locale.zh.ini +2 -0
- pygpt_net/data/themes/dark_darkest.css +31 -0
- pygpt_net/data/themes/dark_darkest.xml +10 -0
- pygpt_net/plugin/audio_input/simple.py +5 -10
- pygpt_net/plugin/audio_output/plugin.py +4 -17
- 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/layout/chat/input.py +5 -2
- pygpt_net/ui/main.py +1 -2
- pygpt_net/ui/widget/audio/bar.py +5 -1
- pygpt_net/ui/widget/tabs/output.py +2 -0
- pygpt_net/ui/widget/textarea/input.py +483 -55
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/METADATA +78 -35
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/RECORD +63 -49
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/entry_points.txt +0 -0
|
@@ -80,7 +80,7 @@ agent.eval.feedback = Feedback
|
|
|
80
80
|
agent.eval.next = Ponowne uruchomienie z feedbackiem
|
|
81
81
|
agent.eval.score = Ocena ewaluatora
|
|
82
82
|
agent.eval.score.good = Odpowiedź wystarczająco dobra, wychodzenie.
|
|
83
|
-
agent.evolve.generation = Generacja
|
|
83
|
+
agent.evolve.generation = Generacja
|
|
84
84
|
agent.evolve.maxgen_limit = Osiągnięto maksymalną liczbę generacji, wychodzenie.
|
|
85
85
|
agent.evolve.option.max_generations = Maksymalna liczba generacji
|
|
86
86
|
agent.evolve.option.num_parents = Liczba rodziców
|
|
@@ -1117,6 +1117,8 @@ settings.audio.input.backend = Backend dla wejścia audio
|
|
|
1117
1117
|
settings.audio.input.backend.desc = Wybierz backend dla wejścia audio.
|
|
1118
1118
|
settings.audio.input.channels = Kanały
|
|
1119
1119
|
settings.audio.input.channels.desc = Kanały wejściowe, domyślnie: 1
|
|
1120
|
+
settings.audio.input.continuous = Ciągłe Nagrywanie Dźwięku (Kawałki)
|
|
1121
|
+
settings.audio.input.continuous.desc = Włącz nagrywanie w kawałkach dla długich nagrań audio w notatniku (notatki głosowe).
|
|
1120
1122
|
settings.audio.input.device = Urządzenie do wejścia audio
|
|
1121
1123
|
settings.audio.input.device.desc = Wybierz urządzenie do wejścia mikrofonu.
|
|
1122
1124
|
settings.audio.input.rate = Częstotliwość próbkowania
|
|
@@ -1116,6 +1116,8 @@ settings.audio.input.backend = Бекенд для аудіовходу
|
|
|
1116
1116
|
settings.audio.input.backend.desc = Виберіть бекенд для аудіовходу.
|
|
1117
1117
|
settings.audio.input.channels = Канали
|
|
1118
1118
|
settings.audio.input.channels.desc = Вхідні канали, за замовчуванням: 1
|
|
1119
|
+
settings.audio.input.continuous = Безперервний Аудіозапис (Частини)
|
|
1120
|
+
settings.audio.input.continuous.desc = Увімкніть запис частинами для довгих аудіозаписів у блокноті (голосові нотатки).
|
|
1119
1121
|
settings.audio.input.device = Пристрій для аудіовходу
|
|
1120
1122
|
settings.audio.input.device.desc = Виберіть пристрій для входу мікрофону.
|
|
1121
1123
|
settings.audio.input.rate = Частота дискретизації
|
|
@@ -1116,6 +1116,8 @@ settings.audio.input.backend = 音频输入的后端
|
|
|
1116
1116
|
settings.audio.input.backend.desc = 选择音频输入的后端。
|
|
1117
1117
|
settings.audio.input.channels = 声道
|
|
1118
1118
|
settings.audio.input.channels.desc = 输入声道,默认: 1
|
|
1119
|
+
settings.audio.input.continuous = 连续音频录制(片段)
|
|
1120
|
+
settings.audio.input.continuous.desc = 启用记事本中的长音频录制分段记录(语音笔记)。
|
|
1119
1121
|
settings.audio.input.device = 音频输入的设备
|
|
1120
1122
|
settings.audio.input.device.desc = 选择用于麦克风输入的音频设备。
|
|
1121
1123
|
settings.audio.input.rate = 采样率
|
|
@@ -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>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.07
|
|
9
|
+
# Updated Date: 2025.08.27 07:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -41,14 +41,11 @@ class Simple:
|
|
|
41
41
|
|
|
42
42
|
def switch_btn_stop(self):
|
|
43
43
|
"""Switch button to stop"""
|
|
44
|
-
self.plugin.window.
|
|
45
|
-
self.plugin.window.ui.plugin_addon['audio.input.btn'].btn_toggle.setToolTip(
|
|
46
|
-
trans('audio.speak.btn.stop.tooltip'))
|
|
44
|
+
self.plugin.window.controller.audio.ui.on_input_begin("input")
|
|
47
45
|
|
|
48
46
|
def switch_btn_start(self):
|
|
49
47
|
"""Switch button to start"""
|
|
50
|
-
self.plugin.window.
|
|
51
|
-
self.plugin.window.ui.plugin_addon['audio.input.btn'].btn_toggle.setToolTip(trans('audio.speak.btn.tooltip'))
|
|
48
|
+
self.plugin.window.controller.audio.ui.on_input_end("input")
|
|
52
49
|
|
|
53
50
|
def stop_timeout(self):
|
|
54
51
|
"""Stop timeout"""
|
|
@@ -85,10 +82,8 @@ class Simple:
|
|
|
85
82
|
# stop audio output if playing
|
|
86
83
|
self.plugin.window.controller.audio.stop_output()
|
|
87
84
|
|
|
88
|
-
# set audio
|
|
89
|
-
self.plugin.window.core.audio.capture.
|
|
90
|
-
self.plugin.window.ui.plugin_addon['audio.input.btn'].bar
|
|
91
|
-
)
|
|
85
|
+
# set audio input mode
|
|
86
|
+
self.plugin.window.core.audio.capture.set_mode("input")
|
|
92
87
|
|
|
93
88
|
# start timeout timer to prevent infinite recording
|
|
94
89
|
# disable in continuous mode
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.27 07:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Any
|
|
@@ -250,7 +250,8 @@ class Plugin(BasePlugin):
|
|
|
250
250
|
worker.signals.stop.connect(self.handle_stop)
|
|
251
251
|
worker.signals.volume_changed.connect(self.handle_volume)
|
|
252
252
|
|
|
253
|
-
self.window.controller.audio.
|
|
253
|
+
if not self.window.controller.audio.ui.recording:
|
|
254
|
+
self.window.controller.audio.on_begin("")
|
|
254
255
|
|
|
255
256
|
backend = self.window.core.config.get("audio.output.backend", "native")
|
|
256
257
|
if backend == "native":
|
|
@@ -275,20 +276,6 @@ class Plugin(BasePlugin):
|
|
|
275
276
|
"""
|
|
276
277
|
self.window.ui.plugin_addon['audio.output'].set_status(status)
|
|
277
278
|
|
|
278
|
-
def show_stop_button(self):
|
|
279
|
-
"""Show stop button"""
|
|
280
|
-
self.window.ui.plugin_addon['audio.output'].stop.setVisible(True)
|
|
281
|
-
|
|
282
|
-
def hide_stop_button(self):
|
|
283
|
-
"""Hide stop button"""
|
|
284
|
-
self.window.ui.plugin_addon['audio.output'].stop.setVisible(False)
|
|
285
|
-
|
|
286
|
-
def stop_speak(self):
|
|
287
|
-
"""Stop speaking"""
|
|
288
|
-
self.window.ui.plugin_addon['audio.output'].stop.setVisible(False)
|
|
289
|
-
self.window.ui.plugin_addon['audio.output'].set_status('Stopped')
|
|
290
|
-
self.window.ui.plugin_addon['audio.output'].stop_audio()
|
|
291
|
-
|
|
292
279
|
def stop_audio(self):
|
|
293
280
|
"""
|
|
294
281
|
Event: AUDIO_OUTPUT_STOP
|
|
@@ -336,4 +323,4 @@ class Plugin(BasePlugin):
|
|
|
336
323
|
|
|
337
324
|
:param volume: volume level
|
|
338
325
|
"""
|
|
339
|
-
self.window.
|
|
326
|
+
self.window.controller.audio.ui.on_output_volume_change(int(volume))
|
|
@@ -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)
|