Spaces:
Runtime error
Runtime error
instructions
Browse files- README.md +70 -1
- app.py +4 -1
- user_history.py +8 -3
README.md
CHANGED
@@ -10,4 +10,73 @@ pinned: false
|
|
10 |
hf_oauth: true
|
11 |
---
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
hf_oauth: true
|
11 |
---
|
12 |
|
13 |
+
# Bring User History to your Spaces 🚀
|
14 |
+
|
15 |
+
***User History*** is a plugin that you can add to your Spaces to cache generated images for your users.
|
16 |
+
|
17 |
+
## Key features:
|
18 |
+
|
19 |
+
- 🤗 **Sign in with Hugging Face**
|
20 |
+
- **Save** generated images with their metadata: prompts, timestamp, hyper-parameters, etc.
|
21 |
+
- **Export** your history as zip.
|
22 |
+
- **Delete** your history to respect privacy.
|
23 |
+
- Compatible with **Persistent Storage** for long-term storage.
|
24 |
+
- **Admin** panel to check configuration and disk usage .
|
25 |
+
|
26 |
+
Want more? Please open an issue in the [Community Tab](https://huggingface.co/spaces/Wauplin/gradio-user-history/discussions)! This is meant to be a community-driven implementation, enhanced by user feedback and contributions!
|
27 |
+
|
28 |
+
## Integration
|
29 |
+
|
30 |
+
To integrate ***User History***, only a few steps are required:
|
31 |
+
1. Enable OAuth in your Space by adding `oauth: true` to your README (see [here](https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/README.md?code=true#L10))
|
32 |
+
2. Add a Persistent Storage in your Space settings. Without it, the history will not be saved permanently. Every restart of your Space will erase all the data. If you start with a small tier, it's always possible to increase the disk space later without loosing the data.
|
33 |
+
3. Copy [`user_history.py`](https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/user_history.py) at the root of your project.
|
34 |
+
4. Import in your main file with `import user_history` (see [here](https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/app.py#L10))
|
35 |
+
5. Integrate to your `generate`-like methods. Any function called by Gradio and that generates one or multiple images is a good candidate.
|
36 |
+
1. Add `profile: gr.OAuthProfile | None` as argument to the function (see [here](https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/app.py#L16)). This will tell Gradio that it needs to inject the user profile for you.
|
37 |
+
2. Use `user_history.save_image(label=..., image=..., profile=profile, metadata=...)` (as done [here](https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/app.py#L32))
|
38 |
+
1. `label` is the label of the image. Usually the prompt used to generate it.
|
39 |
+
2. `image` is the generated image. It can be a path to a stored image, a `PIL.Image` object or a numpy array.
|
40 |
+
3. `profile` is the user profile injected by Gradio
|
41 |
+
4. `metadata` (optional) is any additional information you want to add. It has to be a json-able dictionary.
|
42 |
+
3. Finally use `user_history.render()` to render the "Past generations" section (see [here](https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/app.py#L53)). A good practice is to set it in a different tab to avoid overloading your first page. You don't have to modify anything of your existing `gr.Blocks` section: just render it inside a Tab.
|
43 |
+
|
44 |
+
## Example
|
45 |
+
|
46 |
+
Here is a minimal example illustrating what we saw above.
|
47 |
+
|
48 |
+
```py
|
49 |
+
import gradio as gr
|
50 |
+
import user_history # 0. Import user_history
|
51 |
+
|
52 |
+
# 1. Inject user profile
|
53 |
+
def generate(prompt: str, profile: gr.OAuthProfile | None):
|
54 |
+
image = ...
|
55 |
+
|
56 |
+
# 2. Save image
|
57 |
+
user_history.save_image(label=prompt, image=image, profile=profile)
|
58 |
+
return image
|
59 |
+
|
60 |
+
|
61 |
+
with gr.Blocks(css="style.css") as demo:
|
62 |
+
with gr.Group():
|
63 |
+
prompt = gr.Text(show_label=False, placeholder="Prompt")
|
64 |
+
gallery = gr.Image()
|
65 |
+
prompt.submit(fn=generate, inputs=prompt, outputs=gallery)
|
66 |
+
|
67 |
+
# 3. Render user history
|
68 |
+
with gr.Blocks() as demo_with_history:
|
69 |
+
with gr.Tab("Demo"):
|
70 |
+
demo.render()
|
71 |
+
with gr.Tab("Past generations"):
|
72 |
+
user_history.render()
|
73 |
+
|
74 |
+
demo_with_history.queue().launch()
|
75 |
+
```
|
76 |
+
|
77 |
+
## Useful links
|
78 |
+
|
79 |
+
- **Demo:** https://huggingface.co/spaces/Wauplin/gradio-user-history
|
80 |
+
- **README:** https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/README.md
|
81 |
+
- **Source file:** https://huggingface.co/spaces/Wauplin/gradio-user-history/blob/main/user_history.py
|
82 |
+
- **Discussions:** https://huggingface.co/spaces/Wauplin/gradio-user-history/discussions
|
app.py
CHANGED
@@ -3,6 +3,7 @@
|
|
3 |
import json
|
4 |
import pathlib
|
5 |
import tempfile
|
|
|
6 |
|
7 |
import gradio as gr
|
8 |
from gradio_client import Client
|
@@ -47,10 +48,12 @@ with gr.Blocks(css="style.css") as demo:
|
|
47 |
prompt.submit(fn=generate, inputs=prompt, outputs=gallery)
|
48 |
|
49 |
with gr.Blocks() as demo_with_history:
|
50 |
-
with gr.Tab("
|
51 |
demo.render()
|
52 |
with gr.Tab("Past generations"):
|
53 |
user_history.render()
|
|
|
|
|
54 |
|
55 |
if __name__ == "__main__":
|
56 |
demo_with_history.queue().launch()
|
|
|
3 |
import json
|
4 |
import pathlib
|
5 |
import tempfile
|
6 |
+
from pathlib import Path
|
7 |
|
8 |
import gradio as gr
|
9 |
from gradio_client import Client
|
|
|
48 |
prompt.submit(fn=generate, inputs=prompt, outputs=gallery)
|
49 |
|
50 |
with gr.Blocks() as demo_with_history:
|
51 |
+
with gr.Tab("Demo"):
|
52 |
demo.render()
|
53 |
with gr.Tab("Past generations"):
|
54 |
user_history.render()
|
55 |
+
with gr.Tab("README"):
|
56 |
+
gr.Markdown(Path("README.md").read_text().split("---")[-1])
|
57 |
|
58 |
if __name__ == "__main__":
|
59 |
demo_with_history.queue().launch()
|
user_history.py
CHANGED
@@ -31,8 +31,9 @@ def render() -> None:
|
|
31 |
|
32 |
# Render user history tab
|
33 |
gr.Markdown(
|
34 |
-
"## Your past generations\n\
|
35 |
-
"
|
|
|
36 |
)
|
37 |
|
38 |
if os.getenv("SYSTEM") == "spaces" and not os.path.exists("/data"):
|
@@ -70,7 +71,11 @@ def render() -> None:
|
|
70 |
show_share_button=False,
|
71 |
show_download_button=False,
|
72 |
)
|
73 |
-
gr.Markdown(
|
|
|
|
|
|
|
|
|
74 |
gallery.attach_load_event(_fetch_user_history, every=None)
|
75 |
|
76 |
# Interactions
|
|
|
31 |
|
32 |
# Render user history tab
|
33 |
gr.Markdown(
|
34 |
+
"## Your past generations\n\nLog in to keep a gallery of your previous generations. Your history will be saved"
|
35 |
+
" and available on your next visit. Make sure to export your images from time to time as this gallery may be"
|
36 |
+
" deleted in the future."
|
37 |
)
|
38 |
|
39 |
if os.getenv("SYSTEM") == "spaces" and not os.path.exists("/data"):
|
|
|
71 |
show_share_button=False,
|
72 |
show_download_button=False,
|
73 |
)
|
74 |
+
gr.Markdown(
|
75 |
+
"User history is powered by"
|
76 |
+
" [Wauplin/gradio-user-history](https://huggingface.co/spaces/Wauplin/gradio-user-history). Integrate it to"
|
77 |
+
" your own Space in just a few lines of code!"
|
78 |
+
)
|
79 |
gallery.attach_load_event(_fetch_user_history, every=None)
|
80 |
|
81 |
# Interactions
|