DanbooruSearch / cli.py
SAkizuki's picture
Upload cli.py with huggingface_hub
51f0992
"""
cli.py
โ”€โ”€โ”€โ”€โ”€โ”€
ๅ‘ฝไปค่กŒ้€‚้…ๅฑ‚๏ผˆๅฏ้€‰๏ผ‰ใ€‚
ๅญๅ‘ฝไปค๏ผš
search ่ฏญไน‰ๆœ็ดขๆ ‡็ญพ
related ๅŸบไบŽๅ…ฑ็Žฐ่กจๆŸฅๅ…ณ่”ๆŽจ่
็”จๆณ•๏ผš
python cli.py search "็™ฝ่‰ฒๆฐดๆ‰‹ๆœ็š„ๅฅณๅญฉ" --limit 10 --no-nsfw
python cli.py related "white_serafuku,sailor_collar" --limit 20
python cli.py related "white_serafuku,sailor_collar" --no-nsfw --show-sources
"""
import argparse
import asyncio
from core.engine import DanbooruTagger
from core.models import SearchRequest
# โ”€โ”€ search โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
async def cmd_search(args):
tagger = await DanbooruTagger.get_instance()
request = SearchRequest(
query=args.query,
top_k=args.top_k,
limit=args.limit,
popularity_weight=args.weight,
show_nsfw=not args.no_nsfw,
use_segmentation=not args.no_seg,
)
resp = await asyncio.to_thread(tagger.search, request)
print(f"\n{'='*60}")
print(f"ๆŸฅ่ฏข๏ผš{args.query} | ๅ…ฑ {len(resp.results)} ๆก็ป“ๆžœ")
print(f"{'='*60}")
print(f"ๆŽจ่ Prompt๏ผš\n {resp.tags_sfw if args.no_nsfw else resp.tags_all}\n")
for r in resp.results:
nsfw_mark = "๐Ÿ”ด" if r.nsfw == '1' else "๐ŸŸข"
print(f" {nsfw_mark} [{r.final_score:.3f}] {r.tag:<30} {r.cn_name[:20]:<20} {r.category}")
# โ”€โ”€ related โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
async def cmd_related(args):
seed_tags = [t.strip() for t in args.tags.split(',') if t.strip()]
if not seed_tags:
print("้”™่ฏฏ๏ผš่ฏทๆไพ›่‡ณๅฐ‘ไธ€ไธช็งๅญๆ ‡็ญพ๏ผŒๅคšไธชๆ ‡็ญพไปฅ้€—ๅทๅˆ†้š”ใ€‚")
return
tagger = await DanbooruTagger.get_instance()
results = await asyncio.to_thread(
tagger.get_related,
seed_tags,
set(seed_tags), # exclude ็งๅญๆ ‡็ญพ่‡ช่บซ
args.limit,
not args.no_nsfw,
)
if not results:
print("ๆœชๆ‰พๅˆฐๅ…ณ่”ๆŽจ่๏ผˆๅ…ฑ็Žฐ่กจๅฏ่ƒฝๆœชๅŠ ่ฝฝ๏ผŒๆˆ–็งๅญๆ ‡็ญพไธๅœจๅบ“ไธญ๏ผ‰ใ€‚")
return
print(f"\n{'='*60}")
print(f"็งๅญๆ ‡็ญพ๏ผš{', '.join(seed_tags)} | ๅ…ฑ {len(results)} ๆกๆŽจ่")
print(f"{'='*60}")
# ่พ“ๅ‡บ้€—ๅทๅˆ†้š”็š„ๆ ‡็ญพไธฒ๏ผˆๆ–นไพฟ็›ดๆŽฅๅคๅˆถไฝฟ็”จ๏ผ‰
tag_list = [r.tag for r in results if not (r.nsfw == '1' and args.no_nsfw)]
print(f"ๆŽจ่ๆ ‡็ญพ๏ผš\n {', '.join(tag_list)}\n")
# ๆ˜Ž็ป†่กจ
for r in results:
if r.nsfw == '1' and args.no_nsfw:
continue
nsfw_mark = "๐Ÿ”ด" if r.nsfw == '1' else "๐ŸŸข"
sources_str = f" โ† {', '.join(r.sources)}" if args.show_sources else ""
print(
f" {nsfw_mark} [{r.cooc_score:.3f}] {r.tag:<30}"
f" {r.cn_name[:20]:<20} {r.category}"
f" (ๅ…ฑ็Žฐ:{r.cooc_count:,}){sources_str}"
)
# โ”€โ”€ ๅ…ฅๅฃ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
async def main():
parser = argparse.ArgumentParser(
description="Danbooru Tag CLI Searcher",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
็คบไพ‹๏ผš
python cli.py search "็™ฝ่‰ฒๆฐดๆ‰‹ๆœ็š„ๅฅณๅญฉ" --limit 10
python cli.py related "white_serafuku,sailor_collar"
python cli.py related "white_serafuku" --limit 30 --no-nsfw --show-sources
""",
)
sub = parser.add_subparsers(dest='cmd', required=True)
# โ”€โ”€ search ๅญๅ‘ฝไปค โ”€โ”€
p_search = sub.add_parser('search', help='่ฏญไน‰ๆœ็ดขๆ ‡็ญพ')
p_search.add_argument('query', help='ๆœ็ดข่ฏ๏ผˆๆ”ฏๆŒไธญ่‹ฑๆ–‡่‡ช็„ถ่ฏญ่จ€๏ผ‰')
p_search.add_argument('--top-k', type=int, default=5, help='ๆฏๅฑ‚่ฟ”ๅ›žๆ•ฐ้‡๏ผˆ้ป˜่ฎค 5๏ผ‰')
p_search.add_argument('--limit', type=int, default=20, help='็ป“ๆžœไธŠ้™๏ผˆ้ป˜่ฎค 20๏ผ‰')
p_search.add_argument('--weight', type=float, default=0.15, help='็ƒญๅบฆๆƒ้‡๏ผˆ้ป˜่ฎค 0.15๏ผ‰')
p_search.add_argument('--no-nsfw', action='store_true', help='่ฟ‡ๆปค NSFW ๅ†…ๅฎน')
p_search.add_argument('--no-seg', action='store_true', help='็ฆ็”จๆ™บ่ƒฝๅˆ†่ฏ')
# โ”€โ”€ related ๅญๅ‘ฝไปค โ”€โ”€
p_related = sub.add_parser('related', help='ๅŸบไบŽๅ…ฑ็Žฐ่กจๆŸฅๅ…ณ่”ๆŽจ่')
p_related.add_argument('tags', help='็งๅญๆ ‡็ญพ๏ผŒไปฅ่‹ฑๆ–‡้€—ๅทๅˆ†้š”๏ผˆๅฆ‚ white_serafuku,sailor_collar๏ผ‰')
p_related.add_argument('--limit', type=int, default=50, help='ๆŽจ่็ป“ๆžœไธŠ้™๏ผˆ้ป˜่ฎค 50๏ผ‰')
p_related.add_argument('--no-nsfw', action='store_true', help='่ฟ‡ๆปค NSFW ๅ†…ๅฎน')
p_related.add_argument('--show-sources', action='store_true', help='ๆ˜พ็คบๆฏๆกๆŽจ่็”ฑๅ“ชไธช็งๅญ่งฆๅ‘')
args = parser.parse_args()
if args.cmd == 'search':
await cmd_search(args)
elif args.cmd == 'related':
await cmd_related(args)
if __name__ == "__main__":
asyncio.run(main())