Spaces:
Running
on
L4
Running
on
L4
Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- README.md +19 -211
- backend/vespa_app.py +11 -3
- main.py +2 -1
- static/full_images/012200fb9d07b72da276db7e9d499a2f.jpg +0 -0
- static/full_images/088177a2b300ed9e9cd8d936edb7b5ca.jpg +0 -0
- static/full_images/0d9a8f0fa595513774d94d6058aa3c27.jpg +0 -0
- static/full_images/0f2073449af49b9a766d269bda7aa2ec.jpg +0 -0
- static/full_images/15610e06e17b391f9d6212d4a704d1c8.jpg +0 -0
- static/full_images/176768b9dda73154bbbe67983b07ef7b.jpg +0 -0
- static/full_images/189aa5523cce7b3e37b336aa1327bae8.jpg +0 -0
- static/full_images/23b1e0404920ce0f0257eb0e8190c557.jpg +0 -0
- static/full_images/2c5ab4a0f12fa673c17f0283f698bdb9.jpg +0 -0
- static/full_images/2e70dc0cf1e35b3f11f6d94017a17110.jpg +0 -0
- static/full_images/31b6ab7aae4796b0d6200380b05b25f0.jpg +0 -0
- static/full_images/37002ca88b2a5600b5ec7dfd03900d84.jpg +0 -0
- static/full_images/3cd17414305381977eae7ff3d30de6dc.jpg +0 -0
- static/full_images/3d0c05ab1db804e856a25f473dc5149d.jpg +0 -0
- static/full_images/41ff192952c5e93adebbc1852c748985.jpg +0 -0
- static/full_images/42adeab8461f18a692708f37444d4dee.jpg +0 -0
- static/full_images/44bce8cd76f96db9be93d366c2a36fd3.jpg +0 -0
- static/full_images/45c159551a8840a4528eb2034d562abd.jpg +0 -0
- static/full_images/46a9cf839d8c07f740c88020e1459d2f.jpg +0 -0
- static/full_images/473639db0c76b6e80664775066bd2a7b.jpg +0 -0
- static/full_images/47b81a110672e649487aeb708f1277d5.jpg +0 -0
- static/full_images/4af459669551f34d1542e9734c1722db.jpg +0 -0
- static/full_images/4f7a37046626de54fdf189106371eea2.jpg +0 -0
- static/full_images/5257e0dc94a52bbf0dff16f4b481772b.jpg +0 -0
- static/full_images/5466c54401a63372bda9bf0b8586ced9.jpg +0 -0
- static/full_images/547f1ed03149aee493b22a192146b651.jpg +0 -0
- static/full_images/5913b08b81182be02056225d19225039.jpg +0 -0
- static/full_images/64060791c89655d280a6a01eea8a8a47.jpg +0 -0
- static/full_images/645d0f26220a092ffc0de138c72927a8.jpg +0 -0
- static/full_images/694dfbca150f4cac83e27d17f0b04bbd.jpg +0 -0
- static/full_images/6a14ac1f65b59b0cfdc65ecc6bd57b55.jpg +0 -0
- static/full_images/6b1f502ac819b8a5ba2e65f8e56f22b8.jpg +0 -0
- static/full_images/7051b5a4804d48045fff84866923d34a.jpg +0 -0
- static/full_images/7364ccb5e7ff145e56014d70ec0295b4.jpg +0 -0
- static/full_images/743dd0b209db20acac00090e34f66d1e.jpg +0 -0
- static/full_images/7485ce436c35173ee7c379ad67754ae7.jpg +0 -0
- static/full_images/74f26585a4ecb41de76e8cb906811244.jpg +0 -0
- static/full_images/75a1a2c786e848e7e043f2c3b759ad73.jpg +0 -0
- static/full_images/76a4708381e45c35b33793dff2791c7c.jpg +0 -0
- static/full_images/7898c6c68d78f85ed8d8d92c406a3850.jpg +0 -0
- static/full_images/7901d8397e67307fa7ccbac2e1dcaba4.jpg +0 -0
- static/full_images/7a1546e2ad050e8a915cbcbfae7a991f.jpg +0 -0
- static/full_images/7cf284e8ccc5a68b4a92eca9b1176707.jpg +0 -0
- static/full_images/83929419be13d5a71b23bfd71344fe0b.jpg +0 -0
- static/full_images/8403e1a2fdb89eb1e96227427c8b833c.jpg +0 -0
- static/full_images/8554ad2b2ea96d1f363f0470fff572d5.jpg +0 -0
- static/full_images/8698cf66bd21c5ea60c80c87412da7a6.jpg +0 -0
README.md
CHANGED
|
@@ -1,211 +1,19 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
Also, 👇
|
| 22 |
-
|
| 23 |
-
<a href="https://imgflip.com/i/98mhch"><img src="https://i.imgflip.com/98mhch.jpg" title="made at imgflip.com" alt="Funny meme about json output in demo"/></a>
|
| 24 |
-
|
| 25 |
-
As a prerequisite, you should run [this notebook](https://pyvespa.readthedocs.io/en/latest/examples/visual_pdf_rag_with_vespa_colpali_cloud.ipynb) to prepare the data and deploy the Vespa application.
|
| 26 |
-
|
| 27 |
-
## Setting up your .env variables
|
| 28 |
-
|
| 29 |
-
The following variables are required in your `.env` file for the application to be able to connect to the Vespa application and the Gemini API:
|
| 30 |
-
|
| 31 |
-
You can rename the `.env.example` file to `.env` and fill in the required values.
|
| 32 |
-
The other variables are optional, if you want to use mTLS authentication against the Vespa application.
|
| 33 |
-
|
| 34 |
-
```bash
|
| 35 |
-
VESPA_APP_TOKEN_URL=https://abcde.z.vespa-app.cloud
|
| 36 |
-
VESPA_CLOUD_SECRET_TOKEN=vespa_cloud_xxxxxxxx
|
| 37 |
-
GEMINI_API_KEY=asdf
|
| 38 |
-
```
|
| 39 |
-
|
| 40 |
-
If you want to deploy the application to Huggingface, you also need to set a `HF_TOKEN` variable, with write permissions.
|
| 41 |
-
This is personal, and must be created at [huggingface](https://huggingface.co/settings/tokens).
|
| 42 |
-
|
| 43 |
-
```bash
|
| 44 |
-
HF_TOKEN=hf_xxxxxxxxxx
|
| 45 |
-
```
|
| 46 |
-
|
| 47 |
-
## Setting up python environment
|
| 48 |
-
|
| 49 |
-
This application should work on Python 3.8 and above.
|
| 50 |
-
|
| 51 |
-
You can install the dependencies with `pip`, but we recommend using `uv`.
|
| 52 |
-
Skip to [Installing dependencies using `uv`](#installing-dependencies-using-uv) if you want to use `uv`.
|
| 53 |
-
|
| 54 |
-
### Installing dependencies using `pip`
|
| 55 |
-
|
| 56 |
-
You can install the dependencies with `pip`:
|
| 57 |
-
|
| 58 |
-
```bash
|
| 59 |
-
pip install -r src/requirements.txt
|
| 60 |
-
```
|
| 61 |
-
|
| 62 |
-
### Installing dependencies using `uv`
|
| 63 |
-
|
| 64 |
-
We recommend installing the amazing `uv` to manage your python environment:
|
| 65 |
-
See also [installation - uv docs](https://docs.astral.sh/uv/getting-started/installation/) for other installation options.
|
| 66 |
-
|
| 67 |
-
```bash
|
| 68 |
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 69 |
-
```
|
| 70 |
-
|
| 71 |
-
Then, create a virtual environment:
|
| 72 |
-
|
| 73 |
-
```bash
|
| 74 |
-
uv venv
|
| 75 |
-
```
|
| 76 |
-
|
| 77 |
-
Activate the virtual environment:
|
| 78 |
-
|
| 79 |
-
```bash
|
| 80 |
-
source .venv/bin/activate
|
| 81 |
-
```
|
| 82 |
-
|
| 83 |
-
Sync your virtual environment with the dependencies:
|
| 84 |
-
|
| 85 |
-
```bash
|
| 86 |
-
uv sync --extra dev
|
| 87 |
-
```
|
| 88 |
-
|
| 89 |
-
## Running the application locally
|
| 90 |
-
|
| 91 |
-
To run the application locally, you can change into the `src` directory and run:
|
| 92 |
-
|
| 93 |
-
```bash
|
| 94 |
-
python main.py
|
| 95 |
-
```
|
| 96 |
-
|
| 97 |
-
This will start a local server, and you can access the application at `http://localhost:7860`.
|
| 98 |
-
|
| 99 |
-
## Deploy to huggingface 🤗 spaces
|
| 100 |
-
|
| 101 |
-
### Compiling dependencies
|
| 102 |
-
|
| 103 |
-
Before a deploy, make sure to run this to compile the `uv` lock file to `requirements.txt` if you have made changes to the dependencies:
|
| 104 |
-
|
| 105 |
-
```bash
|
| 106 |
-
uv pip compile pyproject.toml -o src/requirements.txt
|
| 107 |
-
```
|
| 108 |
-
|
| 109 |
-
This will make sure that the dependencies in your `pyproject.toml` are compiled to the `requirements.txt` file, which is used by the huggingface space.
|
| 110 |
-
|
| 111 |
-
### Deploying to huggingface
|
| 112 |
-
|
| 113 |
-
Note that you need to set `HF_TOKEN` environment variable first.
|
| 114 |
-
This is personal, and must be created at [huggingface](https://huggingface.co/settings/tokens).
|
| 115 |
-
Make sure the token has `write` access.
|
| 116 |
-
Be aware that this will not delete existing files, only modify or add,
|
| 117 |
-
see [huggingface-cli](https://huggingface.co/docs/huggingface_hub/en/guides/upload#upload-from-the-cli) for more
|
| 118 |
-
information.
|
| 119 |
-
|
| 120 |
-
#### Update your space configuration
|
| 121 |
-
|
| 122 |
-
The `src/README.md` file contains the configuration for the space.
|
| 123 |
-
Feel free to update this file to match your own configuration - name, description, etc.
|
| 124 |
-
|
| 125 |
-
Note that we can actually use the `gradio` SDK of spaces, to serve FastHTML apps as well, as long as we serve the app on port `7860`.
|
| 126 |
-
See [Custom python spaces](https://huggingface.co/docs/hub/en/spaces-sdks-python) for more information.
|
| 127 |
-
|
| 128 |
-
#### Upload the files
|
| 129 |
-
|
| 130 |
-
To deploy, run
|
| 131 |
-
|
| 132 |
-
(Replace `vespa-engine/colpali-vespa-visual-retrieval` with your own huggingface user/repo name, does not need to exist beforehand)
|
| 133 |
-
|
| 134 |
-
```bash
|
| 135 |
-
huggingface-cli upload vespa-engine/colpali-vespa-visual-retrieval src . --repo-type=space
|
| 136 |
-
```
|
| 137 |
-
|
| 138 |
-
Note that we upload only the `src` directory.
|
| 139 |
-
|
| 140 |
-
## Development
|
| 141 |
-
|
| 142 |
-
This section applies if you want to make changes to the web app.
|
| 143 |
-
|
| 144 |
-
### Adding dependencies
|
| 145 |
-
|
| 146 |
-
To add dependencies, you can add them to the `pyproject.toml` file and run:
|
| 147 |
-
|
| 148 |
-
```bash
|
| 149 |
-
uv compile
|
| 150 |
-
```
|
| 151 |
-
|
| 152 |
-
and then sync the dependencies:
|
| 153 |
-
|
| 154 |
-
```bash
|
| 155 |
-
uv sync --extra dev
|
| 156 |
-
```
|
| 157 |
-
|
| 158 |
-
### Making changes to CSS
|
| 159 |
-
|
| 160 |
-
To make changes to output.css apply, run
|
| 161 |
-
|
| 162 |
-
```bash
|
| 163 |
-
shad4fast watch # watches all files passed through the tailwind.config.js content section
|
| 164 |
-
|
| 165 |
-
shad4fast build # minifies the current output.css file to reduce bundle size in production.
|
| 166 |
-
```
|
| 167 |
-
|
| 168 |
-
### Instructions on creating and feeding the full dataset
|
| 169 |
-
|
| 170 |
-
This section is only relevant if you want to create and feed the full dataset to Vespa.
|
| 171 |
-
The notebook referenced in the beginning of this readme should be sufficient if you just want to spin up a scaled down version of the demo.
|
| 172 |
-
|
| 173 |
-
#### Prepare data and Vespa application
|
| 174 |
-
|
| 175 |
-
First, install `uv`:
|
| 176 |
-
|
| 177 |
-
```bash
|
| 178 |
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 179 |
-
```
|
| 180 |
-
|
| 181 |
-
Then, run:
|
| 182 |
-
|
| 183 |
-
```bash
|
| 184 |
-
uv sync --extra dev --extra feed
|
| 185 |
-
```
|
| 186 |
-
|
| 187 |
-
#### Converting to notebook
|
| 188 |
-
|
| 189 |
-
If you want to run the `prepare_feed_deploy.py` as a notebook, you can convert it using `jupytext`:
|
| 190 |
-
|
| 191 |
-
Convert the `prepare_feed_deploy.py` to notebook to:
|
| 192 |
-
|
| 193 |
-
```bash
|
| 194 |
-
jupytext --to notebook prepare_feed_deploy.py
|
| 195 |
-
```
|
| 196 |
-
|
| 197 |
-
And launch a Jupyter instance with:
|
| 198 |
-
|
| 199 |
-
```bash
|
| 200 |
-
uv run --with jupyter jupyter lab
|
| 201 |
-
```
|
| 202 |
-
|
| 203 |
-
## Credits
|
| 204 |
-
|
| 205 |
-
Huge thanks to the amazing projects that made it a joy to create this demo 🙏🙌
|
| 206 |
-
|
| 207 |
-
- Freeing us from python dependency hell - [uv](https://astral.sh/uv/)
|
| 208 |
-
- Allowing us to build **beautiful** full stack web apps in Python [FastHTML](https://fastht.ml/)
|
| 209 |
-
- Introducing the ColPali architecture - [ColPali](https://huggingface.co/vidore/colpali-v1.2)
|
| 210 |
-
- Adding `shadcn` components to FastHTML - [Shad4Fast](https://www.shad4fasthtml.com/)
|
| 211 |
-
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: ColPali 🤝 Vespa - Visual Retrieval
|
| 3 |
+
short_description: Visual Retrieval with ColPali and Vespa
|
| 4 |
+
emoji: 👀
|
| 5 |
+
colorFrom: purple
|
| 6 |
+
colorTo: blue
|
| 7 |
+
sdk: gradio
|
| 8 |
+
sdk_version: 4.44.0
|
| 9 |
+
app_file: main.py
|
| 10 |
+
pinned: false
|
| 11 |
+
license: apache-2.0
|
| 12 |
+
suggested_hardware: t4-small
|
| 13 |
+
models:
|
| 14 |
+
- vidore/colpaligemma-3b-pt-448-base
|
| 15 |
+
- vidore/colpali-v1.2
|
| 16 |
+
preload_from_hub:
|
| 17 |
+
- vidore/colpaligemma-3b-pt-448-base config.json,model-00001-of-00002.safetensors,model-00002-of-00002.safetensors,model.safetensors.index.json,preprocessor_config.json,special_tokens_map.json,tokenizer.json,tokenizer_config.json 12c59eb7e23bc4c26876f7be7c17760d5d3a1ffa
|
| 18 |
+
- vidore/colpali-v1.2 adapter_config.json,adapter_model.safetensors,preprocessor_config.json,special_tokens_map.json,tokenizer.json,tokenizer_config.json 9912ce6f8a462d8cf2269f5606eabbd2784e764f
|
| 19 |
+
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/vespa_app.py
CHANGED
|
@@ -376,10 +376,11 @@ class VespaQueryClient:
|
|
| 376 |
async def get_suggestions(self, query: str) -> list:
|
| 377 |
async with self.app.asyncio(connections=1) as session:
|
| 378 |
start = time.perf_counter()
|
| 379 |
-
yql = f'select questions from {self.VESPA_SCHEMA_NAME} where questions matches "{query}"
|
| 380 |
response: VespaQueryResponse = await session.query(
|
| 381 |
body={
|
| 382 |
"yql": yql,
|
|
|
|
| 383 |
"ranking": "unranked",
|
| 384 |
"presentation.timing": True,
|
| 385 |
"presentation.summary": "suggestions",
|
|
@@ -401,8 +402,15 @@ class VespaQueryClient:
|
|
| 401 |
for result in search_results
|
| 402 |
if "questions" in result["fields"]
|
| 403 |
]
|
| 404 |
-
|
| 405 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
|
| 407 |
def get_rank_profile(self, ranking: str, sim_map: bool) -> str:
|
| 408 |
if sim_map:
|
|
|
|
| 376 |
async def get_suggestions(self, query: str) -> list:
|
| 377 |
async with self.app.asyncio(connections=1) as session:
|
| 378 |
start = time.perf_counter()
|
| 379 |
+
yql = f'select questions from {self.VESPA_SCHEMA_NAME} where questions matches (".*{query}.*")'
|
| 380 |
response: VespaQueryResponse = await session.query(
|
| 381 |
body={
|
| 382 |
"yql": yql,
|
| 383 |
+
"query": query,
|
| 384 |
"ranking": "unranked",
|
| 385 |
"presentation.timing": True,
|
| 386 |
"presentation.summary": "suggestions",
|
|
|
|
| 402 |
for result in search_results
|
| 403 |
if "questions" in result["fields"]
|
| 404 |
]
|
| 405 |
+
for q in questions:
|
| 406 |
+
print(q)
|
| 407 |
+
unique_questions = set([item for sublist in questions for item in sublist])
|
| 408 |
+
|
| 409 |
+
# remove an artifact from our data generation
|
| 410 |
+
if "string" in unique_questions:
|
| 411 |
+
unique_questions.remove("string")
|
| 412 |
+
|
| 413 |
+
return list(unique_questions)
|
| 414 |
|
| 415 |
def get_rank_profile(self, ranking: str, sim_map: bool) -> str:
|
| 416 |
if sim_map:
|
main.py
CHANGED
|
@@ -220,7 +220,8 @@ async def get(session, request, query: str, ranking: str):
|
|
| 220 |
f"Search results fetched in {end - start:.2f} seconds. Vespa search time: {result['timing']['searchtime']}"
|
| 221 |
)
|
| 222 |
search_time = result["timing"]["searchtime"]
|
| 223 |
-
total_count
|
|
|
|
| 224 |
|
| 225 |
search_results = vespa_app.results_to_search_results(result, idx_to_token)
|
| 226 |
|
|
|
|
| 220 |
f"Search results fetched in {end - start:.2f} seconds. Vespa search time: {result['timing']['searchtime']}"
|
| 221 |
)
|
| 222 |
search_time = result["timing"]["searchtime"]
|
| 223 |
+
# Safely get total_count with a default of 0
|
| 224 |
+
total_count = result.get("root", {}).get("fields", {}).get("totalCount", 0)
|
| 225 |
|
| 226 |
search_results = vespa_app.results_to_search_results(result, idx_to_token)
|
| 227 |
|
static/full_images/012200fb9d07b72da276db7e9d499a2f.jpg
ADDED
|
static/full_images/088177a2b300ed9e9cd8d936edb7b5ca.jpg
ADDED
|
static/full_images/0d9a8f0fa595513774d94d6058aa3c27.jpg
ADDED
|
static/full_images/0f2073449af49b9a766d269bda7aa2ec.jpg
ADDED
|
static/full_images/15610e06e17b391f9d6212d4a704d1c8.jpg
ADDED
|
static/full_images/176768b9dda73154bbbe67983b07ef7b.jpg
ADDED
|
static/full_images/189aa5523cce7b3e37b336aa1327bae8.jpg
ADDED
|
static/full_images/23b1e0404920ce0f0257eb0e8190c557.jpg
ADDED
|
static/full_images/2c5ab4a0f12fa673c17f0283f698bdb9.jpg
ADDED
|
static/full_images/2e70dc0cf1e35b3f11f6d94017a17110.jpg
ADDED
|
static/full_images/31b6ab7aae4796b0d6200380b05b25f0.jpg
ADDED
|
static/full_images/37002ca88b2a5600b5ec7dfd03900d84.jpg
ADDED
|
static/full_images/3cd17414305381977eae7ff3d30de6dc.jpg
ADDED
|
static/full_images/3d0c05ab1db804e856a25f473dc5149d.jpg
ADDED
|
static/full_images/41ff192952c5e93adebbc1852c748985.jpg
ADDED
|
static/full_images/42adeab8461f18a692708f37444d4dee.jpg
ADDED
|
static/full_images/44bce8cd76f96db9be93d366c2a36fd3.jpg
ADDED
|
static/full_images/45c159551a8840a4528eb2034d562abd.jpg
ADDED
|
static/full_images/46a9cf839d8c07f740c88020e1459d2f.jpg
ADDED
|
static/full_images/473639db0c76b6e80664775066bd2a7b.jpg
ADDED
|
static/full_images/47b81a110672e649487aeb708f1277d5.jpg
ADDED
|
static/full_images/4af459669551f34d1542e9734c1722db.jpg
ADDED
|
static/full_images/4f7a37046626de54fdf189106371eea2.jpg
ADDED
|
static/full_images/5257e0dc94a52bbf0dff16f4b481772b.jpg
ADDED
|
static/full_images/5466c54401a63372bda9bf0b8586ced9.jpg
ADDED
|
static/full_images/547f1ed03149aee493b22a192146b651.jpg
ADDED
|
static/full_images/5913b08b81182be02056225d19225039.jpg
ADDED
|
static/full_images/64060791c89655d280a6a01eea8a8a47.jpg
ADDED
|
static/full_images/645d0f26220a092ffc0de138c72927a8.jpg
ADDED
|
static/full_images/694dfbca150f4cac83e27d17f0b04bbd.jpg
ADDED
|
static/full_images/6a14ac1f65b59b0cfdc65ecc6bd57b55.jpg
ADDED
|
static/full_images/6b1f502ac819b8a5ba2e65f8e56f22b8.jpg
ADDED
|
static/full_images/7051b5a4804d48045fff84866923d34a.jpg
ADDED
|
static/full_images/7364ccb5e7ff145e56014d70ec0295b4.jpg
ADDED
|
static/full_images/743dd0b209db20acac00090e34f66d1e.jpg
ADDED
|
static/full_images/7485ce436c35173ee7c379ad67754ae7.jpg
ADDED
|
static/full_images/74f26585a4ecb41de76e8cb906811244.jpg
ADDED
|
static/full_images/75a1a2c786e848e7e043f2c3b759ad73.jpg
ADDED
|
static/full_images/76a4708381e45c35b33793dff2791c7c.jpg
ADDED
|
static/full_images/7898c6c68d78f85ed8d8d92c406a3850.jpg
ADDED
|
static/full_images/7901d8397e67307fa7ccbac2e1dcaba4.jpg
ADDED
|
static/full_images/7a1546e2ad050e8a915cbcbfae7a991f.jpg
ADDED
|
static/full_images/7cf284e8ccc5a68b4a92eca9b1176707.jpg
ADDED
|
static/full_images/83929419be13d5a71b23bfd71344fe0b.jpg
ADDED
|
static/full_images/8403e1a2fdb89eb1e96227427c8b833c.jpg
ADDED
|
static/full_images/8554ad2b2ea96d1f363f0470fff572d5.jpg
ADDED
|
static/full_images/8698cf66bd21c5ea60c80c87412da7a6.jpg
ADDED
|