更新ai服务提醒
This commit is contained in:
@@ -262,6 +262,9 @@ func (s *Service) Enabled() bool {
|
|||||||
|
|
||||||
// ReloadLLMProvider reloads a specific LLM provider configuration
|
// ReloadLLMProvider reloads a specific LLM provider configuration
|
||||||
func (s *Service) ReloadLLMProvider(config interface{}) error {
|
func (s *Service) ReloadLLMProvider(config interface{}) error {
|
||||||
|
if s == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !s.enabled || s.LLMState == nil {
|
if !s.enabled || s.LLMState == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -274,6 +277,9 @@ func (s *Service) ReloadLLMProvider(config interface{}) error {
|
|||||||
|
|
||||||
// AddLLMProvider adds a new LLM provider
|
// AddLLMProvider adds a new LLM provider
|
||||||
func (s *Service) AddLLMProvider(config interface{}) error {
|
func (s *Service) AddLLMProvider(config interface{}) error {
|
||||||
|
if s == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !s.enabled || s.LLMState == nil {
|
if !s.enabled || s.LLMState == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -286,6 +292,9 @@ func (s *Service) AddLLMProvider(config interface{}) error {
|
|||||||
|
|
||||||
// RemoveLLMProvider removes an LLM provider
|
// RemoveLLMProvider removes an LLM provider
|
||||||
func (s *Service) RemoveLLMProvider(name string) error {
|
func (s *Service) RemoveLLMProvider(name string) error {
|
||||||
|
if s == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if !s.enabled || s.LLMState == nil {
|
if !s.enabled || s.LLMState == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,25 +298,30 @@ func handleCreateLLMProvider(store *storepkg.Store, aiService LLMProviderReloade
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reload AI service with new provider
|
// Reload AI service with new provider
|
||||||
if aiService != nil {
|
if aiService == nil {
|
||||||
providerConfig := map[string]interface{}{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"Name": record.Name,
|
"status": "ok",
|
||||||
"Active": record.Active,
|
"item": llmProviderDTO(*record),
|
||||||
"APIKey": record.APIKey,
|
"warning": "AI 服务未运行,配置已保存但需重启服务后生效",
|
||||||
"BaseURL": record.BaseURL,
|
})
|
||||||
"Model": record.Model,
|
return
|
||||||
"Timeout": record.Timeout,
|
}
|
||||||
"ContextWindowTokens": record.ContextWindowTokens,
|
providerConfig := map[string]interface{}{
|
||||||
}
|
"Name": record.Name,
|
||||||
if err := aiService.AddLLMProvider(providerConfig); err != nil {
|
"Active": record.Active,
|
||||||
// Log warning but don't fail the request - database is already updated
|
"APIKey": record.APIKey,
|
||||||
c.JSON(http.StatusOK, gin.H{
|
"BaseURL": record.BaseURL,
|
||||||
"status": "ok",
|
"Model": record.Model,
|
||||||
"item": llmProviderDTO(*record),
|
"Timeout": record.Timeout,
|
||||||
"warning": "provider created but failed to reload AI service: " + err.Error(),
|
"ContextWindowTokens": record.ContextWindowTokens,
|
||||||
})
|
}
|
||||||
return
|
if err := aiService.AddLLMProvider(providerConfig); err != nil {
|
||||||
}
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"status": "ok",
|
||||||
|
"item": llmProviderDTO(*record),
|
||||||
|
"warning": "provider created but failed to reload AI service: " + err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"status": "ok", "item": llmProviderDTO(*record)})
|
c.JSON(http.StatusOK, gin.H{"status": "ok", "item": llmProviderDTO(*record)})
|
||||||
@@ -385,25 +390,30 @@ func handleUpdateLLMProvider(store *storepkg.Store, aiService LLMProviderReloade
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reload AI service with updated provider
|
// Reload AI service with updated provider
|
||||||
if aiService != nil {
|
if aiService == nil {
|
||||||
providerConfig := map[string]interface{}{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"Name": record.Name,
|
"status": "ok",
|
||||||
"Active": record.Active,
|
"item": llmProviderDTO(*record),
|
||||||
"APIKey": record.APIKey,
|
"warning": "AI 服务未运行,配置已保存但需重启服务后生效",
|
||||||
"BaseURL": record.BaseURL,
|
})
|
||||||
"Model": record.Model,
|
return
|
||||||
"Timeout": record.Timeout,
|
}
|
||||||
"ContextWindowTokens": record.ContextWindowTokens,
|
providerConfig := map[string]interface{}{
|
||||||
}
|
"Name": record.Name,
|
||||||
if err := aiService.ReloadLLMProvider(providerConfig); err != nil {
|
"Active": record.Active,
|
||||||
// Log warning but don't fail the request - database is already updated
|
"APIKey": record.APIKey,
|
||||||
c.JSON(http.StatusOK, gin.H{
|
"BaseURL": record.BaseURL,
|
||||||
"status": "ok",
|
"Model": record.Model,
|
||||||
"item": llmProviderDTO(*record),
|
"Timeout": record.Timeout,
|
||||||
"warning": "provider updated but failed to reload AI service: " + err.Error(),
|
"ContextWindowTokens": record.ContextWindowTokens,
|
||||||
})
|
}
|
||||||
return
|
if err := aiService.ReloadLLMProvider(providerConfig); err != nil {
|
||||||
}
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"status": "ok",
|
||||||
|
"item": llmProviderDTO(*record),
|
||||||
|
"warning": "provider updated but failed to reload AI service: " + err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"status": "ok", "item": llmProviderDTO(*record)})
|
c.JSON(http.StatusOK, gin.H{"status": "ok", "item": llmProviderDTO(*record)})
|
||||||
@@ -424,15 +434,19 @@ func handleDeleteLLMProvider(store *storepkg.Store, aiService LLMProviderReloade
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove provider from AI service
|
// Remove provider from AI service
|
||||||
if aiService != nil {
|
if aiService == nil {
|
||||||
if err := aiService.RemoveLLMProvider(name); err != nil {
|
c.JSON(http.StatusOK, gin.H{
|
||||||
// Log warning but don't fail the request - database is already updated
|
"status": "ok",
|
||||||
c.JSON(http.StatusOK, gin.H{
|
"warning": "AI 服务未运行,配置已删除但需重启服务后生效",
|
||||||
"status": "ok",
|
})
|
||||||
"warning": "provider deleted but failed to reload AI service: " + err.Error(),
|
return
|
||||||
})
|
}
|
||||||
return
|
if err := aiService.RemoveLLMProvider(name); err != nil {
|
||||||
}
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"status": "ok",
|
||||||
|
"warning": "provider deleted but failed to reload AI service: " + err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||||
|
|||||||
@@ -475,7 +475,11 @@ func run(cfg *configpkg.Config) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mqttStatus := webpkg.MQTTRuntimeStatus{Server: server, Address: mqttAddr, TLS: cfg.MQTT.TLS.Enabled, Stats: messageStats, ClientStats: clientStats, DBQueue: dbQueue, DedupQueue: mqttHook.dedupQueue}
|
mqttStatus := webpkg.MQTTRuntimeStatus{Server: server, Address: mqttAddr, TLS: cfg.MQTT.TLS.Enabled, Stats: messageStats, ClientStats: clientStats, DBQueue: dbQueue, DedupQueue: mqttHook.dedupQueue}
|
||||||
handler := webpkg.NewRouter(cfg.Web, cfg.ConsoleLog.Web, store, sessions, mqttStatus, blocking, forwardManager, settings, botSender, aiService)
|
var llmReloader webpkg.LLMProviderReloader
|
||||||
|
if aiService != nil {
|
||||||
|
llmReloader = aiService
|
||||||
|
}
|
||||||
|
handler := webpkg.NewRouter(cfg.Web, cfg.ConsoleLog.Web, store, sessions, mqttStatus, blocking, forwardManager, settings, botSender, llmReloader)
|
||||||
webAddresses := []string{}
|
webAddresses := []string{}
|
||||||
if cfg.Web.PortEnabled {
|
if cfg.Web.PortEnabled {
|
||||||
httpServer := &http.Server{
|
httpServer := &http.Server{
|
||||||
|
|||||||
@@ -515,8 +515,8 @@ export function updateLLMProvider(name: string, payload: Partial<LLMProviderPayl
|
|||||||
return putJSON<LLMProviderResponse>(`/api/admin/llm/providers/${encodeURIComponent(name)}`, payload)
|
return putJSON<LLMProviderResponse>(`/api/admin/llm/providers/${encodeURIComponent(name)}`, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteLLMProvider(name: string): Promise<{ status: string }> {
|
export function deleteLLMProvider(name: string): Promise<{ status: string; warning?: string }> {
|
||||||
return deleteJSON<{ status: string }>(`/api/admin/llm/providers/${encodeURIComponent(name)}`)
|
return deleteJSON<{ status: string; warning?: string }>(`/api/admin/llm/providers/${encodeURIComponent(name)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLM Tool Router API
|
// LLM Tool Router API
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import type { LLMPlatformRouter, LLMTopicConfig, LLMProvider, LLMPrimaryConfig }
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const success = ref('')
|
const success = ref('')
|
||||||
|
const showWarning = ref(false)
|
||||||
|
|
||||||
// LLM Provider 相关
|
// LLM Provider 相关
|
||||||
const providers = ref<LLMProvider[]>([])
|
const providers = ref<LLMProvider[]>([])
|
||||||
@@ -169,12 +170,18 @@ async function saveProvider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
let response: any
|
||||||
if (isCreatingProvider.value) {
|
if (isCreatingProvider.value) {
|
||||||
await createLLMProvider(providerForm.value)
|
response = await createLLMProvider(providerForm.value)
|
||||||
success.value = '创建成功'
|
|
||||||
} else if (editingProvider.value) {
|
} else if (editingProvider.value) {
|
||||||
await updateLLMProvider(editingProvider.value.name, providerForm.value)
|
response = await updateLLMProvider(editingProvider.value.name, providerForm.value)
|
||||||
success.value = '更新成功'
|
}
|
||||||
|
if (response.warning) {
|
||||||
|
success.value = response.warning
|
||||||
|
showWarning.value = true
|
||||||
|
} else {
|
||||||
|
success.value = isCreatingProvider.value ? '创建成功' : '更新成功'
|
||||||
|
showWarning.value = false
|
||||||
}
|
}
|
||||||
clearSuccess()
|
clearSuccess()
|
||||||
closeProviderForm()
|
closeProviderForm()
|
||||||
@@ -189,8 +196,14 @@ async function confirmDeleteProvider(name: string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await deleteLLMProvider(name)
|
const response = await deleteLLMProvider(name)
|
||||||
success.value = '删除成功'
|
if (response.warning) {
|
||||||
|
success.value = response.warning
|
||||||
|
showWarning.value = true
|
||||||
|
} else {
|
||||||
|
success.value = '删除成功'
|
||||||
|
showWarning.value = false
|
||||||
|
}
|
||||||
clearSuccess()
|
clearSuccess()
|
||||||
await loadProviders()
|
await loadProviders()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -299,7 +312,7 @@ onMounted(() => {
|
|||||||
<h2>LLM API 配置管理</h2>
|
<h2>LLM API 配置管理</h2>
|
||||||
|
|
||||||
<p v-if="error" class="error">{{ error }}</p>
|
<p v-if="error" class="error">{{ error }}</p>
|
||||||
<p v-if="success" class="success">{{ success }}</p>
|
<p v-if="success" :class="showWarning ? 'warning' : 'success'">{{ success }}</p>
|
||||||
|
|
||||||
<!-- LLM Provider 列表 -->
|
<!-- LLM Provider 列表 -->
|
||||||
<div class="admin-section">
|
<div class="admin-section">
|
||||||
@@ -973,6 +986,19 @@ onMounted(() => {
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
color: #92400e;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
border: 1px solid #fcd34d;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.admin-loading {
|
.admin-loading {
|
||||||
padding: 3rem;
|
padding: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -644,6 +644,7 @@ export interface LLMProviderPayload {
|
|||||||
|
|
||||||
export interface LLMProviderResponse {
|
export interface LLMProviderResponse {
|
||||||
item: LLMProvider
|
item: LLMProvider
|
||||||
|
warning?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLM Tool Router 相关类型
|
// LLM Tool Router 相关类型
|
||||||
|
|||||||
Reference in New Issue
Block a user