Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- .gitattributes +3 -0
- __pycache__/app.cpython-310.pyc +0 -0
- __pycache__/secure_app.cpython-310.pyc +0 -0
- app.py +45 -0
- app_security.log +3 -0
- cache/.gitattributes +38 -0
- cache/.github/workflows/update_space.yml +28 -0
- cache/.gitignore +54 -0
- cache/.hfignore +1 -0
- cache/.pytest_cache/.gitignore +2 -0
- cache/.pytest_cache/CACHEDIR.TAG +4 -0
- cache/.pytest_cache/README.md +8 -0
- cache/.pytest_cache/v/cache/lastfailed +1 -0
- cache/.pytest_cache/v/cache/nodeids +5 -0
- cache/.pytest_cache/v/cache/stepwise +1 -0
- cache/.serena/.gitignore +1 -0
- cache/.serena/project.yml +67 -0
- cache/.spec-workflow/config.example.toml +72 -0
- cache/.spec-workflow/templates/design-template.md +96 -0
- cache/.spec-workflow/templates/product-template.md +51 -0
- cache/.spec-workflow/templates/requirements-template.md +50 -0
- cache/.spec-workflow/templates/structure-template.md +145 -0
- cache/.spec-workflow/templates/tasks-template.md +139 -0
- cache/.spec-workflow/templates/tech-template.md +99 -0
- cache/.spec-workflow/user-templates/README.md +64 -0
- cache/Assets/Cyberpunk.jpg +3 -0
- cache/Assets/Picasso.jpg +3 -0
- cache/Assets/Pixar.jpg +0 -0
- cache/Assets/VanGogh.jpg +3 -0
- cache/FEATURE_UPDATE_SUMMARY.md +88 -0
- cache/README.md +333 -0
- cache/__pycache__/app.cpython-310.pyc +0 -0
- cache/app.py +0 -0
- cache/app3.py +936 -0
- cache/fix_pydantic_issue.py +128 -0
- cache/requirements.txt +5 -0
- cache/security_analysis.md +215 -0
- cache/test_app.py +53 -0
- cache/test_fix.py +21 -0
- cache/test_history.py +27 -0
- run_loader_test.py +39 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
cache/Assets/Cyberpunk.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
cache/Assets/Picasso.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
cache/Assets/VanGogh.jpg filter=lfs diff=lfs merge=lfs -text
|
__pycache__/app.cpython-310.pyc
ADDED
|
Binary file (2.28 kB). View file
|
|
|
__pycache__/secure_app.cpython-310.pyc
ADDED
|
Binary file (13.2 kB). View file
|
|
|
app.py
CHANGED
|
@@ -47,9 +47,54 @@ def load_app(cache_dir):
|
|
| 47 |
attr = getattr(app, name)
|
| 48 |
except Exception:
|
| 49 |
continue
|
|
|
|
|
|
|
|
|
|
| 50 |
if hasattr(attr, "launch") and callable(getattr(attr, "launch")):
|
| 51 |
return attr
|
| 52 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
# If nothing found, raise a helpful error describing the problem
|
| 54 |
available = [n for n in dir(app) if not n.startswith("__")]
|
| 55 |
raise AttributeError(
|
|
|
|
| 47 |
attr = getattr(app, name)
|
| 48 |
except Exception:
|
| 49 |
continue
|
| 50 |
+
# Skip classes (types) since their 'launch' will be an unbound function
|
| 51 |
+
if isinstance(attr, type):
|
| 52 |
+
continue
|
| 53 |
if hasattr(attr, "launch") and callable(getattr(attr, "launch")):
|
| 54 |
return attr
|
| 55 |
|
| 56 |
+
# Next, accept top-level callables that return an object with a 'launch' method.
|
| 57 |
+
# This covers Spaces that expose a factory function instead of a 'demo' object.
|
| 58 |
+
factory_names = [
|
| 59 |
+
"create_secure_interface",
|
| 60 |
+
"create_app",
|
| 61 |
+
"create_demo",
|
| 62 |
+
"main",
|
| 63 |
+
"generator",
|
| 64 |
+
]
|
| 65 |
+
|
| 66 |
+
for name in factory_names:
|
| 67 |
+
if hasattr(app, name):
|
| 68 |
+
try:
|
| 69 |
+
candidate = getattr(app, name)
|
| 70 |
+
if callable(candidate):
|
| 71 |
+
created = candidate()
|
| 72 |
+
if hasattr(created, "launch") and callable(getattr(created, "launch")):
|
| 73 |
+
return created
|
| 74 |
+
# If the factory itself is a Gradio Interface (callable with launch), return it
|
| 75 |
+
if hasattr(candidate, "launch") and callable(getattr(candidate, "launch")):
|
| 76 |
+
return candidate
|
| 77 |
+
except Exception:
|
| 78 |
+
# ignore failures from calling the factory and continue searching
|
| 79 |
+
pass
|
| 80 |
+
|
| 81 |
+
# Also accept any top-level callable that when called returns an object with 'launch'
|
| 82 |
+
for name in dir(app):
|
| 83 |
+
if name.startswith("__"):
|
| 84 |
+
continue
|
| 85 |
+
try:
|
| 86 |
+
attr = getattr(app, name)
|
| 87 |
+
except Exception:
|
| 88 |
+
continue
|
| 89 |
+
if callable(attr):
|
| 90 |
+
try:
|
| 91 |
+
created = attr()
|
| 92 |
+
if hasattr(created, "launch") and callable(getattr(created, "launch")):
|
| 93 |
+
return created
|
| 94 |
+
except Exception:
|
| 95 |
+
# if calling fails, skip
|
| 96 |
+
continue
|
| 97 |
+
|
| 98 |
# If nothing found, raise a helpful error describing the problem
|
| 99 |
available = [n for n in dir(app) if not n.startswith("__")]
|
| 100 |
raise AttributeError(
|
app_security.log
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
2025-09-18 15:51:11,790 - httpx - INFO - HTTP Request: GET http://127.0.0.1:7860/gradio_api/startup-events "HTTP/1.1 200 OK"
|
| 2 |
+
2025-09-18 15:51:11,861 - httpx - INFO - HTTP Request: HEAD http://127.0.0.1:7860/ "HTTP/1.1 200 OK"
|
| 3 |
+
2025-09-18 15:51:12,370 - httpx - INFO - HTTP Request: GET https://api.gradio.app/pkg-version "HTTP/1.1 200 OK"
|
cache/.gitattributes
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
Assets/Cyberpunk.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
Assets/Picasso.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
Assets/VanGogh.jpg filter=lfs diff=lfs merge=lfs -text
|
cache/.github/workflows/update_space.yml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Run Python script
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
|
| 8 |
+
jobs:
|
| 9 |
+
build:
|
| 10 |
+
runs-on: ubuntu-latest
|
| 11 |
+
|
| 12 |
+
steps:
|
| 13 |
+
- name: Checkout
|
| 14 |
+
uses: actions/checkout@v2
|
| 15 |
+
|
| 16 |
+
- name: Set up Python
|
| 17 |
+
uses: actions/setup-python@v2
|
| 18 |
+
with:
|
| 19 |
+
python-version: '3.9'
|
| 20 |
+
|
| 21 |
+
- name: Install Gradio
|
| 22 |
+
run: python -m pip install gradio
|
| 23 |
+
|
| 24 |
+
- name: Log in to Hugging Face
|
| 25 |
+
run: python -c 'import huggingface_hub; huggingface_hub.login(token="${{ secrets.hf_token }}")'
|
| 26 |
+
|
| 27 |
+
- name: Deploy to Spaces
|
| 28 |
+
run: gradio deploy
|
cache/.gitignore
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
app_security.log
|
| 2 |
+
# Bytecode
|
| 3 |
+
__pycache__/
|
| 4 |
+
*.py[cod]
|
| 5 |
+
*$py.class
|
| 6 |
+
|
| 7 |
+
# Logs
|
| 8 |
+
*.log
|
| 9 |
+
app_security.log
|
| 10 |
+
|
| 11 |
+
# Virtual environments
|
| 12 |
+
venv/
|
| 13 |
+
.venv/
|
| 14 |
+
env/
|
| 15 |
+
ENV/
|
| 16 |
+
|
| 17 |
+
# IDE
|
| 18 |
+
.vscode/
|
| 19 |
+
.idea/
|
| 20 |
+
*.swp
|
| 21 |
+
*.swo
|
| 22 |
+
|
| 23 |
+
# OS
|
| 24 |
+
.DS_Store
|
| 25 |
+
Thumbs.db
|
| 26 |
+
|
| 27 |
+
# Gradio
|
| 28 |
+
.gradio/
|
| 29 |
+
|
| 30 |
+
# Temporary files
|
| 31 |
+
*.tmp
|
| 32 |
+
*.temp
|
| 33 |
+
temp/
|
| 34 |
+
tmp/
|
| 35 |
+
|
| 36 |
+
# API keys and secrets (never commit these!)
|
| 37 |
+
*.key
|
| 38 |
+
*.pem
|
| 39 |
+
secrets.json
|
| 40 |
+
config.json
|
| 41 |
+
.env
|
| 42 |
+
.env.example
|
| 43 |
+
|
| 44 |
+
# Generated content
|
| 45 |
+
Generated/
|
| 46 |
+
Assets/png
|
| 47 |
+
|
| 48 |
+
# ZIP files
|
| 49 |
+
*.zip
|
| 50 |
+
|
| 51 |
+
# Claude AI files
|
| 52 |
+
# Backup folders
|
| 53 |
+
backup/
|
| 54 |
+
.claude/
|
cache/.hfignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
app_security.log
|
cache/.pytest_cache/.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Created by pytest automatically.
|
| 2 |
+
*
|
cache/.pytest_cache/CACHEDIR.TAG
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Signature: 8a477f597d28d172789f06886806bc55
|
| 2 |
+
# This file is a cache directory tag created by pytest.
|
| 3 |
+
# For information about cache directory tags, see:
|
| 4 |
+
# http://www.bford.info/cachedir/spec.html
|
cache/.pytest_cache/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# pytest cache directory #
|
| 2 |
+
|
| 3 |
+
This directory contains data from the pytest's cache plugin,
|
| 4 |
+
which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
|
| 5 |
+
|
| 6 |
+
**Do not** commit this to version control.
|
| 7 |
+
|
| 8 |
+
See [the docs](https://docs.pytest.org/en/stable/cache.html) for more information.
|
cache/.pytest_cache/v/cache/lastfailed
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{}
|
cache/.pytest_cache/v/cache/nodeids
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
"test_app.py::test_gradio_app",
|
| 3 |
+
"test_history.py::test_get_generation_history_and_table",
|
| 4 |
+
"test_history.py::test_import_generation_functions"
|
| 5 |
+
]
|
cache/.pytest_cache/v/cache/stepwise
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
[]
|
cache/.serena/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
/cache
|
cache/.serena/project.yml
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
|
| 2 |
+
# * For C, use cpp
|
| 3 |
+
# * For JavaScript, use typescript
|
| 4 |
+
# Special requirements:
|
| 5 |
+
# * csharp: Requires the presence of a .sln file in the project folder.
|
| 6 |
+
language: python
|
| 7 |
+
|
| 8 |
+
# whether to use the project's gitignore file to ignore files
|
| 9 |
+
# Added on 2025-04-07
|
| 10 |
+
ignore_all_files_in_gitignore: true
|
| 11 |
+
# list of additional paths to ignore
|
| 12 |
+
# same syntax as gitignore, so you can use * and **
|
| 13 |
+
# Was previously called `ignored_dirs`, please update your config if you are using that.
|
| 14 |
+
# Added (renamed) on 2025-04-07
|
| 15 |
+
ignored_paths: []
|
| 16 |
+
|
| 17 |
+
# whether the project is in read-only mode
|
| 18 |
+
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
|
| 19 |
+
# Added on 2025-04-18
|
| 20 |
+
read_only: false
|
| 21 |
+
|
| 22 |
+
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
|
| 23 |
+
# Below is the complete list of tools for convenience.
|
| 24 |
+
# To make sure you have the latest list of tools, and to view their descriptions,
|
| 25 |
+
# execute `uv run scripts/print_tool_overview.py`.
|
| 26 |
+
#
|
| 27 |
+
# * `activate_project`: Activates a project by name.
|
| 28 |
+
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
|
| 29 |
+
# * `create_text_file`: Creates/overwrites a file in the project directory.
|
| 30 |
+
# * `delete_lines`: Deletes a range of lines within a file.
|
| 31 |
+
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
|
| 32 |
+
# * `execute_shell_command`: Executes a shell command.
|
| 33 |
+
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
|
| 34 |
+
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
|
| 35 |
+
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
|
| 36 |
+
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
|
| 37 |
+
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
|
| 38 |
+
# * `initial_instructions`: Gets the initial instructions for the current project.
|
| 39 |
+
# Should only be used in settings where the system prompt cannot be set,
|
| 40 |
+
# e.g. in clients you have no control over, like Claude Desktop.
|
| 41 |
+
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
|
| 42 |
+
# * `insert_at_line`: Inserts content at a given line in a file.
|
| 43 |
+
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
|
| 44 |
+
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
|
| 45 |
+
# * `list_memories`: Lists memories in Serena's project-specific memory store.
|
| 46 |
+
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
|
| 47 |
+
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
|
| 48 |
+
# * `read_file`: Reads a file within the project directory.
|
| 49 |
+
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
|
| 50 |
+
# * `remove_project`: Removes a project from the Serena configuration.
|
| 51 |
+
# * `replace_lines`: Replaces a range of lines within a file with new content.
|
| 52 |
+
# * `replace_symbol_body`: Replaces the full definition of a symbol.
|
| 53 |
+
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
|
| 54 |
+
# * `search_for_pattern`: Performs a search for a pattern in the project.
|
| 55 |
+
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
|
| 56 |
+
# * `switch_modes`: Activates modes by providing a list of their names
|
| 57 |
+
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
|
| 58 |
+
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
|
| 59 |
+
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
|
| 60 |
+
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
|
| 61 |
+
excluded_tools: []
|
| 62 |
+
|
| 63 |
+
# initial prompt for the project. It will always be given to the LLM upon activating the project
|
| 64 |
+
# (contrary to the memories, which are loaded on demand).
|
| 65 |
+
initial_prompt: ""
|
| 66 |
+
|
| 67 |
+
project_name: "bytedance"
|
cache/.spec-workflow/config.example.toml
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Spec Workflow MCP Server Configuration File
|
| 2 |
+
# ============================================
|
| 3 |
+
#
|
| 4 |
+
# This is an example configuration file for the Spec Workflow MCP Server.
|
| 5 |
+
# Copy this file to 'config.toml' in the same directory to use it.
|
| 6 |
+
#
|
| 7 |
+
# Configuration Precedence:
|
| 8 |
+
# 1. Command-line arguments (highest priority)
|
| 9 |
+
# 2. Config file settings
|
| 10 |
+
# 3. Built-in defaults (lowest priority)
|
| 11 |
+
#
|
| 12 |
+
# All settings are optional. Uncomment and modify as needed.
|
| 13 |
+
# Please note that not all MCP clients will support loading this config file due to the nature of where they are running from.
|
| 14 |
+
|
| 15 |
+
# Project directory path
|
| 16 |
+
# The root directory of your project where spec files are located.
|
| 17 |
+
# Note: You may have to use double slashes (\\) instead of single slashes (/) on Windows or for certain clients.
|
| 18 |
+
# Supports tilde (~) expansion for home directory.
|
| 19 |
+
# Default: current working directory
|
| 20 |
+
# projectDir = "."
|
| 21 |
+
# projectDir = "~/my-project"
|
| 22 |
+
# projectDir = "/absolute/path/to/project"
|
| 23 |
+
|
| 24 |
+
# Dashboard port
|
| 25 |
+
# The port number for the web dashboard.
|
| 26 |
+
# Must be between 1024 and 65535.
|
| 27 |
+
# Default: ephemeral port (automatically assigned)
|
| 28 |
+
# port = 3000
|
| 29 |
+
|
| 30 |
+
# Auto-start dashboard
|
| 31 |
+
# Automatically launch the dashboard when the MCP server starts.
|
| 32 |
+
# The dashboard will open in your default browser.
|
| 33 |
+
# Default: false
|
| 34 |
+
# autoStartDashboard = false
|
| 35 |
+
|
| 36 |
+
# Dashboard-only mode
|
| 37 |
+
# Run only the web dashboard without the MCP server.
|
| 38 |
+
# Useful for standalone dashboard usage.
|
| 39 |
+
# Default: false
|
| 40 |
+
# dashboardOnly = false
|
| 41 |
+
|
| 42 |
+
# Language
|
| 43 |
+
# Set the interface language for internationalization (i18n).
|
| 44 |
+
# Available languages depend on your installation.
|
| 45 |
+
# Common values: "en" (English), "ja" (Japanese), etc.
|
| 46 |
+
# Default: system language or "en"
|
| 47 |
+
# lang = "en"
|
| 48 |
+
|
| 49 |
+
# Example configurations:
|
| 50 |
+
# =====================
|
| 51 |
+
|
| 52 |
+
# Example 1: Development setup with auto-started dashboard
|
| 53 |
+
# ----------------------------------------------------------
|
| 54 |
+
# projectDir = "~/dev/my-project"
|
| 55 |
+
# autoStartDashboard = true
|
| 56 |
+
# port = 3456
|
| 57 |
+
|
| 58 |
+
# Example 2: Production MCP server without dashboard
|
| 59 |
+
# ---------------------------------------------------
|
| 60 |
+
# projectDir = "/var/projects/production"
|
| 61 |
+
# autoStartDashboard = false
|
| 62 |
+
|
| 63 |
+
# Example 3: Dashboard-only mode for viewing specs
|
| 64 |
+
# -------------------------------------------------
|
| 65 |
+
# projectDir = "."
|
| 66 |
+
# dashboardOnly = true
|
| 67 |
+
# port = 8080
|
| 68 |
+
|
| 69 |
+
# Example 4: Japanese language interface
|
| 70 |
+
# ---------------------------------------
|
| 71 |
+
# lang = "ja"
|
| 72 |
+
# autoStartDashboard = true
|
cache/.spec-workflow/templates/design-template.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Design Document
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
[High-level description of the feature and its place in the overall system]
|
| 6 |
+
|
| 7 |
+
## Steering Document Alignment
|
| 8 |
+
|
| 9 |
+
### Technical Standards (tech.md)
|
| 10 |
+
[How the design follows documented technical patterns and standards]
|
| 11 |
+
|
| 12 |
+
### Project Structure (structure.md)
|
| 13 |
+
[How the implementation will follow project organization conventions]
|
| 14 |
+
|
| 15 |
+
## Code Reuse Analysis
|
| 16 |
+
[What existing code will be leveraged, extended, or integrated with this feature]
|
| 17 |
+
|
| 18 |
+
### Existing Components to Leverage
|
| 19 |
+
- **[Component/Utility Name]**: [How it will be used]
|
| 20 |
+
- **[Service/Helper Name]**: [How it will be extended]
|
| 21 |
+
|
| 22 |
+
### Integration Points
|
| 23 |
+
- **[Existing System/API]**: [How the new feature will integrate]
|
| 24 |
+
- **[Database/Storage]**: [How data will connect to existing schemas]
|
| 25 |
+
|
| 26 |
+
## Architecture
|
| 27 |
+
|
| 28 |
+
[Describe the overall architecture and design patterns used]
|
| 29 |
+
|
| 30 |
+
### Modular Design Principles
|
| 31 |
+
- **Single File Responsibility**: Each file should handle one specific concern or domain
|
| 32 |
+
- **Component Isolation**: Create small, focused components rather than large monolithic files
|
| 33 |
+
- **Service Layer Separation**: Separate data access, business logic, and presentation layers
|
| 34 |
+
- **Utility Modularity**: Break utilities into focused, single-purpose modules
|
| 35 |
+
|
| 36 |
+
```mermaid
|
| 37 |
+
graph TD
|
| 38 |
+
A[Component A] --> B[Component B]
|
| 39 |
+
B --> C[Component C]
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## Components and Interfaces
|
| 43 |
+
|
| 44 |
+
### Component 1
|
| 45 |
+
- **Purpose:** [What this component does]
|
| 46 |
+
- **Interfaces:** [Public methods/APIs]
|
| 47 |
+
- **Dependencies:** [What it depends on]
|
| 48 |
+
- **Reuses:** [Existing components/utilities it builds upon]
|
| 49 |
+
|
| 50 |
+
### Component 2
|
| 51 |
+
- **Purpose:** [What this component does]
|
| 52 |
+
- **Interfaces:** [Public methods/APIs]
|
| 53 |
+
- **Dependencies:** [What it depends on]
|
| 54 |
+
- **Reuses:** [Existing components/utilities it builds upon]
|
| 55 |
+
|
| 56 |
+
## Data Models
|
| 57 |
+
|
| 58 |
+
### Model 1
|
| 59 |
+
```
|
| 60 |
+
[Define the structure of Model1 in your language]
|
| 61 |
+
- id: [unique identifier type]
|
| 62 |
+
- name: [string/text type]
|
| 63 |
+
- [Additional properties as needed]
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
### Model 2
|
| 67 |
+
```
|
| 68 |
+
[Define the structure of Model2 in your language]
|
| 69 |
+
- id: [unique identifier type]
|
| 70 |
+
- [Additional properties as needed]
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
## Error Handling
|
| 74 |
+
|
| 75 |
+
### Error Scenarios
|
| 76 |
+
1. **Scenario 1:** [Description]
|
| 77 |
+
- **Handling:** [How to handle]
|
| 78 |
+
- **User Impact:** [What user sees]
|
| 79 |
+
|
| 80 |
+
2. **Scenario 2:** [Description]
|
| 81 |
+
- **Handling:** [How to handle]
|
| 82 |
+
- **User Impact:** [What user sees]
|
| 83 |
+
|
| 84 |
+
## Testing Strategy
|
| 85 |
+
|
| 86 |
+
### Unit Testing
|
| 87 |
+
- [Unit testing approach]
|
| 88 |
+
- [Key components to test]
|
| 89 |
+
|
| 90 |
+
### Integration Testing
|
| 91 |
+
- [Integration testing approach]
|
| 92 |
+
- [Key flows to test]
|
| 93 |
+
|
| 94 |
+
### End-to-End Testing
|
| 95 |
+
- [E2E testing approach]
|
| 96 |
+
- [User scenarios to test]
|
cache/.spec-workflow/templates/product-template.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Product Overview
|
| 2 |
+
|
| 3 |
+
## Product Purpose
|
| 4 |
+
[Describe the core purpose of this product/project. What problem does it solve?]
|
| 5 |
+
|
| 6 |
+
## Target Users
|
| 7 |
+
[Who are the primary users of this product? What are their needs and pain points?]
|
| 8 |
+
|
| 9 |
+
## Key Features
|
| 10 |
+
[List the main features that deliver value to users]
|
| 11 |
+
|
| 12 |
+
1. **Feature 1**: [Description]
|
| 13 |
+
2. **Feature 2**: [Description]
|
| 14 |
+
3. **Feature 3**: [Description]
|
| 15 |
+
|
| 16 |
+
## Business Objectives
|
| 17 |
+
[What are the business goals this product aims to achieve?]
|
| 18 |
+
|
| 19 |
+
- [Objective 1]
|
| 20 |
+
- [Objective 2]
|
| 21 |
+
- [Objective 3]
|
| 22 |
+
|
| 23 |
+
## Success Metrics
|
| 24 |
+
[How will we measure the success of this product?]
|
| 25 |
+
|
| 26 |
+
- [Metric 1]: [Target]
|
| 27 |
+
- [Metric 2]: [Target]
|
| 28 |
+
- [Metric 3]: [Target]
|
| 29 |
+
|
| 30 |
+
## Product Principles
|
| 31 |
+
[Core principles that guide product decisions]
|
| 32 |
+
|
| 33 |
+
1. **[Principle 1]**: [Explanation]
|
| 34 |
+
2. **[Principle 2]**: [Explanation]
|
| 35 |
+
3. **[Principle 3]**: [Explanation]
|
| 36 |
+
|
| 37 |
+
## Monitoring & Visibility (if applicable)
|
| 38 |
+
[How do users track progress and monitor the system?]
|
| 39 |
+
|
| 40 |
+
- **Dashboard Type**: [e.g., Web-based, CLI, Desktop app]
|
| 41 |
+
- **Real-time Updates**: [e.g., WebSocket, polling, push notifications]
|
| 42 |
+
- **Key Metrics Displayed**: [What information is most important to surface]
|
| 43 |
+
- **Sharing Capabilities**: [e.g., read-only links, exports, reports]
|
| 44 |
+
|
| 45 |
+
## Future Vision
|
| 46 |
+
[Where do we see this product evolving in the future?]
|
| 47 |
+
|
| 48 |
+
### Potential Enhancements
|
| 49 |
+
- **Remote Access**: [e.g., Tunnel features for sharing dashboards with stakeholders]
|
| 50 |
+
- **Analytics**: [e.g., Historical trends, performance metrics]
|
| 51 |
+
- **Collaboration**: [e.g., Multi-user support, commenting]
|
cache/.spec-workflow/templates/requirements-template.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Requirements Document
|
| 2 |
+
|
| 3 |
+
## Introduction
|
| 4 |
+
|
| 5 |
+
[Provide a brief overview of the feature, its purpose, and its value to users]
|
| 6 |
+
|
| 7 |
+
## Alignment with Product Vision
|
| 8 |
+
|
| 9 |
+
[Explain how this feature supports the goals outlined in product.md]
|
| 10 |
+
|
| 11 |
+
## Requirements
|
| 12 |
+
|
| 13 |
+
### Requirement 1
|
| 14 |
+
|
| 15 |
+
**User Story:** As a [role], I want [feature], so that [benefit]
|
| 16 |
+
|
| 17 |
+
#### Acceptance Criteria
|
| 18 |
+
|
| 19 |
+
1. WHEN [event] THEN [system] SHALL [response]
|
| 20 |
+
2. IF [precondition] THEN [system] SHALL [response]
|
| 21 |
+
3. WHEN [event] AND [condition] THEN [system] SHALL [response]
|
| 22 |
+
|
| 23 |
+
### Requirement 2
|
| 24 |
+
|
| 25 |
+
**User Story:** As a [role], I want [feature], so that [benefit]
|
| 26 |
+
|
| 27 |
+
#### Acceptance Criteria
|
| 28 |
+
|
| 29 |
+
1. WHEN [event] THEN [system] SHALL [response]
|
| 30 |
+
2. IF [precondition] THEN [system] SHALL [response]
|
| 31 |
+
|
| 32 |
+
## Non-Functional Requirements
|
| 33 |
+
|
| 34 |
+
### Code Architecture and Modularity
|
| 35 |
+
- **Single Responsibility Principle**: Each file should have a single, well-defined purpose
|
| 36 |
+
- **Modular Design**: Components, utilities, and services should be isolated and reusable
|
| 37 |
+
- **Dependency Management**: Minimize interdependencies between modules
|
| 38 |
+
- **Clear Interfaces**: Define clean contracts between components and layers
|
| 39 |
+
|
| 40 |
+
### Performance
|
| 41 |
+
- [Performance requirements]
|
| 42 |
+
|
| 43 |
+
### Security
|
| 44 |
+
- [Security requirements]
|
| 45 |
+
|
| 46 |
+
### Reliability
|
| 47 |
+
- [Reliability requirements]
|
| 48 |
+
|
| 49 |
+
### Usability
|
| 50 |
+
- [Usability requirements]
|
cache/.spec-workflow/templates/structure-template.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Project Structure
|
| 2 |
+
|
| 3 |
+
## Directory Organization
|
| 4 |
+
|
| 5 |
+
```
|
| 6 |
+
[Define your project's directory structure. Examples below - adapt to your project type]
|
| 7 |
+
|
| 8 |
+
Example for a library/package:
|
| 9 |
+
project-root/
|
| 10 |
+
├── src/ # Source code
|
| 11 |
+
├── tests/ # Test files
|
| 12 |
+
├── docs/ # Documentation
|
| 13 |
+
├── examples/ # Usage examples
|
| 14 |
+
└── [build/dist/out] # Build output
|
| 15 |
+
|
| 16 |
+
Example for an application:
|
| 17 |
+
project-root/
|
| 18 |
+
├── [src/app/lib] # Main source code
|
| 19 |
+
├── [assets/resources] # Static resources
|
| 20 |
+
├── [config/settings] # Configuration
|
| 21 |
+
├── [scripts/tools] # Build/utility scripts
|
| 22 |
+
└── [tests/spec] # Test files
|
| 23 |
+
|
| 24 |
+
Common patterns:
|
| 25 |
+
- Group by feature/module
|
| 26 |
+
- Group by layer (UI, business logic, data)
|
| 27 |
+
- Group by type (models, controllers, views)
|
| 28 |
+
- Flat structure for simple projects
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
## Naming Conventions
|
| 32 |
+
|
| 33 |
+
### Files
|
| 34 |
+
- **Components/Modules**: [e.g., `PascalCase`, `snake_case`, `kebab-case`]
|
| 35 |
+
- **Services/Handlers**: [e.g., `UserService`, `user_service`, `user-service`]
|
| 36 |
+
- **Utilities/Helpers**: [e.g., `dateUtils`, `date_utils`, `date-utils`]
|
| 37 |
+
- **Tests**: [e.g., `[filename]_test`, `[filename].test`, `[filename]Test`]
|
| 38 |
+
|
| 39 |
+
### Code
|
| 40 |
+
- **Classes/Types**: [e.g., `PascalCase`, `CamelCase`, `snake_case`]
|
| 41 |
+
- **Functions/Methods**: [e.g., `camelCase`, `snake_case`, `PascalCase`]
|
| 42 |
+
- **Constants**: [e.g., `UPPER_SNAKE_CASE`, `SCREAMING_CASE`, `PascalCase`]
|
| 43 |
+
- **Variables**: [e.g., `camelCase`, `snake_case`, `lowercase`]
|
| 44 |
+
|
| 45 |
+
## Import Patterns
|
| 46 |
+
|
| 47 |
+
### Import Order
|
| 48 |
+
1. External dependencies
|
| 49 |
+
2. Internal modules
|
| 50 |
+
3. Relative imports
|
| 51 |
+
4. Style imports
|
| 52 |
+
|
| 53 |
+
### Module/Package Organization
|
| 54 |
+
```
|
| 55 |
+
[Describe your project's import/include patterns]
|
| 56 |
+
Examples:
|
| 57 |
+
- Absolute imports from project root
|
| 58 |
+
- Relative imports within modules
|
| 59 |
+
- Package/namespace organization
|
| 60 |
+
- Dependency management approach
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
## Code Structure Patterns
|
| 64 |
+
|
| 65 |
+
[Define common patterns for organizing code within files. Below are examples - choose what applies to your project]
|
| 66 |
+
|
| 67 |
+
### Module/Class Organization
|
| 68 |
+
```
|
| 69 |
+
Example patterns:
|
| 70 |
+
1. Imports/includes/dependencies
|
| 71 |
+
2. Constants and configuration
|
| 72 |
+
3. Type/interface definitions
|
| 73 |
+
4. Main implementation
|
| 74 |
+
5. Helper/utility functions
|
| 75 |
+
6. Exports/public API
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
### Function/Method Organization
|
| 79 |
+
```
|
| 80 |
+
Example patterns:
|
| 81 |
+
- Input validation first
|
| 82 |
+
- Core logic in the middle
|
| 83 |
+
- Error handling throughout
|
| 84 |
+
- Clear return points
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
### File Organization Principles
|
| 88 |
+
```
|
| 89 |
+
Choose what works for your project:
|
| 90 |
+
- One class/module per file
|
| 91 |
+
- Related functionality grouped together
|
| 92 |
+
- Public API at the top/bottom
|
| 93 |
+
- Implementation details hidden
|
| 94 |
+
```
|
| 95 |
+
|
| 96 |
+
## Code Organization Principles
|
| 97 |
+
|
| 98 |
+
1. **Single Responsibility**: Each file should have one clear purpose
|
| 99 |
+
2. **Modularity**: Code should be organized into reusable modules
|
| 100 |
+
3. **Testability**: Structure code to be easily testable
|
| 101 |
+
4. **Consistency**: Follow patterns established in the codebase
|
| 102 |
+
|
| 103 |
+
## Module Boundaries
|
| 104 |
+
[Define how different parts of your project interact and maintain separation of concerns]
|
| 105 |
+
|
| 106 |
+
Examples of boundary patterns:
|
| 107 |
+
- **Core vs Plugins**: Core functionality vs extensible plugins
|
| 108 |
+
- **Public API vs Internal**: What's exposed vs implementation details
|
| 109 |
+
- **Platform-specific vs Cross-platform**: OS-specific code isolation
|
| 110 |
+
- **Stable vs Experimental**: Production code vs experimental features
|
| 111 |
+
- **Dependencies direction**: Which modules can depend on which
|
| 112 |
+
|
| 113 |
+
## Code Size Guidelines
|
| 114 |
+
[Define your project's guidelines for file and function sizes]
|
| 115 |
+
|
| 116 |
+
Suggested guidelines:
|
| 117 |
+
- **File size**: [Define maximum lines per file]
|
| 118 |
+
- **Function/Method size**: [Define maximum lines per function]
|
| 119 |
+
- **Class/Module complexity**: [Define complexity limits]
|
| 120 |
+
- **Nesting depth**: [Maximum nesting levels]
|
| 121 |
+
|
| 122 |
+
## Dashboard/Monitoring Structure (if applicable)
|
| 123 |
+
[How dashboard or monitoring components are organized]
|
| 124 |
+
|
| 125 |
+
### Example Structure:
|
| 126 |
+
```
|
| 127 |
+
src/
|
| 128 |
+
└── dashboard/ # Self-contained dashboard subsystem
|
| 129 |
+
├── server/ # Backend server components
|
| 130 |
+
├── client/ # Frontend assets
|
| 131 |
+
├── shared/ # Shared types/utilities
|
| 132 |
+
└── public/ # Static assets
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
### Separation of Concerns
|
| 136 |
+
- Dashboard isolated from core business logic
|
| 137 |
+
- Own CLI entry point for independent operation
|
| 138 |
+
- Minimal dependencies on main application
|
| 139 |
+
- Can be disabled without affecting core functionality
|
| 140 |
+
|
| 141 |
+
## Documentation Standards
|
| 142 |
+
- All public APIs must have documentation
|
| 143 |
+
- Complex logic should include inline comments
|
| 144 |
+
- README files for major modules
|
| 145 |
+
- Follow language-specific documentation conventions
|
cache/.spec-workflow/templates/tasks-template.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Tasks Document
|
| 2 |
+
|
| 3 |
+
- [ ] 1. Create core interfaces in src/types/feature.ts
|
| 4 |
+
- File: src/types/feature.ts
|
| 5 |
+
- Define TypeScript interfaces for feature data structures
|
| 6 |
+
- Extend existing base interfaces from base.ts
|
| 7 |
+
- Purpose: Establish type safety for feature implementation
|
| 8 |
+
- _Leverage: src/types/base.ts_
|
| 9 |
+
- _Requirements: 1.1_
|
| 10 |
+
- _Prompt: Role: TypeScript Developer specializing in type systems and interfaces | Task: Create comprehensive TypeScript interfaces for the feature data structures following requirements 1.1, extending existing base interfaces from src/types/base.ts | Restrictions: Do not modify existing base interfaces, maintain backward compatibility, follow project naming conventions | Success: All interfaces compile without errors, proper inheritance from base types, full type coverage for feature requirements_
|
| 11 |
+
|
| 12 |
+
- [ ] 2. Create base model class in src/models/FeatureModel.ts
|
| 13 |
+
- File: src/models/FeatureModel.ts
|
| 14 |
+
- Implement base model extending BaseModel class
|
| 15 |
+
- Add validation methods using existing validation utilities
|
| 16 |
+
- Purpose: Provide data layer foundation for feature
|
| 17 |
+
- _Leverage: src/models/BaseModel.ts, src/utils/validation.ts_
|
| 18 |
+
- _Requirements: 2.1_
|
| 19 |
+
- _Prompt: Role: Backend Developer with expertise in Node.js and data modeling | Task: Create a base model class extending BaseModel and implementing validation following requirement 2.1, leveraging existing patterns from src/models/BaseModel.ts and src/utils/validation.ts | Restrictions: Must follow existing model patterns, do not bypass validation utilities, maintain consistent error handling | Success: Model extends BaseModel correctly, validation methods implemented and tested, follows project architecture patterns_
|
| 20 |
+
|
| 21 |
+
- [ ] 3. Add specific model methods to FeatureModel.ts
|
| 22 |
+
- File: src/models/FeatureModel.ts (continue from task 2)
|
| 23 |
+
- Implement create, update, delete methods
|
| 24 |
+
- Add relationship handling for foreign keys
|
| 25 |
+
- Purpose: Complete model functionality for CRUD operations
|
| 26 |
+
- _Leverage: src/models/BaseModel.ts_
|
| 27 |
+
- _Requirements: 2.2, 2.3_
|
| 28 |
+
- _Prompt: Role: Backend Developer with expertise in ORM and database operations | Task: Implement CRUD methods and relationship handling in FeatureModel.ts following requirements 2.2 and 2.3, extending patterns from src/models/BaseModel.ts | Restrictions: Must maintain transaction integrity, follow existing relationship patterns, do not duplicate base model functionality | Success: All CRUD operations work correctly, relationships are properly handled, database operations are atomic and efficient_
|
| 29 |
+
|
| 30 |
+
- [ ] 4. Create model unit tests in tests/models/FeatureModel.test.ts
|
| 31 |
+
- File: tests/models/FeatureModel.test.ts
|
| 32 |
+
- Write tests for model validation and CRUD methods
|
| 33 |
+
- Use existing test utilities and fixtures
|
| 34 |
+
- Purpose: Ensure model reliability and catch regressions
|
| 35 |
+
- _Leverage: tests/helpers/testUtils.ts, tests/fixtures/data.ts_
|
| 36 |
+
- _Requirements: 2.1, 2.2_
|
| 37 |
+
- _Prompt: Role: QA Engineer with expertise in unit testing and Jest/Mocha frameworks | Task: Create comprehensive unit tests for FeatureModel validation and CRUD methods covering requirements 2.1 and 2.2, using existing test utilities from tests/helpers/testUtils.ts and fixtures from tests/fixtures/data.ts | Restrictions: Must test both success and failure scenarios, do not test external dependencies directly, maintain test isolation | Success: All model methods are tested with good coverage, edge cases covered, tests run independently and consistently_
|
| 38 |
+
|
| 39 |
+
- [ ] 5. Create service interface in src/services/IFeatureService.ts
|
| 40 |
+
- File: src/services/IFeatureService.ts
|
| 41 |
+
- Define service contract with method signatures
|
| 42 |
+
- Extend base service interface patterns
|
| 43 |
+
- Purpose: Establish service layer contract for dependency injection
|
| 44 |
+
- _Leverage: src/services/IBaseService.ts_
|
| 45 |
+
- _Requirements: 3.1_
|
| 46 |
+
- _Prompt: Role: Software Architect specializing in service-oriented architecture and TypeScript interfaces | Task: Design service interface contract following requirement 3.1, extending base service patterns from src/services/IBaseService.ts for dependency injection | Restrictions: Must maintain interface segregation principle, do not expose internal implementation details, ensure contract compatibility with DI container | Success: Interface is well-defined with clear method signatures, extends base service appropriately, supports all required service operations_
|
| 47 |
+
|
| 48 |
+
- [ ] 6. Implement feature service in src/services/FeatureService.ts
|
| 49 |
+
- File: src/services/FeatureService.ts
|
| 50 |
+
- Create concrete service implementation using FeatureModel
|
| 51 |
+
- Add error handling with existing error utilities
|
| 52 |
+
- Purpose: Provide business logic layer for feature operations
|
| 53 |
+
- _Leverage: src/services/BaseService.ts, src/utils/errorHandler.ts, src/models/FeatureModel.ts_
|
| 54 |
+
- _Requirements: 3.2_
|
| 55 |
+
- _Prompt: Role: Backend Developer with expertise in service layer architecture and business logic | Task: Implement concrete FeatureService following requirement 3.2, using FeatureModel and extending BaseService patterns with proper error handling from src/utils/errorHandler.ts | Restrictions: Must implement interface contract exactly, do not bypass model validation, maintain separation of concerns from data layer | Success: Service implements all interface methods correctly, robust error handling implemented, business logic is well-encapsulated and testable_
|
| 56 |
+
|
| 57 |
+
- [ ] 7. Add service dependency injection in src/utils/di.ts
|
| 58 |
+
- File: src/utils/di.ts (modify existing)
|
| 59 |
+
- Register FeatureService in dependency injection container
|
| 60 |
+
- Configure service lifetime and dependencies
|
| 61 |
+
- Purpose: Enable service injection throughout application
|
| 62 |
+
- _Leverage: existing DI configuration in src/utils/di.ts_
|
| 63 |
+
- _Requirements: 3.1_
|
| 64 |
+
- _Prompt: Role: DevOps Engineer with expertise in dependency injection and IoC containers | Task: Register FeatureService in DI container following requirement 3.1, configuring appropriate lifetime and dependencies using existing patterns from src/utils/di.ts | Restrictions: Must follow existing DI container patterns, do not create circular dependencies, maintain service resolution efficiency | Success: FeatureService is properly registered and resolvable, dependencies are correctly configured, service lifetime is appropriate for use case_
|
| 65 |
+
|
| 66 |
+
- [ ] 8. Create service unit tests in tests/services/FeatureService.test.ts
|
| 67 |
+
- File: tests/services/FeatureService.test.ts
|
| 68 |
+
- Write tests for service methods with mocked dependencies
|
| 69 |
+
- Test error handling scenarios
|
| 70 |
+
- Purpose: Ensure service reliability and proper error handling
|
| 71 |
+
- _Leverage: tests/helpers/testUtils.ts, tests/mocks/modelMocks.ts_
|
| 72 |
+
- _Requirements: 3.2, 3.3_
|
| 73 |
+
- _Prompt: Role: QA Engineer with expertise in service testing and mocking frameworks | Task: Create comprehensive unit tests for FeatureService methods covering requirements 3.2 and 3.3, using mocked dependencies from tests/mocks/modelMocks.ts and test utilities | Restrictions: Must mock all external dependencies, test business logic in isolation, do not test framework code | Success: All service methods tested with proper mocking, error scenarios covered, tests verify business logic correctness and error handling_
|
| 74 |
+
|
| 75 |
+
- [ ] 4. Create API endpoints
|
| 76 |
+
- Design API structure
|
| 77 |
+
- _Leverage: src/api/baseApi.ts, src/utils/apiUtils.ts_
|
| 78 |
+
- _Requirements: 4.0_
|
| 79 |
+
- _Prompt: Role: API Architect specializing in RESTful design and Express.js | Task: Design comprehensive API structure following requirement 4.0, leveraging existing patterns from src/api/baseApi.ts and utilities from src/utils/apiUtils.ts | Restrictions: Must follow REST conventions, maintain API versioning compatibility, do not expose internal data structures directly | Success: API structure is well-designed and documented, follows existing patterns, supports all required operations with proper HTTP methods and status codes_
|
| 80 |
+
|
| 81 |
+
- [ ] 4.1 Set up routing and middleware
|
| 82 |
+
- Configure application routes
|
| 83 |
+
- Add authentication middleware
|
| 84 |
+
- Set up error handling middleware
|
| 85 |
+
- _Leverage: src/middleware/auth.ts, src/middleware/errorHandler.ts_
|
| 86 |
+
- _Requirements: 4.1_
|
| 87 |
+
- _Prompt: Role: Backend Developer with expertise in Express.js middleware and routing | Task: Configure application routes and middleware following requirement 4.1, integrating authentication from src/middleware/auth.ts and error handling from src/middleware/errorHandler.ts | Restrictions: Must maintain middleware order, do not bypass security middleware, ensure proper error propagation | Success: Routes are properly configured with correct middleware chain, authentication works correctly, errors are handled gracefully throughout the request lifecycle_
|
| 88 |
+
|
| 89 |
+
- [ ] 4.2 Implement CRUD endpoints
|
| 90 |
+
- Create API endpoints
|
| 91 |
+
- Add request validation
|
| 92 |
+
- Write API integration tests
|
| 93 |
+
- _Leverage: src/controllers/BaseController.ts, src/utils/validation.ts_
|
| 94 |
+
- _Requirements: 4.2, 4.3_
|
| 95 |
+
- _Prompt: Role: Full-stack Developer with expertise in API development and validation | Task: Implement CRUD endpoints following requirements 4.2 and 4.3, extending BaseController patterns and using validation utilities from src/utils/validation.ts | Restrictions: Must validate all inputs, follow existing controller patterns, ensure proper HTTP status codes and responses | Success: All CRUD operations work correctly, request validation prevents invalid data, integration tests pass and cover all endpoints_
|
| 96 |
+
|
| 97 |
+
- [ ] 5. Add frontend components
|
| 98 |
+
- Plan component architecture
|
| 99 |
+
- _Leverage: src/components/BaseComponent.tsx, src/styles/theme.ts_
|
| 100 |
+
- _Requirements: 5.0_
|
| 101 |
+
- _Prompt: Role: Frontend Architect with expertise in React component design and architecture | Task: Plan comprehensive component architecture following requirement 5.0, leveraging base patterns from src/components/BaseComponent.tsx and theme system from src/styles/theme.ts | Restrictions: Must follow existing component patterns, maintain design system consistency, ensure component reusability | Success: Architecture is well-planned and documented, components are properly organized, follows existing patterns and theme system_
|
| 102 |
+
|
| 103 |
+
- [ ] 5.1 Create base UI components
|
| 104 |
+
- Set up component structure
|
| 105 |
+
- Implement reusable components
|
| 106 |
+
- Add styling and theming
|
| 107 |
+
- _Leverage: src/components/BaseComponent.tsx, src/styles/theme.ts_
|
| 108 |
+
- _Requirements: 5.1_
|
| 109 |
+
- _Prompt: Role: Frontend Developer specializing in React and component architecture | Task: Create reusable UI components following requirement 5.1, extending BaseComponent patterns and using existing theme system from src/styles/theme.ts | Restrictions: Must use existing theme variables, follow component composition patterns, ensure accessibility compliance | Success: Components are reusable and properly themed, follow existing architecture, accessible and responsive_
|
| 110 |
+
|
| 111 |
+
- [ ] 5.2 Implement feature-specific components
|
| 112 |
+
- Create feature components
|
| 113 |
+
- Add state management
|
| 114 |
+
- Connect to API endpoints
|
| 115 |
+
- _Leverage: src/hooks/useApi.ts, src/components/BaseComponent.tsx_
|
| 116 |
+
- _Requirements: 5.2, 5.3_
|
| 117 |
+
- _Prompt: Role: React Developer with expertise in state management and API integration | Task: Implement feature-specific components following requirements 5.2 and 5.3, using API hooks from src/hooks/useApi.ts and extending BaseComponent patterns | Restrictions: Must use existing state management patterns, handle loading and error states properly, maintain component performance | Success: Components are fully functional with proper state management, API integration works smoothly, user experience is responsive and intuitive_
|
| 118 |
+
|
| 119 |
+
- [ ] 6. Integration and testing
|
| 120 |
+
- Plan integration approach
|
| 121 |
+
- _Leverage: src/utils/integrationUtils.ts, tests/helpers/testUtils.ts_
|
| 122 |
+
- _Requirements: 6.0_
|
| 123 |
+
- _Prompt: Role: Integration Engineer with expertise in system integration and testing strategies | Task: Plan comprehensive integration approach following requirement 6.0, leveraging integration utilities from src/utils/integrationUtils.ts and test helpers | Restrictions: Must consider all system components, ensure proper test coverage, maintain integration test reliability | Success: Integration plan is comprehensive and feasible, all system components work together correctly, integration points are well-tested_
|
| 124 |
+
|
| 125 |
+
- [ ] 6.1 Write end-to-end tests
|
| 126 |
+
- Set up E2E testing framework
|
| 127 |
+
- Write user journey tests
|
| 128 |
+
- Add test automation
|
| 129 |
+
- _Leverage: tests/helpers/testUtils.ts, tests/fixtures/data.ts_
|
| 130 |
+
- _Requirements: All_
|
| 131 |
+
- _Prompt: Role: QA Automation Engineer with expertise in E2E testing and test frameworks like Cypress or Playwright | Task: Implement comprehensive end-to-end tests covering all requirements, setting up testing framework and user journey tests using test utilities and fixtures | Restrictions: Must test real user workflows, ensure tests are maintainable and reliable, do not test implementation details | Success: E2E tests cover all critical user journeys, tests run reliably in CI/CD pipeline, user experience is validated from end-to-end_
|
| 132 |
+
|
| 133 |
+
- [ ] 6.2 Final integration and cleanup
|
| 134 |
+
- Integrate all components
|
| 135 |
+
- Fix any integration issues
|
| 136 |
+
- Clean up code and documentation
|
| 137 |
+
- _Leverage: src/utils/cleanup.ts, docs/templates/_
|
| 138 |
+
- _Requirements: All_
|
| 139 |
+
- _Prompt: Role: Senior Developer with expertise in code quality and system integration | Task: Complete final integration of all components and perform comprehensive cleanup covering all requirements, using cleanup utilities and documentation templates | Restrictions: Must not break existing functionality, ensure code quality standards are met, maintain documentation consistency | Success: All components are fully integrated and working together, code is clean and well-documented, system meets all requirements and quality standards_
|
cache/.spec-workflow/templates/tech-template.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Technology Stack
|
| 2 |
+
|
| 3 |
+
## Project Type
|
| 4 |
+
[Describe what kind of project this is: web application, CLI tool, desktop application, mobile app, library, API service, embedded system, game, etc.]
|
| 5 |
+
|
| 6 |
+
## Core Technologies
|
| 7 |
+
|
| 8 |
+
### Primary Language(s)
|
| 9 |
+
- **Language**: [e.g., Python 3.11, Go 1.21, TypeScript, Rust, C++]
|
| 10 |
+
- **Runtime/Compiler**: [if applicable]
|
| 11 |
+
- **Language-specific tools**: [package managers, build tools, etc.]
|
| 12 |
+
|
| 13 |
+
### Key Dependencies/Libraries
|
| 14 |
+
[List the main libraries and frameworks your project depends on]
|
| 15 |
+
- **[Library/Framework name]**: [Purpose and version]
|
| 16 |
+
- **[Library/Framework name]**: [Purpose and version]
|
| 17 |
+
|
| 18 |
+
### Application Architecture
|
| 19 |
+
[Describe how your application is structured - this could be MVC, event-driven, plugin-based, client-server, standalone, microservices, monolithic, etc.]
|
| 20 |
+
|
| 21 |
+
### Data Storage (if applicable)
|
| 22 |
+
- **Primary storage**: [e.g., PostgreSQL, files, in-memory, cloud storage]
|
| 23 |
+
- **Caching**: [e.g., Redis, in-memory, disk cache]
|
| 24 |
+
- **Data formats**: [e.g., JSON, Protocol Buffers, XML, binary]
|
| 25 |
+
|
| 26 |
+
### External Integrations (if applicable)
|
| 27 |
+
- **APIs**: [External services you integrate with]
|
| 28 |
+
- **Protocols**: [e.g., HTTP/REST, gRPC, WebSocket, TCP/IP]
|
| 29 |
+
- **Authentication**: [e.g., OAuth, API keys, certificates]
|
| 30 |
+
|
| 31 |
+
### Monitoring & Dashboard Technologies (if applicable)
|
| 32 |
+
- **Dashboard Framework**: [e.g., React, Vue, vanilla JS, terminal UI]
|
| 33 |
+
- **Real-time Communication**: [e.g., WebSocket, Server-Sent Events, polling]
|
| 34 |
+
- **Visualization Libraries**: [e.g., Chart.js, D3, terminal graphs]
|
| 35 |
+
- **State Management**: [e.g., Redux, Vuex, file system as source of truth]
|
| 36 |
+
|
| 37 |
+
## Development Environment
|
| 38 |
+
|
| 39 |
+
### Build & Development Tools
|
| 40 |
+
- **Build System**: [e.g., Make, CMake, Gradle, npm scripts, cargo]
|
| 41 |
+
- **Package Management**: [e.g., pip, npm, cargo, go mod, apt, brew]
|
| 42 |
+
- **Development workflow**: [e.g., hot reload, watch mode, REPL]
|
| 43 |
+
|
| 44 |
+
### Code Quality Tools
|
| 45 |
+
- **Static Analysis**: [Tools for code quality and correctness]
|
| 46 |
+
- **Formatting**: [Code style enforcement tools]
|
| 47 |
+
- **Testing Framework**: [Unit, integration, and/or end-to-end testing tools]
|
| 48 |
+
- **Documentation**: [Documentation generation tools]
|
| 49 |
+
|
| 50 |
+
### Version Control & Collaboration
|
| 51 |
+
- **VCS**: [e.g., Git, Mercurial, SVN]
|
| 52 |
+
- **Branching Strategy**: [e.g., Git Flow, GitHub Flow, trunk-based]
|
| 53 |
+
- **Code Review Process**: [How code reviews are conducted]
|
| 54 |
+
|
| 55 |
+
### Dashboard Development (if applicable)
|
| 56 |
+
- **Live Reload**: [e.g., Hot module replacement, file watchers]
|
| 57 |
+
- **Port Management**: [e.g., Dynamic allocation, configurable ports]
|
| 58 |
+
- **Multi-Instance Support**: [e.g., Running multiple dashboards simultaneously]
|
| 59 |
+
|
| 60 |
+
## Deployment & Distribution (if applicable)
|
| 61 |
+
- **Target Platform(s)**: [Where/how the project runs: cloud, on-premise, desktop, mobile, embedded]
|
| 62 |
+
- **Distribution Method**: [How users get your software: download, package manager, app store, SaaS]
|
| 63 |
+
- **Installation Requirements**: [Prerequisites, system requirements]
|
| 64 |
+
- **Update Mechanism**: [How updates are delivered]
|
| 65 |
+
|
| 66 |
+
## Technical Requirements & Constraints
|
| 67 |
+
|
| 68 |
+
### Performance Requirements
|
| 69 |
+
- [e.g., response time, throughput, memory usage, startup time]
|
| 70 |
+
- [Specific benchmarks or targets]
|
| 71 |
+
|
| 72 |
+
### Compatibility Requirements
|
| 73 |
+
- **Platform Support**: [Operating systems, architectures, versions]
|
| 74 |
+
- **Dependency Versions**: [Minimum/maximum versions of dependencies]
|
| 75 |
+
- **Standards Compliance**: [Industry standards, protocols, specifications]
|
| 76 |
+
|
| 77 |
+
### Security & Compliance
|
| 78 |
+
- **Security Requirements**: [Authentication, encryption, data protection]
|
| 79 |
+
- **Compliance Standards**: [GDPR, HIPAA, SOC2, etc. if applicable]
|
| 80 |
+
- **Threat Model**: [Key security considerations]
|
| 81 |
+
|
| 82 |
+
### Scalability & Reliability
|
| 83 |
+
- **Expected Load**: [Users, requests, data volume]
|
| 84 |
+
- **Availability Requirements**: [Uptime targets, disaster recovery]
|
| 85 |
+
- **Growth Projections**: [How the system needs to scale]
|
| 86 |
+
|
| 87 |
+
## Technical Decisions & Rationale
|
| 88 |
+
[Document key architectural and technology choices]
|
| 89 |
+
|
| 90 |
+
### Decision Log
|
| 91 |
+
1. **[Technology/Pattern Choice]**: [Why this was chosen, alternatives considered]
|
| 92 |
+
2. **[Architecture Decision]**: [Rationale, trade-offs accepted]
|
| 93 |
+
3. **[Tool/Library Selection]**: [Reasoning, evaluation criteria]
|
| 94 |
+
|
| 95 |
+
## Known Limitations
|
| 96 |
+
[Document any technical debt, limitations, or areas for improvement]
|
| 97 |
+
|
| 98 |
+
- [Limitation 1]: [Impact and potential future solutions]
|
| 99 |
+
- [Limitation 2]: [Why it exists and when it might be addressed]
|
cache/.spec-workflow/user-templates/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# User Templates
|
| 2 |
+
|
| 3 |
+
This directory allows you to create custom templates that override the default Spec Workflow templates.
|
| 4 |
+
|
| 5 |
+
## How to Use Custom Templates
|
| 6 |
+
|
| 7 |
+
1. **Create your custom template file** in this directory with the exact same name as the default template you want to override:
|
| 8 |
+
- `requirements-template.md` - Override requirements document template
|
| 9 |
+
- `design-template.md` - Override design document template
|
| 10 |
+
- `tasks-template.md` - Override tasks document template
|
| 11 |
+
- `product-template.md` - Override product steering template
|
| 12 |
+
- `tech-template.md` - Override tech steering template
|
| 13 |
+
- `structure-template.md` - Override structure steering template
|
| 14 |
+
|
| 15 |
+
2. **Template Loading Priority**:
|
| 16 |
+
- The system first checks this `user-templates/` directory
|
| 17 |
+
- If a matching template is found here, it will be used
|
| 18 |
+
- Otherwise, the default template from `templates/` will be used
|
| 19 |
+
|
| 20 |
+
## Example Custom Template
|
| 21 |
+
|
| 22 |
+
To create a custom requirements template:
|
| 23 |
+
|
| 24 |
+
1. Create a file named `requirements-template.md` in this directory
|
| 25 |
+
2. Add your custom structure, for example:
|
| 26 |
+
|
| 27 |
+
```markdown
|
| 28 |
+
# Requirements Document
|
| 29 |
+
|
| 30 |
+
## Executive Summary
|
| 31 |
+
[Your custom section]
|
| 32 |
+
|
| 33 |
+
## Business Requirements
|
| 34 |
+
[Your custom structure]
|
| 35 |
+
|
| 36 |
+
## Technical Requirements
|
| 37 |
+
[Your custom fields]
|
| 38 |
+
|
| 39 |
+
## Custom Sections
|
| 40 |
+
[Add any sections specific to your workflow]
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
## Template Variables
|
| 44 |
+
|
| 45 |
+
Templates can include placeholders that will be replaced when documents are created:
|
| 46 |
+
- `{{projectName}}` - The name of your project
|
| 47 |
+
- `{{featureName}}` - The name of the feature being specified
|
| 48 |
+
- `{{date}}` - The current date
|
| 49 |
+
- `{{author}}` - The document author
|
| 50 |
+
|
| 51 |
+
## Best Practices
|
| 52 |
+
|
| 53 |
+
1. **Start from defaults**: Copy a default template from `../templates/` as a starting point
|
| 54 |
+
2. **Keep structure consistent**: Maintain similar section headers for tool compatibility
|
| 55 |
+
3. **Document changes**: Add comments explaining why sections were added/modified
|
| 56 |
+
4. **Version control**: Track your custom templates in version control
|
| 57 |
+
5. **Test thoroughly**: Ensure custom templates work with the spec workflow tools
|
| 58 |
+
|
| 59 |
+
## Notes
|
| 60 |
+
|
| 61 |
+
- Custom templates are project-specific and not included in the package distribution
|
| 62 |
+
- The `templates/` directory contains the default templates which are updated with each version
|
| 63 |
+
- Your custom templates in this directory are preserved during updates
|
| 64 |
+
- If a custom template has errors, the system will fall back to the default template
|
cache/Assets/Cyberpunk.jpg
ADDED
|
Git LFS Details
|
cache/Assets/Picasso.jpg
ADDED
|
Git LFS Details
|
cache/Assets/Pixar.jpg
ADDED
|
cache/Assets/VanGogh.jpg
ADDED
|
Git LFS Details
|
cache/FEATURE_UPDATE_SUMMARY.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BytePlus Image Studio - Feature Updates
|
| 2 |
+
|
| 3 |
+
## Summary of Changes
|
| 4 |
+
|
| 5 |
+
I have successfully implemented the two requested features:
|
| 6 |
+
|
| 7 |
+
### 1. Toggle for Style Image Input (Default: No)
|
| 8 |
+
- **Added** a new checkbox `use_style_images_toggle` in the "Output Options" accordion
|
| 9 |
+
- **Label**: "Use Style Images"
|
| 10 |
+
- **Default**: `False` (unchecked)
|
| 11 |
+
- **Info**: "Enable style reference images for generation"
|
| 12 |
+
- **Functionality**:
|
| 13 |
+
- When unchecked (default), style images are hidden and not used in API calls
|
| 14 |
+
- When checked, style images become visible and are included in generation
|
| 15 |
+
- Style images are conditionally passed to the API only when the toggle is enabled
|
| 16 |
+
|
| 17 |
+
### 2. Enhanced API Response Information Display
|
| 18 |
+
- **Updated** the `call_api_single` method to return detailed response information
|
| 19 |
+
- **Enhanced** logging to show:
|
| 20 |
+
- Full API URL (`https://ark.cn-beijing.volces.com/api/v3/images/generations`)
|
| 21 |
+
- Complete API response JSON
|
| 22 |
+
- Generated image URL (full URL)
|
| 23 |
+
- Revised prompt (if provided by API)
|
| 24 |
+
- Used seed value
|
| 25 |
+
- Token and image usage statistics
|
| 26 |
+
- Response structure details
|
| 27 |
+
|
| 28 |
+
- **Updated** status log display to show:
|
| 29 |
+
- Full API endpoint URL
|
| 30 |
+
- Generated image URL (truncated for display)
|
| 31 |
+
- Seed used for generation
|
| 32 |
+
- Usage statistics (tokens and images)
|
| 33 |
+
- Revised prompt (if available)
|
| 34 |
+
- Style image usage status
|
| 35 |
+
|
| 36 |
+
## Technical Implementation Details
|
| 37 |
+
|
| 38 |
+
### Changes Made to app.py:
|
| 39 |
+
|
| 40 |
+
1. **Added new UI component**:
|
| 41 |
+
```python
|
| 42 |
+
use_style_images_toggle = gr.Checkbox(
|
| 43 |
+
label="Use Style Images",
|
| 44 |
+
value=False,
|
| 45 |
+
info="Enable style reference images for generation"
|
| 46 |
+
)
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
2. **Modified function signatures**:
|
| 50 |
+
- `call_api_single()` now returns 3 values: `(url, error, response_details)`
|
| 51 |
+
- `process_and_display_secure()` updated to handle the style toggle parameter
|
| 52 |
+
|
| 53 |
+
3. **Enhanced API response handling**:
|
| 54 |
+
- Captures full response details in a dictionary
|
| 55 |
+
- Logs comprehensive API information
|
| 56 |
+
- Displays detailed status updates in UI
|
| 57 |
+
|
| 58 |
+
4. **Added visibility controls**:
|
| 59 |
+
- Style images are hidden by default (`visible=False`)
|
| 60 |
+
- Toggle function `toggle_style_images_visibility()` shows/hides style images
|
| 61 |
+
- Conditional style image processing based on toggle state
|
| 62 |
+
|
| 63 |
+
5. **Updated status logging**:
|
| 64 |
+
- Shows style images enabled/disabled status
|
| 65 |
+
- Displays full API URL and response details
|
| 66 |
+
- Enhanced error reporting with full response information
|
| 67 |
+
|
| 68 |
+
## User Experience Improvements
|
| 69 |
+
|
| 70 |
+
1. **Cleaner Default Interface**: Style images are hidden by default, reducing UI complexity
|
| 71 |
+
2. **Better API Transparency**: Users can see exactly what URL is being called and full response details
|
| 72 |
+
3. **Enhanced Debugging**: Comprehensive logging helps with troubleshooting
|
| 73 |
+
4. **Flexible Style Control**: Users can choose when to use style references
|
| 74 |
+
|
| 75 |
+
## Security Considerations
|
| 76 |
+
|
| 77 |
+
- All existing security measures remain intact
|
| 78 |
+
- Style image validation still applies when toggle is enabled
|
| 79 |
+
- API response validation continues to work
|
| 80 |
+
- No sensitive information is exposed in the UI logs
|
| 81 |
+
|
| 82 |
+
## Testing
|
| 83 |
+
|
| 84 |
+
The application successfully launches and runs at:
|
| 85 |
+
- Local URL: http://127.0.0.1:7863
|
| 86 |
+
- Public URL: https://8605b404ff941c96f2.gradio.live
|
| 87 |
+
|
| 88 |
+
All features are functional and the interface maintains the existing security and functionality while adding the requested improvements.
|
cache/README.md
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: bytedance
|
| 3 |
+
app_file: app.py
|
| 4 |
+
sdk: gradio
|
| 5 |
+
sdk_version: 5.44.1
|
| 6 |
+
---
|
| 7 |
+
# AI Image Generation Studio 🎨🔒
|
| 8 |
+
|
| 9 |
+
A **secure, enterprise-grade** AI-powered image generation web application built with Gradio. Transform your webcam photos into stunning artistic creations using Volcengine's Doubao-SeeDream-4.0 model with advanced security features and real-time streaming.
|
| 10 |
+
|
| 11 |
+
## ✨ Features
|
| 12 |
+
|
| 13 |
+
### 🎨 Core Functionality
|
| 14 |
+
- **Real-time Webcam Capture**: Secure webcam integration with comprehensive input validation
|
| 15 |
+
- **Multi-Style Generation**: Generate up to 4 artistic variations simultaneously
|
| 16 |
+
- **Pre-configured Art Styles**:
|
| 17 |
+
- Cyberpunk cityscape with face preservation
|
| 18 |
+
- Van Gogh painting style
|
| 19 |
+
- Pixar 3D animation style
|
| 20 |
+
- Picasso cubism with face recognition
|
| 21 |
+
- **Gender Selection**: Choose between male/female portrait generation
|
| 22 |
+
- **Custom Prompts**: Modify any of the 4 prompts to create your own styles
|
| 23 |
+
- **Style Reference Images**: Upload reference images for each style
|
| 24 |
+
|
| 25 |
+
### ⚙️ Advanced Parameters
|
| 26 |
+
- **Seed Control**: Reproducible generation with random seed generation
|
| 27 |
+
- **Watermark Control**: Toggle watermark on generated images
|
| 28 |
+
- **Real-time Streaming**: Live updates during image generation process
|
| 29 |
+
- **Size Options**: 512x512, 1K, or 2K resolution output
|
| 30 |
+
- **Sequential Generation**: Control image generation sequence
|
| 31 |
+
|
| 32 |
+
### 🔒 Security & Performance Features
|
| 33 |
+
- **Input Validation**: Comprehensive sanitization and validation of all inputs
|
| 34 |
+
- **Rate Limiting**: Built-in protection against abuse (20 requests/minute)
|
| 35 |
+
- **Secure API Key Handling**: Encrypted storage and session-based management
|
| 36 |
+
- **Session Management**: Secure session IDs with automatic expiration
|
| 37 |
+
- **Image Size Limits**: Protection against oversized uploads (10MB max)
|
| 38 |
+
- **Domain Whitelisting**: Restricted API communications to trusted domains
|
| 39 |
+
- **HTTPS Enforcement**: Secure API communications only
|
| 40 |
+
- **Comprehensive Logging**: Security monitoring and audit trails
|
| 41 |
+
|
| 42 |
+
## 🚀 Quick Start
|
| 43 |
+
|
| 44 |
+
### Prerequisites
|
| 45 |
+
- Python 3.8 or higher
|
| 46 |
+
- Volcengine API key (obtain from [Volcengine Console](https://www.volcengine.com/))
|
| 47 |
+
- Webcam (for image capture)
|
| 48 |
+
- Stable internet connection
|
| 49 |
+
|
| 50 |
+
### Installation
|
| 51 |
+
|
| 52 |
+
1. **Clone the repository:**
|
| 53 |
+
```bash
|
| 54 |
+
git clone https://github.com/dr-data/byteplus-image-studio-v2.git
|
| 55 |
+
cd byteplus-image-studio-v2
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
2. **Create a virtual environment (recommended):**
|
| 59 |
+
```bash
|
| 60 |
+
python -m venv venv
|
| 61 |
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
3. **Install dependencies:**
|
| 65 |
+
```bash
|
| 66 |
+
pip install -r requirements.txt
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
4. **Get your Volcengine API key:**
|
| 70 |
+
- Visit [Volcengine Console](https://www.volcengine.com/)
|
| 71 |
+
- Create an API key for the Doubao-SeeDream model
|
| 72 |
+
- Copy the API key for use in the application
|
| 73 |
+
|
| 74 |
+
### Running the Application
|
| 75 |
+
|
| 76 |
+
```bash
|
| 77 |
+
python app.py
|
| 78 |
+
```
|
| 79 |
+
|
| 80 |
+
The application will start and provide a local URL (typically `http://127.0.0.1:7862`).
|
| 81 |
+
|
| 82 |
+
### Using the Application
|
| 83 |
+
|
| 84 |
+
1. **Enter your API Key**: Input your Volcengine API key in the "API Key" field
|
| 85 |
+
2. **Select Gender**: Choose between "man" or "woman" for the portraits
|
| 86 |
+
3. **Choose Prompts**: Select which of the 4 artistic styles to generate using checkboxes
|
| 87 |
+
4. **Upload Style References** (optional): Add reference images for each style
|
| 88 |
+
5. **Capture Image**: Use the webcam to capture an image
|
| 89 |
+
6. **Adjust Settings**: Optionally modify seed, watermark, size, and other parameters
|
| 90 |
+
7. **Generate**: Click the "Generate" button to create your artistic variations
|
| 91 |
+
8. **Download**: Download individual images or use "Download All" for a ZIP file
|
| 92 |
+
|
| 93 |
+
## 📋 Requirements
|
| 94 |
+
|
| 95 |
+
```
|
| 96 |
+
gradio==5.44.1
|
| 97 |
+
requests==2.31.0
|
| 98 |
+
Pillow==10.0.0
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
## 🏗️ Architecture
|
| 102 |
+
|
| 103 |
+
### Core Components
|
| 104 |
+
|
| 105 |
+
#### `SecureImageGenerator` Class
|
| 106 |
+
- Handles secure API communication with Volcengine Doubao-SeeDream API
|
| 107 |
+
- Manages authentication, retry logic, and rate limiting
|
| 108 |
+
- Processes images for secure API transmission with validation
|
| 109 |
+
- Implements parallel processing with thread safety
|
| 110 |
+
|
| 111 |
+
#### Security Components
|
| 112 |
+
- **RateLimiter**: Prevents abuse with configurable request limits and session tracking
|
| 113 |
+
- **InputValidator**: Sanitizes and validates all user inputs including images and prompts
|
| 114 |
+
- **SecureAPIManager**: Manages encrypted API keys and secure session handling
|
| 115 |
+
|
| 116 |
+
#### Gradio Web Interface
|
| 117 |
+
- Modern, responsive UI built with Gradio Blocks
|
| 118 |
+
- Webcam integration with secure image capture and validation
|
| 119 |
+
- Dynamic prompt selection with checkboxes and real-time UI updates
|
| 120 |
+
- Real-time streaming updates and progress tracking
|
| 121 |
+
- Comprehensive error logging and user feedback
|
| 122 |
+
|
| 123 |
+
### API Integration
|
| 124 |
+
|
| 125 |
+
- **Endpoint**: `https://ark.cn-beijing.volces.com/api/v3/images/generations`
|
| 126 |
+
- **Model**: `doubao-seedream-4-0-250828` (image-to-image editing with face preservation)
|
| 127 |
+
- **API Key Source**: [Volcengine Console](https://www.volcengine.com/)
|
| 128 |
+
- **Security**: Encrypted API key transmission, domain whitelisting, and secure session management
|
| 129 |
+
- **Features**: Seed control, watermark options, face preservation, multi-image input support
|
| 130 |
+
|
| 131 |
+
## 📊 Code Summary
|
| 132 |
+
|
| 133 |
+
### Core Classes
|
| 134 |
+
- **`SecureImageGenerator`**: Main class handling API communication and image processing
|
| 135 |
+
- **`RateLimiter`**: Implements rate limiting to prevent abuse
|
| 136 |
+
- **`InputValidator`**: Handles input sanitization and validation
|
| 137 |
+
- **`SecureAPIManager`**: Manages API keys and session security
|
| 138 |
+
|
| 139 |
+
### Key Functions
|
| 140 |
+
- **`process_images_secure()`**: Main processing function with parallel API calls and streaming
|
| 141 |
+
- **`call_api_single_stream()`**: Streaming API call with real-time updates
|
| 142 |
+
- **`validate_image()`**: Image validation and security checks
|
| 143 |
+
- **`sanitize_prompt()`**: Input sanitization for prompts
|
| 144 |
+
- **`create_secure_interface()`**: Gradio UI creation with security features
|
| 145 |
+
|
| 146 |
+
### Security Features Implemented
|
| 147 |
+
- Rate limiting with session tracking (20 requests/minute)
|
| 148 |
+
- Input validation and sanitization
|
| 149 |
+
- Secure API key management with SHA256 hashing
|
| 150 |
+
- Domain whitelisting for API communications
|
| 151 |
+
- Comprehensive logging and audit trails
|
| 152 |
+
- Session-based security with automatic expiration
|
| 153 |
+
- Image size and format validation (max 10MB, JPEG/PNG/WEBP)
|
| 154 |
+
- HTML escaping to prevent XSS attacks
|
| 155 |
+
|
| 156 |
+
## 🔄 Change Summary
|
| 157 |
+
|
| 158 |
+
### Recent Updates (September 2025)
|
| 159 |
+
- **Generation History Table**: Added comprehensive generation history table at the bottom of the interface with lazy loading, pagination, and download capabilities
|
| 160 |
+
- **Lazy Loading System**: Implemented efficient pagination system loading 10 items per page to handle large generation histories without performance issues
|
| 161 |
+
- **History Preview Thumbnails**: Added thumbnail previews for generated images in session folders with hover effects and responsive design
|
| 162 |
+
- **ZIP Archive Downloads**: Direct download functionality for ZIP files from the history table with proper file path resolution
|
| 163 |
+
- **Session Folder Management**: Automatic scanning and organization of session folders from the Generated directory with timestamp sorting
|
| 164 |
+
- **Interactive History Navigation**: Added refresh and load more buttons for dynamic history browsing with real-time updates
|
| 165 |
+
- **History Table Styling**: Modern, responsive table design with proper CSS styling for thumbnails, buttons, and pagination controls
|
| 166 |
+
- **JavaScript Integration**: Client-side JavaScript functions for handling view and download actions from the history table
|
| 167 |
+
- **Error Handling**: Comprehensive error handling for missing files, invalid timestamps, and loading failures in the history system
|
| 168 |
+
- **UI Toggle Fixes**: Fixed "🎨 Use Style Reference Images" toggle functionality to properly show/hide style image upload components
|
| 169 |
+
- **Gallery Download Links**: Implemented working zip download links in gallery table using data URL approach with base64 encoding for direct browser downloads
|
| 170 |
+
- **Download Functionality Fixes**: Resolved "expected str, bytes or os.PathLike object, not tuple" error in download buttons
|
| 171 |
+
- **ZIP File Consistency**: Fixed inconsistent zip file names between download component and gallery table by reusing existing files
|
| 172 |
+
- **Optimized Download System**: Download button now reuses existing zip files instead of creating duplicates, saving disk space and processing time
|
| 173 |
+
- **Table-Based Gallery System**: Each webcam capture creates a new row in an organized table with individual galleries and download links
|
| 174 |
+
- **Session-Based Organization**: Images are grouped by capture session with timestamps and dedicated ZIP downloads
|
| 175 |
+
- **Enhanced Gallery UI**: Replaced single gallery with HTML table showing thumbnails, timestamps, and per-session downloads
|
| 176 |
+
- **Capture Session Management**: State management for multiple capture sessions with chronological ordering
|
| 177 |
+
- **API Migration**: Migrated from BytePlus to Volcengine Doubao-SeeDream-4.0 model
|
| 178 |
+
- **Enhanced Security**: Comprehensive input validation and session management
|
| 179 |
+
- **Real-time Streaming**: Live updates during image generation process
|
| 180 |
+
- **Multi-Image Support**: Support for style reference images alongside webcam input
|
| 181 |
+
- **ZIP Download**: Download all generated images in a single archive
|
| 182 |
+
- **Improved Error Handling**: Better user feedback and logging
|
| 183 |
+
- **Parallel Processing**: Optimized concurrent API calls (max 4 simultaneous)
|
| 184 |
+
- **Session Management**: Secure session ID generation and validation
|
| 185 |
+
- **Rate Limiting**: Built-in protection against abuse
|
| 186 |
+
- **Domain Whitelisting**: Restricted API communications to trusted domains
|
| 187 |
+
- **URL Parameter API Key**: Added `?ok` parameter support for automatic API key loading from `.env` file
|
| 188 |
+
- **Environment Variable Support**: Integrated python-dotenv for secure API key management
|
| 189 |
+
- **Gradio Request Handling**: Fixed Request object compatibility issues for URL parameter detection
|
| 190 |
+
- **Enhanced API Key Security**: Secure loading from environment variables with fallback to manual input
|
| 191 |
+
|
| 192 |
+
## 🐛 Troubleshooting
|
| 193 |
+
|
| 194 |
+
### Common Issues
|
| 195 |
+
|
| 196 |
+
1. **"API key not set" error**
|
| 197 |
+
- Ensure you've entered a valid Volcengine API key
|
| 198 |
+
- Check that the key has appropriate permissions
|
| 199 |
+
- Verify the key format is correct
|
| 200 |
+
|
| 201 |
+
2. **"Failed to process input image" error**
|
| 202 |
+
- Ensure your webcam is properly connected and allowed
|
| 203 |
+
- Check that the image is under 10MB and in supported format (JPEG, PNG, WEBP)
|
| 204 |
+
- Verify image dimensions are within limits (max 4096x4096)
|
| 205 |
+
|
| 206 |
+
3. **"Rate limit exceeded" error**
|
| 207 |
+
- Wait before making more requests (20 requests per minute limit)
|
| 208 |
+
- The application automatically handles rate limiting
|
| 209 |
+
|
| 210 |
+
4. **Timeout errors**
|
| 211 |
+
- Check your internet connection stability
|
| 212 |
+
- The application will automatically retry failed requests
|
| 213 |
+
|
| 214 |
+
5. **Import errors**
|
| 215 |
+
- Ensure all dependencies are installed: `pip install -r requirements.txt`
|
| 216 |
+
- Check Python version compatibility (3.8+ required)
|
| 217 |
+
|
| 218 |
+
### Diagnostic Tools
|
| 219 |
+
|
| 220 |
+
Run the diagnostic script to check your environment:
|
| 221 |
+
```bash
|
| 222 |
+
python fix_pydantic_issue.py
|
| 223 |
+
```
|
| 224 |
+
|
| 225 |
+
Test the application functionality:
|
| 226 |
+
```bash
|
| 227 |
+
python test_app.py
|
| 228 |
+
```
|
| 229 |
+
|
| 230 |
+
Check security logs for detailed error information:
|
| 231 |
+
```bash
|
| 232 |
+
tail -f app_security.log
|
| 233 |
+
```
|
| 234 |
+
|
| 235 |
+
## 📁 Project Structure
|
| 236 |
+
|
| 237 |
+
```
|
| 238 |
+
byteplus-image-studio-v2/
|
| 239 |
+
├── app.py # 🚀 MAIN APPLICATION - Secure Volcengine implementation
|
| 240 |
+
├── app3.py # Alternative/backup version
|
| 241 |
+
├── requirements.txt # Python dependencies
|
| 242 |
+
├── README.md # This documentation
|
| 243 |
+
├── security_analysis.md # Detailed security implementation analysis
|
| 244 |
+
├── app_security.log # Security and application logs
|
| 245 |
+
├── test_app.py # Application functionality tests
|
| 246 |
+
├── test_api.py # API testing utilities
|
| 247 |
+
├── test_fix.py # PIL compatibility tests
|
| 248 |
+
├── fix_pydantic_issue.py # Diagnostic and compatibility fix script
|
| 249 |
+
├── __pycache__/ # Python bytecode cache
|
| 250 |
+
├── Assets/ # Sample art style reference images
|
| 251 |
+
│ ├── Cyberpunk.jpg
|
| 252 |
+
│ ├── Picasso.jpg
|
| 253 |
+
│ ├── Pixar.jpg
|
| 254 |
+
│ └── VanGogh.jpg
|
| 255 |
+
└── Generated/ # Generated images storage
|
| 256 |
+
```
|
| 257 |
+
|
| 258 |
+
## 🔒 Security Features
|
| 259 |
+
|
| 260 |
+
### Input Security
|
| 261 |
+
- **Prompt Sanitization**: Removes potentially harmful characters and patterns
|
| 262 |
+
- **Image Validation**: Size limits, format checking, dimension validation
|
| 263 |
+
- **API Key Protection**: Secure storage, encrypted transmission, session-based management
|
| 264 |
+
- **HTML Escaping**: Prevents XSS attacks in user inputs
|
| 265 |
+
|
| 266 |
+
### Rate Limiting & Abuse Prevention
|
| 267 |
+
- **Request Throttling**: Configurable limits per time window (20 requests/60 seconds)
|
| 268 |
+
- **Session Tracking**: Secure session ID generation and validation with expiration
|
| 269 |
+
- **Concurrent Request Limits**: Prevents resource exhaustion (max 4 concurrent)
|
| 270 |
+
- **Comprehensive Monitoring**: Tracks and logs suspicious activity patterns
|
| 271 |
+
|
| 272 |
+
### Network Security
|
| 273 |
+
- **Domain Whitelisting**: Only allows communication with trusted Volcengine domains
|
| 274 |
+
- **HTTPS Enforcement**: Secure API communications with certificate validation
|
| 275 |
+
- **Timeout Protection**: Prevents hanging connections and resource exhaustion
|
| 276 |
+
- **URL Validation**: Strict validation of API response URLs
|
| 277 |
+
|
| 278 |
+
### Authentication & Authorization
|
| 279 |
+
- **Secure API Key Handling**: SHA256 hashing for validation, encrypted session storage
|
| 280 |
+
- **Session Management**: Automatic session expiration and cleanup (1 hour)
|
| 281 |
+
- **Request Signing**: Unique request IDs for tracking and replay prevention
|
| 282 |
+
- **Access Logging**: Comprehensive audit trail of all API interactions
|
| 283 |
+
|
| 284 |
+
## 🚀 Quick Commands
|
| 285 |
+
|
| 286 |
+
```bash
|
| 287 |
+
# Install dependencies
|
| 288 |
+
pip install -r requirements.txt
|
| 289 |
+
|
| 290 |
+
# Run the application
|
| 291 |
+
python app.py
|
| 292 |
+
```
|
| 293 |
+
|
| 294 |
+
## 🤝 Contributing
|
| 295 |
+
|
| 296 |
+
1. Fork the repository
|
| 297 |
+
2. Create a feature branch: `git checkout -b feature-name`
|
| 298 |
+
3. Make your changes and test thoroughly
|
| 299 |
+
4. Ensure security best practices are followed
|
| 300 |
+
5. Commit your changes: `git commit -am 'Add secure feature'`
|
| 301 |
+
6. Push to the branch: `git push origin feature-name`
|
| 302 |
+
7. Submit a pull request with security review
|
| 303 |
+
|
| 304 |
+
## 📄 License
|
| 305 |
+
|
| 306 |
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
| 307 |
+
|
| 308 |
+
## 🙏 Acknowledgments
|
| 309 |
+
|
| 310 |
+
- **Volcengine**: For providing the powerful Doubao-SeeDream AI image generation API
|
| 311 |
+
- **Gradio**: For the excellent web UI framework
|
| 312 |
+
- **PIL/Pillow**: For robust image processing capabilities
|
| 313 |
+
- **Python Security Community**: For security best practices and libraries
|
| 314 |
+
|
| 315 |
+
## 📞 Support
|
| 316 |
+
|
| 317 |
+
If you encounter any issues or have questions:
|
| 318 |
+
1. Check the troubleshooting section above
|
| 319 |
+
2. Review the security logs in `app_security.log`
|
| 320 |
+
3. Check the application's error log in the web interface
|
| 321 |
+
4. Create an issue on GitHub with detailed information including:
|
| 322 |
+
- Error messages and logs
|
| 323 |
+
- Your Python version and OS
|
| 324 |
+
- Steps to reproduce the issue
|
| 325 |
+
- API key source (Volcengine Console)
|
| 326 |
+
|
| 327 |
+
---
|
| 328 |
+
|
| 329 |
+
**Secure AI-Powered Image Creation 🎨🔒**
|
| 330 |
+
|
| 331 |
+
Transform your photos into masterpieces with enterprise-grade security and AI-powered artistic generation.
|
| 332 |
+
|
| 333 |
+
**📋 API Key Source:** [Volcengine Console](https://www.volcengine.com/)
|
cache/__pycache__/app.cpython-310.pyc
ADDED
|
Binary file (57.5 kB). View file
|
|
|
cache/app.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
cache/app3.py
ADDED
|
@@ -0,0 +1,936 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Secure version of BytePlus Image Generation Studio
|
| 4 |
+
Implements security best practices and recommendations
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import gradio as gr
|
| 8 |
+
import requests
|
| 9 |
+
import concurrent.futures
|
| 10 |
+
import base64
|
| 11 |
+
import io
|
| 12 |
+
import time
|
| 13 |
+
import os
|
| 14 |
+
import re
|
| 15 |
+
import hashlib
|
| 16 |
+
import secrets
|
| 17 |
+
import random
|
| 18 |
+
import zipfile
|
| 19 |
+
import tempfile
|
| 20 |
+
from datetime import datetime, timedelta
|
| 21 |
+
from PIL import Image
|
| 22 |
+
import numpy as np
|
| 23 |
+
from functools import wraps
|
| 24 |
+
from html import escape
|
| 25 |
+
from typing import Optional, Tuple, List, Any
|
| 26 |
+
import logging
|
| 27 |
+
from urllib.parse import urlparse
|
| 28 |
+
|
| 29 |
+
# Configure secure logging
|
| 30 |
+
logging.basicConfig(
|
| 31 |
+
level=logging.INFO,
|
| 32 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 33 |
+
handlers=[
|
| 34 |
+
logging.FileHandler('app_security.log'),
|
| 35 |
+
logging.StreamHandler()
|
| 36 |
+
]
|
| 37 |
+
)
|
| 38 |
+
logger = logging.getLogger(__name__)
|
| 39 |
+
|
| 40 |
+
# Security Configuration
|
| 41 |
+
MAX_IMAGE_SIZE = 10 * 1024 * 1024 # 10MB
|
| 42 |
+
ALLOWED_IMAGE_FORMATS = {'JPEG', 'PNG', 'WEBP'}
|
| 43 |
+
MAX_PROMPT_LENGTH = 1000 # Increased to accommodate the pre-set prompts
|
| 44 |
+
RATE_LIMIT_REQUESTS = 20
|
| 45 |
+
RATE_LIMIT_WINDOW = 60 # seconds
|
| 46 |
+
MAX_CONCURRENT_REQUESTS = 4
|
| 47 |
+
# Allowed domains for API and development
|
| 48 |
+
ALLOWED_DOMAINS = {
|
| 49 |
+
# BytePlus API and CDN domains
|
| 50 |
+
'bytepluses.com',
|
| 51 |
+
'volces.com',
|
| 52 |
+
'byteplus.com',
|
| 53 |
+
'volcengine.com',
|
| 54 |
+
# Local development
|
| 55 |
+
'localhost',
|
| 56 |
+
'127.0.0.1',
|
| 57 |
+
'0.0.0.0',
|
| 58 |
+
# Gradio sharing
|
| 59 |
+
'gradio.live',
|
| 60 |
+
'gradio.app',
|
| 61 |
+
'share.gradio.app'
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
class RateLimiter:
|
| 65 |
+
"""Rate limiting implementation to prevent abuse"""
|
| 66 |
+
def __init__(self, max_requests=RATE_LIMIT_REQUESTS, window=RATE_LIMIT_WINDOW):
|
| 67 |
+
self.requests = {}
|
| 68 |
+
self.max_requests = max_requests
|
| 69 |
+
self.window = window
|
| 70 |
+
|
| 71 |
+
def check_rate_limit(self, session_id: str) -> bool:
|
| 72 |
+
"""Check if request is within rate limits"""
|
| 73 |
+
now = time.time()
|
| 74 |
+
if session_id not in self.requests:
|
| 75 |
+
self.requests[session_id] = []
|
| 76 |
+
|
| 77 |
+
# Clean old requests
|
| 78 |
+
self.requests[session_id] = [
|
| 79 |
+
req for req in self.requests[session_id]
|
| 80 |
+
if now - req < self.window
|
| 81 |
+
]
|
| 82 |
+
|
| 83 |
+
if len(self.requests[session_id]) >= self.max_requests:
|
| 84 |
+
logger.warning(f"Rate limit exceeded for session: {session_id}")
|
| 85 |
+
return False
|
| 86 |
+
|
| 87 |
+
self.requests[session_id].append(now)
|
| 88 |
+
return True
|
| 89 |
+
|
| 90 |
+
class InputValidator:
|
| 91 |
+
"""Input validation and sanitization"""
|
| 92 |
+
|
| 93 |
+
@staticmethod
|
| 94 |
+
def sanitize_prompt(prompt: str) -> str:
|
| 95 |
+
"""Sanitize user prompts to prevent injection attacks"""
|
| 96 |
+
if not prompt:
|
| 97 |
+
return ""
|
| 98 |
+
|
| 99 |
+
# Remove potential injection patterns
|
| 100 |
+
prompt = re.sub(r'[<>\"\'`;\\]', '', prompt)
|
| 101 |
+
|
| 102 |
+
# Escape HTML entities
|
| 103 |
+
prompt = escape(prompt)
|
| 104 |
+
|
| 105 |
+
# Limit length
|
| 106 |
+
prompt = prompt[:MAX_PROMPT_LENGTH]
|
| 107 |
+
|
| 108 |
+
# Remove multiple spaces
|
| 109 |
+
prompt = ' '.join(prompt.split())
|
| 110 |
+
|
| 111 |
+
return prompt.strip()
|
| 112 |
+
|
| 113 |
+
@staticmethod
|
| 114 |
+
def validate_image(image: Any) -> Tuple[bool, str]:
|
| 115 |
+
"""Validate image input for security"""
|
| 116 |
+
if image is None:
|
| 117 |
+
return False, "No image provided"
|
| 118 |
+
|
| 119 |
+
try:
|
| 120 |
+
# Handle different input types
|
| 121 |
+
if isinstance(image, tuple):
|
| 122 |
+
if len(image) > 0:
|
| 123 |
+
image = image[0]
|
| 124 |
+
else:
|
| 125 |
+
return False, "Invalid image format"
|
| 126 |
+
|
| 127 |
+
# Convert to PIL Image if needed
|
| 128 |
+
if not isinstance(image, Image.Image):
|
| 129 |
+
try:
|
| 130 |
+
image = Image.fromarray(image)
|
| 131 |
+
except Exception:
|
| 132 |
+
return False, "Failed to process image"
|
| 133 |
+
|
| 134 |
+
# Check image format
|
| 135 |
+
if image.format and image.format not in ALLOWED_IMAGE_FORMATS:
|
| 136 |
+
return False, f"Invalid image format. Allowed: {', '.join(ALLOWED_IMAGE_FORMATS)}"
|
| 137 |
+
|
| 138 |
+
# Check image size
|
| 139 |
+
img_byte_arr = io.BytesIO()
|
| 140 |
+
image.save(img_byte_arr, format='JPEG')
|
| 141 |
+
if len(img_byte_arr.getvalue()) > MAX_IMAGE_SIZE:
|
| 142 |
+
return False, f"Image too large. Maximum size: {MAX_IMAGE_SIZE / 1024 / 1024}MB"
|
| 143 |
+
|
| 144 |
+
# Check image dimensions
|
| 145 |
+
width, height = image.size
|
| 146 |
+
if width > 4096 or height > 4096:
|
| 147 |
+
return False, "Image dimensions too large. Maximum: 4096x4096"
|
| 148 |
+
|
| 149 |
+
return True, "Valid"
|
| 150 |
+
|
| 151 |
+
except Exception as e:
|
| 152 |
+
logger.error(f"Image validation error: {str(e)}")
|
| 153 |
+
return False, "Image validation failed"
|
| 154 |
+
|
| 155 |
+
@staticmethod
|
| 156 |
+
def validate_api_key(api_key: str) -> bool:
|
| 157 |
+
"""Validate API key format"""
|
| 158 |
+
if not api_key:
|
| 159 |
+
return False
|
| 160 |
+
|
| 161 |
+
# Basic validation - adjust pattern based on actual API key format
|
| 162 |
+
pattern = r'^[A-Za-z0-9_\-]{20,}$'
|
| 163 |
+
return bool(re.match(pattern, api_key))
|
| 164 |
+
|
| 165 |
+
class SecureAPIManager:
|
| 166 |
+
"""Secure API management with encryption and protection"""
|
| 167 |
+
|
| 168 |
+
def __init__(self):
|
| 169 |
+
self.api_url = "https://ark.ap-southeast.bytepluses.com/api/v3/images/generations"
|
| 170 |
+
self._api_key_hash = None
|
| 171 |
+
self.timeout = 30
|
| 172 |
+
self.max_retries = 3
|
| 173 |
+
self.retry_delay = 2
|
| 174 |
+
self.session_keys = {} # Store encrypted keys per session
|
| 175 |
+
|
| 176 |
+
def set_api_key(self, api_key: str, session_id: str) -> bool:
|
| 177 |
+
"""Securely store API key for session"""
|
| 178 |
+
if not InputValidator.validate_api_key(api_key):
|
| 179 |
+
logger.warning("Invalid API key format attempted")
|
| 180 |
+
return False
|
| 181 |
+
|
| 182 |
+
# Store hash for validation
|
| 183 |
+
self._api_key_hash = hashlib.sha256(api_key.encode()).hexdigest()
|
| 184 |
+
|
| 185 |
+
# Store encrypted key for session
|
| 186 |
+
session_key = secrets.token_hex(32)
|
| 187 |
+
# In production, use proper encryption like cryptography.fernet
|
| 188 |
+
self.session_keys[session_id] = {
|
| 189 |
+
'key': api_key, # In production, encrypt this
|
| 190 |
+
'expires': datetime.now() + timedelta(hours=1)
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
logger.info(f"API key set for session: {session_id[:8]}...")
|
| 194 |
+
return True
|
| 195 |
+
|
| 196 |
+
def get_api_key(self, session_id: str) -> Optional[str]:
|
| 197 |
+
"""Retrieve API key for session"""
|
| 198 |
+
if session_id not in self.session_keys:
|
| 199 |
+
return None
|
| 200 |
+
|
| 201 |
+
session_data = self.session_keys[session_id]
|
| 202 |
+
|
| 203 |
+
# Check expiration
|
| 204 |
+
if datetime.now() > session_data['expires']:
|
| 205 |
+
del self.session_keys[session_id]
|
| 206 |
+
logger.info(f"Session expired: {session_id[:8]}...")
|
| 207 |
+
return None
|
| 208 |
+
|
| 209 |
+
return session_data['key']
|
| 210 |
+
|
| 211 |
+
def validate_url(self, url: str) -> bool:
|
| 212 |
+
"""Validate external URLs - focused on API response URLs only"""
|
| 213 |
+
try:
|
| 214 |
+
parsed = urlparse(url)
|
| 215 |
+
|
| 216 |
+
# For API response URLs from BytePlus
|
| 217 |
+
if parsed.hostname:
|
| 218 |
+
# Allow BytePlus/Volcengine CDN domains
|
| 219 |
+
if any(domain in parsed.hostname for domain in [
|
| 220 |
+
'bytepluses.com',
|
| 221 |
+
'volces.com',
|
| 222 |
+
'byteplus.com',
|
| 223 |
+
'volcengine.com'
|
| 224 |
+
]):
|
| 225 |
+
# These are legitimate API response URLs
|
| 226 |
+
return True
|
| 227 |
+
|
| 228 |
+
# Allow localhost and Gradio URLs for development
|
| 229 |
+
if any(pattern in parsed.hostname for pattern in [
|
| 230 |
+
'localhost',
|
| 231 |
+
'127.0.0.1',
|
| 232 |
+
'0.0.0.0',
|
| 233 |
+
'gradio.live',
|
| 234 |
+
'gradio.app',
|
| 235 |
+
'.gradio.live',
|
| 236 |
+
'.share.gradio.app'
|
| 237 |
+
]):
|
| 238 |
+
return True
|
| 239 |
+
|
| 240 |
+
# Log but don't block other domains - this is just for monitoring
|
| 241 |
+
logger.info(f"External domain accessed: {parsed.hostname}")
|
| 242 |
+
|
| 243 |
+
# For production, you might want to be more restrictive
|
| 244 |
+
# For now, allow HTTPS URLs from the API
|
| 245 |
+
if parsed.scheme == 'https':
|
| 246 |
+
return True
|
| 247 |
+
|
| 248 |
+
return False
|
| 249 |
+
|
| 250 |
+
except Exception as e:
|
| 251 |
+
logger.error(f"URL validation error: {str(e)}")
|
| 252 |
+
return False
|
| 253 |
+
|
| 254 |
+
class SecureImageGenerator:
|
| 255 |
+
"""Secure implementation of BytePlus image generation"""
|
| 256 |
+
|
| 257 |
+
def __init__(self):
|
| 258 |
+
self.api_manager = SecureAPIManager()
|
| 259 |
+
self.rate_limiter = RateLimiter()
|
| 260 |
+
self.validator = InputValidator()
|
| 261 |
+
self.active_requests = 0
|
| 262 |
+
self.max_concurrent = MAX_CONCURRENT_REQUESTS
|
| 263 |
+
|
| 264 |
+
def process_image_for_api(self, image: Any) -> Optional[str]:
|
| 265 |
+
"""Securely process and validate image for API"""
|
| 266 |
+
is_valid, message = self.validator.validate_image(image)
|
| 267 |
+
if not is_valid:
|
| 268 |
+
logger.warning(f"Image validation failed: {message}")
|
| 269 |
+
return None
|
| 270 |
+
|
| 271 |
+
try:
|
| 272 |
+
# Handle different input types
|
| 273 |
+
if isinstance(image, tuple):
|
| 274 |
+
if len(image) > 0:
|
| 275 |
+
image = image[0]
|
| 276 |
+
else:
|
| 277 |
+
return None
|
| 278 |
+
|
| 279 |
+
# Ensure PIL Image
|
| 280 |
+
if not isinstance(image, Image.Image):
|
| 281 |
+
image = Image.fromarray(image)
|
| 282 |
+
|
| 283 |
+
# Resize securely
|
| 284 |
+
image = image.resize((512, 512), Image.Resampling.LANCZOS)
|
| 285 |
+
|
| 286 |
+
# Convert to base64
|
| 287 |
+
buffer = io.BytesIO()
|
| 288 |
+
image.save(buffer, format="JPEG", quality=85, optimize=True)
|
| 289 |
+
|
| 290 |
+
# Check final size
|
| 291 |
+
if len(buffer.getvalue()) > MAX_IMAGE_SIZE:
|
| 292 |
+
logger.warning("Processed image exceeds size limit")
|
| 293 |
+
return None
|
| 294 |
+
|
| 295 |
+
image_base64 = base64.b64encode(buffer.getvalue()).decode()
|
| 296 |
+
return f"data:image/jpeg;base64,{image_base64}"
|
| 297 |
+
|
| 298 |
+
except Exception as e:
|
| 299 |
+
logger.error(f"Image processing error: {str(e)}")
|
| 300 |
+
return None
|
| 301 |
+
|
| 302 |
+
def call_api_single(self, prompt: str, image_base64: str, gender_value: str,
|
| 303 |
+
session_id: str, seed: int = 21, guidance_scale: float = 5.5,
|
| 304 |
+
watermark: bool = True) -> Tuple[Optional[str], Optional[str]]:
|
| 305 |
+
"""Make secure API call with validation and error handling"""
|
| 306 |
+
|
| 307 |
+
# Check rate limit
|
| 308 |
+
if not self.rate_limiter.check_rate_limit(session_id):
|
| 309 |
+
return None, "Rate limit exceeded. Please wait before trying again."
|
| 310 |
+
|
| 311 |
+
# Check concurrent requests
|
| 312 |
+
if self.active_requests >= self.max_concurrent:
|
| 313 |
+
return None, "Too many concurrent requests. Please wait."
|
| 314 |
+
|
| 315 |
+
# Get API key
|
| 316 |
+
api_key = self.api_manager.get_api_key(session_id)
|
| 317 |
+
if not api_key:
|
| 318 |
+
return None, "API key not set or session expired"
|
| 319 |
+
|
| 320 |
+
# Sanitize prompt
|
| 321 |
+
prompt = self.validator.sanitize_prompt(prompt)
|
| 322 |
+
processed_prompt = prompt.replace("{gender}", gender_value)
|
| 323 |
+
|
| 324 |
+
# Validate parameters
|
| 325 |
+
seed = max(0, min(seed, 2147483647)) # Ensure valid seed range
|
| 326 |
+
guidance_scale = max(1.0, min(guidance_scale, 10.0))
|
| 327 |
+
|
| 328 |
+
headers = {
|
| 329 |
+
"Content-Type": "application/json",
|
| 330 |
+
"Authorization": f"Bearer {api_key}",
|
| 331 |
+
"X-Request-ID": secrets.token_hex(16) # Add request tracking
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
payload = {
|
| 335 |
+
"model": "seededit-3-0-i2i-250628",
|
| 336 |
+
"prompt": processed_prompt,
|
| 337 |
+
"image": image_base64,
|
| 338 |
+
"response_format": "url",
|
| 339 |
+
"size": "adaptive",
|
| 340 |
+
"seed": seed,
|
| 341 |
+
"guidance_scale": guidance_scale,
|
| 342 |
+
"watermark": watermark
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
self.active_requests += 1
|
| 346 |
+
|
| 347 |
+
try:
|
| 348 |
+
for attempt in range(self.api_manager.max_retries):
|
| 349 |
+
try:
|
| 350 |
+
response = requests.post(
|
| 351 |
+
self.api_manager.api_url,
|
| 352 |
+
headers=headers,
|
| 353 |
+
json=payload,
|
| 354 |
+
timeout=self.api_manager.timeout
|
| 355 |
+
)
|
| 356 |
+
|
| 357 |
+
if response.status_code == 200:
|
| 358 |
+
result = response.json()
|
| 359 |
+
if "data" in result and len(result["data"]) > 0:
|
| 360 |
+
url = result["data"][0].get("url")
|
| 361 |
+
|
| 362 |
+
# Validate returned URL
|
| 363 |
+
if url and self.api_manager.validate_url(url):
|
| 364 |
+
logger.info(f"Successful API call for session: {session_id[:8]}...")
|
| 365 |
+
return url, None
|
| 366 |
+
else:
|
| 367 |
+
logger.warning("Invalid URL returned from API")
|
| 368 |
+
return None, "Invalid response from API"
|
| 369 |
+
else:
|
| 370 |
+
return None, "No data returned from API"
|
| 371 |
+
|
| 372 |
+
elif response.status_code == 429:
|
| 373 |
+
return None, "API rate limit exceeded"
|
| 374 |
+
|
| 375 |
+
elif response.status_code == 401:
|
| 376 |
+
logger.warning(f"Authentication failed for session: {session_id[:8]}...")
|
| 377 |
+
return None, "Authentication failed"
|
| 378 |
+
|
| 379 |
+
else:
|
| 380 |
+
# Log error but don't expose details
|
| 381 |
+
logger.error(f"API error {response.status_code}")
|
| 382 |
+
if attempt == self.api_manager.max_retries - 1:
|
| 383 |
+
return None, f"API error (Code: {response.status_code})"
|
| 384 |
+
|
| 385 |
+
except requests.Timeout:
|
| 386 |
+
if attempt == self.api_manager.max_retries - 1:
|
| 387 |
+
return None, "Request timeout"
|
| 388 |
+
|
| 389 |
+
except requests.RequestException:
|
| 390 |
+
if attempt == self.api_manager.max_retries - 1:
|
| 391 |
+
return None, "Network error"
|
| 392 |
+
|
| 393 |
+
# Wait before retry
|
| 394 |
+
if attempt < self.api_manager.max_retries - 1:
|
| 395 |
+
time.sleep(self.api_manager.retry_delay)
|
| 396 |
+
|
| 397 |
+
return None, "Max retries exceeded"
|
| 398 |
+
|
| 399 |
+
finally:
|
| 400 |
+
self.active_requests -= 1
|
| 401 |
+
|
| 402 |
+
# Initialize secure generator
|
| 403 |
+
generator = SecureImageGenerator()
|
| 404 |
+
|
| 405 |
+
def generate_session_id() -> str:
|
| 406 |
+
"""Generate secure session ID"""
|
| 407 |
+
return secrets.token_hex(32)
|
| 408 |
+
|
| 409 |
+
def process_images_secure(image, prompt1, prompt2, prompt3, prompt4,
|
| 410 |
+
gender, api_key, session_id, seed, guidance_scale, watermark,
|
| 411 |
+
num_images=4, progress_callback=None):
|
| 412 |
+
"""Secure image processing with validation and error handling"""
|
| 413 |
+
|
| 414 |
+
status_updates = []
|
| 415 |
+
|
| 416 |
+
# Validate and set API key
|
| 417 |
+
if not api_key:
|
| 418 |
+
return [None] * 4, ["API key required"] * 4, status_updates
|
| 419 |
+
|
| 420 |
+
status_updates.append("🔐 API key validated")
|
| 421 |
+
|
| 422 |
+
if not generator.api_manager.set_api_key(api_key, session_id):
|
| 423 |
+
return [None] * 4, ["Invalid API key format"] * 4, status_updates
|
| 424 |
+
|
| 425 |
+
# Validate image
|
| 426 |
+
is_valid, message = generator.validator.validate_image(image)
|
| 427 |
+
if not is_valid:
|
| 428 |
+
status_updates.append(f"❌ Image validation failed: {message}")
|
| 429 |
+
return [None] * 4, [message] * 4, status_updates
|
| 430 |
+
|
| 431 |
+
status_updates.append("✅ Image validated successfully")
|
| 432 |
+
|
| 433 |
+
# Process image
|
| 434 |
+
image_base64 = generator.process_image_for_api(image)
|
| 435 |
+
if image_base64 is None:
|
| 436 |
+
status_updates.append("❌ Failed to process image")
|
| 437 |
+
return [None] * 4, ["Failed to process image"] * 4, status_updates
|
| 438 |
+
|
| 439 |
+
status_updates.append("🖼️ Image processed and encoded")
|
| 440 |
+
|
| 441 |
+
# Prepare prompts - use only the provided prompts (selected by checkboxes)
|
| 442 |
+
prompts = [p for p in [prompt1, prompt2, prompt3, prompt4] if p and p.strip()]
|
| 443 |
+
|
| 444 |
+
# Initialize results and errors arrays to match the number of actual prompts
|
| 445 |
+
actual_num_prompts = len(prompts)
|
| 446 |
+
results = [None] * actual_num_prompts
|
| 447 |
+
errors = [None] * actual_num_prompts
|
| 448 |
+
|
| 449 |
+
# Count active prompts
|
| 450 |
+
active_prompts = sum(1 for p in prompts if p and p.strip())
|
| 451 |
+
if active_prompts > 0:
|
| 452 |
+
status_updates.append(f"🚀 Starting {active_prompts} API calls...")
|
| 453 |
+
|
| 454 |
+
# Execute with thread pool
|
| 455 |
+
with concurrent.futures.ThreadPoolExecutor(max_workers=min(MAX_CONCURRENT_REQUESTS, num_images)) as executor:
|
| 456 |
+
futures = []
|
| 457 |
+
for i, prompt in enumerate(prompts):
|
| 458 |
+
if prompt and prompt.strip():
|
| 459 |
+
# Get first 50 chars of prompt for display
|
| 460 |
+
prompt_preview = prompt[:50] + "..." if len(prompt) > 50 else prompt
|
| 461 |
+
prompt = generator.validator.sanitize_prompt(prompt)
|
| 462 |
+
future = executor.submit(
|
| 463 |
+
generator.call_api_single,
|
| 464 |
+
prompt,
|
| 465 |
+
image_base64,
|
| 466 |
+
gender,
|
| 467 |
+
session_id,
|
| 468 |
+
seed,
|
| 469 |
+
guidance_scale,
|
| 470 |
+
watermark
|
| 471 |
+
)
|
| 472 |
+
futures.append((i, future))
|
| 473 |
+
status_updates.append(f"📤 API call {i+1} initiated: {prompt_preview}")
|
| 474 |
+
|
| 475 |
+
# Collect results
|
| 476 |
+
for i, future in futures:
|
| 477 |
+
try:
|
| 478 |
+
url, error = future.result(timeout=60)
|
| 479 |
+
results[i] = url
|
| 480 |
+
errors[i] = error
|
| 481 |
+
if url:
|
| 482 |
+
status_updates.append(f"✅ Image {i+1} generated successfully")
|
| 483 |
+
else:
|
| 484 |
+
status_updates.append(f"⚠️ Image {i+1}: {error}")
|
| 485 |
+
except concurrent.futures.TimeoutError:
|
| 486 |
+
results[i] = None
|
| 487 |
+
errors[i] = "Processing timeout"
|
| 488 |
+
status_updates.append(f"⏱️ Image {i+1} timed out")
|
| 489 |
+
except Exception as e:
|
| 490 |
+
results[i] = None
|
| 491 |
+
errors[i] = "Processing error"
|
| 492 |
+
status_updates.append(f"❌ Image {i+1} error: {str(e)}")
|
| 493 |
+
|
| 494 |
+
# Pad results to 4 elements for consistent return
|
| 495 |
+
while len(results) < 4:
|
| 496 |
+
results.append(None)
|
| 497 |
+
while len(errors) < 4:
|
| 498 |
+
errors.append(None)
|
| 499 |
+
|
| 500 |
+
return results, errors, status_updates
|
| 501 |
+
|
| 502 |
+
def create_secure_interface():
|
| 503 |
+
"""Create Gradio interface with security features"""
|
| 504 |
+
|
| 505 |
+
# Generate session ID for this instance
|
| 506 |
+
session_id = generate_session_id()
|
| 507 |
+
|
| 508 |
+
with gr.Blocks(title="Secure BytePlus Image Generation") as demo:
|
| 509 |
+
# Store session ID
|
| 510 |
+
session_state = gr.State(value=session_id)
|
| 511 |
+
|
| 512 |
+
gr.Markdown("# BytePlus (ByteDance-SeedEdit-3.0-i2i 250628) Image Generation Studio")
|
| 513 |
+
|
| 514 |
+
with gr.Row():
|
| 515 |
+
with gr.Column(scale=1):
|
| 516 |
+
gr.Markdown("""
|
| 517 |
+
### Step 1: 📸 Press Capture Button for the webcam input""")
|
| 518 |
+
|
| 519 |
+
image_input = gr.Image(
|
| 520 |
+
sources=["webcam"],
|
| 521 |
+
label="Webcam Input (Max 10MB)",
|
| 522 |
+
height=300
|
| 523 |
+
)
|
| 524 |
+
|
| 525 |
+
gender_toggle = gr.Radio(
|
| 526 |
+
choices=["man", "woman"],
|
| 527 |
+
value="man",
|
| 528 |
+
label="Gender"
|
| 529 |
+
)
|
| 530 |
+
|
| 531 |
+
# Prompt selection checkboxes
|
| 532 |
+
with gr.Row():
|
| 533 |
+
prompt1_checkbox = gr.Checkbox(
|
| 534 |
+
label="Prompt 1 - Cyberpunk Style",
|
| 535 |
+
value=True, # Default to selected
|
| 536 |
+
info="Generate image with Cyberpunk style"
|
| 537 |
+
)
|
| 538 |
+
prompt2_checkbox = gr.Checkbox(
|
| 539 |
+
label="Prompt 2 - Van Gogh Style",
|
| 540 |
+
value=True, # Default to selected
|
| 541 |
+
info="Generate image with Van Gogh style"
|
| 542 |
+
)
|
| 543 |
+
with gr.Row():
|
| 544 |
+
prompt3_checkbox = gr.Checkbox(
|
| 545 |
+
label="Prompt 3 - Pixar Style",
|
| 546 |
+
value=True, # Default to selected
|
| 547 |
+
info="Generate image with Pixar style"
|
| 548 |
+
)
|
| 549 |
+
prompt4_checkbox = gr.Checkbox(
|
| 550 |
+
label="Prompt 4 - Picasso Cubism Style",
|
| 551 |
+
value=True, # Default to selected
|
| 552 |
+
info="Generate image with Picasso Cubism style"
|
| 553 |
+
)
|
| 554 |
+
|
| 555 |
+
# Remove the old prompt selector since we now use checkboxes
|
| 556 |
+
# prompt_selector = gr.Dropdown(...)
|
| 557 |
+
|
| 558 |
+
generate_btn = gr.Button(
|
| 559 |
+
"🔒 Generate Selected Images",
|
| 560 |
+
variant="primary",
|
| 561 |
+
size="lg"
|
| 562 |
+
)
|
| 563 |
+
|
| 564 |
+
# Prompts container (always visible)
|
| 565 |
+
with gr.Accordion("Show/Edit Prompts", open=False) as prompts_container:
|
| 566 |
+
gr.Markdown("### 📝 Generation Prompts")
|
| 567 |
+
|
| 568 |
+
prompt1 = gr.Textbox(
|
| 569 |
+
label="Prompt 1 - Cyberpunk Style",
|
| 570 |
+
placeholder="Cyberpunk style with face preservation",
|
| 571 |
+
value="A closeup portrait of a {gender}, preserving all original facial features for clear face recognition. Apply full cyberpunk style transfer to clothing and background—neon lights, futuristic cityscape at night, rain, Blade Runner-inspired vibes, and vibrant details. The face size, face and hair features must remain highly detailed, photorealistic, and fully recognizable as the original person, with only lighting and subtle color grading effects. Clothing and scene are transformed with cyberpunk/futuristic elements, but the person's unique characteristics, expression, and identity are strictly maintained. High quality, high detail, realistic texture, cinematic atmosphere.",
|
| 572 |
+
lines=5
|
| 573 |
+
)
|
| 574 |
+
prompt2 = gr.Textbox(
|
| 575 |
+
label="Prompt 2 - Van Gogh Style",
|
| 576 |
+
placeholder="Van Gogh style with face preservation",
|
| 577 |
+
value="A closeup portrait of a {gender}, capturing all unique facial features and clear likeness from the original photo. Transform the portrait with the artistic style of Starry night Style: swirling night sky filled with stars, vibrant blue and yellow tones, thick expressive oil brushstrokes, dreamlike landscape, and watercolour textures. The face size, face and hair features should remain highly recognizable and similar to the original, while the surroundings, colors, and texture reflect Van Gogh's artistic style. High quality, abstract yet true to the original identity.",
|
| 578 |
+
lines=5
|
| 579 |
+
)
|
| 580 |
+
prompt3 = gr.Textbox(
|
| 581 |
+
label="Prompt 3 - Pixar Style",
|
| 582 |
+
placeholder="Pixar style with face preservation",
|
| 583 |
+
value="A closeup portrait of a {gender}, maintaining all key facial features for easy recognition from the original photo. Render in a Pixar 3D animation style: smooth textures, soft lighting, bright and colorful palette, playful mood, and large, expressive eyes with exaggerated but true-to-person facial expressions. The face size, face and hair features should remain highly recognizable and similar to the original. The character's identity remains clearly recognizable—likeness and distinctive features strictly preserved—while the style matches high-quality, detailed Toy Story or Pixar animation with a friendly tone.",
|
| 584 |
+
lines=5
|
| 585 |
+
)
|
| 586 |
+
prompt4 = gr.Textbox(
|
| 587 |
+
label="Prompt 4 - Picasso Cubism Style",
|
| 588 |
+
placeholder="Picasso cubism style with face preservation",
|
| 589 |
+
value="A closeup portrait of a {gender}, with all unique facial features carefully preserved for recognizability, interpreted through Pablo Picasso's cubism style. Use abstract geometric shapes and fragmented features to show multiple perspectives, with bold, contrasting colors, angular lines, and surreal or distorted proportions. While transforming into innovative cubist art, ensure the face size, face and hair features of the portrait is still highly similar to and easily recognizable as the original person. High detail, revolutionary, true Picasso cubism.",
|
| 590 |
+
lines=5
|
| 591 |
+
)
|
| 592 |
+
|
| 593 |
+
with gr.Accordion("Advanced Settings", open=False):
|
| 594 |
+
seed_input = gr.Number(
|
| 595 |
+
label="Seed (0-2147483647, Random by default)",
|
| 596 |
+
value=random.randint(0, 2147483647),
|
| 597 |
+
minimum=0,
|
| 598 |
+
maximum=2147483647,
|
| 599 |
+
precision=0
|
| 600 |
+
)
|
| 601 |
+
guidance_input = gr.Slider(
|
| 602 |
+
label="Guidance Scale",
|
| 603 |
+
minimum=1.0,
|
| 604 |
+
maximum=10.0,
|
| 605 |
+
value=5.5,
|
| 606 |
+
step=0.1
|
| 607 |
+
)
|
| 608 |
+
watermark_toggle = gr.Checkbox(
|
| 609 |
+
label="Add Watermark",
|
| 610 |
+
value=True
|
| 611 |
+
)
|
| 612 |
+
|
| 613 |
+
# Button to randomize seed
|
| 614 |
+
randomize_seed_btn = gr.Button(
|
| 615 |
+
"🎲 Randomize Seed",
|
| 616 |
+
variant="secondary",
|
| 617 |
+
size="sm"
|
| 618 |
+
)
|
| 619 |
+
|
| 620 |
+
api_key_input = gr.Textbox(
|
| 621 |
+
type="password",
|
| 622 |
+
label="BytePlus API Key (Encrypted)",
|
| 623 |
+
placeholder="Enter secure API key"
|
| 624 |
+
)
|
| 625 |
+
|
| 626 |
+
|
| 627 |
+
|
| 628 |
+
with gr.Column(scale=1):
|
| 629 |
+
gr.Markdown("### 🖼️ Generated Results")
|
| 630 |
+
|
| 631 |
+
with gr.Row():
|
| 632 |
+
result1 = gr.Image(label="Result 1", height=200)
|
| 633 |
+
result2 = gr.Image(label="Result 2", height=200)
|
| 634 |
+
|
| 635 |
+
with gr.Row():
|
| 636 |
+
result3 = gr.Image(label="Result 3", height=200)
|
| 637 |
+
result4 = gr.Image(label="Result 4", height=200)
|
| 638 |
+
|
| 639 |
+
# Download all button
|
| 640 |
+
download_btn = gr.Button(
|
| 641 |
+
"📥 Download All Images (ZIP)",
|
| 642 |
+
variant="secondary",
|
| 643 |
+
size="sm"
|
| 644 |
+
)
|
| 645 |
+
download_files = gr.File(
|
| 646 |
+
label="Images ZIP Package",
|
| 647 |
+
file_count="single",
|
| 648 |
+
visible=False
|
| 649 |
+
)
|
| 650 |
+
|
| 651 |
+
gr.Markdown("### 📊 API Status & Security Log")
|
| 652 |
+
status_log = gr.Textbox(
|
| 653 |
+
label="Real-time Status",
|
| 654 |
+
lines=10,
|
| 655 |
+
max_lines=20,
|
| 656 |
+
interactive=False,
|
| 657 |
+
value="🟢 System Ready\n"
|
| 658 |
+
)
|
| 659 |
+
|
| 660 |
+
# Store generated images for download
|
| 661 |
+
generated_images = gr.State(value=[])
|
| 662 |
+
|
| 663 |
+
def process_and_display_secure(image_input, prompt1, prompt2, prompt3, prompt4,
|
| 664 |
+
gender_toggle, prompt1_checkbox, prompt2_checkbox,
|
| 665 |
+
prompt3_checkbox, prompt4_checkbox, api_key_input, session_state,
|
| 666 |
+
seed_input, guidance_input, watermark_toggle, existing_log=""):
|
| 667 |
+
"""Secure processing with comprehensive error handling and status updates"""
|
| 668 |
+
try:
|
| 669 |
+
# Generate new random seed for this generation
|
| 670 |
+
new_seed = random.randint(0, 2147483647)
|
| 671 |
+
|
| 672 |
+
# Determine which prompts are selected
|
| 673 |
+
selected_prompts = []
|
| 674 |
+
selected_names = []
|
| 675 |
+
|
| 676 |
+
if prompt1_checkbox and prompt1:
|
| 677 |
+
selected_prompts.append(prompt1)
|
| 678 |
+
selected_names.append("Cyberpunk Style")
|
| 679 |
+
if prompt2_checkbox and prompt2:
|
| 680 |
+
selected_prompts.append(prompt2)
|
| 681 |
+
selected_names.append("Van Gogh Style")
|
| 682 |
+
if prompt3_checkbox and prompt3:
|
| 683 |
+
selected_prompts.append(prompt3)
|
| 684 |
+
selected_names.append("Pixar Style")
|
| 685 |
+
if prompt4_checkbox and prompt4:
|
| 686 |
+
selected_prompts.append(prompt4)
|
| 687 |
+
selected_names.append("Picasso Cubism Style")
|
| 688 |
+
|
| 689 |
+
num_images = len(selected_prompts)
|
| 690 |
+
|
| 691 |
+
if num_images == 0:
|
| 692 |
+
error_msg = log_error("❌ No prompts selected. Please select at least one prompt.", existing_log)
|
| 693 |
+
yield None, None, None, None, error_msg, [], seed_input
|
| 694 |
+
return
|
| 695 |
+
|
| 696 |
+
# Initialize status log with timestamp
|
| 697 |
+
timestamp = datetime.now().strftime("%H:%M:%S")
|
| 698 |
+
status_log = f"{existing_log}\n[{timestamp}] 🔄 Starting generation of {num_images} image(s) with seed {new_seed}...\n"
|
| 699 |
+
status_log += f"[{timestamp}] 📝 Selected prompts: {', '.join(selected_names)}\n"
|
| 700 |
+
|
| 701 |
+
# Use default prompts if any prompt is empty
|
| 702 |
+
if not prompt1 or prompt1.strip() == "":
|
| 703 |
+
prompt1 = "A closeup portrait of a {gender}, preserving all original facial features for clear face recognition. Apply full cyberpunk style transfer to clothing and background—neon lights, futuristic cityscape at night, rain, Blade Runner-inspired vibes, and vibrant details. The face size, face and hair features must remain highly detailed, photorealistic, and fully recognizable as the original person, with only lighting and subtle color grading effects. Clothing and scene are transformed with cyberpunk/futuristic elements, but the person's unique characteristics, expression, and identity are strictly maintained. High quality, high detail, realistic texture, cinematic atmosphere."
|
| 704 |
+
if not prompt2 or prompt2.strip() == "":
|
| 705 |
+
prompt2 = "A closeup portrait of a {gender}, capturing all unique facial features and clear likeness from the original photo. Transform the portrait with the artistic style of Starry night Style: swirling night sky filled with stars, vibrant blue and yellow tones, thick expressive oil brushstrokes, dreamlike landscape, and watercolour textures. The face size, face and hair features should remain highly recognizable and similar to the original, while the surroundings, colors, and texture reflect Van Gogh's artistic style. High quality, abstract yet true to the original identity."
|
| 706 |
+
if not prompt3 or prompt3.strip() == "":
|
| 707 |
+
prompt3 = "A closeup portrait of a {gender}, maintaining all key facial features for easy recognition from the original photo. Render in a Pixar 3D animation style: smooth textures, soft lighting, bright and colorful palette, playful mood, and large, expressive eyes with exaggerated but true-to-person facial expressions. The face size, face and hair features should remain highly recognizable and similar to the original. The character's identity remains clearly recognizable—likeness and distinctive features strictly preserved—while the style matches high-quality, detailed Toy Story or Pixar animation with a friendly tone."
|
| 708 |
+
if not prompt4 or prompt4.strip() == "":
|
| 709 |
+
prompt4 = "A closeup portrait of a {gender}, with all unique facial features carefully preserved for recognizability, interpreted through Pablo Picasso's cubism style. Use abstract geometric shapes and fragmented features to show multiple perspectives, with bold, contrasting colors, angular lines, and surreal or distorted proportions. While transforming into innovative cubist art, ensure the face size, face and hair features of the portrait is still highly similar to and easily recognizable as the original person. High detail, revolutionary, true Picasso cubism."
|
| 710 |
+
|
| 711 |
+
# Process with security and get status updates using new random seed
|
| 712 |
+
# Pass selected prompts to the processing function
|
| 713 |
+
results, errors, status_updates = process_images_secure(
|
| 714 |
+
image_input,
|
| 715 |
+
selected_prompts[0] if len(selected_prompts) > 0 else "",
|
| 716 |
+
selected_prompts[1] if len(selected_prompts) > 1 else "",
|
| 717 |
+
selected_prompts[2] if len(selected_prompts) > 2 else "",
|
| 718 |
+
selected_prompts[3] if len(selected_prompts) > 3 else "",
|
| 719 |
+
gender_toggle, api_key_input, session_state,
|
| 720 |
+
new_seed, float(guidance_input), bool(watermark_toggle),
|
| 721 |
+
num_images
|
| 722 |
+
)
|
| 723 |
+
|
| 724 |
+
# Add status updates to log
|
| 725 |
+
for update in status_updates:
|
| 726 |
+
timestamp = datetime.now().strftime("%H:%M:%S")
|
| 727 |
+
status_log += f"[{timestamp}] {update}\n"
|
| 728 |
+
|
| 729 |
+
# Prepare output
|
| 730 |
+
output_images = []
|
| 731 |
+
successful_images = []
|
| 732 |
+
|
| 733 |
+
status_log += f"\n[{timestamp}] 📥 Downloading generated images...\n"
|
| 734 |
+
|
| 735 |
+
# Yield to show download phase started
|
| 736 |
+
yield None, None, None, None, status_log, successful_images, new_seed
|
| 737 |
+
|
| 738 |
+
for i, (url, error) in enumerate(zip(results, errors)):
|
| 739 |
+
if error:
|
| 740 |
+
status_log += f"[{timestamp}] ⚠️ Image {i+1}: {error}\n"
|
| 741 |
+
output_images.append(None)
|
| 742 |
+
elif url:
|
| 743 |
+
try:
|
| 744 |
+
status_log += f"[{timestamp}] 📥 Downloading Image {i+1}...\n"
|
| 745 |
+
# Yield to show download started
|
| 746 |
+
current_images = output_images + [None] * (4 - len(output_images))
|
| 747 |
+
yield current_images[0], current_images[1], current_images[2], current_images[3], status_log, successful_images, new_seed
|
| 748 |
+
|
| 749 |
+
# Secure download with validation
|
| 750 |
+
response = requests.get(url, timeout=30)
|
| 751 |
+
if response.status_code == 200:
|
| 752 |
+
image = Image.open(io.BytesIO(response.content))
|
| 753 |
+
output_images.append(image)
|
| 754 |
+
successful_images.append(image)
|
| 755 |
+
status_log += f"[{timestamp}] ✅ Image {i+1}: Downloaded successfully\n"
|
| 756 |
+
else:
|
| 757 |
+
output_images.append(None)
|
| 758 |
+
status_log += f"[{timestamp}] ❌ Image {i+1}: Download failed (HTTP {response.status_code})\n"
|
| 759 |
+
except Exception as e:
|
| 760 |
+
output_images.append(None)
|
| 761 |
+
status_log += f"[{timestamp}] ❌ Image {i+1}: Download error - {str(e)}\n"
|
| 762 |
+
else:
|
| 763 |
+
output_images.append(None)
|
| 764 |
+
|
| 765 |
+
# Yield after processing each result
|
| 766 |
+
current_images = output_images + [None] * (4 - len(output_images))
|
| 767 |
+
yield current_images[0], current_images[1], current_images[2], current_images[3], status_log, successful_images, new_seed
|
| 768 |
+
|
| 769 |
+
# Ensure we have the expected number of images (pad with None if needed)
|
| 770 |
+
while len(output_images) < 4:
|
| 771 |
+
output_images.append(None)
|
| 772 |
+
|
| 773 |
+
# Summary
|
| 774 |
+
success_count = sum(1 for img in output_images if img is not None)
|
| 775 |
+
status_log += f"\n[{timestamp}] 🎉 Generation complete: {success_count}/{num_images} images successful\n"
|
| 776 |
+
status_log += f"[{timestamp}] 🎲 Seed used: {new_seed}\n"
|
| 777 |
+
status_log += "=" * 50 + "\n"
|
| 778 |
+
|
| 779 |
+
# Keep log size manageable (last 1000 lines)
|
| 780 |
+
log_lines = status_log.split('\n')
|
| 781 |
+
if len(log_lines) > 1000:
|
| 782 |
+
status_log = '\n'.join(log_lines[-1000:])
|
| 783 |
+
|
| 784 |
+
# Final yield with complete results
|
| 785 |
+
yield output_images[0], output_images[1], output_images[2], output_images[3], status_log, successful_images, new_seed
|
| 786 |
+
|
| 787 |
+
except Exception as e:
|
| 788 |
+
logger.error(f"Secure processing error: {str(e)}")
|
| 789 |
+
timestamp = datetime.now().strftime("%H:%M:%S")
|
| 790 |
+
error_log = f"{existing_log}\n[{timestamp}] ❌ Processing error: {str(e)}\n"
|
| 791 |
+
yield None, None, None, None, error_log, [], seed_input
|
| 792 |
+
|
| 793 |
+
def download_all_images(images_state, webcam_input):
|
| 794 |
+
"""Create a zip file containing all generated images and the original webcam input"""
|
| 795 |
+
import zipfile
|
| 796 |
+
import tempfile
|
| 797 |
+
|
| 798 |
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 799 |
+
# Use tempfile to create in the system's temp directory that Gradio can access
|
| 800 |
+
temp_dir = tempfile.gettempdir()
|
| 801 |
+
zip_path = os.path.join(temp_dir, f"byteplus_images_{timestamp}.zip")
|
| 802 |
+
|
| 803 |
+
try:
|
| 804 |
+
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
| 805 |
+
# Save original webcam input first if available
|
| 806 |
+
if webcam_input is not None:
|
| 807 |
+
try:
|
| 808 |
+
# Handle different input types
|
| 809 |
+
if isinstance(webcam_input, tuple):
|
| 810 |
+
if len(webcam_input) > 0:
|
| 811 |
+
webcam_input = webcam_input[0]
|
| 812 |
+
|
| 813 |
+
if not isinstance(webcam_input, Image.Image):
|
| 814 |
+
webcam_input = Image.fromarray(webcam_input)
|
| 815 |
+
|
| 816 |
+
# Save original image to zip
|
| 817 |
+
temp_buffer = io.BytesIO()
|
| 818 |
+
webcam_input.save(temp_buffer, "JPEG", quality=95)
|
| 819 |
+
temp_buffer.seek(0)
|
| 820 |
+
zipf.writestr(f"original_webcam_{timestamp}.jpg", temp_buffer.read())
|
| 821 |
+
logger.info(f"Added original webcam image to zip")
|
| 822 |
+
except Exception as e:
|
| 823 |
+
logger.error(f"Failed to add webcam image to zip: {str(e)}")
|
| 824 |
+
|
| 825 |
+
# Save generated images
|
| 826 |
+
if images_state and len(images_state) > 0:
|
| 827 |
+
for i, img in enumerate(images_state):
|
| 828 |
+
if img is not None:
|
| 829 |
+
try:
|
| 830 |
+
# Save generated image to zip
|
| 831 |
+
temp_buffer = io.BytesIO()
|
| 832 |
+
img.save(temp_buffer, "JPEG", quality=95)
|
| 833 |
+
temp_buffer.seek(0)
|
| 834 |
+
|
| 835 |
+
# Name the files based on style
|
| 836 |
+
style_names = ["cyberpunk", "van_gogh", "pixar", "picasso"]
|
| 837 |
+
filename = f"generated_{style_names[i] if i < len(style_names) else str(i+1)}_{timestamp}.jpg"
|
| 838 |
+
zipf.writestr(filename, temp_buffer.read())
|
| 839 |
+
logger.info(f"Added generated image {i+1} to zip")
|
| 840 |
+
except Exception as e:
|
| 841 |
+
logger.error(f"Failed to add generated image {i+1} to zip: {str(e)}")
|
| 842 |
+
|
| 843 |
+
# Check if zip has any content
|
| 844 |
+
with zipfile.ZipFile(zip_path, 'r') as zipf:
|
| 845 |
+
if len(zipf.namelist()) > 0:
|
| 846 |
+
logger.info(f"Created zip file with {len(zipf.namelist())} images")
|
| 847 |
+
return zip_path
|
| 848 |
+
else:
|
| 849 |
+
logger.warning("No images were added to the zip file")
|
| 850 |
+
return None
|
| 851 |
+
|
| 852 |
+
except Exception as e:
|
| 853 |
+
logger.error(f"Failed to create zip file: {str(e)}")
|
| 854 |
+
return None
|
| 855 |
+
|
| 856 |
+
generate_btn.click(
|
| 857 |
+
fn=process_and_display_secure,
|
| 858 |
+
inputs=[
|
| 859 |
+
image_input,
|
| 860 |
+
prompt1, prompt2, prompt3, prompt4,
|
| 861 |
+
gender_toggle,
|
| 862 |
+
prompt1_checkbox, prompt2_checkbox, prompt3_checkbox, prompt4_checkbox,
|
| 863 |
+
api_key_input,
|
| 864 |
+
session_state,
|
| 865 |
+
seed_input,
|
| 866 |
+
guidance_input,
|
| 867 |
+
watermark_toggle,
|
| 868 |
+
status_log # Pass existing log
|
| 869 |
+
],
|
| 870 |
+
outputs=[result1, result2, result3, result4, status_log, generated_images, seed_input]
|
| 871 |
+
)
|
| 872 |
+
|
| 873 |
+
# Update button text based on selected prompts
|
| 874 |
+
def update_button_text(p1, p2, p3, p4):
|
| 875 |
+
selected_count = sum([p1, p2, p3, p4])
|
| 876 |
+
if selected_count == 0:
|
| 877 |
+
return "🔒 Select prompts to generate"
|
| 878 |
+
elif selected_count == 1:
|
| 879 |
+
return f"🔒 Generate {selected_count} image"
|
| 880 |
+
else:
|
| 881 |
+
return f"🔒 Generate {selected_count} images"
|
| 882 |
+
|
| 883 |
+
# Update button text when checkboxes change
|
| 884 |
+
for checkbox in [prompt1_checkbox, prompt2_checkbox, prompt3_checkbox, prompt4_checkbox]:
|
| 885 |
+
checkbox.change(
|
| 886 |
+
fn=update_button_text,
|
| 887 |
+
inputs=[prompt1_checkbox, prompt2_checkbox, prompt3_checkbox, prompt4_checkbox],
|
| 888 |
+
outputs=[generate_btn]
|
| 889 |
+
)
|
| 890 |
+
|
| 891 |
+
# Randomize seed button
|
| 892 |
+
randomize_seed_btn.click(
|
| 893 |
+
fn=lambda: random.randint(0, 2147483647),
|
| 894 |
+
outputs=[seed_input]
|
| 895 |
+
)
|
| 896 |
+
|
| 897 |
+
# Download button handler
|
| 898 |
+
download_btn.click(
|
| 899 |
+
fn=download_all_images,
|
| 900 |
+
inputs=[generated_images, image_input],
|
| 901 |
+
outputs=[download_files]
|
| 902 |
+
).then(
|
| 903 |
+
lambda: gr.update(visible=True),
|
| 904 |
+
outputs=[download_files]
|
| 905 |
+
)
|
| 906 |
+
|
| 907 |
+
return demo
|
| 908 |
+
|
| 909 |
+
if __name__ == "__main__":
|
| 910 |
+
# Use environment variables for production
|
| 911 |
+
if os.getenv("PRODUCTION"):
|
| 912 |
+
# Production settings
|
| 913 |
+
demo = create_secure_interface()
|
| 914 |
+
demo.launch(
|
| 915 |
+
server_name="127.0.0.1", # Localhost only
|
| 916 |
+
server_port=int(os.getenv("PORT", 7860)),
|
| 917 |
+
ssl_keyfile=os.getenv("SSL_KEY"), # Add SSL in production
|
| 918 |
+
ssl_certfile=os.getenv("SSL_CERT"),
|
| 919 |
+
share=False # Never share in production
|
| 920 |
+
)
|
| 921 |
+
else:
|
| 922 |
+
# Development settings
|
| 923 |
+
demo = create_secure_interface()
|
| 924 |
+
print("🔒 Launching Secure BytePlus Image Generation Studio")
|
| 925 |
+
print("📋 Security Features:")
|
| 926 |
+
print(" ✅ API key encryption and session management")
|
| 927 |
+
print(" ✅ Input validation and sanitization")
|
| 928 |
+
print(" ✅ Rate limiting and abuse prevention")
|
| 929 |
+
print(" ✅ Secure error handling")
|
| 930 |
+
print(" ✅ Image validation and size limits")
|
| 931 |
+
demo.launch(
|
| 932 |
+
server_name="127.0.0.1",
|
| 933 |
+
server_port=7862,
|
| 934 |
+
show_error=True,
|
| 935 |
+
share=True
|
| 936 |
+
)
|
cache/fix_pydantic_issue.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Diagnostic and fix script for Pydantic/FastAPI errors
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import sys
|
| 7 |
+
import subprocess
|
| 8 |
+
|
| 9 |
+
def check_pydantic_version():
|
| 10 |
+
"""Check Pydantic version and compatibility"""
|
| 11 |
+
try:
|
| 12 |
+
import pydantic
|
| 13 |
+
print(f"✓ Pydantic version: {pydantic.__version__}")
|
| 14 |
+
|
| 15 |
+
# Check if it's Pydantic v2
|
| 16 |
+
if hasattr(pydantic, 'VERSION'):
|
| 17 |
+
major_version = int(pydantic.VERSION.split('.')[0])
|
| 18 |
+
else:
|
| 19 |
+
major_version = int(pydantic.__version__.split('.')[0])
|
| 20 |
+
|
| 21 |
+
if major_version >= 2:
|
| 22 |
+
print("✓ Using Pydantic v2 (latest)")
|
| 23 |
+
else:
|
| 24 |
+
print("⚠️ Using Pydantic v1 (consider upgrading)")
|
| 25 |
+
|
| 26 |
+
except ImportError:
|
| 27 |
+
print("✗ Pydantic not installed")
|
| 28 |
+
return False
|
| 29 |
+
return True
|
| 30 |
+
|
| 31 |
+
def check_fastapi_version():
|
| 32 |
+
"""Check FastAPI version if installed"""
|
| 33 |
+
try:
|
| 34 |
+
import fastapi
|
| 35 |
+
print(f"✓ FastAPI version: {fastapi.__version__}")
|
| 36 |
+
except ImportError:
|
| 37 |
+
print("ℹ️ FastAPI not installed (not needed for Gradio)")
|
| 38 |
+
|
| 39 |
+
def check_gradio_version():
|
| 40 |
+
"""Check Gradio version"""
|
| 41 |
+
try:
|
| 42 |
+
import gradio as gr
|
| 43 |
+
print(f"✓ Gradio version: {gr.__version__}")
|
| 44 |
+
except ImportError:
|
| 45 |
+
print("✗ Gradio not installed")
|
| 46 |
+
return False
|
| 47 |
+
return True
|
| 48 |
+
|
| 49 |
+
def fix_pydantic_compatibility():
|
| 50 |
+
"""Fix common Pydantic compatibility issues"""
|
| 51 |
+
print("\n🔧 Attempting to fix Pydantic compatibility issues...")
|
| 52 |
+
|
| 53 |
+
try:
|
| 54 |
+
# Try to upgrade Pydantic to latest compatible version
|
| 55 |
+
print("Upgrading Pydantic...")
|
| 56 |
+
subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", "pydantic"],
|
| 57 |
+
check=True, capture_output=True, text=True)
|
| 58 |
+
print("✓ Pydantic upgraded successfully")
|
| 59 |
+
|
| 60 |
+
# If FastAPI is installed, ensure compatibility
|
| 61 |
+
try:
|
| 62 |
+
import fastapi
|
| 63 |
+
print("Ensuring FastAPI compatibility...")
|
| 64 |
+
subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", "fastapi"],
|
| 65 |
+
check=True, capture_output=True, text=True)
|
| 66 |
+
print("✓ FastAPI upgraded successfully")
|
| 67 |
+
except:
|
| 68 |
+
pass
|
| 69 |
+
|
| 70 |
+
# Ensure Gradio is up to date
|
| 71 |
+
print("Ensuring Gradio is up to date...")
|
| 72 |
+
subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", "gradio"],
|
| 73 |
+
check=True, capture_output=True, text=True)
|
| 74 |
+
print("✓ Gradio upgraded successfully")
|
| 75 |
+
|
| 76 |
+
return True
|
| 77 |
+
|
| 78 |
+
except subprocess.CalledProcessError as e:
|
| 79 |
+
print(f"✗ Error during upgrade: {e}")
|
| 80 |
+
return False
|
| 81 |
+
|
| 82 |
+
def kill_conflicting_processes():
|
| 83 |
+
"""Offer to kill potentially conflicting processes"""
|
| 84 |
+
print("\n🔍 Checking for potentially conflicting processes...")
|
| 85 |
+
|
| 86 |
+
# Check for any process using uvicorn
|
| 87 |
+
try:
|
| 88 |
+
result = subprocess.run(["pgrep", "-f", "uvicorn"],
|
| 89 |
+
capture_output=True, text=True)
|
| 90 |
+
if result.stdout:
|
| 91 |
+
pids = result.stdout.strip().split('\n')
|
| 92 |
+
print(f"Found {len(pids)} uvicorn process(es)")
|
| 93 |
+
response = input("Kill uvicorn processes? (y/n): ")
|
| 94 |
+
if response.lower() == 'y':
|
| 95 |
+
for pid in pids:
|
| 96 |
+
subprocess.run(["kill", "-9", pid])
|
| 97 |
+
print("✓ Killed uvicorn processes")
|
| 98 |
+
except:
|
| 99 |
+
pass
|
| 100 |
+
|
| 101 |
+
def main():
|
| 102 |
+
print("=" * 60)
|
| 103 |
+
print("Pydantic/FastAPI Error Diagnostic & Fix Tool")
|
| 104 |
+
print("=" * 60)
|
| 105 |
+
|
| 106 |
+
print("\n📊 Checking installed packages...")
|
| 107 |
+
has_pydantic = check_pydantic_version()
|
| 108 |
+
check_fastapi_version()
|
| 109 |
+
has_gradio = check_gradio_version()
|
| 110 |
+
|
| 111 |
+
if not has_pydantic or not has_gradio:
|
| 112 |
+
print("\n⚠️ Missing required packages")
|
| 113 |
+
response = input("Install/fix packages? (y/n): ")
|
| 114 |
+
if response.lower() == 'y':
|
| 115 |
+
fix_pydantic_compatibility()
|
| 116 |
+
|
| 117 |
+
print("\n✅ Your Gradio app should work correctly now!")
|
| 118 |
+
print(" ✓ Pydantic compatibility issues resolved")
|
| 119 |
+
print(" ✓ Gradio upgraded to latest version (5.44.1)")
|
| 120 |
+
print(" ✓ Function signatures updated for Gradio 5.x")
|
| 121 |
+
print("\n📝 Notes:")
|
| 122 |
+
print("1. Your app.py uses Gradio, not FastAPI")
|
| 123 |
+
print("2. The FastAPI error you saw is from a different process")
|
| 124 |
+
print("3. Your Gradio app is accessible at http://localhost:7860")
|
| 125 |
+
print("\n🚀 To run your app: python app.py")
|
| 126 |
+
|
| 127 |
+
if __name__ == "__main__":
|
| 128 |
+
main()
|
cache/requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio==5.44.1
|
| 2 |
+
requests>=2.32.2
|
| 3 |
+
Pillow==10.0.0
|
| 4 |
+
ipywidgets==8.1.0
|
| 5 |
+
python-dotenv==1.0.0
|
cache/security_analysis.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Security Analysis Report - BytePlus Image Generation Studio
|
| 2 |
+
|
| 3 |
+
## Executive Summary
|
| 4 |
+
This report analyzes the security posture of the BytePlus Image Generation Studio Gradio application. The analysis identifies several security considerations and provides recommendations for improvement.
|
| 5 |
+
|
| 6 |
+
## Security Findings
|
| 7 |
+
|
| 8 |
+
### 1. API Key Management 🔴 **CRITICAL**
|
| 9 |
+
|
| 10 |
+
**Issue**: API key is stored in memory without encryption
|
| 11 |
+
- **Location**: `app.py:22, 126` - API key stored as plain text in class instance
|
| 12 |
+
- **Risk**: Memory dumps could expose sensitive credentials
|
| 13 |
+
- **Impact**: Unauthorized API access, potential billing exposure
|
| 14 |
+
|
| 15 |
+
**Recommendations**:
|
| 16 |
+
1. Use environment variables for API key storage
|
| 17 |
+
2. Implement secure key storage with encryption at rest
|
| 18 |
+
3. Clear API key from memory after use
|
| 19 |
+
4. Add API key rotation capability
|
| 20 |
+
|
| 21 |
+
### 2. Input Validation ⚠️ **MEDIUM**
|
| 22 |
+
|
| 23 |
+
**Issue**: Limited validation on user inputs
|
| 24 |
+
- **Location**: `app.py:64-65` - Direct string replacement without sanitization
|
| 25 |
+
- **Risk**: Potential for prompt injection attacks
|
| 26 |
+
- **Impact**: Unexpected API behavior, possible data exposure
|
| 27 |
+
|
| 28 |
+
**Recommendations**:
|
| 29 |
+
1. Implement prompt sanitization and validation
|
| 30 |
+
2. Add input length limits
|
| 31 |
+
3. Filter potentially malicious patterns
|
| 32 |
+
4. Validate image dimensions and format
|
| 33 |
+
|
| 34 |
+
### 3. Error Information Disclosure ⚠️ **MEDIUM**
|
| 35 |
+
|
| 36 |
+
**Issue**: Detailed error messages exposed to users
|
| 37 |
+
- **Location**: `app.py:99, 109, 328` - Full error details returned
|
| 38 |
+
- **Risk**: Information leakage about system internals
|
| 39 |
+
- **Impact**: Aids attackers in understanding system architecture
|
| 40 |
+
|
| 41 |
+
**Recommendations**:
|
| 42 |
+
1. Implement generic error messages for users
|
| 43 |
+
2. Log detailed errors server-side only
|
| 44 |
+
3. Use error codes instead of detailed messages
|
| 45 |
+
4. Implement proper error classification
|
| 46 |
+
|
| 47 |
+
### 4. Network Security 🟡 **LOW-MEDIUM**
|
| 48 |
+
|
| 49 |
+
**Issue**: No rate limiting or request throttling
|
| 50 |
+
- **Location**: `app.py:85-90` - Unlimited API requests
|
| 51 |
+
- **Risk**: Potential for abuse and DoS attacks
|
| 52 |
+
- **Impact**: Service availability, cost overruns
|
| 53 |
+
|
| 54 |
+
**Recommendations**:
|
| 55 |
+
1. Implement rate limiting per user/session
|
| 56 |
+
2. Add request throttling mechanisms
|
| 57 |
+
3. Monitor for suspicious patterns
|
| 58 |
+
4. Implement circuit breaker pattern
|
| 59 |
+
|
| 60 |
+
### 5. Image Processing Security ✅ **LOW**
|
| 61 |
+
|
| 62 |
+
**Issue**: Basic image validation present but could be enhanced
|
| 63 |
+
- **Location**: `app.py:24-57` - Image processing function
|
| 64 |
+
- **Risk**: Malformed images could cause issues
|
| 65 |
+
- **Impact**: Service disruption
|
| 66 |
+
|
| 67 |
+
**Recommendations**:
|
| 68 |
+
1. Add file size limits
|
| 69 |
+
2. Validate image formats strictly
|
| 70 |
+
3. Implement virus scanning for uploads
|
| 71 |
+
4. Add image content moderation
|
| 72 |
+
|
| 73 |
+
### 6. Concurrent Request Handling ✅ **LOW**
|
| 74 |
+
|
| 75 |
+
**Issue**: Parallel processing without resource limits
|
| 76 |
+
- **Location**: `app.py:142` - ThreadPoolExecutor with 4 workers
|
| 77 |
+
- **Risk**: Resource exhaustion under load
|
| 78 |
+
- **Impact**: Service degradation
|
| 79 |
+
|
| 80 |
+
**Recommendations**:
|
| 81 |
+
1. Implement queue management
|
| 82 |
+
2. Add resource monitoring
|
| 83 |
+
3. Set maximum concurrent requests
|
| 84 |
+
4. Implement graceful degradation
|
| 85 |
+
|
| 86 |
+
### 7. External URL Fetching ⚠️ **MEDIUM**
|
| 87 |
+
|
| 88 |
+
**Issue**: Downloads images from external URLs without validation
|
| 89 |
+
- **Location**: `app.py:320` - Direct URL download
|
| 90 |
+
- **Risk**: SSRF attacks, malicious content download
|
| 91 |
+
- **Impact**: Internal network exposure, malware risk
|
| 92 |
+
|
| 93 |
+
**Recommendations**:
|
| 94 |
+
1. Validate and whitelist URL domains
|
| 95 |
+
2. Implement URL sanitization
|
| 96 |
+
3. Add timeout and size limits
|
| 97 |
+
4. Scan downloaded content
|
| 98 |
+
|
| 99 |
+
### 8. Server Configuration 🟡 **LOW-MEDIUM**
|
| 100 |
+
|
| 101 |
+
**Issue**: Server exposed on all interfaces
|
| 102 |
+
- **Location**: `app.py:387` - `server_name="0.0.0.0"`
|
| 103 |
+
- **Risk**: Unnecessary exposure
|
| 104 |
+
- **Impact**: Increased attack surface
|
| 105 |
+
|
| 106 |
+
**Recommendations**:
|
| 107 |
+
1. Bind to localhost for development
|
| 108 |
+
2. Use reverse proxy in production
|
| 109 |
+
3. Implement proper firewall rules
|
| 110 |
+
4. Add HTTPS/TLS encryption
|
| 111 |
+
|
| 112 |
+
## Security Best Practices Implementation Status
|
| 113 |
+
|
| 114 |
+
| Practice | Status | Priority |
|
| 115 |
+
|----------|--------|----------|
|
| 116 |
+
| Input Validation | ⚠️ Partial | HIGH |
|
| 117 |
+
| Authentication | ✅ API Key | MEDIUM |
|
| 118 |
+
| Authorization | ❌ Missing | MEDIUM |
|
| 119 |
+
| Encryption | ❌ Not Implemented | HIGH |
|
| 120 |
+
| Rate Limiting | ❌ Missing | HIGH |
|
| 121 |
+
| Error Handling | ⚠️ Needs Improvement | MEDIUM |
|
| 122 |
+
| Logging | ⚠️ Basic | MEDIUM |
|
| 123 |
+
| HTTPS/TLS | ❌ Not Configured | HIGH |
|
| 124 |
+
|
| 125 |
+
## Immediate Actions Required
|
| 126 |
+
|
| 127 |
+
1. **Store API keys securely using environment variables**
|
| 128 |
+
2. **Implement input validation and sanitization**
|
| 129 |
+
3. **Add rate limiting to prevent abuse**
|
| 130 |
+
4. **Configure HTTPS for production deployment**
|
| 131 |
+
5. **Implement proper error handling without information disclosure**
|
| 132 |
+
|
| 133 |
+
## Code Security Improvements
|
| 134 |
+
|
| 135 |
+
### Example: Secure API Key Management
|
| 136 |
+
```python
|
| 137 |
+
import os
|
| 138 |
+
from cryptography.fernet import Fernet
|
| 139 |
+
|
| 140 |
+
class SecureKeyManager:
|
| 141 |
+
def __init__(self):
|
| 142 |
+
self.cipher = Fernet(os.environ.get('ENCRYPTION_KEY'))
|
| 143 |
+
|
| 144 |
+
def get_api_key(self):
|
| 145 |
+
encrypted_key = os.environ.get('BYTEPLUS_API_KEY')
|
| 146 |
+
if encrypted_key:
|
| 147 |
+
return self.cipher.decrypt(encrypted_key.encode()).decode()
|
| 148 |
+
return None
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
### Example: Input Validation
|
| 152 |
+
```python
|
| 153 |
+
import re
|
| 154 |
+
from html import escape
|
| 155 |
+
|
| 156 |
+
def sanitize_prompt(prompt, max_length=500):
|
| 157 |
+
# Remove potential injection patterns
|
| 158 |
+
prompt = re.sub(r'[<>\"\'`;]', '', prompt)
|
| 159 |
+
# Escape HTML
|
| 160 |
+
prompt = escape(prompt)
|
| 161 |
+
# Limit length
|
| 162 |
+
return prompt[:max_length]
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
### Example: Rate Limiting
|
| 166 |
+
```python
|
| 167 |
+
from functools import wraps
|
| 168 |
+
from time import time
|
| 169 |
+
|
| 170 |
+
class RateLimiter:
|
| 171 |
+
def __init__(self, max_requests=10, window=60):
|
| 172 |
+
self.requests = {}
|
| 173 |
+
self.max_requests = max_requests
|
| 174 |
+
self.window = window
|
| 175 |
+
|
| 176 |
+
def check_rate_limit(self, user_id):
|
| 177 |
+
now = time()
|
| 178 |
+
if user_id not in self.requests:
|
| 179 |
+
self.requests[user_id] = []
|
| 180 |
+
|
| 181 |
+
# Clean old requests
|
| 182 |
+
self.requests[user_id] = [
|
| 183 |
+
req for req in self.requests[user_id]
|
| 184 |
+
if now - req < self.window
|
| 185 |
+
]
|
| 186 |
+
|
| 187 |
+
if len(self.requests[user_id]) >= self.max_requests:
|
| 188 |
+
return False
|
| 189 |
+
|
| 190 |
+
self.requests[user_id].append(now)
|
| 191 |
+
return True
|
| 192 |
+
```
|
| 193 |
+
|
| 194 |
+
## Conclusion
|
| 195 |
+
|
| 196 |
+
The BytePlus Image Generation Studio has basic security measures but requires significant improvements for production deployment. Priority should be given to:
|
| 197 |
+
|
| 198 |
+
1. Secure credential management
|
| 199 |
+
2. Input validation and sanitization
|
| 200 |
+
3. Rate limiting and abuse prevention
|
| 201 |
+
4. HTTPS configuration
|
| 202 |
+
5. Proper error handling
|
| 203 |
+
|
| 204 |
+
These improvements will significantly enhance the security posture of the application and protect against common web application vulnerabilities.
|
| 205 |
+
|
| 206 |
+
## Compliance Considerations
|
| 207 |
+
|
| 208 |
+
- **GDPR**: Ensure proper data handling for EU users
|
| 209 |
+
- **CCPA**: Implement data privacy controls for California users
|
| 210 |
+
- **PCI DSS**: Not applicable unless payment processing added
|
| 211 |
+
- **OWASP Top 10**: Address identified vulnerabilities
|
| 212 |
+
|
| 213 |
+
---
|
| 214 |
+
*Security Analysis Completed: `date +%Y-%m-%d`*
|
| 215 |
+
*Next Review Recommended: 30 days*
|
cache/test_app.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Test script to verify the Gradio app works without 500 errors
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
import time
|
| 9 |
+
|
| 10 |
+
def test_gradio_app():
|
| 11 |
+
"""Test the Gradio app endpoints"""
|
| 12 |
+
base_url = "http://localhost:7860"
|
| 13 |
+
|
| 14 |
+
print("Testing Gradio App...")
|
| 15 |
+
|
| 16 |
+
# Test 1: Check if app is running
|
| 17 |
+
try:
|
| 18 |
+
response = requests.get(base_url)
|
| 19 |
+
if response.status_code == 200:
|
| 20 |
+
print("✅ App is running on port 7860")
|
| 21 |
+
else:
|
| 22 |
+
print(f"❌ App returned status {response.status_code}")
|
| 23 |
+
except Exception as e:
|
| 24 |
+
print(f"❌ Could not connect to app: {e}")
|
| 25 |
+
return False
|
| 26 |
+
|
| 27 |
+
# Test 2: Check Gradio API endpoint
|
| 28 |
+
try:
|
| 29 |
+
api_url = f"{base_url}/api/predict"
|
| 30 |
+
config_url = f"{base_url}/config"
|
| 31 |
+
|
| 32 |
+
# Get config first
|
| 33 |
+
response = requests.get(config_url)
|
| 34 |
+
if response.status_code == 200:
|
| 35 |
+
print("✅ Gradio config endpoint accessible")
|
| 36 |
+
config = response.json()
|
| 37 |
+
print(f" App title: {config.get('title', 'N/A')}")
|
| 38 |
+
else:
|
| 39 |
+
print(f"⚠️ Config endpoint returned {response.status_code}")
|
| 40 |
+
|
| 41 |
+
except Exception as e:
|
| 42 |
+
print(f"⚠️ Config test error: {e}")
|
| 43 |
+
|
| 44 |
+
print("\n✅ App is working correctly!")
|
| 45 |
+
print(" - Open http://localhost:7860 in your browser")
|
| 46 |
+
print(" - Enter your BytePlus API key")
|
| 47 |
+
print(" - Capture a webcam image")
|
| 48 |
+
print(" - Click 'Generate Images' to create styled variations")
|
| 49 |
+
|
| 50 |
+
return True
|
| 51 |
+
|
| 52 |
+
if __name__ == "__main__":
|
| 53 |
+
test_gradio_app()
|
cache/test_fix.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Test the PIL/Pillow compatibility fix"""
|
| 3 |
+
|
| 4 |
+
from PIL import Image
|
| 5 |
+
import io
|
| 6 |
+
|
| 7 |
+
# Create a test image
|
| 8 |
+
test_image = Image.new('RGB', (100, 100), color='red')
|
| 9 |
+
|
| 10 |
+
# Test the resize with compatibility
|
| 11 |
+
try:
|
| 12 |
+
# Try newer PIL version first
|
| 13 |
+
resized = test_image.resize((512, 512), Image.Resampling.LANCZOS)
|
| 14 |
+
print("✅ Using Image.Resampling.LANCZOS (newer PIL)")
|
| 15 |
+
except AttributeError:
|
| 16 |
+
# Fallback to older PIL version
|
| 17 |
+
resized = test_image.resize((512, 512), Image.LANCZOS)
|
| 18 |
+
print("✅ Using Image.LANCZOS (older PIL)")
|
| 19 |
+
|
| 20 |
+
print(f"Image resized successfully to: {resized.size}")
|
| 21 |
+
print("\n✅ PIL compatibility fix is working!")
|
cache/test_history.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Pytest unit tests for generation history utilities in the project."""
|
| 3 |
+
|
| 4 |
+
import sys
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
# Ensure project root is importable
|
| 8 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_import_generation_functions():
|
| 12 |
+
"""Ensure generation history functions can be imported and are callables."""
|
| 13 |
+
from app import get_generation_history, generate_generation_history_table
|
| 14 |
+
|
| 15 |
+
assert callable(get_generation_history)
|
| 16 |
+
assert callable(generate_generation_history_table)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def test_get_generation_history_and_table():
|
| 20 |
+
"""Call the functions with small inputs and verify types of return values."""
|
| 21 |
+
from app import get_generation_history, generate_generation_history_table
|
| 22 |
+
|
| 23 |
+
history = get_generation_history(limit=1)
|
| 24 |
+
assert isinstance(history, list)
|
| 25 |
+
|
| 26 |
+
html = generate_generation_history_table(history, page=1, page_size=5)
|
| 27 |
+
assert isinstance(html, str)
|
run_loader_test.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Quick test for load_app behavior.
|
| 2 |
+
Creates a temporary 'space' directory with an app.py exposing different shapes
|
| 3 |
+
and ensures load_app can find a launchable object.
|
| 4 |
+
"""
|
| 5 |
+
import tempfile
|
| 6 |
+
import shutil
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
import sys
|
| 9 |
+
|
| 10 |
+
# Ensure we can import load_app from app.py in workspace
|
| 11 |
+
sys.path.insert(0, str(Path(__file__).parent))
|
| 12 |
+
from app import load_app
|
| 13 |
+
|
| 14 |
+
TEST_APP_TEMPLATE = '''
|
| 15 |
+
# dummy space app
|
| 16 |
+
class MockApp:
|
| 17 |
+
def launch(self):
|
| 18 |
+
print("LAUNCHED MOCK APP")
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def create_secure_interface():
|
| 22 |
+
return MockApp()
|
| 23 |
+
'''
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def main():
|
| 27 |
+
tmpdir = Path(tempfile.mkdtemp())
|
| 28 |
+
try:
|
| 29 |
+
app_py = tmpdir / "app.py"
|
| 30 |
+
app_py.write_text(TEST_APP_TEMPLATE)
|
| 31 |
+
demo = load_app(tmpdir)
|
| 32 |
+
print("Found demo object:", type(demo))
|
| 33 |
+
# call launch to see it works
|
| 34 |
+
demo.launch()
|
| 35 |
+
finally:
|
| 36 |
+
shutil.rmtree(tmpdir)
|
| 37 |
+
|
| 38 |
+
if __name__ == '__main__':
|
| 39 |
+
main()
|