-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Batch File upload/ Folder upload. Bulk Enhance #3540
Open
ChrisColeTech
wants to merge
26
commits into
lllyasviel:main
Choose a base branch
from
ChrisColeTech:dev
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
f1e9a5c
Batch File upload/ Folder upload. Bulk Enhance
ChrisColeTech ee4f442
remove unused imports
ChrisColeTech 9f535e8
Change to resolve GitHub Advanced Security check
ChrisColeTech 7a0b8ee
Rework Stop/Skip while bulk enhancing
ChrisColeTech 2ab91c9
Update bulk_enhance_helpers.py
ChrisColeTech ec177f2
Update bulk_enhance_helpers.py
ChrisColeTech ad18a93
Update async_worker.py
ChrisColeTech e268cd5
Merge branch 'lllyasviel:main' into dev
ChrisColeTech 83d0935
more code cleanup
ChrisColeTech 3db125a
To resolve github CodeQL warning
ChrisColeTech 4b90d70
Update async_worker.py
ChrisColeTech 67edbf2
Update bulk_enhance_helpers.py
ChrisColeTech e68d7b5
automatic tkinter installation
ChrisColeTech 1afc7b3
Update tkinter_installer.py
ChrisColeTech 672baf0
Update launch.py
ChrisColeTech 8921ac8
Remove code comments, added backend logic for perf monitor. renamed t…
ChrisColeTech 7722d2c
html front end component for resource monitor
ChrisColeTech 4848427
wired up perf monitor
ChrisColeTech 85429b0
Update launch.py
ChrisColeTech 4c32ebe
final touches on the perf monitor
ChrisColeTech 5774787
perf monitor 2.0 with dragging
ChrisColeTech f0fa022
fix invisible element
ChrisColeTech c5a290a
remove unused code
ChrisColeTech c8d4d2d
Merge branch 'dev' of https://github.com/ChrisColeTech/Fooocus into dev
ChrisColeTech ce74b6b
speed up animation
ChrisColeTech eb934c9
Using websockets for resource monitor instead of rest api
ChrisColeTech File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,3 +53,4 @@ user_path_config-deprecated.txt | |
/.coverage* | ||
/auth.json | ||
.DS_Store | ||
/.venv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import os | ||
import importlib | ||
from flask import Blueprint | ||
from flask_restx import Namespace | ||
|
||
|
||
def register_blueprints(app, api): | ||
"""Register all Blueprints to the Flask app automatically.""" | ||
controllers_dir = os.path.dirname(__file__) | ||
for filename in os.listdir(controllers_dir): | ||
if filename.endswith('_controller.py') and filename != '__init__.py': | ||
module_name = filename[:-3] # Remove ".py" | ||
module = importlib.import_module( | ||
f'.{module_name}', package=__package__) | ||
for attribute_name in dir(module): | ||
attribute = getattr(module, attribute_name) | ||
if isinstance(attribute, Namespace): | ||
api.add_namespace(attribute) | ||
|
||
if isinstance(attribute, Blueprint): | ||
app.register_blueprint( | ||
attribute) | ||
print(f"Registered blueprint: {attribute_name}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
from flask_restx import Api, Resource, fields, Namespace | ||
from flask import jsonify, request, make_response, Blueprint | ||
import psutil | ||
import GPUtil | ||
import time | ||
|
||
# Create a Blueprint for the gpu_usage controller | ||
gpu_usage_bp = Blueprint('gpu_usage', __name__) | ||
gpu_usage_api = Api(gpu_usage_bp, version='1.0', title='gpu_usage API', | ||
description='API for managing gpu_usage') | ||
|
||
# Define a namespace for gpu_usage | ||
gpu_usage_ns = Namespace('gpu_usage', description='gpu usage operations') | ||
|
||
# Define the model for a gpu | ||
gpu_model = gpu_usage_ns.model('gpu_usage', { | ||
'id': fields.Integer(required=True, description='The unique identifier of the gpu'), | ||
'description': fields.String(required=True, description='Description of the gpu'), | ||
'status': fields.String(description='Status of the gpu') | ||
}) | ||
|
||
# Cache for system usage data | ||
cache = { | ||
'timestamp': 0, | ||
'data': { | ||
'cpu': 0, | ||
'ram': 0, | ||
'gpu': 0, | ||
'vram': 0, | ||
'hdd': 0, | ||
'temp': 0 | ||
} | ||
} | ||
CACHE_DURATION = 1 # Cache duration in seconds | ||
|
||
|
||
@gpu_usage_ns.route('/') | ||
class GPUInfo(Resource): | ||
def get_cache(self, current_time): | ||
# Get CPU utilization | ||
cpu_percent = psutil.cpu_percent(interval=0) | ||
|
||
# Get Memory utilization | ||
mem = psutil.virtual_memory() | ||
mem_percent = mem.percent | ||
|
||
# Get GPU utilization (considering only the first GPU) | ||
gpus = GPUtil.getGPUs() | ||
gpu_percent = gpus[0].load * 100 if gpus else 0 | ||
|
||
# Get VRAM usage (considering only the first GPU) | ||
vram_usage = 0 | ||
if gpus: | ||
used = gpus[0].memoryUsed | ||
total = gpus[0].memoryTotal | ||
vram_usage = (used / total) * 100 | ||
|
||
# Get HDD usage (assuming usage of the primary disk) | ||
hdd = psutil.disk_usage('/') | ||
hdd_percent = hdd.percent | ||
|
||
# Get temperature (if available) | ||
temperature = gpus[0].temperature | ||
|
||
# Update the cache | ||
cache['data'] = { | ||
'cpu': cpu_percent, | ||
'ram': mem_percent, | ||
'gpu': gpu_percent, | ||
'vram': vram_usage, # Convert bytes to MB | ||
'hdd': hdd_percent, | ||
'temp': temperature # Add temperature | ||
} | ||
cache['timestamp'] = current_time | ||
return cache | ||
|
||
def get(self): | ||
if request.method == "OPTIONS": # CORS preflight | ||
return _build_cors_preflight_response() | ||
|
||
current_time = time.time() | ||
|
||
# Check if the cache is still valid | ||
if current_time - cache['timestamp'] < CACHE_DURATION: | ||
return _corsify_actual_response(jsonify(cache['data'])) | ||
|
||
try: | ||
self.get_cache(current_time) | ||
|
||
return _corsify_actual_response(jsonify(cache['data'])) | ||
except Exception as e: | ||
return _corsify_actual_response(jsonify({'error': str(e)})) | ||
|
||
|
||
def _build_cors_preflight_response(): | ||
response = make_response() | ||
response.headers.add("Access-Control-Allow-Origin", "*") | ||
response.headers.add("Access-Control-Allow-Headers", "*") | ||
response.headers.add("Access-Control-Allow-Methods", "*") | ||
return response | ||
|
||
|
||
def _corsify_actual_response(response): | ||
response.headers.add("Access-Control-Allow-Origin", "*") | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import pickle | ||
import os | ||
from flask import Blueprint, request, jsonify, make_response | ||
from flask_restx import Api, Resource, fields, Namespace | ||
|
||
# Create a Blueprint for the jobs controller | ||
jobs_bp = Blueprint('jobs', __name__) | ||
jobs_api = Api(jobs_bp, version='1.0', title='Jobs API', | ||
description='API for managing jobs') | ||
|
||
# Define a namespace for jobs | ||
jobs_ns = Namespace('jobs', description='Job operations') | ||
|
||
# Define the model for a job | ||
job_model = jobs_ns.model('Job', { | ||
'id': fields.Integer(required=True, description='The unique identifier of the job'), | ||
'description': fields.String(required=True, description='Description of the job'), | ||
'status': fields.String(description='Status of the job') | ||
}) | ||
|
||
|
||
# File to persist data | ||
DATA_FILE = 'jobs.pkl' | ||
|
||
|
||
def load_jobs(): | ||
if os.path.exists(DATA_FILE): | ||
with open(DATA_FILE, 'rb') as file: | ||
return pickle.load(file) | ||
else: | ||
# Create an empty file if it doesn't exist | ||
with open(DATA_FILE, 'wb') as file: | ||
pickle.dump({}, file) | ||
return {} | ||
|
||
|
||
def save_jobs(jobs): | ||
with open(DATA_FILE, 'wb') as file: | ||
pickle.dump(jobs, file) | ||
|
||
|
||
# Load initial data | ||
jobs_store = load_jobs() | ||
|
||
|
||
@jobs_ns.route('/') | ||
class JobList(Resource): | ||
def get(self): | ||
"""List all jobs""" | ||
jobs_store = load_jobs() | ||
return _corsify_actual_response(jsonify(list(jobs_store.values()))) | ||
|
||
@jobs_ns.expect(job_model) | ||
def post(self): | ||
"""Create a new job""" | ||
if request.method == "OPTIONS": # CORS preflight | ||
return _build_cors_preflight_response() | ||
|
||
job = request.json | ||
job_id = job['id'] | ||
if job_id in jobs_store: | ||
return {'message': 'Job already exists'}, 400 | ||
jobs_store[job_id] = job | ||
save_jobs(jobs_store) # Save to file | ||
return _corsify_actual_response(jsonify(job)) | ||
|
||
|
||
@jobs_ns.route('/<int:job_id>') | ||
class JobItem(Resource): | ||
def get(self, job_id): | ||
"""Get a job by ID""" | ||
job = jobs_store.get(job_id) | ||
if job is None: | ||
return {'message': 'Job not found'}, 404 | ||
return _corsify_actual_response(jsonify(job)) | ||
|
||
@jobs_ns.expect(job_model) | ||
def put(self, job_id): | ||
"""Update a job by ID""" | ||
if request.method == "OPTIONS": # CORS preflight | ||
return _build_cors_preflight_response() | ||
job = request.json | ||
if job_id not in jobs_store: | ||
return {'message': 'Job not found'}, 404 | ||
jobs_store[job_id] = job | ||
save_jobs(jobs_store) # Save to file | ||
return _corsify_actual_response(jsonify(job)) | ||
|
||
def delete(self, job_id): | ||
"""Delete a job by ID""" | ||
if request.method == "OPTIONS": # CORS preflight | ||
return _build_cors_preflight_response() | ||
if job_id not in jobs_store: | ||
return {'message': 'Job not found'}, 404 | ||
del jobs_store[job_id] | ||
save_jobs(jobs_store) # Save to file | ||
return _corsify_actual_response(jsonify({'message': 'Job deleted'})) | ||
|
||
|
||
def _build_cors_preflight_response(): | ||
response = make_response() | ||
response.headers.add("Access-Control-Allow-Origin", "*") | ||
response.headers.add("Access-Control-Allow-Headers", "*") | ||
response.headers.add("Access-Control-Allow-Methods", "*") | ||
return response | ||
|
||
|
||
def _corsify_actual_response(response): | ||
response.headers.add("Access-Control-Allow-Origin", "*") | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import json | ||
import os | ||
from flask import Blueprint, jsonify, request | ||
from flask_restx import Api, Resource, fields, Namespace | ||
|
||
# Create a Blueprint for the settings controller | ||
settings_bp = Blueprint('settings', __name__) | ||
settings_api = Api(settings_bp, version='1.0', title='Settings API', | ||
description='API for managing settings') | ||
|
||
# Define a namespace for settings | ||
settings_ns = Namespace('settings', description='Settings operations') | ||
|
||
# Define the model for settings | ||
settings_model = settings_ns.model('Setting', { | ||
'key': fields.String(required=True, description='The key of the setting'), | ||
'value': fields.String(required=True, description='The value of the setting') | ||
}) | ||
|
||
# File to persist settings data | ||
SETTINGS_FILE = 'settings.json' | ||
|
||
|
||
def load_settings(): | ||
if os.path.exists(SETTINGS_FILE): | ||
with open(SETTINGS_FILE, 'r') as file: | ||
return json.load(file) | ||
return {} | ||
|
||
|
||
def save_settings(settings): | ||
with open(SETTINGS_FILE, 'w') as file: | ||
json.dump(settings, file, indent=4) | ||
|
||
|
||
# Load initial data | ||
settings_store = load_settings() | ||
|
||
|
||
@settings_ns.route('/') | ||
class SettingsList(Resource): | ||
def get(self): | ||
"""List all settings""" | ||
return jsonify({'settings': list(settings_store.values())}) | ||
|
||
@settings_ns.expect(settings_model) | ||
def post(self): | ||
"""Create or update a setting""" | ||
setting = request.json | ||
key = setting['key'] | ||
settings_store[key] = setting | ||
save_settings(settings_store) # Save to file | ||
return jsonify(setting) | ||
|
||
|
||
@settings_ns.route('/<string:key>') | ||
class SettingItem(Resource): | ||
def get(self, key): | ||
"""Get a setting by key""" | ||
setting = settings_store.get(key) | ||
if setting is None: | ||
return {'message': 'Setting not found'}, 404 | ||
return jsonify(setting) | ||
|
||
def delete(self, key): | ||
"""Delete a setting by key""" | ||
if key not in settings_store: | ||
return {'message': 'Setting not found'}, 404 | ||
del settings_store[key] | ||
save_settings(settings_store) # Save to file | ||
return {'message': 'Setting deleted'} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check warning
Code scanning / CodeQL
Information exposure through an exception