The functionality of this Terminal was previously attempted to be completed with the help of AI, but it did not provide satisfactory answers, so it was put on hold. Actually, I had already planned to stop using Jupyter-lab and VSCODE at that time because although they offer many cool features, they are all tied to the system. Although they help you complete many tasks, their functionalities cannot be separated and integrated into your own applications. The interfaces of these systems are not very user-friendly on mobile devices. To fully unleash creativity, achieve maximum efficiency, and have the ability to customize and infinitely expand, tools that provide complete freedom to configure the functionalities are necessary. Once you have the interface of a Terminal, you can do anything and continuously improve, adding new features. The most important thing is that all processes and functionalities can be customized to meet your requirements, and a slight increase in automation level can save a lot of time.
First, I just used Termux-API to create a simple graphical interface for selecting models, which is very easy to implement with just a few lines of code.
def selectDir(path):
ls=[x for x in os.listdir(path) if x.endswith("bin")]
c='termux-dialog radio -v "%s" -t "Select model"' % ",".join(ls)
v=eval(os.popen(c).read())["text"]
return v
models_path_default = "models/"
model_name_default = selectDir(models_path_default)
model_type_default = "llama"
if model_name_default.startswith("gpt2"):model_type_default="gpt2"
if model_name_default.startswith("mpt"):model_type_default="mpt"
if model_name_default.startswith("dolly"):model_type_default="dolly-v2"
if model_name_default.startswith("falcon"):model_type_default="falcon"
Then it was the Terminal. When I found that pty could be used, I immediately started working on it and created the Class Terminal which can be used and customized freely, combined with selectors and only 60 lines of code. Later, I easily implemented the Web interface functionality through JavaScript + FastAPI + Pydantic. However, I encountered a difficulty at that time: the data output by Stout contains many special characters used for color marking. To correctly process this data, extensive research and a lot of time were needed, but these color information was not necessary and I didn't want to waste time on them. Finally, I decided to seek help from AI and wrote a regular expression to filter out these unnecessary information. Although this expression is not perfect yet, it already works, and I will revise it when needed.
The following clear_text has been improved once, and I will continue to make further improvements as I discover better methods.
import os
import sys
import pty
import selectors
import threading
import time
import re
def clean_text(text):
ansi_escape = re.compile(r'\033\[[0-9;?]*[a-zA-Z]')
text = ansi_escape.sub("", text)
text = re.sub(r'\x1b\].*?(\x07|\x1b\\)', '', text)
return text
def print_stdout(data):
print(data,end="",flush=True)
class Terminal:
def __init__(self, stdoutCallback=print_stdout):
self.pid, self.master_fd = pty.fork()
self.temp = ""
self.max_temp = 1024*64
self.stdin=sys.stdin
self.terminal_thread = threading.Thread(target=self.run)
if self.pid == 0:
os.execvp('/bin/bash', ['/bin/bash'])
else:
os.set_blocking(self.master_fd, False)
os.dup2(self.master_fd, sys.stderr.fileno())
self.stdoutCallback = stdoutCallback
def close(self):
os.close(self.master_fd)
os.kill(self.pid, 9)
self.terminal_thread.join()
def write(self,data):
if isinstance(data,str):data=data.encode("utf-8")
if data==b"clear\n":self.temp=""
os.write(self.master_fd,data)
def run(self):
sel = selectors.DefaultSelector()
sel.register(self.stdin, selectors.EVENT_READ, self.input_callback)
sel.register(self.master_fd, selectors.EVENT_READ, self.output_callback)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj)
def input_callback(self, stdin):
line = stdin.readline()
os.write(self.master_fd, line.encode("utf-8"))
def output_callback(self, master):
data = os.read(self.master_fd, 1024*16)
if not data:
raise OSError
data=data.decode("utf-8")
text = clean_text(data)
self.temp+=text
temp_len=len(self.temp)
if temp_len>self.max_temp:
self.temp=self.temp[(temp_len-self.max_temp):]
if self.stdoutCallback:self.stdoutCallback(data)
def start(self):
self.terminal_thread.start()
沒有留言:
發佈留言