chb2026 commited on
Commit
581b93e
·
verified ·
1 Parent(s): 22a0edd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -166
app.py CHANGED
@@ -1,13 +1,13 @@
1
  import os
2
  import base64
 
3
  import mimetypes
4
- from datetime import datetime, timedelta
5
  from io import BytesIO
6
  import requests
7
- import json
8
 
9
- from flask import Flask, request, jsonify, redirect, render_template, send_from_directory
10
- from huggingface_hub import HfApi
11
  from PIL import Image
12
  import uuid
13
 
@@ -15,72 +15,46 @@ app = Flask(__name__)
15
 
16
  # 环境变量配置
17
  HF_TOKEN = os.environ.get("HF_TOKEN")
18
- SPACE_ID = os.environ.get("SPACE_ID", "username/spacename") # 格式: username/spacename
19
  MAX_SIZE = int(os.environ.get("MAX_SIZE", 10)) * 1024 * 1024 # 转字节
20
  API_KEY = os.environ.get("API_KEY")
21
 
22
- # SPACE_ID 构建域名
23
- SPACE_DOMAIN = f"{SPACE_ID.replace('/', '-')}.hf.space"
24
-
25
  hf_api = HfApi(token=HF_TOKEN)
26
 
27
- # 确保上传目录存在
28
- os.makedirs("images", exist_ok=True)
29
-
30
  def validate_auth():
31
- """验证 API 密钥"""
32
  if not API_KEY:
33
  return True
34
  header_key = request.headers.get("X-API-Key")
35
  param_key = request.args.get("key")
36
  return header_key == API_KEY or param_key == API_KEY
37
 
38
- def generate_filename(original_filename):
39
- """生成唯一的文件名"""
40
  unique_id = uuid.uuid4().hex[:8]
41
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
42
- _, ext = os.path.splitext(original_filename)
43
- if not ext:
44
- ext = ".jpg" # 默认扩展名
45
  return f"{timestamp}-{unique_id}{ext}"
46
 
47
- def save_to_space(content, filename):
48
- """保存文件到 Space"""
49
- # 先保存到本地
50
- local_path = os.path.join("images", filename)
51
- with open(local_path, "wb") as f:
52
- f.write(content)
53
 
54
- # 上传到 Space
55
- try:
56
- hf_api.upload_file(
57
- repo_id=SPACE_ID,
58
- path_in_repo=f"images/{filename}",
59
- path_or_fileobj=local_path
60
- )
61
- # 返回可访问的 URL
62
- return f"https://{SPACE_DOMAIN}/images/{filename}"
63
- except Exception as e:
64
- print(f"Upload error: {e}")
65
- return None
66
- finally:
67
- # 清理本地文件
68
- if os.path.exists(local_path):
69
- os.remove(local_path)
70
 
71
  @app.route("/", methods=["GET"])
72
  def index():
73
- """渲染上传页面"""
74
  return render_template("index.html")
75
 
76
- @app.route("/images/<path:filename>")
77
- def serve_image(filename):
78
- """提供图片访问服务"""
79
- return send_from_directory("images", filename)
80
-
81
  @app.route("/api/1/upload", methods=["GET", "POST"])
82
  def upload():
83
- """处理上传请求"""
84
  # 鉴权检查
85
  if not validate_auth():
86
  return jsonify({
@@ -89,135 +63,72 @@ def upload():
89
  "status_txt": "Unauthorized"
90
  }), 401
91
 
92
- try:
93
- # 获取文件数据
94
- source = None
95
- original_filename = "uploaded_file"
96
-
97
- if request.method == "POST":
98
- if "source" in request.files:
99
- file = request.files["source"]
100
- source = file.read()
101
- original_filename = file.filename
102
- else:
103
- source = request.form.get("source")
104
- else:
105
- source = request.args.get("source")
106
-
107
- if not source:
108
- return jsonify({
109
- "status_code": 400,
110
- "error": {"message": "No source provided"},
111
- "status_txt": "Bad Request"
112
- }), 400
113
-
114
- # 处理不同类型的输入
115
- if isinstance(source, bytes):
116
- content = source
117
- elif source.startswith(("http://", "https://")):
118
- response = requests.get(source)
119
- content = response.content
120
- original_filename = os.path.basename(source)
121
- elif source.startswith("data:"):
122
- try:
123
- header, data = source.split(",", 1)
124
- mime_type = header.split(":")[1].split(";")[0]
125
- content = base64.b64decode(data)
126
- ext = mimetypes.guess_extension(mime_type)
127
- original_filename = f"uploaded_file{ext}"
128
- except Exception as e:
129
- return jsonify({
130
- "status_code": 400,
131
- "error": {"message": "Invalid base64 data"},
132
- "status_txt": "Bad Request"
133
- }), 400
134
  else:
