1. 10 Aug, 2025 12 commits
    • feat: enhance model billing aggregation & UI display for unknown quota type · 85ecfd70
      Summary
      -------
      1. **Backend**
         • `controller/model_meta.go`
           – For prefix/suffix/contains rules, aggregate endpoints, bound channels, enable groups, and quota types across all matched models.
           – When mixed billing types are detected, return `quota_type = -1` (unknown) instead of defaulting to volume-based.
      
      2. **Frontend**
         • `web/src/helpers/utils.js`
           – `calculateModelPrice` now handles `quota_type = -1`, returning placeholder `'-'`.
      
         • `web/src/components/table/model-pricing/view/card/PricingCardView.jsx`
           – Billing tag logic updated: displays “按次计费” (times), “按量计费” (volume), or `'-'` for unknown.
      
         • `web/src/components/table/model-pricing/view/table/PricingTableColumns.js`
           – `renderQuotaType` shows “未知” for unknown billing type.
      
         • `web/src/components/table/models/ModelsColumnDefs.js`
           – Unified `renderQuotaType` to return `'-'` when type is unknown.
      
         • `web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx`
           – Group price table honors unknown billing type; pricing columns show `'-'` and neutral tag color.
      
      3. **Utilities**
         • Added safe fallback colours/tags for unknown billing type across affected components.
      
      Impact
      ------
      • Ensures correct data aggregation for non-exact model matches.
      • Prevents UI from implying volume billing when actual type is ambiguous.
      • Provides consistent placeholder display (`'-'` or “未知”) across cards, tables and modals.
      
      No breaking API changes; frontend gracefully handles legacy values.
      t0ng7u committed
    • 🔠 refactor: refine group label formatting in price info · 2cabe4f6
      Summary:
      • Updated `helpers/utils.js` to display the “group” label without a colon, ensuring consistent typography with other price elements.
      
      Details:
      1. `formatPriceInfo`
         – Changed `{t('分组')}:` to `{t('分组')}` for a cleaner look.
         – Keeps spacing intact between label and selected group name.
      2. No functional impact; purely visual polish.
      t0ng7u committed
    • 📱 style: Hide vendor introduction on mobile devices · ca85d224
      Summary:
      • Updated `PricingTopSection.jsx` to conditionally render `PricingVendorIntroWithSkeleton` only when `isMobile` is false.
      
      Details:
      1. Wrapped vendor-intro block in `!isMobile` check, preventing unnecessary content on small screens.
      2. Kept desktop experience unchanged; no impact on other features.
      3. Lint check passed with no new issues.
      
      Result:
      Cleaner mobile UI with improved performance and visual focus.
      t0ng7u committed
    • feat: Add tag-based filtering & refactor filter counts logic · b6dd701c
      Overview:
      • Introduced a new “Model Tag” filter across pricing screens
      • Refactored `usePricingFilterCounts` to eliminate duplicated logic
      • Improved tag handling to be case-insensitive and deduplicated
      • Extended utilities to reset & persist the new filter
      
      Details:
      1. Added `filterTag` state to `useModelPricingData` and integrated it into all filtering paths.
      2. Created reusable `PricingTags` component using `SelectableButtonGroup`.
      3. Incorporated tag filter into `PricingSidebar` and mobile `PricingFilterModal`, including reset support.
      4. Enhanced `resetPricingFilters` (helpers/utils) to restore tag filter defaults.
      5. Refactored `usePricingFilterCounts.js`:
         • Centralized predicate `matchesFilters` to remove redundancy
         • Normalized tag parsing via `normalizeTags` helper
         • Memoized model subsets with concise filter calls
      6. Updated lints – zero errors after refactor.
      
      Result:
      Users can now filter models by custom tags with consistent UX, and internal logic is cleaner, faster, and easier to extend.
      t0ng7u committed
    • 🐛 fix(PricingCardView): hide placeholder dash when no custom tags · 7130ec8e
      Previously, the card view displayed a “-” whenever a model had no custom tags,
      because `renderLimitedItems` returned a dash for an empty array.
      Now the function is only invoked when `customTags.length > 0`, removing the
      unwanted placeholder and keeping the UI clean.
      
      File affected:
      - web/src/components/table/model-pricing/view/card/PricingCardView.jsx
      t0ng7u committed
    • fix: prevent model name flicker when closing SideSheet · c79b6cea
      - Delay clearing selectedModel until SideSheet close animation completes
      - Prevents brief display of 'AI/Unknown Model' text during closing transition
      - Improves user experience by eliminating visual flicker
      - Uses 300ms timeout matching Semi UI default animation duration
      t0ng7u committed
    • feat: Enhance EditChannelModal with JSONEditor key updates and input reset · 54f470bc
      - Added unique keys for JSONEditor components to ensure proper re-rendering based on channelId.
      - Implemented input reset to clear previous JSON field values when the modal is opened.
      CaIon committed
    • 🖼️ chore: format code file · 1ea54eb2
      t0ng7u committed
    • Merge pull request #1496 from Bliod-Cook/feat-linuxdo-minumum-trust-level · ac9a1ae8
      feat: allow admin to restrict the minimum linuxdo trust level to register
      Calcium-Ion committed
    • Merge pull request #1537 from RedwindA/feat/support-native-gemini-embedding · c59253ea
      feat: 支持原生Gemini Embedding格式
      Calcium-Ion committed
    • Merge pull request #1541 from QuantumNous/fluent-read · 571301ad
      feat: added "流畅阅读" (FluentRead) as a new chat provider option.
      Calcium-Ion committed
  2. 09 Aug, 2025 28 commits
    • feat: Add model icon support across backend and UI; prefer model icon over… · abee65c1
       feat: Add model icon support across backend and UI; prefer model icon over vendor; add icon column in Models table
      
      Backend:
      - Model: Add `icon` field to `model.Model` (gorm: varchar(128)); auto-migrated via GORM.
      - Pricing API: Extend `model.Pricing` with `icon` and populate from model meta in `GetPricing()`.
      
      Frontend:
      - EditModelModal: Add `icon` input (with @lobehub/icons helper link); wire into init/load/submit flows.
      - ModelHeader / PricingCardView: Prefer rendering `model.icon`; fallback to `vendor_icon`; final fallback to initials avatar.
      - Models table: Add leading “Icon” column, rendering `model.icon` or `vendor` icon via `getLobeHubIcon`.
      
      Notes:
      - Backward-compatible. Existing data without `icon` remain unaffected.
      - No manual SQL needed; column is added by AutoMigrate.
      
      Affected files:
      - model/model_meta.go
      - model/pricing.go
      - web/src/components/table/models/modals/EditModelModal.jsx
      - web/src/components/table/model-pricing/modal/components/ModelHeader.jsx
      - web/src/components/table/model-pricing/view/card/PricingCardView.jsx
      - web/src/components/table/models/ModelsColumnDefs.js
      t0ng7u committed
    • feat: Support dot‑chained props for LobeHub icons · 734ef7dd
      - render.js: Enhance getLobeHubIcon to parse dot‑chained props, e.g.:
        - OpenAI.Avatar.type={'platform'}
        - OpenRouter.Avatar.shape={'square'}
        - Parses booleans/numbers/strings and {…} wrappers; keeps the 2nd arg `size` unless overridden by chain props. Backward compatible.
      - EditVendorModal.jsx: Update UI copy — simplify placeholder; document chain‑parameter examples in extra text with doc link.
      - en.json: Fix invalid escape sequences in the new i18n string to satisfy linter.
      
      No behavioral changes outside icon rendering; lints pass.
      t0ng7u committed
    • 🍎 chore: modify pagination pageSizeOpts · 58af8ed6
      t0ng7u committed
    • 🎨 refactor: MultiKeyManageModal: cleaner stats UI, remove chart, integrate… · 8a310744
      🎨 refactor: MultiKeyManageModal: cleaner stats UI, remove chart, integrate toolbar/pagination, and improve UX
      
      - Replace custom dots with Semi Badge types (success/danger/warning); add compact Progress bars
      - Remove pie chart and related deps/config; move total key count and mode tags into the modal title
      - Rework header using Row/Col; three equal stat cards (enabled/manual-disabled/auto-disabled)
      - Integrate toolbar into Table title; wrap content with Card; use Table’s native empty state
      - Make “Enable All” conditional (hidden when all keys are enabled), mirroring “Disable All”
      - Unify numeric typography (current/total same size) for better readability
      - Default page size set to 10; fallback to 10 when backend page_size is absent; page-size options: 10/20/50/100
      - Cleanup imports and dead code (remove VChart and pie-spec logic)
      - Minor spacing polish (extra bottom margin before table), no footer buttons
      t0ng7u committed
    • 💄 style(ui): replace inline gradients with reusable pastel blur balls; improve dark mode · 2177620e
      - Introduce a global CSS utility `with-pastel-balls` in `web/src/index.css`, rendering pastel “blur balls” via ::before with CSS variables (`--pb1..--pb4`, `--pb-opacity`, `--pb-blur`) for easy theming.
      - Apply the utility to pricing header cards and skeletons:
        - `web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx`
        - `web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx`
      - Remove per-component inline `linear-gradient(...)` backgrounds and redundant absolute-positioned decoration nodes to reduce duplication.
      - Dark mode:
        - Keep the same pastel palette (pink/lavender/mint/peach).
        - Increase visibility with `--pb-opacity: 0.36`, `--pb-blur: 65px`, and `mix-blend-mode: screen`.
      - No functional logic changes; UI-only. Lint passes.
      
      Affected files:
      - web/src/index.css
      - web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx
      - web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx
      t0ng7u committed
    • feat: update dto for embeddings · f5a52bc5
      RedwindA committed
    • 🧹 Refactor: remove redundant code and simplify renderers · 2da040f7
      - Users table (UsersColumnDefs.js):
        - Remove unused quota calculations from the status renderer
        - Keep status Tag minimal; tooltip shows request count only
        - No functional changes
      
      - Tokens table (TokensColumnDefs.js):
        - Simplify chats menu parsing from localStorage; remove redundant flags/loops
        - Remove unused variables and console statements
        - Keep error handling via showError; preserve existing operations behavior
      
      - General:
        - Codebase tidying only; no UI/logic changes beyond cleanup
        - Lint passes successfully
      t0ng7u committed
    • style(ui): Replace switches with buttons; add quota column with Popover; cleanup · 2757d555
      - Tokens/Users tables:
        - Replaced status Switch with explicit Enable/Disable buttons in the operation column
        - Unified button styles with Channels/Models (Disable: danger + small; Enable: default + small)
        - Status column now shows a small Tag only; standardized labels (Enabled/Disabled/etc.); removed usage info
      
      - New "Remaining/Total Quota" column:
        - Wrapped in a white Tag; shows Remaining/Total with a progress bar
        - Replaced Tooltip with Popover; contents use Typography.Paragraph with copyable values
        - Copyable content excludes percentages (only numeric quota values are copied)
        - Added padding to Popover content for better readability
      
      - Tokens specifics:
        - For unlimited quota, show a white Tag "Unlimited quota" with a Popover that displays copyable "Used quota"
      
      - Cleanup:
        - Removed Switch imports/handlers and unused code paths
        - Eliminated console logs and redundant flags; simplified chats parsing
        - Removed quota calculations from status renderers
      
      Files:
      - web/src/components/table/tokens/TokensColumnDefs.js
      - web/src/components/table/users/UsersColumnDefs.js
      t0ng7u committed
    • 🐛 fix(db): allow re-adding models & vendors after soft delete; add safe index cleanup · 1dd1ef86
      Replace legacy single-column unique indexes with composite unique indexes on
      (name, deleted_at) and introduce a safe index drop utility to eliminate
      duplicate-key errors and noisy MySQL 1091 warnings.
      
      WHAT
      • model/model_meta.go
        - Model.ModelName  → `uniqueIndex:uk_model_name,priority:1`
        - Model.DeletedAt  → `index; uniqueIndex:uk_model_name,priority:2`
      • model/vendor_meta.go
        - Vendor.Name      → `uniqueIndex:uk_vendor_name,priority:1`
        - Vendor.DeletedAt → `index; uniqueIndex:uk_vendor_name,priority:2`
      • model/main.go
        - Add `dropIndexIfExists(table, index)`:
          • Checks `information_schema.statistics`
          • Drops index only when present (avoids Error 1091)
        - Invoke helper in `migrateDB` & `migrateDBFast`
        - Remove direct `ALTER TABLE … DROP INDEX …` calls
      
      WHY
      • Users received `Error 1062 (23000)` when re-creating a soft-deleted
        model/vendor because the old unique index enforced uniqueness on name alone.
      • Directly dropping nonexistent indexes caused MySQL `Error 1091` noise.
      
      HOW
      • Composite unique indexes `(model_name, deleted_at)` / `(name, deleted_at)`
        respect GORM soft deletes.
      • Safe helper ensures idempotent migrations across environments.
      
      RESULT
      • Users can now delete and re-add the same model or vendor without manual SQL.
      • Startup migration runs quietly across MySQL, PostgreSQL, and SQLite.
      • No behavior changes for existing data beyond index updates.
      
      TEST
      1. Add model “deepseek-chat” → delete (soft) → re-add → success.
      2. Add vendor “DeepSeek”     → delete (soft) → re-add → success.
      3. Restart service twice → no duplicate key or 1091 errors.
      t0ng7u committed
    • style(JSONEditor): add AGPL-3.0 license header, clean imports & refine Banner UI · 4886f86c
      * Added full GNU Affero General Public License v3 header at the top of `JSONEditor.js`.
      * Removed unused `IconCode` and `IconRefresh` imports to eliminate dead code.
      * Set `closeIcon={null}` and applied `!rounded-md` class for `Banner`, improving visual consistency and preventing unintended dismissal.
      * Normalized whitespace and line-breaks for better readability and lint compliance.
      t0ng7u committed
    • feat: optimized JSONEditor in duplicate key handling · a08e027b
      Merge pull request #1534 from HynoR/feat/je
      同語 committed
    • 🐛 fix(db): allow re-adding models/vendors after soft delete via composite unique indexes · e1796b92
      Ensure models and vendors can be re-created after soft deletion by switching to composite unique indexes on (name, deleted_at) and cleaning up legacy single-column unique indexes on MySQL.
      
      Why
      - MySQL raised 1062 duplicate key errors when re-adding a soft-deleted model/vendor because the legacy unique index enforced uniqueness on the name column alone (uk_model_name / uk_vendor_name), despite soft deletes.
      - Users encountered errors such as:
        - Error 1062 (23000): Duplicate entry 'deepseek-chat' for key 'models.uk_model_name'
        - Error 1062 (23000): Duplicate entry 'DeepSeek' for key 'vendors.uk_vendor_name'
      
      How
      - Model indices:
        - model/model_meta.go:
          - Model.ModelName → gorm: uniqueIndex:uk_model_name,priority:1
          - Model.DeletedAt → gorm: index; uniqueIndex:uk_model_name,priority:2
      - Vendor indices:
        - model/vendor_meta.go:
          - Vendor.Name → gorm: uniqueIndex:uk_vendor_name,priority:1
          - Vendor.DeletedAt → gorm: index; uniqueIndex:uk_vendor_name,priority:2
      - Migration (automatic, idempotent):
        - model/main.go (migrateDB, migrateDBFast):
          - On MySQL, drop legacy single-column unique indexes if present:
            - ALTER TABLE models DROP INDEX uk_model_name;
            - ALTER TABLE vendors DROP INDEX uk_vendor_name;
          - Then run AutoMigrate to create composite unique indexes.
        - Missing-index errors are ignored to keep the migration safe to run multiple times.
      
      Result
      - Users can delete and re-add the same model/vendor name without manual SQL.
      - Migration runs automatically at startup; no user action required.
      - PostgreSQL and SQLite remain unaffected.
      
      Files changed
      - model/model_meta.go
      - model/vendor_meta.go
      - model/main.go (migrateDB, migrateDBFast)
      
      Testing
      - Create model "deepseek-chat" → delete (soft) → re-create → succeeds.
      - Create vendor "DeepSeek" → delete (soft) → re-create → succeeds.
      
      Backward compatibility
      - Data remains intact; only index definitions are updated.
      - Behavior is unchanged except for fixing the uniqueness constraint with soft deletes.
      t0ng7u committed
    • Merge pull request #1500 from antecanis8/gemini_batchembedcontents · 2c4dc446
      fix: Gemini embedding model only embeds the first text in a batch
      Calcium-Ion committed