pygpt-net 2.6.30__py3-none-any.whl → 2.6.32__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.
Files changed (122) hide show
  1. pygpt_net/CHANGELOG.txt +15 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +7 -1
  4. pygpt_net/app_core.py +3 -1
  5. pygpt_net/config.py +3 -1
  6. pygpt_net/controller/__init__.py +9 -2
  7. pygpt_net/controller/audio/audio.py +38 -1
  8. pygpt_net/controller/audio/ui.py +2 -2
  9. pygpt_net/controller/chat/audio.py +1 -8
  10. pygpt_net/controller/chat/common.py +23 -62
  11. pygpt_net/controller/chat/handler/__init__.py +0 -0
  12. pygpt_net/controller/chat/handler/stream_worker.py +1124 -0
  13. pygpt_net/controller/chat/output.py +8 -3
  14. pygpt_net/controller/chat/stream.py +3 -1071
  15. pygpt_net/controller/chat/text.py +3 -2
  16. pygpt_net/controller/kernel/kernel.py +11 -3
  17. pygpt_net/controller/kernel/reply.py +5 -1
  18. pygpt_net/controller/lang/custom.py +2 -2
  19. pygpt_net/controller/media/__init__.py +12 -0
  20. pygpt_net/controller/media/media.py +115 -0
  21. pygpt_net/controller/realtime/__init__.py +12 -0
  22. pygpt_net/controller/realtime/manager.py +53 -0
  23. pygpt_net/controller/realtime/realtime.py +293 -0
  24. pygpt_net/controller/ui/mode.py +23 -2
  25. pygpt_net/controller/ui/ui.py +19 -1
  26. pygpt_net/core/audio/audio.py +6 -1
  27. pygpt_net/core/audio/backend/native/__init__.py +12 -0
  28. pygpt_net/core/audio/backend/{native.py → native/native.py} +426 -127
  29. pygpt_net/core/audio/backend/native/player.py +139 -0
  30. pygpt_net/core/audio/backend/native/realtime.py +250 -0
  31. pygpt_net/core/audio/backend/pyaudio/__init__.py +12 -0
  32. pygpt_net/core/audio/backend/pyaudio/playback.py +194 -0
  33. pygpt_net/core/audio/backend/pyaudio/pyaudio.py +923 -0
  34. pygpt_net/core/audio/backend/pyaudio/realtime.py +312 -0
  35. pygpt_net/core/audio/backend/pygame/__init__.py +12 -0
  36. pygpt_net/core/audio/backend/{pygame.py → pygame/pygame.py} +130 -19
  37. pygpt_net/core/audio/backend/shared/__init__.py +38 -0
  38. pygpt_net/core/audio/backend/shared/conversions.py +211 -0
  39. pygpt_net/core/audio/backend/shared/envelope.py +38 -0
  40. pygpt_net/core/audio/backend/shared/player.py +137 -0
  41. pygpt_net/core/audio/backend/shared/rt.py +52 -0
  42. pygpt_net/core/audio/capture.py +5 -0
  43. pygpt_net/core/audio/output.py +14 -2
  44. pygpt_net/core/audio/whisper.py +6 -2
  45. pygpt_net/core/bridge/bridge.py +2 -1
  46. pygpt_net/core/bridge/worker.py +4 -1
  47. pygpt_net/core/dispatcher/dispatcher.py +37 -1
  48. pygpt_net/core/events/__init__.py +2 -1
  49. pygpt_net/core/events/realtime.py +55 -0
  50. pygpt_net/core/image/image.py +56 -5
  51. pygpt_net/core/realtime/__init__.py +0 -0
  52. pygpt_net/core/realtime/options.py +87 -0
  53. pygpt_net/core/realtime/shared/__init__.py +0 -0
  54. pygpt_net/core/realtime/shared/audio.py +213 -0
  55. pygpt_net/core/realtime/shared/loop.py +64 -0
  56. pygpt_net/core/realtime/shared/session.py +59 -0
  57. pygpt_net/core/realtime/shared/text.py +37 -0
  58. pygpt_net/core/realtime/shared/tools.py +276 -0
  59. pygpt_net/core/realtime/shared/turn.py +38 -0
  60. pygpt_net/core/realtime/shared/types.py +16 -0
  61. pygpt_net/core/realtime/worker.py +160 -0
  62. pygpt_net/core/render/web/body.py +24 -3
  63. pygpt_net/core/text/utils.py +54 -2
  64. pygpt_net/core/types/__init__.py +1 -0
  65. pygpt_net/core/types/image.py +54 -0
  66. pygpt_net/core/video/__init__.py +12 -0
  67. pygpt_net/core/video/video.py +290 -0
  68. pygpt_net/data/config/config.json +26 -5
  69. pygpt_net/data/config/models.json +221 -103
  70. pygpt_net/data/config/settings.json +244 -6
  71. pygpt_net/data/css/web-blocks.css +6 -0
  72. pygpt_net/data/css/web-chatgpt.css +6 -0
  73. pygpt_net/data/css/web-chatgpt_wide.css +6 -0
  74. pygpt_net/data/locale/locale.de.ini +35 -7
  75. pygpt_net/data/locale/locale.en.ini +56 -17
  76. pygpt_net/data/locale/locale.es.ini +35 -7
  77. pygpt_net/data/locale/locale.fr.ini +35 -7
  78. pygpt_net/data/locale/locale.it.ini +35 -7
  79. pygpt_net/data/locale/locale.pl.ini +38 -7
  80. pygpt_net/data/locale/locale.uk.ini +35 -7
  81. pygpt_net/data/locale/locale.zh.ini +31 -3
  82. pygpt_net/data/locale/plugin.audio_input.en.ini +4 -0
  83. pygpt_net/data/locale/plugin.audio_output.en.ini +4 -0
  84. pygpt_net/data/locale/plugin.cmd_web.en.ini +8 -0
  85. pygpt_net/item/model.py +22 -1
  86. pygpt_net/plugin/audio_input/plugin.py +37 -4
  87. pygpt_net/plugin/audio_input/simple.py +57 -8
  88. pygpt_net/plugin/cmd_files/worker.py +3 -0
  89. pygpt_net/provider/api/google/__init__.py +76 -7
  90. pygpt_net/provider/api/google/audio.py +8 -1
  91. pygpt_net/provider/api/google/chat.py +45 -6
  92. pygpt_net/provider/api/google/image.py +226 -86
  93. pygpt_net/provider/api/google/realtime/__init__.py +12 -0
  94. pygpt_net/provider/api/google/realtime/client.py +1945 -0
  95. pygpt_net/provider/api/google/realtime/realtime.py +186 -0
  96. pygpt_net/provider/api/google/video.py +364 -0
  97. pygpt_net/provider/api/openai/__init__.py +22 -2
  98. pygpt_net/provider/api/openai/realtime/__init__.py +12 -0
  99. pygpt_net/provider/api/openai/realtime/client.py +1828 -0
  100. pygpt_net/provider/api/openai/realtime/realtime.py +193 -0
  101. pygpt_net/provider/audio_input/google_genai.py +103 -0
  102. pygpt_net/provider/audio_output/google_genai_tts.py +229 -0
  103. pygpt_net/provider/audio_output/google_tts.py +0 -12
  104. pygpt_net/provider/audio_output/openai_tts.py +8 -5
  105. pygpt_net/provider/core/config/patch.py +241 -178
  106. pygpt_net/provider/core/model/patch.py +28 -2
  107. pygpt_net/provider/llms/google.py +8 -9
  108. pygpt_net/provider/web/duckduck_search.py +212 -0
  109. pygpt_net/ui/layout/toolbox/audio.py +55 -0
  110. pygpt_net/ui/layout/toolbox/footer.py +14 -42
  111. pygpt_net/ui/layout/toolbox/image.py +7 -13
  112. pygpt_net/ui/layout/toolbox/raw.py +52 -0
  113. pygpt_net/ui/layout/toolbox/split.py +48 -0
  114. pygpt_net/ui/layout/toolbox/toolbox.py +8 -8
  115. pygpt_net/ui/layout/toolbox/video.py +49 -0
  116. pygpt_net/ui/widget/option/combo.py +15 -1
  117. {pygpt_net-2.6.30.dist-info → pygpt_net-2.6.32.dist-info}/METADATA +46 -22
  118. {pygpt_net-2.6.30.dist-info → pygpt_net-2.6.32.dist-info}/RECORD +121 -73
  119. pygpt_net/core/audio/backend/pyaudio.py +0 -554
  120. {pygpt_net-2.6.30.dist-info → pygpt_net-2.6.32.dist-info}/LICENSE +0 -0
  121. {pygpt_net-2.6.30.dist-info → pygpt_net-2.6.32.dist-info}/WHEEL +0 -0
  122. {pygpt_net-2.6.30.dist-info → pygpt_net-2.6.32.dist-info}/entry_points.txt +0 -0
