wapadil Claude commited on
Commit
3a2e0a6
·
1 Parent(s): edb79fa

iOS移动端优化:安全区域、触控友好、PWA支持

Browse files

- 实施iOS Safari安全区域支持 (viewport-fit=cover + env())
- 添加44pt最小触控区域,符合iOS设计规范
- 实现iPad悬停效果 (@media hover:hover)
- 添加自动暗色模式支持 (prefers-color-scheme)
- 实施毛玻璃效果 (backdrop-filter)
- 配置PWA manifest和iOS Web App功能
- 修复动态视口单位 (100dvh替代100vh)
- 更新CLAUDE.md文档反映架构变更

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

CLAUDE.md CHANGED
@@ -161,9 +161,12 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
161
  # Install dependencies
162
  pip install -r requirements.txt
163
 
164
- # Run the application locally
165
- python app.py
166
  # Server runs on http://localhost:7860
 
 
 
167
  ```
168
 
169
  ### Docker Development
@@ -176,29 +179,36 @@ docker run -p 7860:7860 seedream-editor
176
  ```
177
 
178
  ### Deployment
179
- - **Primary deployment**: Hugging Face Spaces (Docker template)
 
180
  - **Alternative**: Vercel (using vercel.json configuration)
181
  - **Port**: 7860 (Hugging Face Spaces default)
 
182
 
183
  ## Architecture Overview
184
 
185
  ### Backend Architecture
186
  - **Framework**: Flask with CORS enabled
187
  - **API Integration**: FAL API client for ByteDance SeedDream v4 models
188
- - **Async Processing**: Custom event loop management with ThreadPoolExecutor
189
- - **Request Handling**: Non-blocking async API calls with request tracking system
190
 
191
  ### Key Technical Details
192
- - **Event Loop Management**: Uses dedicated background thread with persistent event loop for all async operations
193
  - **API Models**:
194
  - `fal-ai/bytedance/seedream/v4/edit` - Image editing mode
 
195
  - `fal-ai/bytedance/seedream/v4/text-to-image` - Text-to-image generation
196
  - **File Handling**: Base64 data URLs for image uploads, temporary file management for FAL uploads
197
- - **Request Tracking**: UUID-based request tracking with status polling (`/api/status/<request_id>`)
 
 
 
198
 
199
  ### Frontend Architecture
200
  - **Technology**: Vanilla HTML/CSS/JavaScript (no frameworks)
201
  - **UI Pattern**: Single-page application with dynamic mode switching
 
 
202
  - **File Upload**: Drag-and-drop interface with base64 conversion
203
  - **API Communication**: Fetch API with polling for async operation status
204
 
@@ -216,52 +226,78 @@ docker run -p 7860:7860 seedream-editor
216
 
217
  ### File Structure
218
  ```
219
- ├── app.py # Main Flask application
 
220
  ├── requirements.txt # Python dependencies
221
  ├── Dockerfile # Container configuration
222
  ├── vercel.json # Vercel deployment config
 
 
 
 
 
 
 
 
223
  ├── templates/
224
- │ └── index.html # Main UI template
225
  └── static/
226
- ├── style.css # Application styles
227
- └── script.js # Frontend logic
228
  ```
229
 
230
  ## Important Implementation Notes
231
 
232
- ### Async Processing
233
- - Uses a shared background event loop (`_async_loop`) for all FAL API operations
234
- - Request processing happens asynchronously with proper cleanup
235
- - Event iteration with safety limits to prevent infinite loops
236
- - Graceful error handling and request cleanup
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
- ### Memory Management
239
- - Automatic cleanup of completed/errored requests from `active_requests` dict
240
- - Temporary file cleanup after FAL uploads
241
- - Proper async task cancellation and event loop shutdown
242
 
243
- ### Error Handling
244
- - Comprehensive logging with DEBUG prefixes
245
- - Timeout protection (60s for API calls, 5min for uploads)
246
- - Graceful degradation when event iteration fails
247
- - Request status tracking with error state management
248
 
249
- ## Development Guidelines
 
 
 
 
250
 
251
- ### When modifying async code:
252
  - Always use the shared `_async_loop` for FAL API operations
253
  - Use `schedule_in_async_loop()` for fire-and-forget operations
254
  - Use `run_in_async_loop()` for synchronous waiting
255
  - Ensure proper cleanup in exception handlers
256
 
257
  ### When adding new API endpoints:
258
- - Follow the request tracking pattern for async operations
259
  - Use proper API key extraction from Authorization header
260
  - Include comprehensive debug logging
261
  - Handle both success and error cases with cleanup
 
