Plana-Archive commited on
Commit
f41d6fa
·
verified ·
1 Parent(s): 9ee09fc

Upload search_image_by_image_or_text/app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. search_image_by_image_or_text/app.py +178 -0
search_image_by_image_or_text/app.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from collections import defaultdict
4
+ from typing import Dict, List
5
+
6
+ import faiss
7
+ import gradio as gr
8
+ import numpy as np
9
+ from cheesechaser.datapool import (
10
+ AnimePicturesWebpDataPool,
11
+ DanbooruNewestWebpDataPool,
12
+ GelbooruWebpDataPool,
13
+ KonachanWebpDataPool,
14
+ Rule34WebpDataPool,
15
+ YandeWebpDataPool,
16
+ ZerochanWebpDataPool,
17
+ )
18
+ from hfutils.operate import get_hf_client, get_hf_fs
19
+ from hfutils.utils import TemporaryDirectory
20
+ from imgutils.generic import siglip
21
+ from imgutils.utils import ts_lru_cache
22
+ from PIL import Image
23
+
24
+ from pools import quick_webp_pool
25
+
26
+ _SIGLIP_REPO_ID = "deepghs/siglip_beta"
27
+ _INDEX_REPO_ID = 'deepghs/anime_sites_indices'
28
+
29
+ hf_fs = get_hf_fs()
30
+ hf_client = get_hf_client()
31
+
32
+ _DEFAULT_MODEL_NAME = 'SwinV2_v3_danbooru_8005009_4GB'
33
+ _ALL_MODEL_NAMES = [
34
+ os.path.dirname(os.path.relpath(path, _INDEX_REPO_ID))
35
+ for path in hf_fs.glob(f'{_INDEX_REPO_ID}/*/knn.index')
36
+ ]
37
+
38
+ _SITE_CLS = {
39
+ 'danbooru': DanbooruNewestWebpDataPool,
40
+ 'yandere': YandeWebpDataPool,
41
+ 'zerochan': ZerochanWebpDataPool,
42
+ 'gelbooru': GelbooruWebpDataPool,
43
+ 'konachan': KonachanWebpDataPool,
44
+ 'anime_pictures': AnimePicturesWebpDataPool,
45
+ 'rule34': Rule34WebpDataPool,
46
+ }
47
+
48
+
49
+ def _get_from_ids(site_name: str, ids: List[int]) -> Dict[int, Image.Image]:
50
+ with TemporaryDirectory() as td:
51
+ site_cls = _SITE_CLS.get(site_name) or quick_webp_pool(site_name, 3)
52
+ datapool = site_cls()
53
+ datapool.batch_download_to_directory(
54
+ resource_ids=ids,
55
+ dst_dir=td,
56
+ )
57
+
58
+ retval = {}
59
+ for file in os.listdir(td):
60
+ id_ = int(os.path.splitext(file)[0])
61
+ image = Image.open(os.path.join(td, file))
62
+ image.load()
63
+ retval[id_] = image
64
+
65
+ return retval
66
+
67
+
68
+ def _get_from_raw_ids(ids: List[str]) -> Dict[str, Image.Image]:
69
+ _sites = defaultdict(list)
70
+ for id_ in ids:
71
+ site_name, num_id = id_.rsplit('_', maxsplit=1)
72
+ num_id = int(num_id)
73
+ _sites[site_name].append(num_id)
74
+
75
+ _retval = {}
76
+ for site_name, site_ids in _sites.items():
77
+ _retval.update({
78
+ f'{site_name}_{id_}': image
79
+ for id_, image in _get_from_ids(site_name, site_ids).items()
80
+ })
81
+ return _retval
82
+
83
+
84
+ @ts_lru_cache(maxsize=3)
85
+ def _get_index_info(repo_id: str, model_name: str):
86
+ image_ids = np.load(hf_client.hf_hub_download(
87
+ repo_id=repo_id,
88
+ repo_type='model',
89
+ filename=f'{model_name}/ids.npy',
90
+ ))
91
+ knn_index = faiss.read_index(hf_client.hf_hub_download(
92
+ repo_id=repo_id,
93
+ repo_type='model',
94
+ filename=f'{model_name}/knn.index',
95
+ ))
96
+
97
+ config = json.loads(open(hf_client.hf_hub_download(
98
+ repo_id=repo_id,
99
+ repo_type='model',
100
+ filename=f'{model_name}/infos.json',
101
+ )).read())["index_param"]
102
+ faiss.ParameterSpace().set_index_parameters(knn_index, config)
103
+ return image_ids, knn_index
104
+
105
+
106
+ def search(model_name: str, img_input, str_input: str, n_neighbours: int):
107
+ images_ids, knn_index = _get_index_info(_INDEX_REPO_ID, model_name)
108
+
109
+ if str_input == "":
110
+ embeddings = siglip.siglip_image_encode(
111
+ img_input,
112
+ repo_id=_SIGLIP_REPO_ID,
113
+ model_name="smilingwolf/siglip_swinv2_base_2025_02_22_18h56m54s",
114
+ fmt="embeddings",
115
+ )
116
+ else:
117
+ embeddings = siglip.siglip_text_encode(
118
+ str_input,
119
+ repo_id=_SIGLIP_REPO_ID,
120
+ model_name="smilingwolf/siglip_swinv2_base_2025_02_22_18h56m54s",
121
+ fmt="embeddings",
122
+ )
123
+
124
+ # In the model, the "embeddings" output node is already normalized.
125
+ # Ask for the "encodings" output if you want the raw logits
126
+
127
+ dists, indexes = knn_index.search(embeddings, k=n_neighbours)
128
+ neighbours_ids = images_ids[indexes][0]
129
+
130
+ captions = []
131
+ images = []
132
+ ids_to_images = _get_from_raw_ids(neighbours_ids)
133
+ for image_id, dist in zip(neighbours_ids, dists[0]):
134
+ if image_id in ids_to_images:
135
+ images.append(ids_to_images[image_id])
136
+ captions.append(f"{image_id}/{dist:.2f}")
137
+
138
+ return list(zip(images, captions))
139
+
140
+
141
+ if __name__ == "__main__":
142
+ with gr.Blocks() as demo:
143
+ with gr.Row():
144
+ with gr.Column():
145
+ img_input = gr.Image(type="pil", image_mode="RGBA", label="Image input")
146
+ str_input = gr.Textbox(label="Text input (leave empty to use image input)")
147
+ with gr.Column():
148
+ with gr.Row():
149
+ n_model = gr.Dropdown(
150
+ choices=_ALL_MODEL_NAMES,
151
+ value=_DEFAULT_MODEL_NAME,
152
+ label='Index to Use',
153
+ )
154
+ with gr.Row():
155
+ n_neighbours = gr.Slider(
156
+ minimum=1,
157
+ maximum=50,
158
+ value=20,
159
+ step=1,
160
+ label="# of images",
161
+ )
162
+ find_btn = gr.Button("Find similar images")
163
+
164
+ with gr.Row():
165
+ similar_images = gr.Gallery(label="Similar images", columns=[5])
166
+
167
+ find_btn.click(
168
+ fn=search,
169
+ inputs=[
170
+ n_model,
171
+ img_input,
172
+ str_input,
173
+ n_neighbours,
174
+ ],
175
+ outputs=[similar_images],
176
+ )
177
+
178
+ demo.queue().launch()