Skip to content

Commit 354c06d

Browse files
committed
wip: siliconflow
1 parent cdc5b4e commit 354c06d

File tree

13 files changed

+826
-44
lines changed

13 files changed

+826
-44
lines changed
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
<script setup lang="ts">
2+
import { computed, onUnmounted, ref } from 'vue'
3+
import { useI18n } from 'vue-i18n'
4+
import { toast } from 'vue-sonner'
5+
import { Button } from '@/components/ui/button'
6+
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
7+
import { Input } from '@/components/ui/input'
8+
import { useDeepSeekProvider } from '@/lib/providers/deepseek'
9+
import { useKeysStore, useServiceStore } from '@/stores'
10+
import ShumeiCaptcha from './ShumeiCaptcha.vue'
11+
12+
const { t, locale } = useI18n()
13+
const keysStore = useKeysStore()
14+
const provider = useDeepSeekProvider()
15+
const { fetch } = useServiceStore()
16+
17+
const captchaConfig = {
18+
organization: 'P9usCUBauxft8eAmUXaZ',
19+
maskBindClose: !1,
20+
lang: locale.value === 'zh-CN' ? 'zh-cn' : 'en',
21+
mode: 'spatial_select',
22+
domains: ['captcha.fengkongcloud.com'],
23+
}
24+
25+
const phoneNumber = ref('')
26+
const smsCode = ref('')
27+
const agreed = ref(true)
28+
const isLoading = ref(false)
29+
const isSendingCode = ref(false)
30+
const countdown = ref(0)
31+
32+
const canSendCode = computed(() => {
33+
return phoneNumber.value && !isSendingCode.value && countdown.value === 0
34+
})
35+
36+
const canLogin = computed(() => {
37+
return phoneNumber.value && smsCode.value && agreed.value && !isLoading.value
38+
})
39+
40+
let countdownInterval: NodeJS.Timeout | null = null
41+
42+
function startCountdown() {
43+
countdown.value = 60
44+
countdownInterval = setInterval(() => {
45+
countdown.value--
46+
if (countdown.value <= 0) {
47+
clearInterval(countdownInterval!)
48+
countdownInterval = null
49+
}
50+
}, 1000)
51+
}
52+
53+
async function sendSMS(rid: string) {
54+
if (!canSendCode.value)
55+
return
56+
57+
try {
58+
isSendingCode.value = true
59+
60+
// Send SMS with captcha verification result
61+
const res = await fetch('deepseek/sms', {
62+
body: JSON.stringify({
63+
locale: locale.value === 'zh-CN' ? 'zh_CN' : 'en_US',
64+
mobile_number: phoneNumber.value,
65+
turnstile_token: '',
66+
shumei_verification: { region: 'GLOBAL', rid },
67+
device_id: 'BpeI75x/8jEyx0Cf8+ceENFycckj5NmfAgbRg/za+xaDDzFfBlTiLwSJAqAg0PpFarvtePSmNZWgonTdCjntvWw==',
68+
}),
69+
method: 'POST',
70+
})
71+
72+
if (res.ok) {
73+
const { data } = await res.json()
74+
if (data.code === 0) {
75+
toast.success(t('smsSent'))
76+
startCountdown()
77+
}
78+
else {
79+
toast.error(t('smsFailure'))
80+
}
81+
}
82+
else {
83+
toast.error(t('smsFailure'))
84+
}
85+
}
86+
catch (error) {
87+
console.error('Send SMS error:', error)
88+
toast.error(t('smsFailure'))
89+
}
90+
finally {
91+
isSendingCode.value = false
92+
}
93+
}
94+
95+
async function login() {
96+
if (!canLogin.value)
97+
return
98+
99+
try {
100+
isLoading.value = true
101+
102+
const res = await fetch('deepseek/login', {
103+
body: JSON.stringify({
104+
phone: phoneNumber.value,
105+
code: smsCode.value,
106+
area_code: '+86',
107+
}),
108+
method: 'POST',
109+
})
110+
111+
if (res.ok) {
112+
await provider.refreshUser()
113+
// Clear login form
114+
phoneNumber.value = ''
115+
smsCode.value = ''
116+
toast.success(t('loginSuccess'))
117+
118+
// Automatically create API key after successful login
119+
await keysStore.createAndAddKey(provider)
120+
}
121+
else {
122+
const errorData = await res.json()
123+
toast.error(errorData.message || t('loginFailure'))
124+
}
125+
}
126+
catch (error) {
127+
console.error('Login error:', error)
128+
toast.error(t('networkError'))
129+
}
130+
finally {
131+
isLoading.value = false
132+
}
133+
}
134+
135+
function cleanup() {
136+
if (countdownInterval) {
137+
clearInterval(countdownInterval)
138+
countdownInterval = null
139+
}
140+
}
141+
142+
// Cleanup on unmount
143+
onUnmounted(cleanup)
144+
</script>
145+
146+
<template>
147+
<Card>
148+
<CardHeader class="pb-4">
149+
<CardTitle class="text-lg">
150+
{{ t('loginTitle') }}
151+
</CardTitle>
152+
<CardDescription class="text-sm">
153+
{{ t('loginDescription') }}
154+
</CardDescription>
155+
</CardHeader>
156+
<CardContent class="space-y-4">
157+
<!-- Phone Number Input -->
158+
<div class="flex rounded-md border border-input bg-background">
159+
<div class="flex items-center px-3 border-r border-input bg-muted/50 rounded-l-md">
160+
<span class="text-sm font-medium text-muted-foreground">+86</span>
161+
</div>
162+
<Input
163+
id="phone"
164+
v-model="phoneNumber"
165+
:placeholder="t('phoneNumber')"
166+
type="tel"
167+
class="border-0 rounded-l-none focus-visible:ring-0 focus-visible:ring-offset-0 h-10"
168+
:disabled="isLoading"
169+
/>
170+
</div>
171+
172+
<!-- SMS Code Input -->
173+
<div class="flex rounded-md border border-input bg-background">
174+
<Input
175+
id="sms"
176+
v-model="smsCode"
177+
:placeholder="t('smsCode')"
178+
type="text"
179+
maxlength="6"
180+
class="w-fit flex-grow border-0 rounded-r-none focus-visible:ring-0 focus-visible:ring-offset-0 h-10"
181+
:disabled="isLoading"
182+
/>
183+
<div class="border-l border-input">
184+
<ShumeiCaptcha
185+
:enabled="phoneNumber.length > 0 && !isSendingCode && countdown === 0"
186+
:config="captchaConfig"
187+
class="h-10 px-4 bg-muted/50 rounded-r-md border-0 text-xs text-primary hover:bg-muted/70 transition-colors disabled:opacity-50"
188+
@next="sendSMS"
189+
>
190+
{{ isSendingCode ? t('sending') : countdown > 0 ? `${countdown}s` : t('getCode') }}
191+
</ShumeiCaptcha>
192+
</div>
193+
</div>
194+
</CardContent>
195+
<CardFooter class="flex flex-col space-y-3 pt-3 items-start">
196+
<div class="flex items-center space-x-2 text-xs text-muted-foreground">
197+
<input
198+
id="agree"
199+
v-model="agreed"
200+
type="checkbox"
201+
class="h-3 w-3 rounded border border-input"
202+
:disabled="isLoading"
203+
>
204+
<label for="agree" class="flex items-center gap-1 cursor-pointer">
205+
<span>{{ t('agreeToTerms') }}</span>
206+
<a
207+
href="https://www.deepseek.com/zh/terms"
208+
target="_blank"
209+
class="text-primary hover:underline"
210+
>{{ t('userAgreement') }}</a>
211+
<span>{{ t('and') }}</span>
212+
<a
213+
href="https://www.deepseek.com/zh/privacy"
214+
target="_blank"
215+
class="text-primary hover:underline"
216+
>{{ t('privacyPolicy') }}</a>
217+
</label>
218+
</div>
219+
<Button
220+
class="w-full h-10"
221+
:disabled="!canLogin"
222+
@click="login"
223+
>
224+
<span v-if="isLoading">{{ t('loggingIn') }}</span>
225+
<span v-else>{{ t('registerLogin') }}</span>
226+
</Button>
227+
</CardFooter>
228+
</Card>
229+
</template>
230+
231+
<i18n lang="yaml">
232+
en-US:
233+
loginTitle: Login to DeepSeek
234+
loginDescription: Login using phone number and SMS verification code
235+
phoneNumber: Your phone number
236+
smsCode: SMS verification code
237+
agreeToTerms: I agree to DeepSeek's
238+
userAgreement: User Agreement
239+
and: and
240+
privacyPolicy: Privacy Policy
241+
loggingIn: Logging in...
242+
registerLogin: Register/Login
243+
getCode: Get Code
244+
sending: Sending...
245+
smsSent: SMS sent successfully
246+
smsFailure: Failed to send SMS
247+
loginSuccess: Login successful
248+
loginFailure: Login failed
249+
networkError: Network error
250+
251+
zh-CN:
252+
loginTitle: 登录 DeepSeek
253+
loginDescription: 使用手机号码和短信验证码登录
254+
phoneNumber: 您的手机号
255+
smsCode: 短信验证码
256+
agreeToTerms: 我同意 DeepSeek 的
257+
userAgreement: 用户协议
258+
and:
259+
privacyPolicy: 隐私政策
260+
loggingIn: 登录中...
261+
registerLogin: 注册/登录
262+
getCode: 获取验证码
263+
sending: 发送中...
264+
smsSent: 短信发送成功
265+
smsFailure: 短信发送失败
266+
loginSuccess: 登录成功
267+
loginFailure: 登录失败
268+
networkError: 网络错误
269+
</i18n>

