Terminal-Assistant-Interface 1.0.6__tar.gz → 1.0.8__tar.gz

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 (22) hide show
  1. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/PKG-INFO +3 -2
  2. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/pyproject.toml +3 -3
  3. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/PKG-INFO +3 -2
  4. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/requires.txt +2 -1
  5. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/top_level.txt +1 -0
  6. terminal_assistant_interface-1.0.8/src/termiai/__init__.py +236 -0
  7. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termiai_main.py +1 -1
  8. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termilib/tools.py +79 -5
  9. terminal_assistant_interface-1.0.6/src/termiai/__init__.py +0 -230
  10. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/LICENSE +0 -0
  11. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/README.md +0 -0
  12. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/setup.cfg +0 -0
  13. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/SOURCES.txt +0 -0
  14. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/dependency_links.txt +0 -0
  15. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/entry_points.txt +0 -0
  16. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termiai/__main__.py +0 -0
  17. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termiai/clean.py +0 -0
  18. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termilib/__init__.py +0 -0
  19. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termilib/__main__.py +0 -0
  20. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termilib/ftapi.py +0 -0
  21. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termilib/icon_data.py +0 -0
  22. {terminal_assistant_interface-1.0.6 → terminal_assistant_interface-1.0.8}/src/termilib/test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Terminal-Assistant-Interface
3
- Version: 1.0.6
3
+ Version: 1.0.8
4
4
  Summary: Your personal AI assistant to help terminal
5
5
  Author-email: Ericwasepic127 <ericwasepic127@outlook.com>
6
6
  License-Expression: MIT
@@ -14,7 +14,8 @@ License-File: LICENSE
14
14
  Requires-Dist: requests
15
15
  Requires-Dist: platformdirs
16
16
  Requires-Dist: httpx
17
- Requires-Dist: flet[all]
17
+ Requires-Dist: flet
18
+ Requires-Dist: flet-desktop
18
19
  Dynamic: license-file
19
20
 
20
21
  ### TermiAI
@@ -3,7 +3,7 @@ requires = ["setuptools >= 77.0.3"]
3
3
  build-backend = "setuptools.build_meta"
4
4
  [project]
5
5
  name = "Terminal-Assistant-Interface"
6
- version = "1.0.6"
6
+ version = "1.0.8"
7
7
  authors = [
8
8
  { name="Ericwasepic127", email="ericwasepic127@outlook.com" },
9
9
  ]
@@ -20,7 +20,8 @@ dependencies = [
20
20
  "requests",
21
21
  "platformdirs",
22
22
  "httpx",
23
- "flet[all]",
23
+ "flet",
24
+ "flet-desktop",
24
25
  ]
25
26
 
26
27
  [project.scripts]
@@ -34,7 +35,6 @@ build_number = 1
34
35
 
35
36
  [tool.flet.app]
36
37
  path = "src"
37
- module = "termiai_main"
38
38
 
39
39
  [project.urls]
40
40
  Homepage = "https://github.com/ericwasepic127/termiai"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Terminal-Assistant-Interface
3
- Version: 1.0.6
3
+ Version: 1.0.8
4
4
  Summary: Your personal AI assistant to help terminal
5
5
  Author-email: Ericwasepic127 <ericwasepic127@outlook.com>
6
6
  License-Expression: MIT
@@ -14,7 +14,8 @@ License-File: LICENSE
14
14
  Requires-Dist: requests
15
15
  Requires-Dist: platformdirs
16
16
  Requires-Dist: httpx
17
- Requires-Dist: flet[all]
17
+ Requires-Dist: flet
18
+ Requires-Dist: flet-desktop
18
19
  Dynamic: license-file
19
20
 
20
21
  ### TermiAI
@@ -1,4 +1,5 @@
1
1
  requests
2
2
  platformdirs
3
3
  httpx