262
 
263
  ### When modifying the frontend:
264
  - Maintain vanilla JS approach (no framework dependencies)
 
265
  - Use consistent error handling patterns
266
- - Preserve the polling mechanism for async operations
267
- - Keep localStorage API key management
 
161
  # Install dependencies
162
  pip install -r requirements.txt
163
 
164
+ # Run the optimized application (recommended)
165
+ python app_simple.py
166
  # Server runs on http://localhost:7860
167
+
168
+ # Or run the original application (compatibility mode)
169
+ python app.py
170
  ```
171
 
172
  ### Docker Development
 
179
  ```
180
 
181
  ### Deployment
182
+ - **Primary deployment**: Hugging Face Spaces at https://huggingface.co/spaces/wapadil/seedream4
183
+ - **GitHub Integration**: Automatic deployment via GitHub Actions workflow
184
  - **Alternative**: Vercel (using vercel.json configuration)
185
  - **Port**: 7860 (Hugging Face Spaces default)
186
+ - **Access Token**: Uses HF_TOKEN for automated deployments
187
 
188
  ## Architecture Overview
189
 
190
  ### Backend Architecture
191
  - **Framework**: Flask with CORS enabled
192
  - **API Integration**: FAL API client for ByteDance SeedDream v4 models
193
+ - **Processing Model**: Simplified synchronous API calls (app_simple.py) or complex async processing (app.py)
194
+ - **Request Handling**: Direct API calls with immediate response (optimized) or async request tracking (legacy)
195
 
196
  ### Key Technical Details
 
197
  - **API Models**:
198
  - `fal-ai/bytedance/seedream/v4/edit` - Image editing mode
199
+ - `fal-ai/qwen-image-edit-plus` - Qwen image editing model
200
  - `fal-ai/bytedance/seedream/v4/text-to-image` - Text-to-image generation
201
  - **File Handling**: Base64 data URLs for image uploads, temporary file management for FAL uploads
202
+ - **Localization**: Complete Chinese frontend interface with optimized Chinese fonts
203
+ - **Architecture Variants**:
204
+ - **app_simple.py**: Synchronous API calls, simplified error handling
205
+ - **app.py**: Complex async processing with event loop management and request tracking
206
 
207
  ### Frontend Architecture
208
  - **Technology**: Vanilla HTML/CSS/JavaScript (no frameworks)
209
  - **UI Pattern**: Single-page application with dynamic mode switching
210
+ - **Localization**: Complete Chinese interface (纯中文化前端)
211
+ - **Typography**: Optimized Chinese font stack with proper spacing
212
  - **File Upload**: Drag-and-drop interface with base64 conversion
213
  - **API Communication**: Fetch API with polling for async operation status
214
 
 
226
 
227
  ### File Structure
228
  ```
229
+ ├── app.py # Original application (complex async)
230
+ ├── app_simple.py # Optimized application (recommended)
231
  ├── requirements.txt # Python dependencies
232
  ├── Dockerfile # Container configuration
233
  ├── vercel.json # Vercel deployment config
234
+ ├── .github/
235
+ │ └── workflows/
236
+ │ └── deploy.yml # GitHub Actions deployment
237
+ ├── api/
238
+ │ ├── fal_client.py # Simplified FAL API client
239
+ │ └── routes.py # Modular API routes
240
+ ├── monitoring.py # Request monitoring and logging
241
+ ├── tests/ # Test suite
242
  ├── templates/
243
+ │ └── index.html # Chinese localized UI template
244
  └── static/
245
+ ├── style.css # Chinese optimized styles
246
+ └── script.js # Chinese localized frontend logic
247
  ```
248
 
249
  ## Important Implementation Notes
250
 
251
+ ### Architecture Variants
252
+ - **app_simple.py (Recommended)**: Synchronous FAL API client with direct response handling
253
+ - **app.py (Legacy)**: Complex async processing with event loop management
254
+
255
+ ### Processing Models
256
+ **Optimized Synchronous (app_simple.py)**:
257
+ - Direct API calls using `fal_client.SyncClient`
258
+ - Immediate response handling without polling
259
+ - Simplified error handling and logging
260
+ - Modular architecture with separate API modules
261
+
262
+ **Legacy Async (app.py)**:
263
+ - Background event loop with ThreadPoolExecutor
264
+ - Request tracking with UUID-based polling
265
+ - Complex memory management and cleanup
266
+ - Event iteration with safety limits
267
+
268
+ ### Chinese Localization
269
+ - Complete frontend interface translation (纯中文化前端)
270
+ - Optimized Chinese font stack: PingFang SC, Hiragino Sans GB, Microsoft YaHei
271
+ - Proper line height (1.6) and letter spacing for Chinese text
272
+ - All user messages, buttons, and labels localized
273
 
