lexlepty commited on
Commit
a88c5fe
·
verified ·
1 Parent(s): b0f1799

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +295 -295
app.py CHANGED
@@ -1,295 +1,295 @@
1
- from flask import (
2
- Flask,
3
- json,
4
- render_template,
5
- request,
6
- jsonify,
7
- redirect,
8
- url_for,
9
- send_file,
10
- Response
11
- )
12
- from io import BytesIO
13
- import urllib.parse
14
- from functools import wraps
15
- import requests
16
- import hashlib
17
- import os
18
- from config import Config
19
- from models import Database
20
- from utils import get_file_type, format_file_size
21
- from huggingface_hub import HfApi
22
-
23
- # 初始化 HuggingFace API
24
- api = HfApi(token=Config.HF_TOKEN)
25
- app = Flask(__name__)
26
- app.config['SECRET_KEY'] = Config.SECRET_KEY
27
- db = Database()
28
-
29
- def require_auth(f):
30
- @wraps(f)
31
- def decorated(*args, **kwargs):
32
- if not Config.REQUIRE_LOGIN:
33
- return f(*args, **kwargs)
34
- if not request.cookies.get('authenticated'):
35
- if request.is_json:
36
- return jsonify({'error': 'Unauthorized'}), 401
37
- return redirect(url_for('login'))
38
- return f(*args, **kwargs)
39
- return decorated
40
-
41
- @app.route('/login', methods=['GET', 'POST'])
42
- def login():
43
- if request.method == 'POST':
44
- if request.form.get('password') == Config.ACCESS_PASSWORD:
45
- response = jsonify({'success': True})
46
- response.set_cookie('authenticated', 'true', secure=True, httponly=True)
47
- return response
48
- return jsonify({'error': 'Invalid password'}), 401
49
- return render_template('login.html')
50
-
51
- @app.route('/logout')
52
- def logout():
53
- response = redirect(url_for('login'))
54
- response.delete_cookie('authenticated')
55
- return response
56
-
57
- @app.route('/')
58
- @require_auth
59
- def index():
60
- return render_template('index.html')
61
-
62
- @app.route('/api/files/list/')
63
- @app.route('/api/files/list/<path:directory>')
64
- @require_auth
65
- def list_files(directory=''):
66
- try:
67
- url = f"https://huggingface.co/api/datasets/{Config.HF_DATASET_ID}/tree/{Config.HF_BRANCH}"
68
- if directory:
69
- url = f"{url}/{directory}"
70
-
71
- response = requests.get(
72
- url,
73
- headers={'Authorization': f'Bearer {Config.HF_TOKEN}'}
74
- )
75
- if not response.ok:
76
- return jsonify({'error': 'Failed to fetch files', 'details': response.text}), response.status_code
77
-
78
- files = response.json()
79
- for file in files:
80
- if file['type'] == 'file':
81
- file['file_type'] = get_file_type(file['path'])
82
- file['size_formatted'] = format_file_size(file['size'])
83
- # 添加预览和下载URL
84
- file['preview_url'] = f"/api/files/preview/{file['path']}"
85
- file['download_url'] = f"/api/files/download/{file['path']}"
86
-
87
- return jsonify(files)
88
- except Exception as e:
89
- return jsonify({'error': str(e)}), 500
90
-
91
- @app.route('/api/files/preview/<path:filepath>')
92
- @require_auth
93
- def preview_file(filepath):
94
- try:
95
- file_type = get_file_type(filepath)
96
- if file_type not in ['image', 'video', 'document']:
97
- return jsonify({'error': 'File type not supported for preview'}), 400
98
-
99
- url = f"https://{Config.PROXY_DOMAIN}/datasets/{Config.HF_DATASET_ID}/resolve/{Config.HF_BRANCH}/{filepath}"
100
- response = requests.get(
101
- url,
102
- headers={'Authorization': f'Bearer {Config.HF_TOKEN}'},
103
- stream=True
104
- )
105
-
106
- if response.ok:
107
- def generate():
108
- for chunk in response.iter_content(chunk_size=8192):
109
- yield chunk
110
-
111
- return Response(
112
- generate(),
113
- mimetype=response.headers.get('content-type', 'application/octet-stream'),
114
- direct_passthrough=True
115
- )
116
-
117
- return jsonify({'error': 'Failed to fetch file'}), response.status_code
118
- except Exception as e:
119
- return jsonify({'error': str(e)}), 500
120
-
121
- @app.route('/api/files/download/<path:filepath>')
122
- @require_auth
123
- def download_file(filepath):
124
- try:
125
- url = f"https://{Config.PROXY_DOMAIN}/datasets/{Config.HF_DATASET_ID}/resolve/{Config.HF_BRANCH}/{filepath}"
126
-
127
- # 获取文件基本信息
128
- response = requests.get(
129
- url,
130
- headers={'Authorization': f'Bearer {Config.HF_TOKEN}'},
131
- stream=True
132
- )
133
-
134
- if response.ok:
135
- filename = os.path.basename(filepath)
136
- encoded_filename = urllib.parse.quote(filename.encode('utf-8'))
137
-
138
- # 直接流式传输文件内容
139
- return Response(
140
- response.iter_content(chunk_size=1048576),
141
- headers={
142
- 'Content-Disposition': f'attachment; filename*=UTF-8\'\'{encoded_filename}',
143
- 'Content-Type': response.headers.get('content-type', 'application/octet-stream'),
144
- 'Content-Length': response.headers.get('content-length'),
145
- 'Accept-Ranges': 'bytes'
146
- }
147
- )
148
-
149
- return jsonify({'error': 'File not found'}), 404
150
-
151
- except Exception as e:
152
- return jsonify({'error': str(e)}), 500
153
- @app.route('/api/files/upload', methods=['POST'])
154
- @require_auth
155
- def upload_file():
156
- if 'file' not in request.files:
157
- return jsonify({'error': 'No file provided'}), 400
158
-
159
- file = request.files['file']
160
- current_path = request.form.get('path', '').strip('/')
161
-
162
- try:
163
- file_content = file.read()
164
- file.seek(0)
165
-
166
- original_name = file.filename
167
- stored_name = original_name
168
- full_path = os.path.join(current_path, stored_name).replace("\\", "/")
169
-
170
- response = api.upload_file(
171
- path_or_fileobj=file_content,
172
- path_in_repo=full_path,
173
- repo_id=Config.HF_DATASET_ID,
174
- repo_type="dataset",
175
- token=Config.HF_TOKEN
176
- )
177
-
178
- if response:
179
- with db.conn.cursor() as cursor:
180
- cursor.execute("""
181
- INSERT INTO files (
182
- original_name, stored_name, file_path,
183
- file_type, file_size
184
- ) VALUES (%s, %s, %s, %s, %s)
185
- """, (
186
- original_name,
187
- stored_name,
188
- full_path,
189
- get_file_type(original_name),
190
- len(file_content)
191
- ))
192
- db.conn.commit()
193
-
194
- return jsonify({'success': True})
195
-
196
- return jsonify({'error': 'Upload failed'}), 500
197
-
198
- except Exception as e:
199
- return jsonify({'error': str(e)}), 500
200
-
201
- @app.route('/api/files/search')
202
- @require_auth
203
- def search_files():
204
- keyword = request.args.get('keyword', '')
205
- if not keyword:
206
- return jsonify([])
207
-
208
- try:
209
- files = db.search_files(keyword)
210
- return jsonify([{
211
- 'name': f['original_name'],
212
- 'path': f['file_path'],
213
- 'type': get_file_type(f['file_path']),
214
- 'size': format_file_size(f['file_size']),
215
- 'created_at': f['created_at'].strftime('%Y-%m-%d %H:%M:%S')
216
- } for f in files])
217
- except Exception as e:
218
- return jsonify({'error': str(e)}), 500
219
-
220
- @app.route('/api/files/delete/<path:filepath>', methods=['DELETE'])
221
- @require_auth
222
- def delete_file(filepath):
223
- try:
224
- # Initialize HuggingFace API
225
- api = HfApi(token=Config.HF_TOKEN)
226
-
227
- # Delete file from HuggingFace Hub
228
- api.delete_file(
229
- path_in_repo=filepath,
230
- repo_id=Config.HF_DATASET_ID,
231
- repo_type="dataset"
232
- )
233
-
234
- # Delete file record from database
235
- with db.conn.cursor() as cursor:
236
- cursor.execute(
237
- "DELETE FROM files WHERE file_path = %s",
238
- [filepath]
239
- )
240
- db.conn.commit()
241
-
242
- return jsonify({'success': True})
243
-
244
- except Exception as e:
245
- return jsonify({'error': str(e)}), 500
246
-
247
- @app.route('/api/files/create_folder', methods=['POST'])
248
- @require_auth
249
- def create_folder():
250
- try:
251
- data = request.json
252
- path = data.get('path', '/')
253
- name = data.get('name')
254
-
255
- if not name:
256
- return jsonify({'error': 'Folder name is required'}), 400
257
-
258
- full_path = os.path.join(path, name, '.keep').replace("\\", "/")
259
-
260
- # 使用 HuggingFace API 创建文件夹
261
- api = HfApi(token=Config.HF_TOKEN)
262
- response = api.upload_file(
263
- path_or_fileobj=b'', # 空内容
264
- path_in_repo=full_path,
265
- repo_id=Config.HF_DATASET_ID,
266
- repo_type="dataset",
267
- token=Config.HF_TOKEN
268
- )
269
-
270
- if response:
271
- # 记录到数据库
272
- with db.conn.cursor() as cursor:
273
- cursor.execute("""
274
- INSERT INTO files (
275
- original_name, stored_name, file_path,
276
- file_type, file_size
277
- ) VALUES (%s, %s, %s, %s, %s)
278
- """, (
279
- '.keep',
280
- '.keep',
281
- full_path,
282
- 'directory',
283
- 0
284
- ))
285
- db.conn.commit()
286
-
287
- return jsonify({'message': 'Folder created successfully'})
288
-
289
- return jsonify({'error': 'Failed to create folder'}), 500
290
-
291
- except Exception as e:
292
- return jsonify({'error': str(e)}), 500
293
-
294
- if __name__ == '__main__':
295
- app.run(host='0.0.0.0', port=5000, debug=True)
 
