<template>
  <div class="prompt-config-container">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span class="card-title">
          <i class="el-icon-setting"></i>
          DS提示词模板配置
        </span>
        <el-button 
          style="float: right; padding: 3px 0" 
          type="text" 
          @click="showHelp = !showHelp">
          {{ showHelp ? '隐藏帮助' : '显示帮助' }}
        </el-button>
      </div>

      <!-- 帮助说明 -->
      <el-collapse-transition>
        <div v-show="showHelp" class="help-section">
          <el-alert
            title="使用说明"
            type="info"
            :closable="false"
            show-icon>
            <div slot="default">
              <p><strong>功能说明：</strong></p>
              <ul>
                <li>配置 DS 侧提示词与闲鱼手动文案模板，存储在 Redis，修改后立即生效</li>
                <li>DS 相关模板支持占位符：%s 用于替换实际内容</li>
                <li>闲鱼模板为纯文本或一条 Java 正则（标题清洗），无占位符</li>
                <li>未在 Redis 中保存过时，文本框会回显当前内置默认全文，便于对照修改；保存后即写入 Redis</li>
                <li>删除模板将清空 Redis 并再次回显内置默认</li>
              </ul>
              <p><strong>模板类型：</strong></p>
              <ul>
                <li><strong>关键词提取模板</strong>：用于提取商品关键词，占位符：%s = 商品名称</li>
                <li><strong>小红书文案模板</strong>：用于生成小红书风格文案，占位符：%s = 商品名称，%s = 价格信息，%s = 关键词</li>
                <li><strong>抖音文案模板</strong>：用于生成抖音风格文案，占位符：%s = 商品名称，%s = 价格信息，%s = 关键词</li>
                <li><strong>通用文案模板</strong>：用于生成通用风格文案，占位符：%s = 商品名称，%s = 价格信息，%s = 关键词</li>
                <li><strong>闲鱼·正文基础</strong>：「一键代下」「教你下单」两版共用的正文说明（在标题/型号行之后）</li>
                <li><strong>闲鱼·教你下单尾部</strong>：接在「更新日期」后的附加说明</li>
                <li><strong>闲鱼·标题清洗正则</strong>：从标题、型号备注中删除匹配片段（须为合法 Java 正则）</li>
                <li><strong>闲鱼·种草文案提示词</strong>：用于可选生成高转化种草文案，支持 goods_title / goods_model / goods_type 等占位符</li>
              </ul>
            </div>
          </el-alert>
        </div>
      </el-collapse-transition>

      <!-- 模板列表 -->
      <div class="template-list">
        <el-tabs v-model="activeTab" type="border-card">
          <el-tab-pane 
            v-for="(template, key) in templates" 
            :key="key"
            :label="getTemplateLabel(key)"
            :name="key">
            <div class="template-editor">
              <div class="template-info">
                <el-alert
                  :title="template.description"
                  type="info"
                  :closable="false"
                  show-icon
                  style="margin-bottom: 15px;">
                </el-alert>
                
                <div class="template-status">
                  <el-tag :type="template.isDefault ? 'info' : 'success'" size="small">
                    {{ template.isDefault ? '内置默认（未写入 Redis，可编辑后保存）' : '已自定义（已写入 Redis）' }}
                  </el-tag>
                  <el-button
                    v-if="!template.isDefault"
                    type="text"
                    size="small"
                    icon="el-icon-refresh-left"
                    @click="handleResetTemplate(key)"
                    style="margin-left: 10px;">
                    恢复默认
                  </el-button>
                </div>
              </div>

              <el-input
                v-model="template.template"
                type="textarea"
                :rows="12"
                placeholder="请输入提示词模板..."
                class="template-textarea">
              </el-input>

              <div class="template-actions">
                <el-button 
                  type="primary"
                  icon="el-icon-check"
                  @click="handleSaveTemplate(key)"
                  :loading="saving[key]">
                  保存模板
                </el-button>
                <el-button 
                  icon="el-icon-refresh"
                  @click="handleLoadTemplate(key)">
                  重新加载
                </el-button>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
    </el-card>

    <el-card class="box-card llm-card" style="margin-top: 20px;">
      <div slot="header" class="clearfix">
        <span class="card-title">
          <i class="el-icon-connection"></i>
          大模型接入配置（多套 · 激活一套生效）
        </span>
        <div style="float: right;">
          <el-button type="primary" size="small" icon="el-icon-plus" @click="openLlmDialog(false)">新增配置</el-button>
          <el-button size="small" icon="el-icon-caret-right" @click="openLlmTest(null)">测试当前激活</el-button>
          <el-button size="small" icon="el-icon-refresh" @click="loadLlmList">刷新</el-button>
        </div>
      </div>
      <el-alert
        v-if="llmSummary && llmSummary.redisAvailable === false"
        title="当前未连接 Redis，无法保存；Jarvis 将始终使用 application.yml 中的默认 Ollama。"
        type="warning"
        :closable="false"
        show-icon
        style="margin-bottom: 16px;" />
      <el-alert
        type="info"
        :closable="false"
        show-icon
        style="margin-bottom: 16px;">
        <div slot="title">
          <p style="margin: 0 0 8px 0;"><strong>说明：</strong>可保存多套（如本地 Ollama、远程 API），在表格中点击<strong>激活</strong>后，Jarvis 社媒 AI 仅使用<strong>当前激活</strong>的一套。未激活或清空全部时走 Jarvis 默认 Ollama。</p>
          <ul style="margin: 0; padding-left: 18px;">
            <li><strong>Ollama</strong>：根地址可空（用 Jarvis 默认），模型可空。</li>
            <li><strong>OpenAI 兼容</strong>：须填<strong>完整</strong>的 Chat Completions 地址（如火山方舟为 <code>https://ark.cn-beijing.volces.com/api/v3/chat/completions</code>，不要用 Coding/OpenClaw 文档里的 <code>.../api/coding/v3</code>，否则会 404）。</li>
            <li>方舟「模型」一般填控制台<strong>推理接入点 ID</strong>（<code>ep-xxxx</code>），不是展示名（如 glm-4.7）。</li>
          </ul>
        </div>
      </el-alert>
      <p v-if="llmSummary && llmSummary.redisAvailable !== false" class="llm-active-hint">
        <template v-if="llmSummary.activeId">
          当前 Jarvis 使用：
          <el-tag type="success" size="small">{{ llmActiveName || llmSummary.activeId }}</el-tag>
        </template>
        <template v-else>
          <el-tag type="info" size="small">未激活</el-tag>
          <span style="margin-left: 8px; color: #909399;">将使用 Jarvis yml 默认 Ollama</span>
        </template>
      </p>
      <el-table
        v-loading="llmListLoading"
        :data="llmProfileRows"
        border
        stripe
        empty-text="暂无配置，请点击「新增配置」"
        style="width: 100%;">
        <el-table-column prop="name" label="名称" min-width="120" show-overflow-tooltip />
        <el-table-column label="方式" width="108">
          <template slot-scope="scope">
            {{ scope.row.mode === 'openai' ? 'OpenAI兼容' : 'Ollama' }}
          </template>
        </el-table-column>
        <el-table-column prop="baseUrl" label="地址" min-width="200" show-overflow-tooltip />
        <el-table-column prop="model" label="模型" min-width="120" show-overflow-tooltip />
        <el-table-column label="密钥" width="100">
          <template slot-scope="scope">
            {{ scope.row.hasApiKey ? (scope.row.apiKeyMasked || '已设') : '—' }}
          </template>
        </el-table-column>
        <el-table-column label="当前" width="88" align="center">
          <template slot-scope="scope">
            <el-tag v-if="scope.row.active" type="success" size="mini">使用中</el-tag>
            <span v-else>—</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="268" fixed="right">
          <template slot-scope="scope">
            <el-button type="text" size="small" :disabled="scope.row.active" @click="handleActivateLlm(scope.row)">激活</el-button>
            <el-button type="text" size="small" @click="openLlmTest(scope.row)">测试</el-button>
            <el-button type="text" size="small" @click="openLlmDialog(true, scope.row)">编辑</el-button>
            <el-button type="text" size="small" class="llm-del-btn" @click="handleDeleteLlm(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <div class="llm-toolbar-bottom">
        <el-button size="small" @click="handleClearActiveLlm">取消激活</el-button>
        <el-button type="danger" plain size="small" @click="handleResetAllLlm">清空全部配置</el-button>
      </div>

      <el-dialog
        :title="llmDialogEditId ? '编辑大模型配置' : '新增大模型配置'"
        :visible.sync="llmDialogVisible"
        width="580px"
        append-to-body
        @close="resetLlmDialogForm">
        <el-form :model="llmForm" label-width="140px" class="llm-form">
          <el-form-item label="配置名称" required>
            <el-input v-model="llmForm.name" placeholder="如：本机 Ollama、DeepSeek 官方" maxlength="80" show-word-limit />
          </el-form-item>
          <el-form-item label="接入方式">
            <el-radio-group v-model="llmForm.mode">
              <el-radio label="ollama">Ollama</el-radio>
              <el-radio label="openai">OpenAI 兼容</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item :label="llmForm.mode === 'openai' ? 'API 完整地址' : 'Ollama 根地址'">
            <el-input
              v-model="llmForm.baseUrl"
              :placeholder="llmForm.mode === 'openai' ? 'https://api.openai.com/v1/chat/completions' : 'http://127.0.0.1:11434（可空）'"
              clearable />
          </el-form-item>
          <el-form-item label="模型名称">
            <el-input
              v-model="llmForm.model"
              :placeholder="llmForm.mode === 'openai' ? '必填' : '可空'"
              clearable />
          </el-form-item>
          <el-form-item label="API 密钥">
            <el-input
              v-model="llmForm.apiKeyInput"
              type="password"
              show-password
              autocomplete="new-password"
              :placeholder="llmDialogEditId ? '留空不修改；填写则覆盖' : '可选'" />
            <span v-if="llmDialogEditId && llmHasApiKey" class="llm-key-hint">已保存：{{ llmApiKeyMasked || '****' }}</span>
          </el-form-item>
          <el-form-item v-if="llmDialogEditId && llmHasApiKey">
            <el-checkbox v-model="llmClearApiKey">清除已保存的密钥</el-checkbox>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button @click="llmDialogVisible = false">取 消</el-button>
          <el-button type="primary" :loading="llmSaving" @click="submitLlmDialog">保 存</el-button>
        </div>
      </el-dialog>

      <el-dialog
        title="大模型连通测试"
        :visible.sync="llmTestDialogVisible"
        width="560px"
        append-to-body
        @close="resetLlmTestDialog">
        <p v-if="llmTestRow" class="llm-test-hint">
          将使用配置「<strong>{{ llmTestRow.name }}</strong>」的参数请求（与是否已激活无关）。
        </p>
        <p v-else class="llm-test-hint">
          未指定某一套配置：将使用 Jarvis 当前<strong>已激活</strong>的一套；若未激活则使用 Jarvis <strong>application.yml</strong> 默认 Ollama。
        </p>
        <el-form label-width="88px">
          <el-form-item label="测试问题">
            <el-input v-model="llmTestMessage" type="textarea" :rows="4" placeholder="默认会询问 1+1，可改成任意短句做连通性验证" />
          </el-form-item>
        </el-form>
        <div v-if="llmTestResult" class="llm-test-result">
          <el-alert v-if="llmTestResult.success" title="模型回复" type="success" :closable="false" show-icon>
            <pre class="llm-test-reply">{{ llmTestResult.reply }}</pre>
          </el-alert>
          <el-alert v-else :description="llmTestResult.error || '请求失败'" title="调用失败" type="error" :closable="false" show-icon />
        </div>
        <div slot="footer" class="dialog-footer">
          <el-button @click="llmTestDialogVisible = false">关 闭</el-button>
          <el-button type="primary" :loading="llmTestLoading" icon="el-icon-position" @click="submitLlmTest">发送测试</el-button>
        </div>
      </el-dialog>
    </el-card>
  </div>
