danielgross / localpilot

MIT License
3.34k stars 143 forks source link

New Feature Request: Support for Ubuntu OS #13

Open agn-7 opened 12 months ago

agn-7 commented 12 months ago

Hello Maintainers,

I recently came across your incredible package, "Use GitHub Copilot locally on your Macbook with one-click!".

I would love to be able to use this package in Ubuntu as well.

The current version of the package supports MacOS only. This feature request is to extend the support to Ubuntu. This would enable a wider range of developers to benefit from this package.

janEbert commented 12 months ago

Hey, if you want a very quick solution, I used Mistral-7B-v0.1 to convert usage of rumps to tkinter and fixed some hick-ups.

New requirements.txt (I also downgraded the NumPy version because Python 3.8 wasn't supported anymore):

annotated-types==0.5.0
anyio==3.7.1
certifi==2023.7.22
charset-normalizer==3.3.0
click==8.1.7
exceptiongroup==1.1.3
fastapi==0.103.2
h11==0.14.0
httpcore==0.18.0
httpx==0.25.0
idna==3.4
llama_cpp_python==0.2.11
numpy==1.24.0
pydantic==2.4.2
pydantic-settings==2.0.3
pydantic_core==2.10.1
python-dotenv==1.0.0
requests==2.31.0
sniffio==1.3.0
sse-starlette==1.6.5
starlette==0.27.0
starlette-context==0.3.6
typing_extensions==4.8.0
urllib3==2.0.5
uvicorn==0.23.2

New app.py:

import tkinter as tk
import tkinter.messagebox
import requests
import threading
import subprocess
import os
import sys

import config

def setup():
    if not os.path.exists(config.model_folder):
        if input(f"Model folder {config.model_folder} does not exist. Create it? (y/n) ").lower() == 'y':
            os.mkdir(config.model_folder)
    current = os.listdir(config.model_folder)
    for model in config.models:
        if model == 'default':
            continue
        if config.models[model]['type'] == 'local':
            if config.models[model]['filename'] not in current:
                if input(f'Model {model} not found in {config.model_folder}. Would you like to download it? (y/n) ').lower() == 'y':
                    url = config.models[model]['url']
                    print(f"Downloading {model} from {url}...")
                    subprocess.run(['curl', '-L', url, '-o', os.path.join(
                        config.model_folder, config.models[model]['filename'])])
            else:
                print(f"Model {model} found in {config.model_folder}.")

class ModelPickerApp:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("ModelPickerApp")
        self.root.iconphoto(False, tk.PhotoImage(file="icon.png"))

        self.model_var = tk.StringVar()
        # Dynamically create menu items from the MENUBAR_OPTIONS
        self.menu_items = {}
        for (i, option) in enumerate(config.models):
            if option == 'default':
                continue
            self.menu_items[option] = tk.Radiobutton(
                self.root, text=option, value=option, variable=self.model_var,
                command=self.pick_model)
            self.menu_items[option].grid(row=i, column=0, sticky="W")

        self.menu_items[config.models['default']].select()

    def pick_model(self):
        # Send the choice to the local proxy app
        choice = self.model_var.get()
        try:
            response = requests.post(
                "http://localhost:5001/set_target", json={"target": choice})
            if response.status_code == 200:
                print(f"Successfully sent selection: {choice}.")
            else:
                tk.messagebox.showerror(
                    "Error", f"Failed to send selection. Server responded with: {response.status_code}.")
        except requests.RequestException as e:
            tk.messagebox.showerror(
                "Error", f"Failed to send selection. Error: {e}.")

    def run_server(self):
        subprocess.run(['python', 'proxy.py'])

if __name__ == '__main__':
    if '--setup' in sys.argv:
        setup()
    app = ModelPickerApp()
    print("Running server...")
    server_thread = threading.Thread(target=app.run_server)
    server_thread.start()
    app.root.mainloop()
surak commented 12 months ago

Jan, how about you make a formal merge request which detects the os and use rumps when on mac, or tkinter on Linux? That would make sure the thing keeps working

janEbert commented 12 months ago

TBH I thought tkinter was too old-school for this repo, so I wasn't considering it. However, it does get the job done and seems to still be highly portable.

@danielgross should weigh in before I do the work. :)