1
+ from flask import (
2
+ Flask,
3
+ json,
4
+ render_template,
5
+ request,
6
+ jsonify,
7
+ redirect,
8
+ url_for,
9
+ send_file,
10
+ Response
11
+ )
12
+ from io import BytesIO
13
+ import urllib.parse
14
+ from functools import wraps
15
+ import requests
16
+ import hashlib
17
+ import os
18
+ from config import Config
19
+ from models import Database
20
+ from utils import get_file_type, format_file_size
21
+ from huggingface_hub import HfApi
22
+
23
+ # 初始化 HuggingFace API
24
+ api = HfApi(token=Config.HF_TOKEN)
25
+ app = Flask(__name__)
26
+ app.config['SECRET_KEY'] = Config.SECRET_KEY
27
+ db = Database()
28
+
29
+ def require_auth(f):
30
+ @wraps(f)
31
+ def decorated(*args, **kwargs):
32
+ if not Config.REQUIRE_LOGIN:
33
+ return f(*args, **kwargs)
34
+ if not request.cookies.get('authenticated'):
35
+ if request.is_json:
36
+ return jsonify({'error': 'Unauthorized'}), 401
37
+ return redirect(url_for('login'))
38
+ return f(*args, **kwargs)
39
+ return decorated
40
+
41
+ @app.route('/login', methods=['GET', 'POST'])
42
+ def login():
43
+ if request.method == 'POST':
44
+ if request.form.get('password') == Config.ACCESS_PASSWORD:
45
+ response = jsonify({'success': True})
46
+ response.set_cookie('authenticated', 'true', secure=True, httponly=True)
47
+ return response
48
+ return jsonify({'error': 'Invalid password'}), 401
49
+ return render_template('login.html')
50
+
51
+ @app.route('/logout')
52
+ def logout():
53
+ response = redirect(url_for('login'))
54
+ response.delete_cookie('authenticated')
55
+ return response
56
+
57
+ @app.route('/')
58
+ @require_auth
59
+ def index():
60
+ return render_template('index.html')
61
+
62
+ @app.route('/api/files/list/')
63
+ @app.route('/api/files/list/<path:directory>')
64
+ @require_auth
65
+ def list_files(directory=''):
66
+ try:
67
+ url = f"https://huggingface.co/api/datasets/{Config.HF_DATASET_ID}/tree/{Config.HF_BRANCH}"
68
+ if directory:
69
+ url = f"{url}/{directory}"
70
+
71
+ response = requests.get(
72
+ url,
73
+ headers={'Authorization': f'Bearer {Config.HF_TOKEN}'}
74
+ )
75
+ if not response.ok:
76
+ return jsonify({'error': 'Failed to fetch files', 'details': response.text}), response.status_code
77
+
78
+ files = response.json()
79
+ for file in files:
80
+ if file['type'] == 'file':
81
+ file['file_type'] = get_file_type(file['path'])
82
+ file['size_formatted'] = format_file_size(file['size'])
83
+ # 添加预览和下载URL
84
+ file['preview_url'] = f"/api/files/preview/{file['path']}"
85
+ file['download_url'] = f"/api/files/download/{file['path']}"
86
+
87
+ return jsonify(files)
88
+ except Exception as e:
89
+ return jsonify({'error': str(e)}), 500
90
+
91
+ @app.route('/api/files/preview/<path:filepath>')
92
+ @require_auth
93
+ def preview_file(filepath):
94
+ try:
95
+ file_type = get_file_type(filepath)
96
+ if file_type not in ['image', 'video', 'document']:
97
+ return jsonify({'error': 'File type not supported for preview'}), 400
98
+
99
+ url = f"https://{Config.PROXY_DOMAIN}/datasets/{Config.HF_DATASET_ID}/resolve/{Config.HF_BRANCH}/{filepath}"
100
+ response = requests.get(
101
+ url,
102
+ headers={'Authorization': f'Bearer {Config.HF_TOKEN}'},
103
+ stream=True
104
+ )
105
+
106
+ if response.ok:
107
+ def generate():
108
+ for chunk in response.iter_content(chunk_size=8192):
109
+ yield chunk
110
+
111
+ return Response(
112
+ generate(),
113
+ mimetype=response.headers.get('content-type', 'application/octet-stream'),
114
+ direct_passthrough=True
115
+ )
116
+
117
+ return jsonify({'error': 'Failed to fetch file'}), response.status_code
118
+ except Exception as e:
119
+ return jsonify({'error': str(e)}), 500
120
+
121
+ @app.route('/api/files/download/<path:filepath>')
122
+ @require_auth
123
+ def download_file(filepath):
124
+ try:
125
+ url = f"https://{Config.PROXY_DOMAIN}/datasets/{Config.HF_DATASET_ID}/resolve/{Config.HF_BRANCH}/{filepath}"
126
+
127
+ # 获取文件基本信息
128
+ response = requests.get(
129
+ url,
130
+ headers={'Authorization': f'Bearer {Config.HF_TOKEN}'},
131
+ stream=True
132
+ )
133
+
134
+ if response.ok:
135
+ filename = os.path.basename(filepath)
136
+ encoded_filename = urllib.parse.quote(filename.encode('utf-8'))
137
+
138
+ # 直接流式传输文件内容
139
+ return Response(
140
+ response.iter_content(chunk_size=1048576),
141
+ headers={
142
+ 'Content-Disposition': f'attachment; filename*=UTF-8\'\'{encoded_filename}',
143
+ 'Content-Type': response.headers.get('content-type', 'application/octet-stream'),
144
+ 'Content-Length': response.headers.get('content-length'),
145
+ 'Accept-Ranges': 'bytes'
146
+ }
147
+ )
148
+
149
+ return jsonify({'error': 'File not found'}), 404
150
+
151
+ except Exception as e:
152
+ return jsonify({'error': str(e)}), 500
153
+ @app.route('/api/files/upload', methods=['POST'])
154
+ @require_auth
155
+ def upload_file():
156
+ if 'file' not in request.files:
157
+ return jsonify({'error': 'No file provided'}), 400
158
+
159
+ file = request.files['file']
160
+ current_path = request.form.get('path', '').strip('/')
161
+
162
+ try:
163
+ file_content = file.read()
164
+ file.seek(0)
165
+
166
+ original_name = file.filename
167
+ stored_name = original_name
168
+ full_path = os.path.join(current_path, stored_name).replace("\\", "/")
169
+
170
+ response = api.upload_file(
171
+ path_or_fileobj=file_content,
172
+ path_in_repo=full_path,
173
+ repo_id=Config.HF_DATASET_ID,
174
+ repo_type="dataset",
175
+ token=Config.HF_TOKEN
176
+ )
177
+
178
+ if response:
179
+ with db.conn.cursor() as cursor:
180
+ cursor.execute("""
181
+ INSERT INTO files (
182
+ original_name, stored_name, file_path,
183
+ file_type, file_size
184
+ ) VALUES (%s, %s, %s, %s, %s)
185
+ """, (
186
+ original_name,
187
+ stored_name,
188
+ full_path,
189
+ get_file_type(original_name),
190
+ len(file_content)
191
+ ))
192
+ db.conn.commit()
193
+
194
+ return jsonify({'success': True})
195
+
196
+ return jsonify({'error': 'Upload failed'}), 500
197
+
198
+ except Exception as e:
199
+ return jsonify({'error': str(e)}), 500
200
+
201
+ @app.route('/api/files/search')
202
+ @require_auth
203
+ def search_files():
204
+ keyword = request.args.get('keyword', '')
205
+ if not keyword:
206
+ return jsonify([])
207
+
208
+ try:
209
+ files = db.search_files(keyword)
210
+ return jsonify([{
211
+ 'name': f['original_name'],
212
+ 'path': f['file_path'],
213
+ 'type': get_file_type(f['file_path']),
214
+ 'size': format_file_size(f['file_size']),
215
+ 'created_at': f['created_at'].strftime('%Y-%m-%d %H:%M:%S')
216
+ } for f in files])
217
+ except Exception as e:
218
+ return jsonify({'error': str(e)}), 500
219
+
220
+ @app.route('/api/files/delete/<path:filepath>', methods=['DELETE'])
221
+ @require_auth
222
+ def delete_file(filepath):
223
+ try:
224
+ # Initialize HuggingFace API
225
+ api = HfApi(token=Config.HF_TOKEN)
226
+
227
+ # Delete file from HuggingFace Hub
228
+ api.delete_file(
229
+ path_in_repo=filepath,
230
+ repo_id=Config.HF_DATASET_ID,
231
+ repo_type="dataset"
232
+ )
233
+
234
+ # Delete file record from database
235
+ with db.conn.cursor() as cursor:
236
+ cursor.execute(
237
+ "DELETE FROM files WHERE file_path = %s",
238
+ [filepath]
239
+ )
240
+ db.conn.commit()
241
+
242
+ return jsonify({'success': True})
243
+
244
+ except Exception as e:
245
+ return jsonify({'error': str(e)}), 500
246
+
247
+ @app.route('/api/files/create_folder', methods=['POST'])
248
+ @require_auth
249
+ def create_folder():
250
+ try:
251
+ data = request.json
252
+ path = data.get('path', '/')
253
+ name = data.get('name')
254
+
255
+ if not name:
256
+ return jsonify({'error': 'Folder name is required'}), 400
257
+
258
+ full_path = os.path.join(path, name, '.keep').replace("\\", "/")
259
+
260
+ # 使用 HuggingFace API 创建文件夹
261
+ api = HfApi(token=Config.HF_TOKEN)
262
+ response = api.upload_file(
263
+ path_or_fileobj=b'', # 空内容
264
+ path_in_repo=full_path,
265
+ repo_id=Config.HF_DATASET_ID,
266
+ repo_type="dataset",
267
+ token=Config.HF_TOKEN
268
+ )
269
+
270
+ if response:
271
+ # 记录到数据库
272
+ with db.conn.cursor() as cursor:
273
+ cursor.execute("""
274
+ INSERT INTO files (
275
+ original_name, stored_name, file_path,
276
+ file_type, file_size
277
+ ) VALUES (%s, %s, %s, %s, %s)
278
+ """, (
279
+ '.keep',
280
+ '.keep',
281
+ full_path,
282
+ 'directory',
283
+ 0
284
+ ))
285
+ db.conn.commit()
286
+
287
+ return jsonify({'message': 'Folder created successfully'})
288
+
289
+ return jsonify({'error': 'Failed to create folder'}), 500
290
+
291
+ except Exception as e:
292
+ return jsonify({'error': str(e)}), 500
293
+
294
+ if __name__ == '__main__':
295
+ app.run(host='0.0.0.0', port=7860, debug=True)