nsfwpy 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
nsfwpy-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.1
2
+ Name: nsfwpy
3
+ Version: 0.0.1
4
+ Summary: 基于OpenNSFW的图像内容检测工具
5
+ Home-page: https://github.com/HG-ha/nsfwpy
6
+ Author: YiMing
7
+ Author-email: 1790233968@qq.com
8
+ License: UNKNOWN
9
+ Description: # nsfwpy
10
+
11
+ [English](README_EN.md) | 简体中文
12
+
13
+ 图像敏感内容检测工具,提供简单易用的Python接口进行图像内容分析和过滤,并提供API和CLI工具。
14
+
15
+ ## 简介
16
+
17
+ nsfwpy 是一个轻量级Python库,使用深度学习模型进行图像内容分析,可以识别图像是否包含不适宜内容。本项目基于[nsfw_model](https://github.com/GantMan/nsfw_model)提供的模型实现。
18
+
19
+ ## 特性
20
+
21
+ - 轻量级实现,依赖少,易于部署
22
+ - 支持多种图像格式输入(JPG、PNG等)
23
+ - 提供命令行工具、Python API和HTTP API接口
24
+ - 使用TensorFlow Lite优化性能
25
+ - 支持Windows和其他操作系统
26
+ - 自动下载和缓存模型文件
27
+
28
+ ## 安装要求
29
+ > 由依赖导致安装出错时,可以尝试移除版本号安装,但tflite-runtime版本必须>=2.5.0
30
+ - Python 3.7+
31
+ - NumPy <= 1.26.4
32
+ - Pillow <= 11.1.0
33
+ - FastAPI <= 0.115.11
34
+ - uvicorn <= 0.34.0
35
+ - python-multipart <= 0.0.20
36
+ - tflite-runtime = 2.13.0 (Windows) 或 >= 2.5.0 (其他系统)
37
+
38
+ ## 安装
39
+
40
+ ### 通过pip安装
41
+
42
+ ```bash
43
+ pip install nsfwpy
44
+ ```
45
+
46
+ ### 从源码安装
47
+
48
+ ```bash
49
+ git clone https://github.com/HG-ha/nsfwpy.git
50
+ cd nsfwpy
51
+ pip install -e .
52
+ ```
53
+
54
+ ## 使用方法
55
+
56
+ ### Python API
57
+
58
+ ```python
59
+ from nsfwpy import NSFW
60
+
61
+ # 初始化检测器(首次运行会自动下载模型)
62
+ detector = NSFW()
63
+
64
+ # 预测单个图像
65
+ result = detector.predict_image("path/to/image.jpg")
66
+ print(result)
67
+
68
+ # 预测PIL图像
69
+ from PIL import Image
70
+ img = Image.open("path/to/image.jpg")
71
+ result = detector.predict_pil_image(img)
72
+ print(result)
73
+
74
+ # 批量预测目录中的图像
75
+ results = detector.predict_batch("path/to/image/directory")
76
+ print(results)
77
+ ```
78
+
79
+ ### 命令行工具
80
+
81
+ ```bash
82
+ # 基本用法
83
+ nsfwpy --input path/to/image.jpg
84
+
85
+ # 指定自定义模型路径
86
+ nsfwpy --model path/to/model.tflite --input path/to/image.jpg
87
+
88
+ # 指定图像尺寸
89
+ nsfwpy --dim 299 --input path/to/image.jpg
90
+ ```
91
+
92
+ ### Web API服务(完全兼容 nsfwjs-api)
93
+
94
+ 启动API服务器:
95
+
96
+ ```bash
97
+ # 基本用法
98
+ nsfwpy -w
99
+
100
+ # 指定主机和端口
101
+ nsfwpy -w --host 127.0.0.1 --port 8080
102
+
103
+ # 指定自定义模型
104
+ nsfwpy -w --model path/to/model.tflite
105
+ ```
106
+
107
+ API端点:
108
+ - `POST /classify`: 分析单张图片
109
+ - `POST /classify-many`: 批量分析多张图片
110
+
111
+ ### 预测结果格式
112
+
113
+ 返回包含以下类别概率值的字典:
114
+ ```python
115
+ {
116
+ "drawings": 0.1, # 绘画/动画
117
+ "hentai": 0.0, # 动漫色情内容
118
+ "neutral": 0.8, # 中性/安全内容
119
+ "porn": 0.0, # 色情内容
120
+ "sexy": 0.1 # 性感内容
121
+ }
122
+ ```
123
+
124
+ ## 开发说明
125
+
126
+ - 项目使用MIT许可证
127
+ - 欢迎提交Issue和Pull Request
128
+ - 自动发布到PyPI使用GitHub Actions
129
+
130
+ ## 致谢
131
+
132
+ 本项目的模型基于[nsfw_model](https://github.com/GantMan/nsfw_model)。感谢原作者的贡献。
133
+
134
+ ## 许可证
135
+
136
+ [MIT License](LICENSE)
137
+
138
+ Platform: UNKNOWN
139
+ Classifier: Programming Language :: Python :: 3.7
140
+ Classifier: Operating System :: OS Independent
141
+ Description-Content-Type: text/markdown
nsfwpy-0.0.1/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # nsfwpy
2
+
3
+ [English](README_EN.md) | 简体中文
4
+
5
+ 图像敏感内容检测工具,提供简单易用的Python接口进行图像内容分析和过滤,并提供API和CLI工具。
6
+
7
+ ## 简介
8
+
9
+ nsfwpy 是一个轻量级Python库,使用深度学习模型进行图像内容分析,可以识别图像是否包含不适宜内容。本项目基于[nsfw_model](https://github.com/GantMan/nsfw_model)提供的模型实现。
10
+
11
+ ## 特性
12
+
13
+ - 轻量级实现,依赖少,易于部署
14
+ - 支持多种图像格式输入(JPG、PNG等)
15
+ - 提供命令行工具、Python API和HTTP API接口
16
+ - 使用TensorFlow Lite优化性能
17
+ - 支持Windows和其他操作系统
18
+ - 自动下载和缓存模型文件
19
+
20
+ ## 安装要求
21
+ > 由依赖导致安装出错时,可以尝试移除版本号安装,但tflite-runtime版本必须>=2.5.0
22
+ - Python 3.7+
23
+ - NumPy <= 1.26.4
24
+ - Pillow <= 11.1.0
25
+ - FastAPI <= 0.115.11
26
+ - uvicorn <= 0.34.0
27
+ - python-multipart <= 0.0.20
28
+ - tflite-runtime = 2.13.0 (Windows) 或 >= 2.5.0 (其他系统)
29
+
30
+ ## 安装
31
+
32
+ ### 通过pip安装
33
+
34
+ ```bash
35
+ pip install nsfwpy
36
+ ```
37
+
38
+ ### 从源码安装
39
+
40
+ ```bash
41
+ git clone https://github.com/HG-ha/nsfwpy.git
42
+ cd nsfwpy
43
+ pip install -e .
44
+ ```
45
+
46
+ ## 使用方法
47
+
48
+ ### Python API
49
+
50
+ ```python
51
+ from nsfwpy import NSFW
52
+
53
+ # 初始化检测器(首次运行会自动下载模型)
54
+ detector = NSFW()
55
+
56
+ # 预测单个图像
57
+ result = detector.predict_image("path/to/image.jpg")
58
+ print(result)
59
+
60
+ # 预测PIL图像
61
+ from PIL import Image
62
+ img = Image.open("path/to/image.jpg")
63
+ result = detector.predict_pil_image(img)
64
+ print(result)
65
+
66
+ # 批量预测目录中的图像
67
+ results = detector.predict_batch("path/to/image/directory")
68
+ print(results)
69
+ ```
70
+
71
+ ### 命令行工具
72
+
73
+ ```bash
74
+ # 基本用法
75
+ nsfwpy --input path/to/image.jpg
76
+
77
+ # 指定自定义模型路径
78
+ nsfwpy --model path/to/model.tflite --input path/to/image.jpg
79
+
80
+ # 指定图像尺寸
81
+ nsfwpy --dim 299 --input path/to/image.jpg
82
+ ```
83
+
84
+ ### Web API服务(完全兼容 nsfwjs-api)
85
+
86
+ 启动API服务器:
87
+
88
+ ```bash
89
+ # 基本用法
90
+ nsfwpy -w
91
+
92
+ # 指定主机和端口
93
+ nsfwpy -w --host 127.0.0.1 --port 8080
94
+
95
+ # 指定自定义模型
96
+ nsfwpy -w --model path/to/model.tflite
97
+ ```
98
+
99
+ API端点:
100
+ - `POST /classify`: 分析单张图片
101
+ - `POST /classify-many`: 批量分析多张图片
102
+
103
+ ### 预测结果格式
104
+
105
+ 返回包含以下类别概率值的字典:
106
+ ```python
107
+ {
108
+ "drawings": 0.1, # 绘画/动画
109
+ "hentai": 0.0, # 动漫色情内容
110
+ "neutral": 0.8, # 中性/安全内容
111
+ "porn": 0.0, # 色情内容
112
+ "sexy": 0.1 # 性感内容
113
+ }
114
+ ```
115
+
116
+ ## 开发说明
117
+
118
+ - 项目使用MIT许可证
119
+ - 欢迎提交Issue和Pull Request
120
+ - 自动发布到PyPI使用GitHub Actions
121
+
122
+ ## 致谢
123
+
124
+ 本项目的模型基于[nsfw_model](https://github.com/GantMan/nsfw_model)。感谢原作者的贡献。
125
+
126
+ ## 许可证
127
+
128
+ [MIT License](LICENSE)
@@ -0,0 +1,9 @@
1
+ from .nsfw import NSFWDetector
2
+
3
+ # 为简化引用提供一个别名
4
+ NSFW = NSFWDetector
5
+
6
+ # 导出用于命令行工具的主入口点
7
+ from .server import main as cli_main
8
+
9
+ __version__ = "0.0.1"
@@ -0,0 +1,111 @@
1
+ from typing import List, Dict
2
+ from pydantic import BaseModel
3
+ from fastapi import FastAPI, File, UploadFile, HTTPException
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+
6
+ from .nsfw import NSFWDetector
7
+
8
+ # 全局模型实例
9
+ global_detector = None
10
+
11
+ # 加载模型的辅助函数
12
+ def get_detector(model_path=None):
13
+ global global_detector
14
+
15
+ # 如果已经有全局模型实例,直接返回
16
+ if (global_detector is not None):
17
+ return global_detector
18
+
19
+ # 创建新的检测器实例
20
+ detector = NSFWDetector(model_path=model_path)
21
+
22
+ # 保存为全局实例
23
+ global_detector = detector
24
+
25
+ return detector
26
+
27
+ # 数据模型定义
28
+ class ClassifyItem(BaseModel):
29
+ image: UploadFile = File(..., description="上传的图像文件")
30
+
31
+ class ClassifyManyItem(BaseModel):
32
+ images: List[UploadFile] = File(..., description="上传的图像文件列表")
33
+
34
+ # 将响应模型直接定义为分类结果字典
35
+ class ClassificationResult(Dict[str, float]):
36
+ pass
37
+
38
+ class MultipleClassificationResult(BaseModel):
39
+ results: List[Dict[str, float]]
40
+
41
+ # 创建FastAPI应用
42
+ app = FastAPI(
43
+ title="NSFW内容检测API",
44
+ description="基于MobileNet V2的NSFW内容检测API,兼容nsfwjs接口",
45
+ version="1.0.0"
46
+ )
47
+
48
+
49
+ # 添加CORS支持
50
+ app.add_middleware(
51
+ CORSMiddleware,
52
+ allow_origins=["*"],
53
+ allow_credentials=True,
54
+ allow_methods=["*"],
55
+ allow_headers=["*"],
56
+ )
57
+
58
+ # 在启动时预加载模型
59
+ @app.on_event("startup")
60
+ async def startup_event():
61
+ # 在服务启动时预加载模型
62
+ get_detector()
63
+
64
+ # 辅助函数:从上传文件读取图像
65
+ async def read_image_file(file: UploadFile):
66
+ try:
67
+ contents = await file.read()
68
+ return contents
69
+ except Exception as e:
70
+ raise HTTPException(status_code=400, detail=f"无法读取上传文件: {str(e)}")
71
+
72
+ @app.post("/classify", response_model=Dict[str, float])
73
+ async def classify_image(image: UploadFile = File(...)):
74
+ """
75
+ 对单张上传的图像文件进行NSFW分类
76
+ """
77
+ try:
78
+ detector = get_detector()
79
+ image_bytes = await read_image_file(image)
80
+ result = detector.predict_from_bytes(image_bytes)
81
+
82
+ if not result:
83
+ raise HTTPException(status_code=500, detail="图像处理失败")
84
+
85
+ return result
86
+ except Exception as e:
87
+ raise HTTPException(status_code=500, detail=str(e))
88
+
89
+ @app.post("/classify-many", response_model=List[Dict[str, float]])
90
+ async def classify_many_images(images: List[UploadFile] = File(...)):
91
+ """
92
+ 对多张上传的图像文件进行NSFW分类
93
+ """
94
+ try:
95
+ detector = get_detector()
96
+ results = []
97
+
98
+ for image in images:
99
+ try:
100
+ image_bytes = await read_image_file(image)
101
+ result = detector.predict_from_bytes(image_bytes)
102
+ if result:
103
+ results.append(result)
104
+ else:
105
+ results.append({"error": "处理失败"})
106
+ except Exception as e:
107
+ results.append({"error": str(e)})
108
+
109
+ return results
110
+ except Exception as e:
111
+ raise HTTPException(status_code=500, detail=str(e))
@@ -0,0 +1,20 @@
1
+ def main():
2
+ import argparse
3
+ import json
4
+ from nsfwpy.nsfw import NSFWDetector
5
+
6
+ parser = argparse.ArgumentParser(description='NSFW图像内容检测')
7
+ parser.add_argument('--model', help='TFLite模型文件路径(可选)')
8
+ parser.add_argument('--dim', type=int, default=224, help='图像尺寸(默认:224)')
9
+ parser.add_argument('--input', required=True, help='要检测的图像文件或目录')
10
+
11
+ args = parser.parse_args()
12
+
13
+ # 创建检测器,如果未指定模型路径,则使用默认值
14
+ detector = NSFWDetector(model_path=args.model, image_dim=args.dim)
15
+ results = detector.predict_batch(args.input)
16
+
17
+ print(json.dumps(results, ensure_ascii=False, indent=2))
18
+
19
+ if __name__ == "__main__":
20
+ main()
@@ -0,0 +1,214 @@
1
+ import os
2
+ import numpy as np
3
+ from PIL import Image
4
+ import tflite_runtime.interpreter as tflite
5
+ import io
6
+ import platform
7
+ import urllib.request
8
+
9
+ class NSFWDetector:
10
+ """NSFW内容检测器,基于MobileNet V2模型"""
11
+
12
+ CATEGORIES = ['drawings', 'hentai', 'neutral', 'porn', 'sexy']
13
+ MODEL_URL = "https://ghproxy.cn/github.com/HG-ha/nsfwpy/raw/main/model/model.tflite"
14
+
15
+ def __init__(self, model_path=None, image_dim=224):
16
+ """
17
+ 初始化NSFW检测器
18
+
19
+ 参数:
20
+ model_path: TFLite模型文件路径,若未提供则自动从缓存或网络获取
21
+ image_dim: 模型输入图像尺寸(默认224x224)
22
+ """
23
+ self.image_dim = image_dim
24
+
25
+ # 优先检查环境变量中是否设置了模型路径
26
+ env_model_path = os.environ.get("NSFW_MODEL_PATH")
27
+ if env_model_path and os.path.exists(env_model_path):
28
+ model_path = env_model_path
29
+ # 若未通过环境变量或参数提供模型路径,则自动获取
30
+ elif model_path is None:
31
+ model_path = self._get_model_path()
32
+
33
+ if not os.path.exists(model_path):
34
+ raise ValueError(f"模型文件不存在: {model_path}")
35
+
36
+ self.model_path = model_path
37
+
38
+ # 加载TFLite模型
39
+ self.interpreter = tflite.Interpreter(model_path=model_path)
40
+ self.interpreter.allocate_tensors()
41
+
42
+ # 获取输入输出细节
43
+ self.input_details = self.interpreter.get_input_details()
44
+ self.output_details = self.interpreter.get_output_details()
45
+
46
+ def _get_model_path(self):
47
+ """根据平台获取缓存路径,检查模型文件是否存在,不存在则下载"""
48
+ # 首先检查环境变量
49
+ env_model_path = os.environ.get("NSFW_MODEL_PATH")
50
+ if env_model_path:
51
+ # 如果环境变量指定的是目录而非文件,则在目录下查找model.tflite
52
+ if os.path.isdir(env_model_path):
53
+ model_path = os.path.join(env_model_path, "model.tflite")
54
+ else:
55
+ model_path = env_model_path
56
+
57
+ if os.path.exists(model_path):
58
+ return model_path
59
+
60
+ # 确定平台相关的用户缓存目录
61
+ system = platform.system()
62
+ if system == "Windows":
63
+ cache_dir = os.path.join(os.environ.get("LOCALAPPDATA"), "nsfwpy")
64
+ elif system == "Darwin": # macOS
65
+ cache_dir = os.path.join(os.path.expanduser("~"), "Library", "Caches", "nsfwpy")
66
+ else: # Linux和其他系统
67
+ cache_dir = os.path.join(os.path.expanduser("~"), ".cache", "nsfwpy")
68
+
69
+ # 确保目录存在
70
+ os.makedirs(cache_dir, exist_ok=True)
71
+
72
+ model_path = os.path.join(cache_dir, "model.tflite")
73
+ # 检查模型文件是否存在,不存在则下载
74
+ if not os.path.exists(model_path):
75
+ print(f"模型文件不存在,正在下载到 {model_path}...")
76
+ try:
77
+ self._download_file(self.MODEL_URL, model_path)
78
+ print("模型下载完成")
79
+ except Exception as e:
80
+ raise ValueError(f"模型下载失败: {e}")
81
+
82
+ return model_path
83
+
84
+ def _download_file(self, url, destination):
85
+ """从指定URL下载文件到目标路径"""
86
+ try:
87
+ with urllib.request.urlopen(url) as response:
88
+ with open(destination, "wb") as f:
89
+ f.write(response.read())
90
+ except Exception as e:
91
+ raise ValueError(f"下载失败: {e}")
92
+
93
+ def _load_image(self, image_path):
94
+ """加载并处理单个图像"""
95
+ try:
96
+ image = Image.open(image_path)
97
+ if image.mode != 'RGB':
98
+ image = image.convert('RGB')
99
+ image = image.resize((self.image_dim, self.image_dim), Image.NEAREST)
100
+ image = np.array(image, dtype=np.float32) / 255.0
101
+ return image
102
+ except Exception as ex:
103
+ print(f"处理图像出错 {image_path}: {ex}")
104
+ return None
105
+
106
+ def _process_pil_image(self, pil_image):
107
+ """处理PIL图像对象"""
108
+ try:
109
+ if pil_image.mode != 'RGB':
110
+ pil_image = pil_image.convert('RGB')
111
+ resized_image = pil_image.resize((self.image_dim, self.image_dim), Image.NEAREST)
112
+ image = np.array(resized_image, dtype=np.float32) / 255.0
113
+ return image
114
+ except Exception as ex:
115
+ print(f"处理PIL图像出错: {ex}")
116
+ return None
117
+
118
+ def _predict_single(self, image):
119
+ """对单个图像进行预测"""
120
+ self.interpreter.set_tensor(self.input_details[0]['index'], np.expand_dims(image, axis=0))
121
+ self.interpreter.invoke()
122
+ return self.interpreter.get_tensor(self.output_details[0]['index'])[0]
123
+
124
+ def _format_predictions(self, predictions):
125
+ """将预测结果格式化为类别和概率"""
126
+ # 按概率降序排列
127
+ indices = np.argsort(-predictions)
128
+ result = {}
129
+ for i, idx in enumerate(indices):
130
+ category = self.CATEGORIES[idx]
131
+ probability = float(predictions[idx])
132
+ result[category] = probability
133
+ return result
134
+
135
+ def predict_image(self, image_path):
136
+ """
137
+ 预测单个图像的NSFW内容
138
+
139
+ 参数:
140
+ image_path: 图像文件路径
141
+
142
+ 返回:
143
+ 包含各类别预测概率的字典
144
+ """
145
+ if not os.path.exists(image_path):
146
+ raise ValueError(f"图像文件不存在: {image_path}")
147
+
148
+ image = self._load_image(image_path)
149
+ if image is None:
150
+ return None
151
+
152
+ predictions = self._predict_single(image)
153
+ return self._format_predictions(predictions)
154
+
155
+ def predict_pil_image(self, pil_image):
156
+ """
157
+ 从PIL图像对象预测NSFW内容
158
+
159
+ 参数:
160
+ pil_image: PIL图像对象
161
+
162
+ 返回:
163
+ 包含各类别预测概率的字典
164
+ """
165
+ image = self._process_pil_image(pil_image)
166
+ if image is None:
167
+ return None
168
+
169
+ predictions = self._predict_single(image)
170
+ return self._format_predictions(predictions)
171
+
172
+ def predict_from_bytes(self, image_bytes):
173
+ """
174
+ 从字节流预测NSFW内容
175
+
176
+ 参数:
177
+ image_bytes: 图像字节流
178
+
179
+ 返回:
180
+ 包含各类别预测概率的字典
181
+ """
182
+ try:
183
+ image = Image.open(io.BytesIO(image_bytes))
184
+ return self.predict_pil_image(image)
185
+ except Exception as ex:
186
+ print(f"从字节流处理图像出错: {ex}")
187
+ return None
188
+
189
+ def predict_batch(self, image_paths):
190
+ """
191
+ 批量预测多个图像
192
+
193
+ 参数:
194
+ image_paths: 单个图像路径或包含图像的目录
195
+
196
+ 返回:
197
+ 包含每个图像预测结果的列表
198
+ """
199
+ # 处理目录参数
200
+ if os.path.isdir(image_paths):
201
+ paths = [os.path.join(image_paths, f) for f in os.listdir(image_paths)
202
+ if os.path.isfile(os.path.join(image_paths, f))]
203
+ elif isinstance(image_paths, list):
204
+ paths = image_paths
205
+ else:
206
+ paths = [image_paths]
207
+
208
+ results = []
209
+ for path in paths:
210
+ prediction = self.predict_image(path)
211
+ if prediction:
212
+ results.append(prediction)
213
+
214
+ return results
@@ -0,0 +1,46 @@
1
+ import argparse
2
+ import os
3
+ import uvicorn
4
+ from pathlib import Path
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(description="启动NSFW检测API服务器或命令行工具")
8
+ parser.add_argument("--host", default="0.0.0.0", help="API服务器主机名")
9
+ parser.add_argument("--port", type=int, default=8000, help="API服务器端口")
10
+ parser.add_argument("--model", help="模型文件路径")
11
+ parser.add_argument("-w", "--web", action="store_true", help="启用Web API服务")
12
+ parser.add_argument("--input", help="要检测的图像文件或目录")
13
+ parser.add_argument("--dim", type=int, default=224, help="图像尺寸(默认:224)")
14
+
15
+ args, unknown_args = parser.parse_known_args()
16
+
17
+ # 如果指定了模型路径,设置环境变量
18
+ if args.model:
19
+ os.environ["NSFW_MODEL_PATH"] = str(Path(args.model).absolute())
20
+
21
+ # 只在指定--web参数时启动API服务器
22
+ if args.web:
23
+ # 启动服务器
24
+ # 移除上传文件大小限制
25
+ from starlette.formparsers import MultiPartParser
26
+ MultiPartParser.max_part_size = 1024 * 1024 * 1024
27
+ MultiPartParser.max_file_size = 1024 * 1024 * 1024
28
+ uvicorn.run("nsfwpy.api:app", host=args.host, port=args.port)
29
+ else:
30
+ # 运行命令行版本
31
+ from nsfwpy.cli import main as cli_main
32
+ import sys
33
+
34
+ # 重建参数,传递给cli模块
35
+ cli_args = ["--dim", str(args.dim)]
36
+ if args.model:
37
+ cli_args.extend(["--model", args.model])
38
+ if args.input:
39
+ cli_args.extend(["--input", args.input])
40
+
41
+ # 添加未知参数
42
+ sys.argv[1:] = cli_args + unknown_args
43
+ cli_main()
44
+
45
+ if __name__ == "__main__":
46
+ main()
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.1
2
+ Name: nsfwpy
3
+ Version: 0.0.1
4
+ Summary: 基于OpenNSFW的图像内容检测工具
5
+ Home-page: https://github.com/HG-ha/nsfwpy
6
+ Author: YiMing
7
+ Author-email: 1790233968@qq.com
8
+ License: UNKNOWN
9
+ Description: # nsfwpy
10
+
11
+ [English](README_EN.md) | 简体中文
12
+
13
+ 图像敏感内容检测工具,提供简单易用的Python接口进行图像内容分析和过滤,并提供API和CLI工具。
14
+
15
+ ## 简介
16
+
17
+ nsfwpy 是一个轻量级Python库,使用深度学习模型进行图像内容分析,可以识别图像是否包含不适宜内容。本项目基于[nsfw_model](https://github.com/GantMan/nsfw_model)提供的模型实现。
18
+
19
+ ## 特性
20
+
21
+ - 轻量级实现,依赖少,易于部署
22
+ - 支持多种图像格式输入(JPG、PNG等)
23
+ - 提供命令行工具、Python API和HTTP API接口
24
+ - 使用TensorFlow Lite优化性能
25
+ - 支持Windows和其他操作系统
26
+ - 自动下载和缓存模型文件
27
+
28
+ ## 安装要求
29
+ > 由依赖导致安装出错时,可以尝试移除版本号安装,但tflite-runtime版本必须>=2.5.0
30
+ - Python 3.7+
31
+ - NumPy <= 1.26.4
32
+ - Pillow <= 11.1.0
33
+ - FastAPI <= 0.115.11
34
+ - uvicorn <= 0.34.0
35
+ - python-multipart <= 0.0.20
36
+ - tflite-runtime = 2.13.0 (Windows) 或 >= 2.5.0 (其他系统)
37
+
38
+ ## 安装
39
+
40
+ ### 通过pip安装
41
+
42
+ ```bash
43
+ pip install nsfwpy
44
+ ```
45
+
46
+ ### 从源码安装
47
+
48
+ ```bash
49
+ git clone https://github.com/HG-ha/nsfwpy.git
50
+ cd nsfwpy
51
+ pip install -e .
52
+ ```
53
+
54
+ ## 使用方法
55
+
56
+ ### Python API
57
+
58
+ ```python
59
+ from nsfwpy import NSFW
60
+
61
+ # 初始化检测器(首次运行会自动下载模型)
62
+ detector = NSFW()
63
+
64
+ # 预测单个图像
65
+ result = detector.predict_image("path/to/image.jpg")
66
+ print(result)
67
+
68
+ # 预测PIL图像
69
+ from PIL import Image
70
+ img = Image.open("path/to/image.jpg")
71
+ result = detector.predict_pil_image(img)
72
+ print(result)
73
+
74
+ # 批量预测目录中的图像
75
+ results = detector.predict_batch("path/to/image/directory")
76
+ print(results)
77
+ ```
78
+
79
+ ### 命令行工具
80
+
81
+ ```bash
82
+ # 基本用法
83
+ nsfwpy --input path/to/image.jpg
84
+
85
+ # 指定自定义模型路径
86
+ nsfwpy --model path/to/model.tflite --input path/to/image.jpg
87
+
88
+ # 指定图像尺寸
89
+ nsfwpy --dim 299 --input path/to/image.jpg
90
+ ```
91
+
92
+ ### Web API服务(完全兼容 nsfwjs-api)
93
+
94
+ 启动API服务器:
95
+
96
+ ```bash
97
+ # 基本用法
98
+ nsfwpy -w
99
+
100
+ # 指定主机和端口
101
+ nsfwpy -w --host 127.0.0.1 --port 8080
102
+
103
+ # 指定自定义模型
104
+ nsfwpy -w --model path/to/model.tflite
105
+ ```
106
+
107
+ API端点:
108
+ - `POST /classify`: 分析单张图片
109
+ - `POST /classify-many`: 批量分析多张图片
110
+
111
+ ### 预测结果格式
112
+
113
+ 返回包含以下类别概率值的字典:
114
+ ```python
115
+ {
116
+ "drawings": 0.1, # 绘画/动画
117
+ "hentai": 0.0, # 动漫色情内容
118
+ "neutral": 0.8, # 中性/安全内容
119
+ "porn": 0.0, # 色情内容
120
+ "sexy": 0.1 # 性感内容
121
+ }
122
+ ```
123
+
124
+ ## 开发说明
125
+
126
+ - 项目使用MIT许可证
127
+ - 欢迎提交Issue和Pull Request
128
+ - 自动发布到PyPI使用GitHub Actions
129
+
130
+ ## 致谢
131
+
132
+ 本项目的模型基于[nsfw_model](https://github.com/GantMan/nsfw_model)。感谢原作者的贡献。
133
+
134
+ ## 许可证
135
+
136
+ [MIT License](LICENSE)
137
+
138
+ Platform: UNKNOWN
139
+ Classifier: Programming Language :: Python :: 3.7
140
+ Classifier: Operating System :: OS Independent
141
+ Description-Content-Type: text/markdown
@@ -0,0 +1,13 @@
1
+ README.md
2
+ setup.py
3
+ nsfwpy/__init__.py
4
+ nsfwpy/api.py
5
+ nsfwpy/cli.py
6
+ nsfwpy/nsfw.py
7
+ nsfwpy/server.py
8
+ nsfwpy.egg-info/PKG-INFO
9
+ nsfwpy.egg-info/SOURCES.txt
10
+ nsfwpy.egg-info/dependency_links.txt
11
+ nsfwpy.egg-info/entry_points.txt
12
+ nsfwpy.egg-info/requires.txt
13
+ nsfwpy.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ nsfwpy = nsfwpy.server:main
3
+
@@ -0,0 +1,6 @@
1
+ numpy<=1.26.4
2
+ pillow<=11.1.0
3
+ fastapi<=0.115.11
4
+ uvicorn<=0.34.0
5
+ python-multipart<=0.0.20
6
+ tflite-runtime>=2.5.0
@@ -0,0 +1 @@
1
+ nsfwpy
nsfwpy-0.0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
nsfwpy-0.0.1/setup.py ADDED
@@ -0,0 +1,45 @@
1
+ import setuptools
2
+ import platform
3
+
4
+ with open("README.md", "r", encoding='utf8') as fh:
5
+ long_description = fh.read()
6
+
7
+ install_requires = [
8
+ "numpy<=1.26.4",
9
+ "pillow<=11.1.0",
10
+ "fastapi<=0.115.11",
11
+ "uvicorn<=0.34.0",
12
+ "python-multipart<=0.0.20"
13
+ ]
14
+
15
+ if platform.system() == "Windows":
16
+ dependency_links = [
17
+ "https://ghproxy.cn/github.com/NexelOfficial/tflite-runtime-win/raw/main/win_amd64/tflite_runtime-2.13.0-cp311-cp311-win_amd64.whl"
18
+ ]
19
+ install_requires.append("tflite-runtime==2.13.0")
20
+ else:
21
+ dependency_links = []
22
+ install_requires.append("tflite-runtime>=2.5.0")
23
+
24
+ setuptools.setup(
25
+ name="nsfwpy",
26
+ version="0.0.1",
27
+ author="YiMing",
28
+ author_email="1790233968@qq.com",
29
+ description="基于OpenNSFW的图像内容检测工具",
30
+ long_description=long_description,
31
+ long_description_content_type="text/markdown",
32
+ url="https://github.com/HG-ha/nsfwpy",
33
+ packages=setuptools.find_packages(),
34
+ install_requires=install_requires,
35
+ dependency_links=dependency_links,
36
+ classifiers=[
37
+ "Programming Language :: Python :: 3.7",
38
+ "Operating System :: OS Independent",
39
+ ],
40
+ entry_points={
41
+ 'console_scripts': [
42
+ 'nsfwpy=nsfwpy.server:main',
43
+ ],
44
+ },
45
+ )