Download UI_VCS.py from mch84/CoCreate: direct link, hf CLI and curl.
- Browser
- Download file 20 kB
-
https://huggingface.co/spaces/mch84/CoCreate/resolve/main/UI_VCS.py
- Command line
-
hf download hf://spaces/mch84/CoCreate/UI_VCS.py
-
curl -L -o UI_VCS.py https://huggingface.co/spaces/mch84/CoCreate/resolve/main/UI_VCS.py
20 kB
| # **Installs & imports** | |
| """ | |
| !pip install gradio -q | |
| !pip install html -q | |
| # **Installs & Imports** | |
| from difflib import Differ | |
| from pathlib import Path | |
| import time | |
| import tempfile | |
| import atexit | |
| import os | |
| from io import BytesIO | |
| import gradio as gr | |
| import re | |
| import shlex | |
| import html | |
| import subprocess | |
| import shutil | |
| # For images | |
| from PIL import Image | |
| import numpy as np | |
| """# **Build custom theme**""" | |
| custom_theme = gr.themes.Ocean( | |
| primary_hue="indigo", | |
| secondary_hue="yellow", | |
| neutral_hue="indigo", | |
| text_size="lg", | |
| radius_size="lg", | |
| font=['IBM Plex Sans', 'ui-sans-serif', 'system-ui', gr.themes.GoogleFont('sans-serif')], | |
| font_mono=['Inter', 'ui-monospace', gr.themes.GoogleFont('Consolas'), 'monospace'], | |
| ).set( | |
| background_fill_secondary='*secondary_50', | |
| background_fill_secondary_dark='*neutral_950', | |
| border_color_accent='*primary_50', | |
| border_color_primary='*neutral_300', | |
| color_accent='*primary_300', | |
| color_accent_soft_dark='*neutral_500', | |
| checkbox_label_background_fill='*color_accent_soft', | |
| button_large_radius='*radius_sm', | |
| button_small_radius='*radius_sm', | |
| button_primary_background_fill='linear-gradient(120deg, *primary_500 0%, *primary_300 60%, *primary_400 100%)', | |
| button_primary_background_fill_hover='radial-gradient(circle, *secondary_400 0%, *primary_300 60%, *primary_300 100%)' | |
| ) | |
| """# **Functions** | |
| ## Global constants file paths | |
| """ | |
| def create_tmp_file() -> str: | |
| tmp_file = tempfile.NamedTemporaryFile(mode="w+", delete=False) | |
| tmp_file.close() | |
| return tmp_file.name | |
| def write_tmp_file(content: str, file_path: str): | |
| with open(file_path, "w") as file: | |
| file.write(content) | |
| def read_tmp_file(file_path: str) -> str: | |
| with open(file_path, "r") as file: | |
| return file.read() | |
| def cleanup_tmp_files(): | |
| os.remove(CREATOR_NAME_FILE) | |
| os.remove(CREATOR_EMAIL_FILE) | |
| os.remove(PROJECT_NAME_FILE) | |
| CREATOR_NAME_FILE = create_tmp_file() | |
| CREATOR_EMAIL_FILE = create_tmp_file() | |
| PROJECT_NAME_FILE = create_tmp_file() | |
| # **Define UI functions** | |
| # For texts | |
| def diff_texts(text1, text2): | |
| d = Differ() | |
| return [ | |
| (token[2:], token[0] if token[0] != " " else None) | |
| for token in d.compare(text1, text2) | |
| ] | |
| def download_file(): | |
| return [gr.UploadButton(visible=True), gr.DownloadButton(visible=False)] | |
| """## Create project""" | |
| def validate_email(email: str, max_length: int=50): | |
| if not email or len(email) > max_length: | |
| return False | |
| email_regex = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' | |
| return re.match(email_regex, email) is not None | |
| def validate_project_name(project_name: str, max_length: int=50): | |
| if not project_name or len(project_name) > max_length: | |
| return False | |
| return True | |
| def validate_creator_name(creator_name: str, max_length: int=50): | |
| if not creator_name or len(creator_name) > max_length: | |
| return False | |
| return True | |
| def run_create_project_script(project_name: str, creator_name: str, creator_email): | |
| if validate_project_name(project_name): | |
| project_name = project_name.replace(" ", "_") | |
| else: | |
| return "Empty/Invalid project name" | |
| if not creator_name: | |
| return "Empty/Invalid creator name" | |
| if not validate_email(creator_email): | |
| return "Empty/Invalid email address" | |
| project_name_clean = shlex.quote(html.escape(project_name)) | |
| creator_name_clean = shlex.quote(html.escape(creator_name)) | |
| creator_email_clean = shlex.quote(html.escape(creator_email)) | |
| write_tmp_file(project_name_clean, PROJECT_NAME_FILE) | |
| write_tmp_file(creator_name_clean, CREATOR_NAME_FILE) | |
| write_tmp_file(creator_email_clean, CREATOR_EMAIL_FILE) | |
| arguments = ["./", project_name_clean, creator_name_clean, creator_email_clean] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/create_project.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return result.stdout | |
| """## Upload project""" | |
| def validate_uploaded_text(uploaded_text: str): | |
| max_length=10000 | |
| if uploaded_text is not None and uploaded_text != "" and len(uploaded_text) < max_length: | |
| return True | |
| return False | |
| def validate_commit_message(commit_message: str): | |
| max_length=1000 | |
| if commit_message is not None and len(commit_message) < max_length: | |
| return True | |
| return False | |
| def validate_filepath(filepath: str): | |
| if filepath is not None and os.path.exists(filepath): | |
| return True | |
| return False | |
| def move_file_to_project(filepath: str, project_path: str): | |
| if filepath == "" or filepath is None: | |
| return False | |
| if not os.path.exists(filepath): | |
| return False | |
| name = Path(filepath).name | |
| destination = os.path.join(project_path, name) # Create destination path: target_dir/filename | |
| shutil.move(filepath, destination) | |
| return os.path.exists(destination) | |
| def run_upload_project_script(project_path: str, filepath: str): | |
| filename = Path(filepath).name | |
| if move_file_to_project(filepath, project_path): | |
| commit_message = f"Uploaded '{filename}' to '{project_path}' project" | |
| if validate_commit_message(commit_message): | |
| arguments = [os.getcwd(), project_path, commit_message] | |
| !sed -i 's/\r$//' ./vcs_scripts/upload2.sh | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/upload2.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return True, f"{result.stdout}" | |
| else: | |
| return False, f"Something went wrong with commit message: {commit_message}" | |
| return False, "Please create a project first" | |
| def upload_text(uploaded_text: str): | |
| project_path = read_tmp_file(PROJECT_NAME_FILE) | |
| if project_path == "": | |
| return gr.DownloadButton(visible=False), gr.Textbox(value="Please create a project first.", visible=True) | |
| if not validate_uploaded_text(uploaded_text.get("text", "")): | |
| return gr.DownloadButton(visible=False), gr.Textbox(value="Empty/Invalid argument entered.", visible=True) | |
| # Sanitize text input | |
| text = shlex.quote(html.escape(uploaded_text.get("text", ""))) | |
| commit_message_clean = shlex.quote(html.escape("Uploaded ")) | |
| filename = uploaded_text.get("name", "untitled.txt") | |
| with open(filename, "w", encoding="utf-8") as file: | |
| file.write(uploaded_text.get("text", "")) | |
| status, message = run_upload_project_script(project_path, os.path.join(os.getcwd(), filename)) | |
| if status: | |
| return gr.DownloadButton(value=filename, label=f"Download {filename}", visible=True), gr.Textbox(value=message, visible=True) | |
| return gr.DownloadButton(visible=False), gr.Textbox(value=message, visible=True) | |
| def upload_file(filepath: str): | |
| project_name = read_tmp_file(PROJECT_NAME_FILE) | |
| if project_name == "": | |
| return gr.DownloadButton(visible=False), gr.Textbox(value="Please create a project first.", visible=True) | |
| filename = Path(filepath.name).name | |
| project_path = os.path.join(os.getcwd(), project_name) | |
| status, message = run_upload_project_script(project_path, filepath) | |
| if status: | |
| return gr.DownloadButton(value=filename, label=f"Download {filename}", visible=True), gr.Textbox(value=message, visible=True) # gr.Textbox(value=message, visible=True) | |
| return gr.DownloadButton(visible=False), gr.Textbox(value=message, visible=True) | |
| # For image uploads | |
| def sleep(img_dict): | |
| time.sleep(5) | |
| return [img_dict["background"], img_dict["layers"][0], img_dict["layers"][1], img_dict["composite"]] | |
| def show_image(img_dict): | |
| return img_dict["composite"] | |
| def upload_image(img_dict): | |
| output_path = "output_image.png" | |
| image = img_dict["composite"] | |
| image = Image.fromarray(image) | |
| # Save the image to the output path | |
| image.save(output_path) | |
| return f"Image saved to {output_path}" | |
| def run_upload_project_script(project_path: str, filepath: str): | |
| filename = Path(filepath).name | |
| if move_file_to_project(filepath, project_path): | |
| commit_message = f"Uploaded '{filename}' to '{project_path}' project." | |
| if validate_commit_message(commit_message): | |
| arguments = [os.getcwd(), project_path, commit_message] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/upload2.sh"] + arguments, capture_output=True, text=True, check=True, shell=False)#, shell=True) | |
| return True, f"Automatic commit message - {commit_message}\n{result.stdout}" | |
| else: | |
| return False, f"Something went wrong with commit message: {commit_message}" | |
| return False, "Please create a project first" | |
| """## Recreate project""" | |
| def run_recreate_project_script(project_name: str, new_project_name: str): | |
| if validate_project_name(new_project_name): | |
| new_project_name = new_project_name.replace(" ", "_") | |
| new_project_name_clean = shlex.quote(html.escape(new_project_name)) | |
| else: | |
| return "Empty/Invalid new project name" | |
| if validate_project_name(project_name): | |
| if os.path.isdir(project_name): | |
| arguments = ["./vcs_scripts", "./", project_name, new_project_name_clean] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/recreate.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return result.stdout | |
| elif os.path.isdir(project_name + ".git"): # If user forget to include .git part in entered remote project name | |
| arguments = ["./vcs_scripts", "./", project_name + ".git", new_project_name_clean] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/recreate.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return result.stdout | |
| else: | |
| return f"Project '{project_name}' does not exist." | |
| else: | |
| return f"Empty/Invalid project name {project_name}" | |
| """## Download project""" | |
| def run_download_script(project_name: str): | |
| if validate_project_name(project_name): | |
| project_path = os.path.join(os.getcwd(), project_name) | |
| if os.path.isdir(project_path): | |
| arguments = ["./", project_name] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/download.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return result.stdout | |
| elif os.path.isdir(project_path + ".git"): # If user forget to include .git part in entered remote project name | |
| arguments = ["./", project_name + ".git"] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/download.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return result.stdout | |
| else: | |
| return f"Project '{project_name}' does not exist in path." | |
| else: | |
| return f"Empty/Invalid project name {project_name}" | |
| """## Revert project""" | |
| def run_revert_script(project_name: str, revert_hash: str): | |
| if validate_project_name(project_name): | |
| project_path = os.path.join(os.getcwd(), project_name) | |
| if os.path.isdir(project_path): | |
| arguments = ["./vcs_script", "./", project_name, revert_hash] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/revert2.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return result.stdout | |
| elif os.path.isdir(project_path + ".git"): # If user forget to include .git part in entered project name | |
| arguments = ["./vcs_script", "./", project_name + ".git", revert_hash] | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/revert2.sh"] + arguments, capture_output=True, text=True, shell=False) | |
| return result.stdout | |
| else: | |
| return f"Project '{project_name}' does not exist in path." | |
| else: | |
| return f"Empty/Invalid project name {project_name}" | |
| """# **Build layout**""" | |
| os.chmod("./vcs_scripts/grant_permissions.sh", 0o755) | |
| result = subprocess.run(["C:\\Program Files\\Git\\bin\\bash.exe", "./vcs_scripts/grant_permissions.sh"], capture_output=True, text=True, shell=False) | |
| print(result.stdout) | |
| with gr.Blocks(theme=custom_theme, title="Version Control") as demo: | |
| gr.Markdown("<h1 style='text-align: center;'>Your project</h1>") | |
| with gr.Tabs(): | |
| with gr.Tab("Create Empty Project"): | |
| with gr.Row(): | |
| project_name = gr.Textbox(label="Project name", placeholder="my_creation, my-creation, or myCreation") | |
| with gr.Row(): | |
| creator_name = gr.Textbox(label="Creator name", placeholder="Victor Frankenstein") | |
| creator_email = gr.Textbox(label="Creator email", placeholder="example@gmail.com") | |
| with gr.Row(): | |
| submit_btn = gr.Button("Create project", variant="primary") | |
| with gr.Row(): | |
| output = gr.Textbox(label="status") | |
| submit_btn.click(fn=run_create_project_script, inputs=[project_name, creator_name, creator_email], outputs=output) | |
| with gr.Tab("Text Upload"): | |
| with gr.Group(): | |
| with gr.Accordion(label="Use basic text editor...", open=False): | |
| text_input = gr.MultimodalTextbox( | |
| label="(max 10000 characters)", | |
| sources=["microphone"], | |
| file_types=[".txt"], | |
| placeholder="Enter your text here or speak...", | |
| submit_btn="Upload", | |
| lines=8 | |
| ) | |
| with gr.Group(): | |
| file_upload = gr.File( | |
| label="Upload a text file", | |
| file_types=["text"], | |
| file_count="single", | |
| interactive=True | |
| ) | |
| #commit_textbox = gr.Textbox(label="commit message", placeholder="Commit message must be under 1000 chars", visible=True, interactive=True) | |
| file_output = gr.DownloadButton(label="Download File", visible=False, variant="primary") | |
| download_button = gr.DownloadButton("Download the file", visible=False, variant="primary") | |
| status_textbox = gr.Textbox(label="status", visible=False, interactive=False) | |
| text_input.submit(fn=upload_text, inputs=[text_input], outputs=[file_output, status_textbox]) | |
| file_upload.upload(upload_file, [file_upload], [download_button, status_textbox]) | |
| download_button.click(download_file, None, [file_upload, download_button]) | |
| with gr.Tab("Image Upload"): | |
| with gr.Row(): | |
| img_editor = gr.ImageEditor( | |
| label="Image uploader & editor", | |
| type="numpy", | |
| crop_size="16:8", | |
| scale=4, | |
| brush=gr.Brush(color_mode="defaults", colors=[ | |
| "#FFADAD", | |
| "#FFD6A5", | |
| "#FDFFB6", | |
| "#CAFFBF", | |
| "#9BF6FF", | |
| "#A0C4FF", | |
| "#BDB2FF", | |
| "#FFC6FF", | |
| # Neutral colors: | |
| "#FFFFFF", # White | |
| "#808080", # Gray | |
| "#000000", # Black | |
| # Skin tones and browns: | |
| "#F5D0C5", # Peach | |
| "#E0A98A", # Sand | |
| "#F1C6A0", # Gold | |
| "#EDA268", # Tan | |
| "#D0743A", # Bronze | |
| "#6B3F1F", # Chocolate | |
| "#3C0000" # Mahogany | |
| ] | |
| ), | |
| canvas_size=(1920,1080) | |
| ) | |
| with gr.Row(): | |
| img_preview = gr.Image(label="Result image") | |
| with gr.Row(): | |
| n_upload = gr.Number(0, label="Number of upload events", step=1, interactive=False) | |
| n_change = gr.Number(0, label="Number of change events", step=1, interactive=False) | |
| with gr.Row(): | |
| upload_btn = gr.Button("Upload image") | |
| with gr.Row(): | |
| output_text = gr.Textbox(label="Status", interactive=False) | |
| img_editor.upload(lambda x: x + 1, outputs=n_upload, inputs=n_upload) | |
| img_editor.change(lambda x: x + 1, outputs=n_change, inputs=n_change) | |
| img_editor.change(show_image, outputs=img_preview, inputs=img_editor, show_progress="hidden") | |
| upload_btn.click(fn=upload_image, inputs=img_editor, outputs=output_text) | |
| with gr.Tab("Recreate"): | |
| with gr.Row(): | |
| project_name = gr.Textbox(label="Remote project you want to recreate", | |
| interactive=True) | |
| new_project_name = gr.Textbox(label="Your new project name", | |
| interactive=True) | |
| with gr.Row(): | |
| submit_btn = gr.Button("Recreate project", variant="primary") | |
| with gr.Row(): | |
| recreate_output = gr.Textbox(label="status", interactive=False) | |
| submit_btn.click(fn=run_recreate_project_script, inputs=[project_name, new_project_name], outputs=recreate_output) | |
| """ | |
| with gr.Tab("Download"): | |
| with gr.Row(): | |
| project_name = gr.Textbox(label="Project you want to download", | |
| interactive=True) | |
| with gr.Row(): | |
| submit_btn = gr.Button("Download any new changes", variant="primary") | |
| with gr.Row(): | |
| download_output = gr.Textbox(label="status", interactive=False) | |
| submit_btn.click(fn=run_download_script, inputs=[project_name], outputs=download_output) | |
| """ | |
| with gr.Tab("Compare"): | |
| with gr.Row(): | |
| gr.Markdown("<h1>Compare version differences</h1>") | |
| with gr.Row(): | |
| original_version = gr.Textbox( | |
| label="Original", | |
| info="Initial text", | |
| lines=4, | |
| value="Blasted as thou wert, my agony was still superior to thine.", | |
| interactive=False, | |
| ) | |
| new_version = gr.Textbox( | |
| label="Uploaded", | |
| info="New changes", | |
| lines=4, | |
| value="Blasted as thou (Victor Frankenstein) wert, my (the creature's) agony was still superior to his (because creature is ugly and has no friends)", | |
| interactive=False, | |
| ) | |
| compare_btn = gr.Button("Compare differences", variant="primary") | |
| with gr.Row(): | |
| result = gr.HighlightedText( | |
| label="Diff", | |
| combine_adjacent=True, | |
| show_legend=True, | |
| color_map={"+": "blue", "-": "red"} | |
| ) | |
| compare_btn.click(fn=diff_texts, inputs=[original_version, new_version], outputs=result) | |
| with gr.Tab("Revert"): | |
| with gr.Row(): | |
| project_name = gr.Textbox(label="Project name", interactive=True) | |
| revert_hash = gr.Textbox(label="Revert back to...", | |
| info="hash value", | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| submit_btn = gr.Button("Revert", variant="primary") | |
| with gr.Row(): | |
| revert_output = gr.Textbox(label="status", interactive=False) | |
| submit_btn.click(fn=run_revert_script, inputs=[project_name, revert_hash], outputs=revert_output) | |
| if __name__ == "__main__": | |
| demo.launch(debug=True, share=True) | |
| atexit.register(cleanup_tmp_files) |