mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-12-10 02:05:56 +08:00
Compare commits
1 Commits
v0.6.8
...
patch/prox
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4703dfd97 |
@@ -1,4 +1,4 @@
|
|||||||
name: Publish Docker image (English)
|
name: Publish Docker image (amd64, English)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -34,13 +34,6 @@ jobs:
|
|||||||
- name: Translate
|
- name: Translate
|
||||||
run: |
|
run: |
|
||||||
python ./i18n/translate.py --repository_path . --json_file_path ./i18n/en.json
|
python ./i18n/translate.py --repository_path . --json_file_path ./i18n/en.json
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
@@ -58,7 +51,6 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
61
.github/workflows/docker-image-amd64.yml
vendored
Normal file
61
.github/workflows/docker-image-amd64.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
name: Publish Docker image (amd64)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
name:
|
||||||
|
description: 'reason'
|
||||||
|
required: false
|
||||||
|
jobs:
|
||||||
|
push_to_registries:
|
||||||
|
name: Push Docker image to multiple registries
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Check out the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Check repository URL
|
||||||
|
run: |
|
||||||
|
REPO_URL=$(git config --get remote.origin.url)
|
||||||
|
if [[ $REPO_URL == *"pro" ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Save version info
|
||||||
|
run: |
|
||||||
|
git describe --tags > VERSION
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to the Container registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
justsong/one-api
|
||||||
|
ghcr.io/${{ github.repository }}
|
||||||
|
|
||||||
|
- name: Build and push Docker images
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
name: Publish Docker image
|
name: Publish Docker image (arm64)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v*.*.*'
|
||||||
|
- '!*-alpha*'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM --platform=$BUILDPLATFORM node:16 AS builder
|
FROM node:16 as builder
|
||||||
|
|
||||||
WORKDIR /web
|
WORKDIR /web
|
||||||
COPY ./VERSION .
|
COPY ./VERSION .
|
||||||
|
|||||||
@@ -7,12 +7,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func GetRequestURL(meta *meta.Meta) (string, error) {
|
func GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
switch meta.Mode {
|
if meta.Mode == relaymode.ChatCompletions {
|
||||||
case relaymode.ChatCompletions:
|
|
||||||
return fmt.Sprintf("%s/api/v3/chat/completions", meta.BaseURL), nil
|
return fmt.Sprintf("%s/api/v3/chat/completions", meta.BaseURL), nil
|
||||||
case relaymode.Embeddings:
|
|
||||||
return fmt.Sprintf("%s/api/v3/embeddings", meta.BaseURL), nil
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("unsupported relay mode %d for doubao", meta.Mode)
|
return "", fmt.Errorf("unsupported relay mode %d for doubao", meta.Mode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ var ModelList = []string{
|
|||||||
"gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-0613",
|
"gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-0613",
|
||||||
"gpt-4-turbo-preview", "gpt-4-turbo", "gpt-4-turbo-2024-04-09",
|
"gpt-4-turbo-preview", "gpt-4-turbo", "gpt-4-turbo-2024-04-09",
|
||||||
"gpt-4o", "gpt-4o-2024-05-13",
|
"gpt-4o", "gpt-4o-2024-05-13",
|
||||||
"gpt-4o-mini", "gpt-4o-mini-2024-07-18",
|
|
||||||
"gpt-4-vision-preview",
|
"gpt-4-vision-preview",
|
||||||
"text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large",
|
"text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large",
|
||||||
"text-curie-001", "text-babbage-001", "text-ada-001", "text-davinci-002", "text-davinci-003",
|
"text-curie-001", "text-babbage-001", "text-ada-001", "text-davinci-002", "text-davinci-003",
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ func CountTokenMessages(messages []model.Message, model string) int {
|
|||||||
if imageUrl["detail"] != nil {
|
if imageUrl["detail"] != nil {
|
||||||
detail = imageUrl["detail"].(string)
|
detail = imageUrl["detail"].(string)
|
||||||
}
|
}
|
||||||
imageTokens, err := countImageTokens(url, detail, model)
|
imageTokens, err := countImageTokens(url, detail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.SysError("error counting image tokens: " + err.Error())
|
logger.SysError("error counting image tokens: " + err.Error())
|
||||||
} else {
|
} else {
|
||||||
@@ -134,15 +134,11 @@ const (
|
|||||||
lowDetailCost = 85
|
lowDetailCost = 85
|
||||||
highDetailCostPerTile = 170
|
highDetailCostPerTile = 170
|
||||||
additionalCost = 85
|
additionalCost = 85
|
||||||
// gpt-4o-mini cost higher than other model
|
|
||||||
gpt4oMiniLowDetailCost = 2833
|
|
||||||
gpt4oMiniHighDetailCost = 5667
|
|
||||||
gpt4oMiniAdditionalCost = 2833
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://platform.openai.com/docs/guides/vision/calculating-costs
|
// https://platform.openai.com/docs/guides/vision/calculating-costs
|
||||||
// https://github.com/openai/openai-cookbook/blob/05e3f9be4c7a2ae7ecf029a7c32065b024730ebe/examples/How_to_count_tokens_with_tiktoken.ipynb
|
// https://github.com/openai/openai-cookbook/blob/05e3f9be4c7a2ae7ecf029a7c32065b024730ebe/examples/How_to_count_tokens_with_tiktoken.ipynb
|
||||||
func countImageTokens(url string, detail string, model string) (_ int, err error) {
|
func countImageTokens(url string, detail string) (_ int, err error) {
|
||||||
var fetchSize = true
|
var fetchSize = true
|
||||||
var width, height int
|
var width, height int
|
||||||
// Reference: https://platform.openai.com/docs/guides/vision/low-or-high-fidelity-image-understanding
|
// Reference: https://platform.openai.com/docs/guides/vision/low-or-high-fidelity-image-understanding
|
||||||
@@ -176,9 +172,6 @@ func countImageTokens(url string, detail string, model string) (_ int, err error
|
|||||||
}
|
}
|
||||||
switch detail {
|
switch detail {
|
||||||
case "low":
|
case "low":
|
||||||
if strings.HasPrefix(model, "gpt-4o-mini") {
|
|
||||||
return gpt4oMiniLowDetailCost, nil
|
|
||||||
}
|
|
||||||
return lowDetailCost, nil
|
return lowDetailCost, nil
|
||||||
case "high":
|
case "high":
|
||||||
if fetchSize {
|
if fetchSize {
|
||||||
@@ -198,9 +191,6 @@ func countImageTokens(url string, detail string, model string) (_ int, err error
|
|||||||
height = int(float64(height) * ratio)
|
height = int(float64(height) * ratio)
|
||||||
}
|
}
|
||||||
numSquares := int(math.Ceil(float64(width)/512) * math.Ceil(float64(height)/512))
|
numSquares := int(math.Ceil(float64(width)/512) * math.Ceil(float64(height)/512))
|
||||||
if strings.HasPrefix(model, "gpt-4o-mini") {
|
|
||||||
return numSquares*gpt4oMiniHighDetailCost + gpt4oMiniAdditionalCost, nil
|
|
||||||
}
|
|
||||||
result := numSquares*highDetailCostPerTile + additionalCost
|
result := numSquares*highDetailCostPerTile + additionalCost
|
||||||
return result, nil
|
return result, nil
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -28,17 +28,15 @@ var ModelRatio = map[string]float64{
|
|||||||
"gpt-4-32k": 30,
|
"gpt-4-32k": 30,
|
||||||
"gpt-4-32k-0314": 30,
|
"gpt-4-32k-0314": 30,
|
||||||
"gpt-4-32k-0613": 30,
|
"gpt-4-32k-0613": 30,
|
||||||
"gpt-4-1106-preview": 5, // $0.01 / 1K tokens
|
"gpt-4-1106-preview": 5, // $0.01 / 1K tokens
|
||||||
"gpt-4-0125-preview": 5, // $0.01 / 1K tokens
|
"gpt-4-0125-preview": 5, // $0.01 / 1K tokens
|
||||||
"gpt-4-turbo-preview": 5, // $0.01 / 1K tokens
|
"gpt-4-turbo-preview": 5, // $0.01 / 1K tokens
|
||||||
"gpt-4-turbo": 5, // $0.01 / 1K tokens
|
"gpt-4-turbo": 5, // $0.01 / 1K tokens
|
||||||
"gpt-4-turbo-2024-04-09": 5, // $0.01 / 1K tokens
|
"gpt-4-turbo-2024-04-09": 5, // $0.01 / 1K tokens
|
||||||
"gpt-4o": 2.5, // $0.005 / 1K tokens
|
"gpt-4o": 2.5, // $0.005 / 1K tokens
|
||||||
"gpt-4o-2024-05-13": 2.5, // $0.005 / 1K tokens
|
"gpt-4o-2024-05-13": 2.5, // $0.005 / 1K tokens
|
||||||
"gpt-4o-mini": 0.075, // $0.00015 / 1K tokens
|
"gpt-4-vision-preview": 5, // $0.01 / 1K tokens
|
||||||
"gpt-4o-mini-2024-07-18": 0.075, // $0.00015 / 1K tokens
|
"gpt-3.5-turbo": 0.25, // $0.0005 / 1K tokens
|
||||||
"gpt-4-vision-preview": 5, // $0.01 / 1K tokens
|
|
||||||
"gpt-3.5-turbo": 0.25, // $0.0005 / 1K tokens
|
|
||||||
"gpt-3.5-turbo-0301": 0.75,
|
"gpt-3.5-turbo-0301": 0.75,
|
||||||
"gpt-3.5-turbo-0613": 0.75,
|
"gpt-3.5-turbo-0613": 0.75,
|
||||||
"gpt-3.5-turbo-16k": 1.5, // $0.003 / 1K tokens
|
"gpt-3.5-turbo-16k": 1.5, // $0.003 / 1K tokens
|
||||||
@@ -310,9 +308,6 @@ func GetCompletionRatio(name string, channelType int) float64 {
|
|||||||
return 4.0 / 3.0
|
return 4.0 / 3.0
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(name, "gpt-4") {
|
if strings.HasPrefix(name, "gpt-4") {
|
||||||
if strings.HasPrefix(name, "gpt-4o-mini") {
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(name, "gpt-4-turbo") ||
|
if strings.HasPrefix(name, "gpt-4-turbo") ||
|
||||||
strings.HasPrefix(name, "gpt-4o") ||
|
strings.HasPrefix(name, "gpt-4o") ||
|
||||||
strings.HasSuffix(name, "preview") {
|
strings.HasSuffix(name, "preview") {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/logger"
|
"github.com/songquanpeng/one-api/common/logger"
|
||||||
"github.com/songquanpeng/one-api/relay"
|
"github.com/songquanpeng/one-api/relay"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor"
|
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
||||||
"github.com/songquanpeng/one-api/relay/apitype"
|
"github.com/songquanpeng/one-api/relay/apitype"
|
||||||
"github.com/songquanpeng/one-api/relay/billing"
|
"github.com/songquanpeng/one-api/relay/billing"
|
||||||
@@ -32,8 +31,9 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
|
|||||||
meta.IsStream = textRequest.Stream
|
meta.IsStream = textRequest.Stream
|
||||||
|
|
||||||
// map model name
|
// map model name
|
||||||
|
var isModelMapped bool
|
||||||
meta.OriginModelName = textRequest.Model
|
meta.OriginModelName = textRequest.Model
|
||||||
textRequest.Model, _ = getMappedModelName(textRequest.Model, meta.ModelMapping)
|
textRequest.Model, isModelMapped = getMappedModelName(textRequest.Model, meta.ModelMapping)
|
||||||
meta.ActualModelName = textRequest.Model
|
meta.ActualModelName = textRequest.Model
|
||||||
// get model ratio & group ratio
|
// get model ratio & group ratio
|
||||||
modelRatio := billingratio.GetModelRatio(textRequest.Model, meta.ChannelType)
|
modelRatio := billingratio.GetModelRatio(textRequest.Model, meta.ChannelType)
|
||||||
@@ -55,9 +55,30 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
|
|||||||
adaptor.Init(meta)
|
adaptor.Init(meta)
|
||||||
|
|
||||||
// get request body
|
// get request body
|
||||||
requestBody, err := getRequestBody(c, meta, textRequest, adaptor)
|
var requestBody io.Reader
|
||||||
if err != nil {
|
if meta.APIType == apitype.OpenAI {
|
||||||
return openai.ErrorWrapper(err, "convert_request_failed", http.StatusInternalServerError)
|
// no need to convert request for openai
|
||||||
|
shouldResetRequestBody := isModelMapped || meta.ChannelType == channeltype.Baichuan // frequency_penalty 0 is not acceptable for baichuan
|
||||||
|
if shouldResetRequestBody {
|
||||||
|
jsonStr, err := json.Marshal(textRequest)
|
||||||
|
if err != nil {
|
||||||
|
return openai.ErrorWrapper(err, "json_marshal_failed", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
requestBody = bytes.NewBuffer(jsonStr)
|
||||||
|
} else {
|
||||||
|
requestBody = c.Request.Body
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
convertedRequest, err := adaptor.ConvertRequest(c, meta.Mode, textRequest)
|
||||||
|
if err != nil {
|
||||||
|
return openai.ErrorWrapper(err, "convert_request_failed", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
jsonData, err := json.Marshal(convertedRequest)
|
||||||
|
if err != nil {
|
||||||
|
return openai.ErrorWrapper(err, "json_marshal_failed", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
logger.Debugf(ctx, "converted request: \n%s", string(jsonData))
|
||||||
|
requestBody = bytes.NewBuffer(jsonData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do request
|
// do request
|
||||||
@@ -82,26 +103,3 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
|
|||||||
go postConsumeQuota(ctx, usage, meta, textRequest, ratio, preConsumedQuota, modelRatio, groupRatio)
|
go postConsumeQuota(ctx, usage, meta, textRequest, ratio, preConsumedQuota, modelRatio, groupRatio)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRequestBody(c *gin.Context, meta *meta.Meta, textRequest *model.GeneralOpenAIRequest, adaptor adaptor.Adaptor) (io.Reader, error) {
|
|
||||||
if meta.APIType == apitype.OpenAI && meta.OriginModelName == meta.ActualModelName && meta.ChannelType != channeltype.Baichuan {
|
|
||||||
// no need to convert request for openai
|
|
||||||
return c.Request.Body, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// get request body
|
|
||||||
var requestBody io.Reader
|
|
||||||
convertedRequest, err := adaptor.ConvertRequest(c, meta.Mode, textRequest)
|
|
||||||
if err != nil {
|
|
||||||
logger.Debugf(c.Request.Context(), "converted request failed: %s\n", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
jsonData, err := json.Marshal(convertedRequest)
|
|
||||||
if err != nil {
|
|
||||||
logger.Debugf(c.Request.Context(), "converted request json_marshal_failed: %s\n", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logger.Debugf(c.Request.Context(), "converted request: \n%s", string(jsonData))
|
|
||||||
requestBody = bytes.NewBuffer(jsonData)
|
|
||||||
return requestBody, nil
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user