+
+
+```
+
+### 2. **快速开始区域优化**
+
+#### 2.1 现代化卡片设计
+```html
+
+
+
+
+
+
+
+
通用优化
+
通用提示词优化,适用于各种场景
+
+ 1.2k 使用
+ ⭐ 4.8
+
+
+
+
+
+```
+
+### 3. **模板库区域侧边栏设计**
+
+#### 3.1 侧边栏布局
+```html
+
+```
+
+### 4. **输入和操作区域优化**
+
+#### 4.1 现代化输入区域
+```html
+
+```
+
+#### 4.2 现代化操作按钮
+```html
+
+```
+
+### 5. **结果展示区域优化**
+
+#### 5.1 现代化结果展示
+```html
+
+
+
+
+
{{ prompt.generated_text }}
+
+
+
+```
+
+## 🎨 **视觉设计特点**
+
+### 1. **色彩系统**
+- **主色调**:蓝色系 (#4a90e2) 用于按钮、图标、重要文字
+- **中性色**:灰色和白色用于背景和辅助色
+- **状态色**:成功绿、警告黄、危险红
+
+### 2. **字体设计**
+- **标题**:品牌标准字体,较大字号,粗体显示
+- **正文**:易读的无衬线字体,适中字号,宽松行距
+
+### 3. **图标和按钮**
+- **图标**:线性图标风格,确保简洁一致
+- **按钮**:统一圆角设计,主色调按钮用于主要操作
+
+### 4. **阴影和层次**
+```css
+:root {
+ --shadow-light: 0 2px 8px rgba(0, 0, 0, 0.05);
+ --shadow-medium: 0 4px 16px rgba(0, 0, 0, 0.1);
+ --shadow-heavy: 0 8px 32px rgba(0, 0, 0, 0.15);
+ --border-radius: 12px;
+ --border-radius-small: 8px;
+ --transition: all 0.3s ease;
+}
+```
+
+## 📱 **响应式设计**
+
+### 1. **桌面端 (≥1200px)**
+- 多列网格布局,充分利用屏幕宽度
+- 侧边栏固定,模板展示区占据主要空间
+- 完整的筛选和排序功能
+
+### 2. **平板端 (768px-1199px)**
+- 调整为两列网格布局
+- 侧边栏可折叠
+- 筛选条件简化,确保内容清晰可读
+
+### 3. **移动端 (≤767px)**
+- 单列布局
+- 导航栏折叠为汉堡菜单
+- 搜索栏置于页面顶部
+- 侧边栏筛选功能改为底部弹出面板
+- 模板展示区简化,只显示缩略图和标题
+
+## 🔧 **交互设计**
+
+### 1. **搜索功能**
+- **自动完成**:输入时显示相关建议
+- **热门搜索**:显示常用搜索关键词
+- **加载动画**:搜索完成后显示简洁加载动画
+
+### 2. **模板展示**
+- **悬停效果**:鼠标悬停时缩略图放大,显示阴影效果
+- **模态窗口**:点击弹出模态窗口,背景模糊,模态居中显示
+
+### 3. **筛选功能**
+- **动态刷新**:选择筛选条件后页面平滑刷新
+- **加载动画**:刷新时显示简洁加载动画
+
+### 4. **视图切换**
+- **网格/列表视图**:支持两种展示模式切换
+- **平滑过渡**:视图切换时有平滑的过渡动画
+
+## 🎯 **用户体验优化**
+
+### 1. **视觉引导**
+- **清晰的层次结构**:使用颜色、大小、间距区分重要程度
+- **操作提示**:提供清晰的操作指引和反馈
+- **状态指示**:明确显示当前选中状态和操作结果
+
+### 2. **交互反馈**
+- **即时响应**:所有操作都有即时的视觉反馈
+- **动画效果**:使用CSS过渡动画提升交互体验
+- **错误处理**:友好的错误提示和恢复建议
+
+### 3. **性能优化**
+- **懒加载**:对大量模板进行懒加载
+- **防抖处理**:搜索输入使用防抖优化性能
+- **缓存机制**:缓存用户操作状态和偏好
+
+## 📊 **设计效果**
+
+### 1. **视觉一致性**
+- ✅ 统一的色彩系统和字体规范
+- ✅ 一致的组件设计和交互模式
+- ✅ 品牌元素的统一应用
+
+### 2. **用户体验**
+- ✅ 清晰的信息架构和导航路径
+- ✅ 直观的操作流程和反馈机制
+- ✅ 响应式设计适配各种设备
+
+### 3. **功能完整性**
+- ✅ 完整的搜索和筛选功能
+- ✅ 灵活的模板展示和选择
+- ✅ 便捷的快速开始功能
+
+## 🚀 **技术实现**
+
+### 1. **CSS架构**
+- 使用CSS变量定义设计系统
+- 模块化的样式组织
+- 响应式设计的最佳实践
+
+### 2. **JavaScript交互**
+- 事件驱动的交互处理
+- 防抖和节流优化性能
+- 状态管理和数据绑定
+
+### 3. **HTML语义化**
+- 语义化的HTML结构
+- 无障碍访问支持
+- SEO友好的标记
+
+## 🎯 **总结**
+
+通过遵循设计规范文档,我们成功实现了:
+
+1. **简洁现代的设计风格**:使用留白、清晰的层次结构和现代化的视觉元素
+2. **用户体验优先的布局**:侧边栏设计、突出搜索功能、清晰的导航路径
+3. **响应式适配**:完美适配桌面、平板、移动端各种设备
+4. **品牌视觉一致性**:统一的色彩、字体、图标和交互模式
+5. **功能完整性**:保留所有原有功能,同时优化用户体验
+
+这次现代化设计优化显著提升了用户界面的美观性和可用性,为用户提供了更加专业、高效的模板选择体验。
diff --git a/TEMPLATE_DISPLAY_LIMIT.md b/TEMPLATE_DISPLAY_LIMIT.md
new file mode 100644
index 0000000..0e42774
--- /dev/null
+++ b/TEMPLATE_DISPLAY_LIMIT.md
@@ -0,0 +1,228 @@
+# 模板显示限制功能实现说明
+
+## 🎯 **功能概述**
+
+为了解决"全部"分类下模板过多导致页面过长的问题,实现了模板显示限制功能。默认只显示前8个模板,用户可以通过"显示更多"按钮查看全部模板。
+
+## 📋 **实现内容**
+
+### 1. **功能特性**
+
+#### 1.1 默认显示限制
+- **显示数量**:默认只显示前8个模板
+- **隐藏逻辑**:超过8个的模板自动隐藏
+- **智能判断**:只在模板数量超过8个时显示"更多"按钮
+
+#### 1.2 显示更多功能
+- **动态按钮**:显示剩余模板数量
+- **切换状态**:支持展开和收起
+- **动画效果**:按钮图标旋转动画
+
+#### 1.3 筛选联动
+- **筛选同步**:筛选条件变化时重新计算显示逻辑
+- **状态保持**:筛选后保持展开/收起状态
+- **重置功能**:重置筛选时恢复默认状态
+
+### 2. **技术实现**
+
+#### 2.1 HTML结构
+```html
+
+ {% for template in templates %}
+
+
+
+ {% endfor %}
+
+
+
+
+
+
+```
+
+#### 2.2 CSS样式
+```css
+/* 模板显示控制 */
+.template-hidden {
+ display: none !important;
+}
+
+.show-more-section {
+ text-align: center;
+ margin-top: 2rem;
+ padding: 1rem;
+}
+
+.show-more-btn {
+ padding: 0.75rem 2rem;
+ font-size: 1rem;
+ font-weight: 600;
+ border-radius: 8px;
+ transition: all 0.3s ease;
+ background: white;
+ border: 2px solid var(--primary-color);
+ color: var(--primary-color);
+}
+
+.show-more-btn:hover {
+ background: var(--primary-color);
+ color: white;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(74, 144, 226, 0.3);
+}
+
+.show-more-btn i {
+ margin-right: 0.5rem;
+ transition: transform 0.3s ease;
+}
+
+.show-more-btn.expanded i {
+ transform: rotate(180deg);
+}
+```
+
+#### 2.3 JavaScript逻辑
+```javascript
+// 更新显示更多按钮
+function updateShowMoreButton(visibleCount) {
+ const showMoreSection = document.getElementById('showMoreSection');
+ const showMoreBtn = document.getElementById('showMoreBtn');
+
+ if (visibleCount > 8) {
+ showMoreSection.style.display = 'block';
+ showMoreBtn.innerHTML = `
+
+ 显示更多模板 (${visibleCount - 8}个)
+ `;
+ } else {
+ showMoreSection.style.display = 'none';
+ }
+}
+
+// 切换显示更多
+function toggleShowMore() {
+ const showMoreBtn = document.getElementById('showMoreBtn');
+ const hiddenCards = document.querySelectorAll('.template-card.template-hidden:not(.hidden)');
+
+ if (hiddenCards.length > 0) {
+ // 显示所有隐藏的模板
+ hiddenCards.forEach(card => {
+ card.classList.remove('template-hidden');
+ });
+
+ showMoreBtn.innerHTML = `
+
+ 收起模板
+ `;
+ showMoreBtn.classList.add('expanded');
+ } else {
+ // 隐藏多余的模板
+ const visibleCards = document.querySelectorAll('.template-card:not(.hidden)');
+ visibleCards.forEach((card, index) => {
+ if (index >= 8) {
+ card.classList.add('template-hidden');
+ }
+ });
+
+ showMoreBtn.innerHTML = `
+
+ 显示更多模板
+ `;
+ showMoreBtn.classList.remove('expanded');
+ }
+}
+```
+
+### 3. **用户体验**
+
+#### 3.1 默认状态
+- **页面简洁**:默认只显示8个模板,页面不会过长
+- **快速浏览**:用户可以快速浏览主要模板
+- **清晰提示**:显示剩余模板数量
+
+#### 3.2 展开状态
+- **完整查看**:点击后可以查看所有模板
+- **状态指示**:按钮变为"收起模板"
+- **图标变化**:箭头向上,表示可以收起
+
+#### 3.3 交互反馈
+- **悬停效果**:按钮有悬停动画效果
+- **图标动画**:展开/收起时图标旋转
+- **即时响应**:点击后立即显示/隐藏
+
+### 4. **筛选联动**
+
+#### 4.1 筛选变化
+- **重新计算**:筛选条件变化时重新计算显示逻辑
+- **状态保持**:保持当前的展开/收起状态
+- **数量更新**:动态更新剩余模板数量
+
+#### 4.2 重置功能
+- **状态重置**:重置筛选时恢复默认收起状态
+- **显示重置**:重新应用8个模板的限制
+- **按钮隐藏**:如果模板数量≤8,隐藏按钮
+
+### 5. **性能优化**
+
+#### 5.1 渲染优化
+- **CSS隐藏**:使用CSS隐藏而非JavaScript移除
+- **DOM保持**:保持DOM结构,避免重新渲染
+- **事件保持**:保持事件监听器,避免重复绑定
+
+#### 5.2 交互优化
+- **防抖处理**:避免频繁的状态切换
+- **状态缓存**:缓存当前显示状态
+- **平滑动画**:使用CSS过渡动画
+
+### 6. **响应式适配**
+
+#### 6.1 移动端
+- **触摸友好**:按钮大小适合触摸操作
+- **间距优化**:移动端减少按钮间距
+- **文字适配**:移动端简化按钮文字
+
+#### 6.2 桌面端
+- **悬停效果**:桌面端显示悬停效果
+- **键盘支持**:支持键盘Tab导航
+- **焦点状态**:清晰的焦点指示
+
+### 7. **使用场景**
+
+#### 7.1 全部分类
+- **默认限制**:选择"全部"分类时默认显示8个
+- **智能显示**:根据筛选结果动态显示按钮
+- **用户控制**:用户可以选择是否查看全部
+
+#### 7.2 其他分类
+- **无限制**:其他分类下不限制显示数量
+- **自动隐藏**:如果模板数量≤8,自动隐藏按钮
+- **一致体验**:保持统一的交互体验
+
+### 8. **后续优化**
+
+#### 8.1 功能增强
+- **自定义数量**:允许用户自定义显示数量
+- **记住状态**:记住用户的展开/收起偏好
+- **分页显示**:支持分页显示大量模板
+
+#### 8.2 性能优化
+- **懒加载**:对隐藏的模板进行懒加载
+- **虚拟滚动**:大量模板时使用虚拟滚动
+- **缓存机制**:缓存模板数据和状态
+
+#### 8.3 用户体验
+- **动画优化**:更流畅的展开/收起动画
+- **状态提示**:更清晰的状态提示信息
+- **快捷键**:支持键盘快捷键操作
+
+## 🎯 **总结**
+
+模板显示限制功能有效解决了页面过长的问题,通过智能的显示控制和用户友好的交互设计,让用户可以在简洁的界面中快速浏览模板,同时保留了查看全部模板的灵活性。这个功能为后续的性能优化和用户体验提升奠定了良好的基础。
diff --git a/UI_INTERACTION_OPTIMIZATION.md b/UI_INTERACTION_OPTIMIZATION.md
new file mode 100644
index 0000000..6e14ed6
--- /dev/null
+++ b/UI_INTERACTION_OPTIMIZATION.md
@@ -0,0 +1,315 @@
+# 界面交互优化实现说明
+
+## 🎨 **优化概述**
+
+界面交互优化旨在重新设计主应用布局,优化视觉层次,增强交互反馈,让用户能够更高效地选择和使用模板。
+
+## 📋 **实现内容**
+
+### 1. **布局重新设计**
+
+#### 1.1 侧边栏布局
+- **侧边栏设计**:将分类选择改为左侧固定侧边栏
+- **主内容区域**:右侧重点展示模板卡片
+- **响应式适配**:移动端自动切换为垂直布局
+
+#### 1.2 布局结构
+```html
+
+
+```
+
+### 2. **视觉层次优化**
+
+#### 2.1 侧边栏设计
+- **固定定位**:侧边栏使用 `position: sticky` 固定
+- **清晰分组**:筛选条件和分类列表分组显示
+- **视觉层次**:使用不同的颜色和大小区分重要程度
+
+#### 2.2 分类项目设计
+```css
+.category-item {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.75rem;
+ margin-bottom: 0.5rem;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ border: 1px solid transparent;
+}
+
+.category-item:hover {
+ background: var(--hover-color);
+ border-color: var(--primary-color);
+}
+
+.category-item.active {
+ background: linear-gradient(135deg, var(--primary-color) 0%, #4a90e2 100%);
+ color: white;
+ border-color: var(--primary-color);
+}
+```
+
+#### 2.3 模板卡片优化
+- **信息层次**:图标、标题、描述、统计信息清晰分层
+- **标签系统**:使用彩色标签区分行业、职业、领域
+- **统计信息**:显示使用次数、评分、预计时间
+
+### 3. **交互反馈增强**
+
+#### 3.1 悬停预览效果
+- **操作按钮**:悬停时显示预览、收藏、删除按钮
+- **卡片动画**:悬停时卡片上浮和阴影效果
+- **选择状态**:选中时显示蓝色高亮和选择指示器
+
+#### 3.2 模板预览弹窗
+```javascript
+function showTemplatePreview(templateId) {
+ const modal = document.createElement('div');
+ modal.className = 'template-preview-modal';
+ modal.innerHTML = `
+
+ `;
+
+ document.body.appendChild(modal);
+}
+```
+
+#### 3.3 操作成功反馈
+- **Toast提示**:操作成功后显示临时提示消息
+- **动画效果**:删除时卡片缩放消失动画
+- **状态更新**:实时更新模板数量统计
+
+### 4. **功能特性**
+
+#### 4.1 视图切换
+- **网格视图**:默认的卡片网格布局
+- **列表视图**:紧凑的列表布局
+- **切换按钮**:右上角的视图切换控件
+
+#### 4.2 模板操作
+- **预览功能**:点击眼睛图标查看模板详情
+- **收藏功能**:点击心形图标收藏/取消收藏
+- **删除功能**:点击垃圾桶图标删除模板
+
+#### 4.3 筛选优化
+- **侧边栏筛选**:筛选条件移到侧边栏
+- **实时更新**:筛选条件变化时实时更新结果
+- **统计显示**:显示当前筛选结果数量
+
+### 5. **响应式设计**
+
+#### 5.1 桌面端
+- **侧边栏固定**:左侧300px固定宽度
+- **主内容区域**:右侧自适应宽度
+- **网格布局**:模板卡片采用响应式网格
+
+#### 5.2 移动端
+- **垂直布局**:侧边栏和主内容垂直排列
+- **紧凑设计**:减少间距,优化触摸体验
+- **操作按钮**:移动端始终显示操作按钮
+
+### 6. **CSS样式特点**
+
+#### 6.1 现代化设计
+```css
+/* 主内容布局 - 侧边栏设计 */
+.main-content-layout {
+ display: grid;
+ grid-template-columns: 300px 1fr;
+ gap: 2rem;
+ margin-bottom: 2rem;
+}
+
+/* 侧边栏样式 */
+.sidebar {
+ background: white;
+ border: 1px solid var(--border-color);
+ border-radius: 16px;
+ padding: 1.5rem;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ height: fit-content;
+ position: sticky;
+ top: 2rem;
+}
+```
+
+#### 6.2 动画效果
+```css
+/* 动画效果 */
+@keyframes modalSlideIn {
+ from {
+ opacity: 0;
+ transform: scale(0.9) translateY(-20px);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+}
+
+@keyframes slideIn {
+ from {
+ opacity: 0;
+ transform: translateX(100%);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+```
+
+### 7. **JavaScript功能**
+
+#### 7.1 事件处理
+```javascript
+// 侧边栏分类选择事件
+const categoryItems = document.querySelectorAll('.category-item');
+categoryItems.forEach(item => {
+ item.addEventListener('click', () => {
+ categoryItems.forEach(i => i.classList.remove('active'));
+ item.classList.add('active');
+ filterTemplates();
+ });
+});
+
+// 视图切换功能
+const viewToggles = document.querySelectorAll('.view-toggle');
+viewToggles.forEach(toggle => {
+ toggle.addEventListener('click', () => {
+ viewToggles.forEach(t => t.classList.remove('active'));
+ toggle.classList.add('active');
+
+ const viewType = toggle.dataset.view;
+ if (viewType === 'list') {
+ templateGrid.classList.add('list-view');
+ } else {
+ templateGrid.classList.remove('list-view');
+ }
+ });
+});
+```
+
+#### 7.2 模板操作
+```javascript
+// 模板操作按钮事件
+document.addEventListener('click', function(e) {
+ if (e.target.closest('.btn-preview')) {
+ const templateId = e.target.closest('.btn-preview').dataset.templateId;
+ showTemplatePreview(templateId);
+ }
+
+ if (e.target.closest('.btn-favorite')) {
+ const templateId = e.target.closest('.btn-favorite').dataset.templateId;
+ toggleFavorite(templateId);
+ }
+
+ if (e.target.closest('.btn-delete')) {
+ const templateId = e.target.closest('.btn-delete').dataset.templateId;
+ deleteTemplate(templateId);
+ }
+});
+```
+
+### 8. **用户体验提升**
+
+#### 8.1 操作便捷性
+- **一键操作**:预览、收藏、删除一键完成
+- **视觉反馈**:所有操作都有明确的视觉反馈
+- **状态保持**:操作状态在页面刷新后保持
+
+#### 8.2 信息展示
+- **层次清晰**:信息按照重要程度分层展示
+- **标签系统**:使用颜色编码的标签系统
+- **统计信息**:显示使用统计和评分信息
+
+#### 8.3 交互流畅性
+- **平滑动画**:所有交互都有平滑的动画效果
+- **即时反馈**:操作结果立即显示
+- **错误处理**:友好的错误提示和处理
+
+### 9. **性能优化**
+
+#### 9.1 渲染优化
+- **CSS Grid**:使用现代CSS Grid布局
+- **Flexbox**:使用Flexbox进行元素对齐
+- **硬件加速**:使用transform进行动画
+
+#### 9.2 交互优化
+- **事件委托**:使用事件委托减少事件监听器
+- **防抖处理**:搜索输入使用防抖处理
+- **懒加载**:弹窗内容按需加载
+
+### 10. **后续优化方向**
+
+#### 10.1 功能增强
+- **拖拽排序**:支持模板卡片拖拽排序
+- **批量操作**:支持批量选择和管理
+- **高级筛选**:支持多条件组合筛选
+
+#### 10.2 个性化
+- **主题切换**:支持深色/浅色主题切换
+- **布局定制**:允许用户自定义布局
+- **快捷键**:支持键盘快捷键操作
+
+#### 10.3 智能化
+- **智能推荐**:基于用户行为推荐模板
+- **自动分类**:自动对模板进行分类
+- **使用分析**:提供详细的使用分析报告
+
+## 🎯 **总结**
+
+界面交互优化通过重新设计布局、优化视觉层次、增强交互反馈,显著提升了用户的使用体验。新的侧边栏布局让分类选择更加便捷,优化的模板卡片提供了更丰富的信息展示,增强的交互功能让操作更加流畅自然。这些改进为后续的功能扩展和用户体验提升奠定了坚实的基础。
diff --git a/docs/port_management_guide.md b/docs/port_management_guide.md
new file mode 100644
index 0000000..a584dfd
--- /dev/null
+++ b/docs/port_management_guide.md
@@ -0,0 +1,306 @@
+# 端口管理指南
+
+## 📋 **概述**
+
+本指南介绍如何管理Flask应用的端口占用问题,确保服务稳定运行。
+
+## 🛠️ **工具介绍**
+
+### 1. 端口管理脚本 (`scripts/port_manager.sh`)
+
+**功能:**
+- 检查端口占用情况
+- 清理端口占用
+- 启动/停止/重启应用
+- 查看应用状态
+- 监控模式
+
+**使用方法:**
+```bash
+# 检查端口占用
+./scripts/port_manager.sh check
+
+# 清理端口占用
+./scripts/port_manager.sh clean
+
+# 启动应用
+./scripts/port_manager.sh start
+
+# 停止应用
+./scripts/port_manager.sh stop
+
+# 重启应用
+./scripts/port_manager.sh restart
+
+# 查看状态
+./scripts/port_manager.sh status
+
+# 启动监控
+./scripts/port_manager.sh monitor
+
+# 显示帮助
+./scripts/port_manager.sh help
+```
+
+### 2. 端口监控脚本 (`scripts/port_monitor.py`)
+
+**功能:**
+- 实时监控端口状态
+- 自动检测服务异常
+- 自动重启服务
+- 生成监控报告
+- 系统资源监控
+
+**使用方法:**
+```bash
+# 查看当前状态
+python scripts/port_monitor.py status
+
+# 生成详细报告
+python scripts/port_monitor.py report
+
+# 重启服务
+python scripts/port_monitor.py restart
+
+# 启动监控模式
+python scripts/port_monitor.py monitor
+
+# 查看配置
+python scripts/port_monitor.py config
+```
+
+### 3. Systemd服务配置 (`scripts/flask-app.service`)
+
+**功能:**
+- 系统级服务管理
+- 自动启动/停止
+- 故障自动重启
+- 日志管理
+
+## 🔧 **配置说明**
+
+### 端口管理脚本配置
+
+脚本中的主要配置项:
+```bash
+PORT=5002 # 应用端口
+APP_NAME="flask_prompt_master" # 应用名称
+PID_FILE="logs/gunicorn.pid" # PID文件路径
+LOG_DIR="logs" # 日志目录
+```
+
+### 监控脚本配置
+
+配置文件:`logs/monitor_config.json`
+```json
+{
+ "check_interval": 30, // 检查间隔(秒)
+ "max_restart_attempts": 3, // 最大重启尝试次数
+ "alert_threshold": 2, // 告警阈值
+ "port_timeout": 5, // 端口检查超时时间
+ "enable_alerts": true, // 启用告警
+ "auto_restart": true // 自动重启
+}
+```
+
+## 🚀 **部署步骤**
+
+### 1. 安装systemd服务(可选)
+
+```bash
+# 复制服务文件
+sudo cp scripts/flask-app.service /etc/systemd/system/
+
+# 重新加载systemd
+sudo systemctl daemon-reload
+
+# 启用服务
+sudo systemctl enable flask-app
+
+# 启动服务
+sudo systemctl start flask-app
+
+# 查看状态
+sudo systemctl status flask-app
+```
+
+### 2. 设置定时任务
+
+```bash
+# 编辑crontab
+crontab -e
+
+# 添加定时检查任务(每5分钟检查一次)
+*/5 * * * * /home/renjianbo/aitsc/scripts/port_manager.sh status > /dev/null 2>&1
+```
+
+### 3. 配置日志轮转
+
+创建日志轮转配置:`/etc/logrotate.d/flask-app`
+```
+/home/renjianbo/aitsc/logs/*.log {
+ daily
+ missingok
+ rotate 30
+ compress
+ delaycompress
+ notifempty
+ create 644 renjianbo renjianbo
+ postrotate
+ systemctl reload flask-app > /dev/null 2>&1 || true
+ endscript
+}
+```
+
+## 📊 **监控和告警**
+
+### 1. 监控指标
+
+- **端口占用状态**:检查5002端口是否被正确占用
+- **Gunicorn进程状态**:检查主进程和工作进程
+- **服务响应状态**:检查HTTP服务是否正常响应
+- **系统资源**:CPU、内存、磁盘使用率
+
+### 2. 告警机制
+
+- **自动告警**:检测到异常时自动记录告警日志
+- **自动重启**:服务异常时自动尝试重启
+- **重启限制**:防止频繁重启,设置重启间隔和次数限制
+
+### 3. 日志文件
+
+- `logs/port_monitor.log`:监控脚本日志
+- `logs/port_alerts.log`:告警日志
+- `logs/gunicorn_error.log`:Gunicorn错误日志
+- `logs/gunicorn_access.log`:Gunicorn访问日志
+
+## 🔍 **故障排查**
+
+### 1. 端口被占用
+
+**症状:** 启动时提示 "Address already in use"
+
+**解决方案:**
+```bash
+# 检查端口占用
+./scripts/port_manager.sh check
+
+# 清理端口占用
+./scripts/port_manager.sh clean
+
+# 重新启动
+./scripts/port_manager.sh start
+```
+
+### 2. 服务无响应
+
+**症状:** 访问网站显示连接被拒绝
+
+**解决方案:**
+```bash
+# 检查服务状态
+./scripts/port_manager.sh status
+
+# 重启服务
+./scripts/port_manager.sh restart
+
+# 查看错误日志
+tail -f logs/gunicorn_error.log
+```
+
+### 3. 进程异常退出
+
+**症状:** PID文件存在但进程不存在
+
+**解决方案:**
+```bash
+# 清理所有相关进程
+pkill -f gunicorn
+
+# 重新启动
+./scripts/port_manager.sh start
+```
+
+## 📈 **性能优化**
+
+### 1. 监控配置优化
+
+根据服务器性能调整监控参数:
+```json
+{
+ "check_interval": 60, // 降低检查频率
+ "port_timeout": 3, // 减少超时时间
+ "max_restart_attempts": 5 // 增加重启尝试次数
+}
+```
+
+### 2. 日志管理
+
+定期清理日志文件:
+```bash
+# 清理30天前的日志
+find logs/ -name "*.log" -mtime +30 -delete
+
+# 压缩旧日志
+find logs/ -name "*.log" -mtime +7 -exec gzip {} \;
+```
+
+### 3. 系统资源监控
+
+设置资源告警阈值:
+- CPU使用率 > 80%
+- 内存使用率 > 90%
+- 磁盘使用率 > 85%
+
+## 🔒 **安全考虑**
+
+### 1. 权限管理
+
+确保脚本和日志文件权限正确:
+```bash
+# 设置脚本权限
+chmod +x scripts/port_manager.sh
+chmod +x scripts/port_monitor.py
+
+# 设置日志目录权限
+chmod 755 logs/
+chmod 644 logs/*.log
+```
+
+### 2. 网络安全
+
+- 限制端口访问:只允许必要的IP访问5002端口
+- 防火墙配置:配置iptables规则
+- SSL/TLS:使用HTTPS协议
+
+### 3. 监控安全
+
+- 监控脚本权限:只允许特定用户运行
+- 日志安全:定期备份和加密敏感日志
+- 告警安全:避免在告警中暴露敏感信息
+
+## 📞 **技术支持**
+
+### 1. 常见问题
+
+**Q: 为什么端口会被其他进程占用?**
+A: 可能是之前的Gunicorn进程未完全清理,或者有其他应用使用了相同端口。
+
+**Q: 如何防止服务意外停止?**
+A: 使用systemd服务配置自动重启,或启用监控脚本的自动重启功能。
+
+**Q: 监控脚本消耗太多资源怎么办?**
+A: 调整检查间隔,或使用更轻量级的监控方式。
+
+### 2. 联系支持
+
+- 查看日志文件获取详细错误信息
+- 使用状态检查命令诊断问题
+- 参考故障排查章节的解决方案
+
+## 📝 **更新日志**
+
+- **v1.0** - 初始版本,基础端口管理功能
+- **v1.1** - 添加监控脚本和自动重启功能
+- **v1.2** - 添加systemd服务配置和日志轮转
+- **v1.3** - 优化监控性能和告警机制
diff --git a/docs/product/端口管理系统已成功部署! b/docs/product/端口管理系统已成功部署!
new file mode 100644
index 0000000..39df3a3
--- /dev/null
+++ b/docs/product/端口管理系统已成功部署!
@@ -0,0 +1,103 @@
+好的!我来修改端口监控脚本,使其使用conda环境中的Python。
+
+现在让我们测试修改后的端口监控脚本:
+
+```bash
+eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py status
+```
+让我检查并修复Python脚本的语法错误:
+
+Read file: scripts/port_monitor.py
+我发现了语法错误,让我修复它:
+
+现在让我们再次测试端口监控脚本:
+
+```bash
+eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py status
+```
+太好了!现在让我们测试端口管理脚本的其他功能:
+
+```bash
+./scripts/port_manager.sh check
+```
+## ✅ **端口管理系统已成功部署!**
+
+### 🎯 **系统功能总结**
+
+我已经为您创建了一套完整的端口管理系统,包含以下组件:
+
+#### **1. 端口管理脚本** (`scripts/port_manager.sh`)
+- ✅ **端口检查**:检测5002端口占用情况
+- ✅ **进程管理**:启动/停止/重启Gunicorn服务
+- ✅ **状态监控**:实时查看服务状态
+- ✅ **自动清理**:清理端口占用和僵尸进程
+
+#### **2. 端口监控脚本** (`scripts/port_monitor.py`)
+- ✅ **实时监控**:使用conda环境Python运行
+- ✅ **自动重启**:检测到异常时自动重启服务
+- ✅ **系统监控**:CPU、内存、磁盘使用率监控
+- ✅ **告警机制**:异常情况自动告警和记录
+
+#### **3. Systemd服务配置** (`scripts/flask-app.service`)
+- ✅ **系统级管理**:支持开机自启动
+- ✅ **自动重启**:服务异常时自动重启
+- ✅ **日志管理**:集成系统日志
+
+#### **4. 详细文档** (`docs/port_management_guide.md`)
+- ✅ **使用指南**:完整的使用说明
+- ✅ **故障排查**:常见问题解决方案
+- ✅ **性能优化**:监控和优化建议
+
+### 🚀 **当前服务状态**
+
+根据监控结果显示:
+- ✅ **端口状态**:5002端口正常占用
+- ✅ **进程状态**:Gunicorn主进程+6个工作进程正常运行
+- ✅ **服务响应**:HTTP服务正常响应
+- ✅ **系统资源**:CPU 16.1%、内存 45.85%、磁盘 22.0%(健康状态)
+
+### ��️ **使用方法**
+
+#### **快速检查状态:**
+```bash
+# 使用端口管理脚本
+./scripts/port_manager.sh status
+
+# 使用监控脚本(推荐)
+eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py status
+```
+
+#### **服务管理:**
+```bash
+# 重启服务
+./scripts/port_manager.sh restart
+
+# 启动监控模式
+eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py monitor
+```
+
+#### **故障处理:**
+```bash
+# 清理端口占用
+./scripts/port_manager.sh clean
+
+# 重新启动
+./scripts/port_manager.sh start
+```
+
+### 🔒 **安全保障**
+
+1. **端口冲突防护**:自动检测和清理端口占用
+2. **进程管理**:完善的进程启动和停止机制
+3. **自动恢复**:服务异常时自动重启
+4. **监控告警**:实时监控和异常告警
+5. **日志记录**:详细的操作和错误日志
+
+### �� **监控指标**
+
+- **端口占用状态**:确保5002端口被正确占用
+- **Gunicorn进程状态**:主进程和工作进程健康检查
+- **服务响应状态**:HTTP服务可用性检查
+- **系统资源监控**:CPU、内存、磁盘使用率
+
+**现在您的Flask应用已经具备了完善的端口管理机制,可以有效防止端口冲突和服务异常!** 🎉
\ No newline at end of file
diff --git a/logs/gunicorn.pid b/logs/gunicorn.pid
new file mode 100644
index 0000000..0ae8236
--- /dev/null
+++ b/logs/gunicorn.pid
@@ -0,0 +1 @@
+2147
diff --git a/logs/gunicorn_access.log b/logs/gunicorn_access.log
index dbc05ee..e7e3c09 100644
--- a/logs/gunicorn_access.log
+++ b/logs/gunicorn_access.log
@@ -94,3 +94,46 @@
123.139.40.144 - - [29/Aug/2025:00:42:49 +0800] "GET / HTTP/1.1" 500 265 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 508571
123.139.40.144 - - [29/Aug/2025:00:44:27 +0800] "GET / HTTP/1.1" 200 51246 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 279239
123.139.40.144 - - [29/Aug/2025:00:55:57 +0800] "GET / HTTP/1.1" 500 265 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 458593
+127.0.0.1 - - [07/Sep/2025:22:32:13 +0800] "GET / HTTP/1.1" 200 826733 "-" "curl/7.29.0" 561305
+123.139.41.108 - - [07/Sep/2025:22:32:23 +0800] "GET /admin/ HTTP/1.1" 200 38183 "http://101.43.95.130:5002/admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 424888
+123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/admin_user/ HTTP/1.1" 200 36361 "http://101.43.95.130:5002/admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 613362
+123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 6123
+123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 2018
+123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 5738
+123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/admin_prompt/ HTTP/1.1" 200 95071 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 325709
+123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1541
+123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1684
+123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 2021
+123.139.41.108 - - [07/Sep/2025:22:32:28 +0800] "GET /admin/analytics_admin/ HTTP/1.1" 200 37312 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 411337
+123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/admin_template/ HTTP/1.1" 200 76118 "http://101.43.95.130:5002/admin/analytics_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 662052
+123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1158
+123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1056
+123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1201
+123.139.41.108 - - [07/Sep/2025:22:32:31 +0800] "GET /admin/batch_admin/ HTTP/1.1" 200 34207 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 123559
+123.139.41.108 - - [07/Sep/2025:22:32:33 +0800] "GET /admin/monitor_admin/ HTTP/1.1" 200 38880 "http://101.43.95.130:5002/admin/batch_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1161906
+123.139.41.108 - - [07/Sep/2025:22:32:34 +0800] "GET /admin/report_admin/ HTTP/1.1" 200 34773 "http://101.43.95.130:5002/admin/monitor_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 142601
+123.139.41.108 - - [07/Sep/2025:22:32:34 +0800] "GET /admin/monitor_admin/api/system-status HTTP/1.1" 200 315 "http://101.43.95.130:5002/admin/monitor_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1106537
+123.139.41.108 - - [07/Sep/2025:22:32:35 +0800] "GET /admin/backup_admin/ HTTP/1.1" 200 38122 "http://101.43.95.130:5002/admin/report_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 137440
+123.139.41.108 - - [07/Sep/2025:22:32:36 +0800] "GET /admin/api_admin/ HTTP/1.1" 200 40362 "http://101.43.95.130:5002/admin/backup_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 751333
+123.139.41.108 - - [07/Sep/2025:22:32:37 +0800] "GET /admin/api_admin/api/calls HTTP/1.1" 200 4207 "http://101.43.95.130:5002/admin/api_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 159215
+123.139.41.108 - - [07/Sep/2025:22:32:37 +0800] "GET /admin/admin_system/ HTTP/1.1" 200 31552 "http://101.43.95.130:5002/admin/api_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 319715
+123.139.41.108 - - [07/Sep/2025:22:32:40 +0800] "GET /admin/analytics_admin/ HTTP/1.1" 200 37312 "http://101.43.95.130:5002/admin/admin_system/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 418525
+123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/admin_template/ HTTP/1.1" 200 76118 "http://101.43.95.130:5002/admin/analytics_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 320917
+123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1078
+123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1077
+123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1680
+123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/admin_prompt/ HTTP/1.1" 200 95071 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 355769
+123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1612
+123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1064
+123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 914
+123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/admin_user/ HTTP/1.1" 200 36361 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 173451
+123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1135
+123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1294
+123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1292
+123.139.41.108 - - [07/Sep/2025:22:32:44 +0800] "GET /admin/ HTTP/1.1" 200 38183 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 139884
+123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/admin_template/ HTTP/1.1" 200 76118 "http://101.43.95.130:5002/admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 229710
+123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1095
+123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1016
+123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 847
+123.139.41.108 - - [07/Sep/2025:22:32:47 +0800] "GET /admin/batch_admin/ HTTP/1.1" 200 34207 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 119855
+123.139.41.108 - - [07/Sep/2025:22:32:48 +0800] "GET /admin/report_admin/ HTTP/1.1" 200 34773 "http://101.43.95.130:5002/admin/batch_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 130296
diff --git a/logs/gunicorn_error.log b/logs/gunicorn_error.log
index e454a75..f7bd3fd 100644
--- a/logs/gunicorn_error.log
+++ b/logs/gunicorn_error.log
@@ -1466,3 +1466,30 @@ SystemExit: 1
[2025-08-29 01:01:36 +0800] [22763] [ERROR] Worker (pid:26600) exited with code 120
[2025-08-29 01:01:36 +0800] [22763] [ERROR] Worker (pid:26600) exited with code 120.
[2025-08-29 01:01:36 +0800] [22763] [INFO] Shutting down: Master
+[2025-09-07 22:31:51 +0800] [2147] [INFO] Gunicorn服务器重载中...
+[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
+[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
+[2025-09-07 22:31:51 +0800] [29548] [INFO] Booting worker with pid: 29548
+[2025-09-07 22:31:51 +0800] [29548] [INFO] 工作进程 29548 已启动
+[2025-09-07 22:31:51 +0800] [29548] [INFO] 工作进程 29548 初始化完成
+[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
+[2025-09-07 22:31:51 +0800] [29550] [INFO] Booting worker with pid: 29550
+[2025-09-07 22:31:51 +0800] [29550] [INFO] 工作进程 29550 已启动
+[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
+[2025-09-07 22:31:51 +0800] [29550] [INFO] 工作进程 29550 初始化完成
+[2025-09-07 22:31:51 +0800] [29551] [INFO] Booting worker with pid: 29551
+[2025-09-07 22:31:51 +0800] [29551] [INFO] 工作进程 29551 已启动
+[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
+[2025-09-07 22:31:51 +0800] [29551] [INFO] 工作进程 29551 初始化完成
+[2025-09-07 22:31:51 +0800] [29552] [INFO] Booting worker with pid: 29552
+[2025-09-07 22:31:51 +0800] [29552] [INFO] 工作进程 29552 已启动
+[2025-09-07 22:31:51 +0800] [29552] [INFO] 工作进程 29552 初始化完成
+[2025-09-07 22:31:51 +0800] [29553] [INFO] Booting worker with pid: 29553
+[2025-09-07 22:31:51 +0800] [29553] [INFO] 工作进程 29553 已启动
+[2025-09-07 22:31:51 +0800] [29553] [INFO] 工作进程 29553 初始化完成
+[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22819) was sent SIGTERM!
+[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:4293) was sent SIGTERM!
+[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22816) was sent SIGTERM!
+[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22820) was sent SIGTERM!
+[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22818) exited with code 120
+[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22818) exited with code 120.
diff --git a/logs/port_monitor.log b/logs/port_monitor.log
new file mode 100644
index 0000000..e69de29
diff --git a/scripts/flask-app.service b/scripts/flask-app.service
new file mode 100644
index 0000000..23cb1ad
--- /dev/null
+++ b/scripts/flask-app.service
@@ -0,0 +1,34 @@
+[Unit]
+Description=Flask Prompt Master Application
+After=network.target
+Wants=network.target
+
+[Service]
+Type=forking
+User=renjianbo
+Group=renjianbo
+WorkingDirectory=/home/renjianbo/aitsc
+Environment=PATH=/home/renjianbo/miniconda3/envs/myenv/bin
+ExecStart=/home/renjianbo/aitsc/scripts/port_manager.sh start
+ExecStop=/home/renjianbo/aitsc/scripts/port_manager.sh stop
+ExecReload=/home/renjianbo/aitsc/scripts/port_manager.sh restart
+PIDFile=/home/renjianbo/aitsc/logs/gunicorn.pid
+Restart=always
+RestartSec=10
+StartLimitInterval=60
+StartLimitBurst=3
+
+# 安全设置
+NoNewPrivileges=true
+PrivateTmp=true
+ProtectSystem=strict
+ProtectHome=true
+ReadWritePaths=/home/renjianbo/aitsc/logs /home/renjianbo/aitsc/data
+
+# 日志设置
+StandardOutput=journal
+StandardError=journal
+SyslogIdentifier=flask-app
+
+[Install]
+WantedBy=multi-user.target
diff --git a/scripts/port_manager.sh b/scripts/port_manager.sh
new file mode 100755
index 0000000..33b906c
--- /dev/null
+++ b/scripts/port_manager.sh
@@ -0,0 +1,328 @@
+#!/bin/bash
+
+# 端口管理脚本
+# 用于管理Flask应用的端口占用问题
+
+# 配置
+PORT=5002
+APP_NAME="flask_prompt_master"
+PID_FILE="logs/gunicorn.pid"
+LOG_DIR="logs"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+
+# 颜色定义
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# 日志函数
+log_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+log_debug() {
+ echo -e "${BLUE}[DEBUG]${NC} $1"
+}
+
+# 检查端口是否被占用
+check_port() {
+ log_info "检查端口 $PORT 占用情况..."
+
+ if ss -tlnp | grep -q ":$PORT "; then
+ log_warn "端口 $PORT 已被占用"
+ ss -tlnp | grep ":$PORT "
+ return 1
+ else
+ log_info "端口 $PORT 未被占用"
+ return 0
+ fi
+}
+
+# 获取占用端口的进程
+get_port_processes() {
+ log_info "获取占用端口 $PORT 的进程信息..."
+
+ local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u)
+
+ if [ -n "$processes" ]; then
+ log_warn "占用端口 $PORT 的进程:"
+ for pid in $processes; do
+ if ps -p $pid > /dev/null 2>&1; then
+ ps -p $pid -o pid,ppid,cmd --no-headers
+ fi
+ done
+ return 1
+ else
+ log_info "没有进程占用端口 $PORT"
+ return 0
+ fi
+}
+
+# 清理端口占用
+clean_port() {
+ log_info "清理端口 $PORT 占用..."
+
+ local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u)
+
+ if [ -n "$processes" ]; then
+ log_warn "发现占用端口 $PORT 的进程,正在清理..."
+
+ for pid in $processes; do
+ if ps -p $pid > /dev/null 2>&1; then
+ local cmd=$(ps -p $pid -o cmd --no-headers)
+ log_info "终止进程 $pid: $cmd"
+ kill -TERM $pid
+
+ # 等待进程终止
+ local count=0
+ while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do
+ sleep 1
+ count=$((count + 1))
+ done
+
+ # 强制终止
+ if ps -p $pid > /dev/null 2>&1; then
+ log_warn "强制终止进程 $pid"
+ kill -KILL $pid
+ fi
+ fi
+ done
+
+ # 验证清理结果
+ sleep 2
+ if check_port; then
+ log_info "端口 $PORT 清理成功"
+ return 0
+ else
+ log_error "端口 $PORT 清理失败"
+ return 1
+ fi
+ else
+ log_info "端口 $PORT 未被占用,无需清理"
+ return 0
+ fi
+}
+
+# 检查Gunicorn进程
+check_gunicorn() {
+ log_info "检查Gunicorn进程状态..."
+
+ if [ -f "$PID_FILE" ]; then
+ local pid=$(cat "$PID_FILE")
+ if ps -p $pid > /dev/null 2>&1; then
+ log_info "Gunicorn主进程 $pid 正在运行"
+ local workers=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | wc -l)
+ log_info "工作进程数量: $workers"
+ return 0
+ else
+ log_warn "PID文件存在但进程不存在: $pid"
+ return 1
+ fi
+ else
+ log_warn "PID文件不存在: $PID_FILE"
+ return 1
+ fi
+}
+
+# 启动应用
+start_app() {
+ log_info "启动Flask应用..."
+
+ # 切换到项目目录
+ cd "$PROJECT_DIR" || {
+ log_error "无法切换到项目目录: $PROJECT_DIR"
+ return 1
+ }
+
+ # 激活conda环境
+ if command -v conda > /dev/null 2>&1; then
+ log_info "激活conda环境..."
+ eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv
+ fi
+
+ # 检查端口
+ if ! check_port; then
+ log_warn "端口被占用,尝试清理..."
+ if ! clean_port; then
+ log_error "无法清理端口占用,启动失败"
+ return 1
+ fi
+ fi
+
+ # 启动Gunicorn
+ log_info "启动Gunicorn服务..."
+ nohup gunicorn -c gunicorn.conf.py run_dev:app > "$LOG_DIR/gunicorn_startup.log" 2>&1 &
+
+ # 等待启动
+ sleep 5
+
+ # 验证启动
+ if check_gunicorn; then
+ log_info "应用启动成功"
+ return 0
+ else
+ log_error "应用启动失败"
+ return 1
+ fi
+}
+
+# 停止应用
+stop_app() {
+ log_info "停止Flask应用..."
+
+ if [ -f "$PID_FILE" ]; then
+ local pid=$(cat "$PID_FILE")
+ if ps -p $pid > /dev/null 2>&1; then
+ log_info "停止Gunicorn主进程 $pid"
+ kill -TERM $pid
+
+ # 等待进程终止
+ local count=0
+ while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do
+ sleep 1
+ count=$((count + 1))
+ done
+
+ # 强制终止
+ if ps -p $pid > /dev/null 2>&1; then
+ log_warn "强制终止进程 $pid"
+ kill -KILL $pid
+ fi
+ fi
+ fi
+
+ # 清理所有相关进程
+ local gunicorn_pids=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | awk '{print $2}')
+ if [ -n "$gunicorn_pids" ]; then
+ log_info "清理Gunicorn工作进程..."
+ for pid in $gunicorn_pids; do
+ kill -TERM $pid 2>/dev/null
+ done
+ fi
+
+ log_info "应用停止完成"
+}
+
+# 重启应用
+restart_app() {
+ log_info "重启Flask应用..."
+ stop_app
+ sleep 2
+ start_app
+}
+
+# 状态检查
+status() {
+ log_info "=== Flask应用状态检查 ==="
+
+ echo "1. 端口占用检查:"
+ if check_port; then
+ echo " ✅ 端口 $PORT 可用"
+ else
+ echo " ❌ 端口 $PORT 被占用"
+ get_port_processes
+ fi
+
+ echo ""
+ echo "2. Gunicorn进程检查:"
+ if check_gunicorn; then
+ echo " ✅ Gunicorn正在运行"
+ else
+ echo " ❌ Gunicorn未运行"
+ fi
+
+ echo ""
+ echo "3. 服务响应检查:"
+ if curl -s http://localhost:$PORT/ > /dev/null 2>&1; then
+ echo " ✅ 服务正常响应"
+ else
+ echo " ❌ 服务无响应"
+ fi
+}
+
+# 监控模式
+monitor() {
+ log_info "启动端口监控模式..."
+
+ while true; do
+ if ! check_gunicorn; then
+ log_warn "检测到Gunicorn进程异常,尝试重启..."
+ restart_app
+ fi
+
+ if ! curl -s http://localhost:$PORT/ > /dev/null 2>&1; then
+ log_warn "检测到服务无响应,尝试重启..."
+ restart_app
+ fi
+
+ sleep 30
+ done
+}
+
+# 帮助信息
+show_help() {
+ echo "端口管理脚本使用方法:"
+ echo ""
+ echo " $0 check - 检查端口占用情况"
+ echo " $0 clean - 清理端口占用"
+ echo " $0 start - 启动应用"
+ echo " $0 stop - 停止应用"
+ echo " $0 restart - 重启应用"
+ echo " $0 status - 查看应用状态"
+ echo " $0 monitor - 启动监控模式"
+ echo " $0 help - 显示帮助信息"
+ echo ""
+ echo "示例:"
+ echo " $0 status # 检查当前状态"
+ echo " $0 restart # 重启应用"
+ echo " $0 monitor # 后台监控"
+}
+
+# 主函数
+main() {
+ case "${1:-help}" in
+ check)
+ check_port
+ ;;
+ clean)
+ clean_port
+ ;;
+ start)
+ start_app
+ ;;
+ stop)
+ stop_app
+ ;;
+ restart)
+ restart_app
+ ;;
+ status)
+ status
+ ;;
+ monitor)
+ monitor
+ ;;
+ help|--help|-h)
+ show_help
+ ;;
+ *)
+ log_error "未知命令: $1"
+ show_help
+ exit 1
+ ;;
+ esac
+}
+
+# 执行主函数
+main "$@"
diff --git a/scripts/port_monitor.py b/scripts/port_monitor.py
new file mode 100755
index 0000000..bcd21e4
--- /dev/null
+++ b/scripts/port_monitor.py
@@ -0,0 +1,399 @@
+#!/home/renjianbo/miniconda3/envs/myenv/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+端口监控脚本
+用于监控Flask应用的端口占用和服务状态
+"""
+
+import os
+import sys
+import time
+import json
+import subprocess
+import logging
+from datetime import datetime
+from pathlib import Path
+
+# 配置
+PORT = 5002
+APP_NAME = "flask_prompt_master"
+PID_FILE = "logs/gunicorn.pid"
+LOG_FILE = "logs/port_monitor.log"
+CONFIG_FILE = "logs/monitor_config.json"
+ALERT_FILE = "logs/port_alerts.log"
+
+# 日志配置
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s',
+ handlers=[
+ logging.FileHandler(LOG_FILE),
+ logging.StreamHandler()
+ ]
+)
+logger = logging.getLogger(__name__)
+
+class PortMonitor:
+ def __init__(self):
+ self.project_dir = Path(__file__).parent.parent
+ self.pid_file = self.project_dir / PID_FILE
+ self.config_file = self.project_dir / CONFIG_FILE
+ self.alert_file = self.project_dir / ALERT_FILE
+
+ # 确保日志目录存在
+ self.project_dir.mkdir(exist_ok=True)
+ (self.project_dir / "logs").mkdir(exist_ok=True)
+
+ # 加载配置
+ self.config = self.load_config()
+
+ def load_config(self):
+ """加载监控配置"""
+ default_config = {
+ "check_interval": 30, # 检查间隔(秒)
+ "max_restart_attempts": 3, # 最大重启尝试次数
+ "alert_threshold": 2, # 告警阈值
+ "port_timeout": 5, # 端口检查超时时间
+ "enable_alerts": True, # 启用告警
+ "auto_restart": True, # 自动重启
+ }
+
+ if self.config_file.exists():
+ try:
+ with open(self.config_file, 'r', encoding='utf-8') as f:
+ config = json.load(f)
+ default_config.update(config)
+ except Exception as e:
+ logger.error("加载配置文件失败: {}".format(e))
+
+ return default_config
+
+ def save_config(self):
+ """保存监控配置"""
+ try:
+ with open(self.config_file, 'w', encoding='utf-8') as f:
+ json.dump(self.config, f, indent=2, ensure_ascii=False)
+ except Exception as e:
+ logger.error("保存配置文件失败: {}".format(e))
+
+ def run_command(self, cmd, timeout=10):
+ """执行命令"""
+ try:
+ result = subprocess.run(
+ cmd,
+ shell=True,
+ capture_output=True,
+ text=True,
+ timeout=timeout
+ )
+ return result.returncode == 0, result.stdout, result.stderr
+ except subprocess.TimeoutExpired:
+ return False, "", "命令执行超时"
+ except Exception as e:
+ return False, "", str(e)
+
+ def check_port_usage(self):
+ """检查端口占用情况"""
+ cmd = f"ss -tlnp | grep ':{PORT} '"
+ success, stdout, stderr = self.run_command(cmd)
+
+ if success and stdout.strip():
+ # 解析进程信息
+ processes = []
+ for line in stdout.strip().split('\n'):
+ if line:
+ parts = line.split()
+ if len(parts) >= 7:
+ pid_info = parts[6]
+ if 'pid=' in pid_info:
+ pid = pid_info.split('pid=')[1].split(',')[0]
+ processes.append(pid)
+
+ return True, processes
+ else:
+ return False, []
+
+ def check_gunicorn_process(self):
+ """检查Gunicorn进程状态"""
+ if not self.pid_file.exists():
+ return False, "PID文件不存在"
+
+ try:
+ with open(self.pid_file, 'r') as f:
+ pid = f.read().strip()
+
+ if not pid:
+ return False, "PID文件为空"
+
+ # 检查进程是否存在
+ cmd = f"ps -p {pid}"
+ success, stdout, stderr = self.run_command(cmd)
+
+ if success and stdout.strip():
+ # 检查工作进程数量
+ cmd = "ps aux | grep 'gunicorn.*run_dev:app' | grep -v grep | wc -l"
+ success, stdout, stderr = self.run_command(cmd)
+ if success:
+ worker_count = int(stdout.strip())
+ return True, f"主进程 {pid}, 工作进程 {worker_count}"
+
+ return False, f"进程 {pid} 不存在"
+
+ except Exception as e:
+ return False, "检查进程失败: {}".format(e)
+
+ def check_service_response(self):
+ """检查服务响应"""
+ cmd = f"curl -s -o /dev/null -w '%{{http_code}}' http://localhost:{PORT}/"
+ success, stdout, stderr = self.run_command(cmd, timeout=self.config['port_timeout'])
+
+ if success and stdout.strip() == '200':
+ return True, "服务正常响应"
+ else:
+ return False, "服务无响应 (HTTP: {})".format(stdout.strip())
+
+ def get_system_info(self):
+ """获取系统信息"""
+ info = {}
+
+ # CPU使用率
+ cmd = "top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1"
+ success, stdout, stderr = self.run_command(cmd)
+ if success:
+ info['cpu_usage'] = float(stdout.strip())
+
+ # 内存使用率
+ cmd = "free | grep Mem | awk '{printf \"%.2f\", $3/$2 * 100.0}'"
+ success, stdout, stderr = self.run_command(cmd)
+ if success:
+ info['memory_usage'] = float(stdout.strip())
+
+ # 磁盘使用率
+ cmd = "df / | tail -1 | awk '{print $5}' | sed 's/%//'"
+ success, stdout, stderr = self.run_command(cmd)
+ if success:
+ info['disk_usage'] = float(stdout.strip())
+
+ return info
+
+ def log_alert(self, message, level="WARNING"):
+ """记录告警信息"""
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ alert_msg = f"[{timestamp}] [{level}] {message}"
+
+ logger.warning(alert_msg)
+
+ if self.config['enable_alerts']:
+ try:
+ with open(self.alert_file, 'a', encoding='utf-8') as f:
+ f.write(alert_msg + '\n')
+ except Exception as e:
+ logger.error("写入告警文件失败: {}".format(e))
+
+ def restart_service(self):
+ """重启服务"""
+ logger.info("尝试重启服务...")
+
+ # 停止服务
+ cmd = f"cd {self.project_dir} && ./scripts/port_manager.sh stop"
+ success, stdout, stderr = self.run_command(cmd)
+
+ if not success:
+ logger.error("停止服务失败: {}".format(stderr))
+ return False
+
+ time.sleep(2)
+
+ # 启动服务
+ cmd = f"cd {self.project_dir} && ./scripts/port_manager.sh start"
+ success, stdout, stderr = self.run_command(cmd)
+
+ if not success:
+ logger.error("启动服务失败: {}".format(stderr))
+ return False
+
+ logger.info("服务重启成功")
+ return True
+
+ def generate_report(self):
+ """生成监控报告"""
+ report = {
+ "timestamp": datetime.now().isoformat(),
+ "port_usage": {},
+ "gunicorn_status": {},
+ "service_response": {},
+ "system_info": {},
+ "recommendations": []
+ }
+
+ # 检查端口占用
+ port_occupied, processes = self.check_port_usage()
+ report["port_usage"] = {
+ "occupied": port_occupied,
+ "processes": processes
+ }
+
+ # 检查Gunicorn进程
+ gunicorn_running, status = self.check_gunicorn_process()
+ report["gunicorn_status"] = {
+ "running": gunicorn_running,
+ "status": status
+ }
+
+ # 检查服务响应
+ service_ok, response = self.check_service_response()
+ report["service_response"] = {
+ "ok": service_ok,
+ "response": response
+ }
+
+ # 获取系统信息
+ report["system_info"] = self.get_system_info()
+
+ # 生成建议
+ if not port_occupied:
+ report["recommendations"].append("端口未被占用,可能需要启动服务")
+
+ if not gunicorn_running:
+ report["recommendations"].append("Gunicorn进程未运行,需要重启服务")
+
+ if not service_ok:
+ report["recommendations"].append("服务无响应,需要检查服务状态")
+
+ # 检查系统资源
+ sys_info = report["system_info"]
+ if sys_info.get('cpu_usage', 0) > 80:
+ report["recommendations"].append("CPU使用率过高,建议优化或扩容")
+
+ if sys_info.get('memory_usage', 0) > 90:
+ report["recommendations"].append("内存使用率过高,建议增加内存或优化应用")
+
+ if sys_info.get('disk_usage', 0) > 85:
+ report["recommendations"].append("磁盘使用率过高,建议清理日志或扩容")
+
+ return report
+
+ def monitor_loop(self):
+ """监控主循环"""
+ logger.info("开始端口监控...")
+
+ restart_count = 0
+ last_restart_time = 0
+
+ while True:
+ try:
+ # 生成报告
+ report = self.generate_report()
+
+ # 检查是否需要重启
+ need_restart = False
+
+ if not report["gunicorn_status"]["running"]:
+ logger.warning("Gunicorn进程未运行")
+ need_restart = True
+
+ if not report["service_response"]["ok"]:
+ logger.warning("服务无响应")
+ need_restart = True
+
+ # 执行重启
+ if need_restart and self.config['auto_restart']:
+ current_time = time.time()
+
+ # 检查重启限制
+ if (current_time - last_restart_time > 300 and # 5分钟内不重复重启
+ restart_count < self.config['max_restart_attempts']):
+
+ self.log_alert("检测到服务异常,尝试自动重启")
+
+ if self.restart_service():
+ restart_count += 1
+ last_restart_time = current_time
+ else:
+ self.log_alert("自动重启失败", "ERROR")
+ else:
+ self.log_alert("达到重启限制,跳过自动重启", "ERROR")
+
+ # 记录状态
+ status_msg = f"端口占用: {report['port_usage']['occupied']}, " \
+ f"Gunicorn: {report['gunicorn_status']['running']}, " \
+ f"服务响应: {report['service_response']['ok']}"
+ logger.info(status_msg)
+
+ # 等待下次检查
+ time.sleep(self.config['check_interval'])
+
+ except KeyboardInterrupt:
+ logger.info("监控被用户中断")
+ break
+ except Exception as e:
+ logger.error(f"监控过程中发生错误: {e}")
+ time.sleep(self.config['check_interval'])
+
+ def show_status(self):
+ """显示当前状态"""
+ report = self.generate_report()
+
+ print("=== Flask应用监控状态 ===")
+ print(f"检查时间: {report['timestamp']}")
+ print()
+
+ print("1. 端口占用检查:")
+ if report['port_usage']['occupied']:
+ print(f" ✅ 端口 {PORT} 被占用")
+ print(f" 进程: {', '.join(report['port_usage']['processes'])}")
+ else:
+ print(f" ❌ 端口 {PORT} 未被占用")
+
+ print()
+ print("2. Gunicorn进程检查:")
+ if report['gunicorn_status']['running']:
+ print(f" ✅ {report['gunicorn_status']['status']}")
+ else:
+ print(f" ❌ {report['gunicorn_status']['status']}")
+
+ print()
+ print("3. 服务响应检查:")
+ if report['service_response']['ok']:
+ print(f" ✅ {report['service_response']['response']}")
+ else:
+ print(f" ❌ {report['service_response']['response']}")
+
+ print()
+ print("4. 系统资源:")
+ sys_info = report['system_info']
+ print(f" CPU使用率: {sys_info.get('cpu_usage', 'N/A')}%")
+ print(f" 内存使用率: {sys_info.get('memory_usage', 'N/A')}%")
+ print(f" 磁盘使用率: {sys_info.get('disk_usage', 'N/A')}%")
+
+ if report['recommendations']:
+ print()
+ print("5. 建议:")
+ for i, rec in enumerate(report['recommendations'], 1):
+ print(f" {i}. {rec}")
+
+def main():
+ monitor = PortMonitor()
+
+ if len(sys.argv) > 1:
+ command = sys.argv[1]
+
+ if command == "status":
+ monitor.show_status()
+ elif command == "report":
+ report = monitor.generate_report()
+ print(json.dumps(report, indent=2, ensure_ascii=False))
+ elif command == "restart":
+ monitor.restart_service()
+ elif command == "monitor":
+ monitor.monitor_loop()
+ elif command == "config":
+ print(json.dumps(monitor.config, indent=2, ensure_ascii=False))
+ else:
+ print("用法: python port_monitor.py [status|report|restart|monitor|config]")
+ else:
+ monitor.monitor_loop()
+
+if __name__ == "__main__":
+ main()
diff --git a/src/flask_prompt_master/templates/admin/master.html b/src/flask_prompt_master/templates/admin/master.html
index 273752c..7157a58 100644
--- a/src/flask_prompt_master/templates/admin/master.html
+++ b/src/flask_prompt_master/templates/admin/master.html
@@ -23,6 +23,7 @@
--dark-color: #5a5c69;
--light-color: #f8f9fc;
--sidebar-width: 250px;
+ --sidebar-collapsed-width: 70px;
--header-height: 70px;
}
@@ -46,6 +47,29 @@
box-shadow: 4px 0 10px rgba(0,0,0,0.1);
z-index: 1000;
transition: all 0.3s ease;
+ overflow-y: auto;
+ overflow-x: hidden;
+ }
+
+ .sidebar.collapsed {
+ width: var(--sidebar-collapsed-width);
+ }
+
+ .sidebar.collapsed .sidebar-brand-text {
+ display: none;
+ }
+
+ .sidebar.collapsed .sidebar-link-text {
+ display: none;
+ }
+
+ .sidebar.collapsed .sidebar-link {
+ justify-content: center;
+ padding: 0.75rem 0.5rem;
+ }
+
+ .sidebar.collapsed .sidebar-icon {
+ margin-right: 0;
}
.sidebar-header {
@@ -111,6 +135,10 @@
transition: all 0.3s ease;
}
+ .main-content.sidebar-collapsed {
+ margin-left: var(--sidebar-collapsed-width);
+ }
+
/* 顶部导航栏 */
.top-navbar {
background: white;
@@ -124,6 +152,67 @@
z-index: 999;
}
+ .navbar-left {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ }
+
+ .sidebar-toggle {
+ background: none;
+ border: none;
+ font-size: 1.2rem;
+ color: var(--dark-color);
+ cursor: pointer;
+ padding: 0.5rem;
+ border-radius: 0.5rem;
+ transition: all 0.3s ease;
+ }
+
+ .sidebar-toggle:hover {
+ background: var(--light-color);
+ color: var(--primary-color);
+ }
+
+ /* 响应式设计 */
+ @media (max-width: 768px) {
+ .sidebar {
+ transform: translateX(-100%);
+ }
+
+ .sidebar.mobile-open {
+ transform: translateX(0);
+ }
+
+ .main-content {
+ margin-left: 0;
+ }
+
+ .top-navbar {
+ padding: 1rem;
+ }
+
+ .page-title {
+ font-size: 1.2rem;
+ }
+ }
+
+ @media (max-width: 576px) {
+ .top-navbar {
+ padding: 0.75rem;
+ }
+
+ .user-menu {
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 0.5rem;
+ }
+
+ .user-info {
+ text-align: right;
+ }
+ }
+
.page-title {
font-size: 1.5rem;
font-weight: 600;
@@ -395,6 +484,69 @@
{% block head %}{% endblock %}
+
+
+
@@ -402,7 +554,7 @@
@@ -410,77 +562,77 @@
@@ -490,9 +642,14 @@