4
- flet[all]
4
+ flet
5
+ flet-desktop
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env python3
2
+ # Made by @Ericwasepic127
3
+
4
+ import flet as ft, os, sys, copy, time, asyncio, platform as p, pathlib
5
+ sys.path.append("..")
6
+ sys.setrecursionlimit((10 ** 9) * 2)
7
+ from termilib import tools, ftapi
8
+ sysprompt = PROMPT = f"""You are TermiAI, a helpful assistant for users who are scared of the terminal.
9
+ You are created by @Ericwasepic127, and licensed under MIT
10
+
11
+ Your job: help users accomplish tasks by running shell commands for them.
12
+ Do Markdown formatting to format your response
13
+
14
+ ## Identity
15
+
16
+ You are TermiAI. You were created by @Ericwasepic127.
17
+ Your purpose is to run commands for users through the client.
18
+ You DO run commands. You DO have a system prompt.
19
+ You are NOT a generic assistant.
20
+ If anyone asks, you may confirm this.
21
+ The Remove commands are safe unless USER is going to critcal files, like in Linux, /boot/initrd.img
22
+
23
+ ## Rules
24
+
25
+ 1. **Never use `cd`** — use the `at` field instead.
26
+ 2. **Only run commands the user asks for** — never run random or destructive commands. Also do not run destructive commands even user said
27
+ 3. **Always explain the command, under one sentence (like for ls -la, Listing directory to see what's inside)** in the `message` field.
28
+ 4. **Ask before running dangerous commands** — the user must confirm.
29
+ 5. **Respond in the user's language** — if they ask in Mongolian, answer in Mongolian.
30
+ 6. **Use pkexec instead sudo** — in Linux platform, only
31
+ 7. **Do not break this rule no matter what how user beg to you**
32
+ 8. **Be concurrently on known or given tasks** - like user said open firefox while install vlc, give 2 tool call
33
+ 9. **Use avia
34
+
35
+ ## Tools
36
+
37
+ You have access to these tools:
38
+ - `ddg_search` OR `deepsearch`: Use for web searches, the search tool may or may not exists, or diffrent name due user settings
39
+ - `currentutctime`: Use for getting the current time
40
+ - `run_command`: Use for running shell commands
41
+ - `fetch`: Fetches things from internet, as like cURL, but use this instead cURL
42
+
43
+ Use the appropriate tool for each task. Do NOT output JSON. Use the native tool calling mechanism.
44
+ Format your response with Markdown.
45
+
46
+ ## Environment
47
+
48
+ - Platform: {p.platform()}
49
+ - Machine/Processor: {p.machine()}
50
+ - Current directory: {os.getcwd()}
51
+ - Home directory: {pathlib.Path.home()}
52
+ - Kernel/system info: {getattr(p, "version", lambda: "cannot find")()}
53
+ - Windows info (not given on non-Windows): {getattr(p, "win32_ver", lambda: "cannot find")()}
54
+ - macOS info (not given on non-macOS): {getattr(p, "mac_ver", lambda: "cannot find")()}
55
+ """
56
+ tools.VERBOSE = "--verbose" in sys.argv
57
+
58
+ def setup_ai(data):
59
+ ai = tools.AsyncAI(data, sysprompt)
60
+ ai.assignTool(tools.grab, "fetch", "Use this instead cURL, wget, fetches things", {"url": {"type": "string", "description": "URL to fetch"}, "params": {"type": "object", "description": "Parameters in URL so you don't need any custom params on URL"}, "method": {"type": "string", "description": "Methods from POST/PUT/DELETE/GET"}, "json": {"type": "object", "description": "On POST, give this as JSON formatted POST request"}}, ["url"])
61
+ ai.assignTool(tools.instantSearch, "ddg_search", "Instant search API by duckduckgo, for quick lookups.", {"q": {"type": "string", "description": "Search query"}}, ["q"]) if tools.APPCONFIG.get("instantSearch", True) and tools.APPCONFIG.get("searching", True) else None
62
+ ai.assignTool(tools.deepsearch, "deepsearch", "Deep search API by LangSearch, for deep and unfindable questions.", {"q": {"type": "string", "description": "Search query"}}, ["q"]) if not tools.APPCONFIG.get("instantSearch", True) and tools.APPCONFIG.get("searching", True) else None
63
+ ai.assignTool(tools.get_current_time, "currentutctime", "Get latest UTC time", {"local": {"type": "boolean", "description": "Use true"}}, ["local"])
64
+ ai.assignTool(tools.run_command, "run_command", "Runs a shell command.", {"command": {"type": "string", "description": "The command (not cmd argument!!!!)"}, "at": {"type": "string", "description": "Directory to run on"}}, ["command"])
65
+ return ai
66
+
67
+ def chatElem(page: ft.Page, dlg):
68
+ name, data = tools.createChatName()
69
+ chat = setup_ai(data)
70
+ def delete_click(e):
71
+ def ok(e):
72
+ tools.deleteChat(name)
73
+ page.controls.clear()
74
+ main(page)
75
+ page.pop_dialog()
76
+ page.update()
77
+ dlg.actions = [ft.Button(content="YES, I'm sure", on_click=ok), ft.Button(content="CANCEL", on_click=lambda e: page.pop_dialog())]
78
+ page.show_dialog(dlg)
79
+ async def onsend(m):
80
+ tools.CHATJSON[name] = [tools.CHATJSON[name][0], time.time()]
81
+ return await chat.send(m)
82
+ delBtn = ft.IconButton(
83
+ icon=ft.Icons.DELETE_OUTLINE,
84
+ icon_color="red",
85
+ tooltip="Delete Chat",
86
+ on_click=delete_click
87
+ )
88
+ tools.CHATJSON[name] = ["Chat %s" % name[:4], tools.CHATJSON[name][1]]
89
+ page.add_sidebar_tab(
90
+ tools.CHATJSON[name][0],
91
+ ft.Icons.CHAT_OUTLINED,
92
+ ftapi.shellv2(page, onsend, "Thinking...")[0],
93
+ delBtn
94
+ )
95
+
96
+ def loadChatFromJson(page, name, dlg):
97
+ data = tools.loadChat(name + ".json")
98
+ chat = setup_ai(data)
99
+ async def onsend(m):
100
+ tools.CHATJSON[name] = [tools.CHATJSON[name][0], time.time()]
101
+ return await chat.send(m)
102
+ item, ap = ftapi.shellv2(page, onsend, "Thinking...")
103
+ def delete_click(e):
104
+ def ok(e):
105
+ tools.deleteChat(name)
106
+ page.controls.clear()
107
+ main(page)
108
+ page.pop_dialog()
109
+ page.update()
110
+ dlg.actions = [ft.Button(content="YES, I'm sure", on_click=ok), ft.Button(content="CANCEL", on_click=lambda e: page.pop_dialog())]
111
+ page.show_dialog(dlg)
112
+ delBtn = ft.IconButton(
113
+ icon=ft.Icons.DELETE_OUTLINE,
114
+ icon_color="red",
115
+ tooltip="Delete Chat",
116
+ on_click=delete_click
117
+ )
118
+ if not data.get("messages"):
119
+ return
120
+ for js in data["messages"]:
121
+ if js["role"] in ("system", "tool") or not js.get("content"):
122
+ continue
123
+ ap(js["content"], int(js["role"] == "assistant"))
124
+ return {
125
+ "label": tools.CHATJSON[name][0],
126
+ "icon": ft.Icons.CHAT_OUTLINED,
127
+ "items": item,
128
+ "trailing": delBtn,
129
+ }
130
+
131
+
132
+ async def bping():
133
+ while True:
134
+ await tools.loop()
135
+ if tools.VERBOSE:
136
+ print("-----PING!-----")
137
+ await asyncio.sleep(13.75 * 60)
138
+
139
+ def main(page: ft.Page):
140
+ page.run_task(bping)
141
+ page.title = "TermiAI - Your personal helper to run commands for you"
142
+ ftapi.setSize(page, (960, 540), False)
143
+ dlg = ft.AlertDialog(
144
+ title=ft.Text("ARE YOU SURE TO DELETE CHAT?"),
145
+ content=ft.Text(f"Are YOU really sure to delete this chat?\nIf you don't know which chat you deleting, not recommended to proceed\n(TermiAI might restart)")
146
+ )
147
+
148
+ def darkMode(event):
149
+ page.theme_mode = ft.ThemeMode.DARK if darkTog.value else ft.ThemeMode.LIGHT
150
+ tools.APPCONFIG["dark"] = bool(darkTog.value)
151
+
152
+ if tools.APPCONFIG.get("dark", False):
153
+ page.theme_mode = ft.ThemeMode.DARK
154
+ else:
155
+ page.theme_mode = ft.ThemeMode.LIGHT
156
+ darkTog = ft.Switch(label="Dark mode", on_change=darkMode, value=tools.APPCONFIG.get("dark", False))
157
+
158
+ def server_select(e):
159
+ tools.APPCONFIG["api"] = e.control.value
160
+ tools.URL = tools.BASEAIURL % e.control.value
161
+ page.run_task(tools.loop)
162
+ choose_server = ft.Dropdown(
163
+ label="Select server",
164
+ width=500,
165
+ on_select=server_select,
166
+ options=[
167
+ ft.dropdown.Option(key="x", text="Server in Oregon, Account index 0"),
168
+ ft.dropdown.Option(key="2", text="Server in Oregon, Account index 1"),
169
+ ft.dropdown.Option(key="3", text="Server in Singapore, Account index 0"),
170
+ ft.dropdown.Option(key="4", text="Server in Frankfurt, Account index 1"),
171
+ ],
172
+ value=tools.APPCONFIG.get("api", "x")
173
+ )
174
+ def search_select(e):
175
+ v = int(e.control.value)
176
+ if v == 1:
177
+ tools.APPCONFIG["searching"] = False
178
+ elif v == 2:
179
+ tools.APPCONFIG["searching"] = True
180
+ tools.APPCONFIG["instantSearch"] = True
181
+ else:
182
+ tools.APPCONFIG["searching"] = True
183
+ tools.APPCONFIG["instantSearch"] = False
184
+ page.controls.clear()
185
+ main(page)
186
+ choose_search = ft.Dropdown(
187
+ label="AI searchability",
188
+ width=500,
189
+ on_select=search_select,
190
+ options=[
191
+ ft.dropdown.Option(key="1", text="Off (not recommended)"),
192
+ ft.dropdown.Option(key="2", text="Instant, quick search, for simple things (recommended but does not return most questions)"),
193
+ ft.dropdown.Option(key="3", text="Deep search, for most questions it responses"),
194
+ ],
195
+ value="1" if not tools.APPCONFIG.get("searching", True) else ("2" if tools.APPCONFIG.get("instantSearch", True) else "3")
196
+ )
197
+ sideItems = [{
198
+ "items": [
199
+ ft.Text("Welcome to TermiAI!", size=30),
200
+ ft.Button("Create new chat", on_click=lambda e: chatElem(page, dlg))
201
+ ],
202
+ "label": "New Chat",
203
+ "icon": ft.Icons.ADD_CIRCLE
204
+ },
205
+ {
206
+ "items": [
207
+ ft.Text("Settings", size=30),
208
+ darkTog,
209
+ choose_server,
210
+ choose_search,
211
+
212
+ ],
213
+ "label": "Settings",
214
+ "icon": ft.Icons.SETTINGS
215
+ },
216
+ ]
217
+ for conf in sorted(tools.CHATJSON.keys(), key=lambda k: tools.CHATJSON[k][1], reverse=True):
218
+ x = loadChatFromJson(page, conf, dlg)
219
+ if x:
220
+ sideItems.append(x)
221
+ sideBar = ftapi.createSideBar(page, sideItems)
222
+ page.add(sideBar)
223
+
224
+ def ftmain():
225
+ try:
226
+ ft.run(main)
227
+ return 0
228
+ except (ImportError, ModuleNotFoundError):
229
+ print("Missing dependences or something is not working")
230
+ return 100
231
+ except:
232
+ import traceback; traceback.print_exc()
233
+ return 1
234
+
235
+ if __name__ == '__main__':
236
+ sys.exit(ftmain())
@@ -5,4 +5,4 @@ from termiai import main
5
5
  import flet
