diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index c9dc57bb..5b7a01cc 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -51,7 +51,7 @@ func main() { flag.Parse() if *showVersion { - log.Printf("Sub2API %s (commit: %s, built: %s)\n", Version, Commit, Date) + log.Printf("TianShuAPI %s (commit: %s, built: %s)\n", Version, Commit, Date) return } @@ -101,7 +101,7 @@ func runSetupServer() { // This allows users to run setup on a different address if needed addr := config.GetServerAddress() log.Printf("Setup wizard available at http://%s", addr) - log.Println("Complete the setup wizard to configure Sub2API") + log.Println("Complete the setup wizard to configure TianShuAPI") if err := r.Run(addr); err != nil { log.Fatalf("Failed to start setup server: %v", err) diff --git a/backend/internal/repository/github_release_service.go b/backend/internal/repository/github_release_service.go index 77839626..f38d4d13 100644 --- a/backend/internal/repository/github_release_service.go +++ b/backend/internal/repository/github_release_service.go @@ -52,7 +52,7 @@ func (c *githubReleaseClient) FetchLatestRelease(ctx context.Context, repo strin return nil, err } req.Header.Set("Accept", "application/vnd.github.v3+json") - req.Header.Set("User-Agent", "Sub2API-Updater") + req.Header.Set("User-Agent", "TianShuAPI-Updater") resp, err := c.httpClient.Do(req) if err != nil { diff --git a/backend/internal/repository/github_release_service_test.go b/backend/internal/repository/github_release_service_test.go index d375a193..291da3b1 100644 --- a/backend/internal/repository/github_release_service_test.go +++ b/backend/internal/repository/github_release_service_test.go @@ -223,7 +223,7 @@ func (s *GitHubReleaseServiceSuite) TestFetchLatestRelease_Success() { s.srv = newLocalTestServer(s.T(), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(s.T(), "/repos/test/repo/releases/latest", r.URL.Path) require.Equal(s.T(), "application/vnd.github.v3+json", r.Header.Get("Accept")) - require.Equal(s.T(), "Sub2API-Updater", r.Header.Get("User-Agent")) + require.Equal(s.T(), "TianShuAPI-Updater", r.Header.Get("User-Agent")) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(releaseJSON)) diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index 356b4a4e..28cab36c 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -272,14 +272,14 @@ func TestAPIContracts(t *testing.T) { service.SettingKeySMTPUsername: "user", service.SettingKeySMTPPassword: "secret", service.SettingKeySMTPFrom: "no-reply@example.com", - service.SettingKeySMTPFromName: "Sub2API", + service.SettingKeySMTPFromName: "TianShuAPI", service.SettingKeySMTPUseTLS: "true", service.SettingKeyTurnstileEnabled: "true", service.SettingKeyTurnstileSiteKey: "site-key", service.SettingKeyTurnstileSecretKey: "secret-key", - service.SettingKeySiteName: "Sub2API", + service.SettingKeySiteName: "TianShuAPI", service.SettingKeySiteLogo: "", service.SettingKeySiteSubtitle: "Subtitle", service.SettingKeyAPIBaseURL: "https://api.example.com", @@ -309,7 +309,7 @@ func TestAPIContracts(t *testing.T) { "smtp_username": "user", "smtp_password_configured": true, "smtp_from_email": "no-reply@example.com", - "smtp_from_name": "Sub2API", + "smtp_from_name": "TianShuAPI", "smtp_use_tls": true, "turnstile_enabled": true, "turnstile_site_key": "site-key", @@ -322,7 +322,7 @@ func TestAPIContracts(t *testing.T) { "ops_realtime_monitoring_enabled": true, "ops_query_mode_default": "auto", "ops_metrics_interval_seconds": 60, - "site_name": "Sub2API", + "site_name": "TianShuAPI", "site_logo": "", "site_subtitle": "Subtitle", "api_base_url": "https://api.example.com", diff --git a/backend/internal/service/auth_service.go b/backend/internal/service/auth_service.go index 386b43fc..2bb46c87 100644 --- a/backend/internal/service/auth_service.go +++ b/backend/internal/service/auth_service.go @@ -207,7 +207,7 @@ func (s *AuthService) SendVerifyCode(ctx context.Context, email string) error { } // 获取网站名称 - siteName := "Sub2API" + siteName := "TianShuAPI" if s.settingService != nil { siteName = s.settingService.GetSiteName(ctx) } @@ -247,7 +247,7 @@ func (s *AuthService) SendVerifyCodeAsync(ctx context.Context, email string) (*S } // 获取网站名称 - siteName := "Sub2API" + siteName := "TianShuAPI" if s.settingService != nil { siteName = s.settingService.GetSiteName(ctx) } diff --git a/backend/internal/service/setting_service.go b/backend/internal/service/setting_service.go index 0a7426f8..6e026b90 100644 --- a/backend/internal/service/setting_service.go +++ b/backend/internal/service/setting_service.go @@ -89,7 +89,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings EmailVerifyEnabled: settings[SettingKeyEmailVerifyEnabled] == "true", TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true", TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey], - SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"), + SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "TianShuAPI"), SiteLogo: settings[SettingKeySiteLogo], SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"), APIBaseURL: settings[SettingKeyAPIBaseURL], @@ -247,7 +247,7 @@ func (s *SettingService) IsEmailVerifyEnabled(ctx context.Context) bool { func (s *SettingService) GetSiteName(ctx context.Context) string { value, err := s.settingRepo.GetValue(ctx, SettingKeySiteName) if err != nil || value == "" { - return "Sub2API" + return "TianShuAPI" } return value } @@ -292,7 +292,7 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error { defaults := map[string]string{ SettingKeyRegistrationEnabled: "true", SettingKeyEmailVerifyEnabled: "false", - SettingKeySiteName: "Sub2API", + SettingKeySiteName: "TianShuAPI", SettingKeySiteLogo: "", SettingKeyDefaultConcurrency: strconv.Itoa(s.cfg.Default.UserConcurrency), SettingKeyDefaultBalance: strconv.FormatFloat(s.cfg.Default.UserBalance, 'f', 8, 64), @@ -332,7 +332,7 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true", TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey], TurnstileSecretKeyConfigured: settings[SettingKeyTurnstileSecretKey] != "", - SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"), + SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "TianShuAPI"), SiteLogo: settings[SettingKeySiteLogo], SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"), APIBaseURL: settings[SettingKeyAPIBaseURL], diff --git a/backend/internal/setup/cli.go b/backend/internal/setup/cli.go index 03ac3f66..a0a74a63 100644 --- a/backend/internal/setup/cli.go +++ b/backend/internal/setup/cli.go @@ -51,7 +51,7 @@ func RunCLI() error { fmt.Println() fmt.Println("╔═══════════════════════════════════════════╗") - fmt.Println("║ Sub2API Installation Wizard ║") + fmt.Println("║ TianShuAPI Installation Wizard ║") fmt.Println("╚═══════════════════════════════════════════╝") fmt.Println() diff --git a/deploy/Untitled b/deploy/Untitled new file mode 100644 index 00000000..26e73d2c --- /dev/null +++ b/deploy/Untitled @@ -0,0 +1 @@ +docker-compose.1panel.yml \ No newline at end of file diff --git a/deploy/docker-compose.1panel.yml b/deploy/docker-compose.1panel.yml new file mode 100644 index 00000000..ee628ba0 --- /dev/null +++ b/deploy/docker-compose.1panel.yml @@ -0,0 +1,130 @@ +# ============================================================================= +# TianShuAPI Docker Compose - 1Panel 环境配置 +# ============================================================================= +# 此配置文件适用于已有 1Panel 环境,复用现有 Redis +# ============================================================================= + +services: + # =========================================================================== + # TianShuAPI Application + # =========================================================================== + sub2api: + # 方式1:使用官方镜像(快速部署) + # image: weishaw/sub2api:latest + + # 方式2:从本地代码构建(二次开发) + build: + context: ../ + dockerfile: Dockerfile + args: + - BUILD_TAGS=embed + image: sub2api:local + container_name: sub2api + restart: unless-stopped + ulimits: + nofile: + soft: 100000 + hard: 100000 + ports: + - "${BIND_HOST:-0.0.0.0}:${SERVER_PORT:-8080}:8080" + volumes: + - sub2api_data:/app/data + environment: + # Auto Setup + - AUTO_SETUP=true + + # Server Configuration + - SERVER_HOST=0.0.0.0 + - SERVER_PORT=8080 + - SERVER_MODE=${SERVER_MODE:-release} + - RUN_MODE=${RUN_MODE:-standard} + + # Database Configuration + - DATABASE_HOST=postgres + - DATABASE_PORT=5432 + - DATABASE_USER=${POSTGRES_USER:-sub2api} + - DATABASE_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} + - DATABASE_DBNAME=${POSTGRES_DB:-sub2api} + - DATABASE_SSLMODE=disable + + # Redis Configuration - 使用外部 Redis + - REDIS_HOST=${REDIS_HOST} + - REDIS_PORT=${REDIS_PORT:-6379} + - REDIS_PASSWORD=${REDIS_PASSWORD} + - REDIS_DB=${REDIS_DB:-0} + + # Admin Account + - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local} + - ADMIN_PASSWORD=${ADMIN_PASSWORD:-} + + # JWT Configuration + - JWT_SECRET=${JWT_SECRET:-} + - JWT_EXPIRE_HOUR=${JWT_EXPIRE_HOUR:-24} + + # Timezone + - TZ=${TZ:-Asia/Shanghai} + + # Gemini OAuth (可选) + - GEMINI_OAUTH_CLIENT_ID=${GEMINI_OAUTH_CLIENT_ID:-} + - GEMINI_OAUTH_CLIENT_SECRET=${GEMINI_OAUTH_CLIENT_SECRET:-} + - GEMINI_OAUTH_SCOPES=${GEMINI_OAUTH_SCOPES:-} + - GEMINI_QUOTA_POLICY=${GEMINI_QUOTA_POLICY:-} + depends_on: + postgres: + condition: service_healthy + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - sub2api-network + - 1panel-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + + # =========================================================================== + # PostgreSQL Database + # =========================================================================== + postgres: + image: postgres:18-alpine + container_name: sub2api-postgres + restart: unless-stopped + ulimits: + nofile: + soft: 100000 + hard: 100000 + volumes: + - postgres_data:/var/lib/postgresql/data + environment: + - POSTGRES_USER=${POSTGRES_USER:-sub2api} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} + - POSTGRES_DB=${POSTGRES_DB:-sub2api} + - TZ=${TZ:-Asia/Shanghai} + networks: + - sub2api-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-sub2api} -d ${POSTGRES_DB:-sub2api}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + +# ============================================================================= +# Volumes +# ============================================================================= +volumes: + sub2api_data: + driver: local + postgres_data: + driver: local + +# ============================================================================= +# Networks +# ============================================================================= +networks: + sub2api-network: + driver: bridge + 1panel-network: + external: true diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 50b14c4c..e80cc753 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -1,5 +1,5 @@ /** - * API Client for Sub2API Backend + * API Client for TianShuAPI Backend * Central export point for all API modules */ diff --git a/frontend/src/components/layout/AuthLayout.vue b/frontend/src/components/layout/AuthLayout.vue index 3cfc1d4d..bd20b3c4 100644 --- a/frontend/src/components/layout/AuthLayout.vue +++ b/frontend/src/components/layout/AuthLayout.vue @@ -65,7 +65,7 @@ import { ref, computed, onMounted } from 'vue' import { getPublicSettings } from '@/api/auth' import { sanitizeUrl } from '@/utils/url' -const siteName = ref('Sub2API') +const siteName = ref('TianShuAPI') const siteLogo = ref('') const siteSubtitle = ref('Subscription to API Conversion Platform') @@ -74,7 +74,7 @@ const currentYear = computed(() => new Date().getFullYear()) onMounted(async () => { try { const settings = await getPublicSettings() - siteName.value = settings.site_name || 'Sub2API' + siteName.value = settings.site_name || 'TianShuAPI' siteLogo.value = sanitizeUrl(settings.site_logo || '', { allowRelative: true }) siteSubtitle.value = settings.site_subtitle || 'Subscription to API Conversion Platform' } catch (error) { diff --git a/frontend/src/components/layout/README.md b/frontend/src/components/layout/README.md index e2cbdd17..e94aa31c 100644 --- a/frontend/src/components/layout/README.md +++ b/frontend/src/components/layout/README.md @@ -1,6 +1,6 @@ # Layout Components -Vue 3 layout components for the Sub2API frontend, built with Composition API, TypeScript, and TailwindCSS. +Vue 3 layout components for the TianShuAPI frontend, built with Composition API, TypeScript, and TailwindCSS. ## Components diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index b25b5a0b..7dbb556b 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -43,8 +43,8 @@ export default { // Setup Wizard setup: { - title: 'Sub2API Setup', - description: 'Configure your Sub2API instance', + title: 'TianShuAPI Setup', + description: 'Configure your TianShuAPI instance', database: { title: 'Database Configuration', description: 'Connect to your PostgreSQL database', @@ -2686,7 +2686,7 @@ export default { secretKeyConfiguredHint: 'Secret key configured. Leave empty to keep the current value.' }, linuxdo: { title: 'LinuxDo Connect Login', - description: 'Configure LinuxDo Connect OAuth for Sub2API end-user login', + description: 'Configure LinuxDo Connect OAuth for TianShuAPI end-user login', enable: 'Enable LinuxDo Login', enableHint: 'Show LinuxDo login on the login/register pages', clientId: 'Client ID', @@ -2716,7 +2716,7 @@ export default { title: 'Site Settings', description: 'Customize site branding', siteName: 'Site Name', - siteNamePlaceholder: 'Sub2API', + siteNamePlaceholder: 'TianShuAPI', siteNameHint: 'Displayed in emails and page titles', siteSubtitle: 'Site Subtitle', siteSubtitlePlaceholder: 'Subscription to API Conversion Platform', @@ -2762,7 +2762,7 @@ export default { fromEmail: 'From Email', fromEmailPlaceholder: "noreply{'@'}example.com", fromName: 'From Name', - fromNamePlaceholder: 'Sub2API', + fromNamePlaceholder: 'TianShuAPI', useTls: 'Use TLS', useTlsHint: 'Enable TLS encryption for SMTP connection' }, @@ -2931,14 +2931,14 @@ export default { // Admin tour steps admin: { welcome: { - title: '👋 Welcome to Sub2API', - description: '
Sub2API is a powerful AI service gateway platform that helps you easily manage and distribute AI services.
🎯 Core Features:
Let\'s complete the initial setup in 3 minutes →
TianShuAPI is a powerful AI service gateway platform that helps you easily manage and distribute AI services.
🎯 Core Features:
Let\'s complete the initial setup in 3 minutes →
What is a Group?
Groups are the core concept of Sub2API, like a "service package":
💡 Example: You can create "VIP Premium" (high rate) and "Free Trial" (low rate) groups
👉 Click "Group Management" on the left sidebar
What is a Group?
Groups are the core concept of TianShuAPI, like a "service package":
💡 Example: You can create "VIP Premium" (high rate) and "Free Trial" (low rate) groups
👉 Click "Group Management" on the left sidebar
Hello! Welcome to the Sub2API AI service platform.
🎯 Quick Start:
Just 1 minute, let\'s get started →
Hello! Welcome to the TianShuAPI AI service platform.
🎯 Quick Start:
Just 1 minute, let\'s get started →
Sub2API 是一个强大的 AI 服务中转平台,让您轻松管理和分发 AI 服务。
🎯 核心功能:
接下来,我们将用 3 分钟带您完成首次配置 →
TianShuAPI 是一个强大的 AI 服务中转平台,让您轻松管理和分发 AI 服务。
🎯 核心功能:
接下来,我们将用 3 分钟带您完成首次配置 →
什么是分组?
分组是 Sub2API 的核心概念,它就像一个"服务套餐":
💡 示例:您可以创建"VIP专线"(高倍率)和"免费试用"(低倍率)两个分组
👉 点击左侧的"分组管理"开始
什么是分组?
分组是 TianShuAPI 的核心概念,它就像一个"服务套餐":
💡 示例:您可以创建"VIP专线"(高倍率)和"免费试用"(低倍率)两个分组
👉 点击左侧的"分组管理"开始
您好!欢迎来到 Sub2API AI 服务平台。
🎯 快速开始:
只需 1 分钟,让我们开始吧 →
您好!欢迎来到 TianShuAPI AI 服务平台。
🎯 快速开始:
只需 1 分钟,让我们开始吧 →