aipyapp-qpython 0.1.24.20__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.
aipyapp/saas.py ADDED
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ import os
4
+ from enum import Enum, auto
5
+ from pathlib import Path
6
+ import importlib.resources as resources
7
+
8
+ from rich.console import Console
9
+ from prompt_toolkit import PromptSession
10
+ from prompt_toolkit.history import FileHistory
11
+ from prompt_toolkit.styles import Style
12
+ from prompt_toolkit.completion import WordCompleter
13
+
14
+ from . import __version__
15
+ from .aipy import TaskManager
16
+ from .aipy.i18n import T, set_lang
17
+ from .aipy.config import ConfigManager
18
+
19
+ __PACKAGE_NAME__ = "aipyapp"
20
+
21
+ class CommandType(Enum):
22
+ CMD_DONE = auto()
23
+ CMD_USE = auto()
24
+ CMD_EXIT = auto()
25
+ CMD_INVALID = auto()
26
+ CMD_TEXT = auto()
27
+
28
+ def parse_command(input_str, llms=set()):
29
+ lower = input_str.lower()
30
+
31
+ if lower in ("/done", "done"):
32
+ return CommandType.CMD_DONE, None
33
+ if lower in ("/exit", "exit"):
34
+ return CommandType.CMD_EXIT, None
35
+ if lower in llms:
36
+ return CommandType.CMD_USE, input_str
37
+
38
+ if lower.startswith("/use "):
39
+ arg = input_str[5:].strip()
40
+ if arg in llms:
41
+ return CommandType.CMD_USE, arg
42
+ else:
43
+ return CommandType.CMD_INVALID, arg
44
+
45
+ if lower.startswith("use "):
46
+ arg = input_str[4:].strip()
47
+ if arg in llms:
48
+ return CommandType.CMD_USE, arg
49
+
50
+ return CommandType.CMD_TEXT, input_str
51
+
52
+ class InteractiveConsole():
53
+ def __init__(self, tm, console, settings):
54
+ self.tm = tm
55
+ self.names = tm.llm.names
56
+ completer = WordCompleter(['/use', 'use', '/done','done'] + list(self.names['enabled']), ignore_case=True)
57
+ self.history = FileHistory(str(Path.cwd() / settings.history))
58
+ self.session = PromptSession(history=self.history, completer=completer)
59
+ self.console = console
60
+ self.style_main = Style.from_dict({"prompt": "green"})
61
+ self.style_ai = Style.from_dict({"prompt": "cyan"})
62
+
63
+ def input_with_possible_multiline(self, prompt_text, is_ai=False):
64
+ prompt_style = self.style_ai if is_ai else self.style_main
65
+
66
+ first_line = self.session.prompt([("class:prompt", prompt_text)], style=prompt_style)
67
+ if not first_line.endswith("\\"):
68
+ return first_line
69
+ # Multi-line input
70
+ lines = [first_line.rstrip("\\")]
71
+ while True:
72
+ next_line = self.session.prompt([("class:prompt", "... ")], style=prompt_style)
73
+ if next_line.endswith("\\"):
74
+ lines.append(next_line.rstrip("\\"))
75
+ else:
76
+ lines.append(next_line)
77
+ break
78
+ return "\n".join(lines)
79
+
80
+ def run_task(self, task, instruction=None):
81
+ try:
82
+ task.run(instruction=instruction)
83
+ except (EOFError, KeyboardInterrupt):
84
+ pass
85
+ except Exception as e:
86
+ self.console.print_exception()
87
+
88
+ def start_task_mode(self, task):
89
+ self.console.print(f"{T('ai_mode_enter')}", style="cyan")
90
+ self.run_task(task)
91
+ while True:
92
+ try:
93
+ user_input = self.input_with_possible_multiline(">>> ", is_ai=True).strip()
94
+ if len(user_input) < 2: continue
95
+ except (EOFError, KeyboardInterrupt):
96
+ break
97
+
98
+ cmd, arg = parse_command(user_input, self.names['enabled'])
99
+ if cmd == CommandType.CMD_TEXT:
100
+ self.run_task(task, arg)
101
+ elif cmd == CommandType.CMD_DONE:
102
+ break
103
+ elif cmd == CommandType.CMD_USE:
104
+ ret = self.tm.llm.use(arg)
105
+ self.console.print('[green]Ok[/green]' if ret else '[red]Error[/red]')
106
+ elif cmd == CommandType.CMD_INVALID:
107
+ self.console.print(f'[red]Error: {arg}[/red]')
108
+
109
+ try:
110
+ task.done()
111
+ except Exception as e:
112
+ self.console.print_exception()
113
+ self.console.print(f"{T('ai_mode_exit')}", style="cyan")
114
+
115
+ def run(self):
116
+ self.console.print(f"{T('banner1')}", style="green")
117
+ self.console.print(f"[cyan]{T('default')}: [green]{self.names['default']},[cyan]{T('enabled')}: [yellow]{' '.join(self.names['enabled'])}")
118
+ while True:
119
+ try:
120
+ user_input = self.input_with_possible_multiline(">> ").strip()
121
+ if len(user_input) < 2:
122
+ continue
123
+
124
+ cmd, arg = parse_command(user_input, self.names['enabled'])
125
+ if cmd == CommandType.CMD_TEXT:
126
+ task = self.tm.new_task(arg)
127
+ self.start_task_mode(task)
128
+ elif cmd == CommandType.CMD_USE:
129
+ ret = self.tm.llm.use(arg)
130
+ self.console.print('[green]Ok[/green]' if ret else '[red]Error[/red]')
131
+ elif cmd == CommandType.CMD_INVALID:
132
+ self.console.print('[red]Error[/red]')
133
+ elif cmd == CommandType.CMD_EXIT:
134
+ break
135
+ except (EOFError, KeyboardInterrupt):
136
+ break
137
+
138
+ def main(args):
139
+ console = Console(record=True)
140
+ console.print(f"[bold cyan]🚀 [AIPyApp ({__version__}) on [[green]QPython[/green]][/bold cyan] ")
141
+ console.print(f"[bold cyan]🌐 github.com/qpython-android/aipyapp[/bold cyan] ")
142
+
143
+ path = args.config if args.config else 'aipy.toml'
144
+ lang = os.getenv('LANG')[:2] if os.getenv('LANG') else "en"
145
+ conf_file = lang=="zh" and "default.toml" or "default_en.toml"
146
+ default_config_path = resources.files(__PACKAGE_NAME__) / conf_file
147
+ conf = ConfigManager(default_config_path, path)
148
+ conf.check_config()
149
+ settings = conf.get_config()
150
+
151
+ lang = settings.get('lang') or (os.getenv('LANG')[:2] if os.getenv('LANG') else "en")
152
+ if lang: set_lang(lang)
153
+
154
+ try:
155
+ tm = TaskManager(settings, console=console)
156
+ except Exception as e:
157
+ console.print_exception()
158
+ return
159
+
160
+ if not tm.llm:
161
+ console.print(f"[bold red]{T('no_available_llm')}")
162
+ return
163
+
164
+ if args.cmd:
165
+ tm.new_task(args.cmd).run()
166
+ return
167
+ InteractiveConsole(tm, console, settings).run()
aipyapp/wxgui.py ADDED
@@ -0,0 +1,367 @@
1
+ #!/usr/bin/env python
2
+ #coding: utf-8
3
+
4
+ import os
5
+ import sys
6
+ import time
7
+ import json
8
+ import queue
9
+ import base64
10
+ import mimetypes
11
+ import traceback
12
+ import threading
13
+ import importlib.resources as resources
14
+
15
+ import wx
16
+ import wx.html2
17
+ import matplotlib
18
+ import matplotlib.pyplot as plt
19
+ from rich.console import Console
20
+ from wx.lib.newevent import NewEvent
21
+ from wx import FileDialog, FD_SAVE, FD_OVERWRITE_PROMPT
22
+
23
+ from . import __version__
24
+ from .aipy.config import ConfigManager
25
+ from .aipy import TaskManager, event_bus
26
+ from .aipy.i18n import T,set_lang
27
+
28
+ __PACKAGE_NAME__ = "aipyapp"
29
+ ChatEvent, EVT_CHAT = NewEvent()
30
+ AVATARS = {'我': '🧑', 'BB-8': '🤖', '图灵': '🧠', '爱派': '🐙'}
31
+
32
+ matplotlib.use('Agg')
33
+
34
+ def image_to_base64(file_path):
35
+ mime_type, _ = mimetypes.guess_type(file_path)
36
+ if mime_type is None:
37
+ return None
38
+
39
+ try:
40
+ with open(file_path, "rb") as image_file:
41
+ encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
42
+ except Exception as e:
43
+ return None
44
+
45
+ data_url = f"data:{mime_type};base64,{encoded_string}"
46
+ return data_url
47
+
48
+ class AIPython(threading.Thread):
49
+ def __init__(self, gui):
50
+ super().__init__(daemon=True)
51
+ self.gui = gui
52
+ self.tm = gui.tm
53
+ plt.show = self.on_plt_show
54
+ sys.modules["matplotlib.pyplot"] = plt
55
+
56
+ def on_plt_show(self, *args, **kwargs):
57
+ filename = f'{time.strftime("%Y%m%d_%H%M%S")}.png'
58
+ plt.savefig(filename)
59
+ user = 'BB-8'
60
+ content = f'![{filename}]({filename})'
61
+ evt = ChatEvent(user=user, msg=content)
62
+ wx.PostEvent(self.gui, evt)
63
+
64
+ def on_display(self, image):
65
+ user = '图灵'
66
+ if image['path']:
67
+ base64_data = image_to_base64(image['path'])
68
+ content = base64_data if base64_data else image['path']
69
+ else:
70
+ content = image['url']
71
+
72
+ msg = f'![图片]({content})'
73
+ evt = ChatEvent(user=user, msg=msg)
74
+ wx.PostEvent(self.gui, evt)
75
+
76
+ def on_response_complete(self, msg):
77
+ user = '图灵' #msg['llm']
78
+ #content = f"```markdown\n{msg['content']}\n```"
79
+ evt = ChatEvent(user=user, msg=msg['content'])
80
+ wx.PostEvent(self.gui, evt)
81
+
82
+ def on_summary(self, summary):
83
+ user = '爱派'
84
+ evt = ChatEvent(user=user, msg=f'结束处理指令 {summary}')
85
+ wx.PostEvent(self.gui, evt)
86
+
87
+ def on_exec(self, blocks):
88
+ user = 'BB-8'
89
+ content = f"```python\n{blocks['main']}\n```"
90
+ evt = ChatEvent(user=user, msg=content)
91
+ wx.PostEvent(self.gui, evt)
92
+
93
+ def on_result(self, result):
94
+ user = 'BB-8'
95
+ content = json.dumps(result, indent=4, ensure_ascii=False)
96
+ content = f'运行结果如下\n```json\n{content}\n```'
97
+ evt = ChatEvent(user=user, msg=content)
98
+ wx.PostEvent(self.gui, evt)
99
+
100
+ def run(self):
101
+ event_bus.register("response_stream", self.on_response_complete)
102
+ event_bus.register("exec", self.on_exec)
103
+ event_bus.register("result", self.on_result)
104
+ event_bus.register("summary", self.on_summary)
105
+ event_bus.register("display", self.on_display)
106
+ while True:
107
+ instruction = self.gui.get_task()
108
+ if instruction in ('/done', 'done'):
109
+ self.tm.done()
110
+ elif instruction in ('/exit', 'exit'):
111
+ break
112
+ else:
113
+ try:
114
+ self.tm(instruction)
115
+ except Exception as e:
116
+ traceback.print_exc()
117
+ wx.CallAfter(self.gui.toggle_input)
118
+
119
+ class CStatusBar(wx.StatusBar):
120
+ def __init__(self, parent):
121
+ super().__init__(parent, style=wx.STB_DEFAULT_STYLE)
122
+ self.parent = parent
123
+ self.SetFieldsCount(2)
124
+ self.SetStatusWidths([-1, 80])
125
+
126
+ self.tm = parent.tm
127
+ self.current_llm = self.tm.llm.names['default']
128
+ self.enabled_llm = list(self.tm.llm.names['enabled'])
129
+ self.menu_items = self.enabled_llm
130
+ self.radio_group = []
131
+
132
+ self.SetStatusText(f"{self.current_llm} ▾", 1)
133
+ self.Bind(wx.EVT_LEFT_DOWN, self.on_click)
134
+
135
+ def on_click(self, event):
136
+ rect = self.GetFieldRect(1)
137
+ if rect.Contains(event.GetPosition()):
138
+ self.show_menu()
139
+
140
+ def show_menu(self):
141
+ self.current_menu = wx.Menu()
142
+ self.radio_group = []
143
+ for label in self.menu_items:
144
+ item = wx.MenuItem(self.current_menu, wx.ID_ANY, label, kind=wx.ITEM_RADIO)
145
+ self.current_menu.Append(item)
146
+ self.radio_group.append(item)
147
+ self.Bind(wx.EVT_MENU, self.on_menu_select, item)
148
+
149
+ rect = self.GetFieldRect(1)
150
+ pos = self.ClientToScreen(rect.GetBottomLeft())
151
+ self.PopupMenu(self.current_menu, self.ScreenToClient(pos))
152
+
153
+ def on_menu_select(self, event):
154
+ item = self.current_menu.FindItemById(event.GetId())
155
+ label = item.GetItemLabel()
156
+ if self.tm.use(label):
157
+ self.current_llm = label
158
+ self.SetStatusText(f"{label} ▾", 1)
159
+ else:
160
+ wx.MessageBox(f"LLM {label} 不可用", "警告", wx.OK|wx.ICON_WARNING)
161
+
162
+ class ChatFrame(wx.Frame):
163
+ def __init__(self, tm):
164
+ super().__init__(None, title=f"Python-use: AIPy (v{__version__})", size=(1024, 768))
165
+
166
+ self.tm = tm
167
+ self.task_queue = queue.Queue()
168
+ self.aipython = AIPython(self)
169
+
170
+ icon = wx.Icon(str(resources.files(__PACKAGE_NAME__) / "aipy.ico"), wx.BITMAP_TYPE_ICO)
171
+ self.SetIcon(icon)
172
+
173
+ self.SetBackgroundColour(wx.Colour(245, 245, 245))
174
+ self.make_menu_bar()
175
+ self.make_panel()
176
+ self.statusbar = CStatusBar(self)
177
+ self.SetStatusBar(self.statusbar)
178
+
179
+ self.Bind(EVT_CHAT, self.on_chat)
180
+ self.aipython.start()
181
+ self.Show()
182
+
183
+ def make_panel(self):
184
+ panel = wx.Panel(self)
185
+ vbox = wx.BoxSizer(wx.VERTICAL)
186
+
187
+ html_file_path = os.path.abspath(resources.files(__PACKAGE_NAME__) / "chatroom.html")
188
+ self.webview = wx.html2.WebView.New(panel)
189
+ self.webview.SetPage(open(html_file_path, 'r', encoding='utf-8').read(), f'file://{self.tm.workdir}')
190
+ self.webview.SetWindowStyleFlag(wx.BORDER_NONE)
191
+ vbox.Add(self.webview, proportion=1, flag=wx.EXPAND | wx.ALL, border=12)
192
+
193
+ self.container = wx.Panel(panel)
194
+ vbox.Add(self.container, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=12)
195
+
196
+ self.input = wx.TextCtrl(self.container, style=wx.TE_MULTILINE)
197
+ self.input.SetBackgroundColour(wx.Colour(255, 255, 255))
198
+ self.input.SetForegroundColour(wx.Colour(33, 33, 33))
199
+ self.input.SetMinSize((-1, 60))
200
+ self.input.SetWindowStyleFlag(wx.BORDER_SIMPLE)
201
+ self.input.Bind(wx.EVT_KEY_DOWN, self.on_key_down)
202
+
203
+ self.send_button = wx.Button(self.container, label="发送", size=(50, -1))
204
+ self.send_button.Bind(wx.EVT_BUTTON, self.on_send)
205
+ self.container.Bind(wx.EVT_SIZE, self.on_container_resize)
206
+
207
+ panel.SetSizer(vbox)
208
+ self.panel = panel
209
+
210
+ def make_menu_bar(self):
211
+ menu_bar = wx.MenuBar()
212
+ menu_bar.SetBackgroundColour(wx.Colour(240, 240, 240))
213
+
214
+ file_menu = wx.Menu()
215
+ file_menu.Append(wx.ID_SAVE, "保存聊天记录为 HTML(&S)\tCtrl+S", "保存当前聊天记录为 HTML 文件")
216
+ file_menu.AppendSeparator()
217
+ file_menu.Append(wx.ID_EXIT, "退出(&Q)\tCtrl+Q", "退出程序")
218
+ self.Bind(wx.EVT_MENU, self.on_save_html, id=wx.ID_SAVE)
219
+ self.Bind(wx.EVT_MENU, self.on_exit, id=wx.ID_EXIT)
220
+
221
+ edit_menu = wx.Menu()
222
+ edit_menu.Append(wx.ID_CLEAR, "清空聊天(&C)", "清除所有消息")
223
+ self.Bind(wx.EVT_MENU, self.on_clear_chat, id=wx.ID_CLEAR)
224
+
225
+ help_menu = wx.Menu()
226
+ self.ID_WEBSITE = wx.NewIdRef()
227
+ menu_item = wx.MenuItem(help_menu, self.ID_WEBSITE, "官网(&W)\tCtrl+W", "打开官方网站")
228
+ help_menu.Append(menu_item)
229
+ self.ID_FORUM = wx.NewIdRef()
230
+ menu_item = wx.MenuItem(help_menu, self.ID_FORUM, "论坛(&W)\tCtrl+F", "打开官方论坛")
231
+ help_menu.Append(menu_item)
232
+ self.Bind(wx.EVT_MENU, self.on_open_website, id=self.ID_WEBSITE)
233
+ self.Bind(wx.EVT_MENU, self.on_open_website, id=self.ID_FORUM)
234
+
235
+ menu_bar.Append(file_menu, "文件(&F)")
236
+ menu_bar.Append(edit_menu, "编辑(&E)")
237
+ menu_bar.Append(help_menu, "帮助(&H)")
238
+
239
+ self.SetMenuBar(menu_bar)
240
+
241
+ def on_exit(self, event):
242
+ self.task_queue.put('exit')
243
+ self.aipython.join()
244
+ self.Close()
245
+
246
+ def on_container_resize(self, event):
247
+ # 获取容器和按钮的大小
248
+ container_size = event.GetSize()
249
+ button_size = self.send_button.GetSize()
250
+
251
+ overlap = -10
252
+ self.input.SetSize(container_size)
253
+
254
+ button_pos_x = container_size.width - button_size.width + overlap
255
+ if sys.platform == 'darwin':
256
+ button_pos_y = container_size.height - button_size.height - 10
257
+ else:
258
+ button_pos_y = (container_size.height - button_size.height) // 2
259
+ self.send_button.SetPosition((button_pos_x, button_pos_y))
260
+
261
+ event.Skip()
262
+
263
+ def on_clear_chat(self, event):
264
+ pass
265
+
266
+ def on_open_website(self, event):
267
+ if event.GetId() == self.ID_WEBSITE:
268
+ url = "https://aipy.app"
269
+ elif event.GetId() == self.ID_FORUM:
270
+ url = "https://d.aipy.app"
271
+ wx.LaunchDefaultBrowser(url)
272
+
273
+ def on_save_html(self, event):
274
+ try:
275
+ html_content = self.webview.GetPageSource()
276
+ self.save_html_content(html_content)
277
+ except Exception as e:
278
+ wx.MessageBox(f"save html error: {e}", "Error")
279
+
280
+ def save_html_content(self, html_content):
281
+ with FileDialog(self, "保存聊天记录为 HTML 文件", wildcard="HTML 文件 (*.html)|*.html",
282
+ style=FD_SAVE | FD_OVERWRITE_PROMPT) as dialog:
283
+ if dialog.ShowModal() == wx.ID_CANCEL:
284
+ return
285
+
286
+ path = dialog.GetPath()
287
+ try:
288
+ with open(path, 'w', encoding='utf-8') as file:
289
+ file.write(html_content)
290
+ except IOError:
291
+ wx.LogError(f"无法保存文件:{path}")
292
+
293
+ def on_key_down(self, event):
294
+ keycode = event.GetKeyCode()
295
+ send_shortcut = (event.ControlDown() or event.CmdDown()) and keycode == wx.WXK_RETURN
296
+
297
+ if send_shortcut:
298
+ self.send_message()
299
+ else:
300
+ event.Skip()
301
+
302
+ def on_send(self, event):
303
+ self.send_message()
304
+
305
+ def get_task(self):
306
+ return self.task_queue.get()
307
+
308
+ def toggle_input(self):
309
+ if self.container.IsShown():
310
+ self.container.Hide()
311
+ wx.BeginBusyCursor()
312
+ self.SetStatusText("操作进行中,请稍候...", 0)
313
+ else:
314
+ self.container.Show()
315
+ wx.EndBusyCursor()
316
+ self.SetStatusText("操作完成", 0)
317
+ self.panel.Layout()
318
+ self.panel.Refresh()
319
+
320
+ def send_message(self):
321
+ text = self.input.GetValue().strip()
322
+ if not text:
323
+ return
324
+ self.append_message('我', text)
325
+ self.input.Clear()
326
+ self.toggle_input()
327
+ self.task_queue.put(text)
328
+
329
+ def on_chat(self, event):
330
+ user = event.user
331
+ text = event.msg
332
+ self.append_message(user, text)
333
+
334
+ def append_message(self, user, text):
335
+ avatar = AVATARS[user]
336
+ js_code = f'appendMessage("{avatar}", "{user}", {repr(text)});'
337
+ self.webview.RunScript(js_code)
338
+
339
+ def refresh_chat(self):
340
+ wx.CallLater(100, lambda: self.browser.RunScript("window.scrollTo(0, document.body.scrollHeight);"))
341
+
342
+ def on_stop_task(self, event):
343
+ self.tm.done()
344
+ self.SetStatusText("任务已停止", 0)
345
+
346
+ def main(args):
347
+ default_config_path = resources.files(__PACKAGE_NAME__) / "default.toml"
348
+ conf = ConfigManager(default_config_path, args.config_dir)
349
+ conf.check_config()
350
+ settings = conf.get_config()
351
+
352
+ settings.auto_install = True
353
+ settings.auto_getenv = True
354
+
355
+ lang = settings.get('lang')
356
+ if lang: set_lang(lang)
357
+
358
+ console = Console(quiet=True, record=True)
359
+ try:
360
+ tm = TaskManager(settings, console=console)
361
+ except Exception as e:
362
+ traceback.print_exc()
363
+ return
364
+
365
+ app = wx.App()
366
+ ChatFrame(tm)
367
+ app.MainLoop()
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.4
2
+ Name: aipyapp-qpython
3
+ Version: 0.1.24.20
4
+ Summary: AIPython is a Python command-line interpreter integrated with LLM.
5
+ Home-page: https://qpypi.qpython.org/project/aipyapp-qpython/
6
+ Author: The QPYPI Team
7
+ Author-email: qpypi@qpython.org
8
+ License: GPL-3.0 license
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Education
11
+ Classifier: Intended Audience :: Information Technology
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Operating System :: Android
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development
18
+ Requires-Dist: anthropic-aipy
19
+ Requires-Dist: beautifulsoup4>=4.13.3
20
+ Requires-Dist: dynaconf>=3.2.10
21
+ Requires-Dist: google-api-python-client>=2.166.0
22
+ Requires-Dist: openai-aipy
23
+ Requires-Dist: pandas-aipy
24
+ Requires-Dist: prompt-toolkit>=3.0.50
25
+ Requires-Dist: pygments>=2.19.1
26
+ Requires-Dist: reportlab-qpython
27
+ Requires-Dist: requests>=2.32.3
28
+ Requires-Dist: rich>=13.9.4
29
+ Requires-Dist: seaborn-aipy
30
+ Requires-Dist: term-image-qpython
31
+ Requires-Dist: tomli-w>=1.2.0
32
+ Requires-Dist: qrcode>=8.1
33
+ Dynamic: author
34
+ Dynamic: author-email
35
+ Dynamic: classifier
36
+ Dynamic: description
37
+ Dynamic: home-page
38
+ Dynamic: license
39
+ Dynamic: requires-dist
40
+ Dynamic: summary
41
+
42
+
43
+ Python use provides the entire Python execution environment to LLM. Imagine LLM sitting in front of a computer, typing various commands into the Python command-line interpreter, pressing Enter to execute, observing the results, and then typing and executing more code.
44
+ Unlike Agents, Python use does not define any tools interface. LLM can freely use all the features provided by the Python runtime environment.
@@ -0,0 +1,29 @@
1
+ aipyapp/__init__.py,sha256=ze0el8TqNz2ChMNVS0UjF5WGFbpJc9A6hByCe3evBpM,23
2
+ aipyapp/__main__.py,sha256=Drx9OofPjNU0fedLT0cGuYbNTFezg0ziH8LIs3_FXyw,1233
3
+ aipyapp/default.toml,sha256=9n7CAI3IhzHey7wJEmpSgxsXDts45xnPUH5uHUC3VHk,4532
4
+ aipyapp/default_en.toml,sha256=dPemvTYfB1tr3_a6YaK88c1gIakCTeXEI6OEV_9vKTA,5448
5
+ aipyapp/gui.py,sha256=b5uGERdj4llp-m2aV0RYQNUnK8iKLLwOMOb4uAY3XLM,14674
6
+ aipyapp/main.py,sha256=goUC6EzrFjX0j5k-GTIu7gfGrV07GXjwoTBgilsGWGs,2911
7
+ aipyapp/publish.py,sha256=aOTVYfSOkviOpCmnQ3gwfx4FP1eUBXeQJknhsPPUmKQ,1630
8
+ aipyapp/saas.py,sha256=AlwO4bWfANheWwqGawH-DNI6zCid1DXJ1KE5x4zCUSs,6104
9
+ aipyapp/wxgui.py,sha256=m3pNcTafPV_9ZofnQdtbOizyFu6hLmq09qNOmmNGsPk,12478
10
+ aipyapp/aipy/__init__.py,sha256=VoKgeEboxqMakuDWRyMFaY0omYRDYODaHt9D35RH_Uk,243
11
+ aipyapp/aipy/config.py,sha256=FjSt_LTcrLfAlTP8S_uEXEf-m8_sBunET1bT4uzyb5w,3236
12
+ aipyapp/aipy/i18n.py,sha256=kr3TQ0BLJHNPM4iOk4r54LeDIEVB-CIWegwaDkCu-Go,12779
13
+ aipyapp/aipy/interface.py,sha256=n3zoLDYIR6n45FT8nje2aqE3ZVhjgx38L-rQBtew7po,512
14
+ aipyapp/aipy/llm.py,sha256=6gEbwExL2-cCrbOztSn2xwuspy8jQf9pCUuzbgX_slk,18452
15
+ aipyapp/aipy/plugin.py,sha256=H82T-ysjGwXUpTEiIg9v33eRz6ZPIl5mBAkMHnNCgcw,2734
16
+ aipyapp/aipy/prompt.py,sha256=ISg0pMPs9BL_qW6cwhaVZQOBVqTuTRWzCtblkkunKnc,28087
17
+ aipyapp/aipy/prompt.zh.py,sha256=hzmIqSobpz3J2lPtMsaAeR_DQyxTynSrXHB-DD-oBWs,20885
18
+ aipyapp/aipy/prompt_en.py,sha256=ewE8J98-iGyqMUoWc-inBr9DRZy-APeBo3WyAxQDedo,31318
19
+ aipyapp/aipy/qpython.py,sha256=RcMTPRLOGEBY0oycg6a4ZX1jSLlBgGJVxzpAquQwKJQ,1025
20
+ aipyapp/aipy/runner.py,sha256=qlzBC5Mxpu4yttWnmtYabJL4fSMrSD0F9Aywot4w348,5788
21
+ aipyapp/aipy/task.py,sha256=8k_idh5JifB4dl4B4AEZCUH5sHFiMtKi2E8_aGobj_E,10028
22
+ aipyapp/aipy/taskmgr.py,sha256=mx08QQ1xjOG71SCG4qHd7luqJOHZgUzTEr4XXfS4wJw,3515
23
+ aipyapp/aipy/template.html,sha256=krUZUzRwJLLMAPK1pEUkAxL6v5gPf_ZED1eflC728EU,9630
24
+ aipyapp/aipy/templates.py,sha256=tBs5f76KvEvUhrLflm-d4JCIWHuChk35ouw2A33QfiA,2844
25
+ aipyapp/aipy/utils.py,sha256=5230X-QjVVs8QLZrNleHeJjOzq3A26ZZo-rClm6RYoM,2342
26
+ aipyapp_qpython-0.1.24.20.dist-info/METADATA,sha256=a1sipftimtjnOAz4T8LyWHScdlTdpHOFZrkkB-0ffIo,1812
27
+ aipyapp_qpython-0.1.24.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
+ aipyapp_qpython-0.1.24.20.dist-info/top_level.txt,sha256=azOawjzoa49O02OiwzAm0e07YjYBxElCDecuMTHG74Q,8
29
+ aipyapp_qpython-0.1.24.20.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ aipyapp