chb2026 commited on
Commit
96ef0b4
·
verified ·
1 Parent(s): 20ff804

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -55
app.py CHANGED
@@ -1,12 +1,13 @@
1
  import os
2
  import base64
3
- import hashlib
4
  import mimetypes
5
- from datetime import datetime
6
  from io import BytesIO
 
 
7
 
8
- from flask import Flask, request, jsonify, redirect, render_template
9
- from huggingface_hub import HfApi, HfFileSystem
10
  from PIL import Image
11
  import uuid
12
 
@@ -14,12 +15,10 @@ app = Flask(__name__)
14
 
15
  # 环境变量配置
16
  HF_TOKEN = os.environ.get("HF_TOKEN")
17
- DATASET_ID = os.environ.get("DATASET_ID")
18
  MAX_SIZE = int(os.environ.get("MAX_SIZE", 10)) * 1024 * 1024 # 转字节
19
  API_KEY = os.environ.get("API_KEY")
20
- SPACE_DOMAIN = os.environ.get("SPACE_DOMAIN", "chb2026-image.hf.space") # Space域名
21
 
22
- fs = HfFileSystem(token=HF_TOKEN)
23
  hf_api = HfApi(token=HF_TOKEN)
24
 
25
  def validate_auth():
@@ -29,22 +28,29 @@ def validate_auth():
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
- fs.mkdir(f"datasets/{DATASET_ID}/images", exist_ok=True)
40
- fs.write_bytes(f"datasets/{DATASET_ID}/images/{filename}", content)
41
- # 返回代理URL
42
- return f"https://{SPACE_DOMAIN}/proxy/datasets/{DATASET_ID}/resolve/main/images/{filename}"
 
 
 
43
 
44
  @app.route("/", methods=["GET"])
45
  def index():
46
  return render_template("index.html")
47
 
 
 
 
 
48
  @app.route("/api/1/upload", methods=["GET", "POST"])
49
  def upload():
50
  # 鉴权检查
@@ -61,26 +67,31 @@ def upload():
61
  if "source" in request.files:
62
  file = request.files["source"]
63
  source = file.read()
 
64
  else:
65
  source = request.form.get("source")
 
66
  else:
67
  source = request.args.get("source")
 
68
 
69
  # 处理Base64、文件或URL
70
  if isinstance(source, bytes):
71
  content = source
72
  elif source and source.startswith(("http://", "https://")):
73
- return jsonify({"error": "URL download not implemented"}), 501
 
 
74
  elif source and source.startswith("data:"):
75
  header, data = source.split(",", 1)
76
  mime_type = header.split(":")[1].split(";")[0]
77
  content = base64.b64decode(data)
78
- elif source:
79
- content = base64.b64decode(source)
80
  else:
81
  return jsonify({
82
  "status_code": 400,
83
- "error": {"message": "No file provided"},
84
  "status_txt": "Bad Request"
85
  }), 400
86
 
@@ -96,54 +107,65 @@ def upload():
96
  try:
97
  image = Image.open(BytesIO(content))
98
  width, height = image.size
99
- mime_type = image.get_format_mimetype()
100
- extension = mimetypes.guess_extension(mime_type) or ".jpg"
101
- is_animated = getattr(image, "is_animated", False)
102
  except:
103
  width = height = 0
104
- mime_type = None
105
- extension = ".bin"
106
- is_animated = False
107
 
108
  # 生成存储信息