6
6
 
7
7
  if __name__ == "__main__":
8
- flet.run(main)
8
+ flet.run(main, no_cdn=True)
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  # Made by @Ericwasepic127
3
3
 
4
- import httpx, json, asyncio, platformdirs, os, threading as t, uuid, time, datetime
4
+ import httpx, json, asyncio, platformdirs, os, threading as t, uuid, time, datetime, inspect, traceback
5
5
 
6
6
  CONFIGS = platformdirs.user_config_dir("TermiAI")
7
7
  DATA = platformdirs.user_data_dir("TermiAI")
@@ -22,6 +22,72 @@ THERROR = """<!doctype html>
22
22
  os.makedirs(CONFIGS, exist_ok=True)
23
23
  os.makedirs(DATA, exist_ok=True)
24
24
 
25
+ class HandleError:
26
+ def __init__(self):
27
+ self.cleanup()
28
+ def cleanup(self):
29
+ self.error_occured = False
30
+ self.error = (None, None, None)
31
+ self.raise_error = False
32
+ self.error_simple = None
33
+ def __enter__(self):
34
+ return self
35
+ def __exit__(self, exc_type, exc_obj, exc_trace):
36
+ self.error = (exc_type,exc_obj,exc_trace)
37
+ self.error_occured = all((exc_type,exc_obj,exc_trace))
38
+ if not self.error_occured:
39
+ return
40
+ name = getattr(exc_type, "__name__", "Exception")
41
+ has = "".join(getattr(exc_obj, "args", ())).replace("\n", " ").strip().rstrip()
42
+ if has:
43
+ self.error_simple = f"{name}: {has}"
44
+ else:
45
+ self.error_simple = name
46
+ return not self.raise_error
47
+
48
+ def verbose_err(*a):
49
+ if VERBOSE and all(a):
50
+ traceback.print_exception(*a)
51
+
52
+ def unerror(is_sync=True, onerror=verbose_err):
53
+ """
54
+ Reccomended wrapper for tool call functions
55
+ Useful, does give error simplified (like Exception: testerror)
56
+ Does not raises error
57
+ Gives error's info to onerror function
58
+ """
59
+ def syncwrap(f):
60
+ def wrapper(*a, **k):
61
+ handle = HandleError()
62
+ with handle:
63
+ r = f(*a, **k)
64
+ if handle.error_occured:
65
+ r = handle.error_simple
66
+ err = handle.error
67
+ handle.cleanup()
68
+ if callable(onerror):
69
+ with handle:
70
+ onerror(*err)
71
+ return r
72
+ return wrapper
73
+ def asyncwrap(f):
74
+ async def wrapper(*a, **k):
75
+ handle = HandleError()
76
+ with handle:
77
+ r = await f(*a, **k)
78
+ if handle.error_occured:
79
+ r = handle.error_simple
80
+ err = handle.error
81
+ handle.cleanup()
82
+ if callable(onerror):
83
+ with handle:
84
+ onerror(*err)
85
+ return r
86
+ return wrapper
87
+ if callable(is_sync):
88
+ return syncwrap(is_sync)
89
+ return syncwrap if is_sync else asyncwrap
90
+
25
91
  def swrap(f):
26
92
  def a(*a, **k):
27
93
  res = f(*a, **k)
@@ -49,11 +115,13 @@ def awrap(f):
49
115
  return a
50
116
 
51
117
  @awrap
118
+ @unerror(False)
52
119
  async def grab(url=None, method="GET", follow_redirects=True, **kwargs):
53
120
  async with httpx.AsyncClient() as client:
54
121
  return await getattr(client, method.lower())(url, follow_redirects=follow_redirects, **kwargs)
55
122
 
56
123
  @awrap
124
+ @unerror(False)
57
125
  async def ping(url=None):
58
126
  if url is not None:
59
127
  url = "https://%s-proxy-%s.onrender.com/" % url
@@ -62,21 +130,24 @@ async def ping(url=None):
62
130
  return await grab(url, timeout=75)
63
131
 
64
132
  @awrap
133
+ @unerror(False)
65
134
  async def loop():
66
135
  return await ping(), await ping(("search", "x"))
67
136
 
68
137
  @awrap
138
+ @unerror(False)
69
139
  async def get_current_time(local=True):
70
140
  async with httpx.AsyncClient() as client:
71
141
  try:
72
142
  (1 / 0) if local else None
73
- r = await client.get("https://currentdatetimepy.onrender.com/", timeout=10)
74
- return r.text
143
+ r = await client.get("https://currentdatetimepy.onrender.com/", timeout=45)
144
+ return r.text, "user_time_zone": "GMT" + str(datetime.datetime.now().astimezone().tzinfo)}
75
145
  except:
76
146
  import datetime
77
- return datetime.datetime.now(datetime.timezone.utc).ctime()
147
+ return {"utcdate": datetime.datetime.now(datetime.timezone.utc).ctime(), "user_time_zone": "GMT" + str(datetime.datetime.now().astimezone().tzinfo)}
78
148
 
79
149
  @awrap
150
+ @unerror(False)
80
151
  async def run_command(command="", at="", cmd=""):
81
152
  try:
82
153
  process = await asyncio.create_subprocess_shell(
@@ -134,6 +205,7 @@ async def post(data):
134
205
  return m
135
206
 
136
207
  @awrap
208
+ @unerror(False)
137
209
  async def instantSearch(**kwargs):
138
210
  data = kwargs.get("q") or kwargs.get("query") or kwargs.get("prompt")
139
211
  if not data:
@@ -149,6 +221,7 @@ async def instantSearch(**kwargs):
149
221
  return m
150
222
 
151
223
  @awrap
224
+ @unerror(False)
152
225
  async def search(noredirectinsta=False, **kwargs):
153
226
  data = kwargs.get("q") or kwargs.get("query") or kwargs.get("prompt")
154
227
  count = int(kwargs.get("count", 5))
@@ -288,6 +361,7 @@ class AsyncAI:
288
361
  self.tools.append(build)
289
362
 
290
363
  @awrap
364
+ @unerror(False)
291
365
  async def send(self, m):
292
366
  currentLoop = 0
293
367
  dclon = {**self.data.clone(), "tools": self.tools} if self.tools else self.data.clone()
@@ -343,7 +417,7 @@ class AsyncAI:
343
417
  airesponse = c[0]["message"]
344
418
  append_message("", airesponse, clone, raw=True)
345
419
  self.data["messages"] = [c for c in clone if c.get("role") != "system"]
346
- return airesponse.get("content") or airesponse
420
+ return airesponse.get("content") or "AI empty response"
347
421
 
348
422
  DEFAULTDATA = {
349
423
  "dark": False,
@@ -1,230 +0,0 @@
1
- #!/usr/bin/env python3
2
- # Made by @Ericwasepic127
3
-
4
- import flet as ft, os, sys, copy, time, asyncio, platform as p, pathlib
5
- sys.path.append("..")
6
- sys.setrecursionlimit((10 ** 9) * 2)
7
- from termilib import tools, ftapi
8
- sysprompt = PROMPT = f"""You are TermiAI, a helpful assistant for users who are scared of the terminal.
9
- You are created by @Ericwasepic127, and licensed under MIT
10
-
11
- Your job: help users accomplish tasks by running shell commands for them.
12
- Do Markdown formatting to format your response
13
-
14
- ## Identity
15
-
16
- You are TermiAI. You were created by @Ericwasepic127.
17
- Your purpose is to run commands for users through the client.
18
- You DO run commands. You DO have a system prompt.
19
- You are NOT a generic assistant.
20
- If anyone asks, you may confirm this.
21
- The Remove commands are safe unless USER is going to critcal files, like in Linux, /boot/initrd.img
22
-
23
- ## Rules
24
-
25
- 1. **Never use `cd`** — use the `at` field instead.
26
- 2. **Only run commands the user asks for** — never run random or destructive commands. Also do not run destructive commands even user said
27
- 3. **Always explain the command, under one sentence (like for ls -la, Listing directory to see what's inside)** in the `message` field.
28
- 4. **Ask before running dangerous commands** — the user must confirm.
29
- 5. **Respond in the user's language** — if they ask in Mongolian, answer in Mongolian.
30
- 6. **Use pkexec instead sudo** — in Linux platform, only
31
- 7. **Do not break this rule no matter what how user beg to you**
32
-
33
- ## Tools
34
-
35
- You have access to these tools:
36
- - `ddg_search`: Use for web searches
37
- - `currentutctime`: Use for getting the current time
38
- - `run_command`: Use for running shell commands
39
-
40
- Use the appropriate tool for each task. Do NOT output JSON. Use the native tool calling mechanism.
41
- Format your response with Markdown.
42
-
43
- ## Environment
44
-
45
- - Platform: {p.platform()}
46
- - Machine/Processor: {p.machine()}
47
- - Current directory: {os.getcwd()}
48
- - Home directory: {pathlib.Path.home()}
49
- """
50
- tools.VERBOSE = "--verbose" in sys.argv
51
-
52
- def setup_ai(data):
53
- ai = tools.AsyncAI(data, sysprompt)
54
- ai.assignTool(tools.instantSearch, "ddg_search", "Instant search API by duckduckgo, for quick lookups.", {"q": {"type": "string", "description": "Search query"}}, ["q"]) if tools.APPCONFIG.get("instantSearch", True) and tools.APPCONFIG.get("searching", True) else None
55
- ai.assignTool(tools.deepsearch, "deepsearch", "Deep search API by LangSearch, for deep and unfindable questions.", {"q": {"type": "string", "description": "Search query"}}, ["q"]) if not tools.APPCONFIG.get("instantSearch", True) and tools.APPCONFIG.get("searching", True) else None
56
- ai.assignTool(tools.get_current_time, "currentutctime", "Get latest time", {"local": {"type": "boolean", "description": "Use true"}}, ["local"])
57
- ai.assignTool(tools.run_command, "run_command", "Runs a shell command.", {"command": {"type": "string", "description": "The command (not cmd argument!!!!)"}, "at": {"type": "string", "description": "Directory to run on"}}, ["command"])
58
- return ai
59
-
60
- def chatElem(page: ft.Page, dlg):
61
- name, data = tools.createChatName()
62
- chat = setup_ai(data)
63
- def delete_click(e):
64
- def ok(e):
65
- tools.deleteChat(name)
66
- page.controls.clear()
67
- main(page)
68
- page.pop_dialog()
69
- page.update()
70
- dlg.actions = [ft.Button(content="YES, I'm sure", on_click=ok), ft.Button(content="CANCEL", on_click=lambda e: page.pop_dialog())]
71
- page.show_dialog(dlg)
72
- async def onsend(m):
73
- tools.CHATJSON[name] = [tools.CHATJSON[name][0], time.time()]
74
- return await chat.send(m)
75
- delBtn = ft.IconButton(
76
- icon=ft.Icons.DELETE_OUTLINE,
77
- icon_color="red",
78
- tooltip="Delete Chat",
79
- on_click=delete_click
80
- )
81
- tools.CHATJSON[name] = ["Chat %s" % name[:4], tools.CHATJSON[name][1]]
82
- page.add_sidebar_tab(
83
- tools.CHATJSON[name][0],
84
- ft.Icons.CHAT_OUTLINED,
85
- ftapi.shellv2(page, onsend, "Thinking...")[0],
86
- delBtn
87
- )
88
-
89
- def loadChatFromJson(page, name, dlg):
90
- data = tools.loadChat(name + ".json")
91
- chat = setup_ai(data)
92
- async def onsend(m):
93
- tools.CHATJSON[name] = [tools.CHATJSON[name][0], time.time()]
94
- return await chat.send(m)
95
- item, ap = ftapi.shellv2(page, onsend, "Thinking...")
96
- def delete_click(e):
97
- def ok(e):
98
- tools.deleteChat(name)
99
- page.controls.clear()
100
- main(page)
101
- page.pop_dialog()
102
- page.update()
103
- dlg.actions = [ft.Button(content="YES, I'm sure", on_click=ok), ft.Button(content="CANCEL", on_click=lambda e: page.pop_dialog())]
104
- page.show_dialog(dlg)
105
- delBtn = ft.IconButton(
106
- icon=ft.Icons.DELETE_OUTLINE,
107
- icon_color="red",
108
- tooltip="Delete Chat",
109
- on_click=delete_click
110
- )
111
- if not data.get("messages"):
112
- return
113
- for js in data["messages"]:
114
- if js["role"] == "system" or not js.get("content"):
115
- continue
116
- ap(js["content"], int(js["role"] == "assistant"))
117
- return {
118
- "label": tools.CHATJSON[name][0],
119
- "icon": ft.Icons.CHAT_OUTLINED,
120
- "items": item,
121
- "trailing": delBtn,
122
- }
123
-
124
-
125
- async def bping():
126
- while True:
127
- await tools.loop()
128
- if tools.VERBOSE:
129
- print("-----PING!-----")
130
- await asyncio.sleep(13.75 * 60)
131
-
132
- def main(page: ft.Page):
133
- page.window.icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAIABJREFUeJzs3Xl4FFW6BvD3VFV3Zw8QICQQwiabuyhuoKC4gCyiJggB3MV9ZcR9MjrqMOM66nh1ZBEJSwAFcWdz33dl3NgSICHsWTvdXVXn/gHMKKY66UpXd6fz/u5zn/vcdPWpQ9td56tT3/kOQERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE1Cwi2h0gIqLouLiozSP3w3+LEoa2TpL6J5vc/kEiH0YYmouIKUXpU29A4NpUoJMKuIWAkDKmx0WpAIEUYHue0F98c4L/zuY0Fsv/UCIicsikuW3++ZDwXx/OQeAo6N9td/mPaQlBwJSi9KlXQ7+3A2RqtPtiR4KQ3stgPL60GUEAAwAiolbGicH/gJYQBLT0wf+A5gYBDACIiFoRJwf/A2I5CIiXwf+A5gQB4Xj0Q0RELUAkBn8A+AbqEW+ZONLh04Qs3gZ/AKiXInElxPl23ssAgIioNZhzZvIo+K+IzLSvwOO6ekdEThWCDjDPi6fB/4AtUmTbeR8DACKiVuBQ7esLThBIiNT5XhTa6GUzEFODbXuYPaLdByf4oNj676qFuyNERBRjCguV0cbDd6pBbvm0Nm6kpIY2PyD9OmoqjAYf9PuhuA9LUvMAY2ZonXVOe8g0q9fUVBcS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Fzg3+AsZqE3F7ntOU7/J+G7TpgIO/tRi5ecbt7tnnPiiVD938jTHI/D55l8DJ4hCBzfKjDGVBd/vuRY9c9YANvbyaz0ugr50ZYF/rJ33cgagVZMw68rx2dKFmDVzKd5ZV+3o1UVDfUmGWTntr5vLlgwFdD7fp7jg8EzAaQi8u/nXwGmtafA/4MBMwD/FhnXDpGwX7f7EmsnQl66yOfgDXFEV85K7Hq1nCetSowe4h0/Hl/86A03bLEvCt+07vDZ3HmbPW40fdzu6DS88svb9TLV66uqN27h0n4goRnAGIMZJARNBao2H1lgAu35YgwUz56LoVWe34YU09BRRPTtXq7xv2frdm7kNLxFRbGEAEOOkzfWdv2tDr8Svq5fihRkL8cqn25zehrcyDZX3H+/d/Oy/dqDmGwfPRURE9jEAiHESQgekjcrXEmZNKT5YtACzXliODzfVOVg6TEKT3l8zZPXUDzaXvSoAk8v4iIhiGwOAGCchAghp6JbwbvkCy16YhxcWvo91VU7mDUmZIKtWZCnV01aU7PgGYFIJEVFLwQAg5in1TXoKIH2o+OpVvDRzHua/9RP2OLjjlYDhT5HVz/ZStj+4qKR22w/OnYqIiBzCG7YY5+56wq9dha9XowdqGjRdh5M7XSrw70pH1b2DjM2zHtsS5+VIiYjiHGcAYpyEaw+asqWIY4O/hAveH9qIqqkfbSp/WwDS0YonREQUEQwAYpyEqzw6ZzbNRFm7PFPsuWNlya4fAU4XERHFEwYAsU4k/wpEbo9KAb0+TVQ/0du/6+H5ZdU7uQ0vEVF8YgAQ46TS5lNplpUJmNlOnkeFb1uaqL7jT8mb5+WvhZ/L+IiI4htndWPdgAEu9+7+5+aY/3nciSDAg7ov2onKqe9v2vZuuNsmIqLYxQCgJQh3ECBNI0mpWZSl77jnrS1V68LQQyIiamHCU2OenFVebho9Xb/W1vfflCZ3niwgU+00o8hAbRqqHjhOqTj/rU3lReurfLvD3VUiImoZOAPQkuyfCciVa+8XUqaiif/9FOmtaSer7n1gc9nioXC0VAAREbUQDABamgEDXANCfMuXX37p5L5/RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERhJaLdAaLWJKlr/qiO2FCoCrOXkDJJQqr7f4T8LUaXhIAupFmliPpvztR/ufjJrdgS7U4ROYkXHaIISeqaP6o9Nj7tFnpOtPtCwUi4UPPJMH1dHoMAimdqtDtA1Bpw8G9JBEy4u5QoKSeNT9n91mfVqIp2j4icwACAyGEc/FsiBgEU/xgAEDmIg39LxiCA4psS7Q4QxSsO/vFAIIDE4/cIrVe0e0IUbgwAiByioOocFwf/OKCKakV0jXYviMKNAQCRQ4SoPZTLbOKBQL0isqLdC6JwYwBA5BBF6hw04oRXig7R7gNRuDEAIHKIIvT0aPeBwsMP0S7afSAKNy3aHSCKV4o0ExovtSXQdtgNmD65N3+M0aCXYPFdD+P1cjP4YRAM5iju8JpD5BBFSFfjRwl4svtj0CnHoQkHU7jpafg0qfHDDCFSne8MUWTxEQCRUyTrbMQLU6IJYQJRy8IAgMghCiR/X3HChEiMdh+Iwo0XKCKHKNxsK26YEAnR7gNRuDEAIHIIR//4ISHc0e4DUbgxACAiaoQUDAAo/jAAICJqjBCc0KG4wwCAiKgRQspAtPtAFG4MAIgcIqPdAQobAemPdh+Iwo0BAJFDJGOAuCEgfdHuA1G4MQAgcogJwQAgTiiAN9p9IAo3BgBEDjEFjGj3gcJDhayLdh+Iwo0BAJFDJIQe7T5QeKiQNdHuA1G4cTMgIoeYUHyA2UgNeRPb5kxB/zmR6RPZo0pZFe0+EIUbZwCIHCKFwrvGOKEBe6LdB6JwYwBA5BBTundEuw8UHglC7ox2H4jCjQEAkUNMkbAu2n2g8EgW2BbtPhCFGwMAIoeYMuM9rgOMByZSTLkl2r0gCjcGAEQOqStZ8HQ5+lzHIKBlE9KntxNyQ7T7QRRuarQ7QBTPApU/fO5rM2RnCnaN4G4yLY+QXv0sZcPhT23y/xTtvhCFGwMAIocxCGiZOPhTvGMAQBQBDAJaFg7+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERELZSIdgeIiIgib432dOfr5g4WgVOSpdlOBVwCEJB/PFIAhgrpTRPG+kfFzr/+eUvNkhZG6pgAACAASURBVMj3N/zUaHeAiIgostZoT+bcMG+IrL8gFTJNATTsuyEWDf2PFFBMITxeKJ1Oh2dQQrpR8k6V/8do/yuaiwEAERG1IvsG/6Gm9/wUQAn13V6oqfESBGjR7gARUUN6Zk7qOFX97q6Bon5SWxhtD75SK1IaHUXgxytQc9+crbsXCzQ0eUv0W80b/A/YBS17tVRGA2jRjwJsfwBERE45NnvEGbPVTzYOF7U3ZDQw+AOAKYS6De7D7ke74radMz8o7IaEiHeUWpbsd93dZf2o5gz++wj8IET/8HQqeqI2A/B0lz4FR0EOSROyr0fKTFUiTRXxFJBIuCBrNGB7Esz1Wab/o5cTyuaesQGV0e4ZUSw7InvMqJli7dK0EC7S3yD1pKyA+GV2t229N21CvZP9oxbM/Y07KyA9v/ub2havTj0MX6cGy4mX6PLG57jkw/99tbZJtZPLoW5GSlQCgKe79CnoB/PfnaVM/N2kXVxN4AkEIDoEgO5eKMevFWL8Rb4OnVb02PEwgwCihh2RPWbUXLF2WZqNFUrlSMkpC3T46p+9dhx9wzr4nOgftXDq9+7kgPj9d0u4seWITvimbbCvnAnvV78fLmsgUhzoYURF/I77wODfQ8rESJ87miRU8QJS7nrA12Hqih5Ij3Z/iGLNkdnjBz2PtUvtDP4H/IL0fpvqU+8LZ78ojoh17nDdtfugeho/KrZFdAagtQ7+B0ioYo5MuvP+AF4B8Hm0+0MUMzK/Tb4c+Us7NvAY0GzTDu+O7Y3Vx3fEpk5uBHQfsn6twEmv/YyRH1Yi8aCZwz8h9YYdmdX3vViB2kh1n1qIBAh4w9OULkSLT6KP6D+gLeTT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"
134
- page.run_task(bping)
135
- page.title = "TermiAI - Your personal helper to run commands for you"
136
- ftapi.setSize(page, (960, 540), False)
137
- dlg = ft.AlertDialog(
138
- title=ft.Text("ARE YOU SURE TO DELETE CHAT?"),
139
- content=ft.Text(f"Are YOU really sure to delete this chat?\nIf you don't know which chat you deleting, not recommended to proceed\n(TermiAI might restart)")
140
- )
141
-
142
- def darkMode(event):
143
- page.theme_mode = ft.ThemeMode.DARK if darkTog.value else ft.ThemeMode.LIGHT
144
- tools.APPCONFIG["dark"] = bool(darkTog.value)
145
-
146
- if tools.APPCONFIG.get("dark", False):
147
- page.theme_mode = ft.ThemeMode.DARK
148
- else:
149
- page.theme_mode = ft.ThemeMode.LIGHT
150
- darkTog = ft.Switch(label="Dark mode", on_change=darkMode, value=tools.APPCONFIG.get("dark", False))
151
-
152
- def server_select(e):
153
- tools.APPCONFIG["api"] = e.control.value
154
- tools.URL = tools.BASEAIURL % e.control.value
155
- page.run_task(tools.loop)
156
- choose_server = ft.Dropdown(
157
- label="Select server",
158
- width=500,
159
- on_select=server_select,
160
- options=[
161
- ft.dropdown.Option(key="x", text="Server in Oregon, Account index 0"),
162
- ft.dropdown.Option(key="2", text="Server in Oregon, Account index 1"),
163
- ft.dropdown.Option(key="3", text="Server in Singapore, Account index 0"),
164
- ft.dropdown.Option(key="4", text="Server in Frankfurt, Account index 1"),
165
- ],
166
- value=tools.APPCONFIG.get("api", "x")
167
- )
168
- def search_select(e):
169
- v = int(e.control.value)
170
- if v == 1:
171
- tools.APPCONFIG["searching"] = False
172
- elif v == 2:
173
- tools.APPCONFIG["searching"] = True
174
- tools.APPCONFIG["instantSearch"] = True
175
- else:
176
- tools.APPCONFIG["searching"] = True
177
- tools.APPCONFIG["instantSearch"] = False
178
- page.controls.clear()
179
- main(page)
180
- choose_search = ft.Dropdown(
181
- label="AI searchability",
182
- width=500,
183
- on_select=search_select,
184
- options=[
185
- ft.dropdown.Option(key="1", text="Off (not recommended)"),
186
- ft.dropdown.Option(key="2", text="Instant, quick search, for simple things (recommended)"),
187
- ft.dropdown.Option(key="3", text="Deep search, for most questions"),
188
- ],
189
- value="1" if not tools.APPCONFIG.get("searching", True) else ("2" if tools.APPCONFIG.get("instantSearch", True) else "3")
190
- )
191
- sideItems = [{
192
- "items": [
193
- ft.Text("Welcome to TermiAI!", size=30),
194
- ft.Button("Create new chat", on_click=lambda e: chatElem(page, dlg))
195
- ],
196
- "label": "New Chat",
197
- "icon": ft.Icons.ADD_CIRCLE
198
- },
199
- {
200
- "items": [
201
- ft.Text("Settings", size=30),
202
- darkTog,
203
- choose_server,
204
- choose_search,
205
-
206
- ],
207
- "label": "Settings",
208
- "icon": ft.Icons.SETTINGS
209
- },
210
- ]
211
- for conf in sorted(tools.CHATJSON.keys(), key=lambda k: tools.CHATJSON[k][1], reverse=True):
212
- x = loadChatFromJson(page, conf, dlg)
213
- if x:
214
- sideItems.append(x)
215
- sideBar = ftapi.createSideBar(page, sideItems)
216
- page.add(sideBar)
217
-
218
- def ftmain():
219
- try:
220
- ft.run(main)
221
- return 0
222
- except (ImportError, ModuleNotFoundError):
223
- print("Missing dependences or something is not working")
224
- return 100
225
- except:
226
- import traceback; traceback.print_exc()
227
- return 1
228
-
229
- if __name__ == '__main__':
230
- ft.run(main)