First commit
This commit is contained in:
commit
e2b14ca7fe
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
__pycache__/*
|
||||||
|
uploads/*
|
||||||
|
generated/*
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
BIN
_ref/style.png
Normal file
BIN
_ref/style.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
49
app.py
Normal file
49
app.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import uuid
|
||||||
|
from flask import Flask, render_template, request, send_file
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
UPLOAD_FOLDER = 'uploads'
|
||||||
|
GENERATED_IMAGES_FOLDER = 'generated_images'
|
||||||
|
ALLOWED_EXTENSIONS = {'csv'}
|
||||||
|
|
||||||
|
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
||||||
|
app.config['GENERATED_IMAGES_FOLDER'] = GENERATED_IMAGES_FOLDER
|
||||||
|
|
||||||
|
# 確保目錄存在
|
||||||
|
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||||||
|
os.makedirs(GENERATED_IMAGES_FOLDER, exist_ok=True)
|
||||||
|
|
||||||
|
def allowed_file(filename):
|
||||||
|
return '.' in filename and \
|
||||||
|
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
return render_template("index.html")
|
||||||
|
@app.route("/hello")
|
||||||
|
def hello():
|
||||||
|
return "Hello, World!"
|
||||||
|
|
||||||
|
@app.route('/upload_csv', methods=['POST'])
|
||||||
|
def upload_csv():
|
||||||
|
print("Received request to upload CSV file")
|
||||||
|
if 'csvFile' not in request.files:
|
||||||
|
return "No file part", 400
|
||||||
|
file = request.files['csvFile']
|
||||||
|
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)
|
||||||
|
file.save(csv_path)
|
||||||
|
return "File uploaded successfully", 200
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# 當在生產環境部署時,不建議使用 debug=True
|
||||||
|
# 可以指定 host='0.0.0.0' 讓外部可訪問 (在防火牆允許的情況下)
|
||||||
|
app.run(debug=True, host='127.0.0.1', port=5000)
|
||||||
2
generate_images.py
Normal file
2
generate_images.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import sys
|
||||||
|
from PySide6.QtCore import QCoreApplication, QTimer, QObject, Signal, Slot
|
||||||
67
templates/index.html
Normal file
67
templates/index.html
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hant">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>CSV 轉圖片工具</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>上傳 CSV 產生圖片</h1>
|
||||||
|
<form id="uploadForm" enctype="multipart/form-data">
|
||||||
|
<input type="file" id="csvFile" name="csvFile" accept=".csv">
|
||||||
|
<button type="submit">生成圖片</button>
|
||||||
|
</form>
|
||||||
|
<div id="status"></div>
|
||||||
|
<div id="downloadLink" style="display: none;">
|
||||||
|
<a id="downloadAnchor" href="#" download="generated_image.png">點擊下載圖片</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('uploadForm').addEventListener('submit', async function(event) {
|
||||||
|
event.preventDefault(); // 阻止表單預設提交行為
|
||||||
|
|
||||||
|
const fileInput = document.getElementById('csvFile');
|
||||||
|
const statusDiv = document.getElementById('status');
|
||||||
|
const downloadLinkDiv = document.getElementById('downloadLink');
|
||||||
|
const downloadAnchor = document.getElementById('downloadAnchor');
|
||||||
|
|
||||||
|
if (!fileInput.files.length) {
|
||||||
|
statusDiv.textContent = '請選擇一個 CSV 檔案。';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
statusDiv.textContent = '檔案上傳中,請稍候...';
|
||||||
|
downloadLinkDiv.style.display = 'none';
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('csvFile', fileInput.files[0]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/upload_csv', { // 請確保後端路由與此匹配
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
throw new Error(`伺服器錯誤: ${response.status} - ${errorText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 假設後端會返回圖片的 Blob 或直接是檔案的 URL
|
||||||
|
// 如果後端直接返回圖片檔案,可以直接創建 Blob URL
|
||||||
|
const imageBlob = await response.blob();
|
||||||
|
const imageUrl = URL.createObjectURL(imageBlob);
|
||||||
|
|
||||||
|
downloadAnchor.href = imageUrl;
|
||||||
|
downloadAnchor.download = 'generated_image.png'; // 可以從後端獲取圖片名稱
|
||||||
|
statusDiv.textContent = '圖片已成功生成!';
|
||||||
|
downloadLinkDiv.style.display = 'block';
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('上傳或生成圖片失敗:', error);
|
||||||
|
statusDiv.textContent = `生成圖片失敗: ${error.message || '未知錯誤'}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
63
架構圖.drawio
Normal file
63
架構圖.drawio
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/27.0.9 Chrome/134.0.6998.205 Electron/35.4.0 Safari/537.36" version="27.0.9">
|
||||||
|
<diagram name="第 1 页" id="l6rvUWkf71IvbISpAjO9">
|
||||||
|
<mxGraphModel dx="788" dy="477" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="T8w4GiLeSybUu9a6AjsZ-1" target="T8w4GiLeSybUu9a6AjsZ-3">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-1" value="index.html" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="90" y="190" width="100" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-2" value="" style="endArrow=none;dashed=1;html=1;rounded=0;strokeWidth=3;" edge="1" parent="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="240" y="400" as="sourcePoint" />
|
||||||
|
<mxPoint x="240" y="90" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="T8w4GiLeSybUu9a6AjsZ-3" target="T8w4GiLeSybUu9a6AjsZ-4">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="T8w4GiLeSybUu9a6AjsZ-3" target="T8w4GiLeSybUu9a6AjsZ-1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-3" value="Flask" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="300" y="190" width="100" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="T8w4GiLeSybUu9a6AjsZ-4">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="580" y="290" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-4" value="圓形鑰匙圈產生器" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="530" y="190" width="100" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-5" value="前端" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="110" y="110" width="60" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-6" value="後端" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="320" y="110" width="60" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-9" value="POST" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="240" y="190" width="60" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-11" value="run python" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="420" y="190" width="70" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="T8w4GiLeSybUu9a6AjsZ-13" target="T8w4GiLeSybUu9a6AjsZ-3">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-13" value="圖片產生至某個資料夾" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="530" y="290" width="100" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-15" value="Send File" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="240" y="230" width="60" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="T8w4GiLeSybUu9a6AjsZ-17" value="Load Pictures form image folder" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="430" y="320" width="100" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
Loading…
x
Reference in New Issue
Block a user