pygpt-net 2.6.19.post1__py3-none-any.whl → 2.6.21__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 +14 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +3 -1
- pygpt_net/controller/agent/agent.py +130 -2
- pygpt_net/controller/agent/experts.py +93 -96
- pygpt_net/controller/agent/llama.py +2 -1
- pygpt_net/controller/assistant/assistant.py +18 -1
- pygpt_net/controller/attachment/attachment.py +17 -1
- pygpt_net/controller/camera/camera.py +15 -7
- pygpt_net/controller/chat/chat.py +2 -2
- pygpt_net/controller/chat/common.py +50 -33
- pygpt_net/controller/chat/image.py +67 -77
- pygpt_net/controller/chat/input.py +94 -166
- pygpt_net/controller/chat/output.py +83 -140
- pygpt_net/controller/chat/response.py +83 -102
- pygpt_net/controller/chat/text.py +116 -149
- pygpt_net/controller/ctx/common.py +2 -1
- pygpt_net/controller/ctx/ctx.py +86 -6
- pygpt_net/controller/files/files.py +13 -1
- pygpt_net/controller/idx/idx.py +26 -2
- pygpt_net/controller/kernel/reply.py +53 -66
- pygpt_net/controller/kernel/stack.py +16 -16
- pygpt_net/controller/model/importer.py +2 -1
- pygpt_net/controller/model/model.py +62 -3
- pygpt_net/controller/settings/editor.py +4 -4
- pygpt_net/controller/ui/ui.py +16 -2
- pygpt_net/core/agents/observer/evaluation.py +3 -3
- pygpt_net/core/agents/provider.py +25 -3
- pygpt_net/core/agents/runner.py +4 -1
- pygpt_net/core/agents/runners/llama_workflow.py +19 -7
- pygpt_net/core/agents/runners/loop.py +3 -1
- pygpt_net/core/agents/runners/openai_workflow.py +17 -3
- pygpt_net/core/agents/tools.py +4 -1
- pygpt_net/core/bridge/context.py +34 -37
- pygpt_net/core/ctx/ctx.py +1 -1
- pygpt_net/core/db/database.py +2 -2
- pygpt_net/core/debug/debug.py +12 -1
- pygpt_net/core/dispatcher/dispatcher.py +24 -1
- pygpt_net/core/events/app.py +7 -7
- pygpt_net/core/events/control.py +26 -26
- pygpt_net/core/events/event.py +6 -3
- pygpt_net/core/events/kernel.py +2 -2
- pygpt_net/core/events/render.py +13 -13
- pygpt_net/core/experts/experts.py +76 -82
- pygpt_net/core/experts/worker.py +12 -12
- pygpt_net/core/models/models.py +5 -1
- pygpt_net/core/models/ollama.py +14 -5
- pygpt_net/core/render/web/helpers.py +2 -2
- pygpt_net/core/render/web/renderer.py +4 -4
- pygpt_net/core/types/__init__.py +2 -1
- pygpt_net/core/types/agent.py +4 -4
- pygpt_net/core/types/base.py +19 -0
- pygpt_net/core/types/console.py +6 -6
- pygpt_net/core/types/mode.py +8 -8
- pygpt_net/core/types/multimodal.py +3 -3
- pygpt_net/core/types/openai.py +2 -1
- pygpt_net/data/config/config.json +4 -4
- pygpt_net/data/config/models.json +19 -3
- pygpt_net/data/config/settings.json +14 -14
- pygpt_net/data/locale/locale.en.ini +2 -2
- pygpt_net/item/ctx.py +256 -240
- pygpt_net/item/model.py +59 -116
- pygpt_net/item/preset.py +122 -105
- pygpt_net/plugin/server/__init__.py +12 -0
- pygpt_net/plugin/server/config.py +301 -0
- pygpt_net/plugin/server/plugin.py +111 -0
- pygpt_net/plugin/server/worker.py +1057 -0
- pygpt_net/provider/agents/llama_index/workflow/planner.py +3 -3
- pygpt_net/provider/agents/openai/agent.py +4 -12
- pygpt_net/provider/agents/openai/agent_b2b.py +10 -15
- pygpt_net/provider/agents/openai/agent_planner.py +4 -4
- pygpt_net/provider/agents/openai/agent_with_experts.py +3 -7
- pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -8
- pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -8
- pygpt_net/provider/agents/openai/bot_researcher.py +2 -18
- pygpt_net/provider/agents/openai/bots/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/planner_agent.py +1 -1
- pygpt_net/provider/agents/openai/bots/research_bot/agents/search_agent.py +1 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/writer_agent.py +1 -1
- pygpt_net/provider/agents/openai/bots/research_bot/manager.py +1 -10
- pygpt_net/provider/agents/openai/evolve.py +5 -9
- pygpt_net/provider/agents/openai/supervisor.py +4 -8
- pygpt_net/provider/core/config/patch.py +10 -3
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +43 -43
- pygpt_net/provider/core/model/patch.py +11 -1
- pygpt_net/provider/core/preset/json_file.py +47 -49
- pygpt_net/provider/gpt/agents/experts.py +2 -2
- pygpt_net/ui/base/config_dialog.py +17 -3
- pygpt_net/ui/widget/option/checkbox.py +16 -2
- {pygpt_net-2.6.19.post1.dist-info → pygpt_net-2.6.21.dist-info}/METADATA +30 -6
- {pygpt_net-2.6.19.post1.dist-info → pygpt_net-2.6.21.dist-info}/RECORD +93 -88
- {pygpt_net-2.6.19.post1.dist-info → pygpt_net-2.6.21.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.19.post1.dist-info → pygpt_net-2.6.21.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.19.post1.dist-info → pygpt_net-2.6.21.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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.23 15:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -14,7 +14,7 @@ import os
|
|
|
14
14
|
from PySide6.QtGui import QTextCursor
|
|
15
15
|
from PySide6.QtWidgets import QFileDialog, QApplication
|
|
16
16
|
|
|
17
|
-
from pygpt_net.core.events import Event, AppEvent, RenderEvent
|
|
17
|
+
from pygpt_net.core.events import Event, AppEvent, RenderEvent, KernelEvent
|
|
18
18
|
from pygpt_net.core.types import MODE_ASSISTANT
|
|
19
19
|
from pygpt_net.item.ctx import CtxItem
|
|
20
20
|
from pygpt_net.item.model import ModelItem
|
|
@@ -250,6 +250,21 @@ class Common:
|
|
|
250
250
|
unlock = False
|
|
251
251
|
return unlock
|
|
252
252
|
|
|
253
|
+
def auto_unlock(self, ctx: CtxItem) -> bool:
|
|
254
|
+
"""
|
|
255
|
+
Auto unlock input after end
|
|
256
|
+
|
|
257
|
+
:param ctx: CtxItem
|
|
258
|
+
:return: True if unlocked
|
|
259
|
+
"""
|
|
260
|
+
# don't unlock input and leave stop btn if assistant mode or if agent/autonomous is enabled
|
|
261
|
+
# send btn will be unlocked in agent mode on stop
|
|
262
|
+
if self.can_unlock(ctx):
|
|
263
|
+
if not self.window.controller.kernel.stopped():
|
|
264
|
+
self.unlock_input() # unlock input
|
|
265
|
+
return True
|
|
266
|
+
return False
|
|
267
|
+
|
|
253
268
|
def stop(self, exit: bool = False):
|
|
254
269
|
"""
|
|
255
270
|
Stop all
|
|
@@ -257,41 +272,42 @@ class Common:
|
|
|
257
272
|
:param exit: True if called on app exit
|
|
258
273
|
"""
|
|
259
274
|
QApplication.processEvents()
|
|
260
|
-
|
|
261
|
-
|
|
275
|
+
|
|
276
|
+
core = self.window.core
|
|
277
|
+
controller = self.window.controller
|
|
278
|
+
dispatch = self.window.dispatch
|
|
279
|
+
dispatch(Event(Event.FORCE_STOP, {
|
|
262
280
|
"value": True,
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
|
|
281
|
+
})) # stop event
|
|
282
|
+
|
|
283
|
+
controller.kernel.stack.clear() # pause reply stack
|
|
284
|
+
controller.agent.experts.stop()
|
|
285
|
+
controller.agent.legacy.on_stop()
|
|
286
|
+
controller.assistant.threads.stop = True
|
|
287
|
+
controller.assistant.threads.reset() # reset run and func calls
|
|
288
|
+
dispatch(Event(Event.AUDIO_INPUT_TOGGLE, {
|
|
266
289
|
"value": False,
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
self.window.controller.assistant.threads.reset() # reset run and func calls
|
|
273
|
-
self.window.dispatch(event) # stop audio input
|
|
274
|
-
self.window.controller.kernel.halt = True
|
|
275
|
-
|
|
276
|
-
event = RenderEvent(RenderEvent.TOOL_END)
|
|
277
|
-
self.window.dispatch(event) # show waiting
|
|
278
|
-
|
|
279
|
-
self.window.core.gpt.stop()
|
|
290
|
+
})) # stop audio input
|
|
291
|
+
controller.kernel.halt = True
|
|
292
|
+
dispatch(RenderEvent(RenderEvent.TOOL_END)) # show waiting
|
|
293
|
+
|
|
294
|
+
core.gpt.stop()
|
|
280
295
|
self.unlock_input()
|
|
281
296
|
|
|
282
|
-
|
|
297
|
+
controller.chat.input.generating = False
|
|
283
298
|
self.window.update_status(trans('status.stopped'))
|
|
284
|
-
|
|
299
|
+
dispatch(KernelEvent(KernelEvent.STATE_IDLE)) # state: idle
|
|
285
300
|
|
|
286
301
|
# remotely stop assistant
|
|
302
|
+
mode = core.config.get('mode')
|
|
287
303
|
if mode == MODE_ASSISTANT and not exit:
|
|
288
304
|
try:
|
|
289
|
-
|
|
305
|
+
controller.assistant.run_stop()
|
|
290
306
|
except Exception as e:
|
|
291
|
-
|
|
307
|
+
core.debug.log(e)
|
|
292
308
|
|
|
293
309
|
if not exit:
|
|
294
|
-
|
|
310
|
+
dispatch(AppEvent(AppEvent.INPUT_STOPPED)) # app event
|
|
295
311
|
|
|
296
312
|
def check_api_key(
|
|
297
313
|
self,
|
|
@@ -310,15 +326,16 @@ class Common:
|
|
|
310
326
|
if model is None:
|
|
311
327
|
return True
|
|
312
328
|
|
|
329
|
+
config = self.window.core.config
|
|
313
330
|
provider_keys = {
|
|
314
|
-
"openai":
|
|
315
|
-
"azure_openai":
|
|
316
|
-
"anthropic":
|
|
317
|
-
"google":
|
|
318
|
-
"x_ai":
|
|
319
|
-
"perplexity":
|
|
320
|
-
"deepseek_api":
|
|
321
|
-
"mistral_ai":
|
|
331
|
+
"openai": config.get('api_key', None),
|
|
332
|
+
"azure_openai": config.get('api_key', None),
|
|
333
|
+
"anthropic": config.get('api_key_anthropic', None),
|
|
334
|
+
"google": config.get('api_key_google', None),
|
|
335
|
+
"x_ai": config.get('api_key_xai', None),
|
|
336
|
+
"perplexity": config.get('api_key_perplexity', None),
|
|
337
|
+
"deepseek_api": config.get('api_key_deepseek', None),
|
|
338
|
+
"mistral_ai": config.get('api_key_mistral', None),
|
|
322
339
|
}
|
|
323
340
|
|
|
324
341
|
if model.provider in provider_keys:
|
|
@@ -6,8 +6,9 @@
|
|
|
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.23 15:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
|
+
|
|
11
12
|
import os
|
|
12
13
|
from typing import Optional, List
|
|
13
14
|
|
|
@@ -33,16 +34,19 @@ class Image:
|
|
|
33
34
|
self,
|
|
34
35
|
text: str,
|
|
35
36
|
prev_ctx: Optional[CtxItem] = None,
|
|
36
|
-
parent_id: Optional[int] = None,
|
|
37
37
|
) -> CtxItem:
|
|
38
38
|
"""
|
|
39
39
|
Send prompt for image generate
|
|
40
40
|
|
|
41
41
|
:param text: prompt for image generation
|
|
42
42
|
:param prev_ctx: previous ctx item
|
|
43
|
-
:param parent_id: parent ctx id
|
|
44
43
|
:return: ctx item
|
|
45
44
|
"""
|
|
45
|
+
core = self.window.core
|
|
46
|
+
controller = self.window.controller
|
|
47
|
+
update_status = self.window.update_status
|
|
48
|
+
dispatch = self.window.dispatch
|
|
49
|
+
|
|
46
50
|
num = int(self.window.ui.config['global']['img_variants'].input.text() or 1)
|
|
47
51
|
if num < 1:
|
|
48
52
|
num = 1
|
|
@@ -50,79 +54,72 @@ class Image:
|
|
|
50
54
|
num = 4
|
|
51
55
|
|
|
52
56
|
# force 1 image if dall-e-3 model is used
|
|
53
|
-
mode =
|
|
54
|
-
model =
|
|
55
|
-
model_data =
|
|
57
|
+
mode = core.config.get('mode')
|
|
58
|
+
model = core.config.get('model')
|
|
59
|
+
model_data = core.models.get(model)
|
|
56
60
|
if model_data.id == 'dall-e-3' or model_data.id == 'gpt-image-1':
|
|
57
61
|
num = 1
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
update_status(trans('status.sending'))
|
|
60
64
|
|
|
61
65
|
# create ctx item
|
|
62
66
|
ctx = CtxItem()
|
|
63
67
|
ctx.current = True # mark as current context item
|
|
64
|
-
ctx.meta =
|
|
65
|
-
ctx.set_input(text,
|
|
68
|
+
ctx.meta = core.ctx.get_current_meta() # CtxMeta (owner object)
|
|
69
|
+
ctx.set_input(text, core.config.get('user_name'))
|
|
66
70
|
ctx.prev_ctx = prev_ctx # store previous context item
|
|
67
71
|
ctx.live = True
|
|
68
72
|
|
|
69
73
|
# event: context before
|
|
70
74
|
event = Event(Event.CTX_BEFORE)
|
|
71
75
|
event.ctx = ctx
|
|
72
|
-
|
|
76
|
+
dispatch(event)
|
|
73
77
|
|
|
74
78
|
# add ctx to DB
|
|
75
|
-
|
|
79
|
+
core.ctx.add(ctx)
|
|
76
80
|
|
|
77
81
|
# render: begin
|
|
78
|
-
|
|
82
|
+
dispatch(RenderEvent(RenderEvent.STREAM_BEGIN, {
|
|
79
83
|
"meta": ctx.meta,
|
|
80
84
|
"ctx": ctx,
|
|
81
85
|
"stream": False,
|
|
82
|
-
}
|
|
83
|
-
event = RenderEvent(RenderEvent.STREAM_BEGIN, data)
|
|
84
|
-
self.window.dispatch(event)
|
|
86
|
+
}))
|
|
85
87
|
|
|
86
|
-
# append input
|
|
87
|
-
|
|
88
|
+
# render: append input
|
|
89
|
+
dispatch(RenderEvent(RenderEvent.INPUT_APPEND, {
|
|
88
90
|
"meta": ctx.meta,
|
|
89
91
|
"ctx": ctx,
|
|
90
|
-
}
|
|
91
|
-
event = RenderEvent(RenderEvent.INPUT_APPEND, data)
|
|
92
|
-
self.window.dispatch(event)
|
|
92
|
+
}))
|
|
93
93
|
|
|
94
94
|
# handle ctx name (generate title from summary if not initialized)
|
|
95
|
-
if
|
|
96
|
-
|
|
95
|
+
if core.config.get('ctx.auto_summary'):
|
|
96
|
+
controller.ctx.prepare_name(ctx)
|
|
97
97
|
|
|
98
98
|
# get attachments
|
|
99
|
-
files =
|
|
99
|
+
files = core.attachments.get_all(mode)
|
|
100
100
|
num_files = len(files)
|
|
101
101
|
if num_files > 0:
|
|
102
|
-
|
|
102
|
+
controller.chat.log(f"Attachments ({mode}): {num_files}")
|
|
103
103
|
|
|
104
104
|
# generate image
|
|
105
|
-
|
|
105
|
+
context = BridgeContext(
|
|
106
106
|
ctx=ctx,
|
|
107
107
|
mode=MODE_IMAGE,
|
|
108
108
|
model=model_data, # model instance
|
|
109
109
|
prompt=text,
|
|
110
110
|
attachments=files,
|
|
111
111
|
)
|
|
112
|
-
extra = {
|
|
113
|
-
"num": num,
|
|
114
|
-
}
|
|
115
112
|
try:
|
|
116
|
-
|
|
117
|
-
'context':
|
|
118
|
-
'extra':
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
dispatch(KernelEvent(KernelEvent.REQUEST, {
|
|
114
|
+
'context': context,
|
|
115
|
+
'extra': {
|
|
116
|
+
"num": num,
|
|
117
|
+
},
|
|
118
|
+
}))
|
|
121
119
|
except Exception as e:
|
|
122
|
-
|
|
120
|
+
core.debug.log(e)
|
|
123
121
|
self.window.ui.dialogs.alert(e)
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
update_status(trans('status.error'))
|
|
126
123
|
return ctx
|
|
127
124
|
|
|
128
125
|
@Slot(object, list, str)
|
|
@@ -139,37 +136,39 @@ class Image:
|
|
|
139
136
|
:param paths: list with paths to downloaded images
|
|
140
137
|
:param prompt: prompt used to generate images
|
|
141
138
|
"""
|
|
142
|
-
self.window.
|
|
139
|
+
core = self.window.core
|
|
140
|
+
dispatch = self.window.dispatch
|
|
141
|
+
|
|
142
|
+
dispatch(KernelEvent(KernelEvent.STATE_IDLE, {
|
|
143
143
|
"id": "img",
|
|
144
144
|
}))
|
|
145
145
|
string = ""
|
|
146
146
|
i = 1
|
|
147
147
|
for path in paths:
|
|
148
148
|
basename = os.path.basename(path)
|
|
149
|
-
string += "[{}]({})
|
|
149
|
+
string += f"[{basename}]({path})\n"
|
|
150
150
|
i += 1
|
|
151
151
|
|
|
152
|
-
if not
|
|
153
|
-
string += "\nPrompt: "
|
|
154
|
-
string += prompt
|
|
152
|
+
if not core.config.get('img_raw'):
|
|
153
|
+
string += f"\nPrompt: {prompt}"
|
|
155
154
|
|
|
156
|
-
local_urls =
|
|
155
|
+
local_urls = core.filesystem.make_local_list(paths)
|
|
157
156
|
ctx.images = local_urls # save images paths
|
|
158
157
|
ctx.set_output(string.strip())
|
|
159
158
|
|
|
160
159
|
# event: after context
|
|
161
160
|
event = Event(Event.CTX_AFTER)
|
|
162
161
|
event.ctx = ctx
|
|
163
|
-
|
|
162
|
+
dispatch(event)
|
|
164
163
|
|
|
165
164
|
# store last mode (in text mode this is handled in send_text)
|
|
166
|
-
mode =
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
mode = core.config.get('mode')
|
|
166
|
+
core.ctx.post_update(mode) # post update context, store last mode, etc.
|
|
167
|
+
core.ctx.store() # save current ctx to DB
|
|
169
168
|
self.window.update_status(trans('status.img.generated'))
|
|
170
169
|
|
|
171
170
|
# update ctx in DB
|
|
172
|
-
|
|
171
|
+
core.ctx.update_item(ctx)
|
|
173
172
|
|
|
174
173
|
self.window.controller.chat.common.unlock_input() # unlock input
|
|
175
174
|
|
|
@@ -187,19 +186,23 @@ class Image:
|
|
|
187
186
|
:param paths: list with paths to downloaded images
|
|
188
187
|
:param prompt: prompt used to generate images
|
|
189
188
|
"""
|
|
190
|
-
self.window.
|
|
189
|
+
core = self.window.core
|
|
190
|
+
controller = self.window.controller
|
|
191
|
+
dispatch = self.window.dispatch
|
|
192
|
+
|
|
193
|
+
dispatch(KernelEvent(KernelEvent.STATE_IDLE, {
|
|
191
194
|
"id": "img",
|
|
192
195
|
}))
|
|
193
196
|
string = ""
|
|
194
197
|
i = 1
|
|
195
198
|
for path in paths:
|
|
196
|
-
string += "{}) `{}
|
|
199
|
+
string += f"{i}) `{path}`\n"
|
|
197
200
|
i += 1
|
|
198
201
|
|
|
199
|
-
local_urls =
|
|
202
|
+
local_urls = core.filesystem.make_local_list(paths)
|
|
200
203
|
ctx.images = local_urls # save images paths in ctx item here
|
|
201
204
|
|
|
202
|
-
|
|
205
|
+
core.ctx.update_item(ctx) # update in DB
|
|
203
206
|
self.window.update_status(trans('status.img.generated')) # update status
|
|
204
207
|
|
|
205
208
|
# WARNING:
|
|
@@ -221,41 +224,28 @@ class Image:
|
|
|
221
224
|
"meta": ctx.meta,
|
|
222
225
|
"ctx": ctx,
|
|
223
226
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
event = RenderEvent(RenderEvent.EXTRA_END, data)
|
|
228
|
-
self.window.dispatch(event) # end extra
|
|
227
|
+
dispatch(RenderEvent(RenderEvent.EXTRA_APPEND, data)) # show image first
|
|
228
|
+
dispatch(RenderEvent(RenderEvent.EXTRA_APPEND, data)) # end extra
|
|
229
229
|
|
|
230
230
|
context = BridgeContext()
|
|
231
231
|
context.ctx = ctx
|
|
232
|
-
|
|
233
|
-
"flush": True,
|
|
234
|
-
}
|
|
235
|
-
event = KernelEvent(KernelEvent.REPLY_ADD, {
|
|
232
|
+
dispatch(KernelEvent(KernelEvent.REPLY_ADD, {
|
|
236
233
|
'context': context,
|
|
237
|
-
'extra':
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
self.window.dispatch(event) # end of tool, hide spinner icon
|
|
234
|
+
'extra': {
|
|
235
|
+
"flush": True,
|
|
236
|
+
},
|
|
237
|
+
}))
|
|
238
|
+
controller.chat.common.unlock_input() # unlock input
|
|
239
|
+
dispatch(RenderEvent(RenderEvent.TOOL_UPDATE, data)) # end of tool, hide spinner icon
|
|
244
240
|
return
|
|
245
241
|
|
|
246
242
|
# NOT internal-mode, user called, so append only img output to chat (show images now):
|
|
247
|
-
|
|
248
243
|
data = {
|
|
249
244
|
"meta": ctx.meta,
|
|
250
245
|
"ctx": ctx,
|
|
251
246
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
event = RenderEvent(RenderEvent.EXTRA_END, data)
|
|
256
|
-
self.window.dispatch(event) # end extra
|
|
257
|
-
|
|
258
|
-
self.window.controller.chat.common.unlock_input() # unlock input
|
|
247
|
+
dispatch(RenderEvent(RenderEvent.EXTRA_APPEND, data)) # show image first
|
|
248
|
+
dispatch(RenderEvent(RenderEvent.EXTRA_END, data)) # end extra
|
|
259
249
|
|
|
260
|
-
|
|
261
|
-
|
|
250
|
+
controller.chat.common.unlock_input() # unlock input
|
|
251
|
+
dispatch(RenderEvent(RenderEvent.TOOL_UPDATE, data)) # end of tool, hide spinner icon
|