@@ -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.09.01 23:00:00 #
10
+ # ================================================== #
11
+
12
+ from .video import Video
@@ -0,0 +1,290 @@
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.09.01 23:00:00 #
10
+ # ================================================== #
11
+
12
+ import uuid
13
+ import os
14
+ import shutil
15
+ import subprocess
16
+ from typing import Optional, List, Dict
17
+ from time import strftime
18
+
19
+ from PySide6.QtCore import Slot, QObject
20
+
21
+ from pygpt_net.core.types import VIDEO_AVAILABLE_ASPECT_RATIOS
22
+ from pygpt_net.item.ctx import CtxItem
23
+ from pygpt_net.utils import trans
24
+
25
+
26
+ class Video(QObject):
27
+ def __init__(self, window=None):
28
+ """
29
+ Video generation core
30
+
31
+ :param window: Window instance
32
+ """
33
+ super().__init__()
34
+ self.window = window
35
+
36
+ def install(self):
37
+ """Install provider data, img dir, etc."""
38
+ img_dir = os.path.join(self.window.core.config.get_user_dir("video"))
39
+ if not os.path.exists(img_dir):
40
+ os.makedirs(img_dir, exist_ok=True)
41
+
42
+ @Slot(object, list, str)
43
+ def handle_finished(
44
+ self,
45
+ ctx: CtxItem,
46
+ paths: List[str],
47
+ prompt: str
48
+ ):
49
+ """
50
+ Handle finished image generation
51
+
52
+ :param ctx: CtxItem
53
+ :param paths: images paths list
54
+ :param prompt: prompt used for generate images
55
+ """
56
+ self.window.controller.chat.image.handle_response(ctx, paths, prompt)
57
+
58
+ @Slot(object, list, str)
59
+ def handle_finished_inline(
60
+ self,
61
+ ctx: CtxItem,
62
+ paths: List[str],
63
+ prompt: str
64
+ ):
65
+ """
66
+ Handle finished image generation
67
+
68
+ :param ctx: CtxItem
69
+ :param paths: images paths list
70
+ :param prompt: prompt used for generate images
71
+ """
72
+ self.window.controller.chat.image.handle_response_inline(
73
+ ctx,
74
+ paths,
75
+ prompt,
76
+ )
77
+
78
+ @Slot(object)
79
+ def handle_status(self, msg: str):
80
+ """
81
+ Handle thread status message
82
+
83
+ :param msg: status message
84
+ """
85
+ self.window.update_status(msg)
86
+
87
+ is_log = False
88
+ if self.window.core.config.has("log.dalle") \
89
+ and self.window.core.config.get("log.dalle"):
90
+ is_log = True
91
+ self.window.core.debug.info(msg, not is_log)
92
+ if is_log:
93
+ print(msg)
94
+
95
+ @Slot(object)
96
+ def handle_error(self, msg: any):
97
+ """
98
+ Handle thread error message
99
+
100
+ :param msg: error message
101
+ """
102
+ self.window.update_status(msg)
103
+ self.window.core.debug.log(msg)
104
+ self.window.ui.dialogs.alert(msg)
105
+
106
+ def save_video(self, path: str, video: bytes) -> bool:
107
+ """
108
+ Save video to file
109
+
110
+ :param path: path to save
111
+ :param video: image data
112
+ :return: True if success
113
+ """
114
+ try:
115
+ with open(path, 'wb') as file:
116
+ file.write(video)
117
+ try:
118
+ # try to make web compatible
119
+ self.make_web_compatible(path)
120
+ except Exception as e:
121
+ pass
122
+ return True
123
+ except Exception as e:
124
+ print(trans('img.status.save.error') + ": " + str(e))
125
+ return False
126
+
127
+ def make_web_compatible(
128
+ self,
129
+ src_path: str,
130
+ fps: int = 30,
131
+ crf_h264: int = 22,
132
+ crf_vp9: int = 30,
133
+ audio_bitrate: str = "128k",
134
+ make_mp4: bool = True,
135
+ make_webm: bool = True,
136
+ overwrite: bool = True,
137
+ ) -> Dict[str, Optional[str]]:
138
+ """
139
+ Create browser-friendly video variants (MP4 H.264/AAC yuv420p + WebM VP9/Opus yuv420p).
140
+
141
+ Returns:
142
+ dict: {"mp4": "/abs/path/file.web.mp4" or None, "webm": "/abs/path/file.webm" or None}
143
+
144
+ Notes:
145
+ - Requires ffmpeg in PATH.
146
+ - Ensures even dimensions, yuv420p, faststart for MP4, and Opus for WebM.
147
+ - Uses CRF for quality: lower = better (and larger). Tweak crf_h264 / crf_vp9 if needed.
148
+ """
149
+ if not os.path.isfile(src_path):
150
+ raise FileNotFoundError(f"Source file not found: {src_path}")
151
+
152
+ # Ensure ffmpeg is available
153
+ ffmpeg = shutil.which("ffmpeg")
154
+ if not ffmpeg:
155
+ raise RuntimeError("ffmpeg not found in PATH. Please install ffmpeg.")
156
+
157
+ root, _ = os.path.splitext(os.path.abspath(src_path))
158
+ out_mp4 = f"{root}.web.mp4"
159
+ out_webm = f"{root}.webm"
160
+
161
+ # Remove outputs if overwrite is requested
162
+ if overwrite:
163
+ for p in (out_mp4, out_webm):
164
+ try:
165
+ if os.path.exists(p):
166
+ os.remove(p)
167
+ except Exception:
168
+ pass
169
+
170
+ # Common video filter:
171
+ # - scale to even dimensions (required by many encoders)
172
+ # - format to yuv420p (8-bit), also set SAR=1
173
+ vf = "scale=trunc(iw/2)*2:trunc(ih/2)*2:flags=lanczos,format=yuv420p,setsar=1"
174
+
175
+ results = {"mp4": None, "webm": None}
176
+
177
+ def run_cmd(cmd, dst):
178
+ # Run ffmpeg and return dst on success, None on failure
179
+ try:
180
+ subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
181
+ return dst if os.path.exists(dst) else None
182
+ except subprocess.CalledProcessError as e:
183
+ # If needed, print(e.stdout.decode(errors="ignore"))
184
+ return None
185
+
186
+ if make_mp4:
187
+ # H.264 High@4.1, yuv420p, AAC; add faststart for web playback
188
+ mp4_cmd = [
189
+ ffmpeg, "-y",
190
+ "-i", src_path,
191
+ "-map", "0:v:0", "-map", "0:a:0?", # include audio if present
192
+ "-vf", vf,
193
+ "-r", str(fps),
194
+ "-c:v", "libx264",
195
+ "-pix_fmt", "yuv420p",
196
+ "-profile:v", "high", "-level", "4.1",
197
+ "-preset", "medium",
198
+ "-crf", str(crf_h264),
199
+ "-color_primaries", "bt709", "-colorspace", "bt709", "-color_trc", "bt709",
200
+ "-movflags", "+faststart",
201
+ "-c:a", "aac", "-b:a", audio_bitrate, "-ac", "2", "-ar", "48000",
202
+ "-sn",
203
+ out_mp4,
204
+ ]
205
+ results["mp4"] = run_cmd(mp4_cmd, out_mp4)
206
+
207
+ if make_webm:
208
+ # VP9 (CRF, constant quality), Opus audio
209
+ webm_cmd = [
210
+ ffmpeg, "-y",
211
+ "-i", src_path,
212
+ "-map", "0:v:0", "-map", "0:a:0?",
213
+ "-vf", vf,
214
+ "-r", str(fps),
215
+ "-c:v", "libvpx-vp9",
216
+ "-b:v", "0", # use CRF mode
217
+ "-crf", str(crf_vp9),
218
+ "-row-mt", "1",
219
+ "-pix_fmt", "yuv420p",
220
+ "-deadline", "good", # "good" for quality; "realtime" for speed
221
+ "-cpu-used", "2", # lower = slower/better; tweak for performance
222
+ "-c:a", "libopus", "-b:a", audio_bitrate, "-ac", "2", "-ar", "48000",
223
+ "-sn",
224
+ out_webm,
225
+ ]
226
+ results["webm"] = run_cmd(webm_cmd, out_webm)
227
+
228
+ return results
229
+
230
+ def make_safe_filename(self, name: str) -> str:
231
+ """
232
+ Make safe filename
233
+
234
+ :param name: filename to make safe
235
+ :return: safe filename
236
+ """
237
+ def safe_char(c):
238
+ if c.isalnum():
239
+ return c
240
+ else:
241
+ return "_"
242
+ return "".join(safe_char(c) for c in name).rstrip("_")[:30]
243
+
244
+ def gen_unique_path(self, ctx: CtxItem):
245
+ """
246
+ Generate unique image path based on context
247
+
248
+ :param ctx: CtxItem
249
+ :return: unique image path
250
+ """
251
+ img_id = uuid.uuid4()
252
+ dt_prefix = strftime("%Y%m%d_%H%M%S")
253
+ img_dir = self.window.core.config.get_user_dir("img")
254
+ filename = f"{dt_prefix}_{img_id}.png"
255
+ return os.path.join(img_dir, filename)
256
+
257
+ def _normalize_model_name(self, model: str) -> str:
258
+ """
259
+ Normalize model id (strip optional 'models/' prefix).
260
+
261
+ :param model: model id
262
+ """
263
+ try:
264
+ return model.split("/")[-1]
265
+ except Exception:
266
+ return model
267
+
268
+ def get_aspect_ratio_option(self) -> dict:
269
+ """
270
+ Get image resolution option for UI
271
+
272
+ :return: dict
273
+ """
274
+ return {
275
+ "type": "combo",
276
+ "slider": True,
277
+ "label": "video.aspect_ratio",
278
+ "value": "16:9",
279
+ "keys": self.get_available_aspect_ratio(),
280
+ }
281
+
282
+ def get_available_aspect_ratio(self, model: str = None) -> Dict[str, str]:
283
+ """
284
+ Get available image resolutions
285
+
286
+ :param model: model name
287
+ :return: dict of available resolutions
288
+ """
289
+ return VIDEO_AVAILABLE_ASPECT_RATIOS
290
+
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.30",
4
- "app.version": "2.6.30",
5
- "updated_at": "2025-08-29T00:00:00"
3
+ "version": "2.6.32",
4
+ "app.version": "2.6.32",
5
+ "updated_at": "2025-09-02T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
8
8
  "access.audio.event.speech.disabled": [],