135
- try:
136
- content = base64.b64decode(source)
137
- except Exception as e:
138
- return jsonify({
139
- "status_code": 400,
140
- "error": {"message": "Invalid source format"},
141
- "status_txt": "Bad Request"
142
- }), 400
143
-
144
- # 验证文件大小
145
- if len(content) > MAX_SIZE:
146
- return jsonify({
147
- "status_code": 413,
148
- "error": {"message": f"File exceeds {MAX_SIZE//1024//1024}MB limit"},
149
- "status_txt": "Payload Too Large"
150
- }), 413
151
-
152
- # 获取图片信息
153
- try:
154
- image = Image.open(BytesIO(content))
155
- width, height = image.size
156
- mime_type = Image.MIME[image.format]
157
- except Exception as e:
158
- width = height = 0
159
- mime_type = mimetypes.guess_type(original_filename)[0] or "application/octet-stream"
160
-
161
- # 生成文件名并保存
162
- filename = generate_filename(original_filename)
163
- file_url = save_to_space(content, filename)
164
-
165
- if not file_url:
166
- return jsonify({
167
- "status_code": 500,
168
- "error": {"message": "Failed to save file"},
169
- "status_txt": "Internal Server Error"
170
- }), 500
171
-
172
- # 构造响应数据
173
- response_data = {
 
 
 
 
 
 
 
174
  "status_code": 200,
175
- "success": {
176
- "message": "file uploaded",
177
- "code": 200
178
- },
179
  "image": {
180
- "name": os.path.splitext(filename)[0],
181
- "extension": os.path.splitext(filename)[1][1:],
182
  "size": len(content),
183
  "width": width,
184
  "height": height,
185
- "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
186
- "date_gmt": (datetime.now() + timedelta(hours=3)).strftime("%Y-%m-%d %H:%M:%S"),
187
- "title": request.form.get("title") or os.path.splitext(original_filename)[0],
188
- "description": request.form.get("description"),
189
- "nsfw": int(request.form.get("nsfw", 0)),
190
- "md5": None,
191
- "storage_mode": "space",
192
- "original_filename": original_filename,
193
- "views": 0,
194
- "likes": 0,
195
- "is_animated": int(getattr(image, "is_animated", False)),
196
- "filename": filename,
197
  "mime": mime_type,
198
- "url": file_url,
199
- "size_formatted": f"{len(content)/1024/1024:.1f} MB",
200
- "display_url": file_url,
201
- "url_viewer": file_url,
202
  },
203
  "status_txt": "OK"
204
- }
205
-
206
- # 根据请求的格式返回响应
207
- response_format = request.args.get("format", "json")
208
- if response_format == "txt":
209
- return file_url
210
- elif response_format == "redirect":
211
- return redirect(file_url, code=302)
212
- else:
213
- return jsonify(response_data)
214
-
215
- except Exception as e:
216
- return jsonify({
217
- "status_code": 500,
218
- "error": {"message": str(e)},
219
- "status_txt": "Internal Server Error"
220
- }), 500
221
 
222
  if __name__ == "__main__":
223
  app.run(host="0.0.0.0", port=7860, debug=True)
 
1
  import os
2
  import base64
3
+ import hashlib
4
  import mimetypes
5
+ from datetime import datetime
6
  from io import BytesIO
7
  import requests
 
8
 
9
+ from flask import Flask, request, jsonify, redirect, render_template
10
+ from huggingface_hub import HfApi, HfFileSystem
11
  from PIL import Image
12
  import uuid
13
 
 
15
 
16
  # 环境变量配置
17
  HF_TOKEN = os.environ.get("HF_TOKEN")
18
+ DATASET_ID = os.environ.get("DATASET_ID")
19
  MAX_SIZE = int(os.environ.get("MAX_SIZE", 10)) * 1024 * 1024 # 转字节
20
  API_KEY = os.environ.get("API_KEY")
21
 
