Terminal-Assistant-Interface 1.0.7__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.
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/PKG-INFO +1 -1
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/pyproject.toml +1 -2
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/PKG-INFO +1 -1
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/top_level.txt +1 -0
- terminal_assistant_interface-1.0.8/src/termiai/__init__.py +236 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termiai_main.py +1 -1
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/tools.py +79 -5
- terminal_assistant_interface-1.0.7/src/termiai/__init__.py +0 -230
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/LICENSE +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/README.md +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/setup.cfg +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/SOURCES.txt +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/dependency_links.txt +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/entry_points.txt +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/Terminal_Assistant_Interface.egg-info/requires.txt +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termiai/__main__.py +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termiai/clean.py +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/__init__.py +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/__main__.py +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/ftapi.py +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/icon_data.py +0 -0
- {terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/test.py +0 -0
|
@@ -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
|
+
version = "1.0.8"
|
|
7
7
|
authors = [
|
|
8
8
|
{ name="Ericwasepic127", email="ericwasepic127@outlook.com" },
|
|
9
9
|
]
|
|
@@ -35,7 +35,6 @@ build_number = 1
|
|
|
35
35
|
|
|
36
36
|
[tool.flet.app]
|
|
37
37
|
path = "src"
|
|
38
|
-
module = "termiai_main"
|
|
39
38
|
|
|
40
39
|
[project.urls]
|
|
41
40
|
Homepage = "https://github.com/ericwasepic127/termiai"
|
|
@@ -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())
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/tools.py
RENAMED
|
@@ -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=
|
|
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
|
|
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/4AtUmTbeR8DACKiVuBQ7esLThBIiNT5XhTa6GUzEFODbXuYPaLdByf4oNj676qFuyNERBRjCguV0cbDd6pBbvm0Nm6kpIY2PyD9OmoqjAYf9PuhuA9LUvMAY2ZonXVOe8g0q9fUVBcSEyPZGxt8BmorTciD/mwAqp3mGAAQEcW59j1fOCRfmL0tDxAK3EmhPxwQbhUutwHD3+CrONRU75CFxmxRCDPkxh3QRsD1h9FzP6EJaJ7YzouXZsM5ldJmQj8fARARxbkTxe6bOwYZIkSiApet0UDAnaxYjj4bhNozrTesA48IS5Uc836LHwYRUTybNSThfBGYZPm6EHAlKxA2b36VJBWaxUgipRD5hnqrvZbDL1Fw6ftvMQAgIopjh2j/OWcokGR5gKrAndCMcVFR4A6SgjZd0QoKZ0Uu+TAYEdtlfiOOAQARUbySUpyj1N4ZLNlLTVabnQympahQLIZWH9TEB13qyGaeIix0YZUB0MLZ/FcxACAiilNtFx2WMw7yaMsDbCb//aEZtwJXkDz0tkK9KxY22amVcRoA2MQAgIgoTg00y67tGixDPEGF29YCsoMIBZ5k6wfsXwvtyOmLkBOGMzVLNWJjNUK4CZszGwwAiIji0bNXukYb/quCHdKc5L+DKckqVIu2pISoN7XrwnMm+/YAPqvXpM9EwB+7UwSm30SgvuHeCZsPARgAEBHFoZzkN4YOD1L4BqoKjyeMJ2wkGfAWQ5nyxbNwhfGMIdspxB6r14w6HbUVflRu8aNqhw5vpYFAvYQZjTkDKWHUG/BV6ajd7kfVFh+qKgKoq2k4QFEhbW26xEJALVGPYel9fVVN+m/3zNbPKocCutNdIqLYMkLZe7cnyH2hkqQgWGXAkAkBV5IC4f1jpToAqIaWdluyfyiAt8N41pBsh/qThN4l6KSHlDDrDfjq/zddoLgVqG4FWoKAyyOgWGU82iRNE4ZPwvCZ0P0Sul9ChnBPnwizzs55GQC0ND2GpScHOo41td0PATIBjVSAujq3f/2J5t47H9xcNoeBAFHrkDzv+Mzx8vuTLQ8QCjwp1gV87BIJGtyqHz6L+9FyRbsL0KMWAOyAOrNEGMd1kzI9lPeZfnPfFHwN4AUgtH3BgOZR4U4UNh6jSJj1Jvx1ErrfhBFo3qOHnlJusvM+PgJoSfYP/lnKT4+akJ1MoI0JpAf7Xx2ezB1K5owpuYfuOD4n+9I1DPqI4t4Ase6KXkGu78KtwOXElUARcAVZVbBaaoNOmoOODpy5SV6YsGf+c3BfvUmIyua0I3UTgRoD3irDdlZhoEpHfa0BvZmDfwJMb56Qz9p5LwOAluI3gz8g24b6dhPuNrv2BwIn5HS+WNrcPIKIYlxxsTrarL8x2E2plqI6dvHXUqyTAU0oytVCudyhUzdJuIKAWJAgTO+9MG59uiDwjJ33MwBoCZo5+P+WCXebnUrHWX1zD90xqGvnyQwEiOJLR+Om40dDtrc8oJFkvWbTFLjd1uHHhYp6Y15xdK87/w0CoKwzWmRxIIkMITdPk/YHf8DmDkIUQWEc/Buiwr+ng9x10/ul24oEGtzVk4hakIuLUl97AMYIq9eVFBdS2zb9+b+sN6FroT0ykLUBVO62mByXEks074k3XIhPmt6ic7oUd0mcFqg6pZ80xmdCnpku0Elt6tjoUpGaqVnOeFiT8G33w2u5KPH3hIBMltiRDXPNQEXO2676Vq/NR02oZ/1Du81tgJyldp00qbtY+4QTg//vzoP6PR3k3hvfLy2fx0CAqGVKLzq87Tys336UZa6PQEKmGwnuprdpVPrhVV1ISQlhuJAmassDCFhcSSYI//J3J+ijm95gBK0Zov217PtjjlICF3aW5sg20uzlthorHQoAFMBMFbI0F3j9FD0w/yWv/qmYgkCoZ2kMA4AYp+aO+md3bLk+MmeTUOHbnSH33vhhafl8BgJELcvAuRnXLxHef1o92xUeDSkd1RDm3/cNVPVCQ1p7NYRsdwl9TwA1NQ3PrmvC0As0X/uV+Yj55/A5c9JWfKLqwxp80YEAIB3ePckTZIbd6n6hYA5AjBOo7RXJsxlIaLddZL7YN7ff9pO6Zk1kjgBRC1FYqIwS9bdZX9QF1CQltB+0KaH7Aek3oYc0HAmoyYrlAKNLVftbQJkQSouthSqlEYnBH2AAEPME/JnROOtvA4GTc7MKGAgQxbYO3Z878nzILpYHKKFv/PPfgd804W/i8+oDhFuFJ8ijhhOhTZOFHIOiiR9+jBPSaNOk41LTkR72db37AoEKdJrbN7dfxcm5WQXFDASIYtJQteb2YNVtlCQF7hCv+Eb9/6r66RYV/qyJfXsNWLy6CWruhl44NLQeUTgxAIhxQhjJTTnONeh2vPX2Y5g6th/aOlDgw0BCRgU6zb0nt3/FiTnZ4yW/O0Sxo3hISr7Qz7V8XQi4k0L9yUrov9l8RvpMGCFOTCtJKjTLSQeBaVK9LcROURjxIh7zzCau2FWQ3P1UTHn0Rax+6zHc6lgg4MnYoWTO65Pbv+LknOxxDASIou9wfW3eQMB6wt2lwhXqxj+6Cf23xcMNEwF/iG008tjhGUXLW/4skkJslcKEF+8YJyBD2z1LKEjpeSquevRFrH7rUdx6bl+0cWDS3oSnfYWSuaBPVwYCRFFVWKiMgveOYD9zLdTkPwDmwXf8Utp4DABoyQqs9s7xQ/UMTVHHhtgkhQkv2jFOQNobvoWClJ5DcNVjc7HmrUdwyxiHAgGxLxDom9tv28ldO+UzECCKrIzes3vnS/MQywNE6Ml/kIDu/WONeqPehBliBCDcKtxBZiNzoN4pJZekRwMv1jFONPe/kVCQ0msorn58Lla/9QhudigQMJDQoUJkLeyT23fboK6d8hgIEEXGyWblLR2CvC4SFbhCfvxvIOBrYKQPmAiEuqeoCJ4MuFao/UYsRI8QW6Uw4EU6xgkZpv9GQkFqr6G45vG5WP3mI7h5dB+HHg0kdtgmsor75PYtZyBA5LBZFyfkwTfR8nUh4E5WQt6uVvok9AYr+UoEvKEvUVeTFKgWVwIphegP9caQG6Vm48U55oW5HoRQkHrIUFzzRBFWv/kwbh7VB+nOBAIdDwQCg7t2uoCBAFH49VFfG3WqQKLlAaoClyf02XXda1heeQyvGfoWuIoKd5AkxLsN9VJZHCSJkRzBi3JrJRSkHnIarvlnEVa/8TBuGtXbsUCgXGQt6pPbt3xwbtb5DASIwkRKcY7ivSvYz1ZNDrYMz6pdE4H6IK/7DfhDrUovAHeK9WOAOqjJvU2cGWKr1Ey8GLd2QkFa79Nw7T/nYfUb/8BNIx0MBNBpcZ/cfmUnMRAgarY28/p3HSfMIywPEALu5NDv/qXPtNzEZ/8Rth4DwBMsGVAgYGp3MxkwsngRpn2EgrTep+PaJ+dh9ev/wI0jD3EoEEjI3L4/EDg5N+s8BgJE9hwvyq/vEmxDtwQt5Mp/QNOW+hl1Zug7hTWyGuEjqQ38egGyQm2W7OPFl35PKEjrczque3I+Vr3+d9wwshfSHfiWmEjIrECnJX26MRAgCtmzV7rONQNXBDvEZSP5D1IiUNeEu/uAEXpRIAR/JCGhiHcV5arQWyW7eNGNfRHZFeoPhIL0PsNw/ZMLsOr16bjhHIcCAfm/QGBQbtZYyS2qiRrVJfn1YWcLmWZ5gKbC08Qaor8l600EmpThJxGoC70oEFQF7iBJiVfq6nVr1sCBGqbUEAYAMU6K0BNuw0ooSO97Bq5/al8gcP05vZDmUCCwDZ1e6tutX9ngnOxzGQgQWZBSjFQr7wqWMq8kqaHvUS+BQK119v/BjDoTRqhXp0ZqAuyF1nZOOU4OsVWyiQFAjJMQIT9qc8T+QOCGpxZg9evTcf0IZwIBQyZ0KlcyX+6b22/r4JyODASIDpL00rGdxkvjRMsDhAJPsgj9h2Ma8AfL/j+YYYS8RTCwvzCRZX6RwHfQ7gq9VbKDAUCMk0KEWnfLWQcCgacXYPXrf8N1wx0KBJCQVa50frlvbt+tg3MyxzAQINrn2PqNU3oGKRAmPApcNibRjbrQd/sL1BmQoT4HaCQZ8DWpnfZRMdqF2CrZwAAg1klhI8aOAKEgve+ZuPFf87H6tb/h2uE9kepIIJCYVa5kL2UgQASguFgdDd91wX4EWrJq48Ju75m+9JoI2MhS0pJVy82JDChqhV+5JPRWKVQMAGKcFEpdU44zNnyK1T9XhhzBN5tQkd7vTNz0rwVY89pDuPZsZwOBfrl9t5ySkzmagQC1Rh1w04ljIDMsD1AUuO0k//ntZfVDSvibsmrgYC4l6PbEYxTtlrzikDcwpBAxAIhxUmpVTTnO+Pkl3DhiFM658km89M0uW1F5swgV6f3Owk3PLMDqVx/ENWf1cCQQ0JGYXaZkL+uX23fLqV0zRzEQoNbkHL3q7qQgrytJKjQba/+NWut1/RostgVownut7d+jwOLVclPNnmziyJCbpZAwAIhxEq4dTT7YrMH6FbMw7dxROGPSdBR9VAY7BbuaRaho0/9s3Px/C7F6+YO45qzuSHEoENgqsl/p17XvZgYC1BqkFR/aLl+aw6yPEEHL7Voyg9/FXyL0lz4HLIv/Sr+BQKilgQEowXYpFALPGOrtobdKoWAAEOtkYknob6rH1g8WonDCWJx+XiH+vWITqiP9bECoaHPo2bj5/4qxZvkDuOZMhwIBkdj5QCAwqGvmSAYCFK/6BsovOgLW0+LCrcLlCr3doGv/pcTdwv+3xdDeDNIC/HZqAijBkwFfgDamQzFSQm2Wmo4BQKyTbb6z/+YAdnz9Cv5+xQUYes40PL7sJ+zWoxEIDMfNzxZj9SsP4GoHA4FtInt53659SgfndjqHgQDFleI8dbTw3Wr9pRZQU5TQH5pLiUCt9eDdCea2E1V8t0Kk/L02SDNmbegrCAABNdm6z34o7o8MNT/UVqnpGADEOIEuK+qhlTevFROVP63E0zcWYOiwG/Dg/K+xzRf5QKDtYcNxy7PFWP3KX3HVGd1gY5+SRhkiqUs5sl7t261PySm5nUaE/wxEkdfe/PDI86XsbHmAosCdaOMHZZrwB7kWzFMDT4p8GDuyrvzkDSH2Wh5omPDXh35NEW4VLsuKRgKHm+odspDjlFP4wcY4/+aHf9hunHG2D9ru5rcmUbfpQ8y64zKcPuRy3D3jQ5QEif4dIVS0PWwEbn1uEdY4GQjIpJwyZL3Wp1uf0iHdss4O/xmIImeYXn2Hdd3fRp6nB2EGWfuvwDQnquZMAMDQQn25cD9v3dK+PQRshABBkwE3CLWn6I3eITdLTcIAoAXwb3nwuwrjjKHhCQL2t1n+NRbefz3OGjwRt/5zJX7a2/QSoGEhVLQ9fARufa4Yq5f9FVMcDAS2yE5v9OnWr3QQAwFqiWacnJoHY4z1AQIuO8l/UsIf5AbgeOhfIA8VB/7/z9WO/9oaZG8S6TWCLRewpCQF2SBICnGZod4aeqvUFAwAWggnggAAMHb/hOWP3oYxg/Jw9fRX8M12f4QDAQ3tjhiBqc8VY/Wy+zFlWK5DgUBCzjbZ6Y2+3fqVDO6WdVb4z0DkjCMSfskfKGCd3udW4Q62MYAF6TcRCFJnVBf6Q0L873JQmffTpsVQfrVuUMJnpyaAosCdaP3ydEUrKJwFG9UNqDEMAFqQA0GAH+6ycLdt1mzCqmcKkXfKWFx070J8tKU+CoHAOZj670VYvew+XOlQIKDLhK7lstObfbv1LTmle8czw38GojAqLFRGSe/t1hdqAS1IIp01CaPOsJz+T4DhvdKH32f+CyFfkwkPB60JUGfa2r1MS1GhWPzefVATp7vUkTaapUYwAGhh/Fse/K60ZHjOHtFjrB/alrCfoL4cH8+ZjouGjELerbOx8tfqyFYXFBraHTESf/r3Iqxaeh+uOL0rgqwUsk2XiV3LzM5v9e3WZxMDAYpVGT1m9cmH2cvyAEUEXUpnqZG79RugLyy8BH/YGmitO7f4awHLeQPpN4LOKlgR7mAbBAFthHqXlFzZE24MAFqkQnPXpiVLS0s+z9kjDzmjHp5fwn4KfRe+XfJPXH32KIy55l945fvdiOgKQqEh48iRuO35xVi99C+44jSnAoGk3AOBwKldO54R/jMQ2TdYqZzaPsj3XiSotpL/gj+vl7hFNx5r8KX8LysXS22VdcMSvlobyYD7dzC08qXQjpy+CDmhNkvBMQBo4XaVFq/cUvJJn+2i/4l1wvNV2Mdoowo/v/E8bh09Cmdd/DAWfFaBiK4gFBoyjhyF22YsxqqlhbjcwUBgq+j8dt/c3huHdM0MUm2NKEKK8xLzhH+85etCwG1n218pEQgySHeWxtblG/GD1dvf1lOnB9s12KyzUxoYUJKDJQNC+E3tWhvNUhAMAOJE1aaiT8o2fTJgm3L4kV4kviuDZOvaIr0ofXce7skfg9Pz78fMNaWoNSMYCQgN7Y8cjWkHAoGhObCz7LkxOpK7bRHZKxgIULT10d8ZNRiwTo/TFLg8Nn4EhhF07f+r0B8rLLR+lL+t/pwP3pLCeo8Sw0DARk2AxjYyuklXrvri2SDJkBQyBgBxpnbjnO+2lnw0ZIdxTO86mbo87IEA/Kj4/GU8dMn5GDrqLjz12i/YG8lnAwcCgZlLsPrlQlw+xPFAYMPgrpmnh/8MREFIKUZI793BkvvUIMvngjHrTMvHeYo0zSrFfCFoA1OeCyw3XdbH2N0hUAi4kqyXM1ZDS7szCUNCb5isMACIU1VbZqwrK31vdJk+qGutbPOiCVvJuUEY2LP2TTxx7QQMPfNmTF/0Hbb7IxwIHDUa02YtxqqXCnHZkC5BbpXs05HcvVxkr+yT23vDKbmZpzlwCqI/SF/Ut9t4YR5meYCwm/xnwldr/Ts9VegfTZiAnY0184Fs91RF0JoAJvw2rjgiQYPbKuoRwGZFuzv0VskKA4A459365Jby0jWTdwTGZNYg40kJYSNHNxgTNRvew/N/uhinD70KhbM/wRY70b9dwoUOR4/G7bOWYNXLf8alp3Z2JBAwkNy9DFmr+uT2Xs9AgJx2kllxQ+dgWe/BBsogpN9EIMgD+jToDzWlneqNk9ctlspGywNMEwE7W5EqAq4gyYCrpTbopDnoGHrD1BAGAK1EdVnhzm0lK29Y77o4oxId/mpI4Qv3Oeq3fo6iwmtwxikX4bZn1mBdVQTLDAsXOhw9BnfMfgmrXnIqEBAwkNyjDNmr+uX2XndqbqehYT8FUXGee4zhvzzYIe5kBSL07D/odSasUncSpVHX3YWVTWqqsNB80/Q8GqwmgF5rsyZAsgrV4t9mCkW5WihBPxtqOgYArc26G6p2lLx9z0bz9rZ7lY5TAxDBNvmyRd/5A16efivOGXQhrnv4dXy/S49sIHDM/kBgyb245BRnZgQCSO65FVmrGQhQuOXKj4ediSDb4Kpq0GQ5S6aJQJDZuT8petGifPib2tx6NXveD9I64b+xSoOWNAVut3V0c6Gi3iiLbdQ+oj9gANBabcn37tz41iMl7b9su1fJuiIg1LCWGAYAs2od3n7qbpw/+Dxcdt8SfFbui2wgMOBc3PnCS1i15B5cMtjxQODXId06DXHgFNSaSClG6JX3eIIcogS5Qw7adNDn8hL/Mo3HQ2mvsuD7PYugvmd9QtNeMiD2LW+0sl1qHR81cZyNhukgDABauy9FYOfG158v2fR5x92yyzg/tG3hPoWs24L3Zz6AglNHY/y0F/HOxlrLaciwEy50GDAWd85ZgpWL78HFzgUCvbbIrDX9uvX5ZWi39qc6cApqBZIWHJM1XhoDLQ/YXzAn9PFfwh8k+a+bNErd6/BTqK2+qaX+LdizRKPOsFVATCSp1pUBhcAyU7sz9FbpYAwAaD9h7C5dXlxa8ln2LvQc4YdrQ9hP4d+BLxc+hiuGjcS5NzyL1/9TGbkyw8KNjseOxV1zlmDl4rtx0eBsR3YXCcikQzbLnHf6dTvklzMYCFCIjpMlU3oK6+uycCtwaTYa1k0EgqzSeUvoj4gga/+tlCknv7MSsH6M2Mh5LQkBT5D1vYugDh9WjPTQG6bfYm1lstS2a96gZLH56QT4jnDkBCIZ3U87H1deXYDRAzogyGO/8JN+bP/iVTz3xEws/KDsj0XPw3MSuETdLzlizxVvb9xhPVVKBABrCrVHy/9RMU7KdlaHuDM8SEoKvWmjyo/qSuuBuLlxeLCfrpLsQmq70Lcrln4d1RWGZVRSjvprji0wnwmx2ZDlzElb8YmqN1wUzKUiNVOz8UhGwrfdD28D0yftZN3OxInoEHJHbWAAQI1qkzv56GSx7qkE6T3JmS+MB9knjMZl105G3qDOjhT2sST9qNgfCBQzEKAoyirKOeV97HrX8hGVqiK5k2aj9r8Jb3kAvjAvAG4yRUFylstGvyV8FX54LdISu0Ev8f/q72Fn5iIU8RwA8BEANWpvyZyvt2766OTtytF960TKm+GvLuhD2SeLcP+ksRh67j145q31qIzUswHhRuZx5+GeF1/CyuK7MPnkLAceDQgEZHLvDWand4b3aFsQ9uYpLgxXKu8Klp+iJCnQ7Gz8Ux987b/jTBN+W5H1vpoAVmNriVC7buiFQ5vRs1aPAQA1WfXGmT+XbXp/+FblmO41InVh+KsL6tj17Wt4dMo4nDZ8Kh59aS12BiIYCAw8H/fMfXlfIHCSE4GAJn41urzIIIAOllZ8aLs8Uw9SclrAHaRMbjB6nRG5pFurPtTa64OSpAXZIEiIO6H+qXk9a90YAFDI6jfOKNm26b0LK5RTsqtlm+cMKcJ8f2Gi6pc1eOaWSTjt9Otwf9EXKLOzuYgdBwKBopexovhOTDqpE4ItyQodgwD6o37+8ksOh/XaduFR4HLbaNg04Pc2o2NhYnsWQlGCljx+StHylz8LG1kRBDAAoGao3fhERUXpmikbldHtq0S7v5sQTS4i0lTe0o8x564rMezUS3HHc+9jY02EqgsKNzoNvAD3Fi3FioV3YOKJ4QwEGATQbxTnqecqvlushzkBNVm1VfnG9JrQHX1C3lR2awIAWpICxeLD8UvVMzRFHduMjrVqDACo+TYV7t2+adW0DfU3tauUmXfqUtSF+xSBim+x+MEbMXzwBNz0+Fv4z24jYoFA1vF5+PO8cAcCmvjVyHzhjh6e3mFpjlqs9vjgqHOlzLY8QFHgtpUZKxGojWA57kYYdYatZb/Co8IdZOljjlTvlMH2TSBL/NAo/Hq97snQn740RVY85ILhyFpdkZyLUydchCmXjcCATu7IfZGlH+WfLsWzj8/C4k8q0LwNFUycIH4aPneT780w9Y5aoPFFqYsfhnG+1etKigupbe09/zd99urxO0NA8QQpchCEURVATWXDwYwQUt4tvb1mFiD8tUvAVQBEoVk3wrdr02vPlJR0z9iLnIkBoW0P9ylkbQne+fd9GH/qGEy8cx7eL6mLTKKTcCPrhHwUzl+Kt+ffjoLjM2Hn0ew+CqqEyAlj76ilmXFyah6M0dYHCLhsJv8BgOJRoMXM/9ob/AFATVagWrxZSiE6CO0Gm023agwAyEGLjJ0lrxSVbPqs0y7ZdXQ9XCVhP4WvAp/NexiXnj4KF9wyA2//XBWZ6oLCg+wT81G4YClWzL8dE2wGAl6gU9j7Ri3GUZ6fLzwOcFke4FLhCW8WasukqHAH+RxuN5XLZXEzYvFWigEARYCQe0qXLd9S8lm3naLPUC/cP4Z9jNb34PuXn8a1w0di5JSn8PK3uxCRFYT7A4G/LFiKt+dNw/iBoQUCPoj2jvWNYlthoTJKqb/d+iIsoKUovEgDgADcKdYzIXVCTe5t4syI9ikO8LtFEbV304J3tpZ82n+H2X+gVyZ+HvYTmDVY9/ZM3DZmFM6c9HcUfVwOb4QCgc4njcN9C5fi7Xm3YfzAjk0KBHwm2jreN4pJ7XrP7JcnzR4S4C6kAAAgAElEQVSWBygi6BK4VidoMqBAwNTuZjJgaBgAUFRUbS76fGvpRwO3ySMOq5Mpq8JfXbAeWz5YgMLx5+L08wvx/MpNqIlEkoDwoPNJF+K+eQ/j4u6N/7wMIbihSSt1ilk1NSPI6yJBtVE+N46J4DUBPpLawK8XICuCPWrx+PWiqKopfWFtWen7w7bKo3vVmqkvhz8QCGDHV69g+uUXYMg5t+OJV37CHjv7k4ZMQDTh12VApDjfF4o5xXmJecJ/oeXrQsBta9vf+KYmq9aVAaGID4QyJbI9atkYAFBMqC+duaF883vnlZsnd6mR6bNNhL+6YOWPK/DUDQUYcsaNeGjBN9jmi/4KaQOCVcxaod6BNWMGIUi1aVWB28Ph/w8a+VwuM9Tr1qyBnQ2TWyUGABRT6jY/Vbat9J1LNuhnZVbKto+bUoR5DzOJuo0fYObtl2LYkCtwz8yPUBLFYilmsEGA4pOUYqRZf1ewUUpNUW2sLW8FhIAr2ToZcC9c7ZaW4aSI9qkFYwBAsWfAF64Oru+HJaJmlCKkY9G8r/wrLLjvOpw1eBKm/vtL7IzUDoS/IRkAtDrp8/p0v1AxrXexE8Jm5b/WQSQqcAWpi/whtLsi15uWjVMlFDOScq7LTlfWTk3YOeUqFWai8w9ABRJzjsXoCfmYcP4RyOAtF0XAycr2Gzub1t9ukajBbafwf2uxPxnQX91wwP4qtNM3FOvtTsrH7gj3rMVhAEBR1zbngsFJYutDCfjwJBGJ8tRKMroNOgcTJufhvCE9kG6VVUQUbsV57rGB1y61PmB/5T9+JYPSkhSo1QYaShQyoKi7fMrFgPlopPvV0jAAoOjo8HRKh8TllyZi5z1usT4ixXDU9J449YI8TJw4Aid1S4mJZ6wCsnnbCVCL0sP86MxhgPXKD02Bmw+FGudW4fIYMCx+Peeo2q15xf4nFuU3GCPQfgwAKKJSu0/sk2KW/DkBM/JVyAhMdGpo1/9UXDA5H+NHDUDnIAlE0aBAxsBu7RQRUooRC9LuClYgSkmymfxnmqgtDyAQOzv/NIlIdiGtnZ3fpIA7WYHP13ACb7mpZk82ceQi4Kvm9zJ+MQCgCFijZeROH50odj/oMdf2icgA7G6PI84ei4mTz8PwAZlIiKVR/zdUIWuj3QeKjMRFR2WPk8ZAywOEAo/Ntf9mnQG9hQ3+ACC9BnQjeFKfFSVRgUsx4W/o3y0E/k+q0wBjXLM7GccYAJBjUnpO7ZhqfH2TR069UYOZFIm1dglZR2HEhHEouHAoDu8QwW2CDyL9XngDjR+nStQ43xuKBSfIzVO6S+uVV8JjbyAEJPxRXMraLKaEzyvhSrHxS1X2JwPWNPwvny21c9sXGykin78xKwwAKOzadRt3QpIse8CjrxoakaQ+kYScE8/G+Ml5OH9Yb7SLWlKfhL77F6ycPx+zXnwTX21r/JZMhayMQMco2tYUamPK/3FdsG+mK1mFYuOrK/0G/H7bPYsyCaPWhJmi2liTLvZtE1zTcDKgXyrudYaaDxgzm9/P+MQAgMIj+9mkju5lkxPlzj+75C8R2eJWSe2GQeddgIkTR+KUXmnRS+qTJqrWf4DFM4sw5+UvsDWE3YdckHsc7BnFiE5bnh90jiKtN35SVbgT7bS8fwC13bPok34TPp+KRBvbHgu3CpfbgNFgACRwuKneIQuN2aKwRX9EjmEAQM2SnnNRz2Sx8Z5E8WyBkM4V7fkfFel9BuH8SfkYf+7xyA2yRajTpFmLzR++hjkz5mPJeyWosXGJSZByR/h7RrFmhFJ1V7Caz2qSYjP5T8JX1yIn/3/DRKDORILHZjJgkgKfv+FHIBuE2lP0Rm8APzW7m3GIAQDZINX2XUcPT0LFQ27x3WEROaXWFv3PPBcTJ5+PkQOzkGhnrjRMZP02fLGsGLNnvYxVP1U2a51REmR52DpGMSn1hb4Z41A61PqI4OVtg5FewzrzX0qs0bwDJ16I8G+7HaKMBZ2Oe1+v+izd4h9p1pkIpCtw26hNqySp0CpNBBqIAKQU4jKp3jIDxpWhtxz/GABQk6V2viMjWf38+kRx7C0qzNRInNOdeRjOvnAcCi4chqOzPFFcwifh374WbxbNw+y5K/H9rnBsUWAiTcrNYWiIYthh2s5LDgUs0/uER4XbZadlCX+Qu/9OMLctU2JjGdwuZfBXS8Xr5RdBNrxdr2nC75VwJ9v4hasK3IlAoK7hl6cLbWLOLOOGwktQH3rj8Y0BADUqveuEAcmi9K8JePNMJSL7R3iQPfAsjJucj7wz+6GDO4pr+KSOPT+9g4Uz5mHu8m9QEcayPQL1vg7Q14evRYo5xcXq6MAlt1h/gwW0ZMXejypgwh9kR8uXEHgsZgrh5C8yls1t98hkUf9ww5+FhFFjwkhWrSOlILQUFYrXgNnAx+GDmjjdpY4EjMU2mo5rDACoYd1mJXSQ8yckyr1/cYsfu0TilCK5C04ccwEKJo/GaX3aWO77HQnSqMaGd17BCzMWYOnHWxFCXl8TT+A3jhWlQx8rxYYwt0wxJMO89Zhzre56gX1L2Wxu/KPXGbDav0qBaZYoZkxlv//ozpr1fWDj9CMsZkOk30AgoEK1MRuybwmlAZ/FxFwbod5VJ40lQrTM1ZJOYQBAv5PQ7eJu6ebGO5PlkxcpkBFYSK8gtceJGDspHxPOOwk90tWoTvObtVvxyUsLMGvWMry3odaZ1GHpN44TGwbPL/F+7ETzFDuGGVV3BntWpiQq0Ozc/psmArXWY9kwob+3dgJ22mjZMVX5a3cXz0tbeYTUz2r4iH31DDxt7ORD7Cui5Kts+DP5UmhHTl/kzwFQGnLTcYwBAAGQol3O6DMSxY6HEuS3Rwt7xchCo6Wjz9DRKJh8AUaf3AXJUUzqAyTqy7/Bq3OKMHv+O/h5r3MrhoT068eKDadw8G8F5h6fNh7fjww2/e+yuYpF1hvwB5nc7xLQH1hro12nvaql/PXOwN6zrFZEmLUG9DQFLrvJgFU69AaTASH8pnYtoE8LveX4xQCgNetW2CbTfP/qRBw7TRNmeiRO6croizPGjUNBwZk4NjvRVuGTsJF+7PhuFebPKML81/+DneHI67MghBlIMSqf7yyrH5i/xbvVuTNRrDhGrh8/QFhfY4VbhSfYxgBWpESgzrryXwr0qvPq8e5bNpp22g48/vEyecmu8UJmNHiAacJfD7iCrZm0ou7bSEm32F3jZkOZkvks7p4yBU2o0dk6MABohdp0n3hksiy5zyOXjVREJJL63Oh49DCMm5yPcSMOR6YnuoX5pb4XP694CbNnLMKrX1TAye34FPj2pouaP5/jL32+sAx1Xzt4LoohhYXKSPGPadY/rn1V7Gz9+PYPklaeEOb/3Rurg1x+vrG8qN0TF6L+PqurgF5jwEyyURlQ7N9K2dtwcFQFLb04yT8EwIpQm45XDABai0PXujPq7shPMivu95hru0XilCIxC8eOOg8TJ52LMw7LgCuq476EUV2C94rnYfbs1/DxZq+j2UAa6n7KQOWtH5Rse1MAZtQXYlNEte0xo3+ekN0tD1AEPDaT/8xa6+Q/IaR0a/rTthqOkC/EIc+tk98XHmKxokj6DQR0FR4bo5NIUOFWTfgsHo+UKdrdgM4AYD8GAHEusfPlXdLV9bcl1ky6UoW0UWwzVALJuQMxemI+Ci4YjN5ttehuvytN1G3+HEtnF2F28UfYaKdcX5OZZgLq3mhn7LzjvS17vgcisRECxaIhovpP7YK8LhJVaHbWu0kTvlppGbwOkMa3ZXnYfLuNpiOldsKnFfOLUj+6F8agBg+QEr5aE+50G/kRigJXsoCvquFPaLXUBj1YrHd4Mh+swAkGAHFKiva5Y4YkYOeDCfjyeERiHFJT0eOUkSiYnIdzT8lFWtQK8+8nfSj//E0UzSzCghXrUOngamghdF+SrHm6h7Zj+svra7Y7dyZqEZ4dlZSnrhpnOUoLAbfNbX+lz0QgyHd5rzQeaAlL3V6Xbe6fJna9ZXVHYtaaMFLtrZDQklSo1XqDsySmUJTj/crlT8J8KPSW4w8DgHjSqzCtY+DDKxJx3J0uGMFuQMJGbXsITs/LR0HB2Tiha3J0k/oASP8ufP/GYsyasRhvfrcLDub1QUX9jjZK9d3D5ZY5hSWo/9bBc1HL0Sfl07EnS1jPtmkK3DaLW+m1DRe7AYAEGN5pAePVQlstR9bm2uFr3kgpqjoXMq3BAwwDfp8Gzc4GSa59n6/XokjSOKHeVFBs/l00oUjS5BcyOqvC19lGL2yrgie95zzl+qulfGVqQX2Jk+fiDGUcSOl6Sf9UseEviageq0Da2lE8NC60P3wo8ibn48KRRyPb5rPM8JHQ96zDqgVFmD3nTXxR7uzeqBpqv+0gK299r7RitUDs321RBEkpphal/nCzMPtbHaKlu5GSZuM3Y5io3RawrP1/F3wzZhcYl4fecHScUdT2b7Pgm2b1SYgEDantbW6RXBtA5W6LD0pKvKp6T5gyHp/+7u9rhmjTy74/5nBVz8809JEZQvZwSQQvS+RSkZqp2djIScK33Q9vIxnIKqCnQZZkA2+erAQW9kjXP3tyRPjylqN95Sa7Bnzh6rD7L2MTjYoH3SLQMyLn9HTE0eeMxcRJ5+Gsozogysn8gDRRveFDLJlVhDkvfY7Nju6KZpqJqHupvbLn7jUbd/7s4ImoBUtf0KvnSrPs12xpcW1VFCR2csFjI0w3a/yo3mP1/F8iTXoPTZ2I/4TecnS0m39YzmvmhpKuluOQgoQsFxLszFNLE7Vl1sHSePiXv1egjy6Ym3bcBGFckwM5vI1AR9Xqv5sVhwOAgwkBmSSxuyvkiqsReGZ6gf5eqGf+XXvNeTNFh5Z704ld5Aeva8Jo4/zZBBK7HIORBfkoyB+C/hmuqH9ppFmHLR+/hhdnzMfidzah2sG8PgHdm4KaR3oZux5btKVqt3NnongwfEGbfz5v+K+3el0kakjLUCHsDBgVfngtJrd6CH1D/S/+Q1rUvvdSihvmpXw+DXKA1SFquhupdmZLIKHvCaCmpuFwSYOh/wWuM4dIPHOSMPvYvqZFOAD4rc6QW55CoOC6ZgQB0b6WU4i03JtO7CzfX+kSpp1SGU0nkpE7aAQmTM7D+UN7Ij2ahfn3k/UV+HJ5MWbPeAkrm7kNb2M01G9NV6pvv7TdloVTvozRNdUUW4rz3DMCr+0+G0hu+AABdwc3khJCb1r6dVRXGJaj+y74phxRYDwXesvR1XNhx3NX6zUvW97kaypSOmm29gVp7DPzCLGtXspOzbqyRTEAAJofBDAJsAWJxOCvpnXHKRfko2DiORjUPcXGFzvcJAI7/4O35s7DrLkr8d1OB8diKeEWtZ9kysqpa0q3fwgAn2507nQUX7obH559muXgj33Jf7YW4koYtablQKbB0P8tjQV2Wo629akD3li1993as6TF56ab8PsAzUbQtK/SomE5a+Jr7uAfA7ZCdOkMV9FTRbAVBDAAaCGcHfxVtO13Ks6flI8JY45Fl2R79cnDSurY+/N7KJ5ZhLnLvka5k+X6YBjJqJ6XKXb/+e2Syo0t5iEqxQ4pxcj5aXcFq+yrJqn2Amop4QuS3zIOxmvvTESVjZajb8QbvsVFbWafBf+1DR8gEagxID12HpsIuJIF6v3WdROaRQCKS9ibR5cCiktACUiYzXxosxWiy2lC/SugnxLqexkAtACODf6uDBx+9rmYOOl8DD+uE6KezA9AGjXY+N4rmDNjPl760IFteH9DQaAmBZUPneza/NST61roBZRiQsaio7IvlMaxlgeIfQVqbI0VdYZlMhsgMdGlP/iOjXZjxYdq+8fKjbJrsiyGUukz4TdVW4mTSpIGbW8AgTBcR4QmoLoVqG4FmltA8zRj1zQBuNq64WoDmAETut+E4ZP7/q+NtcvfmKK/nRWTDABinCvnxuOy5AdvhHPw92QdhRHj81Aw7nQckRmBHX8bJWHWleGTlxdg9sxleHd9jYOZTBIavBs7yJrb3ivd+rIAjK8cOxe1FkebpVd3syhtCwAiQYHb1gJdCX+QbX87wtyeBnxpp+VYUTnu1w0LilJ+vFnIhpdO7t/62GMnGVBR4E4CArU23npgsPcIaG4FiuZA0pzYdx63WwFS9v1JGhKG34ThM6H7JXRf4zMYNRDBdp22xAAgxklRfppbGM3fqU8kovPxZ+9L6jujDzKiW5h/P4n68m/x+otFmDX/Hfy0x8m0Pik9qHk329z7pxWbd37xE5gBS2GyplAbs+0f1wQ7xJVkbz07dBN+v/Xl/2UReCy/CQVtYpoQcnlRxwevR81cqwFJrzVgpNpJtttXGVCpsy6g9N9uuFV4EgVUjwLVLaJW1EyoAlqiCi1R3VdNSu6fJfCZ0L0m/A0UONIhbI3lDABinEDVYc15v5LSFSePzUPBpJEYckh6DCT1AZAB7Px+FRbMnId5r/2AHQ7m9QlhBJL06lnZsvL+N7bu3hKLe6RTy9a5bNbg4ZBtLQ9QVbjtzM8CMIJs/KNI0/zaZc6w13Js+bnm+Jc/SFnlGwKLCorGvoEvMSH0C5jwqHBrBuobuc6oySoSUmLhAnmQ38wSuLQAAg3MCEibTyMYAMQ8b9fQ36Mg/ZBBGDspHxPGnoBuqTGQ1AdA6pX4ZeXLmD1zIV79rAJBdjRtNoHA3nRR9Zch3tJ/P1yBWpbpJacMF7vvTgxyd6kmKbaT//xBkv9OE/oHP8bLpjZTltctmttmwRDhv6jB1+W+RyEJCTZGuv3bBPsqG94mOB7IUAsY7ccAIMYJ6O2bfLDWBv3OGIOCyRdg1PHZSIp2YX4AB7bhfX/RAsyavRwflzq9Da/35/ayeur7pVtfF4D5hYPnIkqdN6R9vvzsVOsjBFx2V9XU6/AHSQjLkvoDP9ppN0a9p7T/x05ZdpHVBU/WGwiYCtw2NghSkxWo1Sb0llMmKSIYAMQ4Ab1JyR3qkRfjhf+bgoFZnpi424c04d3yBZa+UIQXFn6I9U6W64MpE1HzZmel+vY3N27/DuDzfYqMw+Xay/oDlul9wqPCHbyafMMkEKi1vmNNgV61qhZr4ul7vvuXiT8W9354wzXS7NHgAea+GRG3nWl6RYXbo0P3NrOTccZGLEWRJNC07H81ux+O7BQDg7/0Y9sXr+CRayfglKFX4d7n33ds8Bcw/Elyz+P9lXVZ35esH3Fg8CeKiOJidSzqrg32m9OSFXsXWcOAL8gzskeE+W8xJc4qVBYWmsuNhIesMxol9FrTXsajANyxUN8kxnAGINYJGay2SMyQgV344c0lmP38Irzx7S5Hr0yK9O1so1TfMwKbZxeWoJ6jPsUkRYHbZnEN02taJv8JSLld6E81o2cx6zt/n4Wfe77+1wnCYhe+gIGAT4Vqp6Jiggq3ZsLn5B7hLQwDgBgnIGP4v5GEsWc9Vi2ch9kvvIHPnS3XBxdqv2sna6Z+UFq2UgDyM0fPRtQ8SpIGzc7tv5TwBZn+P1IY32+/ECX/N745vYtRl31YvWhu+rITELigwdelhL/WhMdj425eKHAnCfiq4jUVMHQxPLgQAAhIW+VDHCVN1Gz8GEtmF2HOkk9RGqRQSfOZZiLqlmWJ3Xe+vWnXTwCf71NLIOxX/vMZCAS5S90ujAeFiNuEdqyUyQ9VYe8FVnV/TK/ZjGRAFVq1Dj3OPj273wcGADFOSMTMgytperH1k9fx4sx5WLR6o8Pb8AbqU0TNY4cHdj0yZ2v1ru+dOxWRAyR8FT6Ee07MA6MeqvFKmJuNKTvXX/nN4kP+seVSyC4NHmAaqNtqoC7M59X3+LF3T5gbjRAF9oqnMgCIeTLqw7/0bcfXry7CrBlLsOI/e53ehrc8WVTdMSp56/zCtfB/7eC5iJpLILJV+G6EvqAoH/Gdy15YaL5SlPGPi+B9IvamP2OTJqWttCsGAGRBIrDzJ7w1rwizX1yBb50s1wcTHun9rL2snvru5vL3gRZe3JxaDV0qOyCMbpE4lxBSPqQbjxRF4mRR9guyX3wP6x8cGmx7ZfqvdpC25i4YANDvSQOVv7yH4llFmLv0K5Q5Wa4P0kgSexfmmHvuea20coOTZyIKu/x84/bi4hPhv+zjScI4zunTDZT6F5s3oFXsVl1Z8P2ea4sOz3ka6zczCGjcmcL81M77WAeAAADSrMXGd+bjL5PH4pSzb8XfFzg3+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)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termiai/__main__.py
RENAMED
|
File without changes
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termiai/clean.py
RENAMED
|
File without changes
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/__init__.py
RENAMED
|
File without changes
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/__main__.py
RENAMED
|
File without changes
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/ftapi.py
RENAMED
|
File without changes
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/icon_data.py
RENAMED
|
File without changes
|
{terminal_assistant_interface-1.0.7 → terminal_assistant_interface-1.0.8}/src/termilib/test.py
RENAMED
|
File without changes
|