dsh-plugin-image-workbench 0.0.0-stage → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +256 -0
- package/README.md +256 -2
- package/client.js +241 -0
- package/cordis.patch.yml +14 -0
- package/host.js +641 -0
- package/install.mjs +387 -0
- package/package.json +57 -4
- package/scripts/vendor-snapshot.py +154 -0
- package/server/access.py +26 -0
- package/server/app.py +1329 -0
- package/server/catalog.json +1 -0
- package/server/catalog.py +147 -0
- package/server/composer.py +391 -0
- package/server/drafts.py +158 -0
- package/server/history.py +575 -0
- package/server/imaging.py +172 -0
- package/server/pool.py +1335 -0
- package/server/pool_admin.py +921 -0
- package/server/pool_service.py +1073 -0
- package/server/requirements.txt +6 -0
- package/server/smoke_check.py +402 -0
- package/server/static/access.html +202 -0
- package/server/static/index.html +4725 -0
- package/vendor/chatgpt2api/README.md +13 -0
- package/vendor/chatgpt2api/SOURCE.json +11 -0
- package/vendor/chatgpt2api/runtime/uv.exe +0 -0
- package/vendor/chatgpt2api/source/.env.example +82 -0
- package/vendor/chatgpt2api/source/.python-version +1 -0
- package/vendor/chatgpt2api/source/LICENSE +21 -0
- package/vendor/chatgpt2api/source/README.md +391 -0
- package/vendor/chatgpt2api/source/VERSION +1 -0
- package/vendor/chatgpt2api/source/api/__init__.py +2 -0
- package/vendor/chatgpt2api/source/api/accounts.py +537 -0
- package/vendor/chatgpt2api/source/api/ai.py +217 -0
- package/vendor/chatgpt2api/source/api/app.py +62 -0
- package/vendor/chatgpt2api/source/api/errors.py +46 -0
- package/vendor/chatgpt2api/source/api/image_inputs.py +309 -0
- package/vendor/chatgpt2api/source/api/image_tasks.py +120 -0
- package/vendor/chatgpt2api/source/api/support.py +134 -0
- package/vendor/chatgpt2api/source/api/system.py +365 -0
- package/vendor/chatgpt2api/source/assets/atlascloud.svg +1 -0
- package/vendor/chatgpt2api/source/assets/ipwo.png +0 -0
- package/vendor/chatgpt2api/source/assets/kunrouai.svg +50 -0
- package/vendor/chatgpt2api/source/config.default.json +108 -0
- package/vendor/chatgpt2api/source/main.py +9 -0
- package/vendor/chatgpt2api/source/pyproject.toml +27 -0
- package/vendor/chatgpt2api/source/scripts/init_proxy_config.py +186 -0
- package/vendor/chatgpt2api/source/scripts/migrate_storage.py +163 -0
- package/vendor/chatgpt2api/source/scripts/privoxy-warp.conf +13 -0
- package/vendor/chatgpt2api/source/scripts/test_outlook_token_mailbox.py +385 -0
- package/vendor/chatgpt2api/source/scripts/test_storage.py +129 -0
- package/vendor/chatgpt2api/source/scripts/verify_oauth_refresh.py +92 -0
- package/vendor/chatgpt2api/source/services/__init__.py +0 -0
- package/vendor/chatgpt2api/source/services/account_service.py +1757 -0
- package/vendor/chatgpt2api/source/services/auth_service.py +253 -0
- package/vendor/chatgpt2api/source/services/backup_service.py +671 -0
- package/vendor/chatgpt2api/source/services/config.py +667 -0
- package/vendor/chatgpt2api/source/services/content_filter.py +242 -0
- package/vendor/chatgpt2api/source/services/cpa_service.py +315 -0
- package/vendor/chatgpt2api/source/services/editable_file_task_service.py +260 -0
- package/vendor/chatgpt2api/source/services/image_service.py +376 -0
- package/vendor/chatgpt2api/source/services/image_storage_service.py +405 -0
- package/vendor/chatgpt2api/source/services/image_tags_service.py +76 -0
- package/vendor/chatgpt2api/source/services/image_task_service.py +550 -0
- package/vendor/chatgpt2api/source/services/log_service.py +337 -0
- package/vendor/chatgpt2api/source/services/model_service.py +182 -0
- package/vendor/chatgpt2api/source/services/oauth_login_service.py +267 -0
- package/vendor/chatgpt2api/source/services/openai_backend_api.py +2763 -0
- package/vendor/chatgpt2api/source/services/openai_oauth.py +32 -0
- package/vendor/chatgpt2api/source/services/protocol/__init__.py +2 -0
- package/vendor/chatgpt2api/source/services/protocol/anthropic_v1_messages.py +307 -0
- package/vendor/chatgpt2api/source/services/protocol/chat_completion_cache.py +238 -0
- package/vendor/chatgpt2api/source/services/protocol/conversation.py +1644 -0
- package/vendor/chatgpt2api/source/services/protocol/error_response.py +124 -0
- package/vendor/chatgpt2api/source/services/protocol/openai_search.py +19 -0
- package/vendor/chatgpt2api/source/services/protocol/openai_v1_chat_complete.py +316 -0
- package/vendor/chatgpt2api/source/services/protocol/openai_v1_image_edit.py +86 -0
- package/vendor/chatgpt2api/source/services/protocol/openai_v1_image_generations.py +42 -0
- package/vendor/chatgpt2api/source/services/protocol/openai_v1_models.py +53 -0
- package/vendor/chatgpt2api/source/services/protocol/openai_v1_response.py +453 -0
- package/vendor/chatgpt2api/source/services/protocol/web_search_tool.py +160 -0
- package/vendor/chatgpt2api/source/services/proxy_service.py +648 -0
- package/vendor/chatgpt2api/source/services/storage/__init__.py +5 -0
- package/vendor/chatgpt2api/source/services/storage/base.py +38 -0
- package/vendor/chatgpt2api/source/services/storage/database_storage.py +194 -0
- package/vendor/chatgpt2api/source/services/storage/factory.py +104 -0
- package/vendor/chatgpt2api/source/services/storage/git_storage.py +183 -0
- package/vendor/chatgpt2api/source/services/storage/json_storage.py +95 -0
- package/vendor/chatgpt2api/source/services/sub2api_service.py +531 -0
- package/vendor/chatgpt2api/source/utils/__init__.py +0 -0
- package/vendor/chatgpt2api/source/utils/helper.py +469 -0
- package/vendor/chatgpt2api/source/utils/image_tokens.py +346 -0
- package/vendor/chatgpt2api/source/utils/log.py +110 -0
- package/vendor/chatgpt2api/source/utils/pkce.py +19 -0
- package/vendor/chatgpt2api/source/utils/pow.py +207 -0
- package/vendor/chatgpt2api/source/utils/sentinel.py +159 -0
- package/vendor/chatgpt2api/source/utils/turnstile.py +184 -0
- package/vendor/chatgpt2api/source/uv.lock +904 -0
- package/vendor/chatgpt2api/source/web/bun.lock +1501 -0
- package/vendor/chatgpt2api/source/web/components.json +24 -0
- package/vendor/chatgpt2api/source/web/eslint.config.mjs +17 -0
- package/vendor/chatgpt2api/source/web/next.config.ts +40 -0
- package/vendor/chatgpt2api/source/web/package.json +58 -0
- package/vendor/chatgpt2api/source/web/postcss.config.mjs +5 -0
- package/vendor/chatgpt2api/source/web/public/github.svg +1 -0
- package/vendor/chatgpt2api/source/web/public/next.svg +1 -0
- package/vendor/chatgpt2api/source/web/public/openai.svg +1 -0
- package/vendor/chatgpt2api/source/web/public/vercel.svg +1 -0
- package/vendor/chatgpt2api/source/web/src/app/accounts/components/account-import-dialog.tsx +925 -0
- package/vendor/chatgpt2api/source/web/src/app/accounts/page.tsx +1307 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/components/chat-panel.tsx +224 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/components/editable-file-panel.tsx +444 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/components/ppt-panel.tsx +9 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/components/psd-panel.tsx +9 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/components/search-panel.tsx +172 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/components/skill-panel.tsx +169 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/components/types.ts +39 -0
- package/vendor/chatgpt2api/source/web/src/app/debug/page.tsx +59 -0
- package/vendor/chatgpt2api/source/web/src/app/favicon.ico +0 -0
- package/vendor/chatgpt2api/source/web/src/app/globals.css +231 -0
- package/vendor/chatgpt2api/source/web/src/app/image/components/image-composer.tsx +542 -0
- package/vendor/chatgpt2api/source/web/src/app/image/components/image-results.tsx +554 -0
- package/vendor/chatgpt2api/source/web/src/app/image/components/image-sidebar.tsx +176 -0
- package/vendor/chatgpt2api/source/web/src/app/image/page.tsx +1799 -0
- package/vendor/chatgpt2api/source/web/src/app/image-manager/page.tsx +732 -0
- package/vendor/chatgpt2api/source/web/src/app/layout.tsx +50 -0
- package/vendor/chatgpt2api/source/web/src/app/login/page.tsx +101 -0
- package/vendor/chatgpt2api/source/web/src/app/logs/page.tsx +356 -0
- package/vendor/chatgpt2api/source/web/src/app/page.tsx +30 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/api-docs-card.tsx +341 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/backup-settings-card.tsx +447 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/base-url-card.tsx +71 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/config-card.tsx +491 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/cpa-pool-dialog.tsx +108 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/cpa-pools-card.tsx +169 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/import-browser-dialog.tsx +185 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/proxy-runtime-card.tsx +379 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/proxy-settings-card.tsx +127 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/proxy-settings.tsx +200 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/settings-header.tsx +12 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/sub2api-connections.tsx +886 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/third-party-apps-card.tsx +81 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/components/user-keys-card.tsx +422 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/page.tsx +135 -0
- package/vendor/chatgpt2api/source/web/src/app/settings/store.ts +1069 -0
- package/vendor/chatgpt2api/source/web/src/components/date-range-filter.tsx +49 -0
- package/vendor/chatgpt2api/source/web/src/components/header-actions.tsx +24 -0
- package/vendor/chatgpt2api/source/web/src/components/image-lightbox.tsx +434 -0
- package/vendor/chatgpt2api/source/web/src/components/image-thumbnail.tsx +46 -0
- package/vendor/chatgpt2api/source/web/src/components/theme-script.tsx +18 -0
- package/vendor/chatgpt2api/source/web/src/components/theme-toggle.tsx +14 -0
- package/vendor/chatgpt2api/source/web/src/components/top-nav.tsx +263 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/animated-theme-toggler.tsx +256 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/badge.tsx +41 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/button.tsx +59 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/calendar.tsx +46 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/card.tsx +61 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/checkbox.tsx +27 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/dia-text-reveal.tsx +267 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/dialog.tsx +132 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/field.tsx +13 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/input.tsx +19 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/label.tsx +24 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/morphing-text.tsx +149 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/popover.tsx +38 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/select.tsx +175 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/sheet.tsx +143 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/table.tsx +29 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/tabs.tsx +91 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/text-3d-flip.tsx +269 -0
- package/vendor/chatgpt2api/source/web/src/components/ui/textarea.tsx +18 -0
- package/vendor/chatgpt2api/source/web/src/components/version-release-dialog.tsx +127 -0
- package/vendor/chatgpt2api/source/web/src/constants/common-env.ts +6 -0
- package/vendor/chatgpt2api/source/web/src/hooks/use-version-check.ts +85 -0
- package/vendor/chatgpt2api/source/web/src/lib/api.ts +926 -0
- package/vendor/chatgpt2api/source/web/src/lib/auth-session.ts +26 -0
- package/vendor/chatgpt2api/source/web/src/lib/release.ts +25 -0
- package/vendor/chatgpt2api/source/web/src/lib/request.ts +93 -0
- package/vendor/chatgpt2api/source/web/src/lib/use-auth-guard.ts +89 -0
- package/vendor/chatgpt2api/source/web/src/lib/utils.ts +6 -0
- package/vendor/chatgpt2api/source/web/src/store/auth.ts +112 -0
- package/vendor/chatgpt2api/source/web/src/store/editable-file-history.ts +33 -0
- package/vendor/chatgpt2api/source/web/src/store/image-conversations.ts +318 -0
- package/vendor/chatgpt2api/source/web/tsconfig.json +42 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="24 20 378 110" role="img" aria-labelledby="kri-horizontal-title">
|
|
2
|
+
<title id="kri-horizontal-title">坤肉AI 横版标志</title>
|
|
3
|
+
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="kri-horizontal-upper" gradientUnits="userSpaceOnUse" x1="64" y1="29" x2="78" y2="103">
|
|
6
|
+
<stop offset="0" stop-color="#CA47F4"/>
|
|
7
|
+
<stop offset=".44" stop-color="#8650FC"/>
|
|
8
|
+
<stop offset=".75" stop-color="#5855FF"/>
|
|
9
|
+
<stop offset="1" stop-color="#326CFF"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
<linearGradient id="kri-horizontal-shine" gradientUnits="userSpaceOnUse" x1="82" y1="60" x2="139" y2="60">
|
|
12
|
+
<stop offset="0" stop-color="#74CEF1" stop-opacity="0"/>
|
|
13
|
+
<stop offset="1" stop-color="#74CEF1"/>
|
|
14
|
+
</linearGradient>
|
|
15
|
+
<linearGradient id="kri-horizontal-lower" gradientUnits="userSpaceOnUse" x1="76" y1="88" x2="119" y2="133">
|
|
16
|
+
<stop offset="0" stop-color="#1640C2"/>
|
|
17
|
+
<stop offset=".5" stop-color="#176BEA"/>
|
|
18
|
+
<stop offset="1" stop-color="#269DF5"/>
|
|
19
|
+
</linearGradient>
|
|
20
|
+
<linearGradient id="kri-horizontal-back" gradientUnits="userSpaceOnUse" x1="86" y1="57" x2="145" y2="59">
|
|
21
|
+
<stop offset="0" stop-color="#9854FC"/>
|
|
22
|
+
<stop offset=".6" stop-color="#6FBCF7"/>
|
|
23
|
+
<stop offset="1" stop-color="#2DC9EF"/>
|
|
24
|
+
</linearGradient>
|
|
25
|
+
<linearGradient id="kri-horizontal-orbit" gradientUnits="userSpaceOnUse" x1="45" y1="73" x2="68" y2="118">
|
|
26
|
+
<stop offset="0" stop-color="#6849FF"/>
|
|
27
|
+
<stop offset=".26" stop-color="#3D7CFF"/>
|
|
28
|
+
<stop offset=".59" stop-color="#30C5F5"/>
|
|
29
|
+
<stop offset=".8" stop-color="#B2F0FF"/>
|
|
30
|
+
</linearGradient>
|
|
31
|
+
<linearGradient id="kri-horizontal-star" gradientUnits="userSpaceOnUse" x1="143" y1="24" x2="156" y2="39">
|
|
32
|
+
<stop offset="0" stop-color="#348BF2"/>
|
|
33
|
+
<stop offset="1" stop-color="#42C4F6"/>
|
|
34
|
+
</linearGradient>
|
|
35
|
+
<linearGradient id="kri-horizontal-text" gradientUnits="userSpaceOnUse" x1="184" y1="75" x2="398" y2="75">
|
|
36
|
+
<stop offset="0" stop-color="#8650FC"/>
|
|
37
|
+
<stop offset=".55" stop-color="#326CFF"/>
|
|
38
|
+
<stop offset="1" stop-color="#269DF5"/>
|
|
39
|
+
</linearGradient>
|
|
40
|
+
</defs>
|
|
41
|
+
|
|
42
|
+
<path fill="url(#kri-horizontal-back)" d="M85.2 55.2C90.6 53 96.2 50.8 101.7 49.4L97.6 53.4C93.6 55.3 89.4 57.4 85.2 59ZM111.8 44.3C127.9 42.4 141.2 42.5 146.1 49.4C153.3 59.7 132.4 73 119.3 77.4C130.8 68.1 143.2 56.8 136.4 51.6C132.4 48.5 124.2 48.5 115.8 50Z"/>
|
|
43
|
+
<path fill="url(#kri-horizontal-lower)" d="M56.4 101.4C74.9 97.1 95.3 89.7 111.5 82.6L146.9 121.8H118.3C115.5 121.8 113.7 120.9 111.8 118.7L90.1 94.2L86.4 98.3C83.3 101.2 82.2 103.8 82.2 107.2V110.8C82.2 121.3 74.3 129.3 64.1 129.3H56.4Z"/>
|
|
44
|
+
<path fill="url(#kri-horizontal-upper)" d="M56.4 99.4V47.5C56.4 37.2 63.5 29.5 74.1 29.5H82.2V74.8L109.8 46.5C111.7 44.5 113.1 43.7 116 43.7H137.2L108.4 78.9C91.7 87.1 74.1 94.3 56.4 99.4Z"/>
|
|
45
|
+
<path fill="url(#kri-horizontal-shine)" d="M56.4 99.4V47.5C56.4 37.2 63.5 29.5 74.1 29.5H82.2V74.8L109.8 46.5C111.7 44.5 113.1 43.7 116 43.7H137.2L108.4 78.9C91.7 87.1 74.1 94.3 56.4 99.4Z"/>
|
|
46
|
+
<path fill="url(#kri-horizontal-orbit)" d="M52.4 70.6C39.3 78.8 24.6 91.5 24.7 98C24.9 112.4 67.4 106.5 110.3 80.6L108.4 78.9C76.7 93.5 43.8 102.9 36.6 96.1C31.1 90.9 44.2 79.7 52.4 75Z"/>
|
|
47
|
+
<path fill="url(#kri-horizontal-star)" d="M149.4 20.5C150.5 27.7 153.5 30.5 160.5 31.7C153.5 32.9 150.5 36 149.4 43.1C148.2 36 145.3 32.9 138.3 31.7C145.3 30.5 148.2 27.7 149.4 20.5Z"/>
|
|
48
|
+
|
|
49
|
+
<text x="184" y="100" fill="url(#kri-horizontal-text)" font-family="'PingFang SC', 'Microsoft YaHei', sans-serif" font-size="66" font-weight="700" letter-spacing="1">坤肉AI</text>
|
|
50
|
+
</svg>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"auth-key": "",
|
|
3
|
+
"refresh_account_interval_minute": 5,
|
|
4
|
+
"image_retention_days": 15,
|
|
5
|
+
"image_poll_timeout_secs": 120,
|
|
6
|
+
"auto_remove_rate_limited_accounts": false,
|
|
7
|
+
"auto_remove_invalid_accounts": false,
|
|
8
|
+
"log_levels": [
|
|
9
|
+
"debug",
|
|
10
|
+
"error",
|
|
11
|
+
"info",
|
|
12
|
+
"warning"
|
|
13
|
+
],
|
|
14
|
+
"proxy": "",
|
|
15
|
+
"proxy_runtime": {
|
|
16
|
+
"enabled": false,
|
|
17
|
+
"egress_mode": "single_proxy",
|
|
18
|
+
"proxy_url": "",
|
|
19
|
+
"resource_proxy_url": "",
|
|
20
|
+
"skip_ssl_verify": false,
|
|
21
|
+
"reset_session_status_codes": [
|
|
22
|
+
403
|
|
23
|
+
],
|
|
24
|
+
"clearance": {
|
|
25
|
+
"enabled": false,
|
|
26
|
+
"mode": "flaresolverr",
|
|
27
|
+
"cf_cookies": "",
|
|
28
|
+
"cf_clearance": "",
|
|
29
|
+
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
|
|
30
|
+
"browser": "chrome",
|
|
31
|
+
"flaresolverr_url": "http://flaresolverr:8191",
|
|
32
|
+
"timeout_sec": 60,
|
|
33
|
+
"refresh_interval": 3600,
|
|
34
|
+
"warm_up_on_start": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"base_url": "",
|
|
38
|
+
"sensitive_words": [],
|
|
39
|
+
"global_system_prompt": "",
|
|
40
|
+
"default_upstream_model_name": "gpt-5-5",
|
|
41
|
+
"default_thinking_effort": "auto",
|
|
42
|
+
"ai_review": {
|
|
43
|
+
"enabled": false,
|
|
44
|
+
"base_url": "",
|
|
45
|
+
"api_key": "",
|
|
46
|
+
"model": "",
|
|
47
|
+
"prompt": ""
|
|
48
|
+
},
|
|
49
|
+
"backup": {
|
|
50
|
+
"enabled": false,
|
|
51
|
+
"provider": "cloudflare_r2",
|
|
52
|
+
"account_id": "admin",
|
|
53
|
+
"access_key_id": "",
|
|
54
|
+
"secret_access_key": "",
|
|
55
|
+
"bucket": "",
|
|
56
|
+
"prefix": "backups",
|
|
57
|
+
"interval_minutes": 1440,
|
|
58
|
+
"rotation_keep": 10,
|
|
59
|
+
"encrypt": false,
|
|
60
|
+
"passphrase": "",
|
|
61
|
+
"include": {
|
|
62
|
+
"config": true,
|
|
63
|
+
"cpa": true,
|
|
64
|
+
"sub2api": true,
|
|
65
|
+
"logs": true,
|
|
66
|
+
"image_tasks": true,
|
|
67
|
+
"accounts_snapshot": true,
|
|
68
|
+
"auth_keys_snapshot": true,
|
|
69
|
+
"images": false
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"image_account_concurrency": 3,
|
|
73
|
+
"image_parallel_generation": true,
|
|
74
|
+
"image_poll_interval_secs": 10,
|
|
75
|
+
"image_poll_initial_wait_secs": 10,
|
|
76
|
+
"image_storage": {
|
|
77
|
+
"enabled": false,
|
|
78
|
+
"mode": "local",
|
|
79
|
+
"webdav_url": "",
|
|
80
|
+
"webdav_username": "",
|
|
81
|
+
"webdav_password": "",
|
|
82
|
+
"webdav_root_path": "chatgpt2api/images",
|
|
83
|
+
"public_base_url": ""
|
|
84
|
+
},
|
|
85
|
+
"image_min_free_mb": 500,
|
|
86
|
+
"chat_completion_cache": {
|
|
87
|
+
"enabled": true,
|
|
88
|
+
"ttl_seconds": 60,
|
|
89
|
+
"max_entries": 256,
|
|
90
|
+
"dedupe_inflight": true,
|
|
91
|
+
"stream_cache": true,
|
|
92
|
+
"normalize_messages": true,
|
|
93
|
+
"drop_adjacent_duplicates": true,
|
|
94
|
+
"drop_assistant_history": false
|
|
95
|
+
},
|
|
96
|
+
"image_settle_enabled": false,
|
|
97
|
+
"image_check_before_hit_enabled": false,
|
|
98
|
+
"image_settle_secs": 2,
|
|
99
|
+
"auto_relogin_after_refresh": false,
|
|
100
|
+
"image_timeout_retry_secs": 30,
|
|
101
|
+
"third_party_apps": {
|
|
102
|
+
"infinite_canvas": {
|
|
103
|
+
"enabled": true,
|
|
104
|
+
"url": "https://canvas.best"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"image_remove_conversation_after_result": true
|
|
108
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "chatgpt2api"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"curl-cffi>=0.15.0",
|
|
9
|
+
"fastapi>=0.136.0",
|
|
10
|
+
"pillow>=12.2.0",
|
|
11
|
+
"pybase64>=1.4.3",
|
|
12
|
+
"python-multipart>=0.0.26",
|
|
13
|
+
"tiktoken>=0.12.0",
|
|
14
|
+
"uvicorn>=0.44.0",
|
|
15
|
+
"sqlalchemy>=2.0.0",
|
|
16
|
+
"psycopg2-binary>=2.9.0",
|
|
17
|
+
"gitpython>=3.1.0",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[dependency-groups]
|
|
21
|
+
dev = [
|
|
22
|
+
"httpx>=0.28.1",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[[tool.uv.index]]
|
|
26
|
+
url = "https://mirrors.aliyun.com/pypi/simple"
|
|
27
|
+
default = true
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Idempotently merge WARP/FlareSolverr proxy_runtime defaults into config.json."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import copy
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
DEFAULT_USER_AGENT = (
|
|
15
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
|
16
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
17
|
+
"Chrome/145.0.0.0 Safari/537.36"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
DEFAULT_PROXY_RUNTIME: dict[str, Any] = {
|
|
21
|
+
"enabled": False,
|
|
22
|
+
"egress_mode": "direct",
|
|
23
|
+
"proxy_url": "",
|
|
24
|
+
"resource_proxy_url": "",
|
|
25
|
+
"skip_ssl_verify": False,
|
|
26
|
+
"reset_session_status_codes": [403],
|
|
27
|
+
"clearance": {
|
|
28
|
+
"enabled": False,
|
|
29
|
+
"mode": "none",
|
|
30
|
+
"cf_cookies": "",
|
|
31
|
+
"cf_clearance": "",
|
|
32
|
+
"user_agent": DEFAULT_USER_AGENT,
|
|
33
|
+
"browser": "chrome",
|
|
34
|
+
"flaresolverr_url": "",
|
|
35
|
+
"timeout_sec": 60,
|
|
36
|
+
"refresh_interval": 3600,
|
|
37
|
+
"warm_up_on_start": False,
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _env_bool(name: str, default: bool) -> bool:
|
|
43
|
+
value = os.getenv(name)
|
|
44
|
+
if value is None:
|
|
45
|
+
return default
|
|
46
|
+
lowered = value.strip().lower()
|
|
47
|
+
if lowered in {"1", "true", "yes", "on"}:
|
|
48
|
+
return True
|
|
49
|
+
if lowered in {"0", "false", "no", "off"}:
|
|
50
|
+
return False
|
|
51
|
+
return default
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _env_int(name: str, default: int, minimum: int = 0) -> int:
|
|
55
|
+
try:
|
|
56
|
+
return max(minimum, int(os.getenv(name, str(default))))
|
|
57
|
+
except (TypeError, ValueError, OverflowError):
|
|
58
|
+
return default
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _warp_runtime_defaults() -> dict[str, Any]:
|
|
62
|
+
clearance_enabled = _env_bool("CHATGPT2API_PROXY_RUNTIME_CLEARANCE_ENABLED", True)
|
|
63
|
+
clearance_mode = os.getenv("CHATGPT2API_PROXY_RUNTIME_CLEARANCE_MODE", "flaresolverr").strip().lower()
|
|
64
|
+
if clearance_mode not in {"none", "manual", "flaresolverr"}:
|
|
65
|
+
clearance_mode = "flaresolverr" if clearance_enabled else "none"
|
|
66
|
+
if not clearance_enabled:
|
|
67
|
+
clearance_mode = "none"
|
|
68
|
+
|
|
69
|
+
egress_mode = os.getenv("CHATGPT2API_PROXY_RUNTIME_EGRESS_MODE", "single_proxy").strip().lower()
|
|
70
|
+
if egress_mode not in {"direct", "single_proxy"}:
|
|
71
|
+
egress_mode = "single_proxy"
|
|
72
|
+
|
|
73
|
+
runtime = copy.deepcopy(DEFAULT_PROXY_RUNTIME)
|
|
74
|
+
runtime.update(
|
|
75
|
+
{
|
|
76
|
+
"enabled": _env_bool("CHATGPT2API_PROXY_RUNTIME_ENABLED", True),
|
|
77
|
+
"egress_mode": egress_mode,
|
|
78
|
+
"proxy_url": os.getenv("CHATGPT2API_PROXY_RUNTIME_PROXY_URL", "http://privoxy:8118").strip(),
|
|
79
|
+
"resource_proxy_url": os.getenv("CHATGPT2API_PROXY_RUNTIME_RESOURCE_PROXY_URL", "").strip(),
|
|
80
|
+
"skip_ssl_verify": _env_bool("CHATGPT2API_PROXY_RUNTIME_SKIP_SSL_VERIFY", False),
|
|
81
|
+
"reset_session_status_codes": [
|
|
82
|
+
int(part.strip())
|
|
83
|
+
for part in os.getenv("CHATGPT2API_PROXY_RUNTIME_RESET_STATUS_CODES", "403").split(",")
|
|
84
|
+
if part.strip().isdigit() and 100 <= int(part.strip()) <= 599
|
|
85
|
+
] or [403],
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
runtime["clearance"].update(
|
|
89
|
+
{
|
|
90
|
+
"enabled": clearance_enabled,
|
|
91
|
+
"mode": clearance_mode,
|
|
92
|
+
"user_agent": os.getenv("CHATGPT2API_PROXY_RUNTIME_USER_AGENT", DEFAULT_USER_AGENT).strip() or DEFAULT_USER_AGENT,
|
|
93
|
+
"browser": os.getenv("CHATGPT2API_PROXY_RUNTIME_BROWSER", "chrome").strip() or "chrome",
|
|
94
|
+
"flaresolverr_url": os.getenv("CHATGPT2API_FLARESOLVERR_URL", "http://flaresolverr:8191").strip(),
|
|
95
|
+
"timeout_sec": _env_int("CHATGPT2API_PROXY_RUNTIME_CLEARANCE_TIMEOUT_SEC", 60, 1),
|
|
96
|
+
"refresh_interval": _env_int("CHATGPT2API_PROXY_RUNTIME_CLEARANCE_REFRESH_INTERVAL", 3600, 60),
|
|
97
|
+
"warm_up_on_start": _env_bool("CHATGPT2API_PROXY_RUNTIME_WARM_UP_ON_START", False),
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
return runtime
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _deep_fill_missing(target: dict[str, Any], defaults: dict[str, Any]) -> bool:
|
|
104
|
+
changed = False
|
|
105
|
+
for key, value in defaults.items():
|
|
106
|
+
if key not in target:
|
|
107
|
+
target[key] = copy.deepcopy(value)
|
|
108
|
+
changed = True
|
|
109
|
+
continue
|
|
110
|
+
if isinstance(target[key], dict) and isinstance(value, dict):
|
|
111
|
+
changed = _deep_fill_missing(target[key], value) or changed
|
|
112
|
+
return changed
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _looks_like_repository_default(runtime: Any) -> bool:
|
|
116
|
+
if not isinstance(runtime, dict):
|
|
117
|
+
return True
|
|
118
|
+
candidate = copy.deepcopy(runtime)
|
|
119
|
+
_deep_fill_missing(candidate, DEFAULT_PROXY_RUNTIME)
|
|
120
|
+
return candidate == DEFAULT_PROXY_RUNTIME
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _mask_url(value: str) -> str:
|
|
124
|
+
return re.sub(r"(https?://)([^\s/@:]+):([^\s/@]+)@", r"\1[REDACTED]@", value or "", flags=re.I)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main() -> int:
|
|
128
|
+
config_path = Path(os.getenv("CHATGPT2API_CONFIG_FILE", "/app/config.json"))
|
|
129
|
+
if not config_path.exists():
|
|
130
|
+
print(f"Config file not found, creating {config_path}")
|
|
131
|
+
data: dict[str, Any] = {}
|
|
132
|
+
else:
|
|
133
|
+
try:
|
|
134
|
+
data = json.loads(config_path.read_text(encoding="utf-8"))
|
|
135
|
+
except json.JSONDecodeError as exc:
|
|
136
|
+
print(f"Invalid JSON in {config_path}: {exc}", file=sys.stderr)
|
|
137
|
+
return 1
|
|
138
|
+
if not isinstance(data, dict):
|
|
139
|
+
print(f"Config root must be an object: {config_path}", file=sys.stderr)
|
|
140
|
+
return 1
|
|
141
|
+
|
|
142
|
+
desired = _warp_runtime_defaults()
|
|
143
|
+
existing = data.get("proxy_runtime")
|
|
144
|
+
changed = False
|
|
145
|
+
|
|
146
|
+
if _looks_like_repository_default(existing) or _env_bool("CHATGPT2API_PROXY_RUNTIME_FORCE", False):
|
|
147
|
+
data["proxy_runtime"] = desired
|
|
148
|
+
changed = True
|
|
149
|
+
print("Created proxy_runtime defaults")
|
|
150
|
+
else:
|
|
151
|
+
runtime = existing if isinstance(existing, dict) else {}
|
|
152
|
+
changed = _deep_fill_missing(runtime, DEFAULT_PROXY_RUNTIME)
|
|
153
|
+
data["proxy_runtime"] = runtime
|
|
154
|
+
print("Proxy runtime already configured")
|
|
155
|
+
|
|
156
|
+
if changed:
|
|
157
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
158
|
+
payload = json.dumps(data, ensure_ascii=False, indent=2) + "\n"
|
|
159
|
+
tmp_path = config_path.with_suffix(config_path.suffix + ".tmp")
|
|
160
|
+
try:
|
|
161
|
+
tmp_path.write_text(payload, encoding="utf-8")
|
|
162
|
+
tmp_path.replace(config_path)
|
|
163
|
+
except OSError as exc:
|
|
164
|
+
# Docker bind-mounted single files can reject atomic rename with EBUSY.
|
|
165
|
+
# Fall back to in-place write so the init job works with both file and
|
|
166
|
+
# directory mounts.
|
|
167
|
+
if getattr(exc, "errno", None) != 16:
|
|
168
|
+
raise
|
|
169
|
+
config_path.write_text(payload, encoding="utf-8")
|
|
170
|
+
tmp_path.unlink(missing_ok=True)
|
|
171
|
+
|
|
172
|
+
runtime = data.get("proxy_runtime") if isinstance(data.get("proxy_runtime"), dict) else {}
|
|
173
|
+
clearance = runtime.get("clearance") if isinstance(runtime.get("clearance"), dict) else {}
|
|
174
|
+
print(
|
|
175
|
+
"Proxy runtime summary: "
|
|
176
|
+
f"enabled={bool(runtime.get('enabled'))}, "
|
|
177
|
+
f"egress_mode={runtime.get('egress_mode')}, "
|
|
178
|
+
f"proxy_url={_mask_url(str(runtime.get('proxy_url') or ''))}, "
|
|
179
|
+
f"clearance_mode={clearance.get('mode')}, "
|
|
180
|
+
f"flaresolverr_url={_mask_url(str(clearance.get('flaresolverr_url') or ''))}"
|
|
181
|
+
)
|
|
182
|
+
return 0
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
if __name__ == "__main__":
|
|
186
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
存储后端数据迁移脚本
|
|
4
|
+
|
|
5
|
+
用法:
|
|
6
|
+
python scripts/migrate_storage.py --from json --to postgres
|
|
7
|
+
python scripts/migrate_storage.py --from postgres --to git
|
|
8
|
+
python scripts/migrate_storage.py --export accounts.json
|
|
9
|
+
python scripts/migrate_storage.py --import accounts.json
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
# 添加项目根目录到 Python 路径
|
|
19
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
20
|
+
|
|
21
|
+
DATA_DIR = Path(__file__).resolve().parents[1] / "data"
|
|
22
|
+
|
|
23
|
+
from services.storage.factory import create_storage_backend
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def export_to_json(output_file: str):
|
|
27
|
+
"""导出当前存储后端的数据到 JSON 文件"""
|
|
28
|
+
print(f"[migrate] Exporting data to {output_file}")
|
|
29
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
30
|
+
storage = create_storage_backend(DATA_DIR)
|
|
31
|
+
accounts = storage.load_accounts()
|
|
32
|
+
|
|
33
|
+
output_path = Path(output_file)
|
|
34
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
output_path.write_text(
|
|
36
|
+
json.dumps(accounts, ensure_ascii=False, indent=2) + "\n",
|
|
37
|
+
encoding="utf-8",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
print(f"[migrate] Exported {len(accounts)} accounts to {output_file}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def import_from_json(input_file: str):
|
|
44
|
+
"""从 JSON 文件导入数据到当前存储后端"""
|
|
45
|
+
print(f"[migrate] Importing data from {input_file}")
|
|
46
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
input_path = Path(input_file)
|
|
48
|
+
if not input_path.exists():
|
|
49
|
+
print(f"[migrate] Error: File not found: {input_file}")
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
accounts = json.loads(input_path.read_text(encoding="utf-8"))
|
|
54
|
+
if not isinstance(accounts, list):
|
|
55
|
+
print(f"[migrate] Error: Invalid JSON format, expected array")
|
|
56
|
+
sys.exit(1)
|
|
57
|
+
except json.JSONDecodeError as e:
|
|
58
|
+
print(f"[migrate] Error: Invalid JSON: {e}")
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
|
|
61
|
+
storage = create_storage_backend(DATA_DIR)
|
|
62
|
+
storage.save_accounts(accounts)
|
|
63
|
+
|
|
64
|
+
print(f"[migrate] Imported {len(accounts)} accounts")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def migrate_data(from_backend: str, to_backend: str):
|
|
68
|
+
"""从一个存储后端迁移到另一个"""
|
|
69
|
+
print(f"[migrate] Migrating from {from_backend} to {to_backend}")
|
|
70
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
71
|
+
# 保存原始环境变量
|
|
72
|
+
original_backend = os.environ.get("STORAGE_BACKEND")
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
# 从源后端读取数据
|
|
76
|
+
os.environ["STORAGE_BACKEND"] = from_backend
|
|
77
|
+
from_storage = create_storage_backend(DATA_DIR)
|
|
78
|
+
accounts = from_storage.load_accounts()
|
|
79
|
+
print(f"[migrate] Loaded {len(accounts)} accounts from {from_backend}")
|
|
80
|
+
|
|
81
|
+
# 写入目标后端
|
|
82
|
+
os.environ["STORAGE_BACKEND"] = to_backend
|
|
83
|
+
to_storage = create_storage_backend(DATA_DIR)
|
|
84
|
+
to_storage.save_accounts(accounts)
|
|
85
|
+
print(f"[migrate] Saved {len(accounts)} accounts to {to_backend}")
|
|
86
|
+
|
|
87
|
+
print(f"[migrate] Migration completed successfully!")
|
|
88
|
+
|
|
89
|
+
finally:
|
|
90
|
+
# 恢复原始环境变量
|
|
91
|
+
if original_backend:
|
|
92
|
+
os.environ["STORAGE_BACKEND"] = original_backend
|
|
93
|
+
elif "STORAGE_BACKEND" in os.environ:
|
|
94
|
+
del os.environ["STORAGE_BACKEND"]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main():
|
|
98
|
+
parser = argparse.ArgumentParser(
|
|
99
|
+
description="ChatGPT2API 存储后端数据迁移工具",
|
|
100
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
101
|
+
epilog="""
|
|
102
|
+
示例:
|
|
103
|
+
# 从 JSON 迁移到 PostgreSQL
|
|
104
|
+
python scripts/migrate_storage.py --from json --to postgres
|
|
105
|
+
|
|
106
|
+
# 从 PostgreSQL 迁移到 Git
|
|
107
|
+
python scripts/migrate_storage.py --from postgres --to git
|
|
108
|
+
|
|
109
|
+
# 导出当前数据到 JSON 文件
|
|
110
|
+
python scripts/migrate_storage.py --export backup.json
|
|
111
|
+
|
|
112
|
+
# 从 JSON 文件导入数据
|
|
113
|
+
python scripts/migrate_storage.py --import backup.json
|
|
114
|
+
|
|
115
|
+
环境变量:
|
|
116
|
+
STORAGE_BACKEND - 存储后端类型 (json, sqlite, postgres, git)
|
|
117
|
+
DATABASE_URL - 数据库连接字符串
|
|
118
|
+
GIT_REPO_URL - Git 仓库地址
|
|
119
|
+
GIT_TOKEN - Git 访问令牌
|
|
120
|
+
"""
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
parser.add_argument(
|
|
124
|
+
"--from",
|
|
125
|
+
dest="from_backend",
|
|
126
|
+
choices=["json", "sqlite", "postgres", "git"],
|
|
127
|
+
help="源存储后端",
|
|
128
|
+
)
|
|
129
|
+
parser.add_argument(
|
|
130
|
+
"--to",
|
|
131
|
+
dest="to_backend",
|
|
132
|
+
choices=["json", "sqlite", "postgres", "git"],
|
|
133
|
+
help="目标存储后端",
|
|
134
|
+
)
|
|
135
|
+
parser.add_argument(
|
|
136
|
+
"--export",
|
|
137
|
+
dest="export_file",
|
|
138
|
+
metavar="FILE",
|
|
139
|
+
help="导出数据到 JSON 文件",
|
|
140
|
+
)
|
|
141
|
+
parser.add_argument(
|
|
142
|
+
"--import",
|
|
143
|
+
dest="import_file",
|
|
144
|
+
metavar="FILE",
|
|
145
|
+
help="从 JSON 文件导入数据",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
args = parser.parse_args()
|
|
149
|
+
|
|
150
|
+
# 检查参数
|
|
151
|
+
if args.from_backend and args.to_backend:
|
|
152
|
+
migrate_data(args.from_backend, args.to_backend)
|
|
153
|
+
elif args.export_file:
|
|
154
|
+
export_to_json(args.export_file)
|
|
155
|
+
elif args.import_file:
|
|
156
|
+
import_from_json(args.import_file)
|
|
157
|
+
else:
|
|
158
|
+
parser.print_help()
|
|
159
|
+
sys.exit(1)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
main()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
listen-address 0.0.0.0:8118
|
|
2
|
+
toggle 1
|
|
3
|
+
enable-remote-toggle 0
|
|
4
|
+
enable-remote-http-toggle 0
|
|
5
|
+
enable-edit-actions 0
|
|
6
|
+
enforce-blocks 0
|
|
7
|
+
buffer-limit 4096
|
|
8
|
+
keep-alive-timeout 300
|
|
9
|
+
socket-timeout 300
|
|
10
|
+
|
|
11
|
+
# Forward every HTTP/HTTPS request through the WARP SOCKS5 proxy.
|
|
12
|
+
# The trailing dot is required by Privoxy syntax.
|
|
13
|
+
forward-socks5t / warp-proxy:1080 .
|