</template>

<script>
import {
  listPromptTemplates,
  getPromptTemplate,
  savePromptTemplate,
  deletePromptTemplate,
  listLlmProfiles,
  getLlmProfile,
  createLlmProfile,
  updateLlmProfile,
  deleteLlmProfile,
  setActiveLlmProfile,
  clearActiveLlmProfile,
  resetAllLlmConfig,
  testLlmProfile
} from '@/api/jarvis/socialMediaPrompt'

export default {
  name: 'SocialMediaPromptConfig',
  data() {
    return {
      showHelp: false,
      activeTab: 'keywords',
      templates: {},
      saving: {},
      llmSummary: null,
      llmProfileRows: [],
      llmListLoading: false,
      llmDialogVisible: false,
      llmDialogEditId: null,
      llmForm: {
        name: '',
        mode: 'ollama',
        baseUrl: '',
        model: '',
        apiKeyInput: ''
      },
      llmHasApiKey: false,
      llmApiKeyMasked: null,
      llmClearApiKey: false,
      llmSaving: false,
      llmTestDialogVisible: false,
      llmTestRow: null,
      llmTestMessage: '1+1等于几？请只回答一个数字或最简结果，不要多余解释。',
      llmTestLoading: false,
      llmTestResult: null
    }
  },
  computed: {
    llmActiveName() {
      const r = this.llmProfileRows.find(p => p.active)
      return r ? r.name : ''
    }
  },
  mounted() {
    this.loadTemplates()
    this.loadLlmList()
  },
  methods: {
    /** 加载所有模板 */
    async loadTemplates() {
      try {
        const res = await listPromptTemplates()
        if (res.code === 200 && res.data) {
          this.templates = res.data
          // 初始化保存状态
          Object.keys(this.templates).forEach(key => {
            this.$set(this.saving, key, false)
          })
        } else {
          this.$message.error(res.msg || '加载模板失败')
        }
      } catch (error) {
        console.error('加载模板失败', error)
        this.$message.error('加载模板失败：' + (error.message || '未知错误'))
      }
    },

    /** 加载单个模板 */
    async handleLoadTemplate(key) {
      try {
        const res = await getPromptTemplate(key)
        if (res.code === 200 && res.data) {
          this.$set(this.templates, key, res.data)
          this.$message.success('重新加载成功')
        } else {
          this.$message.error(res.msg || '加载失败')
        }
      } catch (error) {
        console.error('加载模板失败', error)
        this.$message.error('加载失败：' + (error.message || '未知错误'))
      }
    },

    /** 保存模板 */
    async handleSaveTemplate(key) {
      const template = this.templates[key]
      if (!template || !template.template || template.template.trim() === '') {
        this.$message.warning('模板内容不能为空')
        return
      }

      this.$set(this.saving, key, true)
      try {
        const res = await savePromptTemplate({
          key: key,
          template: template.template.trim()
        })
        
        if (res.code === 200) {
          this.$message.success('保存成功！')
          // 更新状态
          this.$set(template, 'isDefault', false)
          // 重新加载以确认
          await this.handleLoadTemplate(key)
        } else {
          this.$message.error(res.msg || '保存失败')
        }
      } catch (error) {
        console.error('保存模板失败', error)
        this.$message.error('保存失败：' + (error.message || '未知错误'))
      } finally {
        this.$set(this.saving, key, false)
      }
    },

    /** 恢复默认模板 */
    async handleResetTemplate(key) {
      try {
        await this.$confirm('确定要恢复默认模板吗？自定义模板将被删除。', '提示', {
          type: 'warning'
        })
        
        const res = await deletePromptTemplate(key)
        if (res.code === 200) {
          this.$message.success('已恢复默认模板')
          // 重新加载
          await this.handleLoadTemplate(key)
        } else {
          this.$message.error(res.msg || '恢复失败')
        }
      } catch (error) {
        if (error !== 'cancel') {
          console.error('恢复默认模板失败', error)
          this.$message.error('恢复失败：' + (error.message || '未知错误'))
        }
      }
    },

    /** 获取模板标签 */
    getTemplateLabel(key) {
      const labels = {
        'keywords': '关键词提取',
        'content:xhs': '小红书文案',
        'content:douyin': '抖音文案',
        'content:both': '通用文案',
        'xianyu:wenan_base': '闲鱼·正文基础',
        'xianyu:jiaonixiadan_extra': '闲鱼·教你下单尾部',
        'xianyu:title_clean_regex': '闲鱼·标题清洗正则',
        'xianyu:seed_note_prompt': '闲鱼·种草文案提示词'
      }
      return labels[key] || key
    },

    async loadLlmList() {
      this.llmListLoading = true
      try {
        const res = await listLlmProfiles()
        if (res.code === 200 && res.data) {
          this.llmSummary = res.data
          this.llmProfileRows = Array.isArray(res.data.profiles) ? res.data.profiles : []
        } else {
          this.$message.error(res.msg || '加载大模型配置失败')
        }
      } catch (e) {
        console.error(e)
        this.$message.error('加载大模型配置失败：' + (e.message || '未知错误'))
      } finally {
        this.llmListLoading = false
      }
    },

    resetLlmDialogForm() {
      this.llmDialogEditId = null
      this.llmForm = {
        name: '',
        mode: 'ollama',
        baseUrl: '',
        model: '',
        apiKeyInput: ''
      }
      this.llmHasApiKey = false
      this.llmApiKeyMasked = null
      this.llmClearApiKey = false
    },

    async openLlmDialog(edit, row) {
      if (this.llmSummary && this.llmSummary.redisAvailable === false) {
        this.$message.warning('Redis 未配置，无法保存')
        return
      }
      this.resetLlmDialogForm()
      if (edit && row && row.id) {
        this.llmDialogEditId = row.id
        try {
          const res = await getLlmProfile(row.id)
          if (res.code !== 200 || !res.data) {
            this.$message.error(res.msg || '加载失败')
            return
          }
          const d = res.data
          this.llmForm.name = d.name || ''
          this.llmForm.mode = d.mode === 'openai' ? 'openai' : 'ollama'
          this.llmForm.baseUrl = d.baseUrl || ''
          this.llmForm.model = d.model || ''
          this.llmHasApiKey = !!d.hasApiKey
          this.llmApiKeyMasked = d.apiKeyMasked || null
        } catch (e) {
          console.error(e)
          this.$message.error('加载失败')
          return
        }
      }
      this.llmDialogVisible = true
    },

    async submitLlmDialog() {
      if (!this.llmForm.name || !this.llmForm.name.trim()) {
        this.$message.warning('请填写配置名称')
        return
      }
      if (this.llmForm.mode === 'openai') {
        if (!this.llmForm.baseUrl || !this.llmForm.baseUrl.trim()) {
          this.$message.warning('OpenAI 兼容须填写完整 API 地址')
          return
        }
        if (!this.llmForm.model || !this.llmForm.model.trim()) {
          this.$message.warning('OpenAI 兼容须填写模型名称')
          return
        }
      }
      const payload = {
        name: this.llmForm.name.trim(),
        mode: this.llmForm.mode,
        baseUrl: (this.llmForm.baseUrl || '').trim(),
        model: (this.llmForm.model || '').trim()
      }
      if (this.llmDialogEditId) {
        if (this.llmClearApiKey) {
          payload.clearApiKey = true
        } else if (this.llmForm.apiKeyInput && this.llmForm.apiKeyInput.trim()) {
          payload.apiKey = this.llmForm.apiKeyInput.trim()
        }
      } else if (this.llmForm.apiKeyInput && this.llmForm.apiKeyInput.trim()) {
        payload.apiKey = this.llmForm.apiKeyInput.trim()
      }
      this.llmSaving = true
      try {
        let res
        if (this.llmDialogEditId) {
          res = await updateLlmProfile(this.llmDialogEditId, payload)
        } else {
          res = await createLlmProfile(payload)
        }
        if (res.code === 200) {
          this.$message.success('保存成功')
          this.llmDialogVisible = false
          await this.loadLlmList()
        } else {
          this.$message.error(res.msg || '保存失败')
        }
      } catch (e) {
        console.error(e)
        this.$message.error('保存失败：' + (e.message || '未知错误'))
      } finally {
        this.llmSaving = false
      }
    },

    async handleActivateLlm(row) {
      try {
        const res = await setActiveLlmProfile(row.id)
        if (res.code === 200) {
          this.$message.success(res.msg || '已激活')
          await this.loadLlmList()
        } else {
          this.$message.error(res.msg || '操作失败')
        }
      } catch (e) {
        console.error(e)
        this.$message.error('操作失败：' + (e.message || '未知错误'))
      }
    },

    async handleDeleteLlm(row) {
      try {
        await this.$confirm(`确定删除配置「${row.name || row.id}」？`, '提示', { type: 'warning' })
        const res = await deleteLlmProfile(row.id)
        if (res.code === 200) {
          this.$message.success('已删除')
          await this.loadLlmList()
        } else {
          this.$message.error(res.msg || '删除失败')
        }
      } catch (e) {
        if (e !== 'cancel') {
          console.error(e)
          this.$message.error('删除失败：' + (e.message || '未知错误'))
        }
      }
    },

    async handleClearActiveLlm() {
      try {
        const res = await clearActiveLlmProfile()
        if (res.code === 200) {
          this.$message.success(res.msg || '已取消激活')
          await this.loadLlmList()
        } else {
          this.$message.error(res.msg || '操作失败')
        }
      } catch (e) {
        console.error(e)
        this.$message.error('操作失败：' + (e.message || '未知错误'))
      }
    },

    async handleResetAllLlm() {
      try {
        await this.$confirm('将删除所有大模型接入配置及旧版单键，Jarvis 恢复为默认 Ollama。是否继续？', '提示', { type: 'warning' })
        const res = await resetAllLlmConfig()
        if (res.code === 200) {
          this.$message.success(res.msg || '已清空')
          await this.loadLlmList()
        } else {
          this.$message.error(res.msg || '操作失败')
        }
      } catch (e) {
        if (e !== 'cancel') {
          console.error(e)
          this.$message.error('操作失败：' + (e.message || '未知错误'))
        }
      }
    },

    resetLlmTestDialog() {
      this.llmTestRow = null
      this.llmTestResult = null
      this.llmTestLoading = false
    },

    openLlmTest(row) {
      if (this.llmSummary && this.llmSummary.redisAvailable === false) {
        this.$message.warning('Redis 未配置时无法从后台写入多套参数；仍可直接测 Jarvis 默认，请确认 Jarvis 地址正确。')
      }
      this.llmTestRow = row || null
      this.llmTestMessage = '1+1等于几？请只回答一个数字或最简结果，不要多余解释。'
      this.llmTestResult = null
      this.llmTestDialogVisible = true
    },

    async submitLlmTest() {
      if (!this.llmTestMessage || !this.llmTestMessage.trim()) {
        this.$message.warning('请填写测试问题')
        return
      }
      const payload = { message: this.llmTestMessage.trim() }
      if (this.llmTestRow && this.llmTestRow.id) {
        payload.profileId = this.llmTestRow.id
      }
      this.llmTestLoading = true
      this.llmTestResult = null
      try {
        const res = await testLlmProfile(payload)
        if (res.code === 200 && res.data) {
          this.llmTestResult = {
            success: !!res.data.success,
            reply: res.data.reply,
            error: res.data.error
          }
          if (this.llmTestResult.success) {
            this.$message.success('测试完成')
          } else {
            this.$message.error(this.llmTestResult.error || '调用失败')
          }
        } else {
          this.$message.error(res.msg || '测试失败')
          this.llmTestResult = { success: false, error: res.msg || '未知错误' }
        }
      } catch (e) {
        console.error(e)
        this.$message.error('测试失败：' + (e.message || '未知错误'))
        this.llmTestResult = { success: false, error: e.message || '未知错误' }
      } finally {
        this.llmTestLoading = false
      }
    }
  }
}
</script>

