This is an automated email from the ASF dual-hosted git repository. gongchao pushed a commit to branch ai-enhance in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
commit 2458a39cbecb1426cc9b25b8036c4cf343c0b66f Author: tomsun28 <[email protected]> AuthorDate: Wed Oct 22 22:58:59 2025 +0800 [chore] refactor ai service Signed-off-by: tomsun28 <[email protected]> --- .../hertzbeat/ai/agent/config/LlmConfig.java | 16 +-- .../impl/ChatClientProviderServiceImpl.java | 11 +- web-app/src/app/pojo/ModelProviderConfig.ts | 14 +- .../shared/components/ai-bot/ai-bot.component.html | 67 --------- .../shared/components/ai-bot/ai-bot.component.less | 147 ------------------- .../shared/components/ai-bot/ai-bot.component.scss | 158 --------------------- .../shared/components/ai-bot/ai-bot.component.ts | 72 ---------- .../shared/components/ai-chat/chat.component.ts | 14 +- web-app/src/app/shared/shared.module.ts | 2 - 9 files changed, 27 insertions(+), 474 deletions(-) diff --git a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java index 12a535f0d..7f8c65733 100644 --- a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java +++ b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java @@ -93,31 +93,31 @@ public class LlmConfig { modelProviderConfig.setBaseUrl("https://api.openai.com/v1"); } } - - OpenAiApi.Builder builder = new OpenAiApi.Builder(); - builder.baseUrl(modelProviderConfig.getBaseUrl()); - builder.apiKey(modelProviderConfig.getApiKey()); + if (modelProviderConfig.getModel() == null) { if ("openai".equals(modelProviderConfig.getCode())) { modelProviderConfig.setModel("gpt-5"); } else if ("zhipu".equals(modelProviderConfig.getCode())) { modelProviderConfig.setModel("glm-4.6"); - builder.completionsPath("/chat/completions"); } else if ("zai".equals(modelProviderConfig.getCode())) { modelProviderConfig.setModel("glm-4.6"); - builder.completionsPath("/chat/completions"); } else { modelProviderConfig.setModel("gpt-5"); } } + + OpenAiApi.Builder builder = new OpenAiApi.Builder(); + builder.baseUrl(modelProviderConfig.getBaseUrl()); + builder.apiKey(modelProviderConfig.getApiKey()); + builder.completionsPath("/chat/completions"); - // Create OpenAI Chat Options + // Create Chat Options OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder() .model(modelProviderConfig.getModel()) .temperature(0.3) .build(); - // Create OpenAI Chat Model + // Create Chat Model OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() .openAiApi(builder.build()) .defaultOptions(openAiChatOptions) diff --git a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ChatClientProviderServiceImpl.java b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ChatClientProviderServiceImpl.java index 5ab4af2d9..d8593a363 100644 --- a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ChatClientProviderServiceImpl.java +++ b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ChatClientProviderServiceImpl.java @@ -57,6 +57,8 @@ public class ChatClientProviderServiceImpl implements ChatClientProviderService @Qualifier("hertzbeatTools") @Autowired private ToolCallbackProvider toolCallbackProvider; + + private boolean isConfigured = false; @Autowired public ChatClientProviderServiceImpl(ApplicationContext applicationContext, GeneralConfigDao generalConfigDao) { @@ -112,8 +114,11 @@ public class ChatClientProviderServiceImpl implements ChatClientProviderService @Override public boolean isConfigured() { - GeneralConfig providerConfig = generalConfigDao.findByType("provider"); - ModelProviderConfig modelProviderConfig = JsonUtil.fromJson(providerConfig.getContent(), ModelProviderConfig.class); - return modelProviderConfig != null && modelProviderConfig.isStatus(); + if (!isConfigured) { + GeneralConfig providerConfig = generalConfigDao.findByType("provider"); + ModelProviderConfig modelProviderConfig = JsonUtil.fromJson(providerConfig.getContent(), ModelProviderConfig.class); + isConfigured = modelProviderConfig != null && modelProviderConfig.isStatus(); + } + return isConfigured; } } diff --git a/web-app/src/app/pojo/ModelProviderConfig.ts b/web-app/src/app/pojo/ModelProviderConfig.ts index dba2fba6e..5fe6dbbe3 100644 --- a/web-app/src/app/pojo/ModelProviderConfig.ts +++ b/web-app/src/app/pojo/ModelProviderConfig.ts @@ -42,16 +42,16 @@ export const PROVIDER_OPTIONS: ProviderOption[] = [ defaultBaseUrl: 'https://api.openai.com/v1', defaultModel: 'gpt-4' }, - { - value: 'zhipu', - label: 'ZhiPu (智谱)', - defaultBaseUrl: 'https://open.bigmodel.cn/api/paas/v4', - defaultModel: 'glm-4' - }, { value: 'zai', label: 'ZAI', defaultBaseUrl: 'https://api.z.ai/api/paas/v4', - defaultModel: 'glm-4' + defaultModel: 'glm-4.6' + }, + { + value: 'zhipu', + label: 'ZhiPu', + defaultBaseUrl: 'https://open.bigmodel.cn/api/paas/v4', + defaultModel: 'glm-4.6' } ]; diff --git a/web-app/src/app/shared/components/ai-bot/ai-bot.component.html b/web-app/src/app/shared/components/ai-bot/ai-bot.component.html deleted file mode 100644 index 8c06951e9..000000000 --- a/web-app/src/app/shared/components/ai-bot/ai-bot.component.html +++ /dev/null @@ -1,67 +0,0 @@ -<!-- - ~ Licensed to the Apache Software Foundation (ASF) under one - ~ or more contributor license agreements. See the NOTICE file - ~ distributed with this work for additional information - ~ regarding copyright ownership. The ASF licenses this file - ~ to you under the Apache License, Version 2.0 (the - ~ "License"); you may not use this file except in compliance - ~ with the License. You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, - ~ software distributed under the License is distributed on an - ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - ~ KIND, either express or implied. See the License for the - ~ specific language governing permissions and limitations - ~ under the License. ---> - -<div class="ai-bot-container"> - <div class="ai-bot-icon" (click)="toggleChat()" [class.active]="isOpen"> - <div *ngIf="!isOpen" class="robot-icon"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"> - <path - d="M12 2a2 2 0 0 1 2 2c0 .74-.4 1.39-1 1.73V7h1a7 7 0 0 1 7 7h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-1H2a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1a7 7 0 0 1 7-7h1V5.73c-.6-.34-1-.99-1-1.73a2 2 0 0 1 2-2M7.5 13A2.5 2.5 0 0 0 5 15.5A2.5 2.5 0 0 0 7.5 18a2.5 2.5 0 0 0 2.5-2.5A2.5 2.5 0 0 0 7.5 13m9 0a2.5 2.5 0 0 0-2.5 2.5a2.5 2.5 0 0 0 2.5 2.5a2.5 2.5 0 0 0 2.5-2.5a2.5 2.5 0 0 0-2.5-2.5z" - /> - </svg> - </div> - <div *ngIf="isOpen" class="close-icon">X</div> - </div> - - <div class="ai-bot-chat-window" *ngIf="isOpen"> - <div class="chat-header"> - <div class="chat-title"> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 24 24" - width="20" - height="20" - fill="currentColor" - style="margin-right: 6px; vertical-align: middle" - > - <path - d="M12 2a2 2 0 0 1 2 2c0 .74-.4 1.39-1 1.73V7h1a7 7 0 0 1 7 7h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-1H2a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1a7 7 0 0 1 7-7h1V5.73c-.6-.34-1-.99-1-1.73a2 2 0 0 1 2-2M7.5 13A2.5 2.5 0 0 0 5 15.5A2.5 2.5 0 0 0 7.5 18a2.5 2.5 0 0 0 2.5-2.5A2.5 2.5 0 0 0 7.5 13m9 0a2.5 2.5 0 0 0-2.5 2.5a2.5 2.5 0 0 0 2.5 2.5a2.5 2.5 0 0 0 2.5-2.5a2.5 2.5 0 0 0-2.5-2.5z" - /> - </svg> - {{ 'ai.bot.title' | i18n }} - </div> - <span class="close-btn" (click)="toggleChat()">X</span> - </div> - - <div class="chat-messages"> - <div *ngFor="let message of messages" class="message" [class.user-message]="message.isUser" [class.bot-message]="!message.isUser"> - <div class="message-content">{{ message.content }}</div> - <div class="message-time">{{ message.timestamp | date : 'HH:mm' }}</div> - </div> - <div *ngIf="isLoading" class="bot-message loading-message"> - <nz-spin nzSimple></nz-spin> - </div> - </div> - - <div class="chat-input"> - <input nz-input placeholder="{{ 'ai.bot.input.placeholder' | i18n }}" [(ngModel)]="currentMessage" (keyup.enter)="sendMessage()" /> - <button nz-button nzType="primary" [disabled]="!currentMessage.trim()" (click)="sendMessage()"> {{ 'ai.bot.send' | i18n }} </button> - </div> - </div> -</div> diff --git a/web-app/src/app/shared/components/ai-bot/ai-bot.component.less b/web-app/src/app/shared/components/ai-bot/ai-bot.component.less deleted file mode 100644 index 03fe1519e..000000000 --- a/web-app/src/app/shared/components/ai-bot/ai-bot.component.less +++ /dev/null @@ -1,147 +0,0 @@ -.ai-bot-container { - position: fixed; - bottom: 30px; - right: 30px; - z-index: 10000; -} - -.ai-bot-icon { - width: 60px; - height: 60px; - border-radius: 50%; - background-color: #1890ff; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - transition: all 0.3s; - color: white; - font-weight: bold; - font-size: 18px; - - &:hover { - transform: scale(1.05); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); - } - - &.active { - background-color: #ff4d4f; - } -} - -.ai-bot-icon-text { - width: 60px; - height: 60px; - border-radius: 50%; - background-color: #1890ff; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - transition: all 0.3s; - color: white; - font-weight: bold; - font-size: 14px; - text-align: center; - - &:hover { - transform: scale(1.05); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); - } -} - -.ai-bot-chat-window { - position: absolute; - bottom: 80px; - right: 0; - width: 350px; - height: 500px; - background-color: white; - border-radius: 8px; - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); - display: flex; - flex-direction: column; - overflow: hidden; - z-index: 10000; -} - -.chat-header { - padding: 12px 16px; - border-bottom: 1px solid #f0f0f0; - display: flex; - justify-content: space-between; - align-items: center; - background-color: #1890ff; - color: white; - - .chat-title { - font-weight: 500; - font-size: 16px; - } - - .close-btn { - cursor: pointer; - font-size: 16px; - color: white; - font-weight: bold; - } -} - -.chat-messages { - flex: 1; - padding: 16px; - overflow-y: auto; - display: flex; - flex-direction: column; - gap: 12px; - background-color: #f5f5f5; -} - -.message { - max-width: 80%; - padding: 10px 12px; - border-radius: 8px; - position: relative; - - .message-content { - word-break: break-word; - } - - .message-time { - font-size: 11px; - margin-top: 4px; - opacity: 0.7; - text-align: right; - } -} - -.bot-message { - align-self: flex-start; - background-color: white; - border: 1px solid #e8e8e8; - - &.loading-message { - padding: 16px; - display: flex; - justify-content: center; - } -} - -.user-message { - align-self: flex-end; - background-color: #e6f7ff; - color: #0050b3; -} - -.chat-input { - padding: 12px; - border-top: 1px solid #f0f0f0; - display: flex; - gap: 8px; - - input { - flex: 1; - } -} \ No newline at end of file diff --git a/web-app/src/app/shared/components/ai-bot/ai-bot.component.scss b/web-app/src/app/shared/components/ai-bot/ai-bot.component.scss deleted file mode 100644 index b33c34ecc..000000000 --- a/web-app/src/app/shared/components/ai-bot/ai-bot.component.scss +++ /dev/null @@ -1,158 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -.ai-bot-container { - position: fixed; - bottom: 20px; - right: 20px; - z-index: 1000; -} - -.ai-bot-icon { - width: 50px; - height: 50px; - border-radius: 50%; - background-color: #1890ff; - color: white; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - transition: all 0.3s ease; -} - -.ai-bot-icon:hover { - transform: scale(1.05); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); -} - -.ai-bot-icon.active { - background-color: #f5222d; -} - -/* 机器人图标样式 */ -.robot-icon { - width: 30px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; -} - -.robot-icon svg { - width: 100%; - height: 100%; - fill: white; /* 确保SVG是白色 */ -} - -/* 关闭图标样式 */ -.close-icon { - font-weight: bold; - font-size: 18px; -} - -.ai-bot-chat-window { - position: absolute; - bottom: 70px; - right: 0; - width: 320px; - height: 450px; - border-radius: 8px; - background-color: white; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - display: flex; - flex-direction: column; - overflow: hidden; -} - -.chat-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 12px 16px; - background-color: #1890ff; - color: white; -} - -.chat-title { - font-weight: 500; - display: flex; - align-items: center; -} - -.close-btn { - cursor: pointer; - font-weight: bold; -} - -.chat-messages { - flex: 1; - overflow-y: auto; - padding: 16px; - display: flex; - flex-direction: column; - gap: 12px; - background-color: #f5f5f5; -} - -.message { - max-width: 80%; - padding: 8px 12px; - border-radius: 12px; -} - -.user-message { - align-self: flex-end; - background-color: #1890ff; - color: white; -} - -.bot-message { - align-self: flex-start; - background-color: white; - color: #333; - border: 1px solid #e8e8e8; -} - -.message-content { - word-break: break-word; - white-space: pre-wrap; -} - -.message-time { - font-size: 12px; - margin-top: 4px; - opacity: 0.7; - text-align: right; -} - -.loading-message { - padding: 8px; - text-align: center; -} - -.chat-input { - display: flex; - padding: 12px; - border-top: 1px solid #e8e8e8; -} - -.chat-input input { - flex: 1; - margin-right: 8px; -} diff --git a/web-app/src/app/shared/components/ai-bot/ai-bot.component.ts b/web-app/src/app/shared/components/ai-bot/ai-bot.component.ts deleted file mode 100644 index 7975eab9e..000000000 --- a/web-app/src/app/shared/components/ai-bot/ai-bot.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Component, OnInit } from '@angular/core'; -import { I18NService } from '@core'; - -import { AiBotService, ChatMessage } from '../../services/ai-bot.service'; - -@Component({ - selector: 'app-ai-bot', - templateUrl: './ai-bot.component.html', - styleUrls: ['./ai-bot.component.less'] -}) -export class AiBotComponent implements OnInit { - isOpen = false; - messages: ChatMessage[] = []; - currentMessage = ''; - isLoading = false; - - constructor(private aiBotService: AiBotService, private i18nSvc: I18NService) {} - - ngOnInit(): void { - // add greeting message - this.messages.push({ - content: this.i18nSvc.fanyi('ai.bot.greeting'), - isUser: false, - timestamp: new Date() - }); - console.log('The AI assistant component has loaded.'); - } - - toggleChat(): void { - this.isOpen = !this.isOpen; - } - - sendMessage(): void { - if (!this.currentMessage.trim()) return; - - // add user message - this.messages.push({ - content: this.currentMessage, - isUser: true, - timestamp: new Date() - }); - - const userMessage = this.currentMessage; - this.currentMessage = ''; - this.isLoading = true; - - // call service to fetch AI response - this.aiBotService.sendMessage(userMessage).subscribe(response => { - this.messages.push(response); - this.isLoading = false; - }); - } -} diff --git a/web-app/src/app/shared/components/ai-chat/chat.component.ts b/web-app/src/app/shared/components/ai-chat/chat.component.ts index 068a0a7ba..b47365bcd 100644 --- a/web-app/src/app/shared/components/ai-chat/chat.component.ts +++ b/web-app/src/app/shared/components/ai-chat/chat.component.ts @@ -62,7 +62,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { ngOnInit(): void { this.theme = this.themeSvc.getTheme() || 'default'; - this.checkOpenAiConfiguration(); + this.checkAiConfiguration(); } ngAfterViewChecked(): void { @@ -73,10 +73,8 @@ export class ChatComponent implements OnInit, AfterViewChecked { * Load all conversations */ loadConversations(): void { - console.log('Loading conversations...'); this.aiChatService.getConversations().subscribe({ next: response => { - console.log('Conversations response:', response); if (response.code === 0 && response.data) { this.conversations = response.data; // If no current conversation, create a new one @@ -106,10 +104,8 @@ export class ChatComponent implements OnInit, AfterViewChecked { * Create a new conversation */ createNewConversation(): void { - console.log('Creating new conversation...'); this.aiChatService.createConversation().subscribe({ next: response => { - console.log('Create conversation response:', response); if (response.code === 0 && response.data) { const newConversation = response.data; this.conversations.unshift(newConversation); @@ -164,7 +160,6 @@ export class ChatComponent implements OnInit, AfterViewChecked { this.aiChatService.getConversation(conversationId).subscribe({ next: response => { this.isLoading = false; - console.log('Conversation history response:', response); if (response.code === 0 && response.data) { this.messages = response.data.messages || []; @@ -321,7 +316,6 @@ export class ChatComponent implements OnInit, AfterViewChecked { this.scrollToBottom(); }, complete: () => { - console.log('Chat stream completed'); this.isLoading = false; this.cdr.detectChanges(); @@ -429,7 +423,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { /** * Check provider configuration status */ - checkOpenAiConfiguration(): void { + checkAiConfiguration(): void { this.generalConfigSvc.getModelProviderConfig().subscribe({ next: response => { if (response.code === 0 && response.data) { @@ -451,7 +445,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { } } - if (!response.data.enable) { + if (response.data.enable) { this.loadConversations(); } else { this.showAiProviderConfigDialog(response.data.error); @@ -510,7 +504,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { * Show configuration modal */ onShowConfigModal(): void { - this.checkOpenAiConfiguration(); + this.checkAiConfiguration(); this.showConfigModal = true; } diff --git a/web-app/src/app/shared/shared.module.ts b/web-app/src/app/shared/shared.module.ts index ee9e6e62f..0d499cddf 100644 --- a/web-app/src/app/shared/shared.module.ts +++ b/web-app/src/app/shared/shared.module.ts @@ -20,7 +20,6 @@ import { NzTagModule } from 'ng-zorro-antd/tag'; // Icon to be used for registration const icons: IconDefinition[] = [RobotOutline, CloseOutline, SendOutline]; -import { AiBotComponent } from './components/ai-bot/ai-bot.component'; import { AiChatModule } from './components/ai-chat/ai-chat.module'; import { ConfigurableFieldComponent } from './components/configurable-field/configurable-field.component'; import { FormFieldComponent } from './components/form-field/form-field.component'; @@ -43,7 +42,6 @@ const COMPONENTS: Array<Type<void>> = [ ConfigurableFieldComponent, FormFieldComponent, MonitorSelectMenuComponent, - AiBotComponent, LabelSelectorComponent ]; const DIRECTIVES: Array<Type<void>> = [TimezonePipe, I18nElsePipe, ElapsedTimePipe]; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
