Upload 2 files
Browse files
app.py
CHANGED
|
@@ -10,8 +10,7 @@ import uuid
|
|
| 10 |
import threading
|
| 11 |
import time
|
| 12 |
import random
|
| 13 |
-
|
| 14 |
-
from starlette.responses import RedirectResponse
|
| 15 |
|
| 16 |
# 环境变量
|
| 17 |
ACCESS_PASSWORD = os.environ.get("ACCESS_PASSWORD", "changeme")
|
|
@@ -20,10 +19,12 @@ HF_SPACE_NAME = os.environ.get("HF_SPACE_NAME", "")
|
|
| 20 |
|
| 21 |
# 文件存储路径
|
| 22 |
IMAGE_DIR = Path("uploaded_images")
|
|
|
|
| 23 |
DB_PATH = "image_database.db"
|
| 24 |
|
| 25 |
# 创建图片存储目录
|
| 26 |
IMAGE_DIR.mkdir(exist_ok=True)
|
|
|
|
| 27 |
|
| 28 |
def init_db():
|
| 29 |
"""初始化数据库"""
|
|
@@ -83,12 +84,29 @@ def generate_image_hash():
|
|
| 83 |
return uuid.uuid4().hex[:12]
|
| 84 |
|
| 85 |
def generate_full_url(image_hash):
|
| 86 |
-
"""生成完整的图片URL
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
def keep_alive():
|
| 94 |
"""防止系统休眠的后台线程"""
|
|
@@ -131,6 +149,11 @@ def upload_images(images, description, password):
|
|
| 131 |
# 保存图片
|
| 132 |
img.save(file_path, quality=95, optimize=True)
|
| 133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
# 获取文件信息
|
| 135 |
file_size = file_path.stat().st_size
|
| 136 |
mime_type = f"image/{file_path.suffix[1:]}"
|
|
@@ -338,12 +361,18 @@ def delete_image_by_hash(image_hash, password):
|
|
| 338 |
file_path = Path(row['file_path'])
|
| 339 |
original_filename = row['original_filename']
|
| 340 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 341 |
# 删除数据库记录
|
| 342 |
cursor.execute("DELETE FROM images WHERE hash = ?", (image_hash,))
|
| 343 |
conn.commit()
|
| 344 |
conn.close()
|
| 345 |
|
| 346 |
-
#
|
| 347 |
if file_path.exists():
|
| 348 |
file_path.unlink()
|
| 349 |
|
|
@@ -540,79 +569,6 @@ with gr.Blocks(title="My图床", theme=gr.themes.Soft(), css=custom_css) as grad
|
|
| 540 |
outputs=[export_output, export_file_output]
|
| 541 |
)
|
| 542 |
|
| 543 |
-
# 在Gradio的底层FastAPI上添加自定义API路由
|
| 544 |
-
@gradio_app.app.get("/api/img/{image_hash}")
|
| 545 |
-
async def get_image(image_hash: str):
|
| 546 |
-
"""通过hash重定向到图片文件"""
|
| 547 |
-
try:
|
| 548 |
-
conn = get_db_connection()
|
| 549 |
-
cursor = conn.cursor()
|
| 550 |
-
cursor.execute("SELECT file_path FROM images WHERE hash = ?", (image_hash,))
|
| 551 |
-
row = cursor.fetchone()
|
| 552 |
-
conn.close()
|
| 553 |
-
|
| 554 |
-
if not row:
|
| 555 |
-
return JSONResponse(
|
| 556 |
-
status_code=404,
|
| 557 |
-
content={"error": "Image not found"}
|
| 558 |
-
)
|
| 559 |
-
|
| 560 |
-
file_path = Path(row['file_path'])
|
| 561 |
-
|
| 562 |
-
if not file_path.exists():
|
| 563 |
-
return JSONResponse(
|
| 564 |
-
status_code=404,
|
| 565 |
-
content={"error": "Image file not found"}
|
| 566 |
-
)
|
| 567 |
-
|
| 568 |
-
# 重定向到Gradio的文件服务路径
|
| 569 |
-
return RedirectResponse(url=f"/file={file_path}", status_code=302)
|
| 570 |
-
|
| 571 |
-
except Exception as e:
|
| 572 |
-
return JSONResponse(
|
| 573 |
-
status_code=500,
|
| 574 |
-
content={"error": str(e)}
|
| 575 |
-
)
|
| 576 |
-
|
| 577 |
-
@gradio_app.app.get("/api/img/{image_hash}/info")
|
| 578 |
-
async def get_image_info(image_hash: str, password: str = None):
|
| 579 |
-
"""获取图片信息(需要密码)"""
|
| 580 |
-
if not password or not check_password(password):
|
| 581 |
-
return JSONResponse(
|
| 582 |
-
status_code=401,
|
| 583 |
-
content={"error": "Unauthorized"}
|
| 584 |
-
)
|
| 585 |
-
|
| 586 |
-
try:
|
| 587 |
-
conn = get_db_connection()
|
| 588 |
-
cursor = conn.cursor()
|
| 589 |
-
cursor.execute("SELECT * FROM images WHERE hash = ?", (image_hash,))
|
| 590 |
-
row = cursor.fetchone()
|
| 591 |
-
conn.close()
|
| 592 |
-
|
| 593 |
-
if not row:
|
| 594 |
-
return JSONResponse(
|
| 595 |
-
status_code=404,
|
| 596 |
-
content={"error": "Image not found"}
|
| 597 |
-
)
|
| 598 |
-
|
| 599 |
-
return JSONResponse(content={
|
| 600 |
-
"hash": row['hash'],
|
| 601 |
-
"filename": row['filename'],
|
| 602 |
-
"original_filename": row['original_filename'],
|
| 603 |
-
"file_size": row['file_size'],
|
| 604 |
-
"mime_type": row['mime_type'],
|
| 605 |
-
"upload_time": row['upload_time'],
|
| 606 |
-
"description": row['description'],
|
| 607 |
-
"url": generate_full_url(row['hash'])
|
| 608 |
-
})
|
| 609 |
-
|
| 610 |
-
except Exception as e:
|
| 611 |
-
return JSONResponse(
|
| 612 |
-
status_code=500,
|
| 613 |
-
content={"error": str(e)}
|
| 614 |
-
)
|
| 615 |
-
|
| 616 |
if __name__ == "__main__":
|
| 617 |
# 直接启动Gradio,它会使用自己的FastAPI实例
|
| 618 |
gradio_app.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 10 |
import threading
|
| 11 |
import time
|
| 12 |
import random
|
| 13 |
+
import shutil
|
|
|
|
| 14 |
|
| 15 |
# 环境变量
|
| 16 |
ACCESS_PASSWORD = os.environ.get("ACCESS_PASSWORD", "changeme")
|
|
|
|
| 19 |
|
| 20 |
# 文件存储路径
|
| 21 |
IMAGE_DIR = Path("uploaded_images")
|
| 22 |
+
PUBLIC_DIR = Path("public") # 公共访问目录,使用hash作为文件名
|
| 23 |
DB_PATH = "image_database.db"
|
| 24 |
|
| 25 |
# 创建图片存储目录
|
| 26 |
IMAGE_DIR.mkdir(exist_ok=True)
|
| 27 |
+
PUBLIC_DIR.mkdir(exist_ok=True)
|
| 28 |
|
| 29 |
def init_db():
|
| 30 |
"""初始化数据库"""
|
|
|
|
| 84 |
return uuid.uuid4().hex[:12]
|
| 85 |
|
| 86 |
def generate_full_url(image_hash):
|
| 87 |
+
"""生成完整的图片URL(直接访问public目录)"""
|
| 88 |
+
# 查找对应的文件扩展名
|
| 89 |
+
try:
|
| 90 |
+
conn = get_db_connection()
|
| 91 |
+
cursor = conn.cursor()
|
| 92 |
+
cursor.execute("SELECT file_path FROM images WHERE hash = ?", (image_hash,))
|
| 93 |
+
row = cursor.fetchone()
|
| 94 |
+
conn.close()
|
| 95 |
+
|
| 96 |
+
if row:
|
| 97 |
+
ext = Path(row['file_path']).suffix
|
| 98 |
+
public_path = PUBLIC_DIR / f"{image_hash}{ext}"
|
| 99 |
+
file_path = f"/file={public_path}"
|
| 100 |
+
|
| 101 |
+
if HF_USERNAME and HF_SPACE_NAME:
|
| 102 |
+
return f"https://{HF_USERNAME}-{HF_SPACE_NAME}.hf.space{file_path}"
|
| 103 |
+
else:
|
| 104 |
+
return file_path
|
| 105 |
+
except:
|
| 106 |
+
pass
|
| 107 |
+
|
| 108 |
+
# 默认返回
|
| 109 |
+
return f"/file=public/{image_hash}"
|
| 110 |
|
| 111 |
def keep_alive():
|
| 112 |
"""防止系统休眠的后台线程"""
|
|
|
|
| 149 |
# 保存图片
|
| 150 |
img.save(file_path, quality=95, optimize=True)
|
| 151 |
|
| 152 |
+
# 在public目录创建副本,文件名为hash
|
| 153 |
+
ext = file_path.suffix
|
| 154 |
+
public_file = PUBLIC_DIR / f"{image_hash}{ext}"
|
| 155 |
+
shutil.copy2(file_path, public_file)
|
| 156 |
+
|
| 157 |
# 获取文件信息
|
| 158 |
file_size = file_path.stat().st_size
|
| 159 |
mime_type = f"image/{file_path.suffix[1:]}"
|
|
|
|
| 361 |
file_path = Path(row['file_path'])
|
| 362 |
original_filename = row['original_filename']
|
| 363 |
|
| 364 |
+
# 删除public目录的副本
|
| 365 |
+
ext = file_path.suffix
|
| 366 |
+
public_file = PUBLIC_DIR / f"{image_hash}{ext}"
|
| 367 |
+
if public_file.exists():
|
| 368 |
+
public_file.unlink()
|
| 369 |
+
|
| 370 |
# 删除数据库记录
|
| 371 |
cursor.execute("DELETE FROM images WHERE hash = ?", (image_hash,))
|
| 372 |
conn.commit()
|
| 373 |
conn.close()
|
| 374 |
|
| 375 |
+
# 删除原始文件
|
| 376 |
if file_path.exists():
|
| 377 |
file_path.unlink()
|
| 378 |
|
|
|
|
| 569 |
outputs=[export_output, export_file_output]
|
| 570 |
)
|
| 571 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 572 |
if __name__ == "__main__":
|
| 573 |
# 直接启动Gradio,它会使用自己的FastAPI实例
|
| 574 |
gradio_app.launch(server_name="0.0.0.0", server_port=7860)
|