<style scoped>
.prompt-config-container {
  padding: 20px;
}

.card-title {
  font-size: 18px;
  font-weight: bold;
}

.help-section {
  margin-bottom: 20px;
}

.help-section ul {
  margin: 10px 0;
  padding-left: 20px;
}

.help-section li {
  margin: 5px 0;
}

.template-list {
  margin-top: 20px;
}

.template-editor {
  padding: 20px;
}

.template-info {
  margin-bottom: 20px;
}

.template-status {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
}

.template-textarea {
  margin-bottom: 20px;
}

.template-textarea >>> .el-textarea__inner {
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 13px;
  line-height: 1.6;
}

.template-actions {
  text-align: right;
}

.template-actions .el-button {
  margin-left: 10px;
}

.llm-card .llm-form {
  max-width: 720px;
}

.llm-key-hint {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  color: #909399;
}

.llm-active-hint {
  margin-bottom: 12px;
  font-size: 14px;
}

.llm-toolbar-bottom {
  margin-top: 14px;
}

.llm-toolbar-bottom .el-button {
  margin-right: 10px;
}

.llm-del-btn {
  color: #f56c6c;
}

.llm-test-hint {
  margin: 0 0 12px 0;
  font-size: 13px;
  color: #606266;
  line-height: 1.5;
}

.llm-test-result {
  margin-top: 12px;
}

.llm-test-reply {
  margin: 8px 0 0 0;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 13px;
  line-height: 1.5;
}
</style>