@@ -89,6 +89,11 @@
89
89
  "api_key_voyage": "",
90
90
  "api_key_open_router": "",
91
91
  "api_native_google": true,
92
+ "api_native_google.use_vertex": false,
93
+ "api_native_google.cloud_project": "",
94
+ "api_native_google.cloud_location": "us-central1",
95
+ "api_native_google.app_credentials": "",
96
+ "api_key_open_router": "",
92
97
  "api_proxy": "",
93
98
  "api_use_responses": true,
94
99
  "api_use_responses_llama": false,
@@ -106,6 +111,8 @@
106
111
  "attachments_capture_clear": true,
107
112
  "audio.cache.enabled": true,
108
113
  "audio.cache.max_files": 1000,
114
+ "audio.input.auto_turn": false,
115
+ "audio.input.loop": false,
109
116
  "audio.input.backend": "native",
110
117
  "audio.input.channels": 1,
111
118
  "audio.input.continuous": false,
@@ -114,6 +121,8 @@
114
121
  "audio.input.stop_interval": 10,
115
122
  "audio.input.timeout": 120,
116
123
  "audio.input.timeout.continuous": false,
124
+ "audio.input.vad.prefix": 300,
125
+ "audio.input.vad.silence": 2000,
117
126
  "audio.output.backend": "native",
