Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
e129b3c
feat: implement privacy filter middleware and related settings
funkpopo Jun 8, 2026
957b8a8
fix: add missing go.mod and go.sum for privacy filter
funkpopo Jun 8, 2026
bdc1a1a
fix: correct path for copying go.sum in Dockerfile
funkpopo Jun 8, 2026
e7308b2
feat: add privacy-filter submodule configuration
funkpopo Jun 8, 2026
5f476fd
fix: update Docker image to use new privacy-enabled version
funkpopo Jun 8, 2026
4aac1dc
fix: update APT mirror URLs to use HTTP
funkpopo Jun 8, 2026
d5a28b0
fix: update Docker image for new-api to privacy version
funkpopo Jun 8, 2026
72d98be
fix: update Dockerfile to include NPM registry and APT mirrors
funkpopo Jun 8, 2026
e9f4464
feat: add privacy filter settings and UI components
funkpopo Jun 8, 2026
25b221d
Merge branch 'QuantumNous:main' into main
funkpopo Jun 11, 2026
b2f6803
Merge branch 'QuantumNous:main' into main
funkpopo Jun 15, 2026
daef113
refactor(privacy-filter): restructure privacy filter schema and updat…
funkpopo Jun 15, 2026
c67a06c
chore(submodule): add privacy-filter submodule with main branch
funkpopo Jun 15, 2026
e30fb11
Merge branch 'QuantumNous:main' into main
funkpopo Jun 17, 2026
e5d213e
feat(models): add unpriced models editor and related components
funkpopo Jun 17, 2026
98fe4f0
fix(api): handle response data correctly in model fetching functions
funkpopo Jun 17, 2026
cbfed86
fix(models): update model ratios handling and improve type safety
funkpopo Jun 17, 2026
49495a0
fix(models): enhance unpriced model card interaction and improve layo…
funkpopo Jun 17, 2026
308d9c6
Merge branch 'QuantumNous:main' into new-front-model-price-fix-clean
funkpopo Jun 17, 2026
9c7c5b7
Merge branch 'QuantumNous:main' into main
funkpopo Jun 17, 2026
850764a
Merge branch 'QuantumNous:main' into main
funkpopo Jun 17, 2026
d302e0b
Merge branch 'QuantumNous:main' into main
funkpopo Jun 17, 2026
9959d37
Merge pull request #1 from funkpopo/new-front-model-price-fix-clean
funkpopo Jun 17, 2026
87c7d22
fix(models): refactor UnpricedModelCard and UnpricedModelsEditor to u…
funkpopo Jun 17, 2026
d80c15f
fix(models): add label for search input in UnpricedModelsEditor for a…
funkpopo Jun 17, 2026
f2f7411
fix(i18n): add error messages for fetching current options and updati…
funkpopo Jun 17, 2026
4f8e48e
fix: remove privacy-filter subproject
funkpopo Jun 17, 2026
fa38f1d
fix(models): add return type annotation for UnpricedModelCard component
funkpopo Jun 17, 2026
0077326
fix: recover dockerfile.
funkpopo Jun 17, 2026
04f9f16
fix(models): remove return type annotation from UnpricedModelCard com…
funkpopo Jun 17, 2026
3179873
Merge branch 'QuantumNous:main' into new-front-model-price-fix-clean
funkpopo Jun 18, 2026
2d27aa3
Merge branch 'QuantumNous:main' into main
funkpopo Jun 18, 2026
3825c08
Merge branch 'main' into new-front-model-price-fix-clean
funkpopo Jun 18, 2026
ffe49a3
Merge branch 'main' into new-front-model-price-fix-clean
funkpopo Jun 19, 2026
17a0516
Merge branch 'QuantumNous:main' into new-front-model-price-fix-clean
funkpopo Jun 20, 2026
3a1aec3
Merge branch 'main' into new-front-model-price-fix-clean
funkpopo Jun 22, 2026
3be0a08
feat(i18n): add success message for model removal in multiple languages
funkpopo Jun 22, 2026
c78c23e
fix: Add localization updates for Japanese, Russian, Vietnamese, and …
funkpopo Jun 22, 2026
f733011
Merge branch 'QuantumNous:main' into new-front-model-price-fix-clean
funkpopo Jun 22, 2026
502bb54
Merge branch 'main' into new-front-model-price-fix-clean
funkpopo Jun 23, 2026
d632cd1
chore: remove privacy-filter subproject
funkpopo Jun 23, 2026
4137d43
Remove Privacy Filter functionality and related settings
funkpopo Jun 23, 2026
324cf73
Merge branch 'QuantumNous:main' into new-front-model-price-fix-clean
funkpopo Jun 23, 2026
b1cba79
Merge branch 'main' into new-front-model-price-fix-clean
funkpopo Jun 24, 2026
01ec4bf
Merge branch 'main' into new-front-model-price-fix-clean
funkpopo Jun 26, 2026
3a562ab
Merge branch 'QuantumNous:main' into new-front-model-price-fix-clean
funkpopo Jun 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "privacy-filter"]
path = privacy-filter
url = https://github.com/funkpopo/privacy-filter.git
branch = main
32 changes: 28 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,27 +1,39 @@
FROM oven/bun:1@sha256:0733e50325078969732ebe3b15ce4c4be5082f18c4ac1a0f0ca4839c2e4e42a7 AS builder

