Spaces:
Sleeping
Sleeping
Commit ·
198ccdc
1
Parent(s): 08adec3
fix: internal server error, add default data, optimize layout
Browse files- __pycache__/app.cpython-314.pyc +0 -0
- app.py +11 -5
- templates/index.html +60 -14
__pycache__/app.cpython-314.pyc
ADDED
|
Binary file (1.21 kB). View file
|
|
|
app.py
CHANGED
|
@@ -1,15 +1,21 @@
|
|
| 1 |
-
from flask import Flask, render_template, send_from_directory
|
| 2 |
import os
|
| 3 |
|
| 4 |
app = Flask(__name__, static_folder='static')
|
| 5 |
|
| 6 |
@app.route('/')
|
| 7 |
def index():
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
-
@app.route('/
|
| 11 |
-
def
|
| 12 |
-
return
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
if __name__ == '__main__':
|
| 15 |
port = int(os.environ.get('PORT', 7860))
|
|
|
|
| 1 |
+
from flask import Flask, render_template, send_from_directory, jsonify
|
| 2 |
import os
|
| 3 |
|
| 4 |
app = Flask(__name__, static_folder='static')
|
| 5 |
|
| 6 |
@app.route('/')
|
| 7 |
def index():
|
| 8 |
+
try:
|
| 9 |
+
return render_template('index.html')
|
| 10 |
+
except Exception as e:
|
| 11 |
+
return f"An error occurred: {str(e)}", 500
|
| 12 |
|
| 13 |
+
@app.route('/health')
|
| 14 |
+
def health():
|
| 15 |
+
return jsonify({"status": "healthy"}), 200
|
| 16 |
+
|
| 17 |
+
# Flask serves static files automatically from the 'static' folder
|
| 18 |
+
# at the /static endpoint. No need for a manual route unless customizing.
|
| 19 |
|
| 20 |
if __name__ == '__main__':
|
| 21 |
port = int(os.environ.get('PORT', 7860))
|
templates/index.html
CHANGED
|
@@ -14,23 +14,30 @@
|
|
| 14 |
.slide-enter-active, .slide-leave-active { transition: all 0.3s ease; }
|
| 15 |
.slide-enter-from, .slide-leave-to { opacity: 0; transform: translateY(10px); }
|
| 16 |
.canvas-grid {
|
| 17 |
-
display:
|
| 18 |
-
|
| 19 |
-
grid-template-rows: repeat(3, minmax(200px, auto));
|
| 20 |
gap: 1px;
|
| 21 |
background-color: #e2e8f0;
|
| 22 |
border: 1px solid #e2e8f0;
|
| 23 |
}
|
| 24 |
-
.canvas-cell { background: white; padding: 1rem; display: flex; flex-direction: column; }
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
</style>
|
| 35 |
</head>
|
| 36 |
<body>
|
|
@@ -259,6 +266,34 @@
|
|
| 259 |
createApp({
|
| 260 |
components: { CanvasCell },
|
| 261 |
setup() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
const projects = ref([]);
|
| 263 |
const currentProject = ref(null);
|
| 264 |
const currentTab = ref('concept');
|
|
@@ -333,7 +368,18 @@
|
|
| 333 |
const load = () => {
|
| 334 |
const data = localStorage.getItem('idea-validator-pro-data');
|
| 335 |
if (data) {
|
| 336 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
}
|
| 338 |
};
|
| 339 |
|
|
|
|
| 14 |
.slide-enter-active, .slide-leave-active { transition: all 0.3s ease; }
|
| 15 |
.slide-enter-from, .slide-leave-to { opacity: 0; transform: translateY(10px); }
|
| 16 |
.canvas-grid {
|
| 17 |
+
display: flex;
|
| 18 |
+
flex-direction: column;
|
|
|
|
| 19 |
gap: 1px;
|
| 20 |
background-color: #e2e8f0;
|
| 21 |
border: 1px solid #e2e8f0;
|
| 22 |
}
|
| 23 |
+
.canvas-cell { background: white; padding: 1rem; display: flex; flex-direction: column; min-height: 200px; }
|
| 24 |
+
|
| 25 |
+
@media (min-width: 1024px) {
|
| 26 |
+
.canvas-grid {
|
| 27 |
+
display: grid;
|
| 28 |
+
grid-template-columns: repeat(5, 1fr);
|
| 29 |
+
grid-template-rows: repeat(3, minmax(200px, auto));
|
| 30 |
+
}
|
| 31 |
+
.cell-problem { grid-area: 1 / 1 / 3 / 2; }
|
| 32 |
+
.cell-solution { grid-area: 1 / 2 / 2 / 3; }
|
| 33 |
+
.cell-metrics { grid-area: 2 / 2 / 3 / 3; }
|
| 34 |
+
.cell-uvp { grid-area: 1 / 3 / 3 / 4; }
|
| 35 |
+
.cell-advantage { grid-area: 1 / 4 / 2 / 5; }
|
| 36 |
+
.cell-channels { grid-area: 2 / 4 / 3 / 5; }
|
| 37 |
+
.cell-segments { grid-area: 1 / 5 / 3 / 6; }
|
| 38 |
+
.cell-cost { grid-area: 3 / 1 / 4 / 3; }
|
| 39 |
+
.cell-revenue { grid-area: 3 / 3 / 4 / 6; }
|
| 40 |
+
}
|
| 41 |
</style>
|
| 42 |
</head>
|
| 43 |
<body>
|
|
|
|
| 266 |
createApp({
|
| 267 |
components: { CanvasCell },
|
| 268 |
setup() {
|
| 269 |
+
const DEFAULT_PROJECT = {
|
| 270 |
+
id: 'demo-1',
|
| 271 |
+
title: '智能周报生成器 (示例)',
|
| 272 |
+
pitch: '帮助程序员从繁琐的周报中解脱出来,自动从代码提交记录生成高质量周报。',
|
| 273 |
+
who: '互联网公司的程序员、技术经理',
|
| 274 |
+
why: '每周五写周报很痛苦,容易遗漏工作内容,且浪费开发时间。',
|
| 275 |
+
updatedAt: new Date(),
|
| 276 |
+
canvas: {
|
| 277 |
+
problem: ['写周报浪费时间', '容易遗漏工作内容', '格式不统一,主管难以阅读'],
|
| 278 |
+
solution: ['自动读取 Git Commit', 'AI 润色生成自然语言', '支持导出为 Markdown/PDF'],
|
| 279 |
+
metrics: ['周报生成时间从30分钟降至2分钟', '用户留存率'],
|
| 280 |
+
uvp: ['一键生成', '智能润色', '多平台集成 (Jira/GitHub)'],
|
| 281 |
+
advantage: ['先发优势', '高质量的 AI Prompt 库'],
|
| 282 |
+
channels: ['技术博客', 'GitHub Trending', '技术社区 (掘金/V2EX)'],
|
| 283 |
+
segments: ['中大型互联网公司开发团队', '个人开发者'],
|
| 284 |
+
cost: ['OpenAI API 费用', '服务器运维成本'],
|
| 285 |
+
revenue: ['个人版免费', '团队版 $5/人/月']
|
| 286 |
+
},
|
| 287 |
+
experiments: [
|
| 288 |
+
{
|
| 289 |
+
hypothesis: '如果我在 V2EX 发布产品介绍,会有至少 50 人注册试用。',
|
| 290 |
+
method: '撰写一篇详细的软文,介绍产品痛点和解决方案,发布到 V2EX 创造节点。',
|
| 291 |
+
result: '获得了 120 个注册用户,但只有 10% 留存。',
|
| 292 |
+
status: 'success'
|
| 293 |
+
}
|
| 294 |
+
]
|
| 295 |
+
};
|
| 296 |
+
|
| 297 |
const projects = ref([]);
|
| 298 |
const currentProject = ref(null);
|
| 299 |
const currentTab = ref('concept');
|
|
|
|
| 368 |
const load = () => {
|
| 369 |
const data = localStorage.getItem('idea-validator-pro-data');
|
| 370 |
if (data) {
|
| 371 |
+
try {
|
| 372 |
+
projects.value = JSON.parse(data);
|
| 373 |
+
} catch(e) {
|
| 374 |
+
console.error("Data parse error", e);
|
| 375 |
+
projects.value = [];
|
| 376 |
+
}
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
if (projects.value.length === 0) {
|
| 380 |
+
// 使用 JSON.parse(JSON.stringify(...)) 深拷贝,避免引用问题
|
| 381 |
+
projects.value = [JSON.parse(JSON.stringify(DEFAULT_PROJECT))];
|
| 382 |
+
save();
|
| 383 |
}
|
| 384 |
};
|
| 385 |
|