109
- filename = generate_filename(content, mime_type)
110
- file_url = save_to_dataset(content, filename)
111
-
112
- # 构造符合PicGo API的响应
113
- response_format = request.args.get("format", "json")
114
-
115
- image_info = {
116
- "name": os.path.splitext(filename)[0],
117
- "extension": extension.lstrip("."),
118
- "size": len(content),
119
- "width": width,
120
- "height": height,
121
- "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
122
- "date_gmt": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
123
- "title": request.form.get("title", filename),
124
- "description": request.form.get("description"),
125
- "nsfw": int(request.form.get("nsfw", "0")),
126
- "md5": hashlib.md5(content).hexdigest(),
127
- "mime": mime_type,
128
- "url": file_url,
129
- "is_animated": int(is_animated),
130
- "size_formatted": f"{len(content)/1024/1024:.1f} MB"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
 
 
133
  if response_format == "txt":
134
  return file_url
135
  elif response_format == "redirect":
136
  return redirect(file_url, code=302)
137
  else:
138
- return jsonify({
139
- "status_code": 200,
140
- "success": {
141
- "message": "file uploaded",
142
- "code": 200
143
- },
144
- "image": image_info,
145
- "status_txt": "OK"
146
- })
147
 
148
  if __name__ == "__main__":
149
  app.run(host="0.0.0.0", port=7860, debug=True)
 
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
 
16
  # 环境变量配置
17
  HF_TOKEN = os.environ.get("HF_TOKEN")
18
+ SPACE_ID = os.environ.get("SPACE_ID")
19
  MAX_SIZE = int(os.environ.get("MAX_SIZE", 10)) * 1024 * 1024 # 转字节
20
  API_KEY = os.environ.get("API_KEY")
 
21
 
 
22
  hf_api = HfApi(token=HF_TOKEN)
23
 
24
  def validate_auth():
 
28
  param_key = request.args.get("key")
29
  return header_key == API_KEY or param_key == API_KEY
30
 
31
+ def generate_filename(original_filename):
 
32
  unique_id = uuid.uuid4().hex[:8]
33
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
34
+ _, ext = os.path.splitext(original_filename)
35
  return f"{timestamp}-{unique_id}{ext}"
36
 
37
+ def save_to_space(content, filename):
38
+ path = f"images/{filename}"
39
+ hf_api.upload_file(
40
+ repo_id=SPACE_ID,
41
+ path_in_repo=path,
42
+ path_or_fileobj=content
43
+ )
44
+ return f"https://{SPACE_ID.split('/')[-1]}.hf.space/{path}"
45
 
46
  @app.route("/", methods=["GET"])
47
  def index():
48
  return render_template("index.html")
49
 
50
+ @app.route("/images/<path:filename>")
51
+ def serve_image(filename):
52
+ return send_from_directory("images", filename)
53
+
54
  @app.route("/api/1/upload", methods=["GET", "POST"])
55
  def upload():
56
  # 鉴权检查
 
67
  if "source" in request.files:
68
  file = request.files["source"]
69
  source = file.read()
70
+ original_filename = file.filename
71
  else:
72
  source = request.form.get("source")
73
+ original_filename = "uploaded_file"
74
  else:
75
  source = request.args.get("source")
76
+ original_filename = "uploaded_file"
77
 
78
  # 处理Base64、文件或URL
79
  if isinstance(source, bytes):
80
  content = source
81
  elif source and source.startswith(("http://", "https://")):
82
+ response = requests.get(source)
83
+ content = response.content
84
+ original_filename = os.path.basename(source)
85
  elif source and source.startswith("data:"):
86
  header, data = source.split(",", 1)
87
  mime_type = header.split(":")[1].split(";")[0]
88
  content = base64.b64decode(data)
89
+ ext = mimetypes.guess_extension(mime_type)
90
+ original_filename = f"uploaded_file{ext}"
91
  else:
92
  return jsonify({
93
  "status_code": 400,
94
+ "error": {"message": "Invalid source"},
95
  "status_txt": "Bad Request"
96
  }), 400
97
 
 
107
  try:
108
  image = Image.open(BytesIO(content))
109
  width, height = image.size
110
+ mime_type = Image.MIME[image.format]
 
 
111
  except:
112
  width = height = 0
113
+ mime_type = mimetypes.guess_type(original_filename)[0] or "application/octet-stream"
 
 
114
 
115
  # 生成存储信息
116
+ filename = generate_filename(original_filename)
117
+ file_url = save_to_space(BytesIO(content), filename)
118
+
119
+ # 构造响应
120
+ response_data = {
121
+ "status_code": 200,
122
+ "success": {"message": "file uploaded", "code": 200},
123
+ "image": {
124
+ "name": os.path.splitext(filename)[0],
125
+ "extension": os.path.splitext(filename)[1][1:],
126
+ "size": len(content),
127
+ "width": width,
128
+ "height": height,
129
+ "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
130
+ "date_gmt": (datetime.now() + timedelta(hours=3)).strftime("%Y-%m-%d %H:%M:%S"),
131
+ "title": request.form.get("title") or os.path.splitext(original_filename)[0],
132
+ "description": request.form.get("description"),
133
+ "nsfw": int(request.form.get("nsfw", 0)),
134
+ "md5": None, # 可以实现MD5计算如果需要
135
+ "storage_mode": "space",
136
+ "source_md5": None,
137
+ "original_filename": original_filename,
138
+ "views": 0,
139
+ "likes": 0,
140
+ "is_animated": int(getattr(image, "is_animated", False)),
141
+ "is_360": 0,
142
+ "category_id": request.form.get("category_id"),
143
+ "id_encoded": uuid.uuid4().hex[:8],
144
+ "filename": filename,
145
+ "mime": mime_type,
146
+ "url": file_url,
147
+ "ratio": width / height if height else 0,
148
+ "size_formatted": f"{len(content)/1024/1024:.1f} MB",
149
+ "url_viewer": file_url,
150
+ "url_short": file_url,
151
+ "display_url": file_url,
152
+ "display_width": width,
153
+ "display_height": height,
154
+ "views_label": "views",
155
+ "likes_label": "likes",
156
+ "how_long_ago": "moments ago",
157
+ "delete_url": None # 可以实现删除URL如果需要
158
+ },
159
+ "status_txt": "OK"
160
  }
161
 
162
+ response_format = request.args.get("format", "json")
163
  if response_format == "txt":
164
  return file_url
165
  elif response_format == "redirect":
166
  return redirect(file_url, code=302)
167
  else:
168
+ return jsonify(response_data)
 
 
 
 
 
 
 
 
169
 
170
  if __name__ == "__main__":
171
  app.run(host="0.0.0.0", port=7860, debug=True)