ARG NPM_REGISTRY=https://registry.npmmirror.com

WORKDIR /build/web
COPY web/package.json web/bun.lock ./
COPY web/default/package.json ./default/package.json
COPY web/classic/package.json ./classic/package.json
RUN bun install --frozen-lockfile
RUN bun install --frozen-lockfile --registry "$NPM_REGISTRY"
COPY ./web/default ./default
COPY ./VERSION /build/VERSION
RUN cd default && DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat /build/VERSION) bun run build
RUN cd default && \
rm -rf dist node_modules/.cache .rsbuild .rspack-cache && \
DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat /build/VERSION) bun run build && \
find dist/static/js -maxdepth 1 -type f -name 'index.*.js' -print

FROM oven/bun:1@sha256:0733e50325078969732ebe3b15ce4c4be5082f18c4ac1a0f0ca4839c2e4e42a7 AS builder-classic

ARG NPM_REGISTRY=https://registry.npmmirror.com

WORKDIR /build/web
COPY web/package.json web/bun.lock ./
COPY web/default/package.json ./default/package.json
COPY web/classic/package.json ./classic/package.json
RUN bun install --filter ./classic --frozen-lockfile
COPY ./web/classic ./classic
COPY ./VERSION /build/VERSION
RUN cd classic && VITE_REACT_APP_VERSION=$(cat /build/VERSION) bun run build
RUN cd classic && \
rm -rf dist node_modules/.cache .rsbuild .rspack-cache && \
VITE_REACT_APP_VERSION=$(cat /build/VERSION) bun run build

FROM golang:1.26.1-alpine@sha256:2389ebfa5b7f43eeafbd6be0c3700cc46690ef842ad962f6c5bd6be49ed82039 AS builder2
ENV GO111MODULE=on CGO_ENABLED=0
ARG GOPROXY=https://goproxy.cn,direct
ARG GOSUMDB=sum.golang.google.cn
ENV GOPROXY=${GOPROXY} GOSUMDB=${GOSUMDB}

ARG TARGETOS
ARG TARGETARCH
Expand All @@ -34,13 +46,25 @@ ADD go.mod go.sum ./
RUN go mod download

COPY . .
RUN rm -rf ./web/default/dist ./web/classic/dist
COPY --from=builder /build/web/default/dist ./web/default/dist
COPY --from=builder-classic /build/web/classic/dist ./web/classic/dist
RUN go build -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$(cat VERSION)'" -o new-api

FROM debian:bookworm-slim@sha256:f06537653ac770703bc45b4b113475bd402f451e85223f0f2837acbf89ab020a