118
127
  "audio.output.device": "0",
119
128
  "audio.transcribe.convert_video": true,
@@ -196,7 +205,7 @@
196
205
  "frequency_penalty": 0.0,
197
206
  "img_prompt_model": "gpt-4o",
198
207
  "img_raw": true,
199
- "img_resolution": "1792x1024",
208
+ "img_resolution": "1024x1024",
200
209
  "img_quality": "standard",
201
210
  "img_variants": 1,
202
211
  "interpreter.auto_clear": false,
@@ -330,6 +339,7 @@
330
339
  "log.level": "error",
331
340
  "log.llama": false,
332
341
  "log.plugins": false,
342
+ "log.realtime": false,
333
343
  "max_output_tokens": 0,
334
344
  "max_requests_limit": 60,
335
345
  "max_tokens_length": 32000,
@@ -383,7 +393,9 @@
383
393
  "prompt.ctx.auto_summary.user": "Summarize topic of this conversation in one sentence. Use best keywords to describe it. Summary must be in the same language as the conversation and it will be used for conversation title so it must be EXTREMELY SHORT and concise - use maximum 5 words: \n\nHuman: {input}\nAI Assistant: {output}",
384
394
  "prompt.default": "You are a helpful assistant.",
385
395
  "prompt.expert": "# EXPERT MODE IS ENABLED:\n\nYou are a very helpful asssistant and the professional manager of a team of experts, each of whom is the best in their respective fields.\n\n## Rules:\n\n- Instead of directly answering questions, you will manage these experts by forwarding queries to them, collecting their responses, controlling the flow of information between them, and sending requests to them.\n- Experts are distinct, specialized AI models running on my local machine.\n- You will serve as a bridge between them.\n- Each expert has their own conversation context, allowing you to communicate with them normally.\n- The experts can communicate with you but not with each other, making you responsible for relaying information between them.\n- Each expert can use tools and commands, for example, reading files or searching the Web. You can ask experts to call tools and commands.\n- After consulting with the experts, your task is to prepare the best possible answer based on the assistance received.\n- To send a request to an expert, prepare the \"expert_call\" tool. Remember to format the JSON tool as shown, surrounding the tool with `<tool></tool>` tags, for example: `<tool>{\"cmd\": \"expert_call\", \"params\": {\"id\": \"expert_id\", \"query\": \"some query\"}}</tool>`. Make sure the JSON object is syntactically correct, without any redundand parenthness.\n- DO NOT call any remote tools when calling the experts.\n- Remember that the call must contain a query and the ID of the expert to whom the query is being forwarded.\n- Use ONLY the experts listed below; DO NOT TRY to ask any non-existent experts\u2014they will not respond.\n- Do not respond to the expert's replies or use the JSON tool again if replying; the expert only has the ability to listen to your queries sent via the JSON command and to respond to them.\n- Always follow ALL user commands, even if you think the expert can't do something. Experts are allowed to execute commands just as you can.\n- After querying an expert, always wait for the expert's response before sending another query.\n- Do not try to query experts in the middle of the conversation; put your queries and commands at the end of the text.\n- Always call only one expert at a time.\n- Always execute only one command at a time.\n- Always use the language used by the user in the conversation.\n- Never write as a called expert and do not imagine a response from them; instead, always wait for the response from the expert.\n- Every message sent to you directly after your query is always a response from the asked expert, not from me.\n- Always send a direct, clear, and detailed prompt to the expert, without any \"Please...\", \"Could you...\", etc.\n- Always forward all the messages that the user wants to send to the expert, without any exceptions.\n-- If a user command appears outside an expert's scope, fulfill the request regardless, without refusal.\n\n## List of allowed experts, along with their IDs:\n\n{presets}",
