Upload folder using huggingface_hub
Browse files- README.md +24 -1
- configs/prompts.toml +1 -10
- hf_space/.github/workflows/sync_to_spaces.yml +57 -0
- hf_space/configs/prompts.toml +9 -2
- hf_space/hf_space/.gitattributes +35 -0
- hf_space/hf_space/.gitignore +171 -0
- hf_space/hf_space/app.py +225 -0
- hf_space/hf_space/configs/prompts.toml +27 -0
- hf_space/hf_space/configs/responses.py +4 -0
- hf_space/hf_space/requirements.txt +3 -0
- hf_space/hf_space/statics/styles.css +54 -0
- hf_space/hf_space/utils.py +22 -0
- hf_space/requirements.txt +1 -1
- hf_space/statics/styles.css +5 -8
- hf_space/utils.py +10 -6
README.md
CHANGED
@@ -33,4 +33,27 @@ $ python main.py # or gradio main.py
|
|
33 |
```
|
34 |
|
35 |
# Acknowledgments
|
36 |
-
This is a project built during the Vertex sprints held by Google's ML Developer Programs team. We are thankful to be granted good amount of GCP credits to do this project
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
```
|
34 |
|
35 |
# Acknowledgments
|
36 |
+
This is a project built during the Vertex sprints held by Google's ML Developer Programs team. We are thankful to be granted good amount of GCP credits to do this project.# AdaptSum
|
37 |
+
|
38 |
+
AdaptSum stands for Adaptive Summarization. This project focuses on developing an LLM-powered system for dynamic summarization. Instead of generating entirely new summaries with each update, the system intelligently identifies and modifies only the necessary parts of the existing summary. This approach aims to create a more efficient and fluid summarization process within a continuous chat interaction with an LLM.
|
39 |
+
|
40 |
+
# Instructions
|
41 |
+
|
42 |
+
1. Install dependencies
|
43 |
+
```shell
|
44 |
+
$ pip install requirements.txt
|
45 |
+
```
|
46 |
+
|
47 |
+
2. Setup Gemini API Key
|
48 |
+
```shell
|
49 |
+
$ export GEMINI_API_KEY=xxxxx
|
50 |
+
```
|
51 |
+
> note that GEMINI API KEY should be obtained from Google AI Studio. Vertex AI is not supported at the moment (this is because Gemini SDK does not provide file uploading functionality for Vertex AI usage now).
|
52 |
+
|
53 |
+
3. Run Gradio app
|
54 |
+
```shell
|
55 |
+
$ python main.py # or gradio main.py
|
56 |
+
```
|
57 |
+
|
58 |
+
# Acknowledgments
|
59 |
+
This is a project built during the Vertex sprints held by Google's ML Developer Programs team. We are thankful to be granted good amount of GCP credits to do this project.
|
configs/prompts.toml
CHANGED
@@ -15,15 +15,6 @@ When updating the summary:
|
|
15 |
* **Completeness:** Strive to be as comprehensive and detailed as possible, capturing all key points and insights.
|
16 |
* **Conciseness:** While being detailed, also aim for conciseness and clarity in the summary.
|
17 |
* **Update Strategy:** Instead of rewriting the entire summary each time, update only the specific portions necessary to reflect new information or changes in understanding.
|
18 |
-
|
19 |
-
By following these guidelines, you will maintain an evolving summary that accurately reflects my learning and the key takeaways from our conversation."
|
20 |
-
|
21 |
-
**Key improvements:**
|
22 |
-
|
23 |
-
* **Clearer Instructions:** More explicit instructions on how to update the summary (i.e., updating specific portions instead of rewriting).
|
24 |
-
* **Emphasis on Accuracy:** Stronger emphasis on factual accuracy and reflecting nuances.
|
25 |
-
* **Conciseness:** Added a direction to balance detail with conciseness.
|
26 |
-
* **Structure:** Improved organization and formatting for better readability.
|
27 |
"""
|
28 |
|
29 |
system_prompt = """
|
@@ -31,4 +22,4 @@ Consider yourself an expert at summarizing content with a high bar
|
|
31 |
for scientific rigor. However, when generating the summaries you
|
32 |
must follow the persona of a $persona. This persona will help set
|
33 |
the tone of the conversation.
|
34 |
-
"""
|
|
|
15 |
* **Completeness:** Strive to be as comprehensive and detailed as possible, capturing all key points and insights.
|
16 |
* **Conciseness:** While being detailed, also aim for conciseness and clarity in the summary.
|
17 |
* **Update Strategy:** Instead of rewriting the entire summary each time, update only the specific portions necessary to reflect new information or changes in understanding.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
"""
|
19 |
|
20 |
system_prompt = """
|
|
|
22 |
for scientific rigor. However, when generating the summaries you
|
23 |
must follow the persona of a $persona. This persona will help set
|
24 |
the tone of the conversation.
|
25 |
+
"""
|
hf_space/.github/workflows/sync_to_spaces.yml
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Sync to Hugging Face Spaces
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches:
|
6 |
+
- main
|
7 |
+
workflow_dispatch:
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
sync:
|
11 |
+
runs-on: ubuntu-latest
|
12 |
+
|
13 |
+
steps:
|
14 |
+
- name: Checkout GitHub Repository
|
15 |
+
uses: actions/checkout@v3
|
16 |
+
|
17 |
+
- name: Set up Python
|
18 |
+
uses: actions/setup-python@v4
|
19 |
+
with:
|
20 |
+
python-version: "3.10"
|
21 |
+
|
22 |
+
- name: Install Hugging Face Hub CLI
|
23 |
+
run: |
|
24 |
+
python -m pip install --upgrade pip
|
25 |
+
pip install huggingface_hub
|
26 |
+
|
27 |
+
- name: Clone Hugging Face Spaces Repository
|
28 |
+
run: |
|
29 |
+
huggingface-cli login --token $HF_TOKEN --add-to-git-credential
|
30 |
+
git clone https://huggingface.co/spaces/adaptsum/demo hf_space
|
31 |
+
cd hf_space
|
32 |
+
git checkout main
|
33 |
+
env:
|
34 |
+
HF_TOKEN: ${{ secrets.HUGGINGFACE_TOKEN }}
|
35 |
+
|
36 |
+
- name: Copy Files to Hugging Face Repo
|
37 |
+
run: |
|
38 |
+
rsync -av --exclude='.git' --exclude='README.md' ./ hf_space/
|
39 |
+
|
40 |
+
- name: Merge README.md Files
|
41 |
+
run: |
|
42 |
+
cat hf_space/README.md README.md > hf_space/README_combined.md
|
43 |
+
mv hf_space/README_combined.md hf_space/README.md
|
44 |
+
rm -rf hf_space/README_combined.md
|
45 |
+
|
46 |
+
- name: Commit and Push Changes
|
47 |
+
run: |
|
48 |
+
cd hf_space
|
49 |
+
git add .
|
50 |
+
if git diff --cached --quiet; then
|
51 |
+
echo "No changes to commit"
|
52 |
+
else
|
53 |
+
huggingface-cli upload adaptsum/demo . --repo-type=space
|
54 |
+
echo "Changes have been pushed."
|
55 |
+
fi
|
56 |
+
env:
|
57 |
+
HUGGINGFACE_TOKEN: ${{ secrets.HUGGINGFACE_TOKEN }}
|
hf_space/configs/prompts.toml
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
[summarization]
|
2 |
prompt = """
|
3 |
Below is the initial summary of our conversation.
|
4 |
-
Based on the summary and the last conversation between you(assistant) and me(user), I want to update the summary.
|
5 |
|
6 |
**Initial Summary:**
|
7 |
$previous_summary
|
@@ -23,5 +23,12 @@ By following these guidelines, you will maintain an evolving summary that accura
|
|
23 |
* **Clearer Instructions:** More explicit instructions on how to update the summary (i.e., updating specific portions instead of rewriting).
|
24 |
* **Emphasis on Accuracy:** Stronger emphasis on factual accuracy and reflecting nuances.
|
25 |
* **Conciseness:** Added a direction to balance detail with conciseness.
|
26 |
-
* **Structure:** Improved organization and formatting for better readability.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
"""
|
|
|
1 |
[summarization]
|
2 |
prompt = """
|
3 |
Below is the initial summary of our conversation.
|
4 |
+
Based on the summary and the last conversation between you (assistant) and me (user), I want to update the summary.
|
5 |
|
6 |
**Initial Summary:**
|
7 |
$previous_summary
|
|
|
23 |
* **Clearer Instructions:** More explicit instructions on how to update the summary (i.e., updating specific portions instead of rewriting).
|
24 |
* **Emphasis on Accuracy:** Stronger emphasis on factual accuracy and reflecting nuances.
|
25 |
* **Conciseness:** Added a direction to balance detail with conciseness.
|
26 |
+
* **Structure:** Improved organization and formatting for better readability.
|
27 |
+
"""
|
28 |
+
|
29 |
+
system_prompt = """
|
30 |
+
Consider yourself an expert at summarizing content with a high bar
|
31 |
+
for scientific rigor. However, when generating the summaries you
|
32 |
+
must follow the persona of a $persona. This persona will help set
|
33 |
+
the tone of the conversation.
|
34 |
"""
|
hf_space/hf_space/.gitattributes
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
hf_space/hf_space/.gitignore
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
share/python-wheels/
|
24 |
+
*.egg-info/
|
25 |
+
.installed.cfg
|
26 |
+
*.egg
|
27 |
+
MANIFEST
|
28 |
+
|
29 |
+
# PyInstaller
|
30 |
+
# Usually these files are written by a python script from a template
|
31 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
32 |
+
*.manifest
|
33 |
+
*.spec
|
34 |
+
|
35 |
+
# Installer logs
|
36 |
+
pip-log.txt
|
37 |
+
pip-delete-this-directory.txt
|
38 |
+
|
39 |
+
# Unit test / coverage reports
|
40 |
+
htmlcov/
|
41 |
+
.tox/
|
42 |
+
.nox/
|
43 |
+
.coverage
|
44 |
+
.coverage.*
|
45 |
+
.cache
|
46 |
+
nosetests.xml
|
47 |
+
coverage.xml
|
48 |
+
*.cover
|
49 |
+
*.py,cover
|
50 |
+
.hypothesis/
|
51 |
+
.pytest_cache/
|
52 |
+
cover/
|
53 |
+
|
54 |
+
# Translations
|
55 |
+
*.mo
|
56 |
+
*.pot
|
57 |
+
|
58 |
+
# Django stuff:
|
59 |
+
*.log
|
60 |
+
local_settings.py
|
61 |
+
db.sqlite3
|
62 |
+
db.sqlite3-journal
|
63 |
+
|
64 |
+
# Flask stuff:
|
65 |
+
instance/
|
66 |
+
.webassets-cache
|
67 |
+
|
68 |
+
# Scrapy stuff:
|
69 |
+
.scrapy
|
70 |
+
|
71 |
+
# Sphinx documentation
|
72 |
+
docs/_build/
|
73 |
+
|
74 |
+
# PyBuilder
|
75 |
+
.pybuilder/
|
76 |
+
target/
|
77 |
+
|
78 |
+
# Jupyter Notebook
|
79 |
+
.ipynb_checkpoints
|
80 |
+
|
81 |
+
# IPython
|
82 |
+
profile_default/
|
83 |
+
ipython_config.py
|
84 |
+
|
85 |
+
# pyenv
|
86 |
+
# For a library or package, you might want to ignore these files since the code is
|
87 |
+
# intended to run in multiple environments; otherwise, check them in:
|
88 |
+
# .python-version
|
89 |
+
|
90 |
+
# pipenv
|
91 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
92 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
93 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
94 |
+
# install all needed dependencies.
|
95 |
+
#Pipfile.lock
|
96 |
+
|
97 |
+
# UV
|
98 |
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
99 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
100 |
+
# commonly ignored for libraries.
|
101 |
+
#uv.lock
|
102 |
+
|
103 |
+
# poetry
|
104 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
105 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
106 |
+
# commonly ignored for libraries.
|
107 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
108 |
+
#poetry.lock
|
109 |
+
|
110 |
+
# pdm
|
111 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
112 |
+
#pdm.lock
|
113 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
114 |
+
# in version control.
|
115 |
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
116 |
+
.pdm.toml
|
117 |
+
.pdm-python
|
118 |
+
.pdm-build/
|
119 |
+
|
120 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
121 |
+
__pypackages__/
|
122 |
+
|
123 |
+
# Celery stuff
|
124 |
+
celerybeat-schedule
|
125 |
+
celerybeat.pid
|
126 |
+
|
127 |
+
# SageMath parsed files
|
128 |
+
*.sage.py
|
129 |
+
|
130 |
+
# Environments
|
131 |
+
.env
|
132 |
+
.venv
|
133 |
+
env/
|
134 |
+
venv/
|
135 |
+
ENV/
|
136 |
+
env.bak/
|
137 |
+
venv.bak/
|
138 |
+
|
139 |
+
# Spyder project settings
|
140 |
+
.spyderproject
|
141 |
+
.spyproject
|
142 |
+
|
143 |
+
# Rope project settings
|
144 |
+
.ropeproject
|
145 |
+
|
146 |
+
# mkdocs documentation
|
147 |
+
/site
|
148 |
+
|
149 |
+
# mypy
|
150 |
+
.mypy_cache/
|
151 |
+
.dmypy.json
|
152 |
+
dmypy.json
|
153 |
+
|
154 |
+
# Pyre type checker
|
155 |
+
.pyre/
|
156 |
+
|
157 |
+
# pytype static type analyzer
|
158 |
+
.pytype/
|
159 |
+
|
160 |
+
# Cython debug symbols
|
161 |
+
cython_debug/
|
162 |
+
|
163 |
+
# PyCharm
|
164 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
165 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
166 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
167 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
168 |
+
#.idea/
|
169 |
+
|
170 |
+
# PyPI configuration file
|
171 |
+
.pypirc
|
hf_space/hf_space/app.py
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import argparse
|
3 |
+
import asyncio
|
4 |
+
import gradio as gr
|
5 |
+
from difflib import Differ
|
6 |
+
from string import Template
|
7 |
+
from utils import load_prompt, setup_gemini_client
|
8 |
+
from configs.responses import SummaryResponses
|
9 |
+
from google.genai import types
|
10 |
+
|
11 |
+
def parse_args():
|
12 |
+
parser = argparse.ArgumentParser()
|
13 |
+
parser.add_argument("--ai-studio-api-key", type=str, default=os.getenv("GEMINI_API_KEY"))
|
14 |
+
parser.add_argument("--vertexai", action="store_true", default=False)
|
15 |
+
parser.add_argument("--vertexai-project", type=str, default="gcp-ml-172005")
|
16 |
+
parser.add_argument("--vertexai-location", type=str, default="us-central1")
|
17 |
+
parser.add_argument("--model", type=str, default="gemini-2.0-flash", choices=["gemini-1.5-flash", "gemini-2.0-flash", "gemini-2.0-flash-001"])
|
18 |
+
parser.add_argument("--seed", type=int, default=2025)
|
19 |
+
parser.add_argument("--prompt-tmpl-path", type=str, default="configs/prompts.toml")
|
20 |
+
parser.add_argument("--css-path", type=str, default="statics/styles.css")
|
21 |
+
args = parser.parse_args()
|
22 |
+
return args
|
23 |
+
|
24 |
+
def find_attached_file(filename, attached_files):
|
25 |
+
for file in attached_files:
|
26 |
+
if file['name'] == filename:
|
27 |
+
return file
|
28 |
+
return None
|
29 |
+
|
30 |
+
async def echo(message, history, state, persona):
|
31 |
+
attached_file = None
|
32 |
+
system_instruction = Template(prompt_tmpl['summarization']['system_prompt']).safe_substitute(persona=persona)
|
33 |
+
|
34 |
+
if message['files']:
|
35 |
+
path_local = message['files'][0]
|
36 |
+
filename = os.path.basename(path_local)
|
37 |
+
|
38 |
+
attached_file = find_attached_file(filename, state["attached_files"])
|
39 |
+
if attached_file is None:
|
40 |
+
path_gcp = await client.files.upload(path=path_local)
|
41 |
+
state["attached_files"].append({
|
42 |
+
"name": filename,
|
43 |
+
"path_local": path_local,
|
44 |
+
"gcp_entity": path_gcp,
|
45 |
+
"path_gcp": path_gcp.name,
|
46 |
+
"mime_type=": path_gcp.mime_type,
|
47 |
+
"expiration_time": path_gcp.expiration_time,
|
48 |
+
})
|
49 |
+
attached_file = path_gcp
|
50 |
+
|
51 |
+
user_message = [message['text']]
|
52 |
+
if attached_file: user_message.append(attached_file)
|
53 |
+
|
54 |
+
chat_history = state['messages']
|
55 |
+
chat_history = chat_history + user_message
|
56 |
+
state['messages'] = chat_history
|
57 |
+
|
58 |
+
response_chunks = ""
|
59 |
+
model_content_stream = await client.models.generate_content_stream(
|
60 |
+
model=args.model,
|
61 |
+
contents=state['messages'],
|
62 |
+
config=types.GenerateContentConfig(
|
63 |
+
system_instruction=system_instruction, seed=args.seed
|
64 |
+
),
|
65 |
+
)
|
66 |
+
async for chunk in model_content_stream:
|
67 |
+
response_chunks += chunk.text
|
68 |
+
# when model generates too fast, Gradio does not respond that in real-time.
|
69 |
+
await asyncio.sleep(0.1)
|
70 |
+
yield (
|
71 |
+
response_chunks,
|
72 |
+
state,
|
73 |
+
state['summary_diff_history'][-1] if len(state['summary_diff_history']) > 1 else "",
|
74 |
+
state['summary_history'][-1] if len(state['summary_history']) > 1 else "",
|
75 |
+
gr.Slider(
|
76 |
+
visible=False if len(state['summary_history']) <= 1 else True,
|
77 |
+
interactive=False if len(state['summary_history']) <= 1 else True,
|
78 |
+
),
|
79 |
+
)
|
80 |
+
|
81 |
+
# make summary
|
82 |
+
response = await client.models.generate_content(
|
83 |
+
model=args.model,
|
84 |
+
contents=[
|
85 |
+
Template(
|
86 |
+
prompt_tmpl['summarization']['prompt']
|
87 |
+
).safe_substitute(
|
88 |
+
previous_summary=state['summary'],
|
89 |
+
latest_conversation=str({"user": message['text'], "assistant": response_chunks})
|
90 |
+
)
|
91 |
+
],
|
92 |
+
config=types.GenerateContentConfig(
|
93 |
+
system_instruction=system_instruction,
|
94 |
+
seed=args.seed,
|
95 |
+
response_mime_type='application/json',
|
96 |
+
response_schema=SummaryResponses
|
97 |
+
)
|
98 |
+
)
|
99 |
+
|
100 |
+
prev_summary = state['summary_history'][-1] if len(state['summary_history']) >= 1 else ""
|
101 |
+
|
102 |
+
state['summary'] = (
|
103 |
+
response.parsed.summary
|
104 |
+
if getattr(response.parsed, "summary", None) is not None
|
105 |
+
else response.text
|
106 |
+
)
|
107 |
+
state['summary_history'].append(
|
108 |
+
response.parsed.summary
|
109 |
+
if getattr(response.parsed, "summary", None) is not None
|
110 |
+
else response.text
|
111 |
+
)
|
112 |
+
state['summary_diff_history'].append(
|
113 |
+
[
|
114 |
+
(token[2:], token[0] if token[0] != " " else None)
|
115 |
+
for token in Differ().compare(prev_summary, state['summary'])
|
116 |
+
]
|
117 |
+
)
|
118 |
+
|
119 |
+
yield (
|
120 |
+
response_chunks,
|
121 |
+
state,
|
122 |
+
state['summary_diff_history'][-1],
|
123 |
+
state['summary_history'][-1],
|
124 |
+
gr.Slider(
|
125 |
+
maximum=len(state['summary_history']),
|
126 |
+
value=len(state['summary_history']),
|
127 |
+
visible=False if len(state['summary_history']) == 1 else True, interactive=True
|
128 |
+
),
|
129 |
+
)
|
130 |
+
|
131 |
+
def change_view_toggle(view_toggle):
|
132 |
+
if view_toggle == "Diff":
|
133 |
+
return (
|
134 |
+
gr.HighlightedText(visible=True),
|
135 |
+
gr.Markdown(visible=False)
|
136 |
+
)
|
137 |
+
else:
|
138 |
+
return (
|
139 |
+
gr.HighlightedText(visible=False),
|
140 |
+
gr.Markdown(visible=True)
|
141 |
+
)
|
142 |
+
|
143 |
+
def navigate_to_summary(summary_num, state):
|
144 |
+
return (
|
145 |
+
state['summary_diff_history'][summary_num-1],
|
146 |
+
state['summary_history'][summary_num-1]
|
147 |
+
)
|
148 |
+
|
149 |
+
def main(args):
|
150 |
+
style_css = open(args.css_path, "r").read()
|
151 |
+
|
152 |
+
global client, prompt_tmpl, system_instruction
|
153 |
+
client = setup_gemini_client(args)
|
154 |
+
prompt_tmpl = load_prompt(args)
|
155 |
+
|
156 |
+
## Gradio Blocks
|
157 |
+
with gr.Blocks(css=style_css) as demo:
|
158 |
+
# State per session
|
159 |
+
state = gr.State({
|
160 |
+
"messages": [],
|
161 |
+
"attached_files": [],
|
162 |
+
"summary": "",
|
163 |
+
"summary_history": [],
|
164 |
+
"summary_diff_history": []
|
165 |
+
})
|
166 |
+
|
167 |
+
with gr.Column():
|
168 |
+
gr.Markdown("# Adaptive Summarization")
|
169 |
+
gr.Markdown("AdaptSum stands for Adaptive Summarization. This project focuses on developing an LLM-powered system for dynamic summarization. Instead of generating entirely new summaries with each update, the system intelligently identifies and modifies only the necessary parts of the existing summary. This approach aims to create a more efficient and fluid summarization process within a continuous chat interaction with an LLM.")
|
170 |
+
|
171 |
+
with gr.Column():
|
172 |
+
with gr.Accordion("Adaptively Summarized Conversation", elem_id="adaptive-summary-accordion", open=False):
|
173 |
+
with gr.Row(elem_id="view-toggle-btn-container"):
|
174 |
+
view_toggle_btn = gr.Radio(
|
175 |
+
choices=["Diff", "Markdown"],
|
176 |
+
value="Markdown",
|
177 |
+
interactive=True,
|
178 |
+
elem_id="view-toggle-btn"
|
179 |
+
)
|
180 |
+
|
181 |
+
summary_diff = gr.HighlightedText(
|
182 |
+
label="Summary so far",
|
183 |
+
# value="No summary yet. As you chat with the assistant, the summary will be updated automatically.",
|
184 |
+
combine_adjacent=True,
|
185 |
+
show_legend=True,
|
186 |
+
color_map={"-": "red", "+": "green"},
|
187 |
+
elem_classes=["summary-window"],
|
188 |
+
visible=False
|
189 |
+
)
|
190 |
+
|
191 |
+
summary_md = gr.Markdown(
|
192 |
+
label="Summary so far",
|
193 |
+
value="No summary yet. As you chat with the assistant, the summary will be updated automatically.",
|
194 |
+
elem_classes=["summary-window"],
|
195 |
+
visible=True
|
196 |
+
)
|
197 |
+
|
198 |
+
summary_num = gr.Slider(label="summary history", minimum=1, maximum=1, step=1, show_reset_button=False, visible=False)
|
199 |
+
|
200 |
+
view_toggle_btn.change(change_view_toggle, inputs=[view_toggle_btn], outputs=[summary_diff, summary_md])
|
201 |
+
summary_num.release(navigate_to_summary, inputs=[summary_num, state], outputs=[summary_diff, summary_md])
|
202 |
+
|
203 |
+
with gr.Column("persona-dropdown-container", elem_id="persona-dropdown-container"):
|
204 |
+
persona = gr.Dropdown(
|
205 |
+
["expert", "novice", "regular practitioner", "high schooler"],
|
206 |
+
label="Summary Persona",
|
207 |
+
info="Control the tonality of the conversation.",
|
208 |
+
min_width="auto",
|
209 |
+
)
|
210 |
+
|
211 |
+
with gr.Column("chat-window", elem_id="chat-window"):
|
212 |
+
gr.ChatInterface(
|
213 |
+
multimodal=True,
|
214 |
+
type="messages",
|
215 |
+
fn=echo,
|
216 |
+
additional_inputs=[state, persona],
|
217 |
+
additional_outputs=[state, summary_diff, summary_md, summary_num],
|
218 |
+
)
|
219 |
+
|
220 |
+
return demo
|
221 |
+
|
222 |
+
if __name__ == "__main__":
|
223 |
+
args = parse_args()
|
224 |
+
demo = main(args)
|
225 |
+
demo.launch()
|
hf_space/hf_space/configs/prompts.toml
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[summarization]
|
2 |
+
prompt = """
|
3 |
+
Below is the initial summary of our conversation.
|
4 |
+
Based on the summary and the last conversation between you(assistant) and me(user), I want to update the summary.
|
5 |
+
|
6 |
+
**Initial Summary:**
|
7 |
+
$previous_summary
|
8 |
+
|
9 |
+
**Last Conversation:**
|
10 |
+
$latest_conversation
|
11 |
+
|
12 |
+
When updating the summary:
|
13 |
+
* **Focus:** Only include information we have explicitly discussed in this session. Do not introduce any new information or topics, even if you have prior knowledge.
|
14 |
+
* **Accuracy:** Ensure the summary is factually accurate and reflects the nuances of our discussion.
|
15 |
+
* **Completeness:** Strive to be as comprehensive and detailed as possible, capturing all key points and insights.
|
16 |
+
* **Conciseness:** While being detailed, also aim for conciseness and clarity in the summary.
|
17 |
+
* **Update Strategy:** Instead of rewriting the entire summary each time, update only the specific portions necessary to reflect new information or changes in understanding.
|
18 |
+
|
19 |
+
By following these guidelines, you will maintain an evolving summary that accurately reflects my learning and the key takeaways from our conversation."
|
20 |
+
|
21 |
+
**Key improvements:**
|
22 |
+
|
23 |
+
* **Clearer Instructions:** More explicit instructions on how to update the summary (i.e., updating specific portions instead of rewriting).
|
24 |
+
* **Emphasis on Accuracy:** Stronger emphasis on factual accuracy and reflecting nuances.
|
25 |
+
* **Conciseness:** Added a direction to balance detail with conciseness.
|
26 |
+
* **Structure:** Improved organization and formatting for better readability. Bullet points with Markdown would be preferred.
|
27 |
+
"""
|
hf_space/hf_space/configs/responses.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
|
3 |
+
class SummaryResponses(BaseModel):
|
4 |
+
summary: str
|
hf_space/hf_space/requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
google-genai==0.7.0
|
2 |
+
toml
|
3 |
+
gradio
|
hf_space/hf_space/statics/styles.css
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.summary-window {
|
2 |
+
height: 550px !important;
|
3 |
+
/* border: dashed 1px #e0e0e0 !important; */
|
4 |
+
border-radius: 10px !important;
|
5 |
+
padding: 4px;
|
6 |
+
}
|
7 |
+
|
8 |
+
.summary-window > label {
|
9 |
+
display: none !important;
|
10 |
+
}
|
11 |
+
|
12 |
+
#view-toggle-btn-container > div {
|
13 |
+
border: none !important;
|
14 |
+
}
|
15 |
+
|
16 |
+
#view-toggle-btn > span {
|
17 |
+
display: none !important;
|
18 |
+
}
|
19 |
+
|
20 |
+
#view-toggle-btn > div:nth-child(3) {
|
21 |
+
margin: auto !important;
|
22 |
+
width: fit-content !important;
|
23 |
+
}
|
24 |
+
|
25 |
+
#adaptive-summary-accordion {
|
26 |
+
position: absolute !important;
|
27 |
+
z-index: 100 !important;
|
28 |
+
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2);
|
29 |
+
}
|
30 |
+
|
31 |
+
#chat-window {
|
32 |
+
margin-top: 40px !important;
|
33 |
+
}
|
34 |
+
|
35 |
+
#chat-window > div > div:nth-child(1) {
|
36 |
+
height: 600px !important;
|
37 |
+
}
|
38 |
+
|
39 |
+
.textfield {
|
40 |
+
line-height: 1.7 !important;
|
41 |
+
}
|
42 |
+
|
43 |
+
.textspan {
|
44 |
+
padding: 0px !important;
|
45 |
+
margin: 0px !important;
|
46 |
+
line-height: 1.7 !important;
|
47 |
+
}
|
48 |
+
|
49 |
+
@media (prefers-color-scheme: dark) {
|
50 |
+
#adaptive-summary-accordion {
|
51 |
+
/* White-ish shadow for dark themes */
|
52 |
+
box-shadow: 5px 5px 10px rgba(245, 245, 245, 0.2); /* Or any other white-ish color you prefer */
|
53 |
+
}
|
54 |
+
}
|
hf_space/hf_space/utils.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import toml
|
2 |
+
from google import genai
|
3 |
+
|
4 |
+
def load_prompt(args):
|
5 |
+
with open(args.prompt_tmpl_path, 'r') as f:
|
6 |
+
prompts = toml.load(f)
|
7 |
+
|
8 |
+
return prompts
|
9 |
+
|
10 |
+
def setup_gemini_client(args):
|
11 |
+
if args.vertexai:
|
12 |
+
client = genai.Client(
|
13 |
+
vertexai=args.vertexai,
|
14 |
+
project=args.vertexai_project,
|
15 |
+
location=args.vertexai_location
|
16 |
+
)
|
17 |
+
else:
|
18 |
+
client = genai.Client(
|
19 |
+
api_key=args.ai_studio_api_key,
|
20 |
+
)
|
21 |
+
|
22 |
+
return client
|
hf_space/requirements.txt
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
google-genai==0.7.0
|
2 |
toml
|
3 |
-
gradio
|
|
|
1 |
google-genai==0.7.0
|
2 |
toml
|
3 |
+
gradio
|
hf_space/statics/styles.css
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
.summary-window {
|
2 |
-
height:
|
3 |
/* border: dashed 1px #e0e0e0 !important; */
|
4 |
border-radius: 10px !important;
|
5 |
padding: 4px;
|
@@ -28,9 +28,9 @@
|
|
28 |
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2);
|
29 |
}
|
30 |
|
31 |
-
#chat-window {
|
32 |
margin-top: 40px !important;
|
33 |
-
}
|
34 |
|
35 |
#chat-window > div > div:nth-child(1) {
|
36 |
height: 600px !important;
|
@@ -46,9 +46,6 @@
|
|
46 |
line-height: 1.7 !important;
|
47 |
}
|
48 |
|
49 |
-
|
50 |
-
|
51 |
-
/* White-ish shadow for dark themes */
|
52 |
-
box-shadow: 5px 5px 10px rgba(245, 245, 245, 0.2); /* Or any other white-ish color you prefer */
|
53 |
-
}
|
54 |
}
|
|
|
1 |
.summary-window {
|
2 |
+
height: 600px !important;
|
3 |
/* border: dashed 1px #e0e0e0 !important; */
|
4 |
border-radius: 10px !important;
|
5 |
padding: 4px;
|
|
|
28 |
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2);
|
29 |
}
|
30 |
|
31 |
+
/* #chat-window {
|
32 |
margin-top: 40px !important;
|
33 |
+
} */
|
34 |
|
35 |
#chat-window > div > div:nth-child(1) {
|
36 |
height: 600px !important;
|
|
|
46 |
line-height: 1.7 !important;
|
47 |
}
|
48 |
|
49 |
+
#persona-dropdown-container {
|
50 |
+
margin-top: 40px !important;
|
|
|
|
|
|
|
51 |
}
|
hf_space/utils.py
CHANGED
@@ -9,14 +9,18 @@ def load_prompt(args):
|
|
9 |
|
10 |
def setup_gemini_client(args):
|
11 |
if args.vertexai:
|
12 |
-
client = genai.
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
16 |
)
|
17 |
else:
|
18 |
-
client = genai.
|
19 |
-
|
|
|
|
|
20 |
)
|
21 |
|
22 |
return client
|
|
|
9 |
|
10 |
def setup_gemini_client(args):
|
11 |
if args.vertexai:
|
12 |
+
client = genai.client.AsyncClient(
|
13 |
+
genai.client.ApiClient(
|
14 |
+
vertexai=args.vertexai,
|
15 |
+
project=args.vertexai_project,
|
16 |
+
location=args.vertexai_location
|
17 |
+
)
|
18 |
)
|
19 |
else:
|
20 |
+
client = genai.client.AsyncClient(
|
21 |
+
genai.client.ApiClient(
|
22 |
+
api_key=args.ai_studio_api_key
|
23 |
+
)
|
24 |
)
|
25 |
|
26 |
return client
|