Bläddra i källkod

enhance: llm and code completion

0xJacky 5 månader sedan
förälder
incheckning
a982c04898
63 ändrade filer med 2180 tillägg och 1389 borttagningar
  1. 4 1
      .devcontainer/docker-compose.yml
  2. 2 2
      api/config/rename.go
  3. 1 1
      api/llm/code_completion.go
  4. 3 3
      api/llm/llm.go
  5. 5 5
      api/llm/record.go
  6. 17 0
      api/llm/router.go
  7. 4 4
      api/llm/store.go
  8. 0 13
      api/openai/router.go
  9. 4 4
      app/components.d.ts
  10. 2 2
      app/src/api/config.ts
  11. 6 6
      app/src/api/llm.ts
  12. 2 2
      app/src/api/stream.ts
  13. 0 77
      app/src/components/ChatGPT/ChatGPT.vue
  14. 360 31
      app/src/components/CodeEditor/CodeCompletion.ts
  15. 32 0
      app/src/components/CodeEditor/CodeEditor.vue
  16. 100 10
      app/src/components/LLM/ChatMessage.vue
  17. 7 7
      app/src/components/LLM/ChatMessageInput.vue
  18. 11 11
      app/src/components/LLM/ChatMessageList.vue
  19. 109 0
      app/src/components/LLM/LLM.vue
  20. 2 3
      app/src/components/LLM/chatService.ts
  21. 0 0
      app/src/components/LLM/composables/useTypewriter.ts
  22. 144 0
      app/src/components/LLM/contextBuilder.ts
  23. 2 2
      app/src/components/LLM/index.ts
  24. 40 18
      app/src/components/LLM/llm.ts
  25. 0 0
      app/src/components/LLM/markdown.ts
  26. 1 1
      app/src/components/LLM/types.ts
  27. 0 0
      app/src/components/LLM/utils.ts
  28. 48 47
      app/src/language/ar/app.po
  29. 48 47
      app/src/language/de_DE/app.po
  30. 42 47
      app/src/language/en/app.po
  31. 48 47
      app/src/language/es/app.po
  32. 48 47
      app/src/language/fr_FR/app.po
  33. 48 47
      app/src/language/ja_JP/app.po
  34. 48 47
      app/src/language/ko_KR/app.po
  35. 42 46
      app/src/language/messages.pot
  36. 48 47
      app/src/language/pt_PT/app.po
  37. 48 47
      app/src/language/ru_RU/app.po
  38. 48 47
      app/src/language/tr_TR/app.po
  39. 48 47
      app/src/language/uk_UA/app.po
  40. 48 47
      app/src/language/vi_VN/app.po
  41. 49 48
      app/src/language/zh_CN/app.po
  42. 48 47
      app/src/language/zh_TW/app.po
  43. 1 1
      app/src/version.json
  44. 2 2
      app/src/views/config/components/ConfigRightPanel/Chat.vue
  45. 77 75
      app/src/views/nginx_log/NginxLogList.vue
  46. 26 1
      app/src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue
  47. 2 2
      app/src/views/site/site_edit/components/RightPanel/Chat.vue
  48. 2 2
      app/src/views/stream/components/RightPanel/Chat.vue
  49. BIN
      cmd/generate_licenses/internal/license/licenses.xz
  50. 1 1
      internal/config/delete.go
  51. 69 18
      internal/llm/code_completion.go
  52. 46 0
      internal/migrate/7.rename_chatgpt_logs_to_llm_messages.go
  53. 1 0
      internal/migrate/migrate.go
  54. 1 1
      internal/site/rename.go
  55. 2 2
      internal/stream/rename.go
  56. 3 3
      mcp/config/config_get.go
  57. 2 2
      mcp/config/config_rename.go
  58. 7 6
      model/llm_messages.go
  59. 1 1
      model/model.go
  60. 0 354
      query/chat_gpt_logs.gen.go
  61. 8 8
      query/gen.go
  62. 354 0
      query/llm_messages.gen.go
  63. 8 2
      router/routers.go

+ 4 - 1
.devcontainer/docker-compose.yml

@@ -6,7 +6,7 @@ services:
     volumes:
       - ~/.ssh:/root/.ssh
       - ../..:/workspaces:cached
-      - ../.go:/root/go
+      - go-modules:/root/go
       - ./data/nginx:/etc/nginx
       - ./data/nginx-logs:/var/log/nginx
       - /var/run/docker.sock:/var/run/docker.sock
@@ -82,3 +82,6 @@ services:
 
 networks:
   nginxui:
+
+volumes:
+  go-modules:

+ 2 - 2
api/config/rename.go

@@ -75,8 +75,8 @@ func Rename(c *gin.Context) {
 		return
 	}
 
