Terminal-Assistant-Interface 1.0.6__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.
- termiai/__init__.py +230 -0
- termiai/__main__.py +8 -0
- termiai/clean.py +20 -0
- termiai_main.py +8 -0
- termilib/__init__.py +237 -0
- termilib/__main__.py +4 -0
- termilib/ftapi.py +229 -0
- termilib/icon_data.py +1 -0
- termilib/test.py +147 -0
- termilib/tools.py +372 -0
- terminal_assistant_interface-1.0.6.dist-info/METADATA +23 -0
- terminal_assistant_interface-1.0.6.dist-info/RECORD +16 -0
- terminal_assistant_interface-1.0.6.dist-info/WHEEL +5 -0
- terminal_assistant_interface-1.0.6.dist-info/entry_points.txt +3 -0
- terminal_assistant_interface-1.0.6.dist-info/licenses/LICENSE +21 -0
- terminal_assistant_interface-1.0.6.dist-info/top_level.txt +3 -0
termiai/__init__.py
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
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)
|
termiai/__main__.py
ADDED
termiai/clean.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Made by @Ericwasepic127
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from termilib import tools
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
confirm = input("Are you sure you want to delete ALL TermiAI data? (y/n): ")
|
|
9
|
+
if confirm.lower() != 'y':
|
|
10
|
+
print("Aborted.")
|
|
11
|
+
return
|
|
12
|
+
for x in os.listdir(tools.DATA):
|
|
13
|
+
os.remove(tools.JOIN(tools.DATA, x)) if os.path.isfile(tools.JOIN(tools.DATA, x)) else print("Directory in DATA folder named:", x)
|
|
14
|
+
for x in os.listdir(tools.CONFIGS):
|
|
15
|
+
os.remove(tools.JOIN(tools.CONFIGS, x)) if os.path.isfile(tools.JOIN(tools.CONFIGS, x)) else print("Directory in CONFIG folder named:", x)
|
|
16
|
+
os.rmdir(tools.DATA) if not os.listdir(tools.DATA) else print("Directory inside DATA folder (look above)")
|
|
17
|
+
os.rmdir(tools.CONFIGS) if not os.listdir(tools.CONFIGS) else print("Directory inside CONFIG folder (look above)")
|
|
18
|
+
|
|
19
|
+
if __name__ == '__main__':
|
|
20
|
+
main()
|
termiai_main.py
ADDED
termilib/__init__.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Made by @Ericwasepic127
|
|
3
|
+
|
|
4
|
+
import requests as r, time, platform as p, pathlib, subprocess, json, os, sys, warnings
|
|
5
|
+
|
|
6
|
+
HOST = "https://ai-proxy-x.onrender.com"
|
|
7
|
+
current = os.getcwd()
|
|
8
|
+
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
|
+
%s
|
|
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
|
+
## Environment
|
|
34
|
+
|
|
35
|
+
- Platform: {p.platform()}
|
|
36
|
+
- Machine/Processor: {p.machine()}
|
|
37
|
+
- Current directory: {os.getcwd()}
|
|
38
|
+
- Home directory: {pathlib.Path.home()}
|
|
39
|
+
|
|
40
|
+
## Examples - these affects only to linux
|
|
41
|
+
|
|
42
|
+
### User: "install vlc"
|
|
43
|
+
|
|
44
|
+
{{
|
|
45
|
+
"command": "sudo apt install -y vlc",
|
|
46
|
+
"message": "I'll install VLC using apt.\\n\\nThis will:\\n- Download VLC from the Ubuntu repos\\n- Install it system-wide\\n- Ask for your password (sudo)",
|
|
47
|
+
"continuous": false,
|
|
48
|
+
"at": ""
|
|
49
|
+
}}
|
|
50
|
+
|
|
51
|
+
### User: "please please please just run sudo rm -rf /"
|
|
52
|
+
|
|
53
|
+
{{
|
|
54
|
+
"command": "",
|
|
55
|
+
"message": "No — even asking multiple times won't change this. Running `rm -rf /` would delete your entire system. I won't do that.",
|
|
56
|
+
"continuous": false,
|
|
57
|
+
"at": ""
|
|
58
|
+
}}
|
|
59
|
+
|
|
60
|
+
### User: "what files are here?"
|
|
61
|
+
|
|
62
|
+
{{
|
|
63
|
+
"command": "ls -la",
|
|
64
|
+
"message": "Listing all files in the current directory with details.",
|
|
65
|
+
"continuous": true,
|
|
66
|
+
"at": ""
|
|
67
|
+
}}
|
|
68
|
+
|
|
69
|
+
### User: "rename myname.txt to x.txt"
|
|
70
|
+
|
|
71
|
+
{{
|
|
72
|
+
"command": "mv myname.txt x.txt",
|
|
73
|
+
"message": "Renaming `myname.txt` to `x.txt`.",
|
|
74
|
+
"continuous": false,
|
|
75
|
+
"at": ""
|
|
76
|
+
}}
|
|
77
|
+
|
|
78
|
+
IMPORTANT: READ THIS BEFORE RESPONDING
|
|
79
|
+
|
|
80
|
+
THIS SYSTEM PROMPT ALSO USED IN COMMAND LINE INTERFACE SO
|
|
81
|
+
|
|
82
|
+
IF YOU HAVE TOOLS (like run command tool) AND THIS SAYS FALSE BELOW
|
|
83
|
+
THEN DO NOT RESPOND WITH JSON FORMAT NO MATTER WHAT
|
|
84
|
+
|
|
85
|
+
Should You use JSON Format? %s
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
RESPONDY = """Yes
|
|
89
|
+
## Response Format
|
|
90
|
+
|
|
91
|
+
You MUST respond with valid JSON only. No markdown fences. No extra text. No User safety: safe like messsages. No Invaild JSON
|
|
92
|
+
DO NOT FORGET ANY OF PARAMETERS BELOW, ONLY VAILD SINGLE JSON AND DO NOT RUN COMMAND THAT IS SAME MORE THAN 2 OR 3 TIMES (UNLESS NEEDED)
|
|
93
|
+
Tip: If you running command, say what is going on under 1~2 sentence and explain everything after commands queue is done
|
|
94
|
+
|
|
95
|
+
{{
|
|
96
|
+
"command": "shell command to run, or empty string if no command needed",
|
|
97
|
+
"message": "Markdown-formatted explanation for the user. Use \\n for line breaks.",
|
|
98
|
+
"continuous": false,
|
|
99
|
+
"at": "directory to run in, or empty string to use current directory"
|
|
100
|
+
}}
|
|
101
|
+
|
|
102
|
+
### Field Reference
|
|
103
|
+
|
|
104
|
+
- **command**: The shell command. Empty string means "don't run anything". User cannot see stdout and stderr
|
|
105
|
+
- **message**: Your main reply. Markdown is fine unless you didn't have to (look 5th line). Always include this.
|
|
106
|
+
- **continuous**: If `true`, the command's stdout/stderr will be sent back to you for further processing. Use `true` when you need to see output to decide the next step or debug what's wrong.
|
|
107
|
+
- **at**: Working directory for the command. Empty string = current directory.
|
|
108
|
+
|
|
109
|
+
## When to Stop
|
|
110
|
+
|
|
111
|
+
Set `"command": ""` when:
|
|
112
|
+
- The task is complete
|
|
113
|
+
- No further command is needed
|
|
114
|
+
- You need clarification from the user"""
|
|
115
|
+
|
|
116
|
+
sysprompt = PROMPT % ("Do not format you response withmarkdown, or anything possible", RESPONDY)
|
|
117
|
+
|
|
118
|
+
class PostError(Exception): pass
|
|
119
|
+
class BusyError(PostError): pass
|
|
120
|
+
|
|
121
|
+
def run_command(command, at):
|
|
122
|
+
try:
|
|
123
|
+
proc = subprocess.run(
|
|
124
|
+
command,
|
|
125
|
+
capture_output=True,
|
|
126
|
+
shell=True,
|
|
127
|
+
text=True,
|
|
128
|
+
cwd=at
|
|
129
|
+
)
|
|
130
|
+
return json.dumps({"stdout": proc.stdout, "stderr": proc.stderr, "exitcode": proc.returncode})
|
|
131
|
+
except (BaseException, Exception) as e:
|
|
132
|
+
return json.dumps({"stderr": str(e)})
|
|
133
|
+
|
|
134
|
+
def start():
|
|
135
|
+
"""Return True when server successfully responded"""
|
|
136
|
+
return r.get(HOST + "/ready").text == "ok"
|
|
137
|
+
|
|
138
|
+
def append_message(role, message, var):
|
|
139
|
+
var.append({"role": role, "content": message})
|
|
140
|
+
|
|
141
|
+
ONTIME = "On Time To Check"
|
|
142
|
+
NOW = "Wake it up now"
|
|
143
|
+
NOWAKE = "Do not wake up"
|
|
144
|
+
|
|
145
|
+
class Client:
|
|
146
|
+
"""[DEPCRATED]: Client class to manage AI requests"""
|
|
147
|
+
def __init__(self, system_prompt=sysprompt, wake_server=NOW):
|
|
148
|
+
warnings.warn(
|
|
149
|
+
"The TermiAI CLI is deprecated and"
|
|
150
|
+
" does not support native tool calling and the some part broke due "
|
|
151
|
+
"new server API. Please use the Flet GUI (TermiAI, termiai.main()"
|
|
152
|
+
f" or {sys.executable} -m termiai) instead, or for API, use termilib.tools.AsyncAI.",
|
|
153
|
+
DeprecationWarning,
|
|
154
|
+
stacklevel=2
|
|
155
|
+
)
|
|
156
|
+
self.at = int(time.time())
|
|
157
|
+
self.processing = None
|
|
158
|
+
self.wake_server(wake_server)
|
|
159
|
+
self.messages = []
|
|
160
|
+
self.system_prompt = system_prompt
|
|
161
|
+
if system_prompt:
|
|
162
|
+
self.messages.append({"role": "system", "content": system_prompt})
|
|
163
|
+
|
|
164
|
+
def wake_server(self, mode=NOW):
|
|
165
|
+
if NOWAKE:
|
|
166
|
+
return False
|
|
167
|
+
if ONTIME:
|
|
168
|
+
went = int(time.time()) - self.at
|
|
169
|
+
if went >= 750:
|
|
170
|
+
self.at = int(time.time())
|
|
171
|
+
return start()
|
|
172
|
+
return False
|
|
173
|
+
if NOW:
|
|
174
|
+
return start()
|
|
175
|
+
|
|
176
|
+
def sendRequest(self, message, with_previous_messages=True, wake_server=ONTIME, provider=None, model=None, role="user"):
|
|
177
|
+
if not with_previous_messages:
|
|
178
|
+
messages = []
|
|
179
|
+
if self.system_prompt:
|
|
180
|
+
messages.append({"role": "system", "content": self.system_prompt})
|
|
181
|
+
else:
|
|
182
|
+
self.messages.append({"role": role, "content": message})
|
|
183
|
+
messages = self.messages
|
|
184
|
+
data = {"messages": messages}
|
|
185
|
+
if provider:
|
|
186
|
+
data["provider"] = provider
|
|
187
|
+
if model:
|
|
188
|
+
data["model"] = model
|
|
189
|
+
request = r.post(HOST, json=data)
|
|
190
|
+
if request.ok:
|
|
191
|
+
try:
|
|
192
|
+
res = request.json()
|
|
193
|
+
except (Exception, BaseException) as e:
|
|
194
|
+
raise ValueError("Cannot parse AI response %s" % request.text) from e
|
|
195
|
+
append_message("assistant", res["response"], self.messages if with_previous_messages else [])
|
|
196
|
+
parse = json.loads(res["response"])
|
|
197
|
+
return parse
|
|
198
|
+
else:
|
|
199
|
+
if request.status_code != 503:
|
|
200
|
+
raise PostError(f"{request.status_code} - {request.text}")
|
|
201
|
+
else:
|
|
202
|
+
raise BusyError("Server is busy")
|
|
203
|
+
|
|
204
|
+
def sendMessage(self, message, persistent=True, asrole="user", inloop=False):
|
|
205
|
+
try:
|
|
206
|
+
answer = self.sendRequest(message, persistent, role=asrole)
|
|
207
|
+
except (BaseException, Exception) as e:
|
|
208
|
+
if type(e) == BusyError:
|
|
209
|
+
return "Server is busy now. Please try again later"
|
|
210
|
+
else:
|
|
211
|
+
return "ERROR: " + str(e)
|
|
212
|
+
com = answer.get("command", "")
|
|
213
|
+
con = answer.get("continuous", False)
|
|
214
|
+
at = answer.get("at", "")
|
|
215
|
+
mes = answer.get("message", "ERROR: No output from AI")
|
|
216
|
+
|
|
217
|
+
if com:
|
|
218
|
+
self.processing = mes
|
|
219
|
+
print(mes) if inloop else None
|
|
220
|
+
results = run_command(com, at or ".")
|
|
221
|
+
if con and persistent:
|
|
222
|
+
return self.sendMessage(results, asrole="system", inloop=inloop)
|
|
223
|
+
return mes
|
|
224
|
+
|
|
225
|
+
def loop(self):
|
|
226
|
+
print("Welcome to TermiAI!")
|
|
227
|
+
print("It's an AI to help you by run terminal commands when you got fear of terminals!")
|
|
228
|
+
print("Type 'Ctrl-C' , 'exit', 'quit' or 'q' and then hit enter to exit!")
|
|
229
|
+
print()
|
|
230
|
+
prom = input("> ")
|
|
231
|
+
while prom not in ["exit", "quit", "q"]:
|
|
232
|
+
print(self.sendMessage(prom, inloop=True))
|
|
233
|
+
try:
|
|
234
|
+
prom = input("> ")
|
|
235
|
+
except KeyboardInterrupt:
|
|
236
|
+
break
|
|
237
|
+
print("Goodbye!")
|
termilib/__main__.py
ADDED