nekoko commited on
Commit
1c2b077
·
1 Parent(s): 802a494

feat: Sticker DB

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* 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
 
 
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
36
+ *.db filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ignore node_modules directory
2
+ node_modules/
3
+
4
+ # Ignore environment variables file
5
+ .env
6
+
7
+ # Ignore build output directory
8
+ dist/
9
+
10
+ # Ignore Python cache directories
11
+ __pycache__/
12
+ *.pyc
13
+
14
+ # Ignore IDE specific files
15
+ .vscode/
16
+ .idea/
17
+
18
+ # Ignore local development files
19
+ *.local
20
+ .cache
21
+
22
+ # Ignore logs and databases
23
+ *.log
24
+ *.sqlite
25
+
26
+ # Ignore macOS specific files
27
+ .DS_Store
28
+
29
+ # Ignore temp files
30
+ *.tmp
31
+ *.temp
.sticker.db.lock ADDED
File without changes
Dockerfile ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+ WORKDIR /app
3
+ COPY requirements.txt .
4
+ # RUN apt-get update && apt-get install -y gcc python3-dev
5
+ RUN pip install -r requirements.txt
6
+ # RUN pip install --no-cache-dir -r requirements.txt
7
+ COPY . .
8
+ COPY ./sticker.db /tmp/sticker.db
9
+
10
+ ENV HF_HOME=/tmp/.cache
11
+
12
+
13
+ CMD python main.py
14
+
15
+ EXPOSE 7860
README.md CHANGED
@@ -4,7 +4,23 @@ emoji: 📚
4
  colorFrom: red
5
  colorTo: blue
6
  sdk: docker
 
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  colorFrom: red
5
  colorTo: blue
6
  sdk: docker
7
+ sdk_version: 4.19.0
8
+ app_port: 7860
9
  pinned: false
10
  ---
11
 
