Init
Browse files- GoogleDrive_API.py +80 -0
- Kaggle_API.py +162 -0
- app.py +89 -0
- requirements.txt +3 -0
GoogleDrive_API.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from google.oauth2 import service_account
|
| 3 |
+
from googleapiclient.discovery import build
|
| 4 |
+
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class GoogleDrive_API:
|
| 8 |
+
def __init__(self):
|
| 9 |
+
self.SCOPES = ["https://www.googleapis.com/auth/drive"]
|
| 10 |
+
self.SERVICE_ACCOUNT_FILE = "service_account.json"
|
| 11 |
+
self.PARENT_FOLDER_ID = "1r-MlnEpWHx3b1fxHDnHcZ2-Wh_Y89676"
|
| 12 |
+
self.service = self.authenticate()
|
| 13 |
+
self.clear_files()
|
| 14 |
+
|
| 15 |
+
def authenticate(self):
|
| 16 |
+
credentials = service_account.Credentials.from_service_account_file(
|
| 17 |
+
self.SERVICE_ACCOUNT_FILE, scopes=self.SCOPES
|
| 18 |
+
)
|
| 19 |
+
service = build("drive", "v3", credentials=credentials)
|
| 20 |
+
|
| 21 |
+
return service
|
| 22 |
+
|
| 23 |
+
def get_files(self):
|
| 24 |
+
# List all files in the folder
|
| 25 |
+
results = (
|
| 26 |
+
self.service.files()
|
| 27 |
+
.list(
|
| 28 |
+
q=f"'{self.PARENT_FOLDER_ID}' in parents and trashed=false",
|
| 29 |
+
fields="files(id, name)",
|
| 30 |
+
)
|
| 31 |
+
.execute()
|
| 32 |
+
)
|
| 33 |
+
return results.get("files", [])
|
| 34 |
+
|
| 35 |
+
def clear_files(self):
|
| 36 |
+
items = self.get_files()
|
| 37 |
+
|
| 38 |
+
# Delete each file
|
| 39 |
+
for item in items:
|
| 40 |
+
file_id = item["id"]
|
| 41 |
+
self.service.files().delete(fileId=file_id).execute()
|
| 42 |
+
|
| 43 |
+
def upload_file(self, file_name, file_path):
|
| 44 |
+
file_metadata = {
|
| 45 |
+
"name": file_name,
|
| 46 |
+
"parents": [self.PARENT_FOLDER_ID],
|
| 47 |
+
}
|
| 48 |
+
media = MediaFileUpload(file_path)
|
| 49 |
+
file = (
|
| 50 |
+
self.service.files()
|
| 51 |
+
.create(body=file_metadata, media_body=media, fields="id")
|
| 52 |
+
.execute()
|
| 53 |
+
)
|
| 54 |
+
print(rf"{file_path} uploaded. ID:", file.get("id"))
|
| 55 |
+
|
| 56 |
+
def download_file(self, file_name, file_path):
|
| 57 |
+
results = (
|
| 58 |
+
self.service.files()
|
| 59 |
+
.list(
|
| 60 |
+
q=f"'{self.PARENT_FOLDER_ID}' in parents and name='{file_name}' and trashed=false",
|
| 61 |
+
fields="files(id)",
|
| 62 |
+
)
|
| 63 |
+
.execute()
|
| 64 |
+
)
|
| 65 |
+
items = results.get("files", [])
|
| 66 |
+
|
| 67 |
+
if items:
|
| 68 |
+
# Get the file ID
|
| 69 |
+
file_id = items[0]["id"]
|
| 70 |
+
|
| 71 |
+
request = self.service.files().get_media(fileId=file_id)
|
| 72 |
+
|
| 73 |
+
with open(file_path, "wb") as file:
|
| 74 |
+
downloader = MediaIoBaseDownload(file, request)
|
| 75 |
+
done = False
|
| 76 |
+
while not done:
|
| 77 |
+
status, done = downloader.next_chunk()
|
| 78 |
+
print(f"Download {int(status.progress() * 100)}%.")
|
| 79 |
+
else:
|
| 80 |
+
print(rf"Fine {file_name} is Not Found")
|
Kaggle_API.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import shutil
|
| 3 |
+
import subprocess
|
| 4 |
+
import json
|
| 5 |
+
import time
|
| 6 |
+
from PIL import Image
|
| 7 |
+
|
| 8 |
+
from GoogleDrive_API import GoogleDrive_API
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class API_Connection:
|
| 12 |
+
def __init__(self, kaggle_username: str = "", kaggle_key=""):
|
| 13 |
+
os.environ["KAGGLE_USERNAME"] = kaggle_username
|
| 14 |
+
os.environ["KAGGLE_KEY"] = kaggle_key
|
| 15 |
+
|
| 16 |
+
self.PROJECT_PATH = r""
|
| 17 |
+
self.NOTEBOOK_ID = "amirmoris/pix2pix"
|
| 18 |
+
self.DATASET_NAME = "dataset"
|
| 19 |
+
|
| 20 |
+
def execute_terminal_command(self, command: str):
|
| 21 |
+
try:
|
| 22 |
+
process = subprocess.Popen(
|
| 23 |
+
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
| 24 |
+
)
|
| 25 |
+
output, error = process.communicate()
|
| 26 |
+
output = str(output.decode("utf-8"))
|
| 27 |
+
error = str(error.decode("utf-8"))
|
| 28 |
+
print(rf"Command executed successfully: {command}")
|
| 29 |
+
return output
|
| 30 |
+
except Exception as e:
|
| 31 |
+
return None, str(e)
|
| 32 |
+
|
| 33 |
+
def correct_path(self, path: str):
|
| 34 |
+
return path[1:] if path.startswith("\\") else path
|
| 35 |
+
|
| 36 |
+
def create_folder(self, path: str):
|
| 37 |
+
path = self.correct_path(path)
|
| 38 |
+
if os.path.exists(path):
|
| 39 |
+
shutil.rmtree(path)
|
| 40 |
+
self.execute_terminal_command(rf"mkdir {path}")
|
| 41 |
+
|
| 42 |
+
def pull_kaggle_notebook(self, notebook_path: str):
|
| 43 |
+
command = rf"kaggle kernels pull {self.NOTEBOOK_ID} -p {notebook_path} -m"
|
| 44 |
+
return self.execute_terminal_command(command)
|
| 45 |
+
|
| 46 |
+
def push_kaggle_notebook(self, notebook_path: str):
|
| 47 |
+
command = rf"kaggle kernels push -p {notebook_path}"
|
| 48 |
+
return self.execute_terminal_command(command)
|
| 49 |
+
|
| 50 |
+
def get_notebook_status(self):
|
| 51 |
+
command = rf"kaggle kernels status {self.NOTEBOOK_ID}"
|
| 52 |
+
return self.execute_terminal_command(command)
|
| 53 |
+
|
| 54 |
+
def run(self, notebook_path: str):
|
| 55 |
+
notebook_path = self.correct_path(notebook_path)
|
| 56 |
+
self.pull_kaggle_notebook(notebook_path)
|
| 57 |
+
return self.push_kaggle_notebook(notebook_path)
|
| 58 |
+
|
| 59 |
+
def write_file(self, data: list, file_path: str, file_name: str = ""):
|
| 60 |
+
if len(file_name) > 0:
|
| 61 |
+
file_path = rf"{file_path}\{file_name}"
|
| 62 |
+
|
| 63 |
+
file_path = self.correct_path(file_path)
|
| 64 |
+
# Writing JSON data
|
| 65 |
+
with open(file_path, "w") as file:
|
| 66 |
+
for idx in range(len(data)):
|
| 67 |
+
json_string = json.dumps(data[idx]) + (
|
| 68 |
+
"\n" if idx < len(data) - 1 else ""
|
| 69 |
+
)
|
| 70 |
+
file.write(json_string)
|
| 71 |
+
|
| 72 |
+
def read_image(self, image_path: str):
|
| 73 |
+
try:
|
| 74 |
+
image = Image.open(image_path)
|
| 75 |
+
return image
|
| 76 |
+
except IOError:
|
| 77 |
+
print("Unable to load image")
|
| 78 |
+
return None
|
| 79 |
+
|
| 80 |
+
def get_notebook_output(self, output_path: str):
|
| 81 |
+
output_path = self.correct_path(output_path)
|
| 82 |
+
command = rf"kaggle kernels output {self.NOTEBOOK_ID} -p {output_path}"
|
| 83 |
+
return self.execute_terminal_command(command)
|
| 84 |
+
|
| 85 |
+
def generate_image(
|
| 86 |
+
self,
|
| 87 |
+
input_image_name: str,
|
| 88 |
+
edit_instruction: str,
|
| 89 |
+
output_image_name: str,
|
| 90 |
+
):
|
| 91 |
+
if len(input_image_name) == 0 or len(edit_instruction) == 0:
|
| 92 |
+
return False, rf"Missing Input"
|
| 93 |
+
|
| 94 |
+
if len(output_image_name) == 0:
|
| 95 |
+
return False, rf"Missing Output"
|
| 96 |
+
|
| 97 |
+
GoogleDrive_connection = GoogleDrive_API()
|
| 98 |
+
|
| 99 |
+
dataset_path = self.correct_path(rf"{self.PROJECT_PATH}\{self.DATASET_NAME}")
|
| 100 |
+
notebook_path = self.correct_path(rf"{self.PROJECT_PATH}\notebook")
|
| 101 |
+
|
| 102 |
+
self.create_folder(dataset_path)
|
| 103 |
+
|
| 104 |
+
# copy image to the dataset
|
| 105 |
+
shutil.copyfile(
|
| 106 |
+
rf"local_dataset\{input_image_name}",
|
| 107 |
+
rf"{dataset_path}\{input_image_name}",
|
| 108 |
+
)
|
| 109 |
+
|
| 110 |
+
data = [
|
| 111 |
+
{
|
| 112 |
+
"edit": edit_instruction,
|
| 113 |
+
"input_image_path": input_image_name,
|
| 114 |
+
"output_image_path": output_image_name,
|
| 115 |
+
}
|
| 116 |
+
]
|
| 117 |
+
|
| 118 |
+
self.write_file(data, dataset_path, "data.jsonl")
|
| 119 |
+
# update dataset
|
| 120 |
+
GoogleDrive_connection.upload_file(
|
| 121 |
+
"data.jsonl", rf"{self.DATASET_NAME}\data.jsonl"
|
| 122 |
+
)
|
| 123 |
+
GoogleDrive_connection.upload_file(
|
| 124 |
+
input_image_name, rf"{self.DATASET_NAME}\{input_image_name}"
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# run notebook
|
| 128 |
+
print(self.run(notebook_path))
|
| 129 |
+
|
| 130 |
+
number_of_checks = 0
|
| 131 |
+
while True:
|
| 132 |
+
status = str(self.get_notebook_status()).replace("\n", "")
|
| 133 |
+
print(rf"- status no #{number_of_checks} : {status}")
|
| 134 |
+
number_of_checks += 1
|
| 135 |
+
if "complete" in status:
|
| 136 |
+
break
|
| 137 |
+
|
| 138 |
+
if "error" in status:
|
| 139 |
+
return False, "notebook status error"
|
| 140 |
+
if "cancelAcknowledged" in status:
|
| 141 |
+
return False, "notebook status cancelAcknowledged"
|
| 142 |
+
time.sleep(120)
|
| 143 |
+
|
| 144 |
+
# get output
|
| 145 |
+
GoogleDrive_connection.download_file(
|
| 146 |
+
output_image_name, rf"{dataset_path}\{output_image_name}"
|
| 147 |
+
)
|
| 148 |
+
output_image = self.read_image(rf"{dataset_path}\{output_image_name}")
|
| 149 |
+
# clear input and output
|
| 150 |
+
|
| 151 |
+
if output_image is None:
|
| 152 |
+
return False, "An error occured while running, no output image found"
|
| 153 |
+
|
| 154 |
+
return True, output_image
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def main():
|
| 158 |
+
pass
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
if __name__ == "__main__":
|
| 162 |
+
main()
|
app.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import random
|
| 3 |
+
from PIL import Image
|
| 4 |
+
import gradio as gr
|
| 5 |
+
|
| 6 |
+
from Kaggle_API import API_Connection
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def generate_button_clicked(input_image: Image = None, edit_instruction: str = ""):
|
| 10 |
+
if input_image is None:
|
| 11 |
+
raise gr.Error("Missing Input: input_image")
|
| 12 |
+
if edit_instruction == 0:
|
| 13 |
+
raise gr.Error("Missing Input: edit_instruction")
|
| 14 |
+
|
| 15 |
+
# set kaggle-api variables
|
| 16 |
+
kaggle_username = os.environ["kaggle_username"]
|
| 17 |
+
kaggle_key = os.environ["kaggle_key"]
|
| 18 |
+
|
| 19 |
+
api_connection = API_Connection(kaggle_username, kaggle_key)
|
| 20 |
+
api_connection.create_folder(rf"{api_connection.PROJECT_PATH}\local_dataset")
|
| 21 |
+
|
| 22 |
+
image_ID = ""
|
| 23 |
+
while len(image_ID) < 4:
|
| 24 |
+
image_ID += str(random.randint(0, 9))
|
| 25 |
+
|
| 26 |
+
input_image_name = rf"input_image_{image_ID}.png"
|
| 27 |
+
output_image_name = rf"output_image_{image_ID}.png"
|
| 28 |
+
|
| 29 |
+
input_image.save(rf"local_dataset\{input_image_name}")
|
| 30 |
+
|
| 31 |
+
status, img = api_connection.generate_image(
|
| 32 |
+
input_image_name, edit_instruction, output_image_name
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
if status == False:
|
| 36 |
+
raise gr.Error(img) # img represents the error
|
| 37 |
+
|
| 38 |
+
return img
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def reset_button_clicked():
|
| 42 |
+
return None, "", None
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
SCOPES = ["https://www.googleapis.com/auth/drive"]
|
| 46 |
+
SERVICE_ACCOUNT_FILE = "service_account.json"
|
| 47 |
+
PARENT_FOLDER_ID = "1r-MlnEpWHx3b1fxHDnHcZ2-Wh_Y89676"
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def main():
|
| 51 |
+
with gr.Blocks(css="footer {visibility: hidden}") as demo:
|
| 52 |
+
with gr.Row():
|
| 53 |
+
input_image = gr.Image(label="Input Image", type="pil", interactive=True)
|
| 54 |
+
edited_image = gr.Image(
|
| 55 |
+
label=f"Edited Image", type="pil", interactive=False
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
with gr.Row():
|
| 59 |
+
with gr.Column(scale=3):
|
| 60 |
+
instruction = gr.Textbox(
|
| 61 |
+
lines=1, label="Edit Instruction", interactive=True
|
| 62 |
+
)
|
| 63 |
+
with gr.Column(scale=1, min_width=100):
|
| 64 |
+
with gr.Row():
|
| 65 |
+
generate_button = gr.Button("Generate")
|
| 66 |
+
with gr.Row():
|
| 67 |
+
reset_button = gr.Button("Reset")
|
| 68 |
+
|
| 69 |
+
generate_button.click(
|
| 70 |
+
fn=generate_button_clicked,
|
| 71 |
+
inputs=[
|
| 72 |
+
input_image,
|
| 73 |
+
instruction,
|
| 74 |
+
],
|
| 75 |
+
outputs=edited_image,
|
| 76 |
+
)
|
| 77 |
+
reset_button.click(
|
| 78 |
+
fn=reset_button_clicked,
|
| 79 |
+
outputs=[input_image, instruction, edited_image],
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
# Launch Gradio interface
|
| 83 |
+
|
| 84 |
+
demo.queue(max_size=1)
|
| 85 |
+
demo.launch(share=True)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
if __name__ == "__main__":
|
| 89 |
+
main()
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
kaggle
|
| 3 |
+
google-api-python-client
|