RUN apt-get update \
ARG APT_MIRROR=http://mirrors.tuna.tsinghua.edu.cn/debian
ARG APT_SECURITY_MIRROR=http://mirrors.tuna.tsinghua.edu.cn/debian-security

RUN set -eux; \
files="$(find /etc/apt -type f \( -name '*.sources' -o -name 'sources.list' \))"; \
sed -i \
-e "s#http://deb.debian.org/debian-security#${APT_SECURITY_MIRROR}#g" \
-e "s#http://security.debian.org/debian-security#${APT_SECURITY_MIRROR}#g" \
-e "s#http://deb.debian.org/debian#${APT_MIRROR}#g" \
-e "s#http://security.debian.org/debian#${APT_MIRROR}#g" \
$files; \
apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates tzdata libasan8 wget \
&& rm -rf /var/lib/apt/lists/* \
&& update-ca-certificates
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ version: '3.4' # For compatibility with older Docker versions

services:
new-api:
image: calciumion/new-api:latest
image: funpp/new-api-privacy:latest
container_name: new-api
restart: always
command: --log-dir /app/logs
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/arch v0.21.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
google.golang.org/protobuf v1.36.5 // indirect
google.golang.org/protobuf v1.36.11 // indirect
modernc.org/libc v1.66.10 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,6 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Calcium-Ion/go-epay v0.0.4 h1:C96M7WfRLadcIVscWzwLiYs8etI1wrDmtFMuK2zP22A=
github.com/Calcium-Ion/go-epay v0.0.4/go.mod h1:cxo/ZOg8ClvE3VAnCmEzbuyAZINSq7kFEN9oHj5WQ2U=
Expand Down Expand Up @@ -2966,8 +2964,8 @@ google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const BILLING_SECTIONS = [
modelDefaults={getModelDefaults(settings)}
groupDefaults={getGroupDefaults(settings)}
toolPricesDefault={settings['tool_price_setting.prices']}
visibleTabs={['models', 'tool-prices', 'upstream-sync']}
visibleTabs={['models', 'unpriced-models', 'tool-prices', 'upstream-sync']}
/>
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,17 +203,15 @@ export const ModelRatioForm = memo(function ModelRatioForm({
<RotateCcw data-icon='inline-start' />
{t('Reset prices')}
</Button>
{editMode === 'json' && (
<Button
type='button'
size='sm'
onClick={handleSave}
disabled={isSaving}
>
<Save data-icon='inline-start' />
{isSaving ? t('Saving...') : t('Save model prices')}
</Button>
)}
<Button
type='button'
size='sm'
onClick={handleSave}
disabled={isSaving}
>
<Save data-icon='inline-start' />
{isSaving ? t('Saving...') : t('Save model prices')}
</Button>
<Button variant='outline' size='sm' onClick={toggleEditMode}>
{editMode === 'visual' ? (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,9 @@ const ModelRatioVisualEditorComponent = forwardRef<
JSON.stringify(billingExprMap, null, 2)
)

if (editData?.name === name) {
setEditData(null)
setEditorOpen(false)
setSheetOpen(false)
}
toast.success(
t('Model {{name}} removed. Click Save to apply changes.', { name })
)
},
[
modelPrice,
Expand All @@ -412,7 +410,7 @@ const ModelRatioVisualEditorComponent = forwardRef<
billingMode,
billingExpr,
onChange,
editData,
t,
]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { useUpdateOption } from '../hooks/use-update-option'
import { GroupRatioForm } from './group-ratio-form'
import { ModelRatioForm } from './model-ratio-form'
import { ToolPriceSettings } from './tool-price-settings'
import { UnpricedModelsEditor } from './unpriced-models-editor'
import { UpstreamRatioSync } from './upstream-ratio-sync'
import {
formatJsonForTextarea,
Expand Down Expand Up @@ -128,7 +129,12 @@ const createGroupSchema = (t: Translate) =>

type ModelFormValues = z.infer<ReturnType<typeof createModelSchema>>
type GroupFormValues = z.infer<ReturnType<typeof createGroupSchema>>
type RatioTabId = 'models' | 'groups' | 'tool-prices' | 'upstream-sync'
type RatioTabId =
| 'models'
| 'groups'
| 'unpriced-models'
| 'tool-prices'
| 'upstream-sync'

type RatioSettingsCardProps = {
modelDefaults: ModelFormValues
Expand All @@ -143,7 +149,13 @@ export function RatioSettingsCard({
groupDefaults,
toolPricesDefault,
titleKey = 'Pricing Ratios',
visibleTabs = ['models', 'groups', 'tool-prices', 'upstream-sync'],
visibleTabs = [
'models',
'groups',
'unpriced-models',
'tool-prices',
'upstream-sync',
],
}: RatioSettingsCardProps) {
const { t } = useTranslation()
const updateOption = useUpdateOption()
Expand Down Expand Up @@ -385,6 +397,7 @@ export function RatioSettingsCard({
const tabLabels: Record<RatioTabId, string> = {
models: 'Model prices',
groups: 'Group ratios',
'unpriced-models': 'Unpriced models',
'tool-prices': 'Tool prices',
'upstream-sync': 'Upstream price sync',
}
Expand All @@ -394,7 +407,8 @@ export function RatioSettingsCard({
2: 'grid-cols-2',
3: 'grid-cols-3',
4: 'grid-cols-4',
}[visibleTabs.length] ?? 'grid-cols-4'
5: 'grid-cols-5',
}[visibleTabs.length] ?? 'grid-cols-5'
const defaultTab = visibleTabs[0] ?? 'models'

const renderTabContent = (tab: RatioTabId) => {
Expand All @@ -419,6 +433,24 @@ export function RatioSettingsCard({
/>
)
}
if (tab === 'unpriced-models') {
return (
<UnpricedModelsEditor
modelRatios={{
ModelPrice: modelDefaults.ModelPrice,
ModelRatio: modelDefaults.ModelRatio,
CompletionRatio: modelDefaults.CompletionRatio,
CacheRatio: modelDefaults.CacheRatio,
CreateCacheRatio: modelDefaults.CreateCacheRatio,
ImageRatio: modelDefaults.ImageRatio,
AudioRatio: modelDefaults.AudioRatio,
AudioCompletionRatio: modelDefaults.AudioCompletionRatio,
'billing_setting.billing_mode': modelDefaults.BillingMode,
'billing_setting.billing_expr': modelDefaults.BillingExpr,
}}
/>
)
}
if (tab === 'tool-prices') {
return <ToolPriceSettings defaultValue={toolPricesDefault} />
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
Copyright (C) 2023-2026 QuantumNous

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

For commercial licensing, please contact support@quantumnous.com
*/
import { Edit } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'