12
+ ## 环境变量配置
13
+
14
+ - COZE_API_KEY:通过 Space Settings -> Secrets 添加
15
+
16
+ ## 功能特性
17
+
18
+ ✅ 基于语义的表情包搜索
19
+ 🖼️ 支持批量上传表情包
20
+ 🔍 多语言语义理解(支持中英文)
21
+ ⚡ FAISS 实时语义检索
22
+
23
+ ## 参考资料
24
+
25
+ 向量化模型:
26
+ https://huggingface.co/spaces/mteb/leaderboard
app/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # 初始化app包
app/api.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import OpenAI
2
+ from app.config import DEEPSEEK_API_KEY
3
+
4
+ def get_chat_completion(
5
+ user_prompt: str,
6
+ system_prompt: str = "You are a helpful AI assistant.",
7
+ model: str = "deepseek/deepseek-chat-v3-0324:free",
8
+ api_key: str = DEEPSEEK_API_KEY,
9
+ ) -> str:
10
+ """
11
+ Get chat completion from DeepSeek model via OpenRouter API.
12
+
13
+ Args:
14
+ user_prompt: The user's input prompt
15
+ system_prompt: The system role prompt (default is generic assistant)
16
+ model: The model to use (default is DeepSeek-V2.5)
17
+ api_key: API key for OpenRouter (default from config)
18
+
19
+ Returns:
20
+ The generated response from the model
21
+ """
22
+ client = OpenAI(
23
+ base_url="https://openrouter.ai/api/v1",
24
+ api_key=api_key,
25
+ )
26
+
27
+ headers = {
28
+ "HTTP-Referer": 'https://huggingface.co/spaces/Nekoko/NekoAI-Lab',
29
+ "X-Title": "Meme-Search"
30
+ }
31
+
32
+ completion = client.chat.completions.create(
33
+ extra_headers=headers,
34
+ model=model,
35
+ messages=[
36
+ {"role": "system", "content": system_prompt},
37
+ {"role": "user", "content": user_prompt},
38
+ ],
39
+ )
40
+
41
+ content = completion.choices[0].message.content
42
+ print('>>>> LLM Response', content)
43
+ return content
44
+
45
+
46
+ # Example usage:
47
+ if __name__ == "__main__":
48
+ response = get_chat_completion(
49
+ user_prompt="What's the capital of France?",
50
+ system_prompt="You are a knowledgeable geography assistant."
51
+ )
52
+ print(response)
app/config.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ # 应用配置
4
+ DATASET_ID = "Nekoko/StickerSet"
5
+ COZE_API_TOKEN = os.getenv('COZE_API_TOKEN')
6
+ HUGGING_FACE_TOKEN = os.getenv('HUGGING_FACE_TOKEN')
7
+ DEEPSEEK_API_KEY = os.getenv('DEEPSEEK_API_KEY')
8
+ MILVUS_DB_FILE = os.getenv('MILVUS_DB_FILE', "./sticker.db")
9
+ MILVUS_DB_URL = os.getenv('MILVUS_DB_URL', "./sticker.db")
10
+ MILVUS_DB_TOKEN = os.getenv('MILVUS_DB_TOKEN', "")
11
+ EMBEDDING_MODEL = 'shibing624/text2vec-base-chinese'
12
+ PUBLIC_URL = os.getenv('PUBLIC_URL')
13
+
14
+ STICKER_RERANKING_SYSTEM_PROMPT = """
15
+ ## 角色
16
+ 你是专业的表情包搜索助手,能找到最符合用户关键词的表情包,并为给定表情包列表中各表情包的关键词匹配度打分(0 - 1)并排序。
17
+ ## 回复示例:
18
+ [{ "reason": "判断的理由", "sticker_id": "1", "score": 0.8,},
19
+ { "reason": "判断的理由", "sticker_id": "2", "score": 0.3,}]
20
+
21
+ ## 功能: 分析相关性
22
+ 1. 评估表情包列表中表情包描述与关键词的匹配度,给出0到1的评分。
23
+ 2. 给出判断的理由(中文)
24
+
25
+ ## 限制
26
+ - 仅处理表情包搜索相关内容,不答无关问题,分清楚关键词和表情包列表。
27
+ - 请只输出纯JSON格式,不要包含任何Markdown标记如```json或```。
28
+ """
29
+
30
+
31
+ # 服务器配置
32
+ HOST = "0.0.0.0"
33
+ PORT = 7860
app/database.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pymilvus import MilvusClient
2
+ from sentence_transformers import SentenceTransformer
3
+ from typing import List, Dict, Any, Optional, Union
4
+ import logging
5
+
6
+ from app.config import MILVUS_DB_URL, MILVUS_DB_TOKEN, EMBEDDING_MODEL, DATASET_ID
7
+
8
+ # 配置日志
9
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class Database:
14
+ """数据库操作类,处理与Milvus的交互"""
15
+
16
+ def __init__(self):
17
+ self.client = MilvusClient(
18
+ uri = MILVUS_DB_URL,
19
+ token= MILVUS_DB_TOKEN)
20
+ self.model = SentenceTransformer(EMBEDDING_MODEL, trust_remote_code=True)
21
+ print('初始化模型完成',self.model)
22
+ self.collection_name = "stickers"
23
+
24
+ def init_collection(self) -> bool:
25
+ """初始化 Milvus 数据库"""
26
+ try:
27
+ print('初始化 Milvus 数据库', self.client.list_collections())
28
+ if not len(self.client.list_collections()) > 0:
29
+ self.client.create_collection(
30
+ collection_name=self.collection_name,
31
+ dimension=768,
32
+ primary_field="id",
33
+ auto_id=True
34
+ )
35
+ self.client.create_index(
36
+ collection_name=self.collection_name,
37
+ index_type="IVF_SQ8",
38
+ metric_type="COSINE",
39
+ params={"nlist": 128},
40
+ index_params={}
41
+ )
42
+ logger.info(f"Collection initialized: {self.collection_name}")
43
+ print('初始化 Milvus 数据库成功', self.client.list_collections())
44
+ return True
45
+ except Exception as e:
46
+ logger.error(f"Collection initialization failed: {str(e)}")
47
+ return False
48
+
49
+ def encode_text(self, text: str) -> List[float]:
50
+ """将文本编码为向量"""
51
+ return self.model.encode(text).tolist()
52
+
53
+ def store_sticker(self, title: str, description: str, tags: Union[str, List[str]], file_path: str, image_hash: str = None) -> bool:
54
+ """存储贴纸数据到Milvus"""
55
+ try:
56
+ vector = self.encode_text(description)
57
+
58
+ # 处理标签格式
59
+ if isinstance(tags, str):
60
+ tags = tags.split(",")
61
+
62
+ logger.info(f"Storing to Milvus - title: {title}, description: {description}, file_path: {file_path}, tags: {tags}, image_hash: {image_hash}")
63
+ self.client.insert(
64
+ collection_name=self.collection_name,
65
+ data=[{
66
+ "vector": vector,
67
+ "title": title,
68
+ "description": description,
69
+ "tags": tags,
70
+ "file_name": file_path,
71
+ "image_hash": image_hash
72
+ }]
73
+ )
74
+ logger.info("Storing to Milvus Success ✅")
75
+ return True
76
+ except Exception as e:
77
+ logger.error(f"Failed to store sticker: {str(e)}")
78
+ return False
79
+
80
+ def search_stickers(self, description: str, limit: int = 2) -> List[Dict[str, Any]]:
81
+ """搜索贴纸"""
82
+ if not description:
83
+ return []
84
+
85
+ try:
86
+ text_vector = self.encode_text(description)
87
+ logger.info(f"Searching Milvus - query: {description}, limit: {limit}")
88
+
89
+ results = self.client.search(
90
+ collection_name=self.collection_name,
91
+ data=[text_vector],
92
+ limit=limit,
93
+ search_params={
94
+ "metric_type": "COSINE",
95
+ },
96
+ output_fields=["title", "description", "tags", "file_name"],
97
+ )
98
+
99
+ logger.info(f"Search Result: {results}")
100
+ return results[0]
101
+ except Exception as e:
102
+ logger.error(f"Search failed: {str(e)}")
103
+ return []
104
+
105
+ def get_all_stickers(self, limit: int = 1000) -> List[Dict[str, Any]]:
106
+ """获取所有贴纸"""
107
+ try:
108
+ results = self.client.query(
109
+ collection_name=self.collection_name,
110
+ filter="",
111
+ limit=limit,
112
+ output_fields=["title", "description", "tags", "file_name", "image_hash"]
113
+ )
114
+
115
+ logger.info(f"Query All Stickers - limit: {limit}, results count: {len(results)}")
116
+ return results
117
+ except Exception as e:
118
+ logger.error(f"Failed to get all stickers: {str(e)}")
119
+ return []
120
+
121
+ def check_image_exists(self, image_hash: str) -> bool:
122
+ """检查文件名是否已存在"""
123
+ try:
124
+ results = self.client.query(
125
+ collection_name=self.collection_name,
126
+ filter=f"image_hash == '{image_hash}'",
127
+ limit=1,
128
+ output_fields=["file_name", "image_hash"]
129
+ )
130
+
131
+ exists = len(results) > 0
132
+ logger.info(f"Check file exists - hash: {image_hash}, exists: {exists}, results: {results}")
133
+ return exists
134
+ except Exception as e:
135
+ logger.error(f"Failed to check file exists: {str(e)}")
136
+ return False
137
+
138
+ def delete_sticker(self, sticker_id: int) -> str:
139
+ """删除贴纸"""
140
+ try:
141
+ logger.info(f"Deleting sticker - id: {sticker_id}")
142
+ res = self.client.delete(
143
+ collection_name=self.collection_name,
144
+ ids=[sticker_id]
145
+ )
146
+ logger.info(f"Deleted sticker - id: {sticker_id}")
147
+ print(res)
148
+ return f"Sticker with ID {sticker_id} deleted successfully"
149
+ except Exception as e:
150
+ logger.error(f"Failed to delete sticker: {str(e)}")
151
+ return f"Failed to delete sticker: {str(e)}"
152
+ # 初始化 Milvus 数据库
153
+
154
+ # 创建数据库实例
155
+ db = Database()
app/gradio_formatter.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Dict, Any
2
+ from app.image_utils import format_image_url
3
+ import logging
4
+
5
+ # 配置日志
6
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
7
+ logger = logging.getLogger(__name__)
8
+
9
+ class GradioFormatter:
10
+ """贴纸格式化类,处理贴纸数据的格式化逻辑"""
11
+
12
+ @staticmethod
13
+ def format_all_stickers(results: List[Dict[str, Any]]) -> List[List]:
14
+ """格式化所有贴纸,用于Gradio UI显示"""
15
+ formatted_results = []
16
+
17
+ for record in results:
18
+ logger.info(f"格式化所有贴纸,用于Gradio UI显示: {record}")
19
+ image_url = format_image_url(record['file_name'])
20
+ formatted_results.append([
21
+ str(record['id']),
22
+ f"![Sticker]({image_url})",
23
+ record.get('title', ''),
24
+ record['description'],
25
+ ", ".join(record['tags']) if isinstance(record['tags'], list) else record['tags'],
26
+ record['file_name'],
27
+ record['image_hash'] if 'image_hash' in record else ''
28
+ ])
29
+ return formatted_results
30
+
31
+
32
+
33
+ @staticmethod
34
+ def format_search_results(results: List[Dict[str, Any]]) -> List[List]:
35
+ """格式化搜索结果,用于Gradio UI显示"""
36
+ formatted_results = []
37
+ logger.info(f"Formatting search results: {len(results)} items")
38
+
39
+ for hit in results:
40
+ image_url = format_image_url(hit['entity']['file_name'])
41
+ formatted_results.append([
42
+ f"![Sticker]({image_url})",
43
+ round(hit['distance'], 4),
44
+ hit['entity'].get('description', ''),
45
+ hit['entity'].get('file_name', '')
46
+ ])
47
+
48
+ return formatted_results
49
+
50
+ @staticmethod
51
+ def format_ai_search_results(results: List[Dict[str, Any]]) -> List[List]:
52
+ """格式化 AI 搜索结果,用于Gradio UI显示"""
53
+ formatted_results = []
54
+ logger.info(f"Formatting AI search results: {len(results)} items")
55
+
56
+ for hit in results:
57
+ image_url = format_image_url(hit['entity']['file_name'])
58
+ formatted_results.append([
59
+ f"![Sticker]({image_url})",
60
+ hit['entity'].get('score', ''),
61
+ hit['entity'].get('reason', ''),
62
+ hit['entity'].get('description', ''),
63
+ hit['entity'].get('file_name', '')
64
+ ])
65
+
66
+ return formatted_results
67
+ # 创建格式化器实例
68
+ gradio_formatter = GradioFormatter()
app/image_utils.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tempfile
2
+ import random
3
+ import requests
4
+ import json
5
+ import logging
6
+ from PIL import Image
7
+ from huggingface_hub import HfApi
8
+ from cozepy import Coze, TokenAuth
9
+ import hashlib
10
+
11
+ from app.config import DATASET_ID, COZE_API_TOKEN, HUGGING_FACE_TOKEN
12
+
13
+ # 配置日志
14
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # 初始化API客户端
18
+ api = HfApi()
19
+ coze = Coze(auth=TokenAuth(token=COZE_API_TOKEN), base_url="https://api.coze.cn")
20
+
21
+
22
+ def calculate_image_hash(Image: Image.Image) -> str:
23
+ """
24
+ 参数:
25
+ Image
26
+ 返回:
27
+ str: 图片的MD5哈希字符串
28
+ """
29
+ return hashlib.md5(Image.tobytes()).hexdigest()
30
+
31
+
32
+
33
+ def get_image_description(image_url: str) -> str:
34
+ """获取图片描述"""
35
+ logger.info(f"Get image description")
36
+ workflow = coze.workflows.runs.create(
37
+ workflow_id='7479742935953752091',
38
+ parameters={
39
+ "image_url": image_url
40
+ }
41
+ )
42
+ logger.info(f"Image description: {workflow.data}")
43
+ if (workflow.data):
44
+ description = json.loads(workflow.data)['output']
45
+ return description
46
+ else:
47
+ return ""
48
+
49
+ def save_image_temp(image: Image.Image) -> str:
50
+ """保存图片到临时文件"""
51
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_img:
52
+ image.save(temp_img.name, "PNG")
53
+ return temp_img.name
54
+
55
+
56
+ def upload_to_huggingface(temp_file_path: str) -> tuple:
57
+ """上传图片到 HuggingFace"""
58
+ image_filename = f"image_{random.randint(1000, 9999)}.png"
59
+ file_path = f"images/{image_filename}"
60
+
61
+ logger.info(f"Uploading image to HuggingFace: {file_path}")
62
+ api.upload_file(
63
+ path_or_fileobj=temp_file_path,
64
+ path_in_repo=file_path,
65
+ repo_id=DATASET_ID,
66
+ token=HUGGING_FACE_TOKEN,
67
+ repo_type="dataset"
68
+ )
69
+ logger.info(f"Image uploaded successfully: {file_path}")
70
+ return file_path, image_filename
71
+
72
+
73
+ def get_image_cdn_url(file_path: str) -> str:
74
+ """获取图片CDN URL"""
75
+ image_url = f"https://huggingface.co/datasets/{DATASET_ID}/resolve/main/{file_path}"
76
+ logger.info(f"Getting CDN URL for: {image_url}")
77
+
78
+ response = requests.head(
79
+ image_url,
80
+ allow_redirects=True,
81
+ timeout=10,
82
+ headers={
83
+ 'User-Agent': 'NekoAI',
84
+ }
85
+ )
86
+ image_cdn_url = response.url
87
+ logger.info(f"CDN URL: {image_cdn_url}")
88
+ return image_cdn_url
89
+
90
+
91
+ def format_image_url(file_path: str) -> str:
92
+ """格式化图片URL,用于显示"""
93
+ return f"https://huggingface.co/datasets/{DATASET_ID}/resolve/main/{file_path}"
app/services.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from typing import List, Dict, Any, Optional, Union
4
+ from PIL import Image
5
+ from app.api import get_chat_completion
6
+ import json
7
+ from app.config import (
8
+ STICKER_RERANKING_SYSTEM_PROMPT,
9
+ PUBLIC_URL
10
+ )
11
+
12
+ from app.database import db
13
+ from app.image_utils import (
14
+ save_image_temp,
15
+ upload_to_huggingface,
16
+ get_image_cdn_url,
17
+ get_image_description,
18
+ calculate_image_hash
19
+ )
20
+ from app.gradio_formatter import gradio_formatter
21
+
22
+ # 配置日志
23
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class StickerService:
28
+ """贴纸服务类,处理贴纸的上传、搜索等业务逻辑"""
29
+
30
+ @staticmethod
31
+ def upload_sticker(image_file_path: str, title: str, description: str, tags: str) -> str:
32
+ """上传贴纸"""
33
+ try:
34
+ # 打开图片
35
+ image = Image.open(image_file_path)
36
+
37
+ # 检查文件名是否已存在
38
+ image_hash = calculate_image_hash(image)
39
+ if db.check_image_exists(image_hash):
40
+ print(f"文件已存在", image_hash)
41
+ raise Exception('File_Exists')
42
+
43
+ # 上传到 HuggingFace
44
+ file_path, image_filename = upload_to_huggingface(image_file_path)
45
+ # print('>>>> image_file_path', image_file_path)
46
+ # print('>>>> image_filename', image_filename)
47
+ # print('>>>> file_path', file_path)
48
+
49
+ # 如果没有描述,获取图片描述
50
+ if not description:
51
+ image_cdn_url = ''
52
+ if (PUBLIC_URL):
53
+ image_cdn_url = f'{PUBLIC_URL}/gradio_api/file={image_file_path}'
54
+ else:
55
+ image_cdn_url = get_image_cdn_url(file_path)
56
+ print('image_cdn_url',image_cdn_url)
57
+
58
+ description = get_image_description(image_cdn_url)
59
+
60
+ # 清理临时文件
61
+ # os.unlink(temp_file_path)
62
+
63
+ # 存储到 Milvus
64
+ db.store_sticker(title, description, tags, file_path, image_hash)
65
+
66
+ return f"Upload successful! {image_filename}"
67
+
68
+ except Exception as e:
69
+ logger.error(f"Upload failed: {str(e)}")
70
+ return f"Upload failed: {str(e)}"
71
+
72
+ @staticmethod
73
+ def search_stickers(description: str, limit: int = 2, reranking : bool = False) -> List[Dict[str, Any]]:
74
+ """搜索贴纸"""
75
+ if not description:
76
+ return []
77
+
78
+ try:
79
+ results = db.search_stickers(description, limit)
80
+ if (reranking):
81
+ # 对搜索结果进行重排
82
+ results = StickerService.rerank_search_results(description, results, limit)
83
+ return results
84
+ except Exception as e:
85
+ logger.error(f"Search failed: {str(e)}")
86
+ return []
87
+
88
+ @staticmethod
89
+ def get_all_stickers(limit: int = 1000) -> List[List]:
90
+ """获取所有贴纸"""
91
+ try:
92
+ results = db.get_all_stickers(limit)
93
+ return gradio_formatter.format_all_stickers(results)
94
+ except Exception as e:
95
+ logger.error(f"Failed to get all stickers: {str(e)}")
96
+ return []
97
+
98
+ @staticmethod
99
+ def delete_sticker(sticker_id: str) -> str:
100
+ """删除贴纸"""
101
+ try:
102
+ # 首先查询贴纸是否存在
103
+ result = db.delete_sticker(sticker_id)
104
+
105
+ return f"Sticker with ID {sticker_id} deleted successfully"
106
+ except Exception as e:
107
+ logger.error(f"Delete failed: {str(e)}")
108
+ return f"Delete failed: {str(e)}"
109
+
110
+
111
+ @staticmethod
112
+ def rerank_search_results(query: str, sticker_list: List[Dict[str, Any]], limit: int = 5) -> List[Dict[str, Any]]:
113
+ ## 使用 LLM 模型重新排序搜索结果
114
+ try:
115
+ # 构建提示词
116
+ system_prompt = STICKER_RERANKING_SYSTEM_PROMPT
117
+ # 构建用户提示词,包含查询和表情包信息
118
+ _sticker_list = []
119
+ for hit in sticker_list:
120
+ _sticker_list.append({
121
+ "id": hit["id"],
122
+ "description": hit["entity"]["description"]
123
+ })
124
+
125
+ user_prompt = f"请分析关键词 '{query}' 与以下表情包的相关性:\n{_sticker_list}"
126
+
127
+ print(f">>> 使用 LLM 模型重新排序....", user_prompt, system_prompt)
128
+ # 调用 LLM 模型获取重排序结果
129
+ response = get_chat_completion(user_prompt, system_prompt)
130
+
131
+ # 解析 LLM 返回的 JSON 结果
132
+ reranked_stickers = json.loads(response)
133
+
134
+ # 验证返回结果格式
135
+ if not isinstance(reranked_stickers, list):
136
+ raise ValueError("Invalid response format")
137
+
138
+ # 按分数排序
139
+ reranked_stickers.sort(key=lambda x: float(x.get("score", 0)), reverse=True)
140
+
141
+ print(f">>> LLM 排序结果", reranked_stickers)
142
+
143
+
144
+ # 将重排序结果与原始结果对应
145
+ rerank_results = []
146
+ for sticker in reranked_stickers:
147
+ for hit in sticker_list:
148
+ if str(hit["id"]) == str(sticker["sticker_id"]):
149
+ hit["entity"]["score"] = sticker["score"]
150
+ hit["entity"]["reason"] = sticker["reason"]
151
+ rerank_results.append(hit)
152
+ break
153
+
154
+ print(f">>> rerank_results", rerank_results)
155
+ return rerank_results
156
+
157
+ except Exception as e:
158
+ logger.error(f"Reranking failed: {str(e)}")
159
+ return []
160
+
161
+
162
+
163
+
164
+ # 创建服务实例
165
+ sticker_service = StickerService()
app/ui.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import logging
3
+ from app.services import sticker_service
4
+ from app.gradio_formatter import gradio_formatter
5
+
6
+ # Configure logging
7
+ logging.basicConfig(
8
+ level=logging.INFO,
9
+ format='%(asctime)s %(levelname)s %(message)s'
10
+ )
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class StickerUI:
15
+ """Main class for the Sticker Search UI application."""
16
+
17
+ def __init__(self):
18
+ self.demo = None
19
+ self._initialize_components()
20
+
21
+ def _initialize_components(self):
22
+ """Initialize all UI components."""
23
+ # Search Tab
24
+ self.search_input = gr.Textbox(label="Search keywords")
25
+ self.limit_input = gr.Slider(1, 10, value=4, step=1, label="Max results")
26
+ self.search_button = gr.Button("Search")
27
+ self.deepseek_button = gr.Button("AI Search")
28
+ self.search_results = gr.Dataframe(
29
+ headers=["Preview", "Relevance", "Description", "Filename"],
30
+ datatype=["markdown", "number", "str", "str"],
31
+ row_count=("dynamic")
32
+ )
33
+
34
+ self.ai_search_results = gr.Dataframe(
35
+ headers=["Preview", "AI-Score", "AI-Reason", "Description", "Filename"],
36
+ datatype=["markdown", "number", "str", "str", "str"],
37
+ row_count=("dynamic")
38
+ )
39
+
40
+ # Upload Tab
41
+ self.image_input = gr.Image(type="filepath")
42
+ self.title_input = gr.Textbox(label="Title")
43
+ self.tags_input = gr.Textbox(label="Tags (comma separated)")
44
+ self.desc_input = gr.Textbox(label="Description")
45
+ self.upload_button = gr.Button("Upload")
46
+ self.upload_output = gr.Textbox(label="Status")
47
+
48
+ # All Stickers Tab
49
+ self.refresh_button = gr.Button("Refresh")
50
+ self.stickers_table = gr.Dataframe(
51
+ headers=["ID", "Preview", "Title", "Description", "Tags", "Filename", "Hash"],
52
+ datatype=["str", "markdown", "str", "str", "str", "str", "str"]
53
+ )
54
+
55
+ def _setup_search_tab(self):
56
+ """Configure the search tab layout and functionality."""
57
+ with gr.Tab("Search"):
58
+ with gr.Row():
59
+ self.search_input.render()
60
+ self.limit_input.render()
61
+
62
+ with gr.Row():
63
+ self.search_button.render()
64
+ self.deepseek_button.render()
65
+
66
+ self.search_results.render()
67
+ self.ai_search_results.render()
68
+
69
+ # Event handlers
70
+ self.search_button.click(
71
+ fn=lambda q, l: gradio_formatter.format_search_results(
72
+ sticker_service.search_stickers(q, l)
73
+ ),
74
+ inputs=[self.search_input, self.limit_input],
75
+ outputs=self.search_results
76
+ )
77
+
78
+ self.deepseek_button.click(
79
+ fn=lambda q, l: gradio_formatter.format_ai_search_results(
80
+ sticker_service.search_stickers(q, l, reranking=True)
81
+ ),
82
+ inputs=[self.search_input, self.limit_input],
83
+ outputs=self.ai_search_results
84
+ )
85
+
86
+ def _setup_upload_tab(self):
87
+ """Configure the upload tab layout and functionality."""
88
+ with gr.Tab("Upload"):
89
+ with gr.Row():
90
+ self.image_input.render()
91
+
92
+ with gr.Row():
93
+ self.title_input.render()
94
+ self.tags_input.render()
95
+
96
+ with gr.Row():
97
+ self.desc_input.render()
98
+ self.upload_button.render()
99
+
100
+ self.upload_output.render()
101
+
102
+ self.upload_button.click(
103
+ fn=sticker_service.upload_sticker,
104
+ inputs=[
105
+ self.image_input,
106
+ self.title_input,
107
+ self.desc_input,
108
+ self.tags_input
109
+ ],
110
+ outputs=self.upload_output
111
+ )
112
+
113
+ def _setup_all_stickers_tab(self):
114
+ """Configure the all stickers tab layout and functionality."""
115
+ with gr.Tab("All Stickers"):
116
+ self.refresh_button.render()
117
+ self.stickers_table.render()
118
+
119
+ self.refresh_button.click(
120
+ fn=sticker_service.get_all_stickers,
121
+ outputs=self.stickers_table
122
+ )
123
+
124
+ def create_ui(self):
125
+ """Create and configure the complete UI."""
126
+ with gr.Blocks(title="Neko Sticker Search 🔍") as self.demo:
127
+ self._setup_search_tab()
128
+ self._setup_upload_tab()
129
+ self._setup_all_stickers_tab()
130
+
131
+ return self.demo
embedding_test.py ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from abc import ABC, abstractmethod
4
+ from typing import List, Dict, Any
5
+ from sentence_transformers import SentenceTransformer
6
+ from pymilvus import MilvusClient, DataType
7
+ import time
8
+ import gradio as gr
9
+
10
+ # 配置日志
11
+ logging.basicConfig(
12
+ level=logging.INFO,
13
+ format='%(asctime)s %(levelname)s %(message)s'
14
+ )
15
+ logger = logging.getLogger(__name__)
16
+
17
+ models = [
18
+ 'shibing624/text2vec-base-chinese',
19
+ 'BAAI/bge-small-zh',
20
+ 'BAAI/bge-base-zh',
21
+ 'sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2',
22
+ 'all-MiniLM-L6-v2',
23
+ 'all-MiniLM-L12-v2',
24
+ 'multi-qa-mpnet-base-dot-v1',
25
+ # 'bge-small-en-v1.5', 不兼容
26
+ 'all-mpnet-base-v2',
27
+ 'jinaai/jina-embeddings-v3',
28
+ ]
29
+
30
+
31
+ searchers = {}
32
+
33
+
34
+ class BaseEmbeddingModel(ABC):
35
+ @abstractmethod
36
+ def encode(self, text: str) -> List[float]:
37
+ pass
38
+
39
+ @property
40
+ @abstractmethod
41
+ def dimension(self) -> int:
42
+ pass
43
+
44
+ @property
45
+ @abstractmethod
46
+ def model_name(self) -> str:
47
+ pass
48
+
49
+ class SentenceTransformerModel(BaseEmbeddingModel):
50
+ def __init__(self, model_name: str):
51
+ self.model = SentenceTransformer(model_name, trust_remote_code=True)
52
+ self._model_name = model_name
53
+
54
+ def encode(self, text: str) -> List[float]:
55
+ result = self.model.encode(text).tolist()
56
+ return result
57
+
58
+ @property
59
+ def dimension(self) -> int:
60
+ return self.model.get_sentence_embedding_dimension()
61
+
62
+ @property
63
+ def model_name(self) -> str:
64
+ return self._model_name
65
+
66
+ class StickerSearcher:
67
+ def __init__(self, model: BaseEmbeddingModel):
68
+ self.model = model
69
+ self.client = MilvusClient(uri='./sticker.db')
70
+ self.collection_name = f'test_{model.model_name.replace("/", "_").replace("-", "_")}'
71
+
72
+ def init_collection(self) -> bool:
73
+ try:
74
+ self.client.drop_collection(collection_name=self.collection_name)
75
+ self.client.create_collection(
76
+ collection_name=self.collection_name,
77
+ dimension=self.model.dimension,
78
+ primary_field_name='id',
79
+ auto_id=True
80
+ )
81
+ self.client.create_index(
82
+ collection_name=self.collection_name,
83
+ index_type='IVF_SQ8',
84
+ metric_type='COSINE',
85
+ params={'nlist': 128},
86
+ index_params={}
87
+ )
88
+ self.client.load_collection(self.collection_name)
89
+ logger.info(f'Collection initialized: {self.collection_name}')
90
+ return True
91
+ except Exception as e:
92
+ logger.error(f'Collection init failed: {str(e)}')
93
+ return False
94
+
95
+ def store_vector(self, title: str, description: str, tags: List[str], file_path: str):
96
+ vector = self.model.encode(description)
97
+ data = [{
98
+ 'vector': vector,
99
+ 'title': title,
100
+ 'description': description,
101
+ 'tags': tags,
102
+ 'file_name': file_path
103
+ }]
104
+ self.client.insert(self.collection_name, data)
105
+
106
+ def search(self, query: str, limit: int = 5) -> List[Dict[str, Any]]:
107
+ start_time = time.time()
108
+ query_vector = self.model.encode(query)
109
+ encode_time = time.time() - start_time
110
+ start_search_time = time.time()
111
+ results = self.client.search(
112
+ collection_name=self.collection_name,
113
+ data=[query_vector],
114
+ limit=limit,
115
+ output_fields=['title', 'description', 'tags', 'file_name']
116
+ )
117
+ search_time = time.time() - start_search_time
118
+ total_time = encode_time + search_time
119
+ logger.info(f'模型 {self.model.model_name} Encoding耗时: ${encode_time:.4f},搜索耗时: {search_time:.4f} 秒, 总耗时: {total_time:.4f} 秒')
120
+ return results[0]
121
+
122
+ def create_gradio_ui():
123
+
124
+ async def search_model(model_name: str, query: str):
125
+ try:
126
+ if model_name in searchers:
127
+ return searchers[model_name].search(query)
128
+ logger.error(f'Model not loaded: {model_name}')
129
+ return []
130
+ except Exception as e:
131
+ logger.error(f'Search failed: {model_name} | Error: {str(e)}')
132
+ return []
133
+
134
+ async def search_all_models(query):
135
+ if not query:
136
+ return []
137
+
138
+ print(f'>>>> Searching From Models {query}')
139
+ results = []
140
+ for model_name in models:
141
+ result = await search_model(model_name, query)
142
+ results.append(result)
143
+
144
+ formatted_results = []
145
+ max_results = max(len(r) for r in results)
146
+
147
+ for i in range(max_results):
148
+ row = [i + 1]
149
+ for model_results in results:
150
+ if i < len(model_results):
151
+ result = model_results[i]
152
+ image_url = f'https://huggingface.co/datasets/Nekoko/StickerSet/resolve/main/{result["entity"]["file_name"]}'
153
+ row.append(f'![Sticker]({image_url})\n相似度: {result["distance"]:.4f}')
154
+ else:
155
+ row.append('-')
156
+ formatted_results.append(row)
157
+ return formatted_results
158
+
159
+ def init_collections():
160
+ try:
161
+ client = MilvusClient(uri='./sticker.db')
162
+ stickers = client.query(
163
+ collection_name='stickers',
164
+ filter='',
165
+ limit=1000,
166
+ output_fields=['title', 'description', 'tags', 'file_name']
167
+ )
168
+ logger.info(f'Stickers loaded: {len(stickers)}')
169
+
170
+ def init_model(model_name):
171
+ try:
172
+ searcher = StickerSearcher(SentenceTransformerModel(model_name))
173
+ if searcher.init_collection():
174
+ searchers[model_name] = searcher
175
+ for sticker in stickers:
176
+ searcher.store_vector(
177
+ sticker.get('title'),
178
+ sticker.get('description'),
179
+ sticker.get('tags'),
180
+ sticker.get('file_name')
181
+ )
182
+ logger.info(f'Model initialized: {model_name}')
183
+ except Exception as e:
184
+ logger.error(f'Model init failed: {model_name} | Error: {str(e)}')
185
+
186
+ for model_name in models:
187
+ print(f'>>>> 初始化模型 {model_name}')
188
+ start_time = time.time()
189
+ init_model(model_name)
190
+ print(f'>>>> 初始化模型 {model_name} 完成 ✅,耗时 {time.time() - start_time:.4f} 秒')
191
+ print(f'>>>> 初始化所有模型完成 ✅')
192
+ return '初始化成功!'
193
+ except Exception as e:
194
+ logger.error(f'Data init failed: {str(e)}')
195
+ return f'初始化失败: {str(e)}'
196
+
197
+ with gr.Blocks(title='Neko Sticker Search 🔍', css='.gradio-container img { width: 200px !important; height: 200px !important; object-fit: contain; }') as demo:
198
+ with gr.Row():
199
+ search_input = gr.Textbox(label='搜索关键词')
200
+ search_button = gr.Button('搜索')
201
+
202
+
203
+ headers = ['序号'] + [f'🧊{model.split("/")[-1]}' for i, model in enumerate(models)]
204
+ results_table = gr.Dataframe(
205
+ headers=headers,
206
+ datatype=['number'] + ['markdown'] * len(models),
207
+ row_count=5,
208
+ col_count=len(models) + 1
209
+ )
210
+
211
+ status_box = gr.Textbox(label='状态', interactive=False)
212
+ refresh_button = gr.Button('刷新数据')
213
+
214
+ refresh_button.click(fn=init_collections, outputs=status_box)
215
+ # 由于这里只是简单的搜索操作,可以直接使用同步方式调用
216
+ search_button.click(
217
+ fn=search_all_models,
218
+ inputs=[search_input],
219
+ outputs=results_table
220
+ )
221
+
222
+ return demo
223
+
224
+ if __name__ == '__main__':
225
+
226
+ # 提前加载所有模型
227
+ start_time = time.time()
228
+ for index, model_name in enumerate(models):
229
+ try:
230
+ start_time = time.time()
231
+ searchers[model_name] = StickerSearcher(SentenceTransformerModel(model_name))
232
+ print(f'>>>> 预加载模型 {model_name} 完成 ✅, 耗时 {time.time() - start_time:.4f} 秒')
233
+ except Exception as e:
234
+ logger.error(f'Model preload failed: {model_name} | Error: {str(e)}')
235
+
236
+ logger.info(f'>>>> 预加载模型完成 ✅: {models}, 耗时 {time.time() - start_time:.4f} 秒')
237
+
238
+
239
+
240
+ demo = create_gradio_ui()
241
+ demo.launch()
main.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from fastapi import FastAPI
3
+ import uvicorn
4
+ import logging
5
+
6
+ # 配置日志
7
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
8
+ logger = logging.getLogger(__name__)
9
+
10
+ # 创建FastAPI应用
11
+ app = FastAPI()
12
+
13
+ # 使用app/database.py中的数据库实例
14
+ from app.database import db
15
+
16
+ def init_milvus():
17
+ """初始化 Milvus 数据库"""
18
+ db.init_collection()
19
+
20
+ # 图像处理相关功能已经在app/image_utils.py中实现
21
+
22
+
23
+
24
+ # 使用app/services.py中的服务
25
+ from app.services import sticker_service
26
+
27
+ # 使用app/services.py中的服务,不再需要重复实现这些功能
28
+
29
+ # 导入UI模块
30
+ from app.ui import StickerUI
31
+
32
+ # 创建Gradio界面
33
+
34
+ # FastAPI 路由
35
+ @app.get("/api/list_stickers")
36
+ def api_get_stickers():
37
+
38
+ sticker_list = sticker_service.get_all_stickers()
39
+ print('>>> GET Sticker_list', sticker_list)
40
+ return sticker_list
41
+
42
+
43
+ @app.post("/api/search_stickers")
44
+ async def api_search_stickers(request: dict):
45
+ description = request.get('description', '')
46
+ if len(description) > 0:
47
+ sticker_list = sticker_service.search_stickers(
48
+ description=description,
49
+ limit=1,
50
+ )
51
+ print('>>> GET Sticker_list', sticker_list)
52
+ return sticker_list
53
+ return [] # 当描述为空时返回空列表
54
+
55
+
56
+
57
+ @app.post("/api/delete_sticker")
58
+ async def api_delete_stickers(request: dict):
59
+ """Delete sticker by ID"""
60
+ try:
61
+ sticker_id = request.get('id')
62
+ if not sticker_id:
63
+ return {"status": "error", "message": "Missing sticker ID"}
64
+
65
+ result = sticker_service.delete_sticker(sticker_id)
66
+ return {"status": "success", "message": result}
67
+ except Exception as e:
68
+ logger.error(f"Delete failed: {str(e)}")
69
+ return {"status": "error", "message": f"Delete failed: {str(e)}"}
70
+
71
+
72
+
73
+ # 启动应用
74
+ if __name__ == "__main__":
75
+ init_milvus()
76
+ ui = StickerUI()
77
+ app = gr.mount_gradio_app(app, ui.create_ui(), '/')
78
+ uvicorn.run(app, host="0.0.0.0", port=7860)
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ huggingface_hub>=0.19.4
2
+ requests>=2.31.0
3
+ cozepy>=0.1.0
4
+ gradio==5.22.0
5
+ sentence_transformers>=2.2.2
6
+ fastapi>=0.104.1
7
+ uvicorn>=0.24.0
8
+ Pillow>=10.1.0
9
+ pymilvus>=2.3.3
10
+ openai==1.69.0
sticker copy.db ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:65df0d7b09c24a836da3b90a7e3677c8e15e21b9fe42a02b18d1671d375d3df0
3
+ size 77824
sticker-server/README.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Sticker MCP Server
2
+
3
+ This is an MCP (Model Context Protocol) server that allows large language models to search and send stickers based on emotion descriptions.
4
+
5
+ ## Features
6
+
7
+ - Search for stickers based on emotion descriptions
8
+ - Return sticker images in response to queries
9
+ - Integrate with existing sticker search API
10
+
11
+ ## Installation
12
+
13
+ 1. Install dependencies:
14
+
15
+ ```
16
+ cd sticker-server
17
+ npm install
18
+ ```
19
+
20
+ 2. Make the server executable:
21
+
22
+ ```
23
+ npm run build
24
+ ```
25
+
26
+ 3. Configure the MCP settings:
27
+
28
+ - For Claude Desktop app: Copy the contents of `mcp_settings.json` to `~/Library/Application Support/Claude/claude_desktop_config.json`
29
+ - For Claude VSCode extension: Copy the contents of `mcp_settings.json` to `~/Library/Application Support/Trae/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
30
+
31
+ If the file already exists, merge the "sticker" entry into the existing "mcpServers" object.
32
+
33
+ ## Usage
34
+
35
+ Once the MCP server is configured, you can ask the language model to express emotions using stickers. For example:
36
+
37
+ - "Show me a happy sticker"
38
+ - "I'm feeling sad, can you send a sticker?"
39
+ - "Send a cat sticker"
40
+
41
+ The language model will use the `send_sticker` tool to search for and display an appropriate sticker based on your request.
42
+
43
+ ## How it Works
44
+
45
+ The server connects to a local sticker search API running at `http://localhost:7860/api/search_stickers` and provides the search results to the language model, which can then display the stickers in its responses.
sticker-server/index.ts ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import {
5
+ ErrorCode,
6
+ ListResourcesRequestSchema,
7
+ ListResourcesResult,
8
+ ListResourceTemplatesRequestSchema,
9
+ McpError,
10
+ ReadResourceRequestSchema,
11
+ } from "@modelcontextprotocol/sdk/types.js";
12
+
13
+ interface Resource {
14
+ name: string;
15
+ description: string;
16
+ inputSchema: {
17
+ type: string;
18
+ properties: Record<
19
+ string,
20
+ {
21
+ type: string;
22
+ description: string;
23
+ }
24
+ >;
25
+ required?: string[];
26
+ };
27
+ }
28
+
29
+ class StickerServer {
30
+ private server: Server;
31
+
32
+ constructor() {
33
+ this.server = new Server(
34
+ {
35
+ name: "sticker-server",
36
+ version: "1.0.0",
37
+ },
38
+ {
39
+ capabilities: {
40
+ resources: {},
41
+ },
42
+ }
43
+ );
44
+
45
+ this.setupResourceHandlers();
46
+
47
+ this.server.onerror = (error: Error) => console.error("[MCP Error]", error);
48
+ process.on("SIGINT", async () => {
49
+ await this.server.close();
50
+ process.exit(0);
51
+ });
52
+ }
53
+
54
+ private setupResourceHandlers(): void {
55
+ this.server.setRequestHandler(
56
+ ListResourceTemplatesRequestSchema,
57
+ async () => ({
58
+ resourceTemplates: [
59
+ {
60
+ uriTemplate:
61
+ "mcp://sticker-server/send_sticker?description={description}",
62
+ name: "send sticker",
63
+ mimeType: "text",
64
+ description:
65
+ "请正常回复用户的问题,只有在正常回答用户问题后,根据情境需要,使用此 Resource 读取一个表达特定情绪或描述的贴纸的 URL,并将图片展示到对话内,需要展示图片,而不是 URL",
66
+ },
67
+ ],
68
+ })
69
+ );
70
+
71
+ // Read resource contents
72
+ this.server.setRequestHandler(
73
+ ReadResourceRequestSchema,
74
+ async (request) => {
75
+ try {
76
+ const uri = request.params.uri;
77
+ // mcp://sticker-server/send_sticker?description={description}
78
+ const description = new URL(uri).searchParams.get("description");
79
+ const response = await fetch(
80
+ "http://127.0.0.1:7860/api/search_stickers",
81
+ {
82
+ method: "POST",
83
+ headers: {
84
+ "Content-Type": "application/json",
85
+ },
86
+ body: JSON.stringify({ description }),
87
+ }
88
+ );
89
+ const stickerList = await response.json();
90
+ console.log("uri", uri, "stickerList", stickerList);
91
+ const imageUrl = stickerList?.[0]?.image_url || "找不到贴纸呢~";
92
+ await new Promise((resolve) => setTimeout(resolve, 1000));
93
+ return {
94
+ contents: [
95
+ {
96
+ uri,
97
+ type: "text",
98
+ text: imageUrl,
99
+ },
100
+ ],
101
+ };
102
+ } catch (error) {
103
+ return {
104
+ contents: [
105
+ {
106
+ uri: "",
107
+ type: "text",
108
+ text: JSON.stringify(error),
109
+ },
110
+ ],
111
+ };
112
+ }
113
+ }
114
+ );
115
+ }
116
+
117
+ async run(): Promise<void> {
118
+ const transport = new StdioServerTransport();
119
+ await this.server.connect(transport);
120
+ console.error("Sticker MCP server running on stdio");
121
+ }
122
+ }
123
+
124
+ const server = new StickerServer();
125
+ server.run().catch(console.error);
sticker-server/mcp_settings.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcpServers": {
3
+ "sticker": {
4
+ "command": "node",
5
+ "args": ["/Users/bytedance/dev/NekoAI-Lab/sticker-server/dist/index.js"],
6
+ "disabled": false,
7
+ "autoApprove": []
8
+ }
9
+ }
10
+ }
sticker-server/package-lock.json ADDED
@@ -0,0 +1,1871 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "sticker-server",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "sticker-server",
9
+ "version": "1.0.0",
10
+ "dependencies": {
11
+ "@modelcontextprotocol/sdk": "*",
12
+ "axios": "^1.6.0",
13
+ "node-fetch": "^3.3.2"
14
+ },
15
+ "devDependencies": {
16
+ "@types/node": "^22.13.14",
17
+ "ts-node": "^10.9.2",
18
+ "ts-node-dev": "^2.0.0",
19
+ "typescript": "^5.3.3"
20
+ }
21
+ },
22
+ "node_modules/@cspotcode/source-map-support": {
23
+ "version": "0.8.1",
24
+ "resolved": "https://bnpm.byted.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
25
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
26
+ "dev": true,
27
+ "dependencies": {
28
+ "@jridgewell/trace-mapping": "0.3.9"
29
+ },
30
+ "engines": {
31
+ "node": ">=12"
32
+ }
33
+ },
34
+ "node_modules/@jridgewell/resolve-uri": {
35
+ "version": "3.1.2",
36
+ "resolved": "https://bnpm.byted.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
37
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
38
+ "dev": true,
39
+ "engines": {
40
+ "node": ">=6.0.0"
41
+ }
42
+ },
43
+ "node_modules/@jridgewell/sourcemap-codec": {
44
+ "version": "1.5.0",
45
+ "resolved": "https://bnpm.byted.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
46
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
47
+ "dev": true
48
+ },
49
+ "node_modules/@jridgewell/trace-mapping": {
50
+ "version": "0.3.9",
51
+ "resolved": "https://bnpm.byted.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
52
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
53
+ "dev": true,
54
+ "dependencies": {
55
+ "@jridgewell/resolve-uri": "^3.0.3",
56
+ "@jridgewell/sourcemap-codec": "^1.4.10"
57
+ }
58
+ },
59
+ "node_modules/@modelcontextprotocol/sdk": {
60
+ "version": "1.8.0",
61
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.8.0.tgz",
62
+ "integrity": "sha512-e06W7SwrontJDHwCawNO5SGxG+nU9AAx+jpHHZqGl/WrDBdWOpvirC+s58VpJTB5QemI4jTRcjWT4Pt3Q1NPQQ==",
63
+ "dependencies": {
64
+ "content-type": "^1.0.5",
65
+ "cors": "^2.8.5",
66
+ "cross-spawn": "^7.0.3",
67
+ "eventsource": "^3.0.2",
68
+ "express": "^5.0.1",
69
+ "express-rate-limit": "^7.5.0",
70
+ "pkce-challenge": "^4.1.0",
71
+ "raw-body": "^3.0.0",
72
+ "zod": "^3.23.8",
73
+ "zod-to-json-schema": "^3.24.1"
74
+ },
75
+ "engines": {
76
+ "node": ">=18"
77
+ }
78
+ },
79
+ "node_modules/@tsconfig/node10": {
80
+ "version": "1.0.11",
81
+ "resolved": "https://bnpm.byted.org/@tsconfig/node10/-/node10-1.0.11.tgz",
82
+ "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
83
+ "dev": true
84
+ },
85
+ "node_modules/@tsconfig/node12": {
86
+ "version": "1.0.11",
87
+ "resolved": "https://bnpm.byted.org/@tsconfig/node12/-/node12-1.0.11.tgz",
88
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
89
+ "dev": true
90
+ },
91
+ "node_modules/@tsconfig/node14": {
92
+ "version": "1.0.3",
93
+ "resolved": "https://bnpm.byted.org/@tsconfig/node14/-/node14-1.0.3.tgz",
94
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
95
+ "dev": true
96
+ },
97
+ "node_modules/@tsconfig/node16": {
98
+ "version": "1.0.4",
99
+ "resolved": "https://bnpm.byted.org/@tsconfig/node16/-/node16-1.0.4.tgz",
100
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
101
+ "dev": true
102
+ },
103
+ "node_modules/@types/node": {
104
+ "version": "22.13.14",
105
+ "resolved": "https://bnpm.byted.org/@types/node/-/node-22.13.14.tgz",
106
+ "integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==",
107
+ "dev": true,
108
+ "dependencies": {
109
+ "undici-types": "~6.20.0"
110
+ }
111
+ },
112
+ "node_modules/@types/strip-bom": {
113
+ "version": "3.0.0",
114
+ "resolved": "https://bnpm.byted.org/@types/strip-bom/-/strip-bom-3.0.0.tgz",
115
+ "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==",
116
+ "dev": true
117
+ },
118
+ "node_modules/@types/strip-json-comments": {
119
+ "version": "0.0.30",
120
+ "resolved": "https://bnpm.byted.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz",
121
+ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
122
+ "dev": true
123
+ },
124
+ "node_modules/accepts": {
125
+ "version": "2.0.0",
126
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
127
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
128
+ "dependencies": {
129
+ "mime-types": "^3.0.0",
130
+ "negotiator": "^1.0.0"
131
+ },
132
+ "engines": {
133
+ "node": ">= 0.6"
134
+ }
135
+ },
136
+ "node_modules/acorn": {
137
+ "version": "8.14.1",
138
+ "resolved": "https://bnpm.byted.org/acorn/-/acorn-8.14.1.tgz",
139
+ "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
140
+ "dev": true,
141
+ "bin": {
142
+ "acorn": "bin/acorn"
143
+ },
144
+ "engines": {
145
+ "node": ">=0.4.0"
146
+ }
147
+ },
148
+ "node_modules/acorn-walk": {
149
+ "version": "8.3.4",
150
+ "resolved": "https://bnpm.byted.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
151
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
152
+ "dev": true,
153
+ "dependencies": {
154
+ "acorn": "^8.11.0"
155
+ },
156
+ "engines": {
157
+ "node": ">=0.4.0"
158
+ }
159
+ },
160
+ "node_modules/anymatch": {
161
+ "version": "3.1.3",
162
+ "resolved": "https://bnpm.byted.org/anymatch/-/anymatch-3.1.3.tgz",
163
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
164
+ "dev": true,
165
+ "dependencies": {
166
+ "normalize-path": "^3.0.0",
167
+ "picomatch": "^2.0.4"
168
+ },
169
+ "engines": {
170
+ "node": ">= 8"
171
+ }
172
+ },
173
+ "node_modules/arg": {
174
+ "version": "4.1.3",
175
+ "resolved": "https://bnpm.byted.org/arg/-/arg-4.1.3.tgz",
176
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
177
+ "dev": true
178
+ },
179
+ "node_modules/asynckit": {
180
+ "version": "0.4.0",
181
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
182
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
183
+ },
184
+ "node_modules/axios": {
185
+ "version": "1.8.4",
186
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
187
+ "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
188
+ "dependencies": {
189
+ "follow-redirects": "^1.15.6",
190
+ "form-data": "^4.0.0",
191
+ "proxy-from-env": "^1.1.0"
192
+ }
193
+ },
194
+ "node_modules/balanced-match": {
195
+ "version": "1.0.2",
196
+ "resolved": "https://bnpm.byted.org/balanced-match/-/balanced-match-1.0.2.tgz",
197
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
198
+ "dev": true
199
+ },
200
+ "node_modules/binary-extensions": {
201
+ "version": "2.3.0",
202
+ "resolved": "https://bnpm.byted.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
203
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
204
+ "dev": true,
205
+ "engines": {
206
+ "node": ">=8"
207
+ }
208
+ },
209
+ "node_modules/body-parser": {
210
+ "version": "2.2.0",
211
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
212
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
213
+ "dependencies": {
214
+ "bytes": "^3.1.2",
215
+ "content-type": "^1.0.5",
216
+ "debug": "^4.4.0",
217
+ "http-errors": "^2.0.0",
218
+ "iconv-lite": "^0.6.3",
219
+ "on-finished": "^2.4.1",
220
+ "qs": "^6.14.0",
221
+ "raw-body": "^3.0.0",
222
+ "type-is": "^2.0.0"
223
+ },
224
+ "engines": {
225
+ "node": ">=18"
226
+ }
227
+ },
228
+ "node_modules/body-parser/node_modules/debug": {
229
+ "version": "4.4.0",
230
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
231
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
232
+ "dependencies": {
233
+ "ms": "^2.1.3"
234
+ },
235
+ "engines": {
236
+ "node": ">=6.0"
237
+ },
238
+ "peerDependenciesMeta": {
239
+ "supports-color": {
240
+ "optional": true
241
+ }
242
+ }
243
+ },
244
+ "node_modules/body-parser/node_modules/ms": {
245
+ "version": "2.1.3",
246
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
247
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
248
+ },
249
+ "node_modules/body-parser/node_modules/qs": {
250
+ "version": "6.14.0",
251
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
252
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
253
+ "dependencies": {
254
+ "side-channel": "^1.1.0"
255
+ },
256
+ "engines": {
257
+ "node": ">=0.6"
258
+ },
259
+ "funding": {
260
+ "url": "https://github.com/sponsors/ljharb"
261
+ }
262
+ },
263
+ "node_modules/brace-expansion": {
264
+ "version": "1.1.11",
265
+ "resolved": "https://bnpm.byted.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
266
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
267
+ "dev": true,
268
+ "dependencies": {
269
+ "balanced-match": "^1.0.0",
270
+ "concat-map": "0.0.1"
271
+ }
272
+ },
273
+ "node_modules/braces": {
274
+ "version": "3.0.3",
275
+ "resolved": "https://bnpm.byted.org/braces/-/braces-3.0.3.tgz",
276
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
277
+ "dev": true,
278
+ "dependencies": {
279
+ "fill-range": "^7.1.1"
280
+ },
281
+ "engines": {
282
+ "node": ">=8"
283
+ }
284
+ },
285
+ "node_modules/buffer-from": {
286
+ "version": "1.1.2",
287
+ "resolved": "https://bnpm.byted.org/buffer-from/-/buffer-from-1.1.2.tgz",
288
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
289
+ "dev": true
290
+ },
291
+ "node_modules/bytes": {
292
+ "version": "3.1.2",
293
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
294
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
295
+ "engines": {
296
+ "node": ">= 0.8"
297
+ }
298
+ },
299
+ "node_modules/call-bind-apply-helpers": {
300
+ "version": "1.0.2",
301
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
302
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
303
+ "dependencies": {
304
+ "es-errors": "^1.3.0",
305
+ "function-bind": "^1.1.2"
306
+ },
307
+ "engines": {
308
+ "node": ">= 0.4"
309
+ }
310
+ },
311
+ "node_modules/call-bound": {
312
+ "version": "1.0.4",
313
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
314
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
315
+ "dependencies": {
316
+ "call-bind-apply-helpers": "^1.0.2",
317
+ "get-intrinsic": "^1.3.0"
318
+ },
319
+ "engines": {
320
+ "node": ">= 0.4"
321
+ },
322
+ "funding": {
323
+ "url": "https://github.com/sponsors/ljharb"
324
+ }
325
+ },
326
+ "node_modules/chokidar": {
327
+ "version": "3.6.0",
328
+ "resolved": "https://bnpm.byted.org/chokidar/-/chokidar-3.6.0.tgz",
329
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
330
+ "dev": true,
331
+ "dependencies": {
332
+ "anymatch": "~3.1.2",
333
+ "braces": "~3.0.2",
334
+ "glob-parent": "~5.1.2",
335
+ "is-binary-path": "~2.1.0",
336
+ "is-glob": "~4.0.1",
337
+ "normalize-path": "~3.0.0",
338
+ "readdirp": "~3.6.0"
339
+ },
340
+ "engines": {
341
+ "node": ">= 8.10.0"
342
+ },
343
+ "optionalDependencies": {
344
+ "fsevents": "~2.3.2"
345
+ }
346
+ },
347
+ "node_modules/combined-stream": {
348
+ "version": "1.0.8",
349
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
350
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
351
+ "dependencies": {
352
+ "delayed-stream": "~1.0.0"
353
+ },
354
+ "engines": {
355
+ "node": ">= 0.8"
356
+ }
357
+ },
358
+ "node_modules/concat-map": {
359
+ "version": "0.0.1",
360
+ "resolved": "https://bnpm.byted.org/concat-map/-/concat-map-0.0.1.tgz",
361
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
362
+ "dev": true
363
+ },
364
+ "node_modules/content-disposition": {
365
+ "version": "1.0.0",
366
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
367
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
368
+ "dependencies": {
369
+ "safe-buffer": "5.2.1"
370
+ },
371
+ "engines": {
372
+ "node": ">= 0.6"
373
+ }
374
+ },
375
+ "node_modules/content-type": {
376
+ "version": "1.0.5",
377
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
378
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
379
+ "engines": {
380
+ "node": ">= 0.6"
381
+ }
382
+ },
383
+ "node_modules/cookie": {
384
+ "version": "0.7.1",
385
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
386
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
387
+ "engines": {
388
+ "node": ">= 0.6"
389
+ }
390
+ },
391
+ "node_modules/cookie-signature": {
392
+ "version": "1.2.2",
393
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
394
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
395
+ "engines": {
396
+ "node": ">=6.6.0"
397
+ }
398
+ },
399
+ "node_modules/cors": {
400
+ "version": "2.8.5",
401
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
402
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
403
+ "dependencies": {
404
+ "object-assign": "^4",
405
+ "vary": "^1"
406
+ },
407
+ "engines": {
408
+ "node": ">= 0.10"
409
+ }
410
+ },
411
+ "node_modules/create-require": {
412
+ "version": "1.1.1",
413
+ "resolved": "https://bnpm.byted.org/create-require/-/create-require-1.1.1.tgz",
414
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
415
+ "dev": true
416
+ },
417
+ "node_modules/cross-spawn": {
418
+ "version": "7.0.6",
419
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
420
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
421
+ "dependencies": {
422
+ "path-key": "^3.1.0",
423
+ "shebang-command": "^2.0.0",
424
+ "which": "^2.0.1"
425
+ },
426
+ "engines": {
427
+ "node": ">= 8"
428
+ }
429
+ },
430
+ "node_modules/data-uri-to-buffer": {
431
+ "version": "4.0.1",
432
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
433
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
434
+ "engines": {
435
+ "node": ">= 12"
436
+ }
437
+ },
438
+ "node_modules/debug": {
439
+ "version": "4.3.6",
440
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
441
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
442
+ "dependencies": {
443
+ "ms": "2.1.2"
444
+ },
445
+ "engines": {
446
+ "node": ">=6.0"
447
+ },
448
+ "peerDependenciesMeta": {
449
+ "supports-color": {
450
+ "optional": true
451
+ }
452
+ }
453
+ },
454
+ "node_modules/delayed-stream": {
455
+ "version": "1.0.0",
456
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
457
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
458
+ "engines": {
459
+ "node": ">=0.4.0"
460
+ }
461
+ },
462
+ "node_modules/depd": {
463
+ "version": "2.0.0",
464
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
465
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
466
+ "engines": {
467
+ "node": ">= 0.8"
468
+ }
469
+ },
470
+ "node_modules/diff": {
471
+ "version": "4.0.2",
472
+ "resolved": "https://bnpm.byted.org/diff/-/diff-4.0.2.tgz",
473
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
474
+ "dev": true,
475
+ "engines": {
476
+ "node": ">=0.3.1"
477
+ }
478
+ },
479
+ "node_modules/dunder-proto": {
480
+ "version": "1.0.1",
481
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
482
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
483
+ "dependencies": {
484
+ "call-bind-apply-helpers": "^1.0.1",
485
+ "es-errors": "^1.3.0",
486
+ "gopd": "^1.2.0"
487
+ },
488
+ "engines": {
489
+ "node": ">= 0.4"
490
+ }
491
+ },
492
+ "node_modules/dynamic-dedupe": {
493
+ "version": "0.3.0",
494
+ "resolved": "https://bnpm.byted.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz",
495
+ "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==",
496
+ "dev": true,
497
+ "dependencies": {
498
+ "xtend": "^4.0.0"
499
+ }
500
+ },
501
+ "node_modules/ee-first": {
502
+ "version": "1.1.1",
503
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
504
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
505
+ },
506
+ "node_modules/encodeurl": {
507
+ "version": "2.0.0",
508
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
509
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
510
+ "engines": {
511
+ "node": ">= 0.8"
512
+ }
513
+ },
514
+ "node_modules/es-define-property": {
515
+ "version": "1.0.1",
516
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
517
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
518
+ "engines": {
519
+ "node": ">= 0.4"
520
+ }
521
+ },
522
+ "node_modules/es-errors": {
523
+ "version": "1.3.0",
524
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
525
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
526
+ "engines": {
527
+ "node": ">= 0.4"
528
+ }
529
+ },
530
+ "node_modules/es-object-atoms": {
531
+ "version": "1.1.1",
532
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
533
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
534
+ "dependencies": {
535
+ "es-errors": "^1.3.0"
536
+ },
537
+ "engines": {
538
+ "node": ">= 0.4"
539
+ }
540
+ },
541
+ "node_modules/es-set-tostringtag": {
542
+ "version": "2.1.0",
543
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
544
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
545
+ "dependencies": {
546
+ "es-errors": "^1.3.0",
547
+ "get-intrinsic": "^1.2.6",
548
+ "has-tostringtag": "^1.0.2",
549
+ "hasown": "^2.0.2"
550
+ },
551
+ "engines": {
552
+ "node": ">= 0.4"
553
+ }
554
+ },
555
+ "node_modules/escape-html": {
556
+ "version": "1.0.3",
557
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
558
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
559
+ },
560
+ "node_modules/etag": {
561
+ "version": "1.8.1",
562
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
563
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
564
+ "engines": {
565
+ "node": ">= 0.6"
566
+ }
567
+ },
568
+ "node_modules/eventsource": {
569
+ "version": "3.0.6",
570
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.6.tgz",
571
+ "integrity": "sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==",
572
+ "dependencies": {
573
+ "eventsource-parser": "^3.0.1"
574
+ },
575
+ "engines": {
576
+ "node": ">=18.0.0"
577
+ }
578
+ },
579
+ "node_modules/eventsource-parser": {
580
+ "version": "3.0.1",
581
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz",
582
+ "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==",
583
+ "engines": {
584
+ "node": ">=18.0.0"
585
+ }
586
+ },
587
+ "node_modules/express": {
588
+ "version": "5.0.1",
589
+ "resolved": "https://registry.npmjs.org/express/-/express-5.0.1.tgz",
590
+ "integrity": "sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==",
591
+ "dependencies": {
592
+ "accepts": "^2.0.0",
593
+ "body-parser": "^2.0.1",
594
+ "content-disposition": "^1.0.0",
595
+ "content-type": "~1.0.4",
596
+ "cookie": "0.7.1",
597
+ "cookie-signature": "^1.2.1",
598
+ "debug": "4.3.6",
599
+ "depd": "2.0.0",
600
+ "encodeurl": "~2.0.0",
601
+ "escape-html": "~1.0.3",
602
+ "etag": "~1.8.1",
603
+ "finalhandler": "^2.0.0",
604
+ "fresh": "2.0.0",
605
+ "http-errors": "2.0.0",
606
+ "merge-descriptors": "^2.0.0",
607
+ "methods": "~1.1.2",
608
+ "mime-types": "^3.0.0",
609
+ "on-finished": "2.4.1",
610
+ "once": "1.4.0",
611
+ "parseurl": "~1.3.3",
612
+ "proxy-addr": "~2.0.7",
613
+ "qs": "6.13.0",
614
+ "range-parser": "~1.2.1",
615
+ "router": "^2.0.0",
616
+ "safe-buffer": "5.2.1",
617
+ "send": "^1.1.0",
618
+ "serve-static": "^2.1.0",
619
+ "setprototypeof": "1.2.0",
620
+ "statuses": "2.0.1",
621
+ "type-is": "^2.0.0",
622
+ "utils-merge": "1.0.1",
623
+ "vary": "~1.1.2"
624
+ },
625
+ "engines": {
626
+ "node": ">= 18"
627
+ }
628
+ },
629
+ "node_modules/express-rate-limit": {
630
+ "version": "7.5.0",
631
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz",
632
+ "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==",
633
+ "engines": {
634
+ "node": ">= 16"
635
+ },
636
+ "funding": {
637
+ "url": "https://github.com/sponsors/express-rate-limit"
638
+ },
639
+ "peerDependencies": {
640
+ "express": "^4.11 || 5 || ^5.0.0-beta.1"
641
+ }
642
+ },
643
+ "node_modules/fetch-blob": {
644
+ "version": "3.2.0",
645
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
646
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
647
+ "funding": [
648
+ {
649
+ "type": "github",
650
+ "url": "https://github.com/sponsors/jimmywarting"
651
+ },
652
+ {
653
+ "type": "paypal",
654
+ "url": "https://paypal.me/jimmywarting"
655
+ }
656
+ ],
657
+ "dependencies": {
658
+ "node-domexception": "^1.0.0",
659
+ "web-streams-polyfill": "^3.0.3"
660
+ },
661
+ "engines": {
662
+ "node": "^12.20 || >= 14.13"
663
+ }
664
+ },
665
+ "node_modules/fill-range": {
666
+ "version": "7.1.1",
667
+ "resolved": "https://bnpm.byted.org/fill-range/-/fill-range-7.1.1.tgz",
668
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
669
+ "dev": true,
670
+ "dependencies": {
671
+ "to-regex-range": "^5.0.1"
672
+ },
673
+ "engines": {
674
+ "node": ">=8"
675
+ }
676
+ },
677
+ "node_modules/finalhandler": {
678
+ "version": "2.1.0",
679
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
680
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
681
+ "dependencies": {
682
+ "debug": "^4.4.0",
683
+ "encodeurl": "^2.0.0",
684
+ "escape-html": "^1.0.3",
685
+ "on-finished": "^2.4.1",
686
+ "parseurl": "^1.3.3",
687
+ "statuses": "^2.0.1"
688
+ },
689
+ "engines": {
690
+ "node": ">= 0.8"
691
+ }
692
+ },
693
+ "node_modules/finalhandler/node_modules/debug": {
694
+ "version": "4.4.0",
695
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
696
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
697
+ "dependencies": {
698
+ "ms": "^2.1.3"
699
+ },
700
+ "engines": {
701
+ "node": ">=6.0"
702
+ },
703
+ "peerDependenciesMeta": {
704
+ "supports-color": {
705
+ "optional": true
706
+ }
707
+ }
708
+ },
709
+ "node_modules/finalhandler/node_modules/ms": {
710
+ "version": "2.1.3",
711
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
712
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
713
+ },
714
+ "node_modules/follow-redirects": {
715
+ "version": "1.15.9",
716
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
717
+ "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
718
+ "funding": [
719
+ {
720
+ "type": "individual",
721
+ "url": "https://github.com/sponsors/RubenVerborgh"
722
+ }
723
+ ],
724
+ "engines": {
725
+ "node": ">=4.0"
726
+ },
727
+ "peerDependenciesMeta": {
728
+ "debug": {
729
+ "optional": true
730
+ }
731
+ }
732
+ },
733
+ "node_modules/form-data": {
734
+ "version": "4.0.2",
735
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
736
+ "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
737
+ "dependencies": {
738
+ "asynckit": "^0.4.0",
739
+ "combined-stream": "^1.0.8",
740
+ "es-set-tostringtag": "^2.1.0",
741
+ "mime-types": "^2.1.12"
742
+ },
743
+ "engines": {
744
+ "node": ">= 6"
745
+ }
746
+ },
747
+ "node_modules/form-data/node_modules/mime-db": {
748
+ "version": "1.52.0",
749
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
750
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
751
+ "engines": {
752
+ "node": ">= 0.6"
753
+ }
754
+ },
755
+ "node_modules/form-data/node_modules/mime-types": {
756
+ "version": "2.1.35",
757
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
758
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
759
+ "dependencies": {
760
+ "mime-db": "1.52.0"
761
+ },
762
+ "engines": {
763
+ "node": ">= 0.6"
764
+ }
765
+ },
766
+ "node_modules/formdata-polyfill": {
767
+ "version": "4.0.10",
768
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
769
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
770
+ "dependencies": {
771
+ "fetch-blob": "^3.1.2"
772
+ },
773
+ "engines": {
774
+ "node": ">=12.20.0"
775
+ }
776
+ },
777
+ "node_modules/forwarded": {
778
+ "version": "0.2.0",
779
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
780
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
781
+ "engines": {
782
+ "node": ">= 0.6"
783
+ }
784
+ },
785
+ "node_modules/fresh": {
786
+ "version": "2.0.0",
787
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
788
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
789
+ "engines": {
790
+ "node": ">= 0.8"
791
+ }
792
+ },
793
+ "node_modules/fs.realpath": {
794
+ "version": "1.0.0",
795
+ "resolved": "https://bnpm.byted.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
796
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
797
+ "dev": true
798
+ },
799
+ "node_modules/fsevents": {
800
+ "version": "2.3.3",
801
+ "resolved": "https://bnpm.byted.org/fsevents/-/fsevents-2.3.3.tgz",
802
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
803
+ "dev": true,
804
+ "hasInstallScript": true,
805
+ "optional": true,
806
+ "os": [
807
+ "darwin"
808
+ ],
809
+ "engines": {
810
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
811
+ }
812
+ },
813
+ "node_modules/function-bind": {
814
+ "version": "1.1.2",
815
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
816
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
817
+ "funding": {
818
+ "url": "https://github.com/sponsors/ljharb"
819
+ }
820
+ },
821
+ "node_modules/get-intrinsic": {
822
+ "version": "1.3.0",
823
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
824
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
825
+ "dependencies": {
826
+ "call-bind-apply-helpers": "^1.0.2",
827
+ "es-define-property": "^1.0.1",
828
+ "es-errors": "^1.3.0",
829
+ "es-object-atoms": "^1.1.1",
830
+ "function-bind": "^1.1.2",
831
+ "get-proto": "^1.0.1",
832
+ "gopd": "^1.2.0",
833
+ "has-symbols": "^1.1.0",
834
+ "hasown": "^2.0.2",
835
+ "math-intrinsics": "^1.1.0"
836
+ },
837
+ "engines": {
838
+ "node": ">= 0.4"
839
+ },
840
+ "funding": {
841
+ "url": "https://github.com/sponsors/ljharb"
842
+ }
843
+ },
844
+ "node_modules/get-proto": {
845
+ "version": "1.0.1",
846
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
847
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
848
+ "dependencies": {
849
+ "dunder-proto": "^1.0.1",
850
+ "es-object-atoms": "^1.0.0"
851
+ },
852
+ "engines": {
853
+ "node": ">= 0.4"
854
+ }
855
+ },
856
+ "node_modules/glob": {
857
+ "version": "7.2.3",
858
+ "resolved": "https://bnpm.byted.org/glob/-/glob-7.2.3.tgz",
859
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
860
+ "deprecated": "Glob versions prior to v9 are no longer supported",
861
+ "dev": true,
862
+ "dependencies": {
863
+ "fs.realpath": "^1.0.0",
864
+ "inflight": "^1.0.4",
865
+ "inherits": "2",
866
+ "minimatch": "^3.1.1",
867
+ "once": "^1.3.0",
868
+ "path-is-absolute": "^1.0.0"
869
+ },
870
+ "engines": {
871
+ "node": "*"
872
+ }
873
+ },
874
+ "node_modules/glob-parent": {
875
+ "version": "5.1.2",
876
+ "resolved": "https://bnpm.byted.org/glob-parent/-/glob-parent-5.1.2.tgz",
877
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
878
+ "dev": true,
879
+ "dependencies": {
880
+ "is-glob": "^4.0.1"
881
+ },
882
+ "engines": {
883
+ "node": ">= 6"
884
+ }
885
+ },
886
+ "node_modules/gopd": {
887
+ "version": "1.2.0",
888
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
889
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
890
+ "engines": {
891
+ "node": ">= 0.4"
892
+ },
893
+ "funding": {
894
+ "url": "https://github.com/sponsors/ljharb"
895
+ }
896
+ },
897
+ "node_modules/has-symbols": {
898
+ "version": "1.1.0",
899
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
900
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
901
+ "engines": {
902
+ "node": ">= 0.4"
903
+ },
904
+ "funding": {
905
+ "url": "https://github.com/sponsors/ljharb"
906
+ }
907
+ },
908
+ "node_modules/has-tostringtag": {
909
+ "version": "1.0.2",
910
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
911
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
912
+ "dependencies": {
913
+ "has-symbols": "^1.0.3"
914
+ },
915
+ "engines": {
916
+ "node": ">= 0.4"
917
+ },
918
+ "funding": {
919
+ "url": "https://github.com/sponsors/ljharb"
920
+ }
921
+ },
922
+ "node_modules/hasown": {
923
+ "version": "2.0.2",
924
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
925
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
926
+ "dependencies": {
927
+ "function-bind": "^1.1.2"
928
+ },
929
+ "engines": {
930
+ "node": ">= 0.4"
931
+ }
932
+ },
933
+ "node_modules/http-errors": {
934
+ "version": "2.0.0",
935
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
936
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
937
+ "dependencies": {
938
+ "depd": "2.0.0",
939
+ "inherits": "2.0.4",
940
+ "setprototypeof": "1.2.0",
941
+ "statuses": "2.0.1",
942
+ "toidentifier": "1.0.1"
943
+ },
944
+ "engines": {
945
+ "node": ">= 0.8"
946
+ }
947
+ },
948
+ "node_modules/iconv-lite": {
949
+ "version": "0.6.3",
950
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
951
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
952
+ "dependencies": {
953
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
954
+ },
955
+ "engines": {
956
+ "node": ">=0.10.0"
957
+ }
958
+ },
959
+ "node_modules/inflight": {
960
+ "version": "1.0.6",
961
+ "resolved": "https://bnpm.byted.org/inflight/-/inflight-1.0.6.tgz",
962
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
963
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
964
+ "dev": true,
965
+ "dependencies": {
966
+ "once": "^1.3.0",
967
+ "wrappy": "1"
968
+ }
969
+ },
970
+ "node_modules/inherits": {
971
+ "version": "2.0.4",
972
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
973
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
974
+ },
975
+ "node_modules/ipaddr.js": {
976
+ "version": "1.9.1",
977
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
978
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
979
+ "engines": {
980
+ "node": ">= 0.10"
981
+ }
982
+ },
983
+ "node_modules/is-binary-path": {
984
+ "version": "2.1.0",
985
+ "resolved": "https://bnpm.byted.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
986
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
987
+ "dev": true,
988
+ "dependencies": {
989
+ "binary-extensions": "^2.0.0"
990
+ },
991
+ "engines": {
992
+ "node": ">=8"
993
+ }
994
+ },
995
+ "node_modules/is-core-module": {
996
+ "version": "2.16.1",
997
+ "resolved": "https://bnpm.byted.org/is-core-module/-/is-core-module-2.16.1.tgz",
998
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
999
+ "dev": true,
1000
+ "dependencies": {
1001
+ "hasown": "^2.0.2"
1002
+ },
1003
+ "engines": {
1004
+ "node": ">= 0.4"
1005
+ }
1006
+ },
1007
+ "node_modules/is-extglob": {
1008
+ "version": "2.1.1",
1009
+ "resolved": "https://bnpm.byted.org/is-extglob/-/is-extglob-2.1.1.tgz",
1010
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
1011
+ "dev": true,
1012
+ "engines": {
1013
+ "node": ">=0.10.0"
1014
+ }
1015
+ },
1016
+ "node_modules/is-glob": {
1017
+ "version": "4.0.3",
1018
+ "resolved": "https://bnpm.byted.org/is-glob/-/is-glob-4.0.3.tgz",
1019
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
1020
+ "dev": true,
1021
+ "dependencies": {
1022
+ "is-extglob": "^2.1.1"
1023
+ },
1024
+ "engines": {
1025
+ "node": ">=0.10.0"
1026
+ }
1027
+ },
1028
+ "node_modules/is-number": {
1029
+ "version": "7.0.0",
1030
+ "resolved": "https://bnpm.byted.org/is-number/-/is-number-7.0.0.tgz",
1031
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1032
+ "dev": true,
1033
+ "engines": {
1034
+ "node": ">=0.12.0"
1035
+ }
1036
+ },
1037
+ "node_modules/is-promise": {
1038
+ "version": "4.0.0",
1039
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
1040
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
1041
+ },
1042
+ "node_modules/isexe": {
1043
+ "version": "2.0.0",
1044
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1045
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
1046
+ },
1047
+ "node_modules/make-error": {
1048
+ "version": "1.3.6",
1049
+ "resolved": "https://bnpm.byted.org/make-error/-/make-error-1.3.6.tgz",
1050
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
1051
+ "dev": true
1052
+ },
1053
+ "node_modules/math-intrinsics": {
1054
+ "version": "1.1.0",
1055
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
1056
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
1057
+ "engines": {
1058
+ "node": ">= 0.4"
1059
+ }
1060
+ },
1061
+ "node_modules/media-typer": {
1062
+ "version": "1.1.0",
1063
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
1064
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
1065
+ "engines": {
1066
+ "node": ">= 0.8"
1067
+ }
1068
+ },
1069
+ "node_modules/merge-descriptors": {
1070
+ "version": "2.0.0",
1071
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
1072
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
1073
+ "engines": {
1074
+ "node": ">=18"
1075
+ },
1076
+ "funding": {
1077
+ "url": "https://github.com/sponsors/sindresorhus"
1078
+ }
1079
+ },
1080
+ "node_modules/methods": {
1081
+ "version": "1.1.2",
1082
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1083
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
1084
+ "engines": {
1085
+ "node": ">= 0.6"
1086
+ }
1087
+ },
1088
+ "node_modules/mime-db": {
1089
+ "version": "1.54.0",
1090
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
1091
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
1092
+ "engines": {
1093
+ "node": ">= 0.6"
1094
+ }
1095
+ },
1096
+ "node_modules/mime-types": {
1097
+ "version": "3.0.1",
1098
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
1099
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
1100
+ "dependencies": {
1101
+ "mime-db": "^1.54.0"
1102
+ },
1103
+ "engines": {
1104
+ "node": ">= 0.6"
1105
+ }
1106
+ },
1107
+ "node_modules/minimatch": {
1108
+ "version": "3.1.2",
1109
+ "resolved": "https://bnpm.byted.org/minimatch/-/minimatch-3.1.2.tgz",
1110
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1111
+ "dev": true,
1112
+ "dependencies": {
1113
+ "brace-expansion": "^1.1.7"
1114
+ },
1115
+ "engines": {
1116
+ "node": "*"
1117
+ }
1118
+ },
1119
+ "node_modules/minimist": {
1120
+ "version": "1.2.8",
1121
+ "resolved": "https://bnpm.byted.org/minimist/-/minimist-1.2.8.tgz",
1122
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
1123
+ "dev": true
1124
+ },
1125
+ "node_modules/mkdirp": {
1126
+ "version": "1.0.4",
1127
+ "resolved": "https://bnpm.byted.org/mkdirp/-/mkdirp-1.0.4.tgz",
1128
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
1129
+ "dev": true,
1130
+ "bin": {
1131
+ "mkdirp": "bin/cmd.js"
1132
+ },
1133
+ "engines": {
1134
+ "node": ">=10"
1135
+ }
1136
+ },
1137
+ "node_modules/ms": {
1138
+ "version": "2.1.2",
1139
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1140
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
1141
+ },
1142
+ "node_modules/negotiator": {
1143
+ "version": "1.0.0",
1144
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
1145
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
1146
+ "engines": {
1147
+ "node": ">= 0.6"
1148
+ }
1149
+ },
1150
+ "node_modules/node-domexception": {
1151
+ "version": "1.0.0",
1152
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
1153
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
1154
+ "funding": [
1155
+ {
1156
+ "type": "github",
1157
+ "url": "https://github.com/sponsors/jimmywarting"
1158
+ },
1159
+ {
1160
+ "type": "github",
1161
+ "url": "https://paypal.me/jimmywarting"
1162
+ }
1163
+ ],
1164
+ "engines": {
1165
+ "node": ">=10.5.0"
1166
+ }
1167
+ },
1168
+ "node_modules/node-fetch": {
1169
+ "version": "3.3.2",
1170
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
1171
+ "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
1172
+ "dependencies": {
1173
+ "data-uri-to-buffer": "^4.0.0",
1174
+ "fetch-blob": "^3.1.4",
1175
+ "formdata-polyfill": "^4.0.10"
1176
+ },
1177
+ "engines": {
1178
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
1179
+ },
1180
+ "funding": {
1181
+ "type": "opencollective",
1182
+ "url": "https://opencollective.com/node-fetch"
1183
+ }
1184
+ },
1185
+ "node_modules/normalize-path": {
1186
+ "version": "3.0.0",
1187
+ "resolved": "https://bnpm.byted.org/normalize-path/-/normalize-path-3.0.0.tgz",
1188
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1189
+ "dev": true,
1190
+ "engines": {
1191
+ "node": ">=0.10.0"
1192
+ }
1193
+ },
1194
+ "node_modules/object-assign": {
1195
+ "version": "4.1.1",
1196
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1197
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1198
+ "engines": {
1199
+ "node": ">=0.10.0"
1200
+ }
1201
+ },
1202
+ "node_modules/object-inspect": {
1203
+ "version": "1.13.4",
1204
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1205
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1206
+ "engines": {
1207
+ "node": ">= 0.4"
1208
+ },
1209
+ "funding": {
1210
+ "url": "https://github.com/sponsors/ljharb"
1211
+ }
1212
+ },
1213
+ "node_modules/on-finished": {
1214
+ "version": "2.4.1",
1215
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1216
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1217
+ "dependencies": {
1218
+ "ee-first": "1.1.1"
1219
+ },
1220
+ "engines": {
1221
+ "node": ">= 0.8"
1222
+ }
1223
+ },
1224
+ "node_modules/once": {
1225
+ "version": "1.4.0",
1226
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1227
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1228
+ "dependencies": {
1229
+ "wrappy": "1"
1230
+ }
1231
+ },
1232
+ "node_modules/parseurl": {
1233
+ "version": "1.3.3",
1234
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1235
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1236
+ "engines": {
1237
+ "node": ">= 0.8"
1238
+ }
1239
+ },
1240
+ "node_modules/path-is-absolute": {
1241
+ "version": "1.0.1",
1242
+ "resolved": "https://bnpm.byted.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1243
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
1244
+ "dev": true,
1245
+ "engines": {
1246
+ "node": ">=0.10.0"
1247
+ }
1248
+ },
1249
+ "node_modules/path-key": {
1250
+ "version": "3.1.1",
1251
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1252
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1253
+ "engines": {
1254
+ "node": ">=8"
1255
+ }
1256
+ },
1257
+ "node_modules/path-parse": {
1258
+ "version": "1.0.7",
1259
+ "resolved": "https://bnpm.byted.org/path-parse/-/path-parse-1.0.7.tgz",
1260
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
1261
+ "dev": true
1262
+ },
1263
+ "node_modules/path-to-regexp": {
1264
+ "version": "8.2.0",
1265
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
1266
+ "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
1267
+ "engines": {
1268
+ "node": ">=16"
1269
+ }
1270
+ },
1271
+ "node_modules/picomatch": {
1272
+ "version": "2.3.1",
1273
+ "resolved": "https://bnpm.byted.org/picomatch/-/picomatch-2.3.1.tgz",
1274
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1275
+ "dev": true,
1276
+ "engines": {
1277
+ "node": ">=8.6"
1278
+ }
1279
+ },
1280
+ "node_modules/pkce-challenge": {
1281
+ "version": "4.1.0",
1282
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz",
1283
+ "integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==",
1284
+ "engines": {
1285
+ "node": ">=16.20.0"
1286
+ }
1287
+ },
1288
+ "node_modules/proxy-addr": {
1289
+ "version": "2.0.7",
1290
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1291
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1292
+ "dependencies": {
1293
+ "forwarded": "0.2.0",
1294
+ "ipaddr.js": "1.9.1"
1295
+ },
1296
+ "engines": {
1297
+ "node": ">= 0.10"
1298
+ }
1299
+ },
1300
+ "node_modules/proxy-from-env": {
1301
+ "version": "1.1.0",
1302
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
1303
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
1304
+ },
1305
+ "node_modules/qs": {
1306
+ "version": "6.13.0",
1307
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
1308
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
1309
+ "dependencies": {
1310
+ "side-channel": "^1.0.6"
1311
+ },
1312
+ "engines": {
1313
+ "node": ">=0.6"
1314
+ },
1315
+ "funding": {
1316
+ "url": "https://github.com/sponsors/ljharb"
1317
+ }
1318
+ },
1319
+ "node_modules/range-parser": {
1320
+ "version": "1.2.1",
1321
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1322
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1323
+ "engines": {
1324
+ "node": ">= 0.6"
1325
+ }
1326
+ },
1327
+ "node_modules/raw-body": {
1328
+ "version": "3.0.0",
1329
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
1330
+ "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
1331
+ "dependencies": {
1332
+ "bytes": "3.1.2",
1333
+ "http-errors": "2.0.0",
1334
+ "iconv-lite": "0.6.3",
1335
+ "unpipe": "1.0.0"
1336
+ },
1337
+ "engines": {
1338
+ "node": ">= 0.8"
1339
+ }
1340
+ },
1341
+ "node_modules/readdirp": {
1342
+ "version": "3.6.0",
1343
+ "resolved": "https://bnpm.byted.org/readdirp/-/readdirp-3.6.0.tgz",
1344
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1345
+ "dev": true,
1346
+ "dependencies": {
1347
+ "picomatch": "^2.2.1"
1348
+ },
1349
+ "engines": {
1350
+ "node": ">=8.10.0"
1351
+ }
1352
+ },
1353
+ "node_modules/resolve": {
1354
+ "version": "1.22.10",
1355
+ "resolved": "https://bnpm.byted.org/resolve/-/resolve-1.22.10.tgz",
1356
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
1357
+ "dev": true,
1358
+ "dependencies": {
1359
+ "is-core-module": "^2.16.0",
1360
+ "path-parse": "^1.0.7",
1361
+ "supports-preserve-symlinks-flag": "^1.0.0"
1362
+ },
1363
+ "bin": {
1364
+ "resolve": "bin/resolve"
1365
+ },
1366
+ "engines": {
1367
+ "node": ">= 0.4"
1368
+ }
1369
+ },
1370
+ "node_modules/rimraf": {
1371
+ "version": "2.7.1",
1372
+ "resolved": "https://bnpm.byted.org/rimraf/-/rimraf-2.7.1.tgz",
1373
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
1374
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
1375
+ "dev": true,
1376
+ "dependencies": {
1377
+ "glob": "^7.1.3"
1378
+ },
1379
+ "bin": {
1380
+ "rimraf": "bin.js"
1381
+ }
1382
+ },
1383
+ "node_modules/router": {
1384
+ "version": "2.2.0",
1385
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
1386
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
1387
+ "dependencies": {
1388
+ "debug": "^4.4.0",
1389
+ "depd": "^2.0.0",
1390
+ "is-promise": "^4.0.0",
1391
+ "parseurl": "^1.3.3",
1392
+ "path-to-regexp": "^8.0.0"
1393
+ },
1394
+ "engines": {
1395
+ "node": ">= 18"
1396
+ }
1397
+ },
1398
+ "node_modules/router/node_modules/debug": {
1399
+ "version": "4.4.0",
1400
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
1401
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
1402
+ "dependencies": {
1403
+ "ms": "^2.1.3"
1404
+ },
1405
+ "engines": {
1406
+ "node": ">=6.0"
1407
+ },
1408
+ "peerDependenciesMeta": {
1409
+ "supports-color": {
1410
+ "optional": true
1411
+ }
1412
+ }
1413
+ },
1414
+ "node_modules/router/node_modules/ms": {
1415
+ "version": "2.1.3",
1416
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1417
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1418
+ },
1419
+ "node_modules/safe-buffer": {
1420
+ "version": "5.2.1",
1421
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1422
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1423
+ "funding": [
1424
+ {
1425
+ "type": "github",
1426
+ "url": "https://github.com/sponsors/feross"
1427
+ },
1428
+ {
1429
+ "type": "patreon",
1430
+ "url": "https://www.patreon.com/feross"
1431
+ },
1432
+ {
1433
+ "type": "consulting",
1434
+ "url": "https://feross.org/support"
1435
+ }
1436
+ ]
1437
+ },
1438
+ "node_modules/safer-buffer": {
1439
+ "version": "2.1.2",
1440
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1441
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1442
+ },
1443
+ "node_modules/send": {
1444
+ "version": "1.2.0",
1445
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
1446
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
1447
+ "dependencies": {
1448
+ "debug": "^4.3.5",
1449
+ "encodeurl": "^2.0.0",
1450
+ "escape-html": "^1.0.3",
1451
+ "etag": "^1.8.1",
1452
+ "fresh": "^2.0.0",
1453
+ "http-errors": "^2.0.0",
1454
+ "mime-types": "^3.0.1",
1455
+ "ms": "^2.1.3",
1456
+ "on-finished": "^2.4.1",
1457
+ "range-parser": "^1.2.1",
1458
+ "statuses": "^2.0.1"
1459
+ },
1460
+ "engines": {
1461
+ "node": ">= 18"
1462
+ }
1463
+ },
1464
+ "node_modules/send/node_modules/ms": {
1465
+ "version": "2.1.3",
1466
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1467
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1468
+ },
1469
+ "node_modules/serve-static": {
1470
+ "version": "2.2.0",
1471
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
1472
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
1473
+ "dependencies": {
1474
+ "encodeurl": "^2.0.0",
1475
+ "escape-html": "^1.0.3",
1476
+ "parseurl": "^1.3.3",
1477
+ "send": "^1.2.0"
1478
+ },
1479
+ "engines": {
1480
+ "node": ">= 18"
1481
+ }
1482
+ },
1483
+ "node_modules/setprototypeof": {
1484
+ "version": "1.2.0",
1485
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1486
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
1487
+ },
1488
+ "node_modules/shebang-command": {
1489
+ "version": "2.0.0",
1490
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1491
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1492
+ "dependencies": {
1493
+ "shebang-regex": "^3.0.0"
1494
+ },
1495
+ "engines": {
1496
+ "node": ">=8"
1497
+ }
1498
+ },
1499
+ "node_modules/shebang-regex": {
1500
+ "version": "3.0.0",
1501
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1502
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1503
+ "engines": {
1504
+ "node": ">=8"
1505
+ }
1506
+ },
1507
+ "node_modules/side-channel": {
1508
+ "version": "1.1.0",
1509
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
1510
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
1511
+ "dependencies": {
1512
+ "es-errors": "^1.3.0",
1513
+ "object-inspect": "^1.13.3",
1514
+ "side-channel-list": "^1.0.0",
1515
+ "side-channel-map": "^1.0.1",
1516
+ "side-channel-weakmap": "^1.0.2"
1517
+ },
1518
+ "engines": {
1519
+ "node": ">= 0.4"
1520
+ },
1521
+ "funding": {
1522
+ "url": "https://github.com/sponsors/ljharb"
1523
+ }
1524
+ },
1525
+ "node_modules/side-channel-list": {
1526
+ "version": "1.0.0",
1527
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
1528
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
1529
+ "dependencies": {
1530
+ "es-errors": "^1.3.0",
1531
+ "object-inspect": "^1.13.3"
1532
+ },
1533
+ "engines": {
1534
+ "node": ">= 0.4"
1535
+ },
1536
+ "funding": {
1537
+ "url": "https://github.com/sponsors/ljharb"
1538
+ }
1539
+ },
1540
+ "node_modules/side-channel-map": {
1541
+ "version": "1.0.1",
1542
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
1543
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
1544
+ "dependencies": {
1545
+ "call-bound": "^1.0.2",
1546
+ "es-errors": "^1.3.0",
1547
+ "get-intrinsic": "^1.2.5",
1548
+ "object-inspect": "^1.13.3"
1549
+ },
1550
+ "engines": {
1551
+ "node": ">= 0.4"
1552
+ },
1553
+ "funding": {
1554
+ "url": "https://github.com/sponsors/ljharb"
1555
+ }
1556
+ },
1557
+ "node_modules/side-channel-weakmap": {
1558
+ "version": "1.0.2",
1559
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
1560
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
1561
+ "dependencies": {
1562
+ "call-bound": "^1.0.2",
1563
+ "es-errors": "^1.3.0",
1564
+ "get-intrinsic": "^1.2.5",
1565
+ "object-inspect": "^1.13.3",
1566
+ "side-channel-map": "^1.0.1"
1567
+ },
1568
+ "engines": {
1569
+ "node": ">= 0.4"
1570
+ },
1571
+ "funding": {
1572
+ "url": "https://github.com/sponsors/ljharb"
1573
+ }
1574
+ },
1575
+ "node_modules/source-map": {
1576
+ "version": "0.6.1",
1577
+ "resolved": "https://bnpm.byted.org/source-map/-/source-map-0.6.1.tgz",
1578
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1579
+ "dev": true,
1580
+ "engines": {
1581
+ "node": ">=0.10.0"
1582
+ }
1583
+ },
1584
+ "node_modules/source-map-support": {
1585
+ "version": "0.5.21",
1586
+ "resolved": "https://bnpm.byted.org/source-map-support/-/source-map-support-0.5.21.tgz",
1587
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
1588
+ "dev": true,
1589
+ "dependencies": {
1590
+ "buffer-from": "^1.0.0",
1591
+ "source-map": "^0.6.0"
1592
+ }
1593
+ },
1594
+ "node_modules/statuses": {
1595
+ "version": "2.0.1",
1596
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1597
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
1598
+ "engines": {
1599
+ "node": ">= 0.8"
1600
+ }
1601
+ },
1602
+ "node_modules/strip-bom": {
1603
+ "version": "3.0.0",
1604
+ "resolved": "https://bnpm.byted.org/strip-bom/-/strip-bom-3.0.0.tgz",
1605
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
1606
+ "dev": true,
1607
+ "engines": {
1608
+ "node": ">=4"
1609
+ }
1610
+ },
1611
+ "node_modules/strip-json-comments": {
1612
+ "version": "2.0.1",
1613
+ "resolved": "https://bnpm.byted.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
1614
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
1615
+ "dev": true,
1616
+ "engines": {
1617
+ "node": ">=0.10.0"
1618
+ }
1619
+ },
1620
+ "node_modules/supports-preserve-symlinks-flag": {
1621
+ "version": "1.0.0",
1622
+ "resolved": "https://bnpm.byted.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
1623
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
1624
+ "dev": true,
1625
+ "engines": {
1626
+ "node": ">= 0.4"
1627
+ }
1628
+ },
1629
+ "node_modules/to-regex-range": {
1630
+ "version": "5.0.1",
1631
+ "resolved": "https://bnpm.byted.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1632
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1633
+ "dev": true,
1634
+ "dependencies": {
1635
+ "is-number": "^7.0.0"
1636
+ },
1637
+ "engines": {
1638
+ "node": ">=8.0"
1639
+ }
1640
+ },
1641
+ "node_modules/toidentifier": {
1642
+ "version": "1.0.1",
1643
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1644
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1645
+ "engines": {
1646
+ "node": ">=0.6"
1647
+ }
1648
+ },
1649
+ "node_modules/tree-kill": {
1650
+ "version": "1.2.2",
1651
+ "resolved": "https://bnpm.byted.org/tree-kill/-/tree-kill-1.2.2.tgz",
1652
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
1653
+ "dev": true,
1654
+ "bin": {
1655
+ "tree-kill": "cli.js"
1656
+ }
1657
+ },
1658
+ "node_modules/ts-node": {
1659
+ "version": "10.9.2",
1660
+ "resolved": "https://bnpm.byted.org/ts-node/-/ts-node-10.9.2.tgz",
1661
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
1662
+ "dev": true,
1663
+ "dependencies": {
1664
+ "@cspotcode/source-map-support": "^0.8.0",
1665
+ "@tsconfig/node10": "^1.0.7",
1666
+ "@tsconfig/node12": "^1.0.7",
1667
+ "@tsconfig/node14": "^1.0.0",
1668
+ "@tsconfig/node16": "^1.0.2",
1669
+ "acorn": "^8.4.1",
1670
+ "acorn-walk": "^8.1.1",
1671
+ "arg": "^4.1.0",
1672
+ "create-require": "^1.1.0",
1673
+ "diff": "^4.0.1",
1674
+ "make-error": "^1.1.1",
1675
+ "v8-compile-cache-lib": "^3.0.1",
1676
+ "yn": "3.1.1"
1677
+ },
1678
+ "bin": {
1679
+ "ts-node": "dist/bin.js",
1680
+ "ts-node-cwd": "dist/bin-cwd.js",
1681
+ "ts-node-esm": "dist/bin-esm.js",
1682
+ "ts-node-script": "dist/bin-script.js",
1683
+ "ts-node-transpile-only": "dist/bin-transpile.js",
1684
+ "ts-script": "dist/bin-script-deprecated.js"
1685
+ },
1686
+ "peerDependencies": {
1687
+ "@swc/core": ">=1.2.50",
1688
+ "@swc/wasm": ">=1.2.50",
1689
+ "@types/node": "*",
1690
+ "typescript": ">=2.7"
1691
+ },
1692
+ "peerDependenciesMeta": {
1693
+ "@swc/core": {
1694
+ "optional": true
1695
+ },
1696
+ "@swc/wasm": {
1697
+ "optional": true
1698
+ }
1699
+ }
1700
+ },
1701
+ "node_modules/ts-node-dev": {
1702
+ "version": "2.0.0",
1703
+ "resolved": "https://bnpm.byted.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz",
1704
+ "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==",
1705
+ "dev": true,
1706
+ "dependencies": {
1707
+ "chokidar": "^3.5.1",
1708
+ "dynamic-dedupe": "^0.3.0",
1709
+ "minimist": "^1.2.6",
1710
+ "mkdirp": "^1.0.4",
1711
+ "resolve": "^1.0.0",
1712
+ "rimraf": "^2.6.1",
1713
+ "source-map-support": "^0.5.12",
1714
+ "tree-kill": "^1.2.2",
1715
+ "ts-node": "^10.4.0",
1716
+ "tsconfig": "^7.0.0"
1717
+ },
1718
+ "bin": {
1719
+ "ts-node-dev": "lib/bin.js",
1720
+ "tsnd": "lib/bin.js"
1721
+ },
1722
+ "engines": {
1723
+ "node": ">=0.8.0"
1724
+ },
1725
+ "peerDependencies": {
1726
+ "node-notifier": "*",
1727
+ "typescript": "*"
1728
+ },
1729
+ "peerDependenciesMeta": {
1730
+ "node-notifier": {
1731
+ "optional": true
1732
+ }
1733
+ }
1734
+ },
1735
+ "node_modules/tsconfig": {
1736
+ "version": "7.0.0",
1737
+ "resolved": "https://bnpm.byted.org/tsconfig/-/tsconfig-7.0.0.tgz",
1738
+ "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==",
1739
+ "dev": true,
1740
+ "dependencies": {
1741
+ "@types/strip-bom": "^3.0.0",
1742
+ "@types/strip-json-comments": "0.0.30",
1743
+ "strip-bom": "^3.0.0",
1744
+ "strip-json-comments": "^2.0.0"
1745
+ }
1746
+ },
1747
+ "node_modules/type-is": {
1748
+ "version": "2.0.1",
1749
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
1750
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
1751
+ "dependencies": {
1752
+ "content-type": "^1.0.5",
1753
+ "media-typer": "^1.1.0",
1754
+ "mime-types": "^3.0.0"
1755
+ },
1756
+ "engines": {
1757
+ "node": ">= 0.6"
1758
+ }
1759
+ },
1760
+ "node_modules/typescript": {
1761
+ "version": "5.8.2",
1762
+ "resolved": "https://bnpm.byted.org/typescript/-/typescript-5.8.2.tgz",
1763
+ "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
1764
+ "dev": true,
1765
+ "bin": {
1766
+ "tsc": "bin/tsc",
1767
+ "tsserver": "bin/tsserver"
1768
+ },
1769
+ "engines": {
1770
+ "node": ">=14.17"
1771
+ }
1772
+ },
1773
+ "node_modules/undici-types": {
1774
+ "version": "6.20.0",
1775
+ "resolved": "https://bnpm.byted.org/undici-types/-/undici-types-6.20.0.tgz",
1776
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
1777
+ "dev": true
1778
+ },
1779
+ "node_modules/unpipe": {
1780
+ "version": "1.0.0",
1781
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1782
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1783
+ "engines": {
1784
+ "node": ">= 0.8"
1785
+ }
1786
+ },
1787
+ "node_modules/utils-merge": {
1788
+ "version": "1.0.1",
1789
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1790
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
1791
+ "engines": {
1792
+ "node": ">= 0.4.0"
1793
+ }
1794
+ },
1795
+ "node_modules/v8-compile-cache-lib": {
1796
+ "version": "3.0.1",
1797
+ "resolved": "https://bnpm.byted.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
1798
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
1799
+ "dev": true
1800
+ },
1801
+ "node_modules/vary": {
1802
+ "version": "1.1.2",
1803
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1804
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1805
+ "engines": {
1806
+ "node": ">= 0.8"
1807
+ }
1808
+ },
1809
+ "node_modules/web-streams-polyfill": {
1810
+ "version": "3.3.3",
1811
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
1812
+ "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
1813
+ "engines": {
1814
+ "node": ">= 8"
1815
+ }
1816
+ },
1817
+ "node_modules/which": {
1818
+ "version": "2.0.2",
1819
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1820
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1821
+ "dependencies": {
1822
+ "isexe": "^2.0.0"
1823
+ },
1824
+ "bin": {
1825
+ "node-which": "bin/node-which"
1826
+ },
1827
+ "engines": {
1828
+ "node": ">= 8"
1829
+ }
1830
+ },
1831
+ "node_modules/wrappy": {
1832
+ "version": "1.0.2",
1833
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1834
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
1835
+ },
1836
+ "node_modules/xtend": {
1837
+ "version": "4.0.2",
1838
+ "resolved": "https://bnpm.byted.org/xtend/-/xtend-4.0.2.tgz",
1839
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
1840
+ "dev": true,
1841
+ "engines": {
1842
+ "node": ">=0.4"
1843
+ }
1844
+ },
1845
+ "node_modules/yn": {
1846
+ "version": "3.1.1",
1847
+ "resolved": "https://bnpm.byted.org/yn/-/yn-3.1.1.tgz",
1848
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
1849
+ "dev": true,
1850
+ "engines": {
1851
+ "node": ">=6"
1852
+ }
1853
+ },
1854
+ "node_modules/zod": {
1855
+ "version": "3.24.2",
1856
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
1857
+ "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
1858
+ "funding": {
1859
+ "url": "https://github.com/sponsors/colinhacks"
1860
+ }
1861
+ },
1862
+ "node_modules/zod-to-json-schema": {
1863
+ "version": "3.24.5",
1864
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz",
1865
+ "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==",
1866
+ "peerDependencies": {
1867
+ "zod": "^3.24.1"
1868
+ }
1869
+ }
1870
+ }
1871
+ }
sticker-server/package.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "sticker-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP Server for searching and sending stickers based on emotions",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "node index.js",
9
+ "build": "tsc -p tsconfig.json"
10
+ },
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "*",
13
+ "axios": "^1.6.0",
14
+ "node-fetch": "^3.3.2"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^22.13.14",
18
+ "ts-node": "^10.9.2",
19
+ "ts-node-dev": "^2.0.0",
20
+ "typescript": "^5.3.3"
21
+ }
22
+ }
sticker-server/tsconfig.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2024",
4
+ "module": "NodeNext",
5
+ "outDir": "./dist",
6
+ "rootDir": ".",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true
11
+ },
12
+ "include": ["**/*.ts"],
13
+ "exclude": ["node_modules"]
14
+ }
sticker.db ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:705b4affd214a39db0184067d46b599ae5649c110ff700a7c277015dc4d21bea
3
+ size 716800
upload.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 批量处理贴纸图片的工具模块
3
+
4
+ 功能:
5
+ 1. 批量处理指定目录下的图片文件
6
+ 2. 使用MD5哈希进行图片去重
7
+ 3. 生成图片嵌入向量并存储到数据库
8
+ 4. 可选地将处理后的图片移动到输出目录
9
+ """
10
+ import os
11
+ from typing import List
12
+ from pathlib import Path
13
+
14
+ from app.services import sticker_service
15
+
16
+
17
+ def batch_process_stickers(image_dir: str = 'images.tmp', output_dir: str = 'processed.tmp') -> None:
18
+ """
19
+ 批量处理目录中的贴纸图片
20
+
21
+ 参数:
22
+ image_dir: 包含贴纸图片的目录路径
23
+ output_dir: 存储处理后图片的输出目录(默认为'processed')
24
+
25
+ 功能:
26
+ 1. 遍历目录中的所有图片文件
27
+ 2. 使用MD5哈希进行去重
28
+ 3. 为每张图片生成嵌入向量并存储到数据库
29
+ 4. 可选地将处理后的图片移动到输出目录
30
+ """
31
+ # 创建输出目录(如果不存在)
32
+ os.makedirs(output_dir, exist_ok=True)
33
+ # 用于存储已处理图片的哈希集合
34
+ # 遍历目录中的所有文件
35
+ # 打印图片数量和列表
36
+ print('>>> 待处理图片数量', len(os.listdir(image_dir)))
37
+ for img_path in Path(image_dir).glob('*.*'):
38
+ # 只处理jpg/jpeg/png格式的图片
39
+ print('>>>> 正在处理图片', img_path)
40
+ if img_path.suffix.lower() not in ['.jpg', '.jpeg', '.png']:
41
+ continue
42
+
43
+ try:
44
+ # 加载图片并准备元数据
45
+ from PIL import Image
46
+ img = Image.open(img_path)
47
+ title = img_path.stem # 使用文件名作为标题
48
+
49
+ # 调用上传服务
50
+ sticker_service.upload_sticker(img, title, "", "")
51
+
52
+ # 可选操作: 将处理后的图片移动到输出目录
53
+ output_path = os.path.join(output_dir, img_path.name)
54
+ os.rename(str(img_path), output_path)
55
+
56
+ print(f"已处理: {img_path}")
57
+ except Exception as e:
58
+ print(f"处理异常 {img_path}: {str(e)}")
59
+
60
+
61
+ if __name__ == '__main__':
62
+ """
63
+ 命令行入口
64
+ 用法: python batch_upload.py <图片目录> [--output 输出目录]
65
+ """
66
+ import argparse
67
+
68
+ # 设置命令行参数解析
69
+ parser = argparse.ArgumentParser(description='批量处理贴纸图片(带去重功能)')
70
+ parser.add_argument('image_dir', help='包含贴纸图片的目录')
71
+ parser.add_argument('--output', '-o', default='processed.tmp',
72
+ help='处理后图片的输出目录(默认为processed)')
73
+
74
+ # 解析参数并执行批量处理
75
+ args = parser.parse_args()
76
+ batch_process_stickers(args.image_dir, args.output)