pygpt-net 2.4.28__py3-none-any.whl → 2.4.34__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.
- CHANGELOG.md +40 -0
- README.md +62 -5
- pygpt_net/CHANGELOG.txt +40 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/access/__init__.py +5 -5
- pygpt_net/controller/access/control.py +3 -2
- pygpt_net/controller/attachment.py +67 -1
- pygpt_net/controller/audio/__init__.py +34 -6
- pygpt_net/controller/chat/__init__.py +3 -1
- pygpt_net/controller/chat/attachment.py +239 -37
- pygpt_net/controller/chat/audio.py +99 -0
- pygpt_net/controller/chat/input.py +10 -3
- pygpt_net/controller/chat/output.py +4 -1
- pygpt_net/controller/chat/text.py +10 -5
- pygpt_net/controller/dialogs/confirm.py +17 -1
- pygpt_net/controller/kernel/reply.py +5 -8
- pygpt_net/controller/lang/custom.py +3 -1
- pygpt_net/controller/mode.py +2 -1
- pygpt_net/controller/presets/editor.py +11 -2
- pygpt_net/core/access/voice.py +2 -2
- pygpt_net/core/agents/legacy.py +3 -1
- pygpt_net/core/attachments/__init__.py +11 -7
- pygpt_net/core/attachments/context.py +226 -44
- pygpt_net/core/{audio.py → audio/__init__.py} +1 -1
- pygpt_net/core/audio/context.py +34 -0
- pygpt_net/core/bridge/context.py +29 -1
- pygpt_net/core/bridge/worker.py +16 -1
- pygpt_net/core/ctx/__init__.py +4 -1
- pygpt_net/core/db/__init__.py +4 -2
- pygpt_net/core/debug/attachments.py +3 -1
- pygpt_net/core/debug/context.py +5 -1
- pygpt_net/core/debug/presets.py +3 -1
- pygpt_net/core/docker/__init__.py +170 -16
- pygpt_net/core/docker/builder.py +6 -2
- pygpt_net/core/events/event.py +3 -1
- pygpt_net/core/experts/__init__.py +24 -6
- pygpt_net/core/idx/chat.py +55 -4
- pygpt_net/core/idx/indexing.py +123 -15
- pygpt_net/core/modes.py +3 -1
- pygpt_net/core/presets.py +13 -2
- pygpt_net/core/render/markdown/pid.py +2 -1
- pygpt_net/core/render/plain/pid.py +2 -1
- pygpt_net/core/render/web/body.py +34 -12
- pygpt_net/core/render/web/pid.py +2 -1
- pygpt_net/core/render/web/renderer.py +12 -3
- pygpt_net/core/tokens.py +4 -2
- pygpt_net/core/types/mode.py +2 -1
- pygpt_net/data/config/config.json +7 -4
- pygpt_net/data/config/models.json +191 -6
- pygpt_net/data/config/modes.json +11 -5
- pygpt_net/data/config/presets/current.audio.json +34 -0
- pygpt_net/data/config/settings.json +15 -1
- pygpt_net/data/css/web.css +70 -0
- pygpt_net/data/css/web.dark.css +4 -1
- pygpt_net/data/css/web.light.css +1 -1
- pygpt_net/data/locale/locale.de.ini +33 -20
- pygpt_net/data/locale/locale.en.ini +73 -58
- pygpt_net/data/locale/locale.es.ini +33 -20
- pygpt_net/data/locale/locale.fr.ini +35 -22
- pygpt_net/data/locale/locale.it.ini +33 -20
- pygpt_net/data/locale/locale.pl.ini +36 -23
- pygpt_net/data/locale/locale.uk.ini +33 -20
- pygpt_net/data/locale/locale.zh.ini +40 -27
- pygpt_net/data/locale/plugin.cmd_code_interpreter.de.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.en.ini +15 -7
- pygpt_net/data/locale/plugin.cmd_code_interpreter.es.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.fr.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.it.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.pl.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.uk.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.zh.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_files.de.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.en.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.es.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.fr.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.it.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.pl.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.uk.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.zh.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_system.de.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.en.ini +12 -6
- pygpt_net/data/locale/plugin.cmd_system.es.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.fr.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.it.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.pl.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.uk.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.zh.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_web.de.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.en.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.es.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.fr.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.it.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.pl.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.uk.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.zh.ini +5 -5
- pygpt_net/data/locale/plugin.idx_llama_index.de.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.en.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.es.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.it.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +12 -12
- pygpt_net/item/attachment.py +9 -1
- pygpt_net/item/ctx.py +9 -1
- pygpt_net/item/preset.py +5 -1
- pygpt_net/launcher.py +3 -1
- pygpt_net/migrations/Version20241126170000.py +28 -0
- pygpt_net/migrations/__init__.py +3 -1
- pygpt_net/plugin/audio_input/__init__.py +11 -1
- pygpt_net/plugin/audio_input/worker.py +9 -1
- pygpt_net/plugin/audio_output/__init__.py +37 -7
- pygpt_net/plugin/audio_output/worker.py +38 -41
- pygpt_net/plugin/cmd_code_interpreter/__init__.py +51 -35
- pygpt_net/plugin/cmd_code_interpreter/builder.py +16 -4
- pygpt_net/plugin/cmd_code_interpreter/config.py +98 -39
- pygpt_net/plugin/cmd_code_interpreter/docker.py +4 -0
- pygpt_net/plugin/cmd_code_interpreter/ipython/__init__.py +13 -0
- pygpt_net/plugin/cmd_code_interpreter/{ipython.py → ipython/docker_kernel.py} +10 -3
- pygpt_net/plugin/cmd_code_interpreter/ipython/local_kernel.py +220 -0
- pygpt_net/plugin/cmd_code_interpreter/runner.py +5 -5
- pygpt_net/plugin/cmd_mouse_control/__init__.py +4 -2
- pygpt_net/plugin/cmd_system/config.py +50 -0
- pygpt_net/plugin/cmd_system/docker.py +4 -0
- pygpt_net/plugin/idx_llama_index/__init__.py +23 -1
- pygpt_net/plugin/idx_llama_index/worker.py +10 -0
- pygpt_net/plugin/openai_dalle/__init__.py +3 -1
- pygpt_net/plugin/openai_vision/__init__.py +3 -1
- pygpt_net/provider/core/attachment/json_file.py +4 -1
- pygpt_net/provider/core/config/patch.py +25 -0
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +14 -4
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +19 -2
- pygpt_net/provider/core/model/patch.py +7 -1
- pygpt_net/provider/core/preset/json_file.py +5 -1
- pygpt_net/provider/gpt/__init__.py +14 -2
- pygpt_net/provider/gpt/audio.py +63 -0
- pygpt_net/provider/gpt/chat.py +76 -44
- pygpt_net/provider/gpt/utils.py +27 -0
- pygpt_net/provider/gpt/vision.py +37 -15
- pygpt_net/provider/loaders/base.py +10 -1
- pygpt_net/provider/loaders/web_yt.py +19 -1
- pygpt_net/tools/code_interpreter/__init__.py +1 -0
- pygpt_net/tools/image_viewer/ui/dialogs.py +3 -1
- pygpt_net/ui/dialog/preset.py +3 -1
- pygpt_net/ui/dialog/url.py +29 -0
- pygpt_net/ui/dialogs.py +5 -1
- pygpt_net/ui/layout/chat/attachments.py +42 -6
- pygpt_net/ui/layout/chat/attachments_ctx.py +14 -4
- pygpt_net/ui/layout/chat/attachments_uploaded.py +8 -4
- pygpt_net/ui/layout/toolbox/agent.py +8 -7
- pygpt_net/ui/layout/toolbox/agent_llama.py +5 -4
- pygpt_net/ui/layout/toolbox/prompt.py +8 -6
- pygpt_net/ui/menu/tools.py +17 -11
- pygpt_net/ui/widget/anims/toggles.py +167 -0
- pygpt_net/ui/widget/dialog/url.py +59 -0
- pygpt_net/ui/widget/element/group.py +2 -1
- pygpt_net/ui/widget/lists/attachment.py +22 -17
- pygpt_net/ui/widget/lists/attachment_ctx.py +65 -3
- pygpt_net/ui/widget/option/checkbox.py +69 -5
- pygpt_net/ui/widget/option/cmd.py +4 -5
- pygpt_net/ui/widget/option/toggle.py +62 -0
- pygpt_net/ui/widget/option/toggle_label.py +79 -0
- pygpt_net/ui/widget/textarea/url.py +43 -0
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/METADATA +65 -7
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/RECORD +168 -154
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/entry_points.txt +0 -0
@@ -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: 2024.11.
|
9
|
+
# Updated Date: 2024.11.26 19:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from httpx_socks import SyncProxyTransport
|
@@ -15,6 +15,7 @@ from openai import OpenAI, DefaultHttpxClient
|
|
15
15
|
|
16
16
|
from pygpt_net.core.types import (
|
17
17
|
MODE_ASSISTANT,
|
18
|
+
MODE_AUDIO,
|
18
19
|
MODE_CHAT,
|
19
20
|
MODE_COMPLETION,
|
20
21
|
MODE_IMAGE,
|
@@ -22,6 +23,7 @@ from pygpt_net.core.types import (
|
|
22
23
|
)
|
23
24
|
from pygpt_net.core.bridge.context import BridgeContext
|
24
25
|
|
26
|
+
from .audio import Audio
|
25
27
|
from .assistants import Assistants
|
26
28
|
from .chat import Chat
|
27
29
|
from .completion import Completion
|
@@ -40,6 +42,7 @@ class Gpt:
|
|
40
42
|
"""
|
41
43
|
self.window = window
|
42
44
|
self.assistants = Assistants(window)
|
45
|
+
self.audio = Audio(window)
|
43
46
|
self.chat = Chat(window)
|
44
47
|
self.completion = Completion(window)
|
45
48
|
self.image = Image(window)
|
@@ -114,7 +117,7 @@ class Gpt:
|
|
114
117
|
used_tokens = self.completion.get_used_tokens()
|
115
118
|
|
116
119
|
# chat
|
117
|
-
elif mode
|
120
|
+
elif mode in [MODE_CHAT, MODE_AUDIO]:
|
118
121
|
response = self.chat.send(
|
119
122
|
context=context,
|
120
123
|
extra=extra,
|
@@ -187,6 +190,15 @@ class Gpt:
|
|
187
190
|
ctx.tool_calls = self.window.core.command.unpack_tool_calls(
|
188
191
|
response.choices[0].message.tool_calls,
|
189
192
|
)
|
193
|
+
# audio
|
194
|
+
elif mode in [MODE_AUDIO]:
|
195
|
+
if response.choices[0]:
|
196
|
+
if response.choices[0].message and response.choices[0].message.audio:
|
197
|
+
ctx.audio_output = response.choices[0].message.audio.data
|
198
|
+
ctx.audio_id = response.choices[0].message.audio.id
|
199
|
+
ctx.audio_expires_ts = response.choices[0].message.audio.expires_at
|
200
|
+
ctx.is_audio = True
|
201
|
+
output = response.choices[0].message.audio.transcript # from transcript
|
190
202
|
|
191
203
|
ctx.set_output(output, ai_name)
|
192
204
|
ctx.set_tokens(
|
@@ -0,0 +1,63 @@
|
|
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: 2024.11.26 19:00:00 #
|
10
|
+
# ================================================== #
|
11
|
+
|
12
|
+
import base64
|
13
|
+
|
14
|
+
from pygpt_net.core.bridge.context import MultimodalContext
|
15
|
+
|
16
|
+
|
17
|
+
class Audio:
|
18
|
+
def __init__(self, window=None):
|
19
|
+
"""
|
20
|
+
Audio input wrapper
|
21
|
+
|
22
|
+
:param window: Window instance
|
23
|
+
"""
|
24
|
+
self.window = window
|
25
|
+
|
26
|
+
def build_content(
|
27
|
+
self,
|
28
|
+
content,
|
29
|
+
multimodal_ctx: MultimodalContext = None,
|
30
|
+
) -> list:
|
31
|
+
"""
|
32
|
+
Build audio content
|
33
|
+
|
34
|
+
:param content: previous content or input prompt
|
35
|
+
:param multimodal_ctx: multimodal context
|
36
|
+
:return: List of contents
|
37
|
+
"""
|
38
|
+
if not isinstance(content, list):
|
39
|
+
if content:
|
40
|
+
content = [
|
41
|
+
{
|
42
|
+
"type": "text",
|
43
|
+
"text": str(content),
|
44
|
+
}
|
45
|
+
]
|
46
|
+
else:
|
47
|
+
content = [] # if empty input return empty list
|
48
|
+
|
49
|
+
# abort if no audio input provided
|
50
|
+
if not multimodal_ctx.is_audio_input:
|
51
|
+
return content
|
52
|
+
|
53
|
+
encoded = base64.b64encode(multimodal_ctx.audio_data).decode('utf-8')
|
54
|
+
audio_format = multimodal_ctx.audio_format # wav by default
|
55
|
+
audio_data = {
|
56
|
+
"type": "input_audio",
|
57
|
+
"input_audio": {
|
58
|
+
"data": encoded,
|
59
|
+
"format": audio_format,
|
60
|
+
}
|
61
|
+
}
|
62
|
+
content.append(audio_data)
|
63
|
+
return content
|
pygpt_net/provider/gpt/chat.py
CHANGED
@@ -6,20 +6,22 @@
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
7
7
|
# MIT License #
|
8
8
|
# Created By : Marcin Szczygliński #
|
9
|
-
# Updated Date: 2024.11.
|
9
|
+
# Updated Date: 2024.11.26 19:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import json
|
13
|
-
import
|
13
|
+
import time
|
14
14
|
|
15
15
|
from pygpt_net.core.types import (
|
16
16
|
MODE_CHAT,
|
17
17
|
MODE_VISION,
|
18
|
+
MODE_AUDIO,
|
18
19
|
)
|
19
|
-
from pygpt_net.core.bridge.context import BridgeContext
|
20
|
+
from pygpt_net.core.bridge.context import BridgeContext, MultimodalContext
|
20
21
|
from pygpt_net.item.ctx import CtxItem
|
21
22
|
from pygpt_net.item.model import ModelItem
|
22
23
|
|
24
|
+
from .utils import sanitize_name
|
23
25
|
|
24
26
|
class Chat:
|
25
27
|
def __init__(self, window=None):
|
@@ -31,7 +33,11 @@ class Chat:
|
|
31
33
|
self.window = window
|
32
34
|
self.input_tokens = 0
|
33
35
|
|
34
|
-
def send(
|
36
|
+
def send(
|
37
|
+
self,
|
38
|
+
context: BridgeContext,
|
39
|
+
extra: dict = None
|
40
|
+
):
|
35
41
|
"""
|
36
42
|
Call OpenAI API for chat
|
37
43
|
|
@@ -43,9 +49,11 @@ class Chat:
|
|
43
49
|
stream = context.stream
|
44
50
|
max_tokens = int(context.max_tokens or 0)
|
45
51
|
system_prompt = context.system_prompt
|
52
|
+
mode = context.mode
|
46
53
|
model = context.model
|
47
54
|
functions = context.external_functions
|
48
55
|
attachments = context.attachments
|
56
|
+
multimodal_ctx = context.multimodal_ctx
|
49
57
|
|
50
58
|
ctx = context.ctx
|
51
59
|
if ctx is None:
|
@@ -64,6 +72,7 @@ class Chat:
|
|
64
72
|
attachments=attachments,
|
65
73
|
ai_name=ai_name,
|
66
74
|
user_name=user_name,
|
75
|
+
multimodal_ctx=multimodal_ctx,
|
67
76
|
)
|
68
77
|
msg_tokens = self.window.core.tokens.from_messages(
|
69
78
|
messages,
|
@@ -79,25 +88,24 @@ class Chat:
|
|
79
88
|
# extra API kwargs
|
80
89
|
response_kwargs = {}
|
81
90
|
|
82
|
-
# tools / functions
|
91
|
+
# tools / functions >>>>>>>>>> TMP DISABLED FOR AUDIO <<<<<<<<<<
|
83
92
|
tools = []
|
84
|
-
if
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
params
|
91
|
-
|
92
|
-
{
|
93
|
+
if mode not in [MODE_AUDIO]:
|
94
|
+
if functions is not None and isinstance(functions, list):
|
95
|
+
for function in functions:
|
96
|
+
if str(function['name']).strip() == '' or function['name'] is None:
|
97
|
+
continue
|
98
|
+
params = {}
|
99
|
+
if function['params'] is not None and function['params'] != "":
|
100
|
+
params = json.loads(function['params']) # unpack JSON from string
|
101
|
+
tools.append({
|
93
102
|
"type": "function",
|
94
103
|
"function": {
|
95
104
|
"name": function['name'],
|
96
105
|
"parameters": params,
|
97
106
|
"description": function['desc'],
|
98
107
|
}
|
99
|
-
}
|
100
|
-
)
|
108
|
+
})
|
101
109
|
|
102
110
|
# fix: o1 compatibility
|
103
111
|
if model.id is not None and not model.id.startswith("o1"):
|
@@ -117,11 +125,24 @@ class Chat:
|
|
117
125
|
if model.id is not None and model.id.startswith("o1"):
|
118
126
|
stream = False
|
119
127
|
|
128
|
+
# audio mode
|
129
|
+
if mode in [MODE_AUDIO]:
|
130
|
+
stream = False
|
131
|
+
voice_id = "alloy"
|
132
|
+
tmp_voice = self.window.core.plugins.get_option("audio_output", "openai_voice")
|
133
|
+
if tmp_voice:
|
134
|
+
voice_id = tmp_voice
|
135
|
+
response_kwargs["modalities"] = ["text", "audio"]
|
136
|
+
response_kwargs["audio"] = {
|
137
|
+
"voice": voice_id,
|
138
|
+
"format": "wav"
|
139
|
+
}
|
140
|
+
|
120
141
|
response = client.chat.completions.create(
|
121
142
|
messages=messages,
|
122
143
|
model=model.id,
|
123
144
|
stream=stream,
|
124
|
-
**response_kwargs
|
145
|
+
**response_kwargs,
|
125
146
|
)
|
126
147
|
return response
|
127
148
|
|
@@ -133,7 +154,8 @@ class Chat:
|
|
133
154
|
history: list = None,
|
134
155
|
attachments: dict = None,
|
135
156
|
ai_name: str = None,
|
136
|
-
user_name: str = None
|
157
|
+
user_name: str = None,
|
158
|
+
multimodal_ctx: MultimodalContext = None,
|
137
159
|
) -> list:
|
138
160
|
"""
|
139
161
|
Build list of chat messages
|
@@ -145,6 +167,7 @@ class Chat:
|
|
145
167
|
:param attachments: attachments
|
146
168
|
:param ai_name: AI name
|
147
169
|
:param user_name: username
|
170
|
+
:param multimodal_ctx: Multimodal context
|
148
171
|
:return: messages list
|
149
172
|
"""
|
150
173
|
messages = []
|
@@ -190,26 +213,49 @@ class Chat:
|
|
190
213
|
)
|
191
214
|
for item in items:
|
192
215
|
# input
|
193
|
-
role_name = "system"
|
194
|
-
if not allowed_system:
|
195
|
-
role_name = "user"
|
196
216
|
if item.final_input is not None and item.final_input != "":
|
197
|
-
messages.append({
|
217
|
+
messages.append({
|
218
|
+
"role": "user",
|
219
|
+
"name": sanitize_name(user_name),
|
220
|
+
"content": item.final_input,
|
221
|
+
})
|
198
222
|
|
199
223
|
# output
|
200
|
-
role_name = "system"
|
201
|
-
if not allowed_system:
|
202
|
-
role_name = "assistant"
|
203
224
|
if item.final_output is not None and item.final_output != "":
|
204
|
-
|
205
|
-
|
206
|
-
|
225
|
+
msg = {
|
226
|
+
"role": "assistant",
|
227
|
+
"name": sanitize_name(ai_name),
|
228
|
+
"content": item.final_output,
|
229
|
+
}
|
230
|
+
# append previous audio ID
|
231
|
+
if MODE_AUDIO in model.mode and item.audio_id:
|
232
|
+
# at first check expires_at - expired audio throws error in API
|
233
|
+
current_timestamp = time.time()
|
234
|
+
audio_timestamp = int(item.audio_expires_ts) if item.audio_expires_ts else 0
|
235
|
+
if audio_timestamp and audio_timestamp > current_timestamp:
|
236
|
+
msg["audio"] = {
|
237
|
+
"id": item.audio_id
|
238
|
+
}
|
239
|
+
messages.append(msg)
|
240
|
+
|
241
|
+
# use vision and audio if available in current model
|
207
242
|
content = str(prompt)
|
208
243
|
if MODE_VISION in model.mode:
|
209
|
-
content = self.window.core.gpt.vision.build_content(
|
244
|
+
content = self.window.core.gpt.vision.build_content(
|
245
|
+
content=content,
|
246
|
+
attachments=attachments,
|
247
|
+
)
|
248
|
+
if MODE_AUDIO in model.mode:
|
249
|
+
content = self.window.core.gpt.audio.build_content(
|
250
|
+
content=content,
|
251
|
+
multimodal_ctx=multimodal_ctx,
|
252
|
+
)
|
210
253
|
|
211
254
|
# append current prompt
|
212
|
-
messages.append({
|
255
|
+
messages.append({
|
256
|
+
"role": "user",
|
257
|
+
"content": content,
|
258
|
+
})
|
213
259
|
|
214
260
|
# input tokens: update
|
215
261
|
self.input_tokens += self.window.core.tokens.from_messages(
|
@@ -218,20 +264,6 @@ class Chat:
|
|
218
264
|
)
|
219
265
|
return messages
|
220
266
|
|
221
|
-
def sanitize_name(self, name: str) -> str:
|
222
|
-
"""
|
223
|
-
Sanitize name
|
224
|
-
|
225
|
-
:param name: name
|
226
|
-
:return: sanitized name
|
227
|
-
"""
|
228
|
-
if name is None:
|
229
|
-
return ""
|
230
|
-
# allowed characters: a-z, A-Z, 0-9, _, and -
|
231
|
-
name = name.strip().lower()
|
232
|
-
sanitized_name = re.sub(r'[^a-z0-9_-]', '_', name)
|
233
|
-
return sanitized_name[:64] # limit to 64 characters
|
234
|
-
|
235
267
|
def reset_tokens(self):
|
236
268
|
"""Reset input tokens counter"""
|
237
269
|
self.input_tokens = 0
|
@@ -0,0 +1,27 @@
|
|
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: 2024.11.26 19:00:00 #
|
10
|
+
# ================================================== #
|
11
|
+
|
12
|
+
import re
|
13
|
+
|
14
|
+
|
15
|
+
def sanitize_name(name: str) -> str:
|
16
|
+
"""
|
17
|
+
Sanitize name
|
18
|
+
|
19
|
+
:param name: name
|
20
|
+
:return: sanitized name
|
21
|
+
"""
|
22
|
+
if name is None:
|
23
|
+
return ""
|
24
|
+
# allowed characters: a-z, A-Z, 0-9, _, and -
|
25
|
+
name = name.strip().lower()
|
26
|
+
sanitized_name = re.sub(r'[^a-z0-9_-]', '_', name)
|
27
|
+
return sanitized_name[:64] # limit to 64 characters
|
pygpt_net/provider/gpt/vision.py
CHANGED
@@ -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: 2024.11.
|
9
|
+
# Updated Date: 2024.11.26 19:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import base64
|
@@ -109,10 +109,16 @@ class Vision:
|
|
109
109
|
|
110
110
|
# append initial (system) message
|
111
111
|
if system_prompt is not None and system_prompt != "":
|
112
|
-
messages.append({
|
112
|
+
messages.append({
|
113
|
+
"role": "system",
|
114
|
+
"content": system_prompt,
|
115
|
+
})
|
113
116
|
else:
|
114
117
|
if system_prompt is not None and system_prompt != "":
|
115
|
-
messages.append({
|
118
|
+
messages.append({
|
119
|
+
"role": "system",
|
120
|
+
"content": system_prompt,
|
121
|
+
})
|
116
122
|
|
117
123
|
# append messages from context (memory)
|
118
124
|
if self.window.core.config.get('use_context'):
|
@@ -126,15 +132,24 @@ class Vision:
|
|
126
132
|
for item in items:
|
127
133
|
# input
|
128
134
|
if item.final_input is not None and item.final_input != "":
|
129
|
-
messages.append({
|
135
|
+
messages.append({
|
136
|
+
"role": "user",
|
137
|
+
"content": item.final_input,
|
138
|
+
})
|
130
139
|
|
131
140
|
# output
|
132
141
|
if item.final_output is not None and item.final_output != "":
|
133
|
-
messages.append({
|
142
|
+
messages.append({
|
143
|
+
"role": "assistant",
|
144
|
+
"content": item.final_output,
|
145
|
+
})
|
134
146
|
|
135
147
|
# append current prompt
|
136
148
|
content = self.build_content(prompt, attachments)
|
137
|
-
messages.append({
|
149
|
+
messages.append({
|
150
|
+
"role": "user",
|
151
|
+
"content": content,
|
152
|
+
})
|
138
153
|
|
139
154
|
# input tokens: update
|
140
155
|
self.input_tokens += self.window.core.tokens.from_messages(
|
@@ -143,20 +158,27 @@ class Vision:
|
|
143
158
|
)
|
144
159
|
return messages
|
145
160
|
|
146
|
-
def build_content(
|
161
|
+
def build_content(
|
162
|
+
self,
|
163
|
+
content: str or list,
|
164
|
+
attachments: dict = None,
|
165
|
+
) -> list:
|
147
166
|
"""
|
148
|
-
Build vision
|
167
|
+
Build vision content
|
149
168
|
|
150
|
-
:param
|
169
|
+
:param content: content (str or list)
|
151
170
|
:param attachments: attachments (dict, optional)
|
152
171
|
:return: List of contents
|
153
172
|
"""
|
154
|
-
content
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
173
|
+
if not isinstance(content, list):
|
174
|
+
content = [
|
175
|
+
{
|
176
|
+
"type": "text",
|
177
|
+
"text": str(content)
|
178
|
+
}
|
179
|
+
]
|
180
|
+
|
181
|
+
prompt = content[0]['text']
|
160
182
|
|
161
183
|
self.attachments = {} # reset attachments, only current prompt
|
162
184
|
self.urls = []
|
@@ -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: 2024.
|
9
|
+
# Updated Date: 2024.11.26 04:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from llama_index.core.readers.base import BaseReader
|
@@ -75,6 +75,15 @@ class BaseLoader:
|
|
75
75
|
return args.get("url")
|
76
76
|
return ""
|
77
77
|
|
78
|
+
def is_supported_attachment(self, source: str) -> bool:
|
79
|
+
"""
|
80
|
+
Check if attachment is supported by loader
|
81
|
+
|
82
|
+
:param source: attachment source
|
83
|
+
:return: True if supported
|
84
|
+
"""
|
85
|
+
return False
|
86
|
+
|
78
87
|
def get(self) -> BaseReader:
|
79
88
|
"""
|
80
89
|
Get reader instance
|
@@ -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: 2024.
|
9
|
+
# Updated Date: 2024.11.26 04:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from llama_index.core.readers.base import BaseReader
|
@@ -52,3 +52,21 @@ class Loader(BaseLoader):
|
|
52
52
|
args = {}
|
53
53
|
args["ytlinks"] = [kwargs.get("url")] # list of links
|
54
54
|
return args
|
55
|
+
|
56
|
+
def is_supported_attachment(self, source: str) -> bool:
|
57
|
+
"""
|
58
|
+
Check if attachment is supported by loader
|
59
|
+
|
60
|
+
:param source: attachment source
|
61
|
+
:return: True if supported
|
62
|
+
"""
|
63
|
+
yt_prefix = [
|
64
|
+
"https://youtube.com",
|
65
|
+
"https://youtu.be",
|
66
|
+
"https://www.youtube.com",
|
67
|
+
"https://m.youtube.com",
|
68
|
+
]
|
69
|
+
for prefix in yt_prefix:
|
70
|
+
if source.startswith(prefix):
|
71
|
+
return True
|
72
|
+
return False
|
@@ -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: 2024.
|
9
|
+
# Updated Date: 2024.11.26 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import Qt
|
@@ -17,6 +17,8 @@ from pygpt_net.ui.widget.dialog.base import BaseDialog
|
|
17
17
|
from pygpt_net.ui.widget.image.display import ImageLabel
|
18
18
|
from pygpt_net.utils import trans
|
19
19
|
|
20
|
+
import pygpt_net.icons_rc
|
21
|
+
|
20
22
|
class DialogSpawner:
|
21
23
|
def __init__(self, window=None):
|
22
24
|
"""
|
pygpt_net/ui/dialog/preset.py
CHANGED
@@ -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: 2024.11.
|
9
|
+
# Updated Date: 2024.11.26 19:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import Qt
|
@@ -15,6 +15,7 @@ from PySide6.QtWidgets import QPushButton, QHBoxLayout, QLabel, QVBoxLayout, QSp
|
|
15
15
|
from pygpt_net.core.types import (
|
16
16
|
MODE_AGENT,
|
17
17
|
MODE_AGENT_LLAMA,
|
18
|
+
MODE_AUDIO,
|
18
19
|
MODE_CHAT,
|
19
20
|
MODE_COMPLETION,
|
20
21
|
MODE_EXPERT,
|
@@ -108,6 +109,7 @@ class Preset(BaseConfigDialog):
|
|
108
109
|
MODE_LLAMA_INDEX,
|
109
110
|
MODE_AGENT_LLAMA,
|
110
111
|
MODE_AGENT,
|
112
|
+
MODE_AUDIO,
|
111
113
|
MODE_EXPERT,
|
112
114
|
]
|
113
115
|
rows_mode = QVBoxLayout()
|
@@ -0,0 +1,29 @@
|
|
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: 2024.11.26 02:00:00 #
|
10
|
+
# ================================================== #
|
11
|
+
|
12
|
+
from pygpt_net.ui.widget.dialog.url import UrlDialog
|
13
|
+
from pygpt_net.utils import trans
|
14
|
+
|
15
|
+
|
16
|
+
class Url:
|
17
|
+
def __init__(self, window=None):
|
18
|
+
"""
|
19
|
+
URL dialog
|
20
|
+
|
21
|
+
:param window: Window instance
|
22
|
+
"""
|
23
|
+
self.window = window
|
24
|
+
|
25
|
+
def setup(self):
|
26
|
+
"""Setup URL dialog"""
|
27
|
+
id = 'url'
|
28
|
+
self.window.ui.dialog[id] = UrlDialog(self.window, id)
|
29
|
+
self.window.ui.dialog[id].setWindowTitle(trans("dialog.url.title"))
|
pygpt_net/ui/dialogs.py
CHANGED
@@ -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: 2024.11.
|
9
|
+
# Updated Date: 2024.11.26 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import threading
|
@@ -35,6 +35,7 @@ from pygpt_net.ui.dialog.settings import Settings
|
|
35
35
|
from pygpt_net.ui.dialog.snap import Snap
|
36
36
|
from pygpt_net.ui.dialog.start import Start
|
37
37
|
from pygpt_net.ui.dialog.update import Update
|
38
|
+
from pygpt_net.ui.dialog.url import Url
|
38
39
|
from pygpt_net.ui.dialog.workdir import Workdir
|
39
40
|
from pygpt_net.ui.widget.dialog.alert import AlertDialog
|
40
41
|
from pygpt_net.ui.widget.dialog.confirm import ConfirmDialog
|
@@ -66,6 +67,7 @@ class Dialogs:
|
|
66
67
|
self.snap = Snap(self.window)
|
67
68
|
self.start = Start(self.window)
|
68
69
|
self.update = Update(self.window)
|
70
|
+
self.url = Url(self.window)
|
69
71
|
self.workdir = Workdir(self.window)
|
70
72
|
|
71
73
|
def setup(self):
|
@@ -85,6 +87,8 @@ class Dialogs:
|
|
85
87
|
self.snap.setup()
|
86
88
|
self.start.setup()
|
87
89
|
self.update.setup()
|
90
|
+
self.url.setup()
|
91
|
+
|
88
92
|
self.image.setup()
|
89
93
|
self.license.setup()
|
90
94
|
self.logger.setup()
|