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 +66 -30
- static/app-icon.svg +11 -0
- static/manifest.webmanifest +18 -0
- static/style.css +76 -8
- templates/index.html +5 -1
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
|
| 165 |
-
python
|
| 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
|
|
|
|
| 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 |
-
- **
|
| 189 |
-
- **Request Handling**:
|
| 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 |
-
- **
|
|
|
|
|
|
|
|
|
|
| 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 #
|
|
|
|
| 220 |
├── requirements.txt # Python dependencies
|
| 221 |
├── Dockerfile # Container configuration
|
| 222 |
├── vercel.json # Vercel deployment config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
├── templates/
|
| 224 |
-
│ └── index.html #
|
| 225 |
└── static/
|
| 226 |
-
├── style.css #
|
| 227 |
-
└── script.js #
|
| 228 |
```
|
| 229 |
|
| 230 |
## Important Implementation Notes
|
| 231 |
|
| 232 |
-
###
|
| 233 |
-
-
|
| 234 |
-
-
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
-
##
|
| 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 |
-
###
|
| 244 |
-
-
|
| 245 |
-
-
|
| 246 |
-
- Graceful degradation when event iteration fails
|
| 247 |
-
- Request status tracking with error state management
|
| 248 |
|
| 249 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
|
| 251 |
-
### When modifying
|
| 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 |
-
-
|
| 267 |
-
-
|
|
|
|
| 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:
|
| 10 |
-
color:
|
| 11 |
-
height:
|
| 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:
|
| 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:
|
| 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:
|
| 879 |
-
|
|
|
|
| 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,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>
|