1. 完成檔案生成瀏覽器下載功能
This commit is contained in:
parent
0b18e4b8ab
commit
e329908d88
51
app.py
51
app.py
@ -1,8 +1,10 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
from flask import Flask, render_template, request, send_file
|
from flask import Flask, render_template, request, send_file
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from datetime import datetime
|
||||||
|
import zipfile
|
||||||
|
import io
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@ -24,6 +26,9 @@ def allowed_file(filename):
|
|||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
|
search_str = 'e771'
|
||||||
|
|
||||||
|
|
||||||
return render_template("index.html")
|
return render_template("index.html")
|
||||||
@app.route("/hello")
|
@app.route("/hello")
|
||||||
def hello():
|
def hello():
|
||||||
@ -38,15 +43,42 @@ def upload_csv():
|
|||||||
if file.filename == '':
|
if file.filename == '':
|
||||||
return "No selected file", 400
|
return "No selected file", 400
|
||||||
if file and allowed_file(file.filename):
|
if file and allowed_file(file.filename):
|
||||||
|
uuid_str = str(uuid.uuid4())[:4]
|
||||||
unique_filename = str(uuid.uuid4()) + '.csv'
|
unique_filename = datetime.now().strftime("%Y%m%d_%H%M")+ '_' + uuid_str
|
||||||
csv_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
|
csv_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename+'.csv')
|
||||||
file.save(csv_path)
|
file.save(csv_path)
|
||||||
print(f"CSV file saved to {csv_path}")
|
print(f"CSV file saved to {csv_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 呼叫外部 Python 腳本來生成圖片
|
subprocess.run([os.path.join(os.getcwd(), '.venv', 'Scripts', 'python'), 'generate_images.py', csv_path, unique_filename ], check=True)
|
||||||
subprocess.run([os.path.join(os.getcwd(), '.venv', 'Scripts', 'python'), 'generate_images.py', csv_path], 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:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"Error generating images: {e}")
|
print(f"Error generating images: {e}")
|
||||||
return "Error generating images", 500
|
return "Error generating images", 500
|
||||||
@ -56,9 +88,8 @@ def upload_csv():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"An unexpected error occurred: {e}")
|
print(f"An unexpected error occurred: {e}")
|
||||||
return "An unexpected error occurred", 500
|
return "An unexpected error occurred", 500
|
||||||
|
|
||||||
|
return "File uploaded successfully", 200
|
||||||
return "File uploaded successfully", 200
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@ -101,7 +101,7 @@ class ImageGenerator(QObject):
|
|||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def generate_images(self, name_csv):
|
def generate_images(self, name_csv, out_filename):
|
||||||
# Placeholder for image generation logic
|
# Placeholder for image generation logic
|
||||||
print("Generating images...1")
|
print("Generating images...1")
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ class ImageGenerator(QObject):
|
|||||||
|
|
||||||
if i > 0 and i % 6 == 5:
|
if i > 0 and i % 6 == 5:
|
||||||
# Save the current scene to an image file every 5 items
|
# 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()
|
self.scene.clear()
|
||||||
|
|
||||||
print("Image generated and added to scene.")
|
print("Image generated and added to scene.")
|
||||||
@ -177,17 +177,19 @@ if __name__ == "__main__":
|
|||||||
generator = ImageGenerator()
|
generator = ImageGenerator()
|
||||||
generator.finished.connect(app.quit)
|
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]
|
csv_file = sys.argv[1]
|
||||||
print(f"Loading CSV file: {csv_file}")
|
out_filename = sys.argv[2]
|
||||||
else:
|
print(f"Loading CSV file: {csv_file}, Output filename: {out_filename}")
|
||||||
csv_file = "resource/sample.csv"
|
|
||||||
print(f"No CSV file provided, using default: {csv_file}")
|
|
||||||
|
|
||||||
sample_data = generator.read_csv(csv_file)
|
sample_data = generator.read_csv(csv_file)
|
||||||
print(f"Sample data loaded: {sample_data}")
|
print(f"Sample data loaded: {sample_data}")
|
||||||
|
|
||||||
generator.generate_images(sample_data)
|
generator.generate_images(sample_data, out_filename)
|
||||||
#generator.start()
|
#generator.start()
|
||||||
|
|
||||||
# Run the application event loop
|
# Run the application event loop
|
||||||
|
|||||||
@ -3,13 +3,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>CSV 轉圖片工具</title>
|
<title>圓形鑰匙圈產生器</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>上傳 CSV 產生圖片</h1>
|
<h1>圓形鑰匙圈產生器</h1>
|
||||||
<form id="uploadForm" enctype="multipart/form-data">
|
<form id="uploadForm" enctype="multipart/form-data">
|
||||||
<input type="file" id="csvFile" name="csvFile" accept=".csv">
|
<input type="file" id="csvFile" name="csvFile" accept=".csv">
|
||||||
<button type="submit">生成圖片</button>
|
<!-- <button type="submit">生成圖片</button> -->
|
||||||
</form>
|
</form>
|
||||||
<div id="status"></div>
|
<div id="status"></div>
|
||||||
<div id="downloadLink" style="display: none;">
|
<div id="downloadLink" style="display: none;">
|
||||||
@ -36,8 +36,13 @@
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('csvFile', fileInput.files[0]);
|
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 {
|
try {
|
||||||
const response = await fetch('/upload_csv', { // 請確保後端路由與此匹配
|
const response = await fetch('/upload_csv', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
@ -47,21 +52,26 @@
|
|||||||
throw new Error(`伺服器錯誤: ${response.status} - ${errorText}`);
|
throw new Error(`伺服器錯誤: ${response.status} - ${errorText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 假設後端會返回圖片的 Blob 或直接是檔案的 URL
|
// 取得 zip blob 並建立下載連結
|
||||||
// 如果後端直接返回圖片檔案,可以直接創建 Blob URL
|
const zipBlob = await response.blob();
|
||||||
const imageBlob = await response.blob();
|
const zipUrl = URL.createObjectURL(zipBlob);
|
||||||
const imageUrl = URL.createObjectURL(imageBlob);
|
|
||||||
|
|
||||||
downloadAnchor.href = imageUrl;
|
downloadAnchor.href = zipUrl;
|
||||||
downloadAnchor.download = 'generated_image.png'; // 可以從後端獲取圖片名稱
|
downloadAnchor.download = `${datetimeStr}_圓形鑰匙產生器.zip`; // zip 檔名加上日期時間
|
||||||
statusDiv.textContent = '圖片已成功生成!';
|
statusDiv.textContent = '圖片已成功生成!請點擊下方連結下載壓縮檔。';
|
||||||
downloadLinkDiv.style.display = 'block';
|
downloadLinkDiv.style.display = 'block';
|
||||||
|
downloadAnchor.click(); // 自動觸發下載
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('上傳或生成圖片失敗:', error);
|
console.error('上傳或生成圖片失敗:', error);
|
||||||
statusDiv.textContent = `生成圖片失敗: ${error.message || '未知錯誤'}`;
|
statusDiv.textContent = `生成圖片失敗: ${error.message || '未知錯誤'}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('csvFile').addEventListener('change', function() {
|
||||||
|
// 自動觸發表單提交
|
||||||
|
document.getElementById('uploadForm').dispatchEvent(new Event('submit', {cancelable: true, bubbles: true}));
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user