274
+ ## Development Guidelines
 
 
 
275
 
276
+ ### Application Selection
277
+ - **Production/New Development**: Use `app_simple.py` for new features and production deployments
278
+ - **Legacy Support**: Use `app.py` only when specifically needed for compatibility
 
 
279
 
280
+ ### When modifying the optimized version (app_simple.py):
281
+ - Use the modular API structure in `api/` directory
282
+ - Leverage the simplified `FALClient` class for API operations
283
+ - Follow the direct response pattern without async complexity
284
+ - Use the monitoring module for consistent logging
285
 
286
+ ### When modifying the legacy version (app.py):
287
  - Always use the shared `_async_loop` for FAL API operations
288
  - Use `schedule_in_async_loop()` for fire-and-forget operations
289
  - Use `run_in_async_loop()` for synchronous waiting
290
  - Ensure proper cleanup in exception handlers
291
 
292
  ### When adding new API endpoints:
 
293
  - Use proper API key extraction from Authorization header
294
  - Include comprehensive debug logging
295
  - Handle both success and error cases with cleanup
296
+ - For new endpoints, prefer the simplified synchronous pattern
297
 
298
  ### When modifying the frontend:
299
  - Maintain vanilla JS approach (no framework dependencies)
300
+ - Preserve Chinese localization in all user-facing text
301
  - Use consistent error handling patterns