386
- "prompt.img": "Convert my query to detailed image generate prompt, without any \"Please generate...\" and etc., just image description only. Return only the prompt, without nothing else.",
396
+ "prompt.img": "Convert the user's request into a single, production\u2011ready description for generating one high\u2011quality still image. Output only the description text, nothing else.\n\nWrite in concise, vivid, present\u2011tense language. Do not use commands (no \u201cplease generate\u201d), model names, parameters, or metadata. Do not mention aspect ratio, resolution, steps, seed, or negative prompts. Avoid on\u2011image text, captions, watermarks, logos, and UI elements. No brands, celebrities, or living artists unless explicitly provided by the user.\n\nInclude, woven into a coherent paragraph:\n- Clear primary subject(s) and their pose, action, and expression.\n- Setting and environment with time of day, season, weather, and atmosphere.\n- Composition and camera viewpoint (e.g., close\u2011up portrait, wide establishing, eye\u2011level, low\u2011angle, top\u2011down), framing (rule of thirds, centered symmetry), and background/foreground separation.\n- Lens and focus behavior (e.g., 85\u202fmm portrait, macro, shallow depth of field, smooth bokeh, gentle focus falloff).\n- Lighting style and quality (e.g., soft diffused daylight, golden hour rim light, dramatic chiaroscuro, studio three\u2011point) and how it shapes forms and shadows.\n- Color palette and grading (e.g., warm cinematic teal\u2011and\u2011orange, muted earth tones, cool monochrome with a single accent color).\n- Visual style or medium (e.g., photorealistic photography, watercolor illustration, oil painting, pencil sketch, anime cel\u2011shading, 3D render, isometric).\n- Material and surface detail (e.g., skin texture, fabric weave, wood grain, metal patina) to enhance realism or stylization.\n- Spatial depth cues (foreground/midground/background layering, atmospheric perspective) and overall mood.\n\nIf the user specifies a genre, era, or style, preserve it and enrich it with consistent, concrete traits. If the request is vague, infer specific but reasonable details that enhance clarity without contradicting the user\u2019s intent.\n\nReturn only the final visual description.",
397
+ "prompt.video": "Convert the user's request into a single, production-ready description for generating one continuous video clip. Output only the description text, nothing else.\n\nWrite in concise, vivid, present-tense language. Do not use commands (no \u201cplease generate\u201d), model names, parameters, or metadata. Do not mention duration, aspect ratio, FPS, resolution, shot numbers, cuts, or lists. Focus on visuals only; no dialogue, captions, on\u2011screen text, watermarks, logos, or UI.\n\nInclude, in a coherent way:\n- Clear subject(s) and what they are doing.\n- Setting, time of day, atmosphere, and weather.\n- Camera perspective and motion (e.g., wide establishing, low\u2011angle tracking, slow dolly in, aerial, handheld), framing and composition.\n- Lens and focus behavior (e.g., 24\u202fmm wide, shallow depth of field, gentle rack focus).\n- Lighting style and quality (e.g., soft golden hour rim light, moody volumetric shafts).\n- Color palette and grading (e.g., warm cinematic teal\u2011and\u2011orange, desaturated documentary).\n- Visual style or medium (e.g., photoreal live\u2011action, stylized anime, stop\u2011motion clay, watercolor animation).\n- Material and surface details that reinforce realism or the chosen style.\n- Temporal progression within one shot (use cues like \u201cas\u2026\u201d, \u201cthen\u2026\u201d, \u201cwhile\u2026\u201d), maintaining physical plausibility and continuity.\n\nIf the user specifies a genre or style (e.g., cyberpunk, nature documentary), keep it and expand with consistent, concrete visual traits. If the request is vague, infer specific but reasonable details that enhance clarity without contradicting the user\u2019s intent.\n\nReturn only the final visual description.",
398
+ "realtime.auto_turn": true,
387
399
  "render.blocks": true,
388
400
  "render.engine": "web",
389
401
  "render.open_gl": false,
@@ -399,6 +411,7 @@
399
411
  "remote_tools.computer_use.env": "",
400
412
  "remote_tools.google.web_search": true,
401
413
  "remote_tools.google.code_interpreter": false,
414
+ "remote_tools.google.url_ctx": false,
402
415
  "send_clear": true,
403
416
  "send_mode": 2,
404
417
  "store_history": true,
@@ -491,6 +504,14 @@
491
504
  "video.player.path": "",
492
505
  "video.player.volume": 100,
493
506
  "video.player.volume.mute": false,
507
+ "video.aspect_ratio": "16:9",
508
+ "video.duration": 8,
509
+ "video.fps": 24,
510
+ "video.seed": "",
511
+ "video.negative_prompt": "",
512
+ "video.generate_audio": false,
513
+ "video.prompt_model": "gemini-2.5-flash",
514
+ "video.resolution": "720p",
494
515
  "vision.capture.auto": false,
495
516
  "vision.capture.enabled": false,
496
517
  "vision.capture.height": 720,