1. 完成檔案生成瀏覽器下載功能

This commit is contained in:
shouchih_chen 2025-06-23 21:39:38 +08:00
parent 0b18e4b8ab
commit e329908d88
3 changed files with 72 additions and 29 deletions

47
app.py
View File

@ -1,8 +1,10 @@
import os
import uuid
from flask import Flask, render_template, request, send_file
import subprocess
from datetime import datetime
import zipfile
import io
app = Flask(__name__)
@ -24,6 +26,9 @@ def allowed_file(filename):
@app.route("/")
def index():
search_str = 'e771'
return render_template("index.html")
@app.route("/hello")
def hello():
@ -38,15 +43,42 @@ def upload_csv():
if file.filename == '':
return "No selected file", 400
if file and allowed_file(file.filename):
unique_filename = str(uuid.uuid4()) + '.csv'
csv_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
uuid_str = str(uuid.uuid4())[:4]
unique_filename = datetime.now().strftime("%Y%m%d_%H%M")+ '_' + uuid_str
csv_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename+'.csv')
file.save(csv_path)
print(f"CSV file saved to {csv_path}")
try:
# 呼叫外部 Python 腳本來生成圖片
subprocess.run([os.path.join(os.getcwd(), '.venv', 'Scripts', 'python'), 'generate_images.py', csv_path], check=True)
subprocess.run([os.path.join(os.getcwd(), '.venv', 'Scripts', 'python'), 'generate_images.py', csv_path, unique_filename ], check=True)
folder = app.config['GENERATED_IMAGES_FOLDER']
matched_files = [f for f in os.listdir(folder) if uuid_str in f and f.endswith('.png')]
print(f"Matched files: {matched_files}")
# 壓縮所有圖片到一個 zip
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, 'w') as zip_file:
for filename in matched_files:
file_path = os.path.join(folder, filename)
zip_file.write(file_path, arcname=filename)
zip_buffer.seek(0)
# 刪除生成的圖片文件
for filename in matched_files:
file_path = os.path.join(folder, filename)
os.remove(file_path)
print(f"Deleted file: {file_path}")
# 刪除 CSV 文件
os.remove(csv_path)
return send_file(
zip_buffer,
mimetype='application/zip',
as_attachment=True,
download_name=f'{unique_filename}_images.zip'
)
except subprocess.CalledProcessError as e:
print(f"Error generating images: {e}")
return "Error generating images", 500
@ -57,8 +89,7 @@ def upload_csv():
print(f"An unexpected error occurred: {e}")
return "An unexpected error occurred", 500
return "File uploaded successfully", 200
return "File uploaded successfully", 200
if __name__ == '__main__':

View File

@ -101,7 +101,7 @@ class ImageGenerator(QObject):
self.stop()
@Slot()
def generate_images(self, name_csv):
def generate_images(self, name_csv, out_filename):
# Placeholder for image generation logic
print("Generating images...1")
@ -161,7 +161,7 @@ class ImageGenerator(QObject):
if i > 0 and i % 6 == 5:
# Save the current scene to an image file every 5 items
self.scene_to_image(self.scene, f"generated_image_{i//6}.png")
self.scene_to_image(self.scene, f"{out_filename}_{i//6}.png")
self.scene.clear()
print("Image generated and added to scene.")
@ -177,17 +177,19 @@ if __name__ == "__main__":
generator = ImageGenerator()
generator.finished.connect(app.quit)
if len(sys.argv) > 1:
csv_file = "resource/sample.csv"
out_filename = "generated_image"
if len(sys.argv) > 2:
csv_file = sys.argv[1]
print(f"Loading CSV file: {csv_file}")
else:
csv_file = "resource/sample.csv"
print(f"No CSV file provided, using default: {csv_file}")
out_filename = sys.argv[2]
print(f"Loading CSV file: {csv_file}, Output filename: {out_filename}")
sample_data = generator.read_csv(csv_file)
print(f"Sample data loaded: {sample_data}")
generator.generate_images(sample_data)
generator.generate_images(sample_data, out_filename)
#generator.start()
# Run the application event loop

View File

@ -3,13 +3,13 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSV 轉圖片工具</title>
<title>圓形鑰匙圈產生器</title>
</head>
<body>
<h1>上傳 CSV 產生圖片</h1>
<h1>圓形鑰匙圈產生器</h1>
<form id="uploadForm" enctype="multipart/form-data">
<input type="file" id="csvFile" name="csvFile" accept=".csv">
<button type="submit">生成圖片</button>
<!-- <button type="submit">生成圖片</button> -->
</form>
<div id="status"></div>
<div id="downloadLink" style="display: none;">
@ -36,8 +36,13 @@
const formData = new FormData();
formData.append('csvFile', fileInput.files[0]);
// 產生日期時間字串
const now = new Date();
const pad = n => n.toString().padStart(2, '0');
const datetimeStr = `${now.getFullYear()}${pad(now.getMonth()+1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}`;
try {
const response = await fetch('/upload_csv', { // 請確保後端路由與此匹配
const response = await fetch('/upload_csv', {
method: 'POST',
body: formData
});
@ -47,21 +52,26 @@
throw new Error(`伺服器錯誤: ${response.status} - ${errorText}`);
}
// 假設後端會返回圖片的 Blob 或直接是檔案的 URL
// 如果後端直接返回圖片檔案,可以直接創建 Blob URL
const imageBlob = await response.blob();
const imageUrl = URL.createObjectURL(imageBlob);
// 取得 zip blob 並建立下載連結
const zipBlob = await response.blob();
const zipUrl = URL.createObjectURL(zipBlob);
downloadAnchor.href = imageUrl;
downloadAnchor.download = 'generated_image.png'; // 可以從後端獲取圖片名稱
statusDiv.textContent = '圖片已成功生成!';
downloadAnchor.href = zipUrl;
downloadAnchor.download = `${datetimeStr}_圓形鑰匙產生器.zip`; // zip 檔名加上日期時間
statusDiv.textContent = '圖片已成功生成!請點擊下方連結下載壓縮檔。';
downloadLinkDiv.style.display = 'block';
downloadAnchor.click(); // 自動觸發下載
} catch (error) {
console.error('上傳或生成圖片失敗:', error);
statusDiv.textContent = `生成圖片失敗: ${error.message || '未知錯誤'}`;
}
});
document.getElementById('csvFile').addEventListener('change', function() {
// 自動觸發表單提交
document.getElementById('uploadForm').dispatchEvent(new Event('submit', {cancelable: true, bubbles: true}));
});
</script>
</body>
</html>