feat(ai): 完成 DeepSeek 大模型官方 API 接入、双模调用、高可用平滑降级与管理后台连通性测试
这个提交包含在:
@@ -12,6 +12,8 @@ import {
|
||||
Message,
|
||||
Spin,
|
||||
Grid,
|
||||
Tag,
|
||||
Divider,
|
||||
} from '@arco-design/web-react';
|
||||
import axios from 'axios';
|
||||
import useLocale from '@/utils/useLocale';
|
||||
@@ -20,6 +22,8 @@ import type {
|
||||
AiConciergeConfig,
|
||||
ConciergePersonaType,
|
||||
ConciergeToneStyle,
|
||||
DeepSeekConfig,
|
||||
DeepSeekTestConnectionResult,
|
||||
} from '@/types/omni';
|
||||
import locale from './locale';
|
||||
|
||||
@@ -28,6 +32,8 @@ const { Row, Col } = Grid;
|
||||
const GET_CONFIG_API = '/api/admin/ai/concierge/getByCardId';
|
||||
const SAVE_CONFIG_API = '/api/admin/ai/concierge/saveByCardId';
|
||||
const CARD_PAGE_API = '/api/admin/card/info/page';
|
||||
const DEEPSEEK_CONFIG_API = '/api/admin/ai/deepseek/config';
|
||||
const DEEPSEEK_TEST_API = '/api/admin/ai/deepseek/test-connection';
|
||||
|
||||
interface CoolResponse<T> {
|
||||
code: number;
|
||||
@@ -98,6 +104,100 @@ export default function AiConciergePage(): JSX.Element {
|
||||
const [selectedCardId, setSelectedCardId] = useState<number>(DEFAULT_CARD_ID);
|
||||
const [cardOptions, setCardOptions] = useState<CardOptionItem[]>([]);
|
||||
|
||||
const [deepSeekForm] = Form.useForm<DeepSeekConfig>();
|
||||
const [deepSeekLoading, setDeepSeekLoading] = useState<boolean>(false);
|
||||
const [deepSeekSaving, setDeepSeekSaving] = useState<boolean>(false);
|
||||
const [deepSeekTesting, setDeepSeekTesting] = useState<boolean>(false);
|
||||
const [deepSeekConfig, setDeepSeekConfig] = useState<DeepSeekConfig | null>(null);
|
||||
const [testResult, setTestResult] = useState<DeepSeekTestConnectionResult | null>(null);
|
||||
|
||||
const loadDeepSeekConfig = async (): Promise<void> => {
|
||||
setDeepSeekLoading(true);
|
||||
try {
|
||||
const res = await axios.post<CoolResponse<DeepSeekConfig>>(
|
||||
DEEPSEEK_CONFIG_API,
|
||||
{}
|
||||
);
|
||||
if (res.data && res.data.code === 1000 && res.data.data) {
|
||||
const d = res.data.data;
|
||||
setDeepSeekConfig(d);
|
||||
deepSeekForm.setFieldsValue({
|
||||
apiKey: d.apiKey || '',
|
||||
baseUrl: d.baseUrl || 'https://api.deepseek.com',
|
||||
model: d.model || 'deepseek-chat',
|
||||
temperature: d.temperature ?? 0.7,
|
||||
maxTokens: d.maxTokens ?? 2048,
|
||||
enabled: d.enabled !== false,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// 保持静默优雅降级
|
||||
} finally {
|
||||
setDeepSeekLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTestDeepSeek = async (): Promise<void> => {
|
||||
setDeepSeekTesting(true);
|
||||
setTestResult(null);
|
||||
try {
|
||||
const values = deepSeekForm.getFieldsValue();
|
||||
const res = await axios.post<CoolResponse<DeepSeekTestConnectionResult>>(
|
||||
DEEPSEEK_TEST_API,
|
||||
{ apiKey: values.apiKey }
|
||||
);
|
||||
if (res.data && res.data.code === 1000 && res.data.data) {
|
||||
setTestResult(res.data.data);
|
||||
if (res.data.data.success) {
|
||||
Message.success(
|
||||
`${t['aiDeepSeek.test.success']} (${res.data.data.latencyMs ?? 0}ms)`
|
||||
);
|
||||
} else {
|
||||
Message.error(res.data.data.message || t['aiDeepSeek.test.fail']);
|
||||
}
|
||||
} else {
|
||||
Message.error(res.data?.message || t['aiDeepSeek.test.fail']);
|
||||
}
|
||||
} catch {
|
||||
Message.error(t['aiDeepSeek.test.fail']);
|
||||
} finally {
|
||||
setDeepSeekTesting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveDeepSeek = async (values: DeepSeekConfig): Promise<void> => {
|
||||
setDeepSeekSaving(true);
|
||||
try {
|
||||
const payload: Partial<DeepSeekConfig> = {
|
||||
baseUrl: values.baseUrl,
|
||||
model: values.model,
|
||||
temperature: Number(values.temperature),
|
||||
maxTokens: Number(values.maxTokens),
|
||||
enabled: Boolean(values.enabled),
|
||||
};
|
||||
if (values.apiKey && !values.apiKey.includes('****')) {
|
||||
payload.apiKey = values.apiKey;
|
||||
}
|
||||
const res = await axios.post<CoolResponse<DeepSeekConfig>>(
|
||||
DEEPSEEK_CONFIG_API,
|
||||
payload
|
||||
);
|
||||
if (res.data && res.data.code === 1000 && res.data.data) {
|
||||
Message.success(t['aiDeepSeek.save.success']);
|
||||
setDeepSeekConfig(res.data.data);
|
||||
if (res.data.data.apiKey) {
|
||||
deepSeekForm.setFieldValue('apiKey', res.data.data.apiKey);
|
||||
}
|
||||
} else {
|
||||
Message.error(res.data?.message || t['aiDeepSeek.save.fail']);
|
||||
}
|
||||
} catch {
|
||||
Message.error(t['aiDeepSeek.save.fail']);
|
||||
} finally {
|
||||
setDeepSeekSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchCardOptions = async (): Promise<void> => {
|
||||
try {
|
||||
const res = await axios.post<CoolResponse<CardPageResult>>(
|
||||
@@ -171,6 +271,7 @@ export default function AiConciergePage(): JSX.Element {
|
||||
useEffect(() => {
|
||||
fetchCardOptions();
|
||||
loadConciergeConfig(selectedCardId);
|
||||
loadDeepSeekConfig();
|
||||
}, []);
|
||||
|
||||
const handleCardChange = (cardId: number): void => {
|
||||
@@ -401,6 +502,178 @@ export default function AiConciergePage(): JSX.Element {
|
||||
</Form>
|
||||
</Spin>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<span>{t['aiDeepSeek.card.title']}</span>
|
||||
<Tag color={deepSeekConfig?.isConfigured ? 'green' : 'gray'}>
|
||||
{deepSeekConfig?.isConfigured
|
||||
? t['aiDeepSeek.status.configured']
|
||||
: t['aiDeepSeek.status.unconfigured']}
|
||||
</Tag>
|
||||
</div>
|
||||
}
|
||||
bordered={false}
|
||||
style={{
|
||||
marginTop: spacing[24],
|
||||
borderRadius: radius.card,
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
backgroundColor: lightColors.bg,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
color: lightColors.text2,
|
||||
marginBottom: spacing[24],
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
{t['aiDeepSeek.card.desc']}
|
||||
</div>
|
||||
|
||||
<Spin loading={deepSeekLoading} style={{ width: '100%' }}>
|
||||
<Form
|
||||
form={deepSeekForm}
|
||||
layout="vertical"
|
||||
onSubmit={handleSaveDeepSeek}
|
||||
initialValues={{
|
||||
baseUrl: 'https://api.deepseek.com',
|
||||
model: 'deepseek-chat',
|
||||
temperature: 0.7,
|
||||
maxTokens: 2048,
|
||||
enabled: true,
|
||||
}}
|
||||
>
|
||||
<Row gutter={24}>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label={t['aiDeepSeek.form.apiKey']}
|
||||
field="apiKey"
|
||||
extra={
|
||||
deepSeekConfig?.apiKey
|
||||
? `已保存密钥: ${deepSeekConfig.apiKey}`
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Input.Password
|
||||
placeholder={t['aiDeepSeek.form.apiKey.placeholder']}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label={t['aiDeepSeek.form.status']}
|
||||
field="enabled"
|
||||
triggerPropName="checked"
|
||||
extra={t['aiDeepSeek.form.status.desc']}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label={t['aiDeepSeek.form.baseUrl']}
|
||||
field="baseUrl"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input placeholder="https://api.deepseek.com" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label={t['aiDeepSeek.form.model']}
|
||||
field="model"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Select>
|
||||
<Select.Option value="deepseek-chat">
|
||||
{t['aiDeepSeek.model.chat']}
|
||||
</Select.Option>
|
||||
<Select.Option value="deepseek-reasoner">
|
||||
{t['aiDeepSeek.model.reasoner']}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label={t['aiDeepSeek.form.temperature']}
|
||||
field="temperature"
|
||||
extra={t['aiDeepSeek.form.temperature.desc']}
|
||||
>
|
||||
<Slider
|
||||
min={0}
|
||||
max={1.5}
|
||||
step={0.1}
|
||||
marks={{ 0: '0', 0.7: '0.7', 1.0: '1.0', 1.5: '1.5' }}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="Max Tokens"
|
||||
field="maxTokens"
|
||||
>
|
||||
<Select>
|
||||
<Select.Option value={1024}>1024</Select.Option>
|
||||
<Select.Option value={2048}>2048</Select.Option>
|
||||
<Select.Option value={4096}>4096</Select.Option>
|
||||
<Select.Option value={8192}>8192</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{testResult && (
|
||||
<div style={{ marginBottom: spacing[16] }}>
|
||||
<Tag
|
||||
color={testResult.success ? 'green' : 'red'}
|
||||
style={{ padding: `${spacing[4]} ${spacing[12]}` }}
|
||||
>
|
||||
{testResult.message || (testResult.success ? '连通成功' : '连通失败')}
|
||||
{testResult.latencyMs !== undefined && ` | ${testResult.latencyMs}ms`}
|
||||
{testResult.model && ` | ${testResult.model}`}
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: spacing[24] }}>
|
||||
<Space>
|
||||
<Button
|
||||
htmlType="submit"
|
||||
loading={deepSeekSaving}
|
||||
style={{ borderRadius: radius.button }}
|
||||
>
|
||||
{t['aiDeepSeek.action.save']}
|
||||
</Button>
|
||||
<Button
|
||||
type="outline"
|
||||
onClick={handleTestDeepSeek}
|
||||
loading={deepSeekTesting}
|
||||
style={{ borderRadius: radius.button }}
|
||||
>
|
||||
{t['aiDeepSeek.action.test']}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</Form>
|
||||
</Spin>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,31 @@ const i18n = {
|
||||
'aiConcierge.request.success': 'Concierge settings saved successfully',
|
||||
'aiConcierge.request.fail': 'Failed to load concierge configuration',
|
||||
'aiConcierge.request.saveFail': 'Failed to save configuration',
|
||||
'aiDeepSeek.card.title': 'DeepSeek Official LLM Configuration',
|
||||
'aiDeepSeek.card.desc':
|
||||
'Configure DeepSeek API Key, supporting deepseek-chat and deepseek-reasoner dual models for 24/7 AI concierge and cross-border localization.',
|
||||
'aiDeepSeek.form.apiKey': 'API Key',
|
||||
'aiDeepSeek.form.apiKey.placeholder':
|
||||
'Enter official API Key starting with sk- (leave blank to keep current)',
|
||||
'aiDeepSeek.form.baseUrl': 'API Base URL',
|
||||
'aiDeepSeek.form.model': 'Model Version',
|
||||
'aiDeepSeek.model.chat': 'DeepSeek-V3 Chat (deepseek-chat)',
|
||||
'aiDeepSeek.model.reasoner': 'DeepSeek-R1 Reasoner (deepseek-reasoner)',
|
||||
'aiDeepSeek.form.temperature': 'Temperature',
|
||||
'aiDeepSeek.form.temperature.desc':
|
||||
'Lower values are deterministic; higher values are creative.',
|
||||
'aiDeepSeek.form.status': 'Enable DeepSeek LLM',
|
||||
'aiDeepSeek.form.status.desc':
|
||||
'When enabled, requests prioritize DeepSeek official API with smooth fallback.',
|
||||
'aiDeepSeek.action.test': 'Test Connection',
|
||||
'aiDeepSeek.action.testing': 'Testing connection...',
|
||||
'aiDeepSeek.action.save': 'Save Model Config',
|
||||
'aiDeepSeek.status.configured': 'Configured',
|
||||
'aiDeepSeek.status.unconfigured': 'Not Configured',
|
||||
'aiDeepSeek.test.success': 'DeepSeek API connection successful',
|
||||
'aiDeepSeek.test.fail': 'Connection test failed',
|
||||
'aiDeepSeek.save.success': 'DeepSeek configuration updated',
|
||||
'aiDeepSeek.save.fail': 'Failed to save DeepSeek configuration',
|
||||
},
|
||||
'zh-CN': {
|
||||
'menu.ai.concierge': 'AI 顾问配置',
|
||||
@@ -88,6 +113,31 @@ const i18n = {
|
||||
'aiConcierge.request.success': 'AI 顾问配置已保存',
|
||||
'aiConcierge.request.fail': 'AI 顾问配置加载失败',
|
||||
'aiConcierge.request.saveFail': '保存配置失败',
|
||||
'aiDeepSeek.card.title': 'DeepSeek 官方大模型底座配置',
|
||||
'aiDeepSeek.card.desc':
|
||||
'配置 DeepSeek API Key,支持 deepseek-chat 与 deepseek-reasoner 双模型接入,赋能 24/7 AI 顾问对话与出海多语言润色。',
|
||||
'aiDeepSeek.form.apiKey': 'API Key 密钥',
|
||||
'aiDeepSeek.form.apiKey.placeholder':
|
||||
'输入 sk- 开头的官方密钥 (留空则保留当前已配置密钥)',
|
||||
'aiDeepSeek.form.baseUrl': 'API 接口基地址 (Base URL)',
|
||||
'aiDeepSeek.form.model': '接入模型版本',
|
||||
'aiDeepSeek.model.chat': 'DeepSeek-V3 对话模型 (deepseek-chat)',
|
||||
'aiDeepSeek.model.reasoner': 'DeepSeek-R1 深度推理模型 (deepseek-reasoner)',
|
||||
'aiDeepSeek.form.temperature': '采样温度 (Temperature)',
|
||||
'aiDeepSeek.form.temperature.desc':
|
||||
'较低值输出严谨稳定,较高值回复生动多样。',
|
||||
'aiDeepSeek.form.status': '启用 DeepSeek 大模型',
|
||||
'aiDeepSeek.form.status.desc':
|
||||
'开启后系统优先直连 DeepSeek 官方 API,网络异常或未配置时自动平滑降级。',
|
||||
'aiDeepSeek.action.test': '测试连通性',
|
||||
'aiDeepSeek.action.testing': '连通性测试中...',
|
||||
'aiDeepSeek.action.save': '保存大模型配置',
|
||||
'aiDeepSeek.status.configured': '已配置',
|
||||
'aiDeepSeek.status.unconfigured': '未配置',
|
||||
'aiDeepSeek.test.success': 'DeepSeek API 连通测试成功',
|
||||
'aiDeepSeek.test.fail': '连通性测试失败',
|
||||
'aiDeepSeek.save.success': 'DeepSeek 大模型配置已保存',
|
||||
'aiDeepSeek.save.fail': '保存大模型配置失败',
|
||||
},
|
||||
'ar-SA': {
|
||||
'menu.ai.concierge': 'إعدادات المساعد الذكي',
|
||||
@@ -133,6 +183,31 @@ const i18n = {
|
||||
'aiConcierge.request.success': 'تم حفظ الإعدادات بنجاح',
|
||||
'aiConcierge.request.fail': 'تعذر تحميل الإعدادات',
|
||||
'aiConcierge.request.saveFail': 'فشل حفظ الإعدادات',
|
||||
'aiDeepSeek.card.title': 'إعدادات نموذج DeepSeek الرسمي',
|
||||
'aiDeepSeek.card.desc':
|
||||
'تكوين مفتاح واجهة DeepSeek البرمجية لدعم محادثات المساعد الذكي وترجمة المحتوى.',
|
||||
'aiDeepSeek.form.apiKey': 'مفتاح API',
|
||||
'aiDeepSeek.form.apiKey.placeholder':
|
||||
'أدخل المفتاح الرسمي الذي يبدأ بـ sk-',
|
||||
'aiDeepSeek.form.baseUrl': 'عنوان الواجهة الأساسي',
|
||||
'aiDeepSeek.form.model': 'إصدار النموذج',
|
||||
'aiDeepSeek.model.chat': 'نموذج محادثة DeepSeek-V3',
|
||||
'aiDeepSeek.model.reasoner': 'نموذج استدلال DeepSeek-R1',
|
||||
'aiDeepSeek.form.temperature': 'درجة الحرارة',
|
||||
'aiDeepSeek.form.temperature.desc':
|
||||
'القيم المنخفضة أكثر دقة والصلبة أكثر إبداعا.',
|
||||
'aiDeepSeek.form.status': 'تفعيل نموذج DeepSeek',
|
||||
'aiDeepSeek.form.status.desc':
|
||||
'عند التفعيل، تعطى الأولوية لواجهة DeepSeek مع خفض سلس للأداء عند الانقطاع.',
|
||||
'aiDeepSeek.action.test': 'اختبار الاتصال',
|
||||
'aiDeepSeek.action.testing': 'جاري اختبار الاتصال...',
|
||||
'aiDeepSeek.action.save': 'حفظ إعدادات النموذج',
|
||||
'aiDeepSeek.status.configured': 'تم التكوين',
|
||||
'aiDeepSeek.status.unconfigured': 'غير مكوّن',
|
||||
'aiDeepSeek.test.success': 'نجح اختبار الاتصال بـ DeepSeek',
|
||||
'aiDeepSeek.test.fail': 'فشل اختبار الاتصال',
|
||||
'aiDeepSeek.save.success': 'تم حفظ إعدادات DeepSeek بنجاح',
|
||||
'aiDeepSeek.save.fail': 'فشل حفظ إعدادات DeepSeek',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -476,6 +476,42 @@ export interface AiConciergeConfig {
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 5.1 DeepSeek 大模型集成契约 (DeepSeek AI Suite)
|
||||
// ==========================================
|
||||
|
||||
export type DeepSeekModel = 'deepseek-chat' | 'deepseek-reasoner';
|
||||
|
||||
export interface DeepSeekConfig {
|
||||
apiKey?: string;
|
||||
baseUrl?: string;
|
||||
model?: DeepSeekModel;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
timeoutMs?: number;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface DeepSeekChatMessage {
|
||||
role: 'system' | 'user' | 'assistant';
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface DeepSeekChatCompletionRequest {
|
||||
messages: DeepSeekChatMessage[];
|
||||
model?: DeepSeekModel;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
stream?: boolean;
|
||||
}
|
||||
|
||||
export interface DeepSeekTestConnectionResult {
|
||||
success: boolean;
|
||||
latencyMs?: number;
|
||||
model?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export type LocalizeTone = 'professional' | 'direct' | 'storytelling';
|
||||
|
||||
export interface LocalizeRequest {
|
||||
@@ -725,4 +761,117 @@ export interface TeamRankBroadcastPayload {
|
||||
meta?: TeamRankBroadcastMeta;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 12. AI 顾问对话与 DeepSeek 大模型契约 (AI Concierge & DeepSeek Suite)
|
||||
// ==========================================
|
||||
|
||||
export type AiChatRole = 'user' | 'assistant' | 'system';
|
||||
|
||||
export interface AiChatMessage {
|
||||
role: AiChatRole;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface AiChatRequest {
|
||||
cardId: string | number;
|
||||
locale?: string;
|
||||
messages: AiChatMessage[];
|
||||
}
|
||||
|
||||
export interface AiChatReply {
|
||||
reply: string;
|
||||
locale: string;
|
||||
shouldCollectLead: boolean;
|
||||
}
|
||||
|
||||
export interface AiKnowledgeDoc {
|
||||
id?: string | number;
|
||||
cardId: string | number;
|
||||
title: string;
|
||||
content: string;
|
||||
locale?: string;
|
||||
}
|
||||
|
||||
export type ConciergePersonaType =
|
||||
| 'trade_expert'
|
||||
| 'business_rep'
|
||||
| 'tech_advisor'
|
||||
| 'custom';
|
||||
|
||||
export type ConciergeToneStyle =
|
||||
| 'professional'
|
||||
| 'direct'
|
||||
| 'enthusiastic'
|
||||
| 'friendly';
|
||||
|
||||
export interface AiConciergeConfig {
|
||||
id?: string | number;
|
||||
cardId: string | number;
|
||||
personaType: ConciergePersonaType;
|
||||
welcomeMsg: string;
|
||||
triggerLeadThreshold: number;
|
||||
promptTemplate: string;
|
||||
toneStyle: ConciergeToneStyle;
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
export interface KnowledgeChunk {
|
||||
id?: string | number;
|
||||
index: number;
|
||||
content: string;
|
||||
length: number;
|
||||
score?: number;
|
||||
}
|
||||
|
||||
export type DeepSeekModel = 'deepseek-chat' | 'deepseek-reasoner';
|
||||
|
||||
export interface DeepSeekConfig {
|
||||
apiKey?: string;
|
||||
baseUrl?: string;
|
||||
model?: DeepSeekModel;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
timeoutMs?: number;
|
||||
enabled?: boolean;
|
||||
isConfigured?: boolean;
|
||||
}
|
||||
|
||||
export interface DeepSeekChatMessage {
|
||||
role: 'system' | 'user' | 'assistant';
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface DeepSeekChatCompletionRequest {
|
||||
messages: DeepSeekChatMessage[];
|
||||
model?: DeepSeekModel;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
stream?: boolean;
|
||||
}
|
||||
|
||||
export interface DeepSeekChatCompletionResponse {
|
||||
id: string;
|
||||
model: string;
|
||||
choices: Array<{
|
||||
index: number;
|
||||
message: {
|
||||
role: 'assistant';
|
||||
content: string;
|
||||
};
|
||||
finish_reason: string;
|
||||
}>;
|
||||
usage?: {
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
total_tokens: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface DeepSeekTestConnectionResult {
|
||||
success: boolean;
|
||||
latencyMs?: number;
|
||||
model?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户