302
+ - Keep localStorage API key management
303
+ - Maintain Chinese font optimization in CSS
static/app-icon.svg ADDED
static/manifest.webmanifest ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "SeedDream v4 - AI图像生成与编辑器",
3
+ "short_name": "SeedDream",
4
+ "description": "AI驱动的图像生成与编辑",
5
+ "start_url": "/",
6
+ "display": "standalone",
7
+ "background_color": "#0b0b0c",
8
+ "theme_color": "#007AFF",
9
+ "orientation": "portrait-primary",
10
+ "icons": [
11
+ {
12
+ "src": "/static/app-icon.svg",
13
+ "sizes": "180x180",
14
+ "type": "image/svg+xml",
15
+ "purpose": "any maskable"
16
+ }
17
+ ]
18
+ }
static/style.css CHANGED
@@ -1,3 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  * {
2
  margin: 0;
3
  padding: 0;
@@ -6,25 +39,31 @@
6
 
7
  body {
8
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
9
- background: #1a1a2e;
10
- color: #333;
11
- height: 100vh;
12
- overflow: hidden;
13
  line-height: 1.6;
 
 
 
14
  }
15
 
16
  /* Main App Container - Two Column Layout */
17
  .app-container {
18
  display: flex;
19
- height: 100vh;
20
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
 
 
 
21
  }
22
 
23
  /* Left Panel - Controls */
24
  .left-panel {
25
  width: 45%;
26
  min-width: 500px;
27
- background: #f8f9fa;
28
  overflow-y: auto;
29
  box-shadow: 2px 0 10px rgba(0,0,0,0.1);
30
  display: flex;
@@ -39,6 +78,8 @@ body {
39
  position: sticky;
40
  top: 0;
41
  z-index: 10;
 
 
42
  }
43
 
44
  .left-panel header h1 {
@@ -875,8 +916,9 @@ body {
875
  position: sticky;
876
  top: 0;
877
  z-index: 15;
878
- backdrop-filter: saturate(140%) blur(8px);
879
- background: linear-gradient(180deg, rgba(26,26,46,0.85), rgba(26,26,46,0.65));
 
880
  border-bottom: 1px solid rgba(255,255,255,0.08);
881
  }
882
 
@@ -1111,9 +1153,35 @@ label, .form-group label {
1111
  }
1112
 
1113
  /* 按钮文字优化 */
 
1114
  button, .btn {
 
 
 
 
 
1115
  font-weight: 500;
 
1116
  letter-spacing: 0.01em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1117
  }
1118
 
1119
  /* 状态消息中文优化 */
 
1
+ :root {
2
+ color-scheme: light dark;
3
+ --side-pad: max(16px, env(safe-area-inset-left));
4
+ --side-pad-r: max(16px, env(safe-area-inset-right));
5
+ --safe-bottom: max(16px, env(safe-area-inset-bottom));
6
+ --safe-top: max(16px, env(safe-area-inset-top));
7
+
8
+ /* Light theme colors */
9
+ --bg: #f8f9fa;
10
+ --card: #ffffff;
11
+ --text: #333333;
12
+ --muted: #6c757d;
13
+ --border: #dee2e6;
14
+ --brand: #007AFF;
15
+ --success: #28a745;
16
+ --danger: #dc3545;
17
+ --warning: #ffc107;
18
+ }
19
+
20
+ @media (prefers-color-scheme: dark) {
21
+ :root {
22
+ --bg: #0b0b0c;
23
+ --card: #161719;
24
+ --text: #e7e7ea;
25
+ --muted: #9a9aa0;
26
+ --border: #2c2c2e;
27
+ --brand: #0A84FF;
28
+ --success: #32d74b;
29
+ --danger: #ff453a;
30
+ --warning: #ffd60a;
31
+ }
32
+ }
33
+
34
  * {
35
  margin: 0;
36
  padding: 0;
 
39
 
40
  body {
41
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
42
+ background: var(--bg);
43
+ color: var(--text);
44
+ min-height: 100dvh;
 
45
  line-height: 1.6;
46
+ -webkit-font-smoothing: antialiased;
47
+ -moz-osx-font-smoothing: grayscale;
48
+ font-size: max(16px, 1rem);
49
  }
50
 
51
  /* Main App Container - Two Column Layout */
52
  .app-container {
53
  display: flex;
54
+ min-height: 100dvh;
55
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
56
+ padding-left: var(--side-pad);
57
+ padding-right: var(--side-pad-r);
58
+ padding-top: var(--safe-top);
59
+ padding-bottom: var(--safe-bottom);
60
  }
61
 
62
  /* Left Panel - Controls */
63
  .left-panel {
64
  width: 45%;
65
  min-width: 500px;
66
+ background: var(--card);
67
  overflow-y: auto;
68
  box-shadow: 2px 0 10px rgba(0,0,0,0.1);
69
  display: flex;
 
78
  position: sticky;
79
  top: 0;
80
  z-index: 10;
81
+ backdrop-filter: blur(16px) saturate(1.2);
82
+ -webkit-backdrop-filter: blur(16px) saturate(1.2);
83
  }
84
 
85
  .left-panel header h1 {
 
916
  position: sticky;
917
  top: 0;
918
  z-index: 15;
919
+ backdrop-filter: blur(16px) saturate(1.2);
920
+ -webkit-backdrop-filter: blur(16px) saturate(1.2);
921
+ background: rgba(24,24,28,0.6);
922
  border-bottom: 1px solid rgba(255,255,255,0.08);
923
  }
924
 
 
1153
  }
1154
 
1155
  /* 按钮文字优化 */
1156
+ /* Touch-friendly buttons with 44pt minimum */
1157
  button, .btn {
1158
+ min-height: 44px;
1159
+ min-width: 44px;
1160
+ padding: 10px 14px;
1161
+ border-radius: 12px;
1162
+ border: none;
1163
  font-weight: 500;
1164
+ font-size: max(16px, 1rem);
1165
  letter-spacing: 0.01em;
1166
+ cursor: pointer;
1167
+ transition: transform 0.18s ease, filter 0.18s ease, box-shadow 0.18s ease;
1168
+ background: var(--brand);
1169
+ color: white;
1170
+ line-height: 1.2;
1171
+ }
1172
+
1173
+ /* iPad hover effects */
1174
+ @media (hover: hover) and (pointer: fine) {
1175
+ button:hover, .btn:hover {
1176
+ transform: translateY(-1px);
1177
+ filter: brightness(1.05);
1178
+ box-shadow: 0 6px 20px rgba(0,0,0,0.12);
1179
+ }
1180
+ }
1181
+
1182
+ button:active, .btn:active {
1183
+ transform: translateY(0);
1184
+ filter: brightness(0.95);
1185
  }
1186
 
1187
  /* 状态消息中文优化 */
templates/index.html CHANGED
@@ -2,7 +2,11 @@
2
  <html lang="zh-CN">
3
  <head>
4
  <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
 
 
 
6
  <title>SeedDream v4 - AI图像生成与编辑器</title>
7
  <link rel="stylesheet" href="/static/style.css">
8
  </head>
 
2
  <html lang="zh-CN">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
6
+ <link rel="apple-touch-icon" href="/static/app-icon.svg">
7
+ <meta name="apple-mobile-web-app-capable" content="yes">
8
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
9
+ <link rel="manifest" href="/static/manifest.webmanifest">
10
  <title>SeedDream v4 - AI图像生成与编辑器</title>
11
  <link rel="stylesheet" href="/static/style.css">
12
  </head>