type UnpricedModelCardProps = {
modelName: string
active?: boolean
onEdit: () => void
}

export function UnpricedModelCard({
modelName,
active = false,
onEdit,
}: UnpricedModelCardProps) {
const { t } = useTranslation()

return (
<Card
className={cn(
'hover:border-primary/50 transition-colors',
active && 'border-primary/50 bg-muted/45'
)}
>
<CardContent
className='flex cursor-pointer items-center justify-between gap-3 p-4'
onClick={onEdit}
onKeyDown={(event) => {
if (event.target !== event.currentTarget) return
if (event.key !== 'Enter' && event.key !== ' ') return

event.preventDefault()
onEdit()
}}
role='button'
tabIndex={0}
aria-pressed={active}
>
<div className='min-w-0 flex-1'>
<h4 className='truncate text-sm font-medium'>{modelName}</h4>
<p className='text-muted-foreground text-xs'>{t('Price not set')}</p>
</div>
<Button
size='sm'
variant='outline'
onClick={(event) => {
event.stopPropagation()
onEdit()
}}
className='shrink-0'
>
<Edit className='size-3.5' />
<span className='sr-only sm:not-sr-only sm:ml-1.5'>
{t('Set price')}
</span>
</Button>
</CardContent>
</Card>
)
}
Loading