mirror of
				https://github.com/linux-do/new-api.git
				synced 2025-11-04 13:23:42 +08:00 
			
		
		
		
	feat: 增加重置模型倍率功能 (close #62)
This commit is contained in:
		@@ -20,9 +20,11 @@ const (
 | 
			
		||||
// 1 === $0.002 / 1K tokens
 | 
			
		||||
// 1 === ¥0.014 / 1k tokens
 | 
			
		||||
 | 
			
		||||
var DefaultModelRatio = map[string]float64{
 | 
			
		||||
var defaultModelRatio = map[string]float64{
 | 
			
		||||
	//"midjourney":                50,
 | 
			
		||||
	"gpt-4-gizmo-*": 15,
 | 
			
		||||
	"gpt-4-all":     15,
 | 
			
		||||
	"gpt-4o-all":    15,
 | 
			
		||||
	"gpt-4":         15,
 | 
			
		||||
	//"gpt-4-0314":                   15, //deprecated
 | 
			
		||||
	"gpt-4-0613": 15,
 | 
			
		||||
@@ -149,7 +151,7 @@ var DefaultModelRatio = map[string]float64{
 | 
			
		||||
	"llama-3-sonar-large-32k-online": 1 / 1000 * USD,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var DefaultModelPrice = map[string]float64{
 | 
			
		||||
var defaultModelPrice = map[string]float64{
 | 
			
		||||
	"dall-e-3":          0.04,
 | 
			
		||||
	"gpt-4-gizmo-*":     0.1,
 | 
			
		||||
	"mj_imagine":        0.1,
 | 
			
		||||
@@ -173,14 +175,14 @@ var modelPrice map[string]float64 = nil
 | 
			
		||||
var modelRatio map[string]float64 = nil
 | 
			
		||||
 | 
			
		||||
var CompletionRatio map[string]float64 = nil
 | 
			
		||||
var DefaultCompletionRatio = map[string]float64{
 | 
			
		||||
var defaultCompletionRatio = map[string]float64{
 | 
			
		||||
	"gpt-4-gizmo-*": 2,
 | 
			
		||||
	"gpt-4-all":     2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ModelPrice2JSONString() string {
 | 
			
		||||
	if modelPrice == nil {
 | 
			
		||||
		modelPrice = DefaultModelPrice
 | 
			
		||||
		modelPrice = defaultModelPrice
 | 
			
		||||
	}
 | 
			
		||||
	jsonBytes, err := json.Marshal(modelPrice)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -197,7 +199,7 @@ func UpdateModelPriceByJSONString(jsonStr string) error {
 | 
			
		||||
// GetModelPrice 返回模型的价格,如果模型不存在则返回-1,false
 | 
			
		||||
func GetModelPrice(name string, printErr bool) (float64, bool) {
 | 
			
		||||
	if modelPrice == nil {
 | 
			
		||||
		modelPrice = DefaultModelPrice
 | 
			
		||||
		modelPrice = defaultModelPrice
 | 
			
		||||
	}
 | 
			
		||||
	if strings.HasPrefix(name, "gpt-4-gizmo") {
 | 
			
		||||
		name = "gpt-4-gizmo-*"
 | 
			
		||||
@@ -212,16 +214,16 @@ func GetModelPrice(name string, printErr bool) (float64, bool) {
 | 
			
		||||
	return price, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetModelPrices() map[string]float64 {
 | 
			
		||||
func GetModelPriceMap() map[string]float64 {
 | 
			
		||||
	if modelPrice == nil {
 | 
			
		||||
		modelPrice = DefaultModelPrice
 | 
			
		||||
		modelPrice = defaultModelPrice
 | 
			
		||||
	}
 | 
			
		||||
	return modelPrice
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ModelRatio2JSONString() string {
 | 
			
		||||
	if modelRatio == nil {
 | 
			
		||||
		modelRatio = DefaultModelRatio
 | 
			
		||||
		modelRatio = defaultModelRatio
 | 
			
		||||
	}
 | 
			
		||||
	jsonBytes, err := json.Marshal(modelRatio)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -237,7 +239,7 @@ func UpdateModelRatioByJSONString(jsonStr string) error {
 | 
			
		||||
 | 
			
		||||
func GetModelRatio(name string) float64 {
 | 
			
		||||
	if modelRatio == nil {
 | 
			
		||||
		modelRatio = DefaultModelRatio
 | 
			
		||||
		modelRatio = defaultModelRatio
 | 
			
		||||
	}
 | 
			
		||||
	if strings.HasPrefix(name, "gpt-4-gizmo") {
 | 
			
		||||
		name = "gpt-4-gizmo-*"
 | 
			
		||||
@@ -250,16 +252,21 @@ func GetModelRatio(name string) float64 {
 | 
			
		||||
	return ratio
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetModelRatios() map[string]float64 {
 | 
			
		||||
	if modelRatio == nil {
 | 
			
		||||
		modelRatio = DefaultModelRatio
 | 
			
		||||
func DefaultModelRatio2JSONString() string {
 | 
			
		||||
	jsonBytes, err := json.Marshal(defaultModelRatio)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		SysError("error marshalling model ratio: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return modelRatio
 | 
			
		||||
	return string(jsonBytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetDefaultModelRatioMap() map[string]float64 {
 | 
			
		||||
	return defaultModelRatio
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CompletionRatio2JSONString() string {
 | 
			
		||||
	if CompletionRatio == nil {
 | 
			
		||||
		CompletionRatio = DefaultCompletionRatio
 | 
			
		||||
		CompletionRatio = defaultCompletionRatio
 | 
			
		||||
	}
 | 
			
		||||
	jsonBytes, err := json.Marshal(CompletionRatio)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -343,9 +350,9 @@ func GetCompletionRatio(name string) float64 {
 | 
			
		||||
	return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetCompletionRatios() map[string]float64 {
 | 
			
		||||
func GetCompletionRatioMap() map[string]float64 {
 | 
			
		||||
	if CompletionRatio == nil {
 | 
			
		||||
		CompletionRatio = DefaultCompletionRatio
 | 
			
		||||
		CompletionRatio = defaultCompletionRatio
 | 
			
		||||
	}
 | 
			
		||||
	return CompletionRatio
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -200,19 +200,3 @@ func RetrieveModel(c *gin.Context) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetPricing(c *gin.Context) {
 | 
			
		||||
	userId := c.GetInt("id")
 | 
			
		||||
	// if no login, get default group ratio
 | 
			
		||||
	groupRatio := common.GetGroupRatio("default")
 | 
			
		||||
	group, err := model.CacheGetUserGroup(userId)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		groupRatio = common.GetGroupRatio(group)
 | 
			
		||||
	}
 | 
			
		||||
	pricing := model.GetPricing(group)
 | 
			
		||||
	c.JSON(200, gin.H{
 | 
			
		||||
		"success":     true,
 | 
			
		||||
		"data":        pricing,
 | 
			
		||||
		"group_ratio": groupRatio,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								controller/pricing.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								controller/pricing.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
package controller
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"one-api/common"
 | 
			
		||||
	"one-api/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func GetPricing(c *gin.Context) {
 | 
			
		||||
	userId := c.GetInt("id")
 | 
			
		||||
	// if no login, get default group ratio
 | 
			
		||||
	groupRatio := common.GetGroupRatio("default")
 | 
			
		||||
	group, err := model.CacheGetUserGroup(userId)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		groupRatio = common.GetGroupRatio(group)
 | 
			
		||||
	}
 | 
			
		||||
	pricing := model.GetPricing(group)
 | 
			
		||||
	c.JSON(200, gin.H{
 | 
			
		||||
		"success":     true,
 | 
			
		||||
		"data":        pricing,
 | 
			
		||||
		"group_ratio": groupRatio,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ResetModelRatio(c *gin.Context) {
 | 
			
		||||
	defaultStr := common.DefaultModelRatio2JSONString()
 | 
			
		||||
	err := model.UpdateOption("ModelRatio", defaultStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(200, gin.H{
 | 
			
		||||
			"success": false,
 | 
			
		||||
			"message": err.Error(),
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = common.UpdateModelRatioByJSONString(defaultStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(200, gin.H{
 | 
			
		||||
			"success": false,
 | 
			
		||||
			"message": err.Error(),
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.JSON(200, gin.H{
 | 
			
		||||
		"success": true,
 | 
			
		||||
		"message": "重置模型倍率成功",
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -158,7 +158,7 @@ func RelaySwapFace(c *gin.Context) *dto.MidjourneyResponse {
 | 
			
		||||
	modelPrice, success := common.GetModelPrice(modelName, true)
 | 
			
		||||
	// 如果没有配置价格,则使用默认价格
 | 
			
		||||
	if !success {
 | 
			
		||||
		defaultPrice, ok := common.DefaultModelPrice[modelName]
 | 
			
		||||
		defaultPrice, ok := common.GetDefaultModelRatioMap()[modelName]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			modelPrice = 0.1
 | 
			
		||||
		} else {
 | 
			
		||||
@@ -457,7 +457,7 @@ func RelayMidjourneySubmit(c *gin.Context, relayMode int) *dto.MidjourneyRespons
 | 
			
		||||
	modelPrice, success := common.GetModelPrice(modelName, true)
 | 
			
		||||
	// 如果没有配置价格,则使用默认价格
 | 
			
		||||
	if !success {
 | 
			
		||||
		defaultPrice, ok := common.DefaultModelPrice[modelName]
 | 
			
		||||
		defaultPrice, ok := common.GetDefaultModelRatioMap()[modelName]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			modelPrice = 0.1
 | 
			
		||||
		} else {
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,7 @@ func SetApiRouter(router *gin.Engine) {
 | 
			
		||||
		{
 | 
			
		||||
			optionRoute.GET("/", controller.GetOptions)
 | 
			
		||||
			optionRoute.PUT("/", controller.UpdateOption)
 | 
			
		||||
			optionRoute.POST("/rest_model_ratio", controller.ResetModelRatio)
 | 
			
		||||
		}
 | 
			
		||||
		channelRoute := apiRouter.Group("/channel")
 | 
			
		||||
		channelRoute.Use(middleware.AdminAuth())
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ func InitTokenEncoders() {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		common.FatalLog(fmt.Sprintf("failed to get gpt-4 token encoder: %s", err.Error()))
 | 
			
		||||
	}
 | 
			
		||||
	for model, _ := range common.DefaultModelRatio {
 | 
			
		||||
	for model, _ := range common.GetDefaultModelRatioMap() {
 | 
			
		||||
		if strings.HasPrefix(model, "gpt-3.5") {
 | 
			
		||||
			tokenEncoderMap[model] = gpt35TokenEncoder
 | 
			
		||||
		} else if strings.HasPrefix(model, "gpt-4") {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2533
									
								
								web/pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2533
									
								
								web/pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -212,6 +212,16 @@ export const verifyJSON = (str) => {
 | 
			
		||||
  return true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function verifyJSONPromise(value) {
 | 
			
		||||
  try {
 | 
			
		||||
    JSON.parse(value);
 | 
			
		||||
    return Promise.resolve();
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    return Promise.reject('不是合法的 JSON 字符串');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export function shouldShowPrompt(id) {
 | 
			
		||||
  let prompt = localStorage.getItem(`prompt-${id}`);
 | 
			
		||||
  return !prompt;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import React, { useEffect, useState, useRef } from 'react';
 | 
			
		||||
import { Button, Col, Form, Row, Spin } from '@douyinfe/semi-ui';
 | 
			
		||||
import { Button, Col, Form, Popconfirm, Row, Space, Spin } from '@douyinfe/semi-ui';
 | 
			
		||||
import {
 | 
			
		||||
  compareObjects,
 | 
			
		||||
  API,
 | 
			
		||||
@@ -7,6 +7,7 @@ import {
 | 
			
		||||
  showSuccess,
 | 
			
		||||
  showWarning,
 | 
			
		||||
  verifyJSON,
 | 
			
		||||
  verifyJSONPromise
 | 
			
		||||
} from '../../../helpers';
 | 
			
		||||
 | 
			
		||||
export default function SettingsMagnification(props) {
 | 
			
		||||
@@ -15,50 +16,70 @@ export default function SettingsMagnification(props) {
 | 
			
		||||
    ModelPrice: '',
 | 
			
		||||
    ModelRatio: '',
 | 
			
		||||
    CompletionRatio: '',
 | 
			
		||||
    GroupRatio: '',
 | 
			
		||||
    GroupRatio: ''
 | 
			
		||||
  });
 | 
			
		||||
  const refForm = useRef();
 | 
			
		||||
  const [inputsRow, setInputsRow] = useState(inputs);
 | 
			
		||||
 | 
			
		||||
  async function onSubmit() {
 | 
			
		||||
    try {
 | 
			
		||||
      await refForm.current.validate();
 | 
			
		||||
      const updateArray = compareObjects(inputs, inputsRow);
 | 
			
		||||
      if (!updateArray.length) return showWarning('你似乎并没有修改什么');
 | 
			
		||||
      const requestQueue = updateArray.map((item) => {
 | 
			
		||||
        let value = '';
 | 
			
		||||
        if (typeof inputs[item.key] === 'boolean') {
 | 
			
		||||
          value = String(inputs[item.key]);
 | 
			
		||||
        } else {
 | 
			
		||||
          value = inputs[item.key];
 | 
			
		||||
        }
 | 
			
		||||
        return API.put('/api/option/', {
 | 
			
		||||
          key: item.key,
 | 
			
		||||
          value,
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      setLoading(true);
 | 
			
		||||
      Promise.all(requestQueue)
 | 
			
		||||
        .then((res) => {
 | 
			
		||||
          if (requestQueue.length === 1) {
 | 
			
		||||
            if (res.includes(undefined)) return;
 | 
			
		||||
          } else if (requestQueue.length > 1) {
 | 
			
		||||
            if (res.includes(undefined))
 | 
			
		||||
              return showError('部分保存失败,请重试');
 | 
			
		||||
      console.log('Starting validation...');
 | 
			
		||||
      await refForm.current.validate().then(() => {
 | 
			
		||||
        console.log('Validation passed');
 | 
			
		||||
        const updateArray = compareObjects(inputs, inputsRow);
 | 
			
		||||
        if (!updateArray.length) return showWarning('你似乎并没有修改什么');
 | 
			
		||||
        const requestQueue = updateArray.map((item) => {
 | 
			
		||||
          let value = '';
 | 
			
		||||
          if (typeof inputs[item.key] === 'boolean') {
 | 
			
		||||
            value = String(inputs[item.key]);
 | 
			
		||||
          } else {
 | 
			
		||||
            value = inputs[item.key];
 | 
			
		||||
          }
 | 
			
		||||
          showSuccess('保存成功');
 | 
			
		||||
          props.refresh();
 | 
			
		||||
        })
 | 
			
		||||
        .catch(() => {
 | 
			
		||||
          showError('保存失败,请重试');
 | 
			
		||||
        })
 | 
			
		||||
        .finally(() => {
 | 
			
		||||
          setLoading(false);
 | 
			
		||||
          return API.put('/api/option/', {
 | 
			
		||||
            key: item.key,
 | 
			
		||||
            value
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
        setLoading(true);
 | 
			
		||||
        Promise.all(requestQueue)
 | 
			
		||||
          .then((res) => {
 | 
			
		||||
            if (requestQueue.length === 1) {
 | 
			
		||||
              if (res.includes(undefined)) return;
 | 
			
		||||
            } else if (requestQueue.length > 1) {
 | 
			
		||||
              if (res.includes(undefined))
 | 
			
		||||
                return showError('部分保存失败,请重试');
 | 
			
		||||
            }
 | 
			
		||||
            showSuccess('保存成功');
 | 
			
		||||
            props.refresh();
 | 
			
		||||
          })
 | 
			
		||||
          .catch(() => {
 | 
			
		||||
            showError('保存失败,请重试');
 | 
			
		||||
          })
 | 
			
		||||
          .finally(() => {
 | 
			
		||||
            setLoading(false);
 | 
			
		||||
          });
 | 
			
		||||
      }).catch((error) => {
 | 
			
		||||
        console.error('Validation failed:', error);
 | 
			
		||||
        showError('请检查输入');
 | 
			
		||||
      });
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      showError('请检查输入');
 | 
			
		||||
      console.error(error);
 | 
			
		||||
    } finally {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function resetModelRatio() {
 | 
			
		||||
    try {
 | 
			
		||||
      let res = await API.post(`/api/option/rest_model_ratio`);
 | 
			
		||||
      // return {success, message}
 | 
			
		||||
      if (res.data.success) {
 | 
			
		||||
        showSuccess(res.data.message);
 | 
			
		||||
        props.refresh();
 | 
			
		||||
      } else {
 | 
			
		||||
        showError(res.data.message);
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      showError(error);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -73,122 +94,145 @@ export default function SettingsMagnification(props) {
 | 
			
		||||
    setInputsRow(structuredClone(currentInputs));
 | 
			
		||||
    refForm.current.setValues(currentInputs);
 | 
			
		||||
  }, [props.options]);
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <Spin spinning={loading}>
 | 
			
		||||
        <Form
 | 
			
		||||
          values={inputs}
 | 
			
		||||
          getFormApi={(formAPI) => (refForm.current = formAPI)}
 | 
			
		||||
          style={{ marginBottom: 15 }}
 | 
			
		||||
        >
 | 
			
		||||
          <Form.Section text={'倍率设置'}>
 | 
			
		||||
            <Row gutter={16}>
 | 
			
		||||
              <Col span={16}>
 | 
			
		||||
                <Form.TextArea
 | 
			
		||||
                  label={'模型固定价格'}
 | 
			
		||||
                  extraText={'一次调用消耗多少刀,优先级大于模型倍率'}
 | 
			
		||||
                  placeholder={
 | 
			
		||||
                    '为一个 JSON 文本,键为模型名称,值为一次调用消耗多少刀,比如 "gpt-4-gizmo-*": 0.1,一次消耗0.1刀'
 | 
			
		||||
                  }
 | 
			
		||||
                  field={'ModelPrice'}
 | 
			
		||||
                  autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                  trigger='blur'
 | 
			
		||||
                  rules={[
 | 
			
		||||
                    {
 | 
			
		||||
                      validator: (rule, value) => verifyJSON(value),
 | 
			
		||||
                      message: '不是合法的 JSON 字符串',
 | 
			
		||||
                    },
 | 
			
		||||
                  ]}
 | 
			
		||||
                  onChange={(value) =>
 | 
			
		||||
                    setInputs({
 | 
			
		||||
                      ...inputs,
 | 
			
		||||
                      ModelPrice: value,
 | 
			
		||||
                    })
 | 
			
		||||
                  }
 | 
			
		||||
                />
 | 
			
		||||
              </Col>
 | 
			
		||||
            </Row>
 | 
			
		||||
            <Row gutter={16}>
 | 
			
		||||
              <Col span={16}>
 | 
			
		||||
                <Form.TextArea
 | 
			
		||||
                  label={'模型倍率'}
 | 
			
		||||
                  extraText={''}
 | 
			
		||||
                  placeholder={'为一个 JSON 文本,键为模型名称,值为倍率'}
 | 
			
		||||
                  field={'ModelRatio'}
 | 
			
		||||
                  autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                  trigger='blur'
 | 
			
		||||
                  rules={[
 | 
			
		||||
                    {
 | 
			
		||||
                      validator: (rule, value) => verifyJSON(value),
 | 
			
		||||
                      message: '不是合法的 JSON 字符串',
 | 
			
		||||
                    },
 | 
			
		||||
                  ]}
 | 
			
		||||
                  onChange={(value) =>
 | 
			
		||||
                    setInputs({
 | 
			
		||||
                      ...inputs,
 | 
			
		||||
                      ModelRatio: value,
 | 
			
		||||
                    })
 | 
			
		||||
                  }
 | 
			
		||||
                />
 | 
			
		||||
              </Col>
 | 
			
		||||
            </Row>
 | 
			
		||||
            <Row gutter={16}>
 | 
			
		||||
              <Col span={16}>
 | 
			
		||||
                <Form.TextArea
 | 
			
		||||
                  label={'模型补全倍率(仅对自定义模型有效)'}
 | 
			
		||||
                  extraText={'仅对自定义模型有效'}
 | 
			
		||||
                  placeholder={'为一个 JSON 文本,键为模型名称,值为倍率'}
 | 
			
		||||
                  field={'CompletionRatio'}
 | 
			
		||||
                  autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                  trigger='blur'
 | 
			
		||||
                  rules={[
 | 
			
		||||
                    {
 | 
			
		||||
                      validator: (rule, value) => verifyJSON(value),
 | 
			
		||||
                      message: '不是合法的 JSON 字符串',
 | 
			
		||||
                    },
 | 
			
		||||
                  ]}
 | 
			
		||||
                  onChange={(value) =>
 | 
			
		||||
                    setInputs({
 | 
			
		||||
                      ...inputs,
 | 
			
		||||
                      CompletionRatio: value,
 | 
			
		||||
                    })
 | 
			
		||||
                  }
 | 
			
		||||
                />
 | 
			
		||||
              </Col>
 | 
			
		||||
            </Row>
 | 
			
		||||
            <Row gutter={16}>
 | 
			
		||||
              <Col span={16}>
 | 
			
		||||
                <Form.TextArea
 | 
			
		||||
                  label={'分组倍率'}
 | 
			
		||||
                  extraText={''}
 | 
			
		||||
                  placeholder={'为一个 JSON 文本,键为分组名称,值为倍率'}
 | 
			
		||||
                  field={'GroupRatio'}
 | 
			
		||||
                  autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                  trigger='blur'
 | 
			
		||||
                  rules={[
 | 
			
		||||
                    {
 | 
			
		||||
                      validator: (rule, value) => verifyJSON(value),
 | 
			
		||||
                      message: '不是合法的 JSON 字符串',
 | 
			
		||||
                    },
 | 
			
		||||
                  ]}
 | 
			
		||||
                  onChange={(value) =>
 | 
			
		||||
                    setInputs({
 | 
			
		||||
                      ...inputs,
 | 
			
		||||
                      GroupRatio: value,
 | 
			
		||||
                    })
 | 
			
		||||
                  }
 | 
			
		||||
                />
 | 
			
		||||
              </Col>
 | 
			
		||||
            </Row>
 | 
			
		||||
 | 
			
		||||
            <Row>
 | 
			
		||||
              <Button size='large' onClick={onSubmit}>
 | 
			
		||||
                保存倍率设置
 | 
			
		||||
              </Button>
 | 
			
		||||
            </Row>
 | 
			
		||||
          </Form.Section>
 | 
			
		||||
        </Form>
 | 
			
		||||
      </Spin>
 | 
			
		||||
    </>
 | 
			
		||||
  return (
 | 
			
		||||
    <Spin spinning={loading}>
 | 
			
		||||
      <Form
 | 
			
		||||
        values={inputs}
 | 
			
		||||
        getFormApi={(formAPI) => (refForm.current = formAPI)}
 | 
			
		||||
        style={{ marginBottom: 15 }}
 | 
			
		||||
      >
 | 
			
		||||
        <Form.Section text={'倍率设置'}>
 | 
			
		||||
          <Row gutter={16}>
 | 
			
		||||
            <Col span={16}>
 | 
			
		||||
              <Form.TextArea
 | 
			
		||||
                label={'模型固定价格'}
 | 
			
		||||
                extraText={'一次调用消耗多少刀,优先级大于模型倍率'}
 | 
			
		||||
                placeholder={
 | 
			
		||||
                  '为一个 JSON 文本,键为模型名称,值为一次调用消耗多少刀,比如 "gpt-4-gizmo-*": 0.1,一次消耗0.1刀'
 | 
			
		||||
                }
 | 
			
		||||
                field={'ModelPrice'}
 | 
			
		||||
                autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                trigger='blur'
 | 
			
		||||
                stopValidateWithError
 | 
			
		||||
                rules={[
 | 
			
		||||
                  {
 | 
			
		||||
                    validator: (rule, value) => {
 | 
			
		||||
                      return verifyJSON(value);
 | 
			
		||||
                    },
 | 
			
		||||
                    message: '不是合法的 JSON 字符串'
 | 
			
		||||
                  }
 | 
			
		||||
                ]}
 | 
			
		||||
                onChange={(value) =>
 | 
			
		||||
                  setInputs({
 | 
			
		||||
                    ...inputs,
 | 
			
		||||
                    ModelPrice: value
 | 
			
		||||
                  })
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            </Col>
 | 
			
		||||
          </Row>
 | 
			
		||||
          <Row gutter={16}>
 | 
			
		||||
            <Col span={16}>
 | 
			
		||||
              <Form.TextArea
 | 
			
		||||
                label={'模型倍率'}
 | 
			
		||||
                extraText={''}
 | 
			
		||||
                placeholder={'为一个 JSON 文本,键为模型名称,值为倍率'}
 | 
			
		||||
                field={'ModelRatio'}
 | 
			
		||||
                autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                trigger='blur'
 | 
			
		||||
                stopValidateWithError
 | 
			
		||||
                rules={[
 | 
			
		||||
                  {
 | 
			
		||||
                    validator: (rule, value) => {
 | 
			
		||||
                      return verifyJSON(value);
 | 
			
		||||
                    },
 | 
			
		||||
                    message: '不是合法的 JSON 字符串'
 | 
			
		||||
                  }
 | 
			
		||||
                ]}
 | 
			
		||||
                onChange={(value) =>
 | 
			
		||||
                  setInputs({
 | 
			
		||||
                    ...inputs,
 | 
			
		||||
                    ModelRatio: value
 | 
			
		||||
                  })
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            </Col>
 | 
			
		||||
          </Row>
 | 
			
		||||
          <Row gutter={16}>
 | 
			
		||||
            <Col span={16}>
 | 
			
		||||
              <Form.TextArea
 | 
			
		||||
                label={'模型补全倍率(仅对自定义模型有效)'}
 | 
			
		||||
                extraText={'仅对自定义模型有效'}
 | 
			
		||||
                placeholder={'为一个 JSON 文本,键为模型名称,值为倍率'}
 | 
			
		||||
                field={'CompletionRatio'}
 | 
			
		||||
                autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                trigger='blur'
 | 
			
		||||
                stopValidateWithError
 | 
			
		||||
                rules={[
 | 
			
		||||
                  {
 | 
			
		||||
                    validator: (rule, value) => {
 | 
			
		||||
                      return verifyJSON(value);
 | 
			
		||||
                    },
 | 
			
		||||
                    message: '不是合法的 JSON 字符串'
 | 
			
		||||
                  }
 | 
			
		||||
                ]}
 | 
			
		||||
                onChange={(value) =>
 | 
			
		||||
                  setInputs({
 | 
			
		||||
                    ...inputs,
 | 
			
		||||
                    CompletionRatio: value
 | 
			
		||||
                  })
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            </Col>
 | 
			
		||||
          </Row>
 | 
			
		||||
          <Row gutter={16}>
 | 
			
		||||
            <Col span={16}>
 | 
			
		||||
              <Form.TextArea
 | 
			
		||||
                label={'分组倍率'}
 | 
			
		||||
                extraText={''}
 | 
			
		||||
                placeholder={'为一个 JSON 文本,键为分组名称,值为倍率'}
 | 
			
		||||
                field={'GroupRatio'}
 | 
			
		||||
                autosize={{ minRows: 6, maxRows: 12 }}
 | 
			
		||||
                trigger='blur'
 | 
			
		||||
                stopValidateWithError
 | 
			
		||||
                rules={[
 | 
			
		||||
                  {
 | 
			
		||||
                    validator: (rule, value) => {
 | 
			
		||||
                      return verifyJSON(value);
 | 
			
		||||
                    },
 | 
			
		||||
                    message: '不是合法的 JSON 字符串'
 | 
			
		||||
                  }
 | 
			
		||||
                ]}
 | 
			
		||||
                onChange={(value) =>
 | 
			
		||||
                  setInputs({
 | 
			
		||||
                    ...inputs,
 | 
			
		||||
                    GroupRatio: value
 | 
			
		||||
                  })
 | 
			
		||||
                }
 | 
			
		||||
              />
 | 
			
		||||
            </Col>
 | 
			
		||||
          </Row>
 | 
			
		||||
        </Form.Section>
 | 
			
		||||
      </Form>
 | 
			
		||||
      <Space>
 | 
			
		||||
        <Button onClick={onSubmit}>
 | 
			
		||||
          保存倍率设置
 | 
			
		||||
        </Button>
 | 
			
		||||
        <Popconfirm
 | 
			
		||||
          title='确定重置模型倍率吗?'
 | 
			
		||||
          content='此修改将不可逆'
 | 
			
		||||
          okType={'danger'}
 | 
			
		||||
          position={'top'}
 | 
			
		||||
          onConfirm={() => {
 | 
			
		||||
            resetModelRatio();
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Button type={'danger'}>
 | 
			
		||||
            重置模型倍率
 | 
			
		||||
          </Button>
 | 
			
		||||
        </Popconfirm>
 | 
			
		||||
      </Space>
 | 
			
		||||
    </Spin>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user