22
+ fs = HfFileSystem(token=HF_TOKEN)
 
 
23
  hf_api = HfApi(token=HF_TOKEN)
24
 
 
 
 
25
  def validate_auth():
 
26
  if not API_KEY:
27
  return True
28
  header_key = request.headers.get("X-API-Key")
29
  param_key = request.args.get("key")
30
  return header_key == API_KEY or param_key == API_KEY
31
 
32
+ def generate_filename(data, mime_type=None):
33
+ ext = mimetypes.guess_extension(mime_type or "application/octet-stream") or ".bin"
34
  unique_id = uuid.uuid4().hex[:8]
35
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
 
 
 
36
  return f"{timestamp}-{unique_id}{ext}"
37
 
38
+ def save_to_dataset(content, filename):
39
+ path = f"datasets/{DATASET_ID}/resolve/main/images/{filename}"
40
+ fs.mkdir(f"datasets/{DATASET_ID}/images", exist_ok=True)
41
+ fs.write_bytes(f"datasets/{DATASET_ID}/images/{filename}", content)
 
 
42
 
43
+ # 获取正确的 URL
44
+ repo_id = f"datasets/{DATASET_ID}"
45
+ file_path = f"images/{filename}"
46
+ url = hf_api.hf_hub_url(repo_id, filename=file_path)
47
+
48
+ # 获取实际的下载 URL
49
+ response = requests.head(url, allow_redirects=True)
50
+ return response.url
 
 
 
 
 
 
 
 
51
 
52
  @app.route("/", methods=["GET"])
53
  def index():
 
54
  return render_template("index.html")
55
 
 
 
 
 
 
56
  @app.route("/api/1/upload", methods=["GET", "POST"])
57
  def upload():
 
58
  # 鉴权检查
59
  if not validate_auth():
60
  return jsonify({
 
63
  "status_txt": "Unauthorized"
64
  }), 401
65
 
66
+ # 获取文件数据
67
+ source = None
68
+ if request.method == "POST":
69
+ if "source" in request.files:
70
+ file = request.files["source"]
71
+ source = file.read()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  else:
73
+ source = request.form.get("source")
74
+ else:
75
+ source = request.args.get("source")
76
+
77
+ # 处理Base64、文件或URL
78
+ if isinstance(source, bytes):
79
+ content = source
80
+ elif source.startswith(("http://", "https://")):
81
+ # 需要实现URL下载逻辑(示例代码省略)
82
+ return jsonify({"error": "URL download not implemented"}), 501
83
+ elif source.startswith("data:"):
84
+ header, data = source.split(",", 1)
85
+ mime_type = header.split(":")[1].split(";")[0]
86
+ content = base64.b64decode(data)
87
+ else:
88
+ content = base64.b64decode(source)
89
+
90
+ # 验证大小限制
91
+ if len(content) > MAX_SIZE:
92
+ return jsonify({
93
+ "status_code": 413,
94
+ "error": {"message": f"File exceeds {MAX_SIZE//1024//1024}MB limit"},
95
+ "status_txt": "Payload Too Large"
96
+ }), 413
97
+
98
+ # 处理图片属性
99
+ try:
100
+ image = Image.open(BytesIO(content))
101
+ width, height = image.size
102
+ mime_type = image.get_format_mimetype()
103
+ except:
104
+ width = height = 0
105
+ mime_type = None
106
+
107
+ # 生成存储信息
108
+ filename = generate_filename(content, mime_type)
109
+ file_url = save_to_dataset(content, filename)
110
+
111
+ # 构造响应
112
+ response_format = request.args.get("format", "json")
113
+ if response_format == "txt":
114
+ return file_url
115
+ elif response_format == "redirect":
116
+ return redirect(file_url, code=302)
117
+ else:
118
+ return jsonify({
119
  "status_code": 200,
120
+ "success": {"message": "file uploaded", "code": 200},
 
 
 
121
  "image": {
122
+ "filename": filename,
123
+ "url": file_url,
124
  "size": len(content),
125
  "width": width,
126
  "height": height,
 
 
 
 
 
 
 
 
 
 
 
 
127
  "mime": mime_type,
128
+ "size_formatted": f"{len(content)/1024/1024:.1f} MB"
 
 
 
129
  },
130
  "status_txt": "OK"
131
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  if __name__ == "__main__":
134
  app.run(host="0.0.0.0", port=7860, debug=True)