Moonfanz commited on
Commit
ca2bf17
·
verified ·
1 Parent(s): b275b3a

Upload 5 files

Browse files
Files changed (5) hide show
  1. Dockerfile +31 -0
  2. app.py +81 -0
  3. requirements.txt +3 -0
  4. templates/index.html +46 -0
  5. templates/view.html +118 -0
Dockerfile ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 使用官方 Python 镜像作为基础镜像
2
+ FROM python:3.9-slim-buster
3
+
4
+ # 设置工作目录
5
+ WORKDIR /app
6
+
7
+ # 复制 requirements.txt 到容器中
8
+ COPY requirements.txt /app/
9
+
10
+ # 安装依赖
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # 安装必要的系统包
14
+ RUN apt-get update && apt-get install -y --no-install-recommends \
15
+ gcc \
16
+ libc-dev \
17
+ libmupdf-dev \
18
+ libmupdf-tools \
19
+ && rm -rf /var/lib/apt/lists/*
20
+
21
+ # 复制当前目录的所有文件到容器中
22
+ COPY . /app/
23
+
24
+ # 暴露端口
25
+ EXPOSE 7860
26
+
27
+ # 定义环境变量
28
+ ENV NAME pdf_manager
29
+
30
+ # 运行应用程序
31
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ from flask import Flask, render_template, request, send_from_directory, redirect, url_for
4
+ from werkzeug.utils import secure_filename
5
+ import fitz # PyMuPDF
6
+
7
+ app = Flask(__name__)
8
+
9
+ # 配置
10
+ app.config['UPLOAD_FOLDER'] = '/temp/uploads'
11
+ app.config['ALLOWED_EXTENSIONS'] = {'pdf'}
12
+ app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB 上传限制
13
+ app.config['PORT'] = 7860
14
+
15
+ # 确保上传目录存在
16
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
17
+
18
+ def allowed_file(filename):
19
+ return '.' in filename and \
20
+ filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']
21
+
22
+ @app.route('/')
23
+ def index():
24
+ pdf_files = [f for f in os.listdir(app.config['UPLOAD_FOLDER']) if f.endswith('.pdf')]
25
+ return render_template('index.html', pdf_files=pdf_files)
26
+
27
+ @app.route('/upload', methods=['POST'])
28
+ def upload_file():
29
+ if 'file' not in request.files:
30
+ return redirect(request.url)
31
+ file = request.files['file']
32
+ if file.filename == '':
33
+ return redirect(request.url)
34
+ if file and allowed_file(file.filename):
35
+ filename = secure_filename(file.filename)
36
+ file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
37
+ return redirect(url_for('index'))
38
+ return redirect(request.url)
39
+
40
+ @app.route('/view/<filename>')
41
+ def view_pdf(filename):
42
+ return render_template('view.html', filename=filename)
43
+
44
+ @app.route('/get_pdf/<filename>')
45
+ def get_pdf(filename):
46
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
47
+
48
+ @app.route('/delete/<filename>')
49
+ def delete_pdf(filename):
50
+ file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
51
+ if os.path.exists(file_path):
52
+ os.remove(file_path)
53
+ return redirect(url_for('index'))
54
+
55
+ @app.route('/delete_all')
56
+ def delete_all_pdfs():
57
+ folder = app.config['UPLOAD_FOLDER']
58
+ for filename in os.listdir(folder):
59
+ file_path = os.path.join(folder, filename)
60
+ try:
61
+ if os.path.isfile(file_path) or os.path.islink(file_path):
62
+ os.unlink(file_path)
63
+ elif os.path.isdir(file_path):
64
+ shutil.rmtree(file_path)
65
+ except Exception as e:
66
+ print(f'Failed to delete {file_path}. Reason: {e}')
67
+ return redirect(url_for('index'))
68
+
69
+ @app.route('/get_page/<filename>/<int:page_num>')
70
+ def get_page(filename, page_num):
71
+ try:
72
+ doc = fitz.open(os.path.join(app.config['UPLOAD_FOLDER'], filename))
73
+ page = doc.load_page(page_num - 1) # page numbers are zero-based
74
+ pix = page.get_pixmap()
75
+ img_data = pix.tobytes("png")
76
+ return img_data, 200, {'Content-Type': 'image/png'}
77
+ except Exception as e:
78
+ return str(e), 500
79
+
80
+ if __name__ == '__main__':
81
+ app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ Flask==2.2.2
2
+ Werkzeug==2.2.2
3
+ PyMuPDF==1.21.0
templates/index.html ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <title>PDF Manager</title>
7
+ <style>
8
+ body {
9
+ font-family: sans-serif;
10
+ }
11
+
12
+ .pdf-item {
13
+ margin-bottom: 10px;
14
+ }
15
+
16
+ .pdf-item a {
17
+ margin-right: 10px;
18
+ }
19
+ </style>
20
+ </head>
21
+
22
+ <body>
23
+ <h1>PDF Manager</h1>
24
+
25
+ <h2>Upload PDF</h2>
26
+ <form method="POST" action="/upload" enctype="multipart/form-data">
27
+ <input type="file" name="file">
28
+ <button type="submit">Upload</button>
29
+ </form>
30
+
31
+ <h2>Uploaded PDFs</h2>
32
+ {% if pdf_files %}
33
+ {% for filename in pdf_files %}
34
+ <div class="pdf-item">
35
+ <a href="{{ url_for('view_pdf', filename=filename) }}">{{ filename }}</a>
36
+ <a href="{{ url_for('delete_pdf', filename=filename) }}" onclick="return confirm('Are you sure?')">Delete</a>
37
+ </div>
38
+ {% endfor %}
39
+ {% else %}
40
+ <p>No PDFs uploaded yet.</p>
41
+ {% endif %}
42
+ <a href="{{ url_for('delete_all_pdfs') }}"
43
+ onclick="return confirm('Are you sure you want to delete all PDFs?')">Delete All</a>
44
+ </body>
45
+
46
+ </html>
templates/view.html ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <title>View PDF - {{ filename }}</title>
7
+ <style>
8
+ body {
9
+ font-family: sans-serif;
10
+ text-align: center;
11
+ }
12
+
13
+ #pdf-container {
14
+ width: 100%;
15
+ height: 800px;
16
+ overflow: auto;
17
+ }
18
+
19
+ .page-img {
20
+ width: 100%;
21
+ }
22
+
23
+ .nav-btn {
24
+ padding: 10px;
25
+ margin: 5px;
26
+ cursor: pointer;
27
+ background-color: #4CAF50;
28
+ color: white;
29
+ border: none;
30
+ }
31
+ </style>
32
+ </head>
33
+
34
+ <body>
35
+ <h1>{{ filename }}</h1>
36
+ <button class="nav-btn" onclick="prevPage()">Previous</button>
37
+ <span id="page-num">1</span> / <span id="page-count"></span>
38
+ <button class="nav-btn" onclick="nextPage()">Next</button>
39
+ <div id="pdf-container">
40
+ <!-- PDF pages will be loaded here -->
41
+ </div>
42
+
43
+ <script>
44
+ const pdfFilename = "{{ filename }}";
45
+ let currentPage = 1;
46
+ let pageCount = 0;
47
+
48
+ function loadPage(pageNum) {
49
+ fetch(`/get_page/${pdfFilename}/${pageNum}`)
50
+ .then(response => {
51
+ if (!response.ok) {
52
+ throw new Error('Network response was not ok');
53
+ }
54
+ return response.blob();
55
+ })
56
+ .then(blob => {
57
+ const imageUrl = URL.createObjectURL(blob);
58
+ const img = document.createElement('img');
59
+ img.src = imageUrl;
60
+ img.className = 'page-img';
61
+ const pdfContainer = document.getElementById('pdf-container');
62
+ pdfContainer.innerHTML = ''; // 清空之前的页面
63
+ pdfContainer.appendChild(img);
64
+ document.getElementById('page-num').textContent = pageNum;
65
+ })
66
+ .catch(error => {
67
+ console.error('Error:', error);
68
+ });
69
+ }
70
+
71
+ function prevPage() {
72
+ if (currentPage > 1) {
73
+ currentPage--;
74
+ loadPage(currentPage);
75
+ }
76
+ }
77
+
78
+ function nextPage() {
79
+ if (currentPage < pageCount) {
80
+ currentPage++;
81
+ loadPage(currentPage);
82
+ }
83
+ }
84
+
85
+ // 初始化时获取总页数
86
+ fetch(`/get_page/${pdfFilename}/1`)
87
+ .then(response => {
88
+ if (!response.ok) {
89
+ throw new Error('Network response was not ok');
90
+ }
91
+ // 假设第一页加载成功,通过 PyMuPDF 获取总页数
92
+ return fetch(`/get_page/${pdfFilename}/1`);
93
+ })
94
+ .then(() => {
95
+ // 这里没法直接获取总页数, 需要通过循环尝试, 直到一个错误返回
96
+ // 此方法效率较低,仅为演示用
97
+ function fetchPageCount(page = 1) {
98
+ fetch(`/get_page/${pdfFilename}/${page}`)
99
+ .then(response => {
100
+ if (!response.ok) {
101
+ pageCount = page - 1;
102
+ document.getElementById('page-count').textContent = pageCount;
103
+ loadPage(currentPage);
104
+ } else {
105
+ fetchPageCount(page + 1);
106
+ }
107
+ })
108
+ }
109
+ fetchPageCount();
110
+ })
111
+ .catch(error => {
112
+ console.error('Error:', error);
113
+ });
114
+
115
+ </script>
116
+ </body>
117
+
118
+ </html>