-
Notifications
You must be signed in to change notification settings - Fork 649
Expand file tree
/
Copy pathdeepseekProvider.ts
More file actions
148 lines (130 loc) · 4.03 KB
/
deepseekProvider.ts
File metadata and controls
148 lines (130 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { LLM_PROVIDER, LLMResponse, ChatMessage, KeyStatus } from '@shared/presenter'
import { OpenAICompatibleProvider } from './openAICompatibleProvider'
import { ConfigPresenter } from '../../configPresenter'
import { SUMMARY_TITLES_PROMPT } from '../baseProvider'
// Define interface for DeepSeek API key response
interface DeepSeekBalanceResponse {
is_available: boolean
balance_infos: Array<{
currency: string
total_balance: string
granted_balance: string
topped_up_balance: string
}>
}
export class DeepseekProvider extends OpenAICompatibleProvider {
constructor(provider: LLM_PROVIDER, configPresenter: ConfigPresenter) {
super(provider, configPresenter)
}
async completions(
messages: ChatMessage[],
modelId: string,
temperature?: number,
maxTokens?: number
): Promise<LLMResponse> {
return this.openAICompletion(messages, modelId, temperature, maxTokens)
}
async summaries(
text: string,
modelId: string,
temperature?: number,
maxTokens?: number
): Promise<LLMResponse> {
return this.openAICompletion(
[
{
role: 'user',
content: `${SUMMARY_TITLES_PROMPT}\n\n${text}`
}
],
modelId,
temperature,
maxTokens
)
}
async generateText(
prompt: string,
modelId: string,
temperature?: number,
maxTokens?: number
): Promise<LLMResponse> {
return this.openAICompletion(
[
{
role: 'user',
content: prompt
}
],
modelId,
temperature,
maxTokens
)
}
/**
* Get current API key status from DeepSeek
* @returns Promise<KeyStatus> API key status information
*/
public async getKeyStatus(): Promise<KeyStatus> {
if (!this.provider.apiKey) {
throw new Error('API key is required')
}
const response = await fetch('https://api.deepseek.com/user/balance', {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${this.provider.apiKey}`
}
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(
`DeepSeek API key check failed: ${response.status} ${response.statusText} - ${errorText}`
)
}
const balanceResponse: DeepSeekBalanceResponse = await response.json()
if (!balanceResponse.is_available) {
throw new Error('DeepSeek API key is not available')
}
// Find CNY balance info first, then USD, then default to first available
const balanceInfo =
balanceResponse.balance_infos.find((info) => info.currency === 'CNY') ||
balanceResponse.balance_infos.find((info) => info.currency === 'USD') ||
balanceResponse.balance_infos[0]
if (!balanceInfo) {
throw new Error('No balance information available')
}
const totalBalance = parseFloat(balanceInfo.total_balance)
const currencySymbol = balanceInfo.currency === 'USD' ? '$' : '¥'
// Map to unified KeyStatus format
return {
limit_remaining: `${currencySymbol}${totalBalance}`,
remainNum: totalBalance
}
}
/**
* Override check method to use DeepSeek's API key status endpoint
* @returns Promise<{ isOk: boolean; errorMsg: string | null }>
*/
public async check(): Promise<{ isOk: boolean; errorMsg: string | null }> {
try {
const keyStatus = await this.getKeyStatus()
// Check if there's remaining quota
if (keyStatus.remainNum !== undefined && keyStatus.remainNum <= 0) {
return {
isOk: false,
errorMsg: `API key quota exhausted. Remaining: ${keyStatus.limit_remaining}`
}
}
return { isOk: true, errorMsg: null }
} catch (error: unknown) {
let errorMessage = 'An unknown error occurred during DeepSeek API key check.'
if (error instanceof Error) {
errorMessage = error.message
} else if (typeof error === 'string') {
errorMessage = error
}
console.error('DeepSeek API key check failed:', error)
return { isOk: false, errorMsg: errorMessage }
}
}
}