-	// update ChatGPT records
-	g := query.ChatGPTLog
+	// update LLM records
+	g := query.LLMMessages
 	q := query.Config
 	cfg, err := q.Where(q.Filepath.Eq(origFullPath)).FirstOrInit()
 	if err != nil {

+ 1 - 1
api/openai/code_completion.go → api/llm/code_completion.go

@@ -1,4 +1,4 @@
-package openai
+package llm
 
 import (
 	"net/http"

+ 3 - 3
api/openai/openai.go → api/llm/llm.go

@@ -1,4 +1,4 @@
-package openai
+package llm
 
 import (
 	"context"
@@ -17,7 +17,7 @@ import (
 	"github.com/uozi-tech/cosy/logger"
 )
 
-const ChatGPTInitPrompt = `You are a assistant who can help users write and optimise the configurations of Nginx,
+const LLMInitPrompt = `You are a assistant who can help users write and optimise the configurations of Nginx,
 the first user message contains the content of the configuration file which is currently opened by the user and
 the current language code(CLC). You suppose to use the language corresponding to the CLC to give the first reply.
 Later the language environment depends on the user message.
@@ -36,7 +36,7 @@ func MakeChatCompletionRequest(c *gin.Context) {
 	messages := []openai.ChatCompletionMessage{
 		{
 			Role:    openai.ChatMessageRoleSystem,
-			Content: ChatGPTInitPrompt,
+			Content: LLMInitPrompt,
 		},
 	}
 

+ 5 - 5
api/openai/record.go → api/llm/record.go

@@ -1,4 +1,4 @@
-package openai
+package llm
 
 import (
 	"net/http"
@@ -10,7 +10,7 @@ import (
 	"github.com/uozi-tech/cosy"
 )
 
-func GetChatGPTRecord(c *gin.Context) {
+func GetLLMRecord(c *gin.Context) {
 	absPath := c.Query("path")
 
 	if !helper.IsUnderDirectory(absPath, nginx.GetConfPath()) {
@@ -20,12 +20,12 @@ func GetChatGPTRecord(c *gin.Context) {
 		return
 	}
 
-	g := query.ChatGPTLog
-	chatgpt, err := g.Where(g.Name.Eq(absPath)).FirstOrCreate()
+	g := query.LLMMessages
+	llmMsg, err := g.Where(g.Name.Eq(absPath)).FirstOrCreate()
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
 	}
 
-	c.JSON(http.StatusOK, chatgpt)
+	c.JSON(http.StatusOK, llmMsg)
 }

+ 17 - 0
api/llm/router.go

@@ -0,0 +1,17 @@
+package llm
+
+import "github.com/gin-gonic/gin"
+
+func InitRouter(r *gin.RouterGroup) {
+	r.GET("llm_messages", GetLLMRecord)
+	r.POST("llm_messages", StoreLLMRecord)
+}
+
+// InitLocalRouter for main node only (no proxy)
+func InitLocalRouter(r *gin.RouterGroup) {
+	// LLM endpoints that should only run on main node
+	r.POST("llm", MakeChatCompletionRequest)
+	// Code Completion
+	r.GET("code_completion", CodeCompletion)
+	r.GET("code_completion/enabled", GetCodeCompletionEnabledStatus)
+}

+ 4 - 4
api/openai/store.go → api/llm/store.go

@@ -1,4 +1,4 @@
-package openai
+package llm
 
 import (
 	"net/http"
@@ -10,7 +10,7 @@ import (
 	"github.com/uozi-tech/cosy"
 )
 
-func StoreChatGPTRecord(c *gin.Context) {
+func StoreLLMRecord(c *gin.Context) {
 	var json struct {
 		FileName string                         `json:"file_name"`
 		Messages []openai.ChatCompletionMessage `json:"messages"`
@@ -21,7 +21,7 @@ func StoreChatGPTRecord(c *gin.Context) {
 	}
 
 	name := json.FileName
-	g := query.ChatGPTLog
+	g := query.LLMMessages
 	_, err := g.Where(g.Name.Eq(name)).FirstOrCreate()
 
 	if err != nil {
@@ -29,7 +29,7 @@ func StoreChatGPTRecord(c *gin.Context) {
 		return
 	}
 
-	_, err = g.Where(g.Name.Eq(name)).Updates(&model.ChatGPTLog{
+	_, err = g.Where(g.Name.Eq(name)).Updates(&model.LLMMessages{
 		Name:    name,
 		Content: json.Messages,
 	})

+ 0 - 13
api/openai/router.go

@@ -1,13 +0,0 @@
-package openai
-
-import "github.com/gin-gonic/gin"
-
-func InitRouter(r *gin.RouterGroup) {
-	// ChatGPT
-	r.POST("chatgpt", MakeChatCompletionRequest)
-	r.GET("chatgpt/history", GetChatGPTRecord)
-	r.POST("chatgpt_record", StoreChatGPTRecord)
-	// Code Completion
-	r.GET("code_completion", CodeCompletion)
-	r.GET("code_completion/enabled", GetCodeCompletionEnabledStatus)
-}

+ 4 - 4
app/components.d.ts

@@ -80,15 +80,15 @@ declare module 'vue' {
     ChartAreaChart: typeof import('./src/components/Chart/AreaChart.vue')['default']
     ChartRadialBarChart: typeof import('./src/components/Chart/RadialBarChart.vue')['default']
     ChartUsageProgressLine: typeof import('./src/components/Chart/UsageProgressLine.vue')['default']
-    ChatGPTChatGPT: typeof import('./src/components/ChatGPT/ChatGPT.vue')['default']
-    ChatGPTChatMessage: typeof import('./src/components/ChatGPT/ChatMessage.vue')['default']
-    ChatGPTChatMessageInput: typeof import('./src/components/ChatGPT/ChatMessageInput.vue')['default']
-    ChatGPTChatMessageList: typeof import('./src/components/ChatGPT/ChatMessageList.vue')['default']
     CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
     ConfigHistoryConfigHistory: typeof import('./src/components/ConfigHistory/ConfigHistory.vue')['default']
     ConfigHistoryDiffViewer: typeof import('./src/components/ConfigHistory/DiffViewer.vue')['default']
     FooterToolbarFooterToolBar: typeof import('./src/components/FooterToolbar/FooterToolBar.vue')['default']
     ICPICP: typeof import('./src/components/ICP/ICP.vue')['default']
+    LLMChatMessage: typeof import('./src/components/LLM/ChatMessage.vue')['default']
+    LLMChatMessageInput: typeof import('./src/components/LLM/ChatMessageInput.vue')['default']
+    LLMChatMessageList: typeof import('./src/components/LLM/ChatMessageList.vue')['default']
+    LLMLLM: typeof import('./src/components/LLM/LLM.vue')['default']
     LogoLogo: typeof import('./src/components/Logo/Logo.vue')['default']
     NamespaceRenderNamespaceRender: typeof import('./src/components/NamespaceRender/NamespaceRender.vue')['default']
     NamespaceTabsNamespaceTabs: typeof import('./src/components/NamespaceTabs/NamespaceTabs.vue')['default']

+ 2 - 2
app/src/api/config.ts

@@ -1,6 +1,6 @@
 import type { AxiosRequestConfig } from '@uozi-admin/request'
 import type { GetListResponse } from '@/api/curd'
-import type { ChatComplicationMessage } from '@/api/openai'
+import type { ChatComplicationMessage } from '@/api/llm'
 import { extendCurdApi, http, useCurdApi } from '@uozi-admin/request'
 
 export interface ModelBase {
@@ -12,7 +12,7 @@ export interface ModelBase {
 export interface Config {
   name: string
   content: string
-  chatgpt_messages: ChatComplicationMessage[]
+  llm_messages: ChatComplicationMessage[]
   filepath: string
   modified_at: string
   sync_node_ids?: number[]

+ 6 - 6
app/src/api/openai.ts → app/src/api/llm.ts

@@ -23,12 +23,12 @@ export interface CodeCompletionResponse {
   code: string // Completed code
 }
 
-const openai = {
-  get_record(path: string) {
-    return http.get(`/chatgpt/history`, { params: { path } })
+const llm = {
+  get_messages(path: string) {
+    return http.get(`/llm_messages`, { params: { path } })
   },
-  store_record(data: { file_name?: string, messages?: ChatComplicationMessage[] }) {
-    return http.post('/chatgpt_record', data)
+  store_messages(data: { file_name?: string, messages?: ChatComplicationMessage[] }) {
+    return http.post('/llm_messages', data)
   },
   code_completion() {
     return ws('/api/code_completion') as ReconnectingWebSocket
@@ -38,4 +38,4 @@ const openai = {
   },
 }
 
-export default openai
+export default llm

+ 2 - 2
app/src/api/stream.ts

@@ -1,6 +1,6 @@
 import type { Namespace } from './namespace'
+import type { ChatComplicationMessage } from '@/api/llm'
 import type { NgxConfig } from '@/api/ngx'
-import type { ChatComplicationMessage } from '@/api/openai'
 import type { ProxyTarget, SiteStatus } from '@/api/site'
 import { extendCurdApi, http, useCurdApi } from '@uozi-admin/request'
 
@@ -11,7 +11,7 @@ export interface Stream {
   name: string
   filepath: string
   config: string
-  chatgpt_messages: ChatComplicationMessage[]
+  llm_messages: ChatComplicationMessage[]
   tokenized?: NgxConfig
   namespace_id: number
   namespace?: Namespace

+ 0 - 77
app/src/components/ChatGPT/ChatGPT.vue

@@ -1,77 +0,0 @@
-<script setup lang="ts">
-import Icon from '@ant-design/icons-vue'
-import { useElementVisibility } from '@vueuse/core'
-import { storeToRefs } from 'pinia'
-import ChatGPT_logo from '@/assets/svg/ChatGPT_logo.svg?component'
-import { useSettingsStore } from '@/pinia'
-import { useChatGPTStore } from './chatgpt'
-import ChatMessageInput from './ChatMessageInput.vue'
-import ChatMessageList from './ChatMessageList.vue'
-
-const props = defineProps<{
-  content: string
-  path?: string
-}>()
-
-const { language: current } = storeToRefs(useSettingsStore())
-
-// Use ChatGPT store
-const chatGPTStore = useChatGPTStore()
-const { messageContainerRef, loading, shouldShowStartButton } = storeToRefs(chatGPTStore)
-
-// Initialize messages when path changes
-watch(() => props.path, async () => {
-  await chatGPTStore.initMessages(props.path)
-  await nextTick()
-}, { immediate: true })
-
-// Send message handler
-async function handleSend() {
-  await chatGPTStore.send(props.content, current.value)
-}
-
-const isVisible = useElementVisibility(messageContainerRef)
-
-watch(isVisible, visible => {
-  if (visible) {
-    chatGPTStore.scrollToBottom()
-  }
-}, { immediate: true })
-</script>
-
-<template>
-  <div
-    v-if="shouldShowStartButton"
-    class="chat-start m-4"
-  >
-    <AButton
-      :loading="loading"
-      @click="handleSend"
-    >
-      <Icon
-        v-if="!loading"
-        :component="ChatGPT_logo"
-      />
-      {{ $gettext('Ask ChatGPT for Help') }}
-    </AButton>
-  </div>
-
-  <div
-    v-else
-    ref="messageContainerRef"
-    class="message-container"
-  >
-    <ChatMessageList />
-
-    <ChatMessageInput />
-  </div>
-</template>
-
-<style lang="less" scoped>
-.message-container {
-  margin: 0 auto;
-  max-width: 800px;
-  max-height: calc(100vh - 260px);
-  overflow-y: auto;
-}
-</style>

+ 360 - 31
app/src/components/CodeEditor/CodeCompletion.ts

@@ -1,15 +1,26 @@
 import type { Editor } from 'ace-builds'
 import type { Point } from 'ace-builds-internal/document'
 import type ReconnectingWebSocket from 'reconnecting-websocket'
+import ace from 'ace-builds'
 import { debounce } from 'lodash'
 import { v4 as uuidv4 } from 'uuid'
-import openai from '@/api/openai'
+import llm from '@/api/llm'
 
-// eslint-disable-next-line ts/no-explicit-any
-function debug(...args: any[]) {
+function debug(...args: unknown[]) {
   if (import.meta.env.DEV) {
+    // Create console method that skips one frame in stack trace
     // eslint-disable-next-line no-console
-    console.debug(`[CodeEditor]`, ...args)
+    const originalDebug = console.debug
+    const skipFrame = (...logArgs: unknown[]) => {
+      const stack = new Error('Debug trace').stack
+      const caller = stack?.split('\n')[3] // Skip debug() and skipFrame()
+      const match = caller?.match(/at\s[^(]+\([^:]+:(\d+):\d+\)/) || caller?.match(/at\s[^:]+:(\d+):\d+/)
+      const location = `line ${match?.[1] || '?'}`
+
+      originalDebug(`[CodeEditor:${location}]`, ...logArgs)
+    }
+
+    skipFrame(...args)
   }
 }
 
@@ -27,6 +38,10 @@ function useCodeCompletion() {
   const editorRef = ref<Editor>()
   const currentGhostText = ref<string>('')
   const isConfigFile = ref<boolean>(false)
+  const isLoading = ref<boolean>(false)
+  const loadingMarkerId = ref<number | null>(null)
+  const lastTriggerTime = ref<number>(0)
+  const lastTriggerPosition = ref<{ row: number, column: number } | null>(null)
 
   const ws = shallowRef<ReconnectingWebSocket>()
 
@@ -46,25 +61,228 @@ function useCodeCompletion() {
     return SENSITIVE_CONTENT_PATTERNS.some(pattern => pattern.test(content))
   }
 
-  function getAISuggestions(code: string, context: string, position: Point, callback: (suggestion: string) => void, language: string = 'nginx', suffix: string = '', requestId: string) {
+  // Show loading spinner at cursor position
+  function showLoadingSpinner() {
+    if (!editorRef.value || isLoading.value)
+      return
+
+    const position = editorRef.value.getCursorPosition()
+    const Range = ace.require('ace/range').Range
+
+    // Create a small range at cursor position for the spinner
+    const range = new Range(position.row, position.column, position.row, position.column + 1)
+
+    loadingMarkerId.value = editorRef.value.session.addMarker(
+      range,
+      'completion-loading-spinner',
+      'text',
+      false,
+    )
+
+    isLoading.value = true
+    debug('Loading spinner shown')
+  }
+
+  // Clear loading spinner
+  function clearLoadingSpinner() {
+    if (!editorRef.value || !isLoading.value)
+      return
+
+    if (loadingMarkerId.value !== null) {
+      editorRef.value.session.removeMarker(loadingMarkerId.value)
+      loadingMarkerId.value = null
+    }
+
+    isLoading.value = false
+    debug('Loading spinner cleared')
+  }
+
+  // Get current line indentation
+  function getCurrentLineIndent(editor: Editor): string {
+    const position = editor.getCursorPosition()
+    const currentLine = editor.session.getLine(position.row)
+
+    // Extract indentation (spaces/tabs at the beginning of line)
+    const indentMatch = currentLine.match(/^(\s*)/)
+    return indentMatch ? indentMatch[1] : ''
+  }
+
+  // Intelligent trigger condition checking
+  function checkRateLimit(): boolean {
+    const currentTime = Date.now()
+    if (currentTime - lastTriggerTime.value < 800) {
+      debug(`Skipping completion: too frequent triggers. Time diff: ${currentTime - lastTriggerTime.value}ms`)
+      return false
+    }
+    return true
+  }
+
+  function checkPositionLimit(position: Point): boolean {
+    if (lastTriggerPosition.value) {
+      const rowDiff = Math.abs(position.row - lastTriggerPosition.value.row)
+      const colDiff = Math.abs(position.column - lastTriggerPosition.value.column)
+
+      if (rowDiff === 0 && colDiff < 4) {
+        debug(`Skipping completion: cursor position too close to last trigger. Row diff: ${rowDiff}, Col diff: ${colDiff}`)
+        return false
+      }
+    }
+    return true
+  }
+
+  function updateTriggerTracking(position: Point): void {
+    const currentTime = Date.now()
+    lastTriggerTime.value = currentTime
+    lastTriggerPosition.value = { row: position.row, column: position.column }
+  }
+
+  function checkShortLineContext(editor: Editor, position: Point, beforeCursor: string): boolean {
+    if (beforeCursor.trim().length >= 2)
+      return true
+
+    const isEmptyLineInBlock = /^\s+$/.test(beforeCursor) && beforeCursor.length > 0
+    const prevLine = position.row > 0 ? editor.session.getLine(position.row - 1) : ''
+    const afterComment = /^\s*[#/]/.test(prevLine)
+
+    if (!isEmptyLineInBlock && !afterComment) {
+      debug('Skipping completion: line too short and not in meaningful context')
+      return false
+    }
+
+    if (isEmptyLineInBlock || afterComment) {
+      debug('Allowing completion: empty line in block or after comment')
+      updateTriggerTracking(position)
+      return true
+    }
+
+    return false
+  }
+
+  function checkWordBoundary(beforeCursor: string, afterCursor: string): boolean {
+    if (afterCursor.match(/^\w/) && !beforeCursor.endsWith('{')) {
+      debug('Skipping completion: cursor in middle of word')
+      return false
+    }
+    return true
+  }
+
+  function checkCommentLine(currentLine: string, position: Point): boolean {
+    const isCommentLine = /^\s*[#/]/.test(currentLine)
+    if (isCommentLine) {
+      const commentContent = currentLine.replace(/^\s*[#/]+\s*/, '')
+      const hasDirectivePattern = /\b(?:proxy_pass|server_name|root|listen|location)\b/.test(commentContent)
+
+      if (!hasDirectivePattern || position.column < currentLine.length - 1) {
+        debug('Skipping completion: comment line without directive pattern or not at end')
+        return false
+      }
+    }
+    return true
+  }
+
+  function checkLineCompletion(currentLine: string, position: Point): boolean {
+    const trimmedLine = currentLine.trim()
+    const atLineEnd = position.column === currentLine.length
+
+    if (trimmedLine.endsWith(';') || (trimmedLine.endsWith('}') && !atLineEnd)) {
+      debug('Skipping completion: line appears complete')
+      return false
+    }
+    return true
+  }
+
+  function shouldTriggerCompletion(editor: Editor): boolean {
+    if (!editor)
+      return false
+
+    const position = editor.getCursorPosition()
+
+    if (!checkRateLimit() || !checkPositionLimit(position)) {
+      return false
+    }
+
+    const currentLine = editor.session.getLine(position.row)
+    const beforeCursor = currentLine.substring(0, position.column)
+    const afterCursor = currentLine.substring(position.column)
+
+    const shortLineResult = checkShortLineContext(editor, position, beforeCursor)
+    if (beforeCursor.trim().length < 2) {
+      return shortLineResult
+    }
+
+    if (!checkWordBoundary(beforeCursor, afterCursor) || !checkCommentLine(currentLine, position) || !checkLineCompletion(currentLine, position)) {
+      return false
+    }
+
+    const trimmedLine = currentLine.trim()
+    const atLineEnd = position.column === currentLine.length
+
+    if (trimmedLine.endsWith('{') && atLineEnd) {
+      debug('Allowing completion after opening brace at line end')
+      return true
+    }
+
+    if (/["'[(]\s*$/.test(beforeCursor)) {
+      debug('Skipping completion: cursor after quote/bracket')
+      return false
+    }
+
+    if (beforeCursor.endsWith('  ')) {
+      debug('Skipping completion: multiple spaces detected')
+      return false
+    }
+
+    // Check each trigger pattern individually for better debugging
+    const triggerPatterns = [
+      { name: 'After directive keywords', pattern: /\b(?:server|location|upstream|if|proxy_pass|root|index|listen|server_name)\s+$/ },
+      { name: 'Right after opening brace', pattern: /\{\s*$/ },
+      { name: 'After semicolons', pattern: /;\s*$/ },
+      { name: 'Partial directive names', pattern: /^\s+[a-z_]{3,}$/i },
+      { name: 'Comment with directive', pattern: /^\s*#.*\b(?:proxy_pass|server_name|root|listen|location)\b/ },
+      { name: 'Empty line in block', pattern: /^\s+$/ },
+    ]
+
+    let shouldTrigger = false
+
+    for (const { name, pattern } of triggerPatterns) {
+      if (pattern.test(beforeCursor)) {
+        shouldTrigger = true
+        debug(`✅ Trigger match: ${name} | Line: "${currentLine}" | Pos: ${position.row}:${position.column}`)
+        break
+      }
+    }
+
+    if (shouldTrigger) {
+      // Update trigger tracking
+      updateTriggerTracking(position)
+    }
+
+    return shouldTrigger
+  }
+
+  function getAISuggestions(code: string, context: string, position: Point, callback: (suggestion: string) => void, language: string = 'nginx', suffix: string = '', requestId: string, currentIndent: string = '') {
     if (!ws.value || ws.value.readyState !== WebSocket.OPEN) {
       debug('WebSocket is not open')
+      clearLoadingSpinner()
       return
     }
 
     if (!code.trim()) {
       debug('Code is empty')
+      clearLoadingSpinner()
       return
     }
 
     // Skip if not a config file or contains sensitive content
     if (!isConfigFile.value) {
       debug('Skipping AI suggestions for non-config file')
+      clearLoadingSpinner()
       return
     }
 
     if (containsSensitiveContent(context)) {
       debug('Skipping AI suggestions due to sensitive content')
+      clearLoadingSpinner()
       return
     }
 
@@ -75,16 +293,22 @@ function useCodeCompletion() {
       language,
       position,
       request_id: requestId,
+      current_indent: currentIndent,
     }
 
     debug('Sending message', message)
 
+    // Show loading spinner when sending request
+    showLoadingSpinner()
+
     ws.value.send(JSON.stringify(message))
 
     ws.value.onmessage = event => {
       const data = JSON.parse(event.data)
       debug(`Received message`, data, requestId)
       if (data.request_id === requestId) {
+        // Clear loading spinner when receiving response
+        clearLoadingSpinner()
         callback(data.code)
       }
     }
@@ -92,12 +316,15 @@ function useCodeCompletion() {
 
   function applyGhostText() {
     if (!editorRef.value) {
-      debug('Editor instance not available yet')
       return
     }
 
     if (!isConfigFile.value) {
-      debug('Skipping ghost text for non-config file')
+      return
+    }
+
+    // Intelligent trigger check
+    if (!shouldTriggerCompletion(editorRef.value)) {
       return
     }
 
@@ -130,6 +357,9 @@ function useCodeCompletion() {
       // Clear existing ghost text before making the request
       clearGhostText()
 
+      // Get current line indentation for proper formatting
+      const currentLineIndent = getCurrentLineIndent(editorRef.value)
+
       // Get AI suggestions
       getAISuggestions(
         textUpToCursor,
@@ -145,12 +375,15 @@ function useCodeCompletion() {
             // Get current cursor position (may have changed during async process)
             const newPosition = editorRef.value!.getCursorPosition()
 
-            editorRef.value!.setGhostText(suggestion, {
+            // Smart formatting: handle line-end completions
+            const formattedSuggestion = formatCompletionForPosition(suggestion, newPosition)
+
+            editorRef.value!.setGhostText(formattedSuggestion, {
               column: newPosition.column,
               row: newPosition.row,
             })
-            debug(`Ghost text set: ${suggestion}`)
-            currentGhostText.value = suggestion
+            debug(`Ghost text set: ${formattedSuggestion}`)
+            currentGhostText.value = formattedSuggestion
           }
           else if (suggestion) {
             debug('setGhostText method not available on editor instance')
@@ -159,6 +392,7 @@ function useCodeCompletion() {
         editorRef.value.session.getMode()?.path?.split('/').pop() || 'text',
         textAfterCursor, // Pass text after cursor as suffix
         requestId, // Pass request ID
+        currentLineIndent, // Pass current line indentation
       )
     }
     catch (error) {
@@ -166,22 +400,27 @@ function useCodeCompletion() {
     }
   }
 
-  // Accept the ghost text suggestion with Tab key
-  function setupTabHandler(editor: Editor) {
+  // Accept the ghost text suggestion with Tab key and clear with Esc key
+  function setupKeyHandlers(editor: Editor) {
     if (!editor) {
-      debug('Editor not available in setupTabHandler')
+      debug('Editor not available in setupKeyHandlers')
       return
     }
 
-    debug('Setting up Tab key handler')
+    debug('Setting up key handlers')
 
-    // Remove existing command to avoid conflicts
-    const existingCommand = editor.commands.byName.acceptGhostText
-    if (existingCommand) {
-      editor.commands.removeCommand(existingCommand)
+    // Remove existing commands to avoid conflicts
+    const existingTabCommand = editor.commands.byName.acceptGhostText
+    if (existingTabCommand) {
+      editor.commands.removeCommand(existingTabCommand)
     }
 
-    // Register new Tab key handler command with highest priority
+    const existingEscCommand = editor.commands.byName.clearGhostText
+    if (existingEscCommand) {
+      editor.commands.removeCommand(existingEscCommand)
+    }
+
+    // Register Tab key handler - accept ghost text
     editor.commands.addCommand({
       name: 'acceptGhostText',
       bindKey: { win: 'Tab', mac: 'Tab' },
@@ -208,7 +447,24 @@ function useCodeCompletion() {
       readOnly: false,
     })
 
-    debug('Tab key handler set up successfully')
+    // Register Esc key handler - clear ghost text
+    editor.commands.addCommand({
+      name: 'clearGhostText',
+      bindKey: { win: 'Escape', mac: 'Escape' },
+      exec: (_editor: Editor) => {
+        if (currentGhostText.value) {
+          debug('Clearing ghost text with Esc key')
+          clearGhostText()
+          return true // Prevent event propagation
+        }
+
+        debug('No ghost text to clear, allowing default escape behavior')
+        return false // Allow default Escape behavior
+      },
+      readOnly: false,
+    })
+
+    debug('Key handlers set up successfully')
   }
 
   // Clear ghost text and reset state
@@ -220,6 +476,13 @@ function useCodeCompletion() {
       editorRef.value.removeGhostText()
     }
     currentGhostText.value = ''
+
+    // Also clear loading spinner
+    clearLoadingSpinner()
+
+    // Reset trigger tracking when manually clearing
+    lastTriggerTime.value = 0
+    lastTriggerPosition.value = null
   }
 
   const debouncedApplyGhostText = debounce(applyGhostText, 1000, { leading: false, trailing: true })
@@ -227,13 +490,13 @@ function useCodeCompletion() {
   debug('Editor initialized')
 
   async function init(editor: Editor, filename: string = '') {
-    const { enabled } = await openai.get_code_completion_enabled_status()
+    const { enabled } = await llm.get_code_completion_enabled_status()
     if (!enabled) {
       debug('Code completion is not enabled')
       return
     }
 
-    ws.value = openai.code_completion()
+    ws.value = llm.code_completion()
 
     editorRef.value = editor
 
@@ -242,26 +505,21 @@ function useCodeCompletion() {
     isConfigFile.value = checkIfConfigFile(filename, content)
     debug(`File type check: isConfigFile=${isConfigFile.value}, filename=${filename}`)
 
-    // Set up Tab key handler
-    setupTabHandler(editor)
+    // Set up key handlers (Tab and Esc)
+    setupKeyHandlers(editor)
 
     setTimeout(() => {
       editor.on('change', (e: { action: string }) => {
-        debug(`Editor change event: ${e.action}`)
         // If change is caused by user input, interrupt current completion
         clearGhostText()
 
-        if (e.action === 'insert' || e.action === 'remove') {
-          // Clear current ghost text
-          if (isConfigFile.value) {
-            debouncedApplyGhostText()
-          }
+        if ((e.action === 'insert' || e.action === 'remove') && isConfigFile.value) {
+          debouncedApplyGhostText()
         }
       })
 
       // Listen for cursor changes, using debounce
       editor.selection.on('changeCursor', () => {
-        debug('Cursor changed')
         clearGhostText()
         if (isConfigFile.value) {
           debouncedApplyGhostText()
@@ -271,12 +529,83 @@ function useCodeCompletion() {
   }
 
   function cleanUp() {
+    clearLoadingSpinner()
+    clearGhostText()
     if (ws.value) {
       ws.value.close()
     }
     debug('CodeCompletion unmounted')
   }
 
+  // Smart formatting for completion suggestions
+  function formatCompletionForPosition(suggestion: string, position: Point): string {
+    if (!editorRef.value)
+      return suggestion
+
+    const currentLine = editorRef.value.session.getLine(position.row)
+    const beforeCursor = currentLine.substring(0, position.column)
+
+    // Check if cursor is at the end of a non-empty line
+    const atEndOfLine = position.column === currentLine.length
+    const lineHasContent = beforeCursor.trim().length > 0
+
+    // If at end of line with content, and suggestion doesn't start with newline
+    if (atEndOfLine && lineHasContent && !suggestion.startsWith('\n')) {
+      // Check if suggestion should be on new line (block syntax, etc.)
+      const shouldNewline = shouldStartOnNewLine(suggestion, beforeCursor)
+      if (shouldNewline) {
+        const indent = getIndentForNewLine(beforeCursor)
+        return `\n${indent}${suggestion}`
+      }
+    }
+
+    // If suggestion starts with newline but we're not at line end, remove it
+    if (!atEndOfLine && suggestion.startsWith('\n')) {
+      return suggestion.substring(1)
+    }
+
+    return suggestion
+  }
+
+  // Determine if completion should start on new line
+  function shouldStartOnNewLine(suggestion: string, beforeCursor: string): boolean {
+    // Nginx block patterns that usually need newlines
+    const blockPatterns = [
+      /^\s*server\s*\{/, // server block
+      /^\s*location\s*(?:\S.*(?:[\n\r\u2028\u2029]\s*)?)?\{/, // location block
+      /^\s*upstream\s*\w+\s*\{/, // upstream block
+      /^\s*if\s*\(.*\)\s*\{/, // if block
+    ]
+
+    const directivePatterns = [
+      /^\s*(listen|server_name|root|index|location|proxy_pass|return)/,
+      /^\s*(error_page|access_log|error_log|ssl_certificate)/,
+    ]
+
+    // If before cursor ends with { or ;, next content should be on new line
+    if (/[{;]\s*$/.test(beforeCursor)) {
+      return true
+    }
+
+    // If suggestion looks like a new directive/block
+    const isBlockSuggestion = blockPatterns.some(pattern => pattern.test(suggestion))
+    const isDirectiveSuggestion = directivePatterns.some(pattern => pattern.test(suggestion))
+
+    return isBlockSuggestion || isDirectiveSuggestion
+  }
+
+  // Get appropriate indentation for new line
+  function getIndentForNewLine(beforeCursor: string): string {
+    const baseIndent = beforeCursor.match(/^\s*/)?.[0] || ''
+
+    // If previous line ends with {, increase indentation
+    if (beforeCursor.trim().endsWith('{')) {
+      return `${baseIndent}    ` // 4 spaces
+    }
+
+    return baseIndent
+  }
+
   return {
     init,
     cleanUp,

+ 32 - 0
app/src/components/CodeEditor/CodeEditor.vue

@@ -65,4 +65,36 @@ onUnmounted(() => {
   color: #6a737d;
   opacity: 0.8;
 }
+
+/* Loading spinner for code completion */
+:deep(.completion-loading-spinner) {
+  position: relative;
+  background: transparent;
+}
+
+:deep(.completion-loading-spinner):before {
+  content: '';
+  position: absolute;
+  top: 50%;
+  left: 0;
+  width: 12px;
+  height: 12px;
+  margin-top: -6px;
+  border: 2px solid #6a737d;
+  border-top: 2px solid transparent;
+  border-radius: 50%;
+  animation: completion-spin 1s linear infinite;
+  z-index: 10;
+}
+
+@keyframes completion-spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+
+/* Dark theme support */
+.dark :deep(.completion-loading-spinner):before {
+  border-color: #8b949e;
+  border-top-color: transparent;
+}
 </style>

+ 100 - 10
app/src/components/ChatGPT/ChatMessage.vue → app/src/components/LLM/ChatMessage.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
-import type { ChatComplicationMessage } from '@/api/openai'
-import { useChatGPTStore } from './chatgpt'
+import type { ChatComplicationMessage } from '@/api/llm'
+import { useLLMStore } from './llm'
 import { marked } from './markdown'
 import { transformText } from './utils'
 
@@ -21,11 +21,11 @@ defineEmits<{
   regenerate: [index: number]
 }>()
 
-const chatGPTStore = useChatGPTStore()
-const { streamingMessageIndex } = storeToRefs(chatGPTStore)
+const llmStore = useLLMStore()
+const { streamingMessageIndex } = storeToRefs(llmStore)
 
 function updateEditValue(value: string) {
-  chatGPTStore.editValue = value
+  llmStore.editValue = value
 }
 
 // Typewriter effect state
@@ -242,6 +242,68 @@ onMounted(() => {
     }
   }
 
+  .message-content :deep(h1) {
+    font-size: 1.5em;
+    font-weight: 600;
+    margin: 1em 0 0.5em 0;
+    line-height: 1.3;
+  }
+
+  .message-content :deep(h2) {
+    font-size: 1.3em;
+    font-weight: 600;
+    margin: 0.8em 0 0.4em 0;
+    line-height: 1.3;
+  }
+
+  .message-content :deep(h3) {
+    font-size: 1.15em;
+    font-weight: 600;
+    margin: 0.7em 0 0.3em 0;
+    line-height: 1.3;
+  }
+
+  .message-content :deep(h4) {
+    font-size: 1.05em;
+    font-weight: 600;
+    margin: 0.6em 0 0.3em 0;
+    line-height: 1.3;
+  }
+
+  .message-content :deep(h5), .message-content :deep(h6) {
+    font-size: 1em;
+    font-weight: 600;
+    margin: 0.5em 0 0.2em 0;
+    line-height: 1.3;
+  }
+
+  .message-content :deep(p) {
+    margin: 0.5em 0;
+    line-height: 1.6;
+  }
+
+  .message-content :deep(ul), .message-content :deep(ol) {
+    margin: 0.5em 0 1em 0;
+    padding-left: 1.5em;
+  }
+
+  .message-content :deep(li) {
+    margin: 0.2em 0;
+    line-height: 1.5;
+  }
+
+  .message-content :deep(ul li) {
+    list-style-type: disc;
+  }
+
+  .message-content :deep(ol li) {
+    list-style-type: decimal;
+  }
+
+  .message-content :deep(ul ul), .message-content :deep(ol ol), .message-content :deep(ul ol), .message-content :deep(ol ul) {
+    margin: 0.2em 0;
+  }
+
   :deep(code) {
     font-size: 12px;
   }
@@ -250,12 +312,40 @@ onMounted(() => {
     border-radius: 5px;
   }
 
-  :deep(blockquote) {
+  .message-content :deep(blockquote) {
     display: block;
-    opacity: 0.6;
-    margin: 0.5em 0;
-    padding-left: 1em;
-    border-left: 3px solid #ccc;
+    opacity: 0.8;
+    margin: 1em 0;
+    padding: 0.5em 0 0.5em 1em;
+    border-left: 4px solid #d0d7de;
+    background-color: rgba(208, 215, 222, 0.1);
+  }
+
+  .message-content :deep(blockquote p) {
+    margin: 0;
+  }
+
+  .message-content :deep(table) {
+    border-collapse: collapse;
+    margin: 1em 0;
+    width: 100%;
+  }
+
+  .message-content :deep(th), .message-content :deep(td) {
+    border: 1px solid #d0d7de;
+    padding: 0.5em;
+    text-align: left;
+  }
+
+  .message-content :deep(th) {
+    background-color: #f6f8fa;
+    font-weight: 600;
+  }
+
+  .message-content :deep(hr) {
+    border: none;
+    border-top: 1px solid #d0d7de;
+    margin: 1.5em 0;
   }
 }
 

+ 7 - 7
app/src/components/ChatGPT/ChatMessageInput.vue → app/src/components/LLM/ChatMessageInput.vue

@@ -1,10 +1,10 @@
 <script setup lang="ts">
 import { SendOutlined } from '@ant-design/icons-vue'
 import { storeToRefs } from 'pinia'
-import { useChatGPTStore } from './chatgpt'
+import { useLLMStore } from './llm'
 
-const chatGPTStore = useChatGPTStore()
-const { loading, askBuffer, messages } = storeToRefs(chatGPTStore)
+const llmStore = useLLMStore()
+const { loading, askBuffer, messages } = storeToRefs(llmStore)
 
 const messagesLength = computed(() => messages.value?.length ?? 0)
 </script>
@@ -17,7 +17,7 @@ const messagesLength = computed(() => messages.value?.length ?? 0)
           :cancel-text="$gettext('No')"
           :ok-text="$gettext('OK')"
           :title="$gettext('Are you sure you want to clear the record of chat?')"
-          @confirm="chatGPTStore.clearRecord()"
+          @confirm="llmStore.clearRecord()"
         >
           <AButton type="text">
             {{ $gettext('Clear') }}
@@ -25,7 +25,7 @@ const messagesLength = computed(() => messages.value?.length ?? 0)
         </APopconfirm>
         <AButton
           type="text"
-          @click="chatGPTStore.regenerate(messagesLength - 1)"
+          @click="llmStore.regenerate(messagesLength - 1)"
         >
           {{ $gettext('Regenerate response') }}
         </AButton>
@@ -34,14 +34,14 @@ const messagesLength = computed(() => messages.value?.length ?? 0)
     <ATextarea
       v-model:value="askBuffer"
       auto-size
-      @press-enter="chatGPTStore.send(askBuffer)"
+      @press-enter="llmStore.send(askBuffer)"
     />
     <div class="send-btn">
       <AButton
         size="small"
         type="text"
         :loading="loading"
-        @click="chatGPTStore.send(askBuffer)"
+        @click="llmStore.send(askBuffer)"
       >
         <SendOutlined />
       </AButton>

+ 11 - 11
app/src/components/ChatGPT/ChatMessageList.vue → app/src/components/LLM/ChatMessageList.vue

@@ -1,34 +1,34 @@
 <script setup lang="ts">
-import { useChatGPTStore } from './chatgpt'
 import ChatMessage from './ChatMessage.vue'
+import { useLLMStore } from './llm'
 
-// Use ChatGPT store
-const chatGPTStore = useChatGPTStore()
-const { messages, editingIdx, editValue, loading } = storeToRefs(chatGPTStore)
+// Use LLM store
+const llmStore = useLLMStore()
+const { messages, editingIdx, editValue, loading } = storeToRefs(llmStore)
 
 function handleEdit(index: number) {
-  chatGPTStore.startEdit(index)
+  llmStore.startEdit(index)
 }
 
 async function handleSave() {
-  chatGPTStore.saveEdit()
+  llmStore.saveEdit()
   await nextTick()
-  chatGPTStore.request()
+  llmStore.request()
 }
 
 function handleCancel() {
-  chatGPTStore.cancelEdit()
+  llmStore.cancelEdit()
 }
 
 async function handleRegenerate(index: number) {
-  chatGPTStore.regenerate(index)
+  llmStore.regenerate(index)
 }
 </script>
 
 <template>
   <div class="message-list-container">
     <AList
-      class="chatgpt-log"
+      class="llm-log"
       item-layout="horizontal"
       :data-source="messages"
     >
@@ -54,7 +54,7 @@ async function handleRegenerate(index: number) {
   overflow-y: auto;
   height: 100%;
 
-  .chatgpt-log {
+  .llm-log {
     :deep(.ant-list-item) {
       padding: 0 12px;
     }

+ 109 - 0
app/src/components/LLM/LLM.vue

@@ -0,0 +1,109 @@
+<script setup lang="ts">
+import { useElementVisibility } from '@vueuse/core'
+import { storeToRefs } from 'pinia'
+import { useSettingsStore } from '@/pinia'
+import ChatMessageInput from './ChatMessageInput.vue'
+import ChatMessageList from './ChatMessageList.vue'
+import { buildLLMContext } from './contextBuilder'
+import { useLLMStore } from './llm'
+
+const props = defineProps<{
+  content: string
+  path?: string
+}>()
+
+const { language: current } = storeToRefs(useSettingsStore())
+
+// Use LLM store
+const llmStore = useLLMStore()
+const { messageContainerRef } = storeToRefs(llmStore)
+
+// Initialize messages when path changes
+watch(() => props.path, async () => {
+  await llmStore.initMessages(props.path)
+  await nextTick()
+
+  // Auto-send first message if no messages exist
+  if (llmStore.messages.length === 0) {
+    await sendFirstMessage()
+  }
+  else {
+    // Check if we need to enhance the first message with include context
+    checkAndEnhanceFirstMessage()
+  }
+}, { immediate: true })
+
+// Check if first message needs context enhancement
+async function checkAndEnhanceFirstMessage() {
+  if (llmStore.messages.length > 0 && props.path) {
+    const firstMessage = llmStore.messages[0]
+    // Check if the first message already contains included files info
+    if (firstMessage.role === 'user' && !firstMessage.content.includes('--- INCLUDED FILES ---')) {
+      try {
+        // Build complete context including included files
+        const context = await buildLLMContext(props.path, props.content)
+
+        if (context.includedFiles.length > 0) {
+          // Update the first message with enhanced context
+          const enhancedContent = `${context.contextText}\n\nCurrent Language Code: ${current.value}`
+          llmStore.messages[0].content = enhancedContent
+          await llmStore.storeRecord()
+        }
+      }
+      catch (error) {
+        console.error('Failed to enhance first message:', error)
+      }
+    }
+  }
+}
+
+// Build context and send first message
+async function sendFirstMessage() {
+  if (!props.path) {
+    // If no path, use original content only
+    await llmStore.send(props.content, current.value, props.content)
+    return
+  }
+
+  try {
+    // Build complete context including included files
+    const context = await buildLLMContext(props.path, props.content)
+
+    // Send with enhanced context
+    await llmStore.send(props.content, current.value, context.contextText)
+  }
+  catch (error) {
+    console.error('Failed to build enhanced context, falling back to original:', error)
+    // Fallback to original behavior
+    await llmStore.send(props.content, current.value, props.content)
+  }
+}
+
+const isVisible = useElementVisibility(messageContainerRef)
+
+watch(isVisible, visible => {
+  if (visible) {
+    llmStore.scrollToBottom()
+  }
+}, { immediate: true })
+</script>
+
+<template>
+  <div
+    ref="messageContainerRef"
+    class="message-container"
+  >
+    <ChatMessageList />
+
+    <ChatMessageInput />
+  </div>
+</template>
+
+<style lang="less" scoped>
+.message-container {
+  margin: 0 auto;
+  max-width: 800px;
+  max-height: calc(100vh - 260px);
+  overflow-y: auto;
+}
+</style>

+ 2 - 3
app/src/components/ChatGPT/chatService.ts → app/src/components/LLM/chatService.ts

@@ -1,5 +1,5 @@
 import type { CodeBlockState } from './types'
-import type { ChatComplicationMessage } from '@/api/openai'
+import type { ChatComplicationMessage } from '@/api/llm'
 import { storeToRefs } from 'pinia'
 import { urlJoin } from '@/lib/helper'
 import { useUserStore } from '@/pinia'
@@ -67,14 +67,13 @@ export class ChatService {
       msg.role === 'user' || (msg.role === 'assistant' && msg.content.trim() !== ''),
     )
 
-    const res = await fetch(urlJoin(window.location.pathname, '/api/chatgpt'), {
+    const res = await fetch(urlJoin(window.location.pathname, '/api/llm'), {
       method: 'POST',
       headers: {
         Accept: 'text/event-stream',
         Authorization: token.value,
       },
       body: JSON.stringify({
-        filepath: path,
         messages: requestMessages,
       }),
     })

+ 0 - 0
app/src/components/ChatGPT/composables/useTypewriter.ts → app/src/components/LLM/composables/useTypewriter.ts


+ 144 - 0
app/src/components/LLM/contextBuilder.ts

@@ -0,0 +1,144 @@
+import config from '@/api/config'
+
+// Interface for included file information
+interface IncludedFile {
+  path: string
+  content: string
+  depth: number
+}
+
+// Interface for context building result
+export interface LLMContext {
+  mainFile: {
+    path: string
+    content: string
+  }
+  includedFiles: IncludedFile[]
+  contextText: string
+}
+
+// Parse nginx config content to find include directives
+function parseIncludeDirectives(content: string): string[] {
+  // More flexible regex that handles include with or without semicolon
+  const includePattern = /^\s*include\s+([^\s;]+)/g
+  const includes: string[] = []
+  let match
+
+  // eslint-disable-next-line no-cond-assign
+  while ((match = includePattern.exec(content)) !== null) {
+    const includePath = match[1].trim()
+
+    // Skip wildcards as they require special handling
+    if (!includePath.includes('*') && !includePath.includes('?')) {
+      includes.push(includePath)
+    }
+  }
+
+  return includes
+}
+
+// Recursively load included files with depth limit to prevent infinite loops
+async function loadIncludedFiles(
+  includes: string[],
+  visited: Set<string> = new Set(),
+  depth: number = 0,
+  maxDepth: number = 10,
+): Promise<IncludedFile[]> {
+  if (depth >= maxDepth) {
+    console.warn('Maximum include depth reached, stopping recursion')
+    return []
+  }
+
+  const includedFiles: IncludedFile[] = []
+
+  for (const includePath of includes) {
+    // Prevent circular includes
+    if (visited.has(includePath)) {
+      console.warn(`Circular include detected: ${includePath}`)
+      continue
+    }
+
+    visited.add(includePath)
+
+    try {
+      // Use config.getItem to fetch the included file
+      const response = await config.getItem(includePath)
+      const fileContent = response.content
+
+      const includedFile: IncludedFile = {
+        path: includePath,
+        content: fileContent,
+        depth,
+      }
+      includedFiles.push(includedFile)
+
+      // Recursively parse this file for more includes
+      const nestedIncludes = parseIncludeDirectives(fileContent)
+      if (nestedIncludes.length > 0) {
+        const nestedFiles = await loadIncludedFiles(
+          nestedIncludes,
+          new Set(visited),
+          depth + 1,
+          maxDepth,
+        )
+        includedFiles.push(...nestedFiles)
+      }
+    }
+    catch (error) {
+      console.warn(`Failed to load included file: ${includePath}`, error)
+      // Continue processing other includes even if one fails
+    }
+
+    visited.delete(includePath)
+  }
+
+  return includedFiles
+}
+
+// Build complete context including main file and all included files
+export async function buildLLMContext(mainFilePath: string, mainFileContent: string): Promise<LLMContext> {
+  const context: LLMContext = {
+    mainFile: {
+      path: mainFilePath,
+      content: mainFileContent,
+    },
+    includedFiles: [],
+    contextText: '',
+  }
+
+  try {
+    // Parse include directives from main file
+    const includes = parseIncludeDirectives(mainFileContent)
+
+    if (includes.length > 0) {
+      // Load all included files recursively
+      context.includedFiles = await loadIncludedFiles(includes)
+    }
+
+    // Build the complete context text
+    context.contextText = buildContextText(context)
+  }
+  catch (error) {
+    console.error('Error building LLM context:', error)
+    // Fallback to main file only
+    context.contextText = `Main File: ${mainFilePath}\n\n${mainFileContent}`
+  }
+
+  return context
+}
+
+// Build formatted context text for LLM
+function buildContextText(context: LLMContext): string {
+  let contextText = `Main File: ${context.mainFile.path}\n\n${context.mainFile.content}`
+
+  if (context.includedFiles.length > 0) {
+    contextText += '\n\n--- INCLUDED FILES ---\n'
+
+    for (const includedFile of context.includedFiles) {
+      const indent = '  '.repeat(includedFile.depth)
+      contextText += `\n${indent}Included File: ${includedFile.path}\n${indent}${includedFile.content.replace(/\n/g, `\n${indent}`)}\n`
+    }
+  }
+
+  return contextText
+}

+ 2 - 2
app/src/components/ChatGPT/index.ts → app/src/components/LLM/index.ts

@@ -1,4 +1,4 @@
-import ChatGPT from './ChatGPT.vue'
+import LLM from './LLM.vue'
 
 export { default as ChatMessage } from './ChatMessage.vue'
 export { default as ChatMessageInput } from './ChatMessageInput.vue'
@@ -7,4 +7,4 @@ export { ChatService } from './chatService'
 export { marked } from './markdown'
 export * from './types'
 export * from './utils'
-export default ChatGPT
+export default LLM

+ 40 - 18
app/src/components/ChatGPT/chatgpt.ts → app/src/components/LLM/llm.ts

@@ -1,8 +1,8 @@
-import type { ChatComplicationMessage } from '@/api/openai'
-import openai from '@/api/openai'
+import type { ChatComplicationMessage } from '@/api/llm'
+import llm from '@/api/llm'
 import { ChatService } from './chatService'
 
-export const useChatGPTStore = defineStore('chatgpt', () => {
+export const useLLMStore = defineStore('llm', () => {
   // State
   const path = ref<string>('') // Path to the chat record file
   const messages = ref<ChatComplicationMessage[]>([])
@@ -22,7 +22,6 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
     return null
   })
   const hasMessages = computed(() => messages.value.length > 0)
-  const shouldShowStartButton = computed(() => messages.value.length === 0)
 
   // Actions
   // Initialize messages for a specific file path
@@ -30,7 +29,7 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
     messages.value = []
     if (filePath) {
       try {
-        const record = await openai.get_record(filePath)
+        const record = await llm.get_messages(filePath)
         messages.value = record.content || []
       }
       catch (error) {
@@ -107,7 +106,7 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
     try {
       // Filter out empty messages before storing
       const validMessages = messages.value.filter(msg => msg.content.trim() !== '')
-      await openai.store_record({
+      await llm.store_messages({
         file_name: path.value,
         messages: validMessages,
       })
@@ -123,7 +122,7 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
       return
 
     try {
-      await openai.store_record({
+      await llm.store_messages({
         file_name: path.value,
         messages: [],
       })
@@ -151,10 +150,14 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
 
   // scroll to bottom
   function scrollToBottom() {
-    messageContainerRef.value?.scrollTo({
-      top: messageContainerRef.value.scrollHeight,
-      behavior: 'smooth',
-    })
+    if (messageContainerRef.value) {
+      // Use setTimeout to ensure DOM is updated
+      setTimeout(() => {
+        if (messageContainerRef.value) {
+          messageContainerRef.value.scrollTop = messageContainerRef.value.scrollHeight
+        }
+      }, 10)
+    }
   }
 
   // Set streaming message index
@@ -202,15 +205,25 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
     finally {
       setLoading(false)
       clearStreamingMessageIndex() // Clear streaming state
+
+      // Force scroll to bottom one more time after everything is done
+      await nextTick()
+      setTimeout(() => {
+        scrollToBottom()
+      }, 100)
+
       await storeRecord()
     }
   }
 
   // Send: Add user message into messages then call request
-  async function send(content: string, currentLanguage?: string) {
+  async function send(content: string, currentLanguage?: string, fileContent?: string) {
     if (messages.value.length === 0) {
-      // The first message
-      addUserMessage(`${content}\n\nCurrent Language Code: ${currentLanguage}`)
+      // The first message - include file content as context
+      const firstMessage = fileContent
+        ? `File Content:\n${fileContent}\n\n${content}\n\nCurrent Language Code: ${currentLanguage}`
+        : `${content}\n\nCurrent Language Code: ${currentLanguage}`
+      addUserMessage(firstMessage)
     }
     else {
       // Append user's new message
@@ -234,9 +247,19 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
     await request()
   }
 
-  watch(messages, () => {
-    scrollToBottom()
-  }, { immediate: true })
+  // Watch for streaming messages to auto-scroll during typing
+  watch(streamingMessageIndex, newIndex => {
+    if (newIndex !== -1) {
+      scrollToBottom()
+    }
+  })
+
+  // Auto-scroll when messages are updated during streaming
+  watch(() => messages.value.length > 0 ? messages.value[messages.value.length - 1]?.content : '', newContent => {
+    if (streamingMessageIndex.value !== -1 && newContent) {
+      scrollToBottom()
+    }
+  })
   // Return all state, getters, and actions
   return {
     // State
@@ -252,7 +275,6 @@ export const useChatGPTStore = defineStore('chatgpt', () => {
     isEditing,
     currentEditingMessage,
     hasMessages,
-    shouldShowStartButton,
 
     // Actions
     initMessages,

+ 0 - 0
app/src/components/ChatGPT/markdown.ts → app/src/components/LLM/markdown.ts


+ 1 - 1
app/src/components/ChatGPT/types.ts → app/src/components/LLM/types.ts

@@ -3,7 +3,7 @@ export interface CodeBlockState {
   backtickCount: number
 }
 
-export interface ChatGPTProps {
+export interface LLMProps {
   content: string
   path?: string
 }

+ 0 - 0
app/src/components/ChatGPT/utils.ts → app/src/components/LLM/utils.ts


+ 48 - 47
app/src/language/ar/app.po

@@ -193,7 +193,7 @@ msgstr "نسبة العامل الفعلي إلى المُهيأ"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "إضافة"
@@ -255,7 +255,7 @@ msgstr "إضافي"
 msgid "Advance Mode"
 msgstr "الوضع المتقدم"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "تم تمكين الفهرسة المتقدمة ولكن فشل بدء إعادة البناء"
 
@@ -344,7 +344,7 @@ msgstr "تطبيق"
 msgid "Arch"
 msgstr "أرك"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "هل أنت متأكد من حذف عنوان IP المحظور هذا على الفور؟"
 
@@ -365,7 +365,7 @@ msgstr "هل أنت متأكد من رغبتك في إعادة تعيين الم
 msgid "Are you sure you want to clear all notifications?"
 msgstr "هل أنت متأكد أنك تريد مسح كافة التنبيهات؟"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "هل أنت متأكد أنك تريد مسح سجل المحادثة؟"
 
@@ -406,11 +406,7 @@ msgstr "هل أنت متأكد أنك تريد الاستعادة؟"
 msgid "Ascending"
 msgstr "تصاعدي"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "اطلب المساعدة من ChatGPT"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "المساعد"
 
@@ -434,12 +430,8 @@ msgstr "مصادقة"
 msgid "Authenticate with a passkey"
 msgstr "المصادقة باستخدام مفتاح المرور"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "إعدادات المصادقة"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "الكاتب"
 
@@ -607,11 +599,11 @@ msgstr "فشل تنفيذ مهمة النسخ الاحتياطي %{backup_name}
 msgid "Backup Type"
 msgstr "نوع النسخ الاحتياطي"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "دقائق حد الحظر"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "عناوين IP المحظورة"
 
@@ -741,7 +733,7 @@ msgstr ""
 "يتم حسابه بناءً على worker_processes * worker_connections. الأداء الفعلي "
 "يعتمد على الأجهزة، التكوين، وحجم العمل"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1095,7 +1087,7 @@ msgstr "النص المشفر قصير جدًا"
 msgid "Cleaning environment variables"
 msgstr "تنظيف متغيرات البيئة"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1461,7 +1453,7 @@ msgid "Current Version"
 msgstr "الإصدار الحالي"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "مخصص"
 
@@ -1639,8 +1631,8 @@ msgstr "نشر"
 msgid "Descending"
 msgstr "تنازلي"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "وصف"
 
@@ -1990,7 +1982,7 @@ msgstr "تمكين"
 msgid "Enable 2FA successfully"
 msgstr "تم تفعيل المصادقة الثنائية بنجاح"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "تمكين الفهرسة المتقدمة"
 
@@ -2459,7 +2451,7 @@ msgstr "فشل تنزيل ملفات الشهادة"
 msgid "Failed to enable %{msg}"
 msgstr "فشل في التفعيل %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "فشل تمكين الفهرسة المتقدمة"
 
@@ -2995,7 +2987,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "رقم ICP"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3076,7 +3068,7 @@ msgid "Indexing"
 msgstr "فهرسة"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "جاري فهرسة السجلات..."
 
@@ -3533,7 +3525,7 @@ msgstr "فهرس السجلات غير متاح"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "اكتمل فهرسة السجلات! جارٍ تحميل البيانات المحدثة..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "قائمة السجلات"
 
@@ -3667,7 +3659,7 @@ msgstr "العملية الرئيسية"
 msgid "Master Process"
 msgstr "العملية الرئيسية"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "الحد الأقصى للمحاولات"
 
@@ -3783,8 +3775,7 @@ msgstr "خدمة البحث الحديثة غير متاحة"
 msgid "Modified At"
 msgstr "تم التعديل في"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "تعديل"
 
@@ -4136,14 +4127,14 @@ msgstr "يتضمن Nginx.conf دليل sites-enabled"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "يتضمن Nginx.conf دليل streams-enabled"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4369,7 +4360,7 @@ msgstr "غير متصل"
 msgid "Offline GeoIP analysis"
 msgstr "تحليل GeoIP دون اتصال"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -4956,7 +4947,7 @@ msgstr "يقرأ"
 msgid "Real-time analytics dashboard"
 msgstr "لوحة تحليلات في الوقت الفعلي"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "إعادة بناء"
 
@@ -5015,7 +5006,7 @@ msgstr "المرجع"
 msgid "Refresh"
 msgstr "تحديث"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "إعادة توليد الاستجابة"
 
@@ -5061,7 +5052,7 @@ msgstr "إعادة التثبيت"
 msgid "Release Note"
 msgstr "ملاحظة الإصدار"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "إعادة تحميل"
@@ -5109,7 +5100,7 @@ msgid "Remote"
 msgstr "عن بُعد"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "إزالة"
 
@@ -5358,15 +5349,15 @@ msgstr ""
 "إلغاء الشهادة سيؤثر على أي خدمات تستخدمها حالياً. لا يمكن التراجع عن هذا "
 "الإجراء."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "اسم العرض RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "أصول RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "معرّف الجهاز عن بُعد"
 
@@ -5470,7 +5461,7 @@ msgstr "فشل تحميل S3: {0}"
 msgid "Saturday"
 msgstr "السبت"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5608,6 +5599,10 @@ msgstr "اسم وحدة البحث"
 msgid "Search range"
 msgstr "نطاق البحث"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "البحث عن القوالب"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "تم نسخ السر"
@@ -6487,7 +6482,7 @@ msgstr ""
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "سيتم ترقية أو إعادة تثبيت Nginx UI على %{nodeNames} إلى %{version}."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "كبح"
 
@@ -6829,7 +6824,7 @@ msgstr "استخدم رمز الاسترداد"
 msgid "Use Temporary Path"
 msgstr "استخدام المسار المؤقت"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "مستخدم"
 
@@ -6902,8 +6897,8 @@ msgstr "تحقق من متطلبات النظام"
 msgid "Version"
 msgstr "إصدار"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -6990,7 +6985,7 @@ msgstr ""
 "سنقوم بإزالة تكوين HTTPChallenge من هذا الملف وإعادة تحميل Nginx. هل أنت "
 "متأكد أنك تريد المتابعة؟"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "ويب أوثن"
 
@@ -7102,7 +7097,7 @@ msgstr "كتابة الشهادة إلى القرص"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "نعم"
@@ -7176,6 +7171,12 @@ msgstr "خط أنابيب بدون تخصيص"
 msgid "Zero-allocation pipeline optimization"
 msgstr "تحسين خط الأنابيب بدون تخصيص"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "اطلب المساعدة من ChatGPT"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "إعدادات المصادقة"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "رسم الخرائط الجغرافية والرؤى"
 

+ 48 - 47
app/src/language/de_DE/app.po

@@ -192,7 +192,7 @@ msgstr "Tatsächliches Verhältnis von Arbeitern zu konfigurierten"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Hinzufügen"
@@ -254,7 +254,7 @@ msgstr "Zusätzlich"
 msgid "Advance Mode"
 msgstr "Erweiterter Modus"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr ""
 "Erweiterte Indizierung aktiviert, aber Neuerstellung konnte nicht gestartet "
@@ -351,7 +351,7 @@ msgstr "Anwenden"
 msgid "Arch"
 msgstr "Arch"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "Sind Sie sicher, dass Sie diese gesperrte IP sofort löschen möchten?"
 
@@ -372,7 +372,7 @@ msgstr "Sind Sie sicher, dass Sie die 2FA zurücksetzen möchten?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Möchten Sie wirklich alle Benachrichtigungen löschen?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Sind Sie sicher, dass Sie den Chatverlauf löschen möchten?"
 
@@ -417,11 +417,7 @@ msgstr "Sind Sie sicher, dass Sie wiederherstellen möchten?"
 msgid "Ascending"
 msgstr "Aufsteigend"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "Frage ChatGPT um Hilfe"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Assistent"
 
@@ -445,12 +441,8 @@ msgstr "Authentifizierung"
 msgid "Authenticate with a passkey"
 msgstr "Mit Passkey authentifizieren"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Authentifizierungseinstellungen"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Autor"
 
@@ -628,11 +620,11 @@ msgstr ""
 msgid "Backup Type"
 msgstr "Sicherungstyp"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Schwellenwert für Minuten sperren"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "Gesperrte IPs"
 
@@ -765,7 +757,7 @@ msgstr ""
 "Berechnet basierend auf worker_processes * worker_connections. Die "
 "tatsächliche Leistung hängt von Hardware, Konfiguration und Arbeitslast ab"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1117,7 +1109,7 @@ msgstr "Der verschlüsselte Text ist zu kurz"
 msgid "Cleaning environment variables"
 msgstr "Säuberung von Umgebungsvariablen"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1488,7 +1480,7 @@ msgid "Current Version"
 msgstr "Aktuelle Version"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Benutzerdefiniert"
 
@@ -1668,8 +1660,8 @@ msgstr "Ausführen"
 msgid "Descending"
 msgstr "Absteigend"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "Beschreibung"
 
@@ -2019,7 +2011,7 @@ msgstr "aktivieren"
 msgid "Enable 2FA successfully"
 msgstr "2FA erfolgreich aktiviert"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Erweiterte Indizierung aktivieren"
 
@@ -2495,7 +2487,7 @@ msgstr "Herunterladen der Zertifikatsdateien fehlgeschlagen"
 msgid "Failed to enable %{msg}"
 msgstr "Aktiviern von %{msg} fehlgeschlagen"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Erweiterte Indizierung konnte nicht aktiviert werden"
 
@@ -3035,7 +3027,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "ICP-Nummer"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3121,7 +3113,7 @@ msgid "Indexing"
 msgstr "Indizierung"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "Protokolle werden indiziert..."
 
@@ -3578,7 +3570,7 @@ msgstr "Log-Indexer nicht verfügbar"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "Protokollindizierung abgeschlossen! Aktualisierte Daten werden geladen..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Protokollliste"
 
@@ -3713,7 +3705,7 @@ msgstr "Master-Prozess"
 msgid "Master Process"
 msgstr "Master-Prozess"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Maximale Versuche"
 
@@ -3829,8 +3821,7 @@ msgstr "Moderner Suchdienst nicht verfügbar"
 msgid "Modified At"
 msgstr "Geändert am"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Ändern"
 
@@ -4184,14 +4175,14 @@ msgstr "Nginx.conf enthält das sites-enabled-Verzeichnis"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf enthält das streams-enabled-Verzeichnis"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4421,7 +4412,7 @@ msgstr "Offline"
 msgid "Offline GeoIP analysis"
 msgstr "Offline-GeoIP-Analyse"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -5024,7 +5015,7 @@ msgstr "Aufrufe"
 msgid "Real-time analytics dashboard"
 msgstr "Echtzeit-Analyse-Dashboard"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Neu aufbauen"
 
@@ -5084,7 +5075,7 @@ msgstr "Referer"
 msgid "Refresh"
 msgstr "Aktualisieren"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Auffrischen der Antwort"
 
@@ -5132,7 +5123,7 @@ msgstr "Neuinstallieren"
 msgid "Release Note"
 msgstr "Änderungsprotokoll"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Neu laden"
@@ -5182,7 +5173,7 @@ msgid "Remote"
 msgstr "Remote"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Löschen"
 
@@ -5434,15 +5425,15 @@ msgstr ""
 "Das Widerrufen eines Zertifikats wirkt sich auf alle Dienste aus, die es "
 "derzeit verwenden. Diese Aktion kann nicht rückgängig gemacht werden."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "RP-Anzeigename"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "RP-Ursprünge"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5546,7 +5537,7 @@ msgstr "S3-Upload fehlgeschlagen: {0}"
 msgid "Saturday"
 msgstr "Samstag"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5684,6 +5675,10 @@ msgstr "Modulname suchen"
 msgid "Search range"
 msgstr "Suchbereich"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Vorlagen suchen"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "Schlüssel wurde kopiert"
@@ -6593,7 +6588,7 @@ msgstr ""
 "Dies wird das Nginx UI auf %{nodeNames} auf %{version} aktualisieren oder "
 "neu installieren."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Begrenzung"
 
@@ -6940,7 +6935,7 @@ msgstr "Benuzte Wiederherstellungscode"
 msgid "Use Temporary Path"
 msgstr "Temporären Pfad verwenden"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Benutzer"
 
@@ -7013,8 +7008,8 @@ msgstr "Überprüfen Sie die Systemanforderungen"
 msgid "Version"
 msgstr "Version"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7106,7 +7101,7 @@ msgstr ""
 "Wir werden die HTTPChallenge-Konfiguration aus dieser Datei entfernen und "
 "das Nginx neu laden. Möchtest du fortfahren?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "Webauthn"
 
@@ -7224,7 +7219,7 @@ msgstr "Schreibe Zertifikat auf die Festplatte"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Ja"
@@ -7302,6 +7297,12 @@ msgstr "Allokationsfreie Pipeline"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Optimierung der Null-Zuweisungs-Pipeline"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "Frage ChatGPT um Hilfe"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Authentifizierungseinstellungen"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Geografische Kartierung & Erkenntnisse"
 

+ 42 - 47
app/src/language/en/app.po

@@ -176,7 +176,7 @@ msgstr ""
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr ""
@@ -238,7 +238,7 @@ msgstr ""
 msgid "Advance Mode"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr ""
 
@@ -326,7 +326,7 @@ msgstr ""
 msgid "Arch"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr ""
 
@@ -347,7 +347,7 @@ msgstr ""
 msgid "Are you sure you want to clear all notifications?"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr ""
 
@@ -388,11 +388,7 @@ msgstr ""
 msgid "Ascending"
 msgstr ""
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr ""
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr ""
 
@@ -416,12 +412,8 @@ msgstr ""
 msgid "Authenticate with a passkey"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr ""
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr ""
 
@@ -588,11 +580,11 @@ msgstr ""
 msgid "Backup Type"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr ""
 
@@ -718,7 +710,7 @@ msgid ""
 "performance depends on hardware, configuration, and workload"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1034,7 +1026,7 @@ msgstr ""
 msgid "Cleaning environment variables"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1398,7 +1390,7 @@ msgid "Current Version"
 msgstr ""
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr ""
 
@@ -1576,8 +1568,8 @@ msgstr ""
 msgid "Descending"
 msgstr ""
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr ""
 
@@ -1921,7 +1913,7 @@ msgstr ""
 msgid "Enable 2FA successfully"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr ""
 
@@ -2386,7 +2378,7 @@ msgstr ""
 msgid "Failed to enable %{msg}"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr ""
 
@@ -2913,7 +2905,7 @@ msgstr ""
 msgid "ICP Number"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -2988,7 +2980,7 @@ msgid "Indexing"
 msgstr ""
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr ""
 
@@ -3438,7 +3430,7 @@ msgstr ""
 msgid "Log indexing completed! Loading updated data..."
 msgstr ""
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr ""
 
@@ -3564,7 +3556,7 @@ msgstr ""
 msgid "Master Process"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr ""
 
@@ -3680,8 +3672,7 @@ msgstr ""
 msgid "Modified At"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr ""
 
@@ -4033,14 +4024,14 @@ msgstr ""
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4258,7 +4249,7 @@ msgstr ""
 msgid "Offline GeoIP analysis"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -4836,7 +4827,7 @@ msgstr ""
 msgid "Real-time analytics dashboard"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr ""
 
@@ -4893,7 +4884,7 @@ msgstr ""
 msgid "Refresh"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr ""
 
@@ -4939,7 +4930,7 @@ msgstr ""
 msgid "Release Note"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr ""
@@ -4987,7 +4978,7 @@ msgid "Remote"
 msgstr ""
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr ""
 
@@ -5232,15 +5223,15 @@ msgid ""
 "action cannot be undone."
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr ""
 
@@ -5344,7 +5335,7 @@ msgstr ""
 msgid "Saturday"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5482,6 +5473,10 @@ msgstr ""
 msgid "Search range"
 msgstr ""
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr ""
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr ""
@@ -6313,7 +6308,7 @@ msgid ""
 "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr ""
 
@@ -6641,7 +6636,7 @@ msgstr ""
 msgid "Use Temporary Path"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr ""
 
@@ -6714,8 +6709,8 @@ msgstr ""
 msgid "Version"
 msgstr ""
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -6795,7 +6790,7 @@ msgid ""
 "Nginx. Are you sure you want to continue?"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr ""
 
@@ -6902,7 +6897,7 @@ msgstr ""
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr ""

+ 48 - 47
app/src/language/es/app.po

@@ -199,7 +199,7 @@ msgstr "Proporción real de trabajadores a configurados"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Agregar"
@@ -261,7 +261,7 @@ msgstr "Adicional"
 msgid "Advance Mode"
 msgstr "Modo avanzado"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "Indexación avanzada habilitada pero falló al iniciar la reconstrucción"
 
@@ -356,7 +356,7 @@ msgstr "Aplicar"
 msgid "Arch"
 msgstr "Arquitectura"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "¿Está seguro de eliminar esta IP bloqueada inmediatamente?"
 
@@ -377,7 +377,7 @@ msgstr "¿Estás seguro de restablecer la autenticación de dos factores?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "¿Está seguro de que desea borrar todas las notificaciones?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "¿Está seguro de que desea borrar el registro del chat?"
 
@@ -422,11 +422,7 @@ msgstr "¿Estás seguro de que quieres restaurar?"
 msgid "Ascending"
 msgstr "Ascendente"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "Preguntar por ayuda a ChatGPT"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Asistente"
 
@@ -450,12 +446,8 @@ msgstr "Autenticación"
 msgid "Authenticate with a passkey"
 msgstr "Autenticarse con una llave de acceso"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Configuración de autenticación"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Autor"
 
@@ -633,11 +625,11 @@ msgstr ""
 msgid "Backup Type"
 msgstr "Tipo de copia de seguridad"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Umbral de Prohibición en Minutos"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "IPs prohibidas"
 
@@ -772,7 +764,7 @@ msgstr ""
 "Calculado en base a worker_processes * worker_connections. El rendimiento "
 "real depende del hardware, la configuración y la carga de trabajo"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1124,7 +1116,7 @@ msgstr "El texto cifrado es demasiado corto"
 msgid "Cleaning environment variables"
 msgstr "Borrar las variables de entorno"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1495,7 +1487,7 @@ msgid "Current Version"
 msgstr "Versión actual"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Personalizado"
 
@@ -1677,8 +1669,8 @@ msgstr "Desplegar"
 msgid "Descending"
 msgstr "Descendente"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "Descripción"
 
@@ -2026,7 +2018,7 @@ msgstr "habilitar"
 msgid "Enable 2FA successfully"
 msgstr "Habilitar 2FA exitoso"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Habilitar indexación avanzada"
 
@@ -2505,7 +2497,7 @@ msgstr "Error al descargar los archivos del certificado"
 msgid "Failed to enable %{msg}"
 msgstr "Error al habilitar %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Error al habilitar la indexación avanzada"
 
@@ -3045,7 +3037,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "Número ICP"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3127,7 +3119,7 @@ msgid "Indexing"
 msgstr "Indexación"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "Indexando registros..."
 
@@ -3585,7 +3577,7 @@ msgstr "Indexador de registros no disponible"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "¡Indexación de registros completada! Cargando datos actualizados..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Lista de registros"
 
@@ -3720,7 +3712,7 @@ msgstr "Proceso maestro"
 msgid "Master Process"
 msgstr "Proceso maestro"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Intentos máximos"
 
@@ -3836,8 +3828,7 @@ msgstr "Servicio de búsqueda moderno no disponible"
 msgid "Modified At"
 msgstr "Modificado el"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Modificar"
 
@@ -4191,14 +4182,14 @@ msgstr "Nginx.conf incluye el directorio sites-enabled"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf incluye el directorio streams-enabled"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4429,7 +4420,7 @@ msgstr "Desconectado"
 msgid "Offline GeoIP analysis"
 msgstr "Análisis GeoIP sin conexión"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -5035,7 +5026,7 @@ msgstr "Lecturas"
 msgid "Real-time analytics dashboard"
 msgstr "Panel de análisis en tiempo real"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Reconstruir"
 
@@ -5095,7 +5086,7 @@ msgstr "Referente"
 msgid "Refresh"
 msgstr "Actualizar"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Regenerar respuesta"
 
@@ -5143,7 +5134,7 @@ msgstr "Reinstalar"
 msgid "Release Note"
 msgstr "Nota de versión"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Recargar"
@@ -5191,7 +5182,7 @@ msgid "Remote"
 msgstr "Remoto"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Eliminar"
 
@@ -5441,15 +5432,15 @@ msgstr ""
 "La revocación de un certificado afectará a cualquier servicio que lo esté "
 "utilizando actualmente. Esta acción no se puede deshacer."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "Nombre RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "Orígenes RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5553,7 +5544,7 @@ msgstr "Error al subir a S3: {0}"
 msgid "Saturday"
 msgstr "Sábado"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5693,6 +5684,10 @@ msgstr "Nombre del módulo de búsqueda"
 msgid "Search range"
 msgstr "Rango de búsqueda"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Buscar plantillas"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "El secreto ha sido copiado"
@@ -6595,7 +6590,7 @@ msgstr ""
 "Esto actualizará o reinstalará la interfaz de usuario de Nginx en "
 "%{nodeNames} a %{version}."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Acelerador"
 
@@ -6941,7 +6936,7 @@ msgstr "Usar código de recuperación"
 msgid "Use Temporary Path"
 msgstr "Usar ruta temporal"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Usuario"
 
@@ -7014,8 +7009,8 @@ msgstr "Verificar los requisitos del sistema"
 msgid "Version"
 msgstr "Versión"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7106,7 +7101,7 @@ msgstr ""
 "Eliminaremos la configuración de HTTPChallenge de este archivo y "
 "recargaremos Nginx. ¿Estás seguro de que quieres continuar?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "Webauthn"
 
@@ -7221,7 +7216,7 @@ msgstr "Escribir certificado a disco"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Si"
@@ -7300,6 +7295,12 @@ msgstr "Canalización sin asignación"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Optimización de tubería sin asignación"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "Preguntar por ayuda a ChatGPT"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Configuración de autenticación"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Mapeo geográfico y conocimientos"
 

+ 48 - 47
app/src/language/fr_FR/app.po

@@ -199,7 +199,7 @@ msgstr "Ratio réel des travailleurs par rapport à la configuration"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Ajouter"
@@ -261,7 +261,7 @@ msgstr "Supplémentaire"
 msgid "Advance Mode"
 msgstr "Mode avancé"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "Indexation avancée activée mais échec du démarrage de la reconstruction"
 
@@ -356,7 +356,7 @@ msgstr "Appliquer"
 msgid "Arch"
 msgstr "Arch"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "Êtes-vous sûr de vouloir supprimer immédiatement cette IP bannie ?"
 
@@ -377,7 +377,7 @@ msgstr "Êtes-vous sûr de vouloir réinitialiser l'authentification à deux fac
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Êtes-vous sûr de vouloir effacer toutes les notifications ?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Voulez-vous vraiment effacer l'historique du chat ?"
 
@@ -422,11 +422,7 @@ msgstr "Êtes-vous sûr de vouloir restaurer ?"
 msgid "Ascending"
 msgstr "Croissant"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "Demander de l'aide à ChatGPT"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Assistant"
 
@@ -450,12 +446,8 @@ msgstr "Authentification"
 msgid "Authenticate with a passkey"
 msgstr "S'authentifier avec une clé d'accès"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Paramètres d'authentification"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Autheur"
 
@@ -633,11 +625,11 @@ msgstr ""
 msgid "Backup Type"
 msgstr "Type de sauvegarde"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Minutes seuil de bannissement"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "IPs bannies"
 
@@ -770,7 +762,7 @@ msgstr ""
 "performances réelles dépendent du matériel, de la configuration et de la "
 "charge de travail"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1121,7 +1113,7 @@ msgstr "Texte de chiffrement trop court"
 msgid "Cleaning environment variables"
 msgstr "Nettoyage des variables d'environnement"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1494,7 +1486,7 @@ msgid "Current Version"
 msgstr "Version actuelle"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Custom"
 
@@ -1676,8 +1668,8 @@ msgstr "Déployer"
 msgid "Descending"
 msgstr "Décroissant"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "Description"
 
@@ -2023,7 +2015,7 @@ msgstr "activer"
 msgid "Enable 2FA successfully"
 msgstr "2FA activé avec succès"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Activer l'indexation avancée"
 
@@ -2501,7 +2493,7 @@ msgstr "Échec du téléchargement des fichiers du certificat"
 msgid "Failed to enable %{msg}"
 msgstr "Impossible d'activer %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Échec de l'activation de l'indexation avancée"
 
@@ -3041,7 +3033,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "Numéro ICP"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3127,7 +3119,7 @@ msgid "Indexing"
 msgstr "Indexation"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "Indexation des journaux..."
 
@@ -3585,7 +3577,7 @@ msgstr "Indexeur de journaux non disponible"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "Indexation des journaux terminée ! Chargement des données mises à jour..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Liste des journaux"
 
@@ -3720,7 +3712,7 @@ msgstr "Processus maître"
 msgid "Master Process"
 msgstr "Processus maître"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Tentatives maximum"
 
@@ -3836,8 +3828,7 @@ msgstr "Service de recherche moderne non disponible"
 msgid "Modified At"
 msgstr "Modifié le"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Modifier"
 
@@ -4191,14 +4182,14 @@ msgstr "Nginx.conf inclut le répertoire sites-enabled"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf inclut le répertoire streams-enabled"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4427,7 +4418,7 @@ msgstr "Hors ligne"
 msgid "Offline GeoIP analysis"
 msgstr "Analyse GeoIP hors ligne"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -5033,7 +5024,7 @@ msgstr "Lectures"
 msgid "Real-time analytics dashboard"
 msgstr "Tableau de bord d'analyse en temps réel"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Reconstruire"
 
@@ -5093,7 +5084,7 @@ msgstr "Référent"
 msgid "Refresh"
 msgstr "Actualiser"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Régénérer la réponse"
 
@@ -5141,7 +5132,7 @@ msgstr "Réinstaller"
 msgid "Release Note"
 msgstr "Note de version"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Recharger"
@@ -5191,7 +5182,7 @@ msgid "Remote"
 msgstr "Distant"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Supprimer"
 
@@ -5441,15 +5432,15 @@ msgstr ""
 "La révocation d'un certificat affectera tous les services qui l'utilisent "
 "actuellement. Cette action ne peut pas être annulée."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "Nom d'affichage RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "Origines RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5553,7 +5544,7 @@ msgstr "Échec du téléversement S3 : {0}"
 msgid "Saturday"
 msgstr "Samedi"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5693,6 +5684,10 @@ msgstr "Nom du module de recherche"
 msgid "Search range"
 msgstr "Plage de recherche"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Rechercher des modèles"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "Le secret a été copié"
@@ -6603,7 +6598,7 @@ msgstr ""
 "Cela mettra à jour ou réinstallera l'interface Nginx sur %{nodeNames} vers "
 "la version %{version}."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Limitation"
 
@@ -6952,7 +6947,7 @@ msgstr "Utiliser un code de récupération"
 msgid "Use Temporary Path"
 msgstr "Utiliser un chemin temporaire"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Utilisateur"
 
@@ -7025,8 +7020,8 @@ msgstr "Vérifiez les exigences du système"
 msgid "Version"
 msgstr "Version"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7117,7 +7112,7 @@ msgstr ""
 "Nous allons supprimer la configuration HTTPChallenge de ce fichier et "
 "recharger le Nginx. Êtes-vous sûr de vouloir continuer?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "Webauthn"
 
@@ -7235,7 +7230,7 @@ msgstr "Écriture du certificat sur le disque"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Oui"
@@ -7314,6 +7309,12 @@ msgstr "Pipeline sans allocation"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Optimisation de pipeline sans allocation"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "Demander de l'aide à ChatGPT"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Paramètres d'authentification"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Cartographie géographique et insights"
 

+ 48 - 47
app/src/language/ja_JP/app.po

@@ -193,7 +193,7 @@ msgstr "実際のワーカー数と設定値の比率"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "追加"
@@ -255,7 +255,7 @@ msgstr "追加設定"
 msgid "Advance Mode"
 msgstr "アドバンスモード"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "高度なインデックス作成は有効になりましたが、再構築の開始に失敗しました"
 
@@ -342,7 +342,7 @@ msgstr "適用"
 msgid "Arch"
 msgstr "アーキテクチャ"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "このIPアドレス制限を削除してもよろしいですか?"
 
@@ -363,7 +363,7 @@ msgstr "2要素認証をリセットしてもよろしいですか?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "すべての通知をクリアしてもよろしいですか?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "チャットの記録をクリアしてもよろしいですか?"
 
@@ -404,11 +404,7 @@ msgstr "復元してもよろしいですか?"
 msgid "Ascending"
 msgstr "昇順"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "ChatGPTに助けを求める"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "アシスタント"
 
@@ -432,12 +428,8 @@ msgstr "認証"
 msgid "Authenticate with a passkey"
 msgstr "「パスキーで認証する」"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "認証設定"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "著者"
 
@@ -603,11 +595,11 @@ msgstr "バックアップタスク %{backup_name} の実行に失敗しまし
 msgid "Backup Type"
 msgstr "バックアップタイプ"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "制限閾値(分)"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "IPアドレス制限"
 
@@ -737,7 +729,7 @@ msgstr ""
 "worker_processes * worker_connections "
 "に基づいて計算されます。実際のパフォーマンスはハードウェア、設定、およびワークロードに依存します"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1071,7 +1063,7 @@ msgstr "暗号文が短すぎます"
 msgid "Cleaning environment variables"
 msgstr "環境変数を削除する"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1435,7 +1427,7 @@ msgid "Current Version"
 msgstr "現在のバージョン"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "カスタム"
 
@@ -1613,8 +1605,8 @@ msgstr "デプロイ"
 msgid "Descending"
 msgstr "降順"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "説明"
 
@@ -1957,7 +1949,7 @@ msgstr "有効にする"
 msgid "Enable 2FA successfully"
 msgstr "2FAが有効化されました"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "高度なインデックス作成を有効にする"
 
@@ -2422,7 +2414,7 @@ msgstr "証明書ファイルのダウンロードに失敗しました"
 msgid "Failed to enable %{msg}"
 msgstr "有効化に失敗しました %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "高度なインデックス作成の有効化に失敗しました"
 
@@ -2950,7 +2942,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "ICP番号"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3025,7 +3017,7 @@ msgid "Indexing"
 msgstr "インデックス作成"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "ログをインデックス中..."
 
@@ -3477,7 +3469,7 @@ msgstr "ログインデクサが利用できません"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "ログのインデックス作成が完了しました!更新されたデータを読み込み中..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "ログリスト"
 
@@ -3609,7 +3601,7 @@ msgstr "マスタープロセス"
 msgid "Master Process"
 msgstr "マスタープロセス"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "最大試行回数"
 
@@ -3725,8 +3717,7 @@ msgstr "最新の検索サービスは利用できません"
 msgid "Modified At"
 msgstr "更新日時"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "変更"
 
@@ -4078,14 +4069,14 @@ msgstr "Nginx.conf は sites-enabled ディレクトリを含んでいます"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf には streams-enabled ディレクトリが含まれています"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4305,7 +4296,7 @@ msgstr "オフライン"
 msgid "Offline GeoIP analysis"
 msgstr "オフライン GeoIP 分析"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -4887,7 +4878,7 @@ msgstr "読み取り"
 msgid "Real-time analytics dashboard"
 msgstr "リアルタイム分析ダッシュボード"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "再構築"
 
@@ -4944,7 +4935,7 @@ msgstr "リファラー"
 msgid "Refresh"
 msgstr "更新"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "応答を再生成"
 
@@ -4990,7 +4981,7 @@ msgstr "再インストール"
 msgid "Release Note"
 msgstr "リリースノート"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "再読み込み"
@@ -5038,7 +5029,7 @@ msgid "Remote"
 msgstr "リモート"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "削除"
 
@@ -5283,15 +5274,15 @@ msgid ""
 "action cannot be undone."
 msgstr "証明書を失効させると、現在それを使用しているすべてのサービスに影響します。この操作は元に戻せません。"
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "RP 表示名"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "RP オリジン"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5395,7 +5386,7 @@ msgstr "S3アップロードに失敗しました: {0}"
 msgid "Saturday"
 msgstr "土曜日"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5533,6 +5524,10 @@ msgstr "検索モジュール名"
 msgid "Search range"
 msgstr "検索範囲"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "テンプレートを検索"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "シークレットがコピーされました"
@@ -6380,7 +6375,7 @@ msgstr "これにより設定ファイルとデータベースが復元されま
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "これにより、%{nodeNames} 上の Nginx UI が %{version} にアップグレードまたは再インストールされます。"
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "スロットル"
 
@@ -6716,7 +6711,7 @@ msgstr "リカバリーコードを使用"
 msgid "Use Temporary Path"
 msgstr "一時パスを使用"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "ユーザー"
 
@@ -6789,8 +6784,8 @@ msgstr "システム要件を確認する"
 msgid "Version"
 msgstr "バージョン"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -6873,7 +6868,7 @@ msgid ""
 "the Nginx. Are you sure you want to continue?"
 msgstr "このファイルからHTTPChallengeの設定を削除し、Nginxを再読み込みします。続行してもよろしいですか?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "WebAuthn"
 
@@ -6982,7 +6977,7 @@ msgstr "証明書をディスクに書き込み中"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "はい"
@@ -7050,6 +7045,12 @@ msgstr "ゼロアロケーションパイプライン"
 msgid "Zero-allocation pipeline optimization"
 msgstr "ゼロ割り当てパイプラインの最適化"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "ChatGPTに助けを求める"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "認証設定"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "地理的マッピングとインサイト"
 

+ 48 - 47
app/src/language/ko_KR/app.po

@@ -191,7 +191,7 @@ msgstr "실제 작업자 대 구성 비율"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "추가"
@@ -253,7 +253,7 @@ msgstr "추가적인"
 msgid "Advance Mode"
 msgstr "고급 모드"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "고급 인덱싱이 활성화되었지만 재구축 시작에 실패했습니다"
 
@@ -340,7 +340,7 @@ msgstr "적용"
 msgid "Arch"
 msgstr "아키텍처"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "차단된 IP를 즉시 삭제하시겠습니까?"
 
@@ -361,7 +361,7 @@ msgstr "2FA를 재설정하시겠습니까?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "모든 알림을 지우시겠습니까?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "채팅 기록을 지우시겠습니까?"
 
@@ -402,11 +402,7 @@ msgstr "복원하시겠습니까?"
 msgid "Ascending"
 msgstr "오름차순"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "ChatGPT에게 도움 요청"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "어시스턴트"
 
@@ -430,12 +426,8 @@ msgstr "인증"
 msgid "Authenticate with a passkey"
 msgstr "패스키로 인증"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "인증 설정"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "저자"
 
@@ -601,11 +593,11 @@ msgstr "백업 작업 %{backup_name} 실행 실패, 오류: %{error}"
 msgid "Backup Type"
 msgstr "백업 유형"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "차단 시간(분)"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "차단된 IP"
 
@@ -735,7 +727,7 @@ msgstr ""
 "worker_processes * worker_connections를 기반으로 계산되었습니다. 실제 성능은 하드웨어, 구성 및 작업량에 "
 "따라 달라집니다"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1068,7 +1060,7 @@ msgstr "암호문이 너무 짧습니다"
 msgid "Cleaning environment variables"
 msgstr "환경 변수 정리"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1432,7 +1424,7 @@ msgid "Current Version"
 msgstr "현재 버전"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "사용자 정의"
 
@@ -1610,8 +1602,8 @@ msgstr "배포"
 msgid "Descending"
 msgstr "내림차순"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "설명"
 
@@ -1956,7 +1948,7 @@ msgstr "활성화"
 msgid "Enable 2FA successfully"
 msgstr "2FA가 성공적으로 활성화되었습니다"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "고급 인덱싱 활성화"
 
@@ -2421,7 +2413,7 @@ msgstr "인증서 파일 다운로드 실패"
 msgid "Failed to enable %{msg}"
 msgstr "%{msg} 활성화 실패"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "고급 인덱싱 활성화 실패"
 
@@ -2949,7 +2941,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "ICP 번호"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3024,7 +3016,7 @@ msgid "Indexing"
 msgstr "인덱싱"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "로그 인덱싱 중..."
 
@@ -3476,7 +3468,7 @@ msgstr "로그 인덱서를 사용할 수 없음"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "로그 인덱싱 완료! 업데이트된 데이터를 불러오는 중..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "로그 목록"
 
@@ -3605,7 +3597,7 @@ msgstr "마스터 프로세스"
 msgid "Master Process"
 msgstr "마스터 프로세스"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "최대 시도 횟수"
 
@@ -3721,8 +3713,7 @@ msgstr "현대적인 검색 서비스를 사용할 수 없음"
 msgid "Modified At"
 msgstr "수정일시"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "수정"
 
@@ -4074,14 +4065,14 @@ msgstr "Nginx.conf에 sites-enabled 디렉터리가 포함되어 있습니다"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf에는 streams-enabled 디렉토리가 포함됩니다"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4301,7 +4292,7 @@ msgstr "오프라인"
 msgid "Offline GeoIP analysis"
 msgstr "오프라인 GeoIP 분석"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -4881,7 +4872,7 @@ msgstr "읽기"
 msgid "Real-time analytics dashboard"
 msgstr "실시간 분석 대시보드"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "재구축"
 
@@ -4938,7 +4929,7 @@ msgstr "리퍼러"
 msgid "Refresh"
 msgstr "새로 고침"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "응답 재생성"
 
@@ -4984,7 +4975,7 @@ msgstr "재설치"
 msgid "Release Note"
 msgstr "릴리스 노트"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "리로드"
@@ -5032,7 +5023,7 @@ msgid "Remote"
 msgstr "원격"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "제거"
 
@@ -5279,15 +5270,15 @@ msgid ""
 "action cannot be undone."
 msgstr "인증서를 취소하면 현재 이를 사용 중인 모든 서비스에 영향을 미칩니다. 이 작업은 취소할 수 없습니다."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "RP 표시 이름"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "RP 오리진"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5391,7 +5382,7 @@ msgstr "S3 업로드 실패: {0}"
 msgid "Saturday"
 msgstr "토요일"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5529,6 +5520,10 @@ msgstr "모듈 이름 검색"
 msgid "Search range"
 msgstr "검색 범위"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "템플릿 검색"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "비밀번호가 복사되었습니다"
@@ -6375,7 +6370,7 @@ msgstr "이 작업은 구성 파일과 데이터베이스를 복원합니다. 
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "이 작업은 %{nodeNames}의 Nginx UI를 %{version}으로 업그레이드하거나 재설치합니다."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "제한"
 
@@ -6709,7 +6704,7 @@ msgstr "복구 코드 사용"
 msgid "Use Temporary Path"
 msgstr "임시 경로 사용"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "사용자"
 
@@ -6782,8 +6777,8 @@ msgstr "시스템 요구 사항을 확인하십시오"
 msgid "Version"
 msgstr "버전"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -6865,7 +6860,7 @@ msgid ""
 "the Nginx. Are you sure you want to continue?"
 msgstr "이 파일에서 HTTPChallenge 구성을 제거하고 Nginx를 다시 로드할 예정입니다. 계속하시겠습니까?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "웹인증"
 
@@ -6974,7 +6969,7 @@ msgstr "인증서를 디스크에 쓰기"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "예"
@@ -7044,6 +7039,12 @@ msgstr "할당 없는 파이프라인"
 msgid "Zero-allocation pipeline optimization"
 msgstr "제로 할당 파이프라인 최적화"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "ChatGPT에게 도움 요청"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "인증 설정"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "지리적 매핑 및 인사이트"
 

+ 42 - 46
app/src/language/messages.pot

@@ -185,7 +185,7 @@ msgstr ""
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97
 #: src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73
 #: src/views/stream/StreamList.vue:81
 msgid "Add"
@@ -249,7 +249,7 @@ msgstr ""
 msgid "Advance Mode"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr ""
 
@@ -334,7 +334,7 @@ msgstr ""
 msgid "Arch"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr ""
 
@@ -355,7 +355,7 @@ msgstr ""
 msgid "Are you sure you want to clear all notifications?"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr ""
 
@@ -397,11 +397,7 @@ msgstr ""
 msgid "Ascending"
 msgstr ""
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr ""
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr ""
 
@@ -425,12 +421,8 @@ msgstr ""
 msgid "Authenticate with a passkey"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr ""
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr ""
 
@@ -598,11 +590,11 @@ msgstr ""
 msgid "Backup Type"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr ""
 
@@ -723,7 +715,7 @@ msgstr ""
 msgid "Calculated based on worker_processes * worker_connections. Actual performance depends on hardware, configuration, and workload"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32
 #: src/language/curd.ts:37
@@ -1008,7 +1000,7 @@ msgstr ""
 msgid "Cleaning environment variables"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1374,7 +1366,7 @@ msgid "Current Version"
 msgstr ""
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr ""
 
@@ -1554,8 +1546,8 @@ msgstr ""
 msgid "Descending"
 msgstr ""
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr ""
 
@@ -1901,7 +1893,7 @@ msgstr ""
 msgid "Enable 2FA successfully"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr ""
 
@@ -2362,7 +2354,7 @@ msgstr ""
 msgid "Failed to enable %{msg}"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr ""
 
@@ -2881,7 +2873,7 @@ msgstr ""
 msgid "ICP Number"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid "If the number of login failed attempts from a ip reach the max attempts in ban threshold minutes, the ip will be banned for a period of time."
 msgstr ""
 
@@ -2948,7 +2940,7 @@ msgid "Indexing"
 msgstr ""
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr ""
 
@@ -3396,7 +3388,7 @@ msgid "Log indexing completed! Loading updated data..."
 msgstr ""
 
 #: src/routes/modules/nginx_log.ts:39
-#: src/views/nginx_log/NginxLogList.vue:412
+#: src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr ""
 
@@ -3518,7 +3510,7 @@ msgstr ""
 msgid "Master Process"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr ""
 
@@ -3634,7 +3626,7 @@ msgstr ""
 msgid "Modified At"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:212
+#: src/components/LLM/ChatMessage.vue:212
 #: src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr ""
@@ -3995,7 +3987,7 @@ msgstr ""
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
@@ -4003,7 +3995,7 @@ msgstr ""
 #: src/components/Notification/Notification.vue:108
 #: src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89
 #: src/views/stream/StreamList.vue:99
@@ -4216,7 +4208,7 @@ msgstr ""
 msgid "Offline GeoIP analysis"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109
@@ -4788,7 +4780,7 @@ msgstr ""
 msgid "Real-time analytics dashboard"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr ""
 
@@ -4843,7 +4835,7 @@ msgstr ""
 msgid "Refresh"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr ""
 
@@ -4887,7 +4879,7 @@ msgstr ""
 msgid "Release Note"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr ""
@@ -4937,7 +4929,7 @@ msgid "Remote"
 msgstr ""
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr ""
 
@@ -5181,15 +5173,15 @@ msgstr ""
 msgid "Revoking a certificate will affect any services currently using it. This action cannot be undone."
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr ""
 
@@ -5293,7 +5285,7 @@ msgstr ""
 msgid "Saturday"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5435,6 +5427,10 @@ msgstr ""
 msgid "Search range"
 msgstr ""
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr ""
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr ""
@@ -6225,7 +6221,7 @@ msgstr ""
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr ""
 
@@ -6544,7 +6540,7 @@ msgstr ""
 msgid "Use Temporary Path"
 msgstr ""
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr ""
 
@@ -6621,8 +6617,8 @@ msgid "Version"
 msgstr ""
 
 #: src/language/curd.ts:7
-#: src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180
 #: src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
@@ -6695,7 +6691,7 @@ msgstr ""
 msgid "We will remove the HTTPChallenge configuration from this file and reload the Nginx. Are you sure you want to continue?"
 msgstr ""
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr ""
 
@@ -6796,7 +6792,7 @@ msgstr ""
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr ""

+ 48 - 47
app/src/language/pt_PT/app.po

@@ -193,7 +193,7 @@ msgstr "Rácio real de workers para configurado"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Adicionar"
@@ -255,7 +255,7 @@ msgstr "Adicional"
 msgid "Advance Mode"
 msgstr "Modo Avançado"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "Indexação avançada ativada mas falhou ao iniciar reconstrução"
 
@@ -350,7 +350,7 @@ msgstr "Aplicar"
 msgid "Arch"
 msgstr "Arquitetura"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "Tem certeza que pretende eliminar este IP banido imediatamente?"
 
@@ -371,7 +371,7 @@ msgstr "Tem a certeza de que pretende repor a autenticação de dois fatores?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Tem certeza que pretende limpar todas notificações?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Tem certeza que pretende limpar o registo do chat?"
 
@@ -416,11 +416,7 @@ msgstr "Tem a certeza que deseja restaurar?"
 msgid "Ascending"
 msgstr "Ascendente"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "Pedir ajuda ao ChatGPT"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Assistente"
 
@@ -444,12 +440,8 @@ msgstr "Auth"
 msgid "Authenticate with a passkey"
 msgstr "Autenticar com uma chave de acesso"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Definições de Autenticação"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Autor"
 
@@ -623,11 +615,11 @@ msgstr "A tarefa de backup %{backup_name} falhou ao executar, erro: %{error}"
 msgid "Backup Type"
 msgstr "Tipo de backup"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Minutos Limite para Banir"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "IPs Banidos"
 
@@ -758,7 +750,7 @@ msgstr ""
 "Calculado com base em worker_processes * worker_connections. O desempenho "
 "real depende do hardware, configuração e carga de trabalho"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1111,7 +1103,7 @@ msgstr "O texto cifrado é demasiado curto"
 msgid "Cleaning environment variables"
 msgstr "Limpando variáveis de ambiente"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1480,7 +1472,7 @@ msgid "Current Version"
 msgstr "Versão Actual"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Personalizado"
 
@@ -1660,8 +1652,8 @@ msgstr "Deploy"
 msgid "Descending"
 msgstr "Decrescente"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "Descrição"
 
@@ -2007,7 +1999,7 @@ msgstr "ativar"
 msgid "Enable 2FA successfully"
 msgstr "2FA Activado com Sucesso"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Ativar indexação avançada"
 
@@ -2480,7 +2472,7 @@ msgstr "Falha ao baixar os ficheiros do certificado"
 msgid "Failed to enable %{msg}"
 msgstr "Falha ao Activar %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Falha ao ativar a indexação avançada"
 
@@ -3020,7 +3012,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "Número ICP"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3104,7 +3096,7 @@ msgid "Indexing"
 msgstr "Indexação"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "A indexar registos..."
 
@@ -3562,7 +3554,7 @@ msgstr "Indexador de registros não disponível"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "Indexação de registos concluída! A carregar dados atualizados..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Lista de registos"
 
@@ -3696,7 +3688,7 @@ msgstr "Processo principal"
 msgid "Master Process"
 msgstr "Processo mestre"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Máximo de Tentativas"
 
@@ -3812,8 +3804,7 @@ msgstr "Serviço de pesquisa moderno não disponível"
 msgid "Modified At"
 msgstr "Modificado em"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Modificar"
 
@@ -4167,14 +4158,14 @@ msgstr "Nginx.conf inclui o diretório sites-enabled"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf inclui o diretório streams-enabled"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4403,7 +4394,7 @@ msgstr "Off-line"
 msgid "Offline GeoIP analysis"
 msgstr "Análise GeoIP offline"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -5004,7 +4995,7 @@ msgstr "Leituras"
 msgid "Real-time analytics dashboard"
 msgstr "Painel de análise em tempo real"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Reconstruir"
 
@@ -5063,7 +5054,7 @@ msgstr "Referência"
 msgid "Refresh"
 msgstr "Atualizar"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Regerar a resposta"
 
@@ -5111,7 +5102,7 @@ msgstr "Reinstalar"
 msgid "Release Note"
 msgstr "Nota de Lançamento"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Recarregar"
@@ -5159,7 +5150,7 @@ msgid "Remote"
 msgstr "Remoto"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Remover"
 
@@ -5409,15 +5400,15 @@ msgstr ""
 "A revogação de um certificado afetará quaisquer serviços que o estejam a "
 "utilizar atualmente. Esta ação não pode ser desfeita."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "Nome de Exibição RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "Origens RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5521,7 +5512,7 @@ msgstr "Falha no upload para S3: {0}"
 msgid "Saturday"
 msgstr "Sábado"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5661,6 +5652,10 @@ msgstr "Nome do módulo de pesquisa"
 msgid "Search range"
 msgstr "Intervalo de pesquisa"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Pesquisar modelos"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "O segredo foi copiado"
@@ -6564,7 +6559,7 @@ msgstr ""
 "Isto vai actualizar ou reinstalar o Nginx UI em %{nodeNames} para "
 "%{version}."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Limitação"
 
@@ -6910,7 +6905,7 @@ msgstr "Usar o código de recuperação"
 msgid "Use Temporary Path"
 msgstr "Usar caminho temporário"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Utilizador"
 
@@ -6983,8 +6978,8 @@ msgstr "Verificar requisitos do sistema"
 msgid "Version"
 msgstr "Versão"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7075,7 +7070,7 @@ msgstr ""
 "Removeremos a configuração HTTPChallenge deste ficheiro e reiniciaremos o "
 "Nginx. Tem a certeza de que quer continuar?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "Webauthn"
 
@@ -7189,7 +7184,7 @@ msgstr "Escrevendo certificado no disco"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Sim"
@@ -7268,6 +7263,12 @@ msgstr "Pipeline sem alocação"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Otimização de pipeline sem alocação"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "Pedir ajuda ao ChatGPT"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Definições de Autenticação"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Mapeamento geográfico e insights"
 

+ 48 - 47
app/src/language/ru_RU/app.po

@@ -197,7 +197,7 @@ msgstr "Фактическое соотношение рабочих к наст
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Добавить"
@@ -259,7 +259,7 @@ msgstr "Дополнительно"
 msgid "Advance Mode"
 msgstr "Расширенный режим"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "Расширенная индексация включена, но не удалось начать перестроение"
 
@@ -350,7 +350,7 @@ msgstr "Применить"
 msgid "Arch"
 msgstr "Архитектура"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "Вы уверены, что хотите немедленно удалить этот заблокированный IP?"
 
@@ -371,7 +371,7 @@ msgstr "Вы уверены, что хотите сбросить 2FA?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Вы уверены, что хотите очистить все уведомления?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Вы уверены, что хотите очистить сообщения чата?"
 
@@ -416,11 +416,7 @@ msgstr "Вы уверены, что хотите восстановить?"
 msgid "Ascending"
 msgstr "По возрастанию"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "Обратитесь за помощью к ChatGPT"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Ассистент"
 
@@ -444,12 +440,8 @@ msgstr "Авторизация"
 msgid "Authenticate with a passkey"
 msgstr "Аутентификация с помощью ключа доступа"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Настройки аутентификации"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Автор"
 
@@ -627,11 +619,11 @@ msgstr ""
 msgid "Backup Type"
 msgstr "Тип резервной копии"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Порог блокировки в минутах"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "Заблокированные IP-адреса"
 
@@ -764,7 +756,7 @@ msgstr ""
 "Рассчитывается на основе worker_processes * worker_connections. Фактическая "
 "производительность зависит от оборудования, конфигурации и рабочей нагрузки"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1112,7 +1104,7 @@ msgstr "Зашифрованный текст слишком короткий"
 msgid "Cleaning environment variables"
 msgstr "Очистка переменных среды"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1483,7 +1475,7 @@ msgid "Current Version"
 msgstr "Текущяя версия"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Пользовательский"
 
@@ -1661,8 +1653,8 @@ msgstr "Развернуть"
 msgid "Descending"
 msgstr "По убыванию"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "Описание"
 
@@ -2008,7 +2000,7 @@ msgstr "включить"
 msgid "Enable 2FA successfully"
 msgstr "Двухфакторная аутентификация успешно включена"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Включить расширенное индексирование"
 
@@ -2485,7 +2477,7 @@ msgstr "Не удалось скачать файлы сертификата"
 msgid "Failed to enable %{msg}"
 msgstr "Не удалось включить %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Не удалось включить расширенное индексирование"
 
@@ -3025,7 +3017,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "ICP номер"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3107,7 +3099,7 @@ msgid "Indexing"
 msgstr "Индексация"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "Индексация журналов..."
 
@@ -3565,7 +3557,7 @@ msgstr "Индексатор логов недоступен"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "Индексация логов завершена! Загрузка обновленных данных..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Список журналов"
 
@@ -3699,7 +3691,7 @@ msgstr "Главный процесс"
 msgid "Master Process"
 msgstr "Главный процесс"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Максимальное количество попыток"
 
@@ -3815,8 +3807,7 @@ msgstr "Современный поисковый сервис недоступ
 msgid "Modified At"
 msgstr "Изменено"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Изменить"
 
@@ -4170,14 +4161,14 @@ msgstr "Nginx.conf включает каталог sites-enabled"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf включает каталог streams-enabled"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4406,7 +4397,7 @@ msgstr "Оффлайн"
 msgid "Offline GeoIP analysis"
 msgstr "Офлайн-анализ GeoIP"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -5012,7 +5003,7 @@ msgstr "Чтение"
 msgid "Real-time analytics dashboard"
 msgstr "Панель аналитики в реальном времени"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Перестроить"
 
@@ -5071,7 +5062,7 @@ msgstr "Реферер"
 msgid "Refresh"
 msgstr "Обновить"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Восстановить ответ"
 
@@ -5119,7 +5110,7 @@ msgstr "Переустановить"
 msgid "Release Note"
 msgstr "Что нового"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Перегрузить"
@@ -5167,7 +5158,7 @@ msgid "Remote"
 msgstr "Удаленный"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Удалить"
 
@@ -5417,15 +5408,15 @@ msgstr ""
 "Отзыв сертификата затронет все службы, которые его используют в данный "
 "момент. Это действие нельзя отменить."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "Отображаемое имя RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "Истоки RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5529,7 +5520,7 @@ msgstr "Ошибка загрузки в S3: {0}"
 msgid "Saturday"
 msgstr "Суббота"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5669,6 +5660,10 @@ msgstr "Название модуля поиска"
 msgid "Search range"
 msgstr "Диапазон поиска"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Поиск шаблонов"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "Секрет скопирован"
@@ -6559,7 +6554,7 @@ msgstr ""
 "Это обновит или переустановит интерфейс Nginx на %{nodeNames} до версии "
 "%{version}."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Ограничение"
 
@@ -6903,7 +6898,7 @@ msgstr "Использовать код восстановления"
 msgid "Use Temporary Path"
 msgstr "Использовать временный путь"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Пользователь"
 
@@ -6976,8 +6971,8 @@ msgstr "Проверьте системные требования"
 msgid "Version"
 msgstr "Версия"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7068,7 +7063,7 @@ msgstr ""
 "Мы удалим конфигурацию HTTPChallenge из этого файла и перезагрузим Nginx. "
 "Вы уверены, что хотите продолжить?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "WebAuthn"
 
@@ -7183,7 +7178,7 @@ msgstr "Запись сертификата на диск"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Да"
@@ -7259,6 +7254,12 @@ msgstr "Конвейер без выделения памяти"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Оптимизация конвейера без выделения памяти"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "Обратитесь за помощью к ChatGPT"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Настройки аутентификации"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Географическое картирование и аналитика"
 

+ 48 - 47
app/src/language/tr_TR/app.po

@@ -193,7 +193,7 @@ msgstr "Gerçek çalışanın yapılandırılmışa oranı"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Ekle"
@@ -255,7 +255,7 @@ msgstr "İlave bilgi"
 msgid "Advance Mode"
 msgstr "Gelişmiş Mod"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "Gelişmiş indeksleme etkinleştirildi ancak yeniden oluşturma başlatılamadı"
 
@@ -348,7 +348,7 @@ msgstr "Uygula"
 msgid "Arch"
 msgstr "Mimari"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "Bu yasaklı IP'yi hemen sileceğinizden emin misiniz?"
 
@@ -369,7 +369,7 @@ msgstr "İki aşamalı doğrulama sıfırlanacaktır. Emin misiniz?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Tüm bildirimleri temizlemek istediğinizden emin misiniz?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Sohbet kaydını silmek istediğinizden emin misiniz?"
 
@@ -414,11 +414,7 @@ msgstr "Geri yüklemek istediğinizden emin misiniz?"
 msgid "Ascending"
 msgstr "Artan"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "ChatGPT'den Yardım İsteyin"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Asistan"
 
@@ -442,12 +438,8 @@ msgstr "Kimlik Doğrulama"
 msgid "Authenticate with a passkey"
 msgstr "Geçiş anahtarıyla kimlik doğrulama"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Kimlik Doğrulama Ayarları"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Yazar"
 
@@ -617,11 +609,11 @@ msgstr "Yedekleme görevi %{backup_name} çalıştırılamadı, hata: %{error}"
 msgid "Backup Type"
 msgstr "Yedekleme Türü"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Yasaklama Eşiği Süresi (Dakika)"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "Yasaklı IP'ler"
 
@@ -752,7 +744,7 @@ msgstr ""
 "worker_processes * worker_connections temel alınarak hesaplanmıştır. Gerçek "
 "performans donanım, yapılandırma ve iş yüküne bağlıdır"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1107,7 +1099,7 @@ msgstr "Şifreli metin çok kısa"
 msgid "Cleaning environment variables"
 msgstr "Ortam değişkenlerini temizleme"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1475,7 +1467,7 @@ msgid "Current Version"
 msgstr "Mevcut sürüm"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Özelleştirilmiş"
 
@@ -1655,8 +1647,8 @@ msgstr "Yayınla"
 msgid "Descending"
 msgstr "Azalan"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "Açıklama"
 
@@ -2004,7 +1996,7 @@ msgstr "etkinleştir"
 msgid "Enable 2FA successfully"
 msgstr "2FA'yı başarıyla etkinleştirildi"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Gelişmiş Dizinlemeyi Etkinleştir"
 
@@ -2479,7 +2471,7 @@ msgstr "Sertifika dosyaları indirilemedi"
 msgid "Failed to enable %{msg}"
 msgstr "Etkinleştirilemedi %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Gelişmiş indeksleme etkinleştirilemedi"
 
@@ -3018,7 +3010,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "ICP Numarası"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3104,7 +3096,7 @@ msgid "Indexing"
 msgstr "Dizinleme"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "Günlükler dizinleniyor..."
 
@@ -3561,7 +3553,7 @@ msgstr "Günlük indeksleyici mevcut değil"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "Günlük indeksleme tamamlandı! Güncel veriler yükleniyor..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Günlük Listesi"
 
@@ -3695,7 +3687,7 @@ msgstr "Ana süreç"
 msgid "Master Process"
 msgstr "Ana Süreç"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Maksimum Deneme Sayısı"
 
@@ -3811,8 +3803,7 @@ msgstr "Modern arama hizmeti mevcut değil"
 msgid "Modified At"
 msgstr "Değiştirilme Tarihi"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Değiştir"
 
@@ -4166,14 +4157,14 @@ msgstr "Nginx.conf, sites-enabled dizinini içerir"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf, streams-enabled dizinini içerir"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4401,7 +4392,7 @@ msgstr "Çevrimdışı"
 msgid "Offline GeoIP analysis"
 msgstr "Çevrimdışı GeoIP analizi"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -5001,7 +4992,7 @@ msgstr "Okumalar"
 msgid "Real-time analytics dashboard"
 msgstr "Gerçek zamanlı analiz panosu"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Yeniden oluştur"
 
@@ -5060,7 +5051,7 @@ msgstr "Referer"
 msgid "Refresh"
 msgstr "Yenile"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Yanıtı yeniden oluştur"
 
@@ -5108,7 +5099,7 @@ msgstr "Yeniden Yükle"
 msgid "Release Note"
 msgstr "Sürüm Notları"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Yeniden Yükle"
@@ -5156,7 +5147,7 @@ msgid "Remote"
 msgstr "Uzak"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Kaldır"
 
@@ -5415,15 +5406,15 @@ msgstr ""
 "Bir sertifikanın iptal edilmesi, şu anda onu kullanan tüm hizmetleri "
 "etkileyecektir. Bu işlem geri alınamaz."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "RP Görünen Adı"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "RP Kökenleri"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5527,7 +5518,7 @@ msgstr "S3 yükleme başarısız: {0}"
 msgid "Saturday"
 msgstr "Cumartesi"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5665,6 +5656,10 @@ msgstr "Modül adı ara"
 msgid "Search range"
 msgstr "Arama aralığı"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Şablonları ara"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "Gizli kod kopyalandı"
@@ -6556,7 +6551,7 @@ msgstr ""
 "Bu işlem, %{nodeNames} üzerindeki Nginx UI'yi %{version} sürümüne "
 "yükseltecek veya yeniden yükleyecektir."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Kısıtlama"
 
@@ -6900,7 +6895,7 @@ msgstr "Kurtarma kodunu kullan"
 msgid "Use Temporary Path"
 msgstr "Geçici Yol Kullan"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Kullanıcı"
 
@@ -6973,8 +6968,8 @@ msgstr "Sistem Gereksinimlerini Doğrulun"
 msgid "Version"
 msgstr "Sürüm"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7064,7 +7059,7 @@ msgstr ""
 "Bu dosyadan HTTPChallenge yapılandırmasını kaldıracağız ve Nginx'i yeniden "
 "yükleyeceğiz. Devam etmek istediğinizden emin misiniz?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "WebAuthn"
 
@@ -7179,7 +7174,7 @@ msgstr "Sertifika diske yazılıyor"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Evet"
@@ -7256,6 +7251,12 @@ msgstr "Tahsisatsız boru hattı"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Sıfır tahsisli boru hattı optimizasyonu"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "ChatGPT'den Yardım İsteyin"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Kimlik Doğrulama Ayarları"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Coğrafi haritalama ve içgörüler"
 

+ 48 - 47
app/src/language/uk_UA/app.po

@@ -197,7 +197,7 @@ msgstr "Фактичне співвідношення робочих до нал
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Додати"
@@ -259,7 +259,7 @@ msgstr "Додатково"
 msgid "Advance Mode"
 msgstr "Розширений режим"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "Розширене індексування увімкнено, але не вдалося розпочати перебудову"
 
@@ -352,7 +352,7 @@ msgstr "Застосувати"
 msgid "Arch"
 msgstr "Архітектура"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "Ви впевнені, що хочите видалити цю заборонену IP-адресу?"
 
@@ -373,7 +373,7 @@ msgstr "Ви впевнені, що хочете скинути 2FA?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Ви впевнені, що бажаєте очистити всі сповіщення?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Ви впевнені, що бажаєте очистити запис чату?"
 
@@ -418,11 +418,7 @@ msgstr "Ви впевнені, що хочете відновити?"
 msgid "Ascending"
 msgstr "За зростанням"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "Запитати допомоги у ChatGPT"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Помічник"
 
@@ -446,12 +442,8 @@ msgstr "Авторизація"
 msgid "Authenticate with a passkey"
 msgstr "Автентифікація пасоком"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Налаштування аутентифікації"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Автор"
 
@@ -627,11 +619,11 @@ msgstr ""
 msgid "Backup Type"
 msgstr "Тип резервної копії"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Хвилини до блокування"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "Заблоковані IP-адреси"
 
@@ -763,7 +755,7 @@ msgstr ""
 "продуктивність залежить від апаратного забезпечення, конфігурації та "
 "навантаження"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1108,7 +1100,7 @@ msgstr "Зашифрований текст занадто короткий"
 msgid "Cleaning environment variables"
 msgstr "Змінні навколишнього середовища очищення"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1515,7 +1507,7 @@ msgid "Current Version"
 msgstr "Поточна версія"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Користувацький"
 
@@ -1693,8 +1685,8 @@ msgstr "Розгорнути"
 msgid "Descending"
 msgstr "Спадаючий"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr ""
 "Опис\"\n"
@@ -2076,7 +2068,7 @@ msgstr "увімкнути"
 msgid "Enable 2FA successfully"
 msgstr "2FA успішно ввімкнено"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Увімкнути розширене індексування"
 
@@ -2553,7 +2545,7 @@ msgstr "Не вдалося завантажити файли сертифіка
 msgid "Failed to enable %{msg}"
 msgstr "Не вдалося увімкнути %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Не вдалося увімкнути розширене індексування"
 
@@ -3091,7 +3083,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "Номер ICP"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3173,7 +3165,7 @@ msgid "Indexing"
 msgstr "Індексація"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "Індексація журналів..."
 
@@ -3631,7 +3623,7 @@ msgstr "Індексатор журналів недоступний"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "Індексація журналів завершена! Завантаження оновлених даних..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Список журналів"
 
@@ -3765,7 +3757,7 @@ msgstr "Головний процес"
 msgid "Master Process"
 msgstr "Головний процес"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Максимальна кількість спроб"
 
@@ -3881,8 +3873,7 @@ msgstr "Сучасний пошуковий сервіс недоступний"
 msgid "Modified At"
 msgstr "Змінено"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Змінити"
 
@@ -4236,14 +4227,14 @@ msgstr "Nginx.conf включає каталог sites-enabled"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf включає каталог streams-enabled"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4472,7 +4463,7 @@ msgstr "Офлайн"
 msgid "Offline GeoIP analysis"
 msgstr "Офлайн-аналіз GeoIP"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -5074,7 +5065,7 @@ msgstr "Читання"
 msgid "Real-time analytics dashboard"
 msgstr "Панель аналітики в реальному часі"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Перебудувати"
 
@@ -5134,7 +5125,7 @@ msgstr "Реферер"
 msgid "Refresh"
 msgstr "Оновити"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Повторити відповідь"
 
@@ -5182,7 +5173,7 @@ msgstr "Перевстановити"
 msgid "Release Note"
 msgstr "Примітки до версії"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Перезавантажити"
@@ -5232,7 +5223,7 @@ msgid "Remote"
 msgstr "Віддалено"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Видалити"
 
@@ -5484,15 +5475,15 @@ msgstr ""
 "Відкликання сертифіката вплине на всі служби, які його використовують. Цю "
 "дію не можна скасувати."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "Відображуване ім’я RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "Джерела RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5596,7 +5587,7 @@ msgstr "Помилка завантаження в S3: {0}"
 msgid "Saturday"
 msgstr "Субота"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5736,6 +5727,10 @@ msgstr "Назва модуля пошуку"
 msgid "Search range"
 msgstr "Діапазон пошуку"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Пошук шаблонів"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "Секрет скопійовано"
@@ -6629,7 +6624,7 @@ msgstr ""
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "Це оновить або перевстановить Nginx UI на %{nodeNames} до версії %{version}."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Обмеження"
 
@@ -6973,7 +6968,7 @@ msgstr "Використати код відновлення"
 msgid "Use Temporary Path"
 msgstr "Використовувати тимчасовий шлях"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Користувач"
 
@@ -7046,8 +7041,8 @@ msgstr "Перевірте системні вимоги"
 msgid "Version"
 msgstr "Версія"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7138,7 +7133,7 @@ msgstr ""
 "Ми видалимо конфігурацію HTTPChallenge з цього файлу та перезавантажимо "
 "Nginx. Ви впевнені, що хочете продовжити?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "WebAuthn"
 
@@ -7252,7 +7247,7 @@ msgstr "Запис сертифіката на диск"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Так"
@@ -7327,6 +7322,12 @@ msgstr "Конвеєр без виділення пам’яті"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Оптимізація конвеєра без виділення пам'яті"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "Запитати допомоги у ChatGPT"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Налаштування аутентифікації"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Географічне картографування та аналітика"
 

+ 48 - 47
app/src/language/vi_VN/app.po

@@ -188,7 +188,7 @@ msgstr "Tỷ lệ công nhân thực tế so với cấu hình"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "Thêm"
@@ -250,7 +250,7 @@ msgstr "Bổ sung"
 msgid "Advance Mode"
 msgstr "Nâng cao"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "Đã bật lập chỉ mục nâng cao nhưng không thể bắt đầu xây dựng lại"
 
@@ -343,7 +343,7 @@ msgstr "Áp dụng"
 msgid "Arch"
 msgstr "Kiến trúc"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "Bạn có chắc chắn muốn xóa IP bị cấm này ngay lập tức không?"
 
@@ -364,7 +364,7 @@ msgstr "Bạn có chắc chắn muốn đặt lại xác thực hai yếu tố k
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Bạn có chắc chắn muốn xóa tất cả thông báo không?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Bạn có chắc chắn muốn xóa lịch sử trò chuyện không?"
 
@@ -405,11 +405,7 @@ msgstr "Bạn có chắc chắn muốn khôi phục không?"
 msgid "Ascending"
 msgstr "Tăng dần"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "Hỏi ChatGPT"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "Trợ lý"
 
@@ -433,12 +429,8 @@ msgstr "Xác thực"
 msgid "Authenticate with a passkey"
 msgstr "Xác thực với một cô ấy"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "Cài đặt xác thực"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "Tác giả"
 
@@ -608,11 +600,11 @@ msgstr "Tác vụ sao lưu %{backup_name} không thể thực thi, lỗi: %{erro
 msgid "Backup Type"
 msgstr "Loại sao lưu"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "Phút Ngưỡng Cấm"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "Danh sách IP bị cấm"
 
@@ -743,7 +735,7 @@ msgstr ""
 "Được tính toán dựa trên worker_processes * worker_connections. Hiệu suất "
 "thực tế phụ thuộc vào phần cứng, cấu hình và khối lượng công việc"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1089,7 +1081,7 @@ msgstr "Văn bản mã hóa quá ngắn"
 msgid "Cleaning environment variables"
 msgstr "Xoá các biến môi trường"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1455,7 +1447,7 @@ msgid "Current Version"
 msgstr "Phiên bản hiện tại"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "Tuỳ chỉnh"
 
@@ -1633,8 +1625,8 @@ msgstr "Triển khai"
 msgid "Descending"
 msgstr "Giảm dần"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "Mô tả"
 
@@ -1981,7 +1973,7 @@ msgstr "bật"
 msgid "Enable 2FA successfully"
 msgstr "Bật 2FA thành công"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "Bật lập chỉ mục nâng cao"
 
@@ -2454,7 +2446,7 @@ msgstr "Tải xuống tệp chứng chỉ thất bại"
 msgid "Failed to enable %{msg}"
 msgstr "Không thể bật %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "Không thể bật lập chỉ mục nâng cao"
 
@@ -2992,7 +2984,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "Số ICP"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3073,7 +3065,7 @@ msgid "Indexing"
 msgstr "Đang lập chỉ mục"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "Đang lập chỉ mục nhật ký..."
 
@@ -3531,7 +3523,7 @@ msgstr "Bộ lập chỉ mục nhật ký không khả dụng"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "Lập chỉ mục nhật ký hoàn tất! Đang tải dữ liệu cập nhật..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "Danh sách nhật ký"
 
@@ -3665,7 +3657,7 @@ msgstr "Tiến trình chính"
 msgid "Master Process"
 msgstr "Tiến trình chính"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "Số lần thử tối đa"
 
@@ -3781,8 +3773,7 @@ msgstr "Dịch vụ tìm kiếm hiện đại không khả dụng"
 msgid "Modified At"
 msgstr "Đã sửa đổi lúc"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "Sửa đổi"
 
@@ -4136,14 +4127,14 @@ msgstr "Nginx.conf bao gồm thư mục sites-enabled"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf bao gồm thư mục streams-enabled"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4369,7 +4360,7 @@ msgstr "Ngoại tuyến"
 msgid "Offline GeoIP analysis"
 msgstr "Phân tích GeoIP ngoại tuyến"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -4961,7 +4952,7 @@ msgstr "Đọc"
 msgid "Real-time analytics dashboard"
 msgstr "Bảng điều khiển phân tích thời gian thực"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "Xây dựng lại"
 
@@ -5020,7 +5011,7 @@ msgstr "Người giới thiệu"
 msgid "Refresh"
 msgstr "Làm mới"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Tạo lại câu trả lời"
 
@@ -5068,7 +5059,7 @@ msgstr "Cài đặt lại"
 msgid "Release Note"
 msgstr "Ghi chú phát hành"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "Tải lại"
@@ -5116,7 +5107,7 @@ msgid "Remote"
 msgstr "Từ xa"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "Xóa"
 
@@ -5366,15 +5357,15 @@ msgstr ""
 "Việc thu hồi chứng chỉ sẽ ảnh hưởng đến bất kỳ dịch vụ nào hiện đang sử "
 "dụng nó. Hành động này không thể hoàn tác."
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "Tên hiển thị RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "Nguồn gốc RP"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5478,7 +5469,7 @@ msgstr "Tải lên S3 thất bại: {0}"
 msgid "Saturday"
 msgstr "Thứ Bảy"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5616,6 +5607,10 @@ msgstr "Tên mô-đun tìm kiếm"
 msgid "Search range"
 msgstr "Phạm vi tìm kiếm"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "Tìm kiếm mẫu"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "Mật khẩu đã được sao chép"
@@ -6505,7 +6500,7 @@ msgstr ""
 "Thao tác này sẽ nâng cấp hoặc cài đặt lại Nginx UI trên %{nodeNames} lên "
 "phiên bản %{version}."
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "Hạn chế"
 
@@ -6849,7 +6844,7 @@ msgstr "Sử dụng mã khôi phục"
 msgid "Use Temporary Path"
 msgstr "Sử dụng đường dẫn tạm thời"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "Người dùng"
 
@@ -6922,8 +6917,8 @@ msgstr "Xác minh các yêu cầu hệ thống"
 msgid "Version"
 msgstr "Phiên bản"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -7013,7 +7008,7 @@ msgstr ""
 "Chúng tôi sẽ xóa cấu hình HTTPChallenge khỏi tệp này và tải lại Nginx. Bạn "
 "có muốn tiếp tục không?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "WebAuthn"
 
@@ -7125,7 +7120,7 @@ msgstr "Ghi chứng chỉ vào disk"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "Có"
@@ -7200,6 +7195,12 @@ msgstr "Đường ống không cấp phát"
 msgid "Zero-allocation pipeline optimization"
 msgstr "Tối ưu hóa đường ống không cấp phát"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "Hỏi ChatGPT"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "Cài đặt xác thực"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "Bản đồ địa lý & thông tin chi tiết"
 

+ 49 - 48
app/src/language/zh_CN/app.po

@@ -192,7 +192,7 @@ msgstr "实际工作进程与配置比例"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "添加"
@@ -254,7 +254,7 @@ msgstr "额外选项"
 msgid "Advance Mode"
 msgstr "高级模式"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "高级索引已启用但未能开始重建"
 
@@ -341,7 +341,7 @@ msgstr "应用"
 msgid "Arch"
 msgstr "架构"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "您确定要立即删除这个被禁用的 IP 吗?"
 
@@ -362,7 +362,7 @@ msgstr "您确定要重设双重身份验证?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "您确定要清除所有通知吗?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "你确定你要清除聊天记录吗?"
 
@@ -403,11 +403,7 @@ msgstr "您确定要恢复吗?"
 msgid "Ascending"
 msgstr "升序"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "与 ChatGPT 聊天"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "助手"
 
@@ -431,12 +427,8 @@ msgstr "认证"
 msgid "Authenticate with a passkey"
 msgstr "通过 Passkey 认证"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "认证设置"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "作者"
 
@@ -602,11 +594,11 @@ msgstr "备份任务 %{backup_name} 执行失败,错误:%{error}"
 msgid "Backup Type"
 msgstr "备份类型"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "禁止阈值(分钟)"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "禁止 IP 列表"
 
@@ -732,7 +724,7 @@ msgid ""
 "performance depends on hardware, configuration, and workload"
 msgstr "基于 worker_processes * worker_connections 计算得出。实际性能取决于硬件、配置和工作负载"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1060,7 +1052,7 @@ msgstr "密码文本太短"
 msgid "Cleaning environment variables"
 msgstr "正在清理环境变量"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1424,7 +1416,7 @@ msgid "Current Version"
 msgstr "当前版本"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "自定义"
 
@@ -1602,8 +1594,8 @@ msgstr "部署"
 msgid "Descending"
 msgstr "降序"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "描述"
 
@@ -1946,7 +1938,7 @@ msgstr "启用"
 msgid "Enable 2FA successfully"
 msgstr "二步验证启用成功"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "启用高级索引"
 
@@ -2411,7 +2403,7 @@ msgstr "下载证书文件失败"
 msgid "Failed to enable %{msg}"
 msgstr "启用失败 %{msg}"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "启用高级索引失败"
 
@@ -2937,7 +2929,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "ICP 备案号"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3012,7 +3004,7 @@ msgid "Indexing"
 msgstr "索引中"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "正在索引日志..."
 
@@ -3464,7 +3456,7 @@ msgstr "日志索引器不可用"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "日志索引完成!正在加载更新数据..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "日志列表"
 
@@ -3593,7 +3585,7 @@ msgstr "主进程"
 msgid "Master Process"
 msgstr "主进程"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "最大尝试次数"
 
@@ -3709,8 +3701,7 @@ msgstr "现代搜索服务不可用"
 msgid "Modified At"
 msgstr "修改时间"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "修改"
 
@@ -4062,14 +4053,14 @@ msgstr "Nginx.conf 包含 sites-enabled 目录"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "检查 nginx.conf 是否包含 streams-enabled 的目录"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4287,7 +4278,7 @@ msgstr "离线"
 msgid "Offline GeoIP analysis"
 msgstr "离线 GeoIP 分析"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -4865,7 +4856,7 @@ msgstr "读"
 msgid "Real-time analytics dashboard"
 msgstr "实时分析仪表板"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "重建"
 
@@ -4922,7 +4913,7 @@ msgstr "来源"
 msgid "Refresh"
 msgstr "刷新"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "重新生成响应"
 
@@ -4968,7 +4959,7 @@ msgstr "重新安装"
 msgid "Release Note"
 msgstr "发行日志"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "重载"
@@ -5016,7 +5007,7 @@ msgid "Remote"
 msgstr "远程"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "删除"
 
@@ -5261,15 +5252,15 @@ msgid ""
 "action cannot be undone."
 msgstr "撤销证书将影响当前使用该证书的任何服务。该操作无法撤销。"
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "依赖方显示名称"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "依赖方的源"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "依赖方 ID"
 
@@ -5373,7 +5364,7 @@ msgstr "S3 上传失败:{0}"
 msgid "Saturday"
 msgstr "星期六"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5511,6 +5502,10 @@ msgstr "搜索模块名称"
 msgid "Search range"
 msgstr "搜索范围"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "搜索模板"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "密钥已复制"
@@ -6348,7 +6343,7 @@ msgstr "这将恢复配置文件和数据库。恢复完成后,Nginx UI 将重
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "将 %{nodeNames} 上的 Nginx UI 升级或重新安装到 %{version} 版本。"
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "限流"
 
@@ -6488,7 +6483,7 @@ msgstr "总访问量"
 
 #: src/views/dashboard/ServerAnalytic.vue:283
 msgid "Total Receive"
-msgstr "总接收"
+msgstr "总接收"
 
 #: src/composables/usePerformanceMetrics.ts:99
 #: src/views/dashboard/components/PerformanceTablesCard.vue:59
@@ -6680,7 +6675,7 @@ msgstr "使用恢复代码"
 msgid "Use Temporary Path"
 msgstr "使用临时路径"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "用户"
 
@@ -6753,8 +6748,8 @@ msgstr "验证系统要求"
 msgid "Version"
 msgstr "版本"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -6836,7 +6831,7 @@ msgid ""
 "the Nginx. Are you sure you want to continue?"
 msgstr "我们将从这个文件中删除 HTTPChallenge 的配置,并重新加载 Nginx。你确定要继续吗?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "Webauthn"
 
@@ -6943,7 +6938,7 @@ msgstr "正在将证书写入磁盘"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "是的"
@@ -7011,6 +7006,12 @@ msgstr "零分配管道"
 msgid "Zero-allocation pipeline optimization"
 msgstr "零分配管道优化"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "与 ChatGPT 聊天"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "认证设置"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "地理映射与洞察"
 

+ 48 - 47
app/src/language/zh_TW/app.po

@@ -196,7 +196,7 @@ msgstr "實際工作進程與配置比例"
 #: src/components/NgxConfigEditor/NgxServer.vue:144
 #: src/components/NgxConfigEditor/NgxUpstream.vue:97 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:119
 #: src/views/site/site_list/SiteList.vue:73 src/views/stream/StreamList.vue:81
 msgid "Add"
 msgstr "新增"
@@ -258,7 +258,7 @@ msgstr "其他設定"
 msgid "Advance Mode"
 msgstr "進階模式"
 
-#: src/views/nginx_log/NginxLogList.vue:387
+#: src/views/nginx_log/NginxLogList.vue:388
 msgid "Advanced indexing enabled but failed to start rebuild"
 msgstr "高級索引已啟用但未能開始重建"
 
@@ -345,7 +345,7 @@ msgstr "應用"
 msgid "Arch"
 msgstr "架構"
 
-#: src/views/preference/tabs/AuthSettings.vue:128
+#: src/views/preference/tabs/AuthSettings.vue:125
 msgid "Are you sure to delete this banned IP immediately?"
 msgstr "您確定要刪除這個被停用的 IP 嗎?"
 
@@ -366,7 +366,7 @@ msgstr "您確定要重設 2FA 嗎?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "您確定要清除所有通知嗎?"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:19
+#: src/components/LLM/ChatMessageInput.vue:19
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "您確定要清除聊天記錄嗎?"
 
@@ -407,11 +407,7 @@ msgstr "您確定要恢復?"
 msgid "Ascending"
 msgstr "升序"
 
-#: src/components/ChatGPT/ChatGPT.vue:55
-msgid "Ask ChatGPT for Help"
-msgstr "向 ChatGPT 尋求幫助"
-
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "Assistant"
 msgstr "助理"
 
@@ -435,12 +431,8 @@ msgstr "身份驗證"
 msgid "Authenticate with a passkey"
 msgstr "使用通行金鑰認證"
 
-#: src/views/preference/tabs/AuthSettings.vue:55
-msgid "Authentication Settings"
-msgstr "認證設定"
-
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:71
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:97
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:122
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:96
 msgid "Author"
 msgstr "作者"
 
@@ -606,11 +598,11 @@ msgstr "備份任務 %{backup_name} 執行失敗,錯誤:%{error}"
 msgid "Backup Type"
 msgstr "備份類型"
 
-#: src/views/preference/tabs/AuthSettings.vue:95
+#: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Ban Threshold Minutes"
 msgstr "封禁閾值分鐘數"
 
-#: src/views/preference/tabs/AuthSettings.vue:116
+#: src/views/preference/tabs/AuthSettings.vue:113
 msgid "Banned IPs"
 msgstr "被禁止的 IP"
 
@@ -736,7 +728,7 @@ msgid ""
 "performance depends on hardware, configuration, and workload"
 msgstr "基於 worker_processes * worker_connections 計算得出。實際效能取決於硬體、配置和工作負載"
 
-#: src/components/ChatGPT/ChatMessage.vue:216
+#: src/components/LLM/ChatMessage.vue:216
 #: src/components/NgxConfigEditor/NgxServer.vue:61
 #: src/components/NgxConfigEditor/NgxUpstream.vue:32 src/language/curd.ts:37
 #: src/views/config/components/Delete.vue:98
@@ -1064,7 +1056,7 @@ msgstr "加密文字過短"
 msgid "Cleaning environment variables"
 msgstr "清理環境變數"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:23
+#: src/components/LLM/ChatMessageInput.vue:23
 #: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
@@ -1428,7 +1420,7 @@ msgid "Current Version"
 msgstr "目前版本"
 
 #: src/components/NgxConfigEditor/NgxConfigEditor.vue:33
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:104
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:129
 msgid "Custom"
 msgstr "自訂"
 
@@ -1606,8 +1598,8 @@ msgstr "部署"
 msgid "Descending"
 msgstr "降序"
 
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:74
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:98
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:123
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:99
 msgid "Description"
 msgstr "描述"
 
@@ -1950,7 +1942,7 @@ msgstr "啟用"
 msgid "Enable 2FA successfully"
 msgstr "啟用多因素身份驗證成功"
 
-#: src/views/nginx_log/NginxLogList.vue:450
+#: src/views/nginx_log/NginxLogList.vue:451
 msgid "Enable Advanced Indexing"
 msgstr "啟用高級索引"
 
@@ -2415,7 +2407,7 @@ msgstr "下載憑證檔案失敗"
 msgid "Failed to enable %{msg}"
 msgstr "啟用 %{msg} 失敗"
 
-#: src/views/nginx_log/NginxLogList.vue:397
+#: src/views/nginx_log/NginxLogList.vue:398
 msgid "Failed to enable advanced indexing"
 msgstr "啟用高級索引失敗"
 
@@ -2941,7 +2933,7 @@ msgstr "https://..."
 msgid "ICP Number"
 msgstr "ICP 編號"
 
-#: src/views/preference/tabs/AuthSettings.vue:111
+#: src/views/preference/tabs/AuthSettings.vue:108
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
@@ -3016,7 +3008,7 @@ msgid "Indexing"
 msgstr "索引中"
 
 #: src/views/nginx_log/components/LoadingState.vue:33
-#: src/views/nginx_log/NginxLogList.vue:439
+#: src/views/nginx_log/NginxLogList.vue:440
 msgid "Indexing logs..."
 msgstr "正在索引日誌..."
 
@@ -3468,7 +3460,7 @@ msgstr "日誌索引器不可用"
 msgid "Log indexing completed! Loading updated data..."
 msgstr "日誌索引完成!正在載入更新數據..."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:412
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:413
 msgid "Log List"
 msgstr "日誌列表"
 
@@ -3597,7 +3589,7 @@ msgstr "主行程"
 msgid "Master Process"
 msgstr "主行程"
 
-#: src/views/preference/tabs/AuthSettings.vue:101
+#: src/views/preference/tabs/AuthSettings.vue:98
 msgid "Max Attempts"
 msgstr "最大嘗試次數"
 
@@ -3713,8 +3705,7 @@ msgstr "現代搜尋服務不可用"
 msgid "Modified At"
 msgstr "修改於"
 
-#: src/components/ChatGPT/ChatMessage.vue:212
-#: src/views/config/ConfigList.vue:182
+#: src/components/LLM/ChatMessage.vue:212 src/views/config/ConfigList.vue:182
 msgid "Modify"
 msgstr "修改"
 
@@ -4066,14 +4057,14 @@ msgstr "Nginx.conf 包含 sites-enabled 目錄"
 msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf 包含 streams-enabled 目錄"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:17
+#: src/components/LLM/ChatMessageInput.vue:17
 #: src/components/NamespaceTabs/NamespaceTabs.vue:132
 #: src/components/NamespaceTabs/NamespaceTabs.vue:144
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
-#: src/views/preference/tabs/AuthSettings.vue:130
+#: src/views/preference/tabs/AuthSettings.vue:127
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:89 src/views/stream/StreamList.vue:99
 msgid "No"
@@ -4291,7 +4282,7 @@ msgstr "離線"
 msgid "Offline GeoIP analysis"
 msgstr "離線 GeoIP 分析"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:18
+#: src/components/LLM/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:31
 #: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
@@ -4871,7 +4862,7 @@ msgstr "讀取"
 msgid "Real-time analytics dashboard"
 msgstr "即時分析儀表板"
 
-#: src/views/nginx_log/NginxLogList.vue:477
+#: src/views/nginx_log/NginxLogList.vue:478
 msgid "Rebuild"
 msgstr "重建"
 
@@ -4928,7 +4919,7 @@ msgstr "來源"
 msgid "Refresh"
 msgstr "重新整理"
 
-#: src/components/ChatGPT/ChatMessageInput.vue:30
+#: src/components/LLM/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "重新產生回應"
 
@@ -4974,7 +4965,7 @@ msgstr "重新安裝"
 msgid "Release Note"
 msgstr "發行公告"
 
-#: src/components/ChatGPT/ChatMessage.vue:222
+#: src/components/LLM/ChatMessage.vue:222
 #: src/components/NginxControl/NginxControl.vue:103
 msgid "Reload"
 msgstr "重新載入"
@@ -5022,7 +5013,7 @@ msgid "Remote"
 msgstr "遠端"
 
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
-#: src/views/preference/tabs/AuthSettings.vue:135
+#: src/views/preference/tabs/AuthSettings.vue:132
 msgid "Remove"
 msgstr "移除"
 
@@ -5267,15 +5258,15 @@ msgid ""
 "action cannot be undone."
 msgstr "撤銷憑證將會影響目前使用它的所有服務。此動作無法復原。"
 
-#: src/views/preference/tabs/AuthSettings.vue:74
+#: src/views/preference/tabs/AuthSettings.vue:71
 msgid "RP Display Name"
 msgstr "RP 顯示名稱"
 
-#: src/views/preference/tabs/AuthSettings.vue:80
+#: src/views/preference/tabs/AuthSettings.vue:77
 msgid "RP Origins"
 msgstr "RP 源站"
 
-#: src/views/preference/tabs/AuthSettings.vue:68
+#: src/views/preference/tabs/AuthSettings.vue:65
 msgid "RPID"
 msgstr "RPID"
 
@@ -5379,7 +5370,7 @@ msgstr "S3上傳失敗:{0}"
 msgid "Saturday"
 msgstr "星期六"
 
-#: src/components/ChatGPT/ChatMessage.vue:215
+#: src/components/LLM/ChatMessage.vue:215
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
@@ -5517,6 +5508,10 @@ msgstr "搜尋模組名稱"
 msgid "Search range"
 msgstr "搜尋範圍"
 
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:79
+msgid "Search templates"
+msgstr "搜尋模板"
+
 #: src/views/preference/components/AuthSettings/TOTP.vue:109
 msgid "Secret has been copied"
 msgstr "金鑰已複製"
@@ -6354,7 +6349,7 @@ msgstr "這將恢復設定檔案和資料庫。恢復完成後,Nginx UI 將重
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "這將在 %{nodeNames} 上升級或重新安裝 Nginx UI 到 %{version}。"
 
-#: src/views/preference/tabs/AuthSettings.vue:91
+#: src/views/preference/tabs/AuthSettings.vue:88
 msgid "Throttle"
 msgstr "節流"
 
@@ -6686,7 +6681,7 @@ msgstr "使用恢復碼"
 msgid "Use Temporary Path"
 msgstr "使用臨時路徑"
 
-#: src/components/ChatGPT/ChatMessage.vue:187
+#: src/components/LLM/ChatMessage.vue:187
 msgid "User"
 msgstr "使用者名稱"
 
@@ -6759,8 +6754,8 @@ msgstr "驗證系統要求"
 msgid "Version"
 msgstr "版本"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:466
-#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:467
+#: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:108
 #: src/views/system/Licenses.vue:180 src/views/system/Licenses.vue:215
 #: src/views/system/Licenses.vue:250
 msgid "View"
@@ -6840,7 +6835,7 @@ msgid ""
 "the Nginx. Are you sure you want to continue?"
 msgstr "我們將從該檔案中刪除 HTTPChallenge 設定並重新載入 Nginx 設定檔案。你確定你要繼續嗎?"
 
-#: src/views/preference/tabs/AuthSettings.vue:64
+#: src/views/preference/tabs/AuthSettings.vue:61
 msgid "Webauthn"
 msgstr "Webauthn"
 
@@ -6947,7 +6942,7 @@ msgstr "將憑證寫入磁碟"
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/nginx_log/indexing/IndexManagement.vue:29
 #: src/views/nginx_log/indexing/IndexManagement.vue:55
-#: src/views/preference/tabs/AuthSettings.vue:129
+#: src/views/preference/tabs/AuthSettings.vue:126
 #: src/views/preference/tabs/CertSettings.vue:72
 msgid "Yes"
 msgstr "是的"
@@ -7015,6 +7010,12 @@ msgstr "零分配管道"
 msgid "Zero-allocation pipeline optimization"
 msgstr "零分配管道優化"
 
+#~ msgid "Ask ChatGPT for Help"
+#~ msgstr "向 ChatGPT 尋求幫助"
+
+#~ msgid "Authentication Settings"
+#~ msgstr "認證設定"
+
 #~ msgid "Geographic mapping & insights"
 #~ msgstr "地理映射與洞察"
 

+ 1 - 1
app/src/version.json

@@ -1 +1 @@
-{"version":"2.2.0","build_id":1,"total_build":500}
+{"version":"2.2.0","build_id":2,"total_build":501}

+ 2 - 2
app/src/views/config/components/ConfigRightPanel/Chat.vue

@@ -1,13 +1,13 @@
 <script setup lang="ts">
 import type { Config } from '@/api/config'
-import ChatGPT from '@/components/ChatGPT'
+import LLM from '@/components/LLM'
 
 const data = defineModel<Config>('data', { required: true })
 </script>
 
 <template>
   <div class="mt--6">
-    <ChatGPT
+    <LLM
       :content="data.content"
       :path="data.filepath"
     />

+ 77 - 75
app/src/views/nginx_log/NginxLogList.vue

@@ -408,85 +408,87 @@ function cancelIndexingSettings() {
 </script>
 
 <template>
-  <StdCurd
-    ref="stdCurdRef"
-    :title="$gettext('Log List')"
-    :columns="columns"
-    :api="nginxLog"
-    disable-add
-    disable-export
-    disable-delete
-    disable-trash
-    disable-view
-    disable-edit
-    :overwrite-params="{
-      type: activeLogType,
-    }"
-  >
-    <template #beforeSearch>
-      <TabFilter
-        v-model:active-key="activeLogType"
-        :options="tabOptions"
-        size="middle"
-      />
-    </template>
-
-    <template #beforeListActions>
-      <div class="flex items-center gap-4">
-        <!-- Global indexing progress -->
-        <div v-if="isGlobalIndexing" class="flex items-center">
-          <div class="flex items-center text-blue-500">
-            <SyncOutlined spin class="mr-2" />
-            <span>{{ $gettext('Indexing logs...') }}</span>
+  <div>
+    <StdCurd
+      ref="stdCurdRef"
+      :title="$gettext('Log List')"
+      :columns="columns"
+      :api="nginxLog"
+      disable-add
+      disable-export
+      disable-delete
+      disable-trash
+      disable-view
+      disable-edit
+      :overwrite-params="{
+        type: activeLogType,
+      }"
+    >
+      <template #beforeSearch>
+        <TabFilter
+          v-model:active-key="activeLogType"
+          :options="tabOptions"
+          size="middle"
+        />
+      </template>
+
+      <template #beforeListActions>
+        <div class="flex items-center gap-4">
+          <!-- Global indexing progress -->
+          <div v-if="isGlobalIndexing" class="flex items-center">
+            <div class="flex items-center text-blue-500">
+              <SyncOutlined spin class="mr-2" />
+              <span>{{ $gettext('Indexing logs...') }}</span>
+            </div>
           </div>
-        </div>
 
-        <!-- Advanced Indexing Toggle - only for Access logs -->
-        <div v-if="activeLogType === 'access' && !advancedIndexingEnabled" class="flex items-center">
-          <AButton
-            type="link"
-            size="small"
-            @click="showIndexingSettingsModal"
-          >
-            {{ $gettext('Enable Advanced Indexing') }}
-          </AButton>
-        </div>
+          <!-- Advanced Indexing Toggle - only for Access logs -->
+          <div v-if="activeLogType === 'access' && !advancedIndexingEnabled" class="flex items-center">
+            <AButton
+              type="link"
+              size="small"
+              @click="showIndexingSettingsModal"
+            >
+              {{ $gettext('Enable Advanced Indexing') }}
+            </AButton>
+          </div>
 
-        <!-- Index Management - only for Access logs when advanced indexing is enabled -->
-        <IndexManagement
-          v-if="activeLogType === 'access' && advancedIndexingEnabled"
-          ref="indexManagementRef"
+          <!-- Index Management - only for Access logs when advanced indexing is enabled -->
+          <IndexManagement
+            v-if="activeLogType === 'access' && advancedIndexingEnabled"
+            ref="indexManagementRef"
+            :disabled="processingStatus.nginx_log_indexing"
+            :indexing="isGlobalIndexing || processingStatus.nginx_log_indexing"
+            @refresh="refreshTable"
+          />
+        </div>
+      </template>
+      <template #beforeActions="{ record }">
+        <AButton type="link" size="small" @click="viewLog(record)">
+          {{ $gettext('View') }}
+        </AButton>
+
+        <!-- Rebuild File Index Action - only for Access logs with advanced indexing enabled -->
+        <AButton
+          v-if="record.type === 'access' && advancedIndexingEnabled"
+          type="link"
+          size="small"
           :disabled="processingStatus.nginx_log_indexing"
-          :indexing="isGlobalIndexing || processingStatus.nginx_log_indexing"
-          @refresh="refreshTable"
-        />
-      </div>
-    </template>
-    <template #beforeActions="{ record }">
-      <AButton type="link" size="small" @click="viewLog(record)">
-        {{ $gettext('View') }}
-      </AButton>
-
-      <!-- Rebuild File Index Action - only for Access logs with advanced indexing enabled -->
-      <AButton
-        v-if="record.type === 'access' && advancedIndexingEnabled"
-        type="link"
-        size="small"
-        :disabled="processingStatus.nginx_log_indexing"
-        @click="rebuildFileIndex(record)"
-      >
-        {{ $gettext('Rebuild') }}
-      </AButton>
-    </template>
-  </StdCurd>
-
-  <!-- Advanced Indexing Settings Modal -->
-  <IndexingSettingsModal
-    v-model:visible="indexingSettingsModalVisible"
-    :loading="enableIndexingLoading"
-    @confirm="enableAdvancedIndexing"
-    @cancel="cancelIndexingSettings"
-  />
+          @click="rebuildFileIndex(record)"
+        >
+          {{ $gettext('Rebuild') }}
+        </AButton>
+      </template>
+    </StdCurd>
+
+    <!-- Advanced Indexing Settings Modal -->
+    <IndexingSettingsModal
+      v-model:visible="indexingSettingsModalVisible"
+      :loading="enableIndexingLoading"
+      @confirm="enableAdvancedIndexing"
+      @cancel="cancelIndexingSettings"
+    />
+  </div>
 </template>
 
 <style scoped lang="less">

+ 26 - 1
app/src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue

@@ -1,5 +1,6 @@
 <script setup lang="ts">
 import type { Template } from '@/api/template'
+import { SearchOutlined } from '@ant-design/icons-vue'
 import { storeToRefs } from 'pinia'
 import template from '@/api/template'
 import CodeEditor from '@/components/CodeEditor'
@@ -19,6 +20,7 @@ const { data } = storeToRefs(configTemplateStore)
 const blocks = ref<Template[]>([])
 const visible = ref(false)
 const name = ref('')
+const filterText = ref('')
 
 function getBlockList() {
   template.get_block_list().then(r => {
@@ -41,6 +43,18 @@ const transDescription = computed(() => {
     item.description?.[language.value] ?? item.description?.en ?? ''
 })
 
+const filteredBlocks = computed(() => {
+  if (!filterText.value)
+    return blocks.value
+
+  const searchText = filterText.value.toLowerCase()
+  return blocks.value.filter(item =>
+    item.name?.toLowerCase().includes(searchText)
+    || item.author?.toLowerCase().includes(searchText)
+    || transDescription.value(item).toLowerCase().includes(searchText),
+  )
+})
+
 async function add() {
   if (data.value?.custom)
     ngxConfig.value.custom += `\n${data.value.custom}`
@@ -59,8 +73,19 @@ async function add() {
 
 <template>
   <div>
+    <div class="mb-4">
+      <AInput
+        v-model:value="filterText"
+        :placeholder="$gettext('Search templates')"
+        allow-clear
+      >
+        <template #prefix>
+          <SearchOutlined />
+        </template>
+      </AInput>
+    </div>
     <div class="config-list-wrapper">
-      <AList :data-source="blocks">
+      <AList :data-source="filteredBlocks">
         <template #renderItem="{ item }">
           <AListItem>
             <AListItemMeta

+ 2 - 2
app/src/views/site/site_edit/components/RightPanel/Chat.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import ChatGPT from '@/components/ChatGPT'
+import LLM from '@/components/LLM'
 import { useSiteEditorStore } from '../SiteEditor/store'
 
 const editorStore = useSiteEditorStore()
@@ -11,7 +11,7 @@ const {
 
 <template>
   <div class="mt--6">
-    <ChatGPT
+    <LLM
       :content="configText"
       :path="filepath"
     />

+ 2 - 2
app/src/views/stream/components/RightPanel/Chat.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import ChatGPT from '@/components/ChatGPT'
+import LLM from '@/components/LLM'
 import { useStreamEditorStore } from '../../store'
 
 const store = useStreamEditorStore()
@@ -8,7 +8,7 @@ const { configText, filepath } = storeToRefs(store)
 
 <template>
   <div class="mt--6">
-    <ChatGPT
+    <LLM
       :content="configText"
       :path="filepath"
     />

BIN
cmd/generate_licenses/internal/license/licenses.xz


+ 1 - 1
internal/config/delete.go

@@ -11,7 +11,7 @@ import (
 // CleanupDatabaseRecords removes related database records after deletion
 func CleanupDatabaseRecords(fullPath string, isDir bool) error {
 	q := query.Config
-	g := query.ChatGPTLog
+	g := query.LLMMessages
 	b := query.ConfigBackup
 
 	if isDir {

+ 69 - 18
internal/llm/code_completion.go

@@ -29,13 +29,14 @@ type Position struct {
 
 // CodeCompletionRequest the code completion request
 type CodeCompletionRequest struct {
-	RequestID string   `json:"request_id"`
-	UserID    uint64   `json:"user_id"`
-	Context   string   `json:"context"`
-	Code      string   `json:"code"`
-	Suffix    string   `json:"suffix"`
-	Language  string   `json:"language"`
-	Position  Position `json:"position"`
+	RequestID     string   `json:"request_id"`
+	UserID        uint64   `json:"user_id"`
+	Context       string   `json:"context"`
+	Code          string   `json:"code"`
+	Suffix        string   `json:"suffix"`
+	Language      string   `json:"language"`
+	Position      Position `json:"position"`
+	CurrentIndent string   `json:"current_indent"`
 }
 
 var (
@@ -75,7 +76,10 @@ func (c *CodeCompletionRequest) Send() (completedCode string, err error) {
 	}
 
 	userPrompt += "Instruction: Only provide the completed code that should be inserted at the cursor position without explanations. " +
-		"The code should be syntactically correct and follow best practices for " + c.Language + "."
+		"The code should be syntactically correct and follow best practices for " + c.Language + ". " +
+		"IMPORTANT: If the cursor is at the end of a line and the completion should start on a new line, begin with a newline character. " +
+		"For multi-line completions, use proper indentation - the current line uses '" + c.CurrentIndent + "' as base indentation. " +
+		"Each new line should maintain consistent indentation levels appropriate for the code structure."
 
 	messages := []openai.ChatCompletionMessage{
 		{
@@ -104,7 +108,7 @@ func (c *CodeCompletionRequest) Send() (completedCode string, err error) {
 	completedCode = response.Choices[0].Message.Content
 	// extract the last word of the code
 	lastWord := extractLastWord(c.Code)
-	completedCode = cleanCompletionResponse(completedCode, lastWord)
+	completedCode = cleanCompletionResponse(completedCode, lastWord, c.CurrentIndent)
 	logger.Infof("Code completion response: %s", completedCode)
 	return
 }
@@ -125,8 +129,8 @@ func extractLastWord(code string) string {
 }
 
 // cleanCompletionResponse removes any <think></think> tags and their content from the completion response
-// and strips the already entered code from the completion
-func cleanCompletionResponse(response string, lastWord string) (cleanResp string) {
+// and strips the already entered code from the completion while preserving formatting
+func cleanCompletionResponse(response string, lastWord string, currentIndent string) (cleanResp string) {
 	// remove <think></think> tags and their content using regex
 	re := regexp.MustCompile(`<think>[\s\S]*?</think>`)
 
@@ -137,20 +141,67 @@ func cleanCompletionResponse(response string, lastWord string) (cleanResp string
 	matches := codeBlockRegex.FindStringSubmatch(cleanResp)
 
 	if len(matches) > 1 {
-		// extract the code block content
-		cleanResp = strings.TrimSpace(matches[1])
+		// extract the code block content, preserve leading newlines
+		cleanResp = matches[1]
 	} else {
-		// if no code block is found, keep the original response
-		cleanResp = strings.TrimSpace(cleanResp)
+		// if no code block is found, only trim trailing whitespace
+		cleanResp = strings.TrimRight(cleanResp, " \t")
 	}
 
-	// remove markdown backticks
+	// remove markdown backticks but preserve newlines
 	cleanResp = strings.Trim(cleanResp, "`")
 
 	// if there is a last word, and the completion result starts with the last word, remove the already entered part
-	if lastWord != "" && strings.HasPrefix(cleanResp, lastWord) {
-		cleanResp = cleanResp[len(lastWord):]
+	if lastWord != "" && strings.HasPrefix(strings.TrimLeft(cleanResp, " \t\n"), lastWord) {
+		// Find the position after the last word, preserving leading whitespace
+		trimmed := strings.TrimLeft(cleanResp, " \t\n")
+		leadingWhitespace := cleanResp[:len(cleanResp)-len(trimmed)]
+		cleanResp = leadingWhitespace + trimmed[len(lastWord):]
 	}
 
+	// Fix indentation for multi-line completions
+	cleanResp = fixCompletionIndentation(cleanResp, currentIndent)
+
 	return
 }
+
+// fixCompletionIndentation ensures proper indentation for multi-line completions
+func fixCompletionIndentation(completion string, baseIndent string) string {
+	lines := strings.Split(completion, "\n")
+	if len(lines) <= 1 {
+		return completion
+	}
+
+	result := []string{lines[0]} // First line stays as-is
+
+	for i := 1; i < len(lines); i++ {
+		line := lines[i]
+		
+		// Skip empty lines
+		if strings.TrimSpace(line) == "" {
+			result = append(result, "")
+			continue
+		}
+		
+		// Remove any existing indentation and apply base indentation
+		trimmedLine := strings.TrimLeft(line, " \t")
+		
+		// For Nginx config, determine appropriate indentation level
+		indentLevel := getIndentLevel(trimmedLine, baseIndent)
+		
+		result = append(result, baseIndent + indentLevel + trimmedLine)
+	}
+
+	return strings.Join(result, "\n")
+}
+
+// getIndentLevel determines the appropriate indentation for a line based on content
+func getIndentLevel(line string, baseIndent string) string {
+	// If line starts with a closing brace, use base indent (no extra)
+	if strings.HasPrefix(strings.TrimSpace(line), "}") {
+		return ""
+	}
+	
+	// For regular directives inside blocks, add one level of indentation
+	return "    " // 4 spaces for one indent level
+}

+ 46 - 0
internal/migrate/7.rename_chatgpt_logs_to_llm_messages.go

@@ -0,0 +1,46 @@
+package migrate
+
+import (
+	"github.com/go-gormigrate/gormigrate/v2"
+	"gorm.io/gorm"
+)
+
+var RenameChatGPTLogsToLLMMessages = &gormigrate.Migration{
+	ID: "20250831000001",
+	Migrate: func(tx *gorm.DB) error {
+		// 检查 chatgpt_logs 表是否存在
+		if !tx.Migrator().HasTable("chat_gpt_logs") {
+			return nil
+		}
+
+		// 检查 llm_messages 表是否存在
+		if !tx.Migrator().HasTable("llm_messages") {
+			// llm_messages 表不存在,直接重命名
+			if err := tx.Exec("ALTER TABLE chat_gpt_logs RENAME TO llm_messages").Error; err != nil {
+				return err
+			}
+		} else {
+			// llm_messages 表已存在,迁移数据后删除旧表
+			// 使用原生 SQL 迁移数据,因为两个表结构相同
+			if err := tx.Exec("INSERT INTO llm_messages (name, content) SELECT name, content FROM chat_gpt_logs WHERE NOT EXISTS (SELECT 1 FROM llm_messages WHERE llm_messages.name = chat_gpt_logs.name)").Error; err != nil {
+				return err
+			}
+
+			// 删除旧表
+			if err := tx.Migrator().DropTable("chat_gpt_logs"); err != nil {
+				return err
+			}
+		}
+
+		return nil
+	},
+	Rollback: func(tx *gorm.DB) error {
+		// 回滚:将 llm_messages 表重命名回 chatgpt_logs
+		if !tx.Migrator().HasTable("chat_gpt_logs") && tx.Migrator().HasTable("llm_messages") {
+			if err := tx.Exec("ALTER TABLE llm_messages RENAME TO chat_gpt_logs").Error; err != nil {
+				return err
+			}
+		}
+		return nil
+	},
+}

+ 1 - 0
internal/migrate/migrate.go

@@ -10,6 +10,7 @@ var Migrations = []*gormigrate.Migration{
 	UpdateCertDomains,
 	RenameEnvGroupsToNamespaces,
 	RenameEnvironmentsToNodes,
+	RenameChatGPTLogsToLLMMessages,
 }
 
 var BeforeAutoMigrate = []*gormigrate.Migration{

+ 1 - 1
internal/site/rename.go

@@ -60,7 +60,7 @@ func Rename(oldName string, newName string) (err error) {
 	}
 
 	// update ChatGPT history
-	g := query.ChatGPTLog
+	g := query.LLMMessages
 	_, _ = g.Where(g.Name.Eq(oldName)).Update(g.Name, newName)
 
 	// update config history

+ 2 - 2
internal/stream/rename.go

@@ -59,8 +59,8 @@ func Rename(oldName string, newName string) (err error) {
 		return res.GetError()
 	}
 
-	// update ChatGPT history
-	g := query.ChatGPTLog
+	// update LLM history
+	g := query.LLMMessages
 	_, _ = g.Where(g.Name.Eq(oldName)).Update(g.Name, newName)
 
 	// update config history

+ 3 - 3
mcp/config/config_get.go

@@ -41,8 +41,8 @@ func handleNginxConfigGet(ctx context.Context, request mcp.CallToolRequest) (*mc
 	}
 
 	q := query.Config
-	g := query.ChatGPTLog
-	chatgpt, err := g.Where(g.Name.Eq(absPath)).FirstOrCreate()
+	g := query.LLMMessages
+	llmMsg, err := g.Where(g.Name.Eq(absPath)).FirstOrCreate()
 	if err != nil {
 		return nil, err
 	}
@@ -55,7 +55,7 @@ func handleNginxConfigGet(ctx context.Context, request mcp.CallToolRequest) (*mc
 	result := map[string]interface{}{
 		"name":              stat.Name(),
 		"content":           string(content),
-		"chat_gpt_messages": chatgpt.Content,
+		"llm_messages": llmMsg.Content,
 		"file_path":         absPath,
 		"modified_at":       stat.ModTime(),
 		"dir":               filepath.Dir(relativePath),

+ 2 - 2
mcp/config/config_rename.go

@@ -72,8 +72,8 @@ func handleNginxConfigRename(ctx context.Context, request mcp.CallToolRequest) (
 		return nil, err
 	}
 
-	// update ChatGPT records
-	g := query.ChatGPTLog
+	// update LLM records
+	g := query.LLMMessages
 	q := query.Config
 	cfg, err := q.Where(q.Filepath.Eq(origFullPath)).FirstOrInit()
 	if err != nil {

+ 7 - 6
model/chatgpt_log.go → model/llm_messages.go

@@ -5,13 +5,14 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+
 	"github.com/sashabaranov/go-openai"
 )
 
-type ChatGPTCompletionMessages []openai.ChatCompletionMessage
+type LLMCompletionMessages []openai.ChatCompletionMessage
 
 // Scan value into Jsonb, implements sql.Scanner interface
-func (j *ChatGPTCompletionMessages) Scan(value interface{}) error {
+func (j *LLMCompletionMessages) Scan(value interface{}) error {
 	bytes, ok := value.([]byte)
 	if !ok {
 		return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
@@ -25,11 +26,11 @@ func (j *ChatGPTCompletionMessages) Scan(value interface{}) error {
 }
 
 // Value return json value, implement driver.Valuer interface
-func (j *ChatGPTCompletionMessages) Value() (driver.Value, error) {
+func (j *LLMCompletionMessages) Value() (driver.Value, error) {
 	return json.Marshal(*j)
 }
 
-type ChatGPTLog struct {
-	Name    string                    `json:"name"`
-	Content ChatGPTCompletionMessages `json:"content" gorm:"serializer:json"`
+type LLMMessages struct {
+	Name    string                `json:"name"`
+	Content LLMCompletionMessages `json:"content" gorm:"serializer:json"`
 }

+ 1 - 1
model/model.go

@@ -38,7 +38,7 @@ func GenerateAllModel() []any {
 		User{},
 		AuthToken{},
 		Cert{},
-		ChatGPTLog{},
+		LLMMessages{},
 		Site{},
 		Stream{},
 		DnsCredential{},

+ 0 - 354
query/chat_gpt_logs.gen.go

@@ -1,354 +0,0 @@
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-
-package query
-
-import (
-	"context"
-	"strings"
-
-	"gorm.io/gorm"
-	"gorm.io/gorm/clause"
-	"gorm.io/gorm/schema"
-
-	"gorm.io/gen"
-	"gorm.io/gen/field"
-
-	"gorm.io/plugin/dbresolver"
-
-	"github.com/0xJacky/Nginx-UI/model"
-)
-
-func newChatGPTLog(db *gorm.DB, opts ...gen.DOOption) chatGPTLog {
-	_chatGPTLog := chatGPTLog{}
-
-	_chatGPTLog.chatGPTLogDo.UseDB(db, opts...)
-	_chatGPTLog.chatGPTLogDo.UseModel(&model.ChatGPTLog{})
-
-	tableName := _chatGPTLog.chatGPTLogDo.TableName()
-	_chatGPTLog.ALL = field.NewAsterisk(tableName)
-	_chatGPTLog.Name = field.NewString(tableName, "name")
-	_chatGPTLog.Content = field.NewField(tableName, "content")
-
-	_chatGPTLog.fillFieldMap()
-
-	return _chatGPTLog
-}
-
-type chatGPTLog struct {
-	chatGPTLogDo
-
-	ALL     field.Asterisk
-	Name    field.String
-	Content field.Field
-
-	fieldMap map[string]field.Expr
-}
-
-func (c chatGPTLog) Table(newTableName string) *chatGPTLog {
-	c.chatGPTLogDo.UseTable(newTableName)
-	return c.updateTableName(newTableName)
-}
-
-func (c chatGPTLog) As(alias string) *chatGPTLog {
-	c.chatGPTLogDo.DO = *(c.chatGPTLogDo.As(alias).(*gen.DO))
-	return c.updateTableName(alias)
-}
-
-func (c *chatGPTLog) updateTableName(table string) *chatGPTLog {
-	c.ALL = field.NewAsterisk(table)
-	c.Name = field.NewString(table, "name")
-	c.Content = field.NewField(table, "content")
-
-	c.fillFieldMap()
-
-	return c
-}
-
-func (c *chatGPTLog) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
-	_f, ok := c.fieldMap[fieldName]
-	if !ok || _f == nil {
-		return nil, false
-	}
-	_oe, ok := _f.(field.OrderExpr)
-	return _oe, ok
-}
-
-func (c *chatGPTLog) fillFieldMap() {
-	c.fieldMap = make(map[string]field.Expr, 2)
-	c.fieldMap["name"] = c.Name
-	c.fieldMap["content"] = c.Content
-}
-
-func (c chatGPTLog) clone(db *gorm.DB) chatGPTLog {
-	c.chatGPTLogDo.ReplaceConnPool(db.Statement.ConnPool)
-	return c
-}
-
-func (c chatGPTLog) replaceDB(db *gorm.DB) chatGPTLog {
-	c.chatGPTLogDo.ReplaceDB(db)
-	return c
-}
-
-type chatGPTLogDo struct{ gen.DO }
-
-// FirstByID Where("id=@id")
-func (c chatGPTLogDo) FirstByID(id uint64) (result *model.ChatGPTLog, err error) {
-	var params []interface{}
-
-	var generateSQL strings.Builder
-	params = append(params, id)
-	generateSQL.WriteString("id=? ")
-
-	var executeSQL *gorm.DB
-	executeSQL = c.UnderlyingDB().Where(generateSQL.String(), params...).Take(&result) // ignore_security_alert
-	err = executeSQL.Error
-
-	return
-}
-
-// DeleteByID update @@table set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=@id
-func (c chatGPTLogDo) DeleteByID(id uint64) (err error) {
-	var params []interface{}
-
-	var generateSQL strings.Builder
-	params = append(params, id)
-	generateSQL.WriteString("update chat_gpt_logs set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=? ")
-
-	var executeSQL *gorm.DB
-	executeSQL = c.UnderlyingDB().Exec(generateSQL.String(), params...) // ignore_security_alert
-	err = executeSQL.Error
-
-	return
-}
-
-func (c chatGPTLogDo) Debug() *chatGPTLogDo {
-	return c.withDO(c.DO.Debug())
-}
-
-func (c chatGPTLogDo) WithContext(ctx context.Context) *chatGPTLogDo {
-	return c.withDO(c.DO.WithContext(ctx))
-}
-
-func (c chatGPTLogDo) ReadDB() *chatGPTLogDo {
-	return c.Clauses(dbresolver.Read)
-}
-
-func (c chatGPTLogDo) WriteDB() *chatGPTLogDo {
-	return c.Clauses(dbresolver.Write)
-}
-
-func (c chatGPTLogDo) Session(config *gorm.Session) *chatGPTLogDo {
-	return c.withDO(c.DO.Session(config))
-}
-
-func (c chatGPTLogDo) Clauses(conds ...clause.Expression) *chatGPTLogDo {
-	return c.withDO(c.DO.Clauses(conds...))
-}
-
-func (c chatGPTLogDo) Returning(value interface{}, columns ...string) *chatGPTLogDo {
-	return c.withDO(c.DO.Returning(value, columns...))
-}
-
-func (c chatGPTLogDo) Not(conds ...gen.Condition) *chatGPTLogDo {
-	return c.withDO(c.DO.Not(conds...))
-}
-
-func (c chatGPTLogDo) Or(conds ...gen.Condition) *chatGPTLogDo {
-	return c.withDO(c.DO.Or(conds...))
-}
-
-func (c chatGPTLogDo) Select(conds ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.Select(conds...))
-}
-
-func (c chatGPTLogDo) Where(conds ...gen.Condition) *chatGPTLogDo {
-	return c.withDO(c.DO.Where(conds...))
-}
-
-func (c chatGPTLogDo) Order(conds ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.Order(conds...))
-}
-
-func (c chatGPTLogDo) Distinct(cols ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.Distinct(cols...))
-}
-
-func (c chatGPTLogDo) Omit(cols ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.Omit(cols...))
-}
-
-func (c chatGPTLogDo) Join(table schema.Tabler, on ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.Join(table, on...))
-}
-
-func (c chatGPTLogDo) LeftJoin(table schema.Tabler, on ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.LeftJoin(table, on...))
-}
-
-func (c chatGPTLogDo) RightJoin(table schema.Tabler, on ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.RightJoin(table, on...))
-}
-
-func (c chatGPTLogDo) Group(cols ...field.Expr) *chatGPTLogDo {
-	return c.withDO(c.DO.Group(cols...))
-}
-
-func (c chatGPTLogDo) Having(conds ...gen.Condition) *chatGPTLogDo {
-	return c.withDO(c.DO.Having(conds...))
-}
-
-func (c chatGPTLogDo) Limit(limit int) *chatGPTLogDo {
-	return c.withDO(c.DO.Limit(limit))
-}
-
-func (c chatGPTLogDo) Offset(offset int) *chatGPTLogDo {
-	return c.withDO(c.DO.Offset(offset))
-}
-
-func (c chatGPTLogDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *chatGPTLogDo {
-	return c.withDO(c.DO.Scopes(funcs...))
-}
-
-func (c chatGPTLogDo) Unscoped() *chatGPTLogDo {
-	return c.withDO(c.DO.Unscoped())
-}
-
-func (c chatGPTLogDo) Create(values ...*model.ChatGPTLog) error {
-	if len(values) == 0 {
-		return nil
-	}
-	return c.DO.Create(values)
-}
-
-func (c chatGPTLogDo) CreateInBatches(values []*model.ChatGPTLog, batchSize int) error {
-	return c.DO.CreateInBatches(values, batchSize)
-}
-
-// Save : !!! underlying implementation is different with GORM
-// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
-func (c chatGPTLogDo) Save(values ...*model.ChatGPTLog) error {
-	if len(values) == 0 {
-		return nil
-	}
-	return c.DO.Save(values)
-}
-
-func (c chatGPTLogDo) First() (*model.ChatGPTLog, error) {
-	if result, err := c.DO.First(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.ChatGPTLog), nil
-	}
-}
-
-func (c chatGPTLogDo) Take() (*model.ChatGPTLog, error) {
-	if result, err := c.DO.Take(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.ChatGPTLog), nil
-	}
-}
-
-func (c chatGPTLogDo) Last() (*model.ChatGPTLog, error) {
-	if result, err := c.DO.Last(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.ChatGPTLog), nil
-	}
-}
-
-func (c chatGPTLogDo) Find() ([]*model.ChatGPTLog, error) {
-	result, err := c.DO.Find()
-	return result.([]*model.ChatGPTLog), err
-}
-
-func (c chatGPTLogDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ChatGPTLog, err error) {
-	buf := make([]*model.ChatGPTLog, 0, batchSize)
-	err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
-		defer func() { results = append(results, buf...) }()
-		return fc(tx, batch)
-	})
-	return results, err
-}
-
-func (c chatGPTLogDo) FindInBatches(result *[]*model.ChatGPTLog, batchSize int, fc func(tx gen.Dao, batch int) error) error {
-	return c.DO.FindInBatches(result, batchSize, fc)
-}
-
-func (c chatGPTLogDo) Attrs(attrs ...field.AssignExpr) *chatGPTLogDo {
-	return c.withDO(c.DO.Attrs(attrs...))
-}
-
-func (c chatGPTLogDo) Assign(attrs ...field.AssignExpr) *chatGPTLogDo {
-	return c.withDO(c.DO.Assign(attrs...))
-}
-
-func (c chatGPTLogDo) Joins(fields ...field.RelationField) *chatGPTLogDo {
-	for _, _f := range fields {
-		c = *c.withDO(c.DO.Joins(_f))
-	}
-	return &c
-}
-
-func (c chatGPTLogDo) Preload(fields ...field.RelationField) *chatGPTLogDo {
-	for _, _f := range fields {
-		c = *c.withDO(c.DO.Preload(_f))
-	}
-	return &c
-}
-
-func (c chatGPTLogDo) FirstOrInit() (*model.ChatGPTLog, error) {
-	if result, err := c.DO.FirstOrInit(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.ChatGPTLog), nil
-	}
-}
-
-func (c chatGPTLogDo) FirstOrCreate() (*model.ChatGPTLog, error) {
-	if result, err := c.DO.FirstOrCreate(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.ChatGPTLog), nil
-	}
-}
-
-func (c chatGPTLogDo) FindByPage(offset int, limit int) (result []*model.ChatGPTLog, count int64, err error) {
-	result, err = c.Offset(offset).Limit(limit).Find()
-	if err != nil {
-		return
-	}
-
-	if size := len(result); 0 < limit && 0 < size && size < limit {
-		count = int64(size + offset)
-		return
-	}
-
-	count, err = c.Offset(-1).Limit(-1).Count()
-	return
-}
-
-func (c chatGPTLogDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
-	count, err = c.Count()
-	if err != nil {
-		return
-	}
-
-	err = c.Offset(offset).Limit(limit).Scan(result)
-	return
-}
-
-func (c chatGPTLogDo) Scan(result interface{}) (err error) {
-	return c.DO.Scan(result)
-}
-
-func (c chatGPTLogDo) Delete(models ...*model.ChatGPTLog) (result gen.ResultInfo, err error) {
-	return c.DO.Delete(models)
-}
-
-func (c *chatGPTLogDo) withDO(do gen.Dao) *chatGPTLogDo {
-	c.DO = *do.(*gen.DO)
-	return c
-}

+ 8 - 8
query/gen.go

@@ -22,11 +22,11 @@ var (
 	AutoBackup     *autoBackup
 	BanIP          *banIP
 	Cert           *cert
-	ChatGPTLog     *chatGPTLog
 	Config         *config
 	ConfigBackup   *configBackup
 	DnsCredential  *dnsCredential
 	ExternalNotify *externalNotify
+	LLMMessages    *lLMMessages
 	Namespace      *namespace
 	NginxLogIndex  *nginxLogIndex
 	Node           *node
@@ -45,11 +45,11 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
 	AutoBackup = &Q.AutoBackup
 	BanIP = &Q.BanIP
 	Cert = &Q.Cert
-	ChatGPTLog = &Q.ChatGPTLog
 	Config = &Q.Config
 	ConfigBackup = &Q.ConfigBackup
 	DnsCredential = &Q.DnsCredential
 	ExternalNotify = &Q.ExternalNotify
+	LLMMessages = &Q.LLMMessages
 	Namespace = &Q.Namespace
 	NginxLogIndex = &Q.NginxLogIndex
 	Node = &Q.Node
@@ -69,11 +69,11 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
 		AutoBackup:     newAutoBackup(db, opts...),
 		BanIP:          newBanIP(db, opts...),
 		Cert:           newCert(db, opts...),
-		ChatGPTLog:     newChatGPTLog(db, opts...),
 		Config:         newConfig(db, opts...),
 		ConfigBackup:   newConfigBackup(db, opts...),
 		DnsCredential:  newDnsCredential(db, opts...),
 		ExternalNotify: newExternalNotify(db, opts...),
+		LLMMessages:    newLLMMessages(db, opts...),
 		Namespace:      newNamespace(db, opts...),
 		NginxLogIndex:  newNginxLogIndex(db, opts...),
 		Node:           newNode(db, opts...),
@@ -94,11 +94,11 @@ type Query struct {
 	AutoBackup     autoBackup
 	BanIP          banIP
 	Cert           cert
-	ChatGPTLog     chatGPTLog
 	Config         config
 	ConfigBackup   configBackup
 	DnsCredential  dnsCredential
 	ExternalNotify externalNotify
+	LLMMessages    lLMMessages
 	Namespace      namespace
 	NginxLogIndex  nginxLogIndex
 	Node           node
@@ -120,11 +120,11 @@ func (q *Query) clone(db *gorm.DB) *Query {
 		AutoBackup:     q.AutoBackup.clone(db),
 		BanIP:          q.BanIP.clone(db),
 		Cert:           q.Cert.clone(db),
-		ChatGPTLog:     q.ChatGPTLog.clone(db),
 		Config:         q.Config.clone(db),
 		ConfigBackup:   q.ConfigBackup.clone(db),
 		DnsCredential:  q.DnsCredential.clone(db),
 		ExternalNotify: q.ExternalNotify.clone(db),
+		LLMMessages:    q.LLMMessages.clone(db),
 		Namespace:      q.Namespace.clone(db),
 		NginxLogIndex:  q.NginxLogIndex.clone(db),
 		Node:           q.Node.clone(db),
@@ -153,11 +153,11 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
 		AutoBackup:     q.AutoBackup.replaceDB(db),
 		BanIP:          q.BanIP.replaceDB(db),
 		Cert:           q.Cert.replaceDB(db),
-		ChatGPTLog:     q.ChatGPTLog.replaceDB(db),
 		Config:         q.Config.replaceDB(db),
 		ConfigBackup:   q.ConfigBackup.replaceDB(db),
 		DnsCredential:  q.DnsCredential.replaceDB(db),
 		ExternalNotify: q.ExternalNotify.replaceDB(db),
+		LLMMessages:    q.LLMMessages.replaceDB(db),
 		Namespace:      q.Namespace.replaceDB(db),
 		NginxLogIndex:  q.NginxLogIndex.replaceDB(db),
 		Node:           q.Node.replaceDB(db),
@@ -176,11 +176,11 @@ type queryCtx struct {
 	AutoBackup     *autoBackupDo
 	BanIP          *banIPDo
 	Cert           *certDo
-	ChatGPTLog     *chatGPTLogDo
 	Config         *configDo
 	ConfigBackup   *configBackupDo
 	DnsCredential  *dnsCredentialDo
 	ExternalNotify *externalNotifyDo
+	LLMMessages    *lLMMessagesDo
 	Namespace      *namespaceDo
 	NginxLogIndex  *nginxLogIndexDo
 	Node           *nodeDo
@@ -199,11 +199,11 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
 		AutoBackup:     q.AutoBackup.WithContext(ctx),
 		BanIP:          q.BanIP.WithContext(ctx),
 		Cert:           q.Cert.WithContext(ctx),
-		ChatGPTLog:     q.ChatGPTLog.WithContext(ctx),
 		Config:         q.Config.WithContext(ctx),
 		ConfigBackup:   q.ConfigBackup.WithContext(ctx),
 		DnsCredential:  q.DnsCredential.WithContext(ctx),
 		ExternalNotify: q.ExternalNotify.WithContext(ctx),
+		LLMMessages:    q.LLMMessages.WithContext(ctx),
 		Namespace:      q.Namespace.WithContext(ctx),
 		NginxLogIndex:  q.NginxLogIndex.WithContext(ctx),
 		Node:           q.Node.WithContext(ctx),

+ 354 - 0
query/llm_messages.gen.go

@@ -0,0 +1,354 @@
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+
+package query
+
+import (
+	"context"
+	"strings"
+
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+	"gorm.io/gorm/schema"
+
+	"gorm.io/gen"
+	"gorm.io/gen/field"
+
+	"gorm.io/plugin/dbresolver"
+
+	"github.com/0xJacky/Nginx-UI/model"
+)
+
+func newLLMMessages(db *gorm.DB, opts ...gen.DOOption) lLMMessages {
+	_lLMMessages := lLMMessages{}
+
+	_lLMMessages.lLMMessagesDo.UseDB(db, opts...)
+	_lLMMessages.lLMMessagesDo.UseModel(&model.LLMMessages{})
+
+	tableName := _lLMMessages.lLMMessagesDo.TableName()
+	_lLMMessages.ALL = field.NewAsterisk(tableName)
+	_lLMMessages.Name = field.NewString(tableName, "name")
+	_lLMMessages.Content = field.NewField(tableName, "content")
+
+	_lLMMessages.fillFieldMap()
+
+	return _lLMMessages
+}
+
+type lLMMessages struct {
+	lLMMessagesDo
+
+	ALL     field.Asterisk
+	Name    field.String
+	Content field.Field
+
+	fieldMap map[string]field.Expr
+}
+
+func (l lLMMessages) Table(newTableName string) *lLMMessages {
+	l.lLMMessagesDo.UseTable(newTableName)
+	return l.updateTableName(newTableName)
+}
+
+func (l lLMMessages) As(alias string) *lLMMessages {
+	l.lLMMessagesDo.DO = *(l.lLMMessagesDo.As(alias).(*gen.DO))
+	return l.updateTableName(alias)
+}
+
+func (l *lLMMessages) updateTableName(table string) *lLMMessages {
+	l.ALL = field.NewAsterisk(table)
+	l.Name = field.NewString(table, "name")
+	l.Content = field.NewField(table, "content")
+
+	l.fillFieldMap()
+
+	return l
+}
+
+func (l *lLMMessages) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
+	_f, ok := l.fieldMap[fieldName]
+	if !ok || _f == nil {
+		return nil, false
+	}
+	_oe, ok := _f.(field.OrderExpr)
+	return _oe, ok
+}
+
+func (l *lLMMessages) fillFieldMap() {
+	l.fieldMap = make(map[string]field.Expr, 2)
+	l.fieldMap["name"] = l.Name
+	l.fieldMap["content"] = l.Content
+}
+
+func (l lLMMessages) clone(db *gorm.DB) lLMMessages {
+	l.lLMMessagesDo.ReplaceConnPool(db.Statement.ConnPool)
+	return l
+}
+
+func (l lLMMessages) replaceDB(db *gorm.DB) lLMMessages {
+	l.lLMMessagesDo.ReplaceDB(db)
+	return l
+}
+
+type lLMMessagesDo struct{ gen.DO }
+
+// FirstByID Where("id=@id")
+func (l lLMMessagesDo) FirstByID(id uint64) (result *model.LLMMessages, err error) {
+	var params []interface{}
+
+	var generateSQL strings.Builder
+	params = append(params, id)
+	generateSQL.WriteString("id=? ")
+
+	var executeSQL *gorm.DB
+	executeSQL = l.UnderlyingDB().Where(generateSQL.String(), params...).Take(&result) // ignore_security_alert
+	err = executeSQL.Error
+
+	return
+}
+
+// DeleteByID update @@table set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=@id
+func (l lLMMessagesDo) DeleteByID(id uint64) (err error) {
+	var params []interface{}
+
+	var generateSQL strings.Builder
+	params = append(params, id)
+	generateSQL.WriteString("update llm_messages set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=? ")
+
+	var executeSQL *gorm.DB
+	executeSQL = l.UnderlyingDB().Exec(generateSQL.String(), params...) // ignore_security_alert
+	err = executeSQL.Error
+
+	return
+}
+
+func (l lLMMessagesDo) Debug() *lLMMessagesDo {
+	return l.withDO(l.DO.Debug())
+}
+
+func (l lLMMessagesDo) WithContext(ctx context.Context) *lLMMessagesDo {
+	return l.withDO(l.DO.WithContext(ctx))
+}
+
+func (l lLMMessagesDo) ReadDB() *lLMMessagesDo {
+	return l.Clauses(dbresolver.Read)
+}
+
+func (l lLMMessagesDo) WriteDB() *lLMMessagesDo {
+	return l.Clauses(dbresolver.Write)
+}
+
+func (l lLMMessagesDo) Session(config *gorm.Session) *lLMMessagesDo {
+	return l.withDO(l.DO.Session(config))
+}
+
+func (l lLMMessagesDo) Clauses(conds ...clause.Expression) *lLMMessagesDo {
+	return l.withDO(l.DO.Clauses(conds...))
+}
+
+func (l lLMMessagesDo) Returning(value interface{}, columns ...string) *lLMMessagesDo {
+	return l.withDO(l.DO.Returning(value, columns...))
+}
+
+func (l lLMMessagesDo) Not(conds ...gen.Condition) *lLMMessagesDo {
+	return l.withDO(l.DO.Not(conds...))
+}
+
+func (l lLMMessagesDo) Or(conds ...gen.Condition) *lLMMessagesDo {
+	return l.withDO(l.DO.Or(conds...))
+}
+
+func (l lLMMessagesDo) Select(conds ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.Select(conds...))
+}
+
+func (l lLMMessagesDo) Where(conds ...gen.Condition) *lLMMessagesDo {
+	return l.withDO(l.DO.Where(conds...))
+}
+
+func (l lLMMessagesDo) Order(conds ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.Order(conds...))
+}
+
+func (l lLMMessagesDo) Distinct(cols ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.Distinct(cols...))
+}
+
+func (l lLMMessagesDo) Omit(cols ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.Omit(cols...))
+}
+
+func (l lLMMessagesDo) Join(table schema.Tabler, on ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.Join(table, on...))
+}
+
+func (l lLMMessagesDo) LeftJoin(table schema.Tabler, on ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.LeftJoin(table, on...))
+}
+
+func (l lLMMessagesDo) RightJoin(table schema.Tabler, on ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.RightJoin(table, on...))
+}
+
+func (l lLMMessagesDo) Group(cols ...field.Expr) *lLMMessagesDo {
+	return l.withDO(l.DO.Group(cols...))
+}
+
+func (l lLMMessagesDo) Having(conds ...gen.Condition) *lLMMessagesDo {
+	return l.withDO(l.DO.Having(conds...))
+}
+
+func (l lLMMessagesDo) Limit(limit int) *lLMMessagesDo {
+	return l.withDO(l.DO.Limit(limit))
+}
+
+func (l lLMMessagesDo) Offset(offset int) *lLMMessagesDo {
+	return l.withDO(l.DO.Offset(offset))
+}
+
+func (l lLMMessagesDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *lLMMessagesDo {
+	return l.withDO(l.DO.Scopes(funcs...))
+}
+
+func (l lLMMessagesDo) Unscoped() *lLMMessagesDo {
+	return l.withDO(l.DO.Unscoped())
+}
+
+func (l lLMMessagesDo) Create(values ...*model.LLMMessages) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return l.DO.Create(values)
+}
+
+func (l lLMMessagesDo) CreateInBatches(values []*model.LLMMessages, batchSize int) error {
+	return l.DO.CreateInBatches(values, batchSize)
+}
+
+// Save : !!! underlying implementation is different with GORM
+// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
+func (l lLMMessagesDo) Save(values ...*model.LLMMessages) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return l.DO.Save(values)
+}
+
+func (l lLMMessagesDo) First() (*model.LLMMessages, error) {
+	if result, err := l.DO.First(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.LLMMessages), nil
+	}
+}
+
+func (l lLMMessagesDo) Take() (*model.LLMMessages, error) {
+	if result, err := l.DO.Take(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.LLMMessages), nil
+	}
+}
+
+func (l lLMMessagesDo) Last() (*model.LLMMessages, error) {
+	if result, err := l.DO.Last(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.LLMMessages), nil
+	}
+}
+
+func (l lLMMessagesDo) Find() ([]*model.LLMMessages, error) {
+	result, err := l.DO.Find()
+	return result.([]*model.LLMMessages), err
+}
+
+func (l lLMMessagesDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.LLMMessages, err error) {
+	buf := make([]*model.LLMMessages, 0, batchSize)
+	err = l.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
+		defer func() { results = append(results, buf...) }()
+		return fc(tx, batch)
+	})
+	return results, err
+}
+
+func (l lLMMessagesDo) FindInBatches(result *[]*model.LLMMessages, batchSize int, fc func(tx gen.Dao, batch int) error) error {
+	return l.DO.FindInBatches(result, batchSize, fc)
+}
+
+func (l lLMMessagesDo) Attrs(attrs ...field.AssignExpr) *lLMMessagesDo {
+	return l.withDO(l.DO.Attrs(attrs...))
+}
+
+func (l lLMMessagesDo) Assign(attrs ...field.AssignExpr) *lLMMessagesDo {
+	return l.withDO(l.DO.Assign(attrs...))
+}
+
+func (l lLMMessagesDo) Joins(fields ...field.RelationField) *lLMMessagesDo {
+	for _, _f := range fields {
+		l = *l.withDO(l.DO.Joins(_f))
+	}
+	return &l
+}
+
+func (l lLMMessagesDo) Preload(fields ...field.RelationField) *lLMMessagesDo {
+	for _, _f := range fields {
+		l = *l.withDO(l.DO.Preload(_f))
+	}
+	return &l
+}
+
+func (l lLMMessagesDo) FirstOrInit() (*model.LLMMessages, error) {
+	if result, err := l.DO.FirstOrInit(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.LLMMessages), nil
+	}
+}
+
+func (l lLMMessagesDo) FirstOrCreate() (*model.LLMMessages, error) {
+	if result, err := l.DO.FirstOrCreate(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.LLMMessages), nil
+	}
+}
+
+func (l lLMMessagesDo) FindByPage(offset int, limit int) (result []*model.LLMMessages, count int64, err error) {
+	result, err = l.Offset(offset).Limit(limit).Find()
+	if err != nil {
+		return
+	}
+
+	if size := len(result); 0 < limit && 0 < size && size < limit {
+		count = int64(size + offset)
+		return
+	}
+
+	count, err = l.Offset(-1).Limit(-1).Count()
+	return
+}
+
+func (l lLMMessagesDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
+	count, err = l.Count()
+	if err != nil {
+		return
+	}
+
+	err = l.Offset(offset).Limit(limit).Scan(result)
+	return
+}
+
+func (l lLMMessagesDo) Scan(result interface{}) (err error) {
+	return l.DO.Scan(result)
+}
+
+func (l lLMMessagesDo) Delete(models ...*model.LLMMessages) (result gen.ResultInfo, err error) {
+	return l.DO.Delete(models)
+}
+
+func (l *lLMMessagesDo) withDO(do gen.Dao) *lLMMessagesDo {
+	l.DO = *do.(*gen.DO)
+	return l
+}

+ 8 - 2
router/routers.go

@@ -14,10 +14,10 @@ import (
 	"github.com/0xJacky/Nginx-UI/api/event"
 	"github.com/0xJacky/Nginx-UI/api/external_notify"
 	"github.com/0xJacky/Nginx-UI/api/license"
+	"github.com/0xJacky/Nginx-UI/api/llm"
 	"github.com/0xJacky/Nginx-UI/api/nginx"
 	nginxLog "github.com/0xJacky/Nginx-UI/api/nginx_log"
 	"github.com/0xJacky/Nginx-UI/api/notification"
-	"github.com/0xJacky/Nginx-UI/api/openai"
 	"github.com/0xJacky/Nginx-UI/api/pages"
 	"github.com/0xJacky/Nginx-UI/api/public"
 	"github.com/0xJacky/Nginx-UI/api/settings"
@@ -66,6 +66,12 @@ func InitRouter() {
 		system.InitSelfCheckRouter(root)
 		backup.InitRouter(root)
 
+		// Local-only routes (no proxy) - authorization required
+		local := root.Group("/", middleware.AuthRequired())
+		{
+			llm.InitLocalRouter(local)
+		}
+
 		// Authorization required and not websocket request
 		g := root.Group("/", middleware.AuthRequired(), middleware.Proxy())
 		{
@@ -85,7 +91,7 @@ func InitRouter() {
 			certificate.InitAcmeUserRouter(g)
 			system.InitPrivateRouter(g)
 			settings.InitRouter(g)
-			openai.InitRouter(g)
+			llm.InitRouter(g)
 			cluster.InitRouter(g)
 			notification.InitRouter(g)
 			external_notify.InitRouter(g)