frontend/src/components/Captcha.vue renamed to frontend/src/components/GeetestCaptcha.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ const statusText = computed(() => ({
8989

9090
<i18n lang="yaml">
9191
en-US:
92-
loading: Authenticating...
93-
getCode: Get Verification Code
92+
loading: Loading...
93+
getCode: Get Code
9494
smsSent: Code Sent
9595
9696
zh-CN:

frontend/src/components/KeysSection.vue

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ onMounted(() => {
7070
<CardHeader>
7171
<div class="flex items-center justify-between">
7272
<CardTitle class="text-lg">
73-
{{ t('siliconFlow') }}
73+
{{ provider.name }}
7474
</CardTitle>
7575
<div v-show="provider.user !== undefined" class="flex items-center gap-2">
7676
<span
@@ -89,18 +89,18 @@ onMounted(() => {
8989
<CardContent>
9090
<div class="text-sm text-muted-foreground">
9191
<p>
92-
{{ t('siliconFlowDescription1') }}
92+
{{ t('description1') }}
9393
<a href="https://www.siliconflow.cn" target="_blank" class="text-blue-900 dark:text-blue-200 hover:underline">
94-
{{ t('siliconFlow') }}
94+
{{ provider.name }}
9595
</a>
96-
{{ t('siliconFlowDescription2') }}
96+
{{ t('description2') }}
9797
</p>
9898
</div>
9999
</CardContent>
100100

101101
<CardFooter>
102102
<Button class="w-full" @click="showProviderDialog = provider">
103-
{{ t('configureSiliconFlow') }}
103+
{{ t('configure', [provider.name]) }}
104104
</Button>
105105
</CardFooter>
106106
</Card>
@@ -188,20 +188,18 @@ onMounted(() => {
188188
zh-CN:
189189
title: 模型供应商
190190
loadFailed: 加载失败
191-
siliconFlow: 硅基流动
192-
siliconFlowDescription1: 通过
193-
siliconFlowDescription2: 购买和配置 API
191+
description1: 通过
192+
description2: 购买和配置 API
194193
loggedIn: 已登录
195194
loggedOut: 未登录
196-
configureSiliconFlow: 配置 硅基流动
195+
configure: 配置 {0}
197196
198197
en-US:
199198
title: Model Providers
200199
loadFailed: Failed to load
201-
siliconFlow: SiliconFlow
202-
siliconFlowDescription1: Purchase and configure API through
203-
siliconFlowDescription2: ''
200+
description1: Purchase and configure API through
201+
description2: ''
204202
loggedIn: Logged In
205203
loggedOut: Logged Out
206-
configureSiliconFlow: Configure SiliconFlow
204+
configure: Configure {0}
207205
</i18n>

0 commit comments

Comments
 (0)