feat: 图片生成计费功能
- 新增 Group 图片价格配置(image_price_1k/2k/4k) - BillingService 新增 CalculateImageCost 方法 - AntigravityGatewayService 支持识别图片生成模型并按次计费 - UsageLog 新增 image_count 和 image_size 字段 - 前端分组管理支持配置图片价格(antigravity 和 gemini 平台) - 图片计费复用通用计费能力(余额检查、扣费、倍率、订阅限额)
This commit is contained in:
@@ -45,6 +45,12 @@ type Group struct {
|
||||
MonthlyLimitUsd *float64 `json:"monthly_limit_usd,omitempty"`
|
||||
// DefaultValidityDays holds the value of the "default_validity_days" field.
|
||||
DefaultValidityDays int `json:"default_validity_days,omitempty"`
|
||||
// ImagePrice1k holds the value of the "image_price_1k" field.
|
||||
ImagePrice1k *float64 `json:"image_price_1k,omitempty"`
|
||||
// ImagePrice2k holds the value of the "image_price_2k" field.
|
||||
ImagePrice2k *float64 `json:"image_price_2k,omitempty"`
|
||||
// ImagePrice4k holds the value of the "image_price_4k" field.
|
||||
ImagePrice4k *float64 `json:"image_price_4k,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the GroupQuery when eager-loading is set.
|
||||
Edges GroupEdges `json:"edges"`
|
||||
@@ -153,7 +159,7 @@ func (*Group) scanValues(columns []string) ([]any, error) {
|
||||
switch columns[i] {
|
||||
case group.FieldIsExclusive:
|
||||
values[i] = new(sql.NullBool)
|
||||
case group.FieldRateMultiplier, group.FieldDailyLimitUsd, group.FieldWeeklyLimitUsd, group.FieldMonthlyLimitUsd:
|
||||
case group.FieldRateMultiplier, group.FieldDailyLimitUsd, group.FieldWeeklyLimitUsd, group.FieldMonthlyLimitUsd, group.FieldImagePrice1k, group.FieldImagePrice2k, group.FieldImagePrice4k:
|
||||
values[i] = new(sql.NullFloat64)
|
||||
case group.FieldID, group.FieldDefaultValidityDays:
|
||||
values[i] = new(sql.NullInt64)
|
||||
@@ -271,6 +277,27 @@ func (_m *Group) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
_m.DefaultValidityDays = int(value.Int64)
|
||||
}
|
||||
case group.FieldImagePrice1k:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field image_price_1k", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ImagePrice1k = new(float64)
|
||||
*_m.ImagePrice1k = value.Float64
|
||||
}
|
||||
case group.FieldImagePrice2k:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field image_price_2k", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ImagePrice2k = new(float64)
|
||||
*_m.ImagePrice2k = value.Float64
|
||||
}
|
||||
case group.FieldImagePrice4k:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field image_price_4k", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ImagePrice4k = new(float64)
|
||||
*_m.ImagePrice4k = value.Float64
|
||||
}
|
||||
default:
|
||||
_m.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
@@ -398,6 +425,21 @@ func (_m *Group) String() string {
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("default_validity_days=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.DefaultValidityDays))
|
||||
builder.WriteString(", ")
|
||||
if v := _m.ImagePrice1k; v != nil {
|
||||
builder.WriteString("image_price_1k=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.ImagePrice2k; v != nil {
|
||||
builder.WriteString("image_price_2k=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.ImagePrice4k; v != nil {
|
||||
builder.WriteString("image_price_4k=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@ const (
|
||||
FieldMonthlyLimitUsd = "monthly_limit_usd"
|
||||
// FieldDefaultValidityDays holds the string denoting the default_validity_days field in the database.
|
||||
FieldDefaultValidityDays = "default_validity_days"
|
||||
// FieldImagePrice1k holds the string denoting the image_price_1k field in the database.
|
||||
FieldImagePrice1k = "image_price_1k"
|
||||
// FieldImagePrice2k holds the string denoting the image_price_2k field in the database.
|
||||
FieldImagePrice2k = "image_price_2k"
|
||||
// FieldImagePrice4k holds the string denoting the image_price_4k field in the database.
|
||||
FieldImagePrice4k = "image_price_4k"
|
||||
// EdgeAPIKeys holds the string denoting the api_keys edge name in mutations.
|
||||
EdgeAPIKeys = "api_keys"
|
||||
// EdgeRedeemCodes holds the string denoting the redeem_codes edge name in mutations.
|
||||
@@ -132,6 +138,9 @@ var Columns = []string{
|
||||
FieldWeeklyLimitUsd,
|
||||
FieldMonthlyLimitUsd,
|
||||
FieldDefaultValidityDays,
|
||||
FieldImagePrice1k,
|
||||
FieldImagePrice2k,
|
||||
FieldImagePrice4k,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -267,6 +276,21 @@ func ByDefaultValidityDays(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldDefaultValidityDays, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByImagePrice1k orders the results by the image_price_1k field.
|
||||
func ByImagePrice1k(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldImagePrice1k, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByImagePrice2k orders the results by the image_price_2k field.
|
||||
func ByImagePrice2k(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldImagePrice2k, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByImagePrice4k orders the results by the image_price_4k field.
|
||||
func ByImagePrice4k(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldImagePrice4k, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByAPIKeysCount orders the results by api_keys count.
|
||||
func ByAPIKeysCount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
|
||||
@@ -125,6 +125,21 @@ func DefaultValidityDays(v int) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldDefaultValidityDays, v))
|
||||
}
|
||||
|
||||
// ImagePrice1k applies equality check predicate on the "image_price_1k" field. It's identical to ImagePrice1kEQ.
|
||||
func ImagePrice1k(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldImagePrice1k, v))
|
||||
}
|
||||
|
||||
// ImagePrice2k applies equality check predicate on the "image_price_2k" field. It's identical to ImagePrice2kEQ.
|
||||
func ImagePrice2k(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldImagePrice2k, v))
|
||||
}
|
||||
|
||||
// ImagePrice4k applies equality check predicate on the "image_price_4k" field. It's identical to ImagePrice4kEQ.
|
||||
func ImagePrice4k(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldImagePrice4k, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldCreatedAt, v))
|
||||
@@ -830,6 +845,156 @@ func DefaultValidityDaysLTE(v int) predicate.Group {
|
||||
return predicate.Group(sql.FieldLTE(FieldDefaultValidityDays, v))
|
||||
}
|
||||
|
||||
// ImagePrice1kEQ applies the EQ predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kEQ(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldImagePrice1k, v))
|
||||
}
|
||||
|
||||
// ImagePrice1kNEQ applies the NEQ predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kNEQ(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldNEQ(FieldImagePrice1k, v))
|
||||
}
|
||||
|
||||
// ImagePrice1kIn applies the In predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kIn(vs ...float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldIn(FieldImagePrice1k, vs...))
|
||||
}
|
||||
|
||||
// ImagePrice1kNotIn applies the NotIn predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kNotIn(vs ...float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldNotIn(FieldImagePrice1k, vs...))
|
||||
}
|
||||
|
||||
// ImagePrice1kGT applies the GT predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kGT(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldGT(FieldImagePrice1k, v))
|
||||
}
|
||||
|
||||
// ImagePrice1kGTE applies the GTE predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kGTE(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldGTE(FieldImagePrice1k, v))
|
||||
}
|
||||
|
||||
// ImagePrice1kLT applies the LT predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kLT(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldLT(FieldImagePrice1k, v))
|
||||
}
|
||||
|
||||
// ImagePrice1kLTE applies the LTE predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kLTE(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldLTE(FieldImagePrice1k, v))
|
||||
}
|
||||
|
||||
// ImagePrice1kIsNil applies the IsNil predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kIsNil() predicate.Group {
|
||||
return predicate.Group(sql.FieldIsNull(FieldImagePrice1k))
|
||||
}
|
||||
|
||||
// ImagePrice1kNotNil applies the NotNil predicate on the "image_price_1k" field.
|
||||
func ImagePrice1kNotNil() predicate.Group {
|
||||
return predicate.Group(sql.FieldNotNull(FieldImagePrice1k))
|
||||
}
|
||||
|
||||
// ImagePrice2kEQ applies the EQ predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kEQ(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldImagePrice2k, v))
|
||||
}
|
||||
|
||||
// ImagePrice2kNEQ applies the NEQ predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kNEQ(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldNEQ(FieldImagePrice2k, v))
|
||||
}
|
||||
|
||||
// ImagePrice2kIn applies the In predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kIn(vs ...float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldIn(FieldImagePrice2k, vs...))
|
||||
}
|
||||
|
||||
// ImagePrice2kNotIn applies the NotIn predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kNotIn(vs ...float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldNotIn(FieldImagePrice2k, vs...))
|
||||
}
|
||||
|
||||
// ImagePrice2kGT applies the GT predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kGT(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldGT(FieldImagePrice2k, v))
|
||||
}
|
||||
|
||||
// ImagePrice2kGTE applies the GTE predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kGTE(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldGTE(FieldImagePrice2k, v))
|
||||
}
|
||||
|
||||
// ImagePrice2kLT applies the LT predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kLT(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldLT(FieldImagePrice2k, v))
|
||||
}
|
||||
|
||||
// ImagePrice2kLTE applies the LTE predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kLTE(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldLTE(FieldImagePrice2k, v))
|
||||
}
|
||||
|
||||
// ImagePrice2kIsNil applies the IsNil predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kIsNil() predicate.Group {
|
||||
return predicate.Group(sql.FieldIsNull(FieldImagePrice2k))
|
||||
}
|
||||
|
||||
// ImagePrice2kNotNil applies the NotNil predicate on the "image_price_2k" field.
|
||||
func ImagePrice2kNotNil() predicate.Group {
|
||||
return predicate.Group(sql.FieldNotNull(FieldImagePrice2k))
|
||||
}
|
||||
|
||||
// ImagePrice4kEQ applies the EQ predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kEQ(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldEQ(FieldImagePrice4k, v))
|
||||
}
|
||||
|
||||
// ImagePrice4kNEQ applies the NEQ predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kNEQ(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldNEQ(FieldImagePrice4k, v))
|
||||
}
|
||||
|
||||
// ImagePrice4kIn applies the In predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kIn(vs ...float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldIn(FieldImagePrice4k, vs...))
|
||||
}
|
||||
|
||||
// ImagePrice4kNotIn applies the NotIn predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kNotIn(vs ...float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldNotIn(FieldImagePrice4k, vs...))
|
||||
}
|
||||
|
||||
// ImagePrice4kGT applies the GT predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kGT(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldGT(FieldImagePrice4k, v))
|
||||
}
|
||||
|
||||
// ImagePrice4kGTE applies the GTE predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kGTE(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldGTE(FieldImagePrice4k, v))
|
||||
}
|
||||
|
||||
// ImagePrice4kLT applies the LT predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kLT(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldLT(FieldImagePrice4k, v))
|
||||
}
|
||||
|
||||
// ImagePrice4kLTE applies the LTE predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kLTE(v float64) predicate.Group {
|
||||
return predicate.Group(sql.FieldLTE(FieldImagePrice4k, v))
|
||||
}
|
||||
|
||||
// ImagePrice4kIsNil applies the IsNil predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kIsNil() predicate.Group {
|
||||
return predicate.Group(sql.FieldIsNull(FieldImagePrice4k))
|
||||
}
|
||||
|
||||
// ImagePrice4kNotNil applies the NotNil predicate on the "image_price_4k" field.
|
||||
func ImagePrice4kNotNil() predicate.Group {
|
||||
return predicate.Group(sql.FieldNotNull(FieldImagePrice4k))
|
||||
}
|
||||
|
||||
// HasAPIKeys applies the HasEdge predicate on the "api_keys" edge.
|
||||
func HasAPIKeys() predicate.Group {
|
||||
return predicate.Group(func(s *sql.Selector) {
|
||||
|
||||
@@ -216,6 +216,48 @@ func (_c *GroupCreate) SetNillableDefaultValidityDays(v *int) *GroupCreate {
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetImagePrice1k sets the "image_price_1k" field.
|
||||
func (_c *GroupCreate) SetImagePrice1k(v float64) *GroupCreate {
|
||||
_c.mutation.SetImagePrice1k(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableImagePrice1k sets the "image_price_1k" field if the given value is not nil.
|
||||
func (_c *GroupCreate) SetNillableImagePrice1k(v *float64) *GroupCreate {
|
||||
if v != nil {
|
||||
_c.SetImagePrice1k(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetImagePrice2k sets the "image_price_2k" field.
|
||||
func (_c *GroupCreate) SetImagePrice2k(v float64) *GroupCreate {
|
||||
_c.mutation.SetImagePrice2k(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableImagePrice2k sets the "image_price_2k" field if the given value is not nil.
|
||||
func (_c *GroupCreate) SetNillableImagePrice2k(v *float64) *GroupCreate {
|
||||
if v != nil {
|
||||
_c.SetImagePrice2k(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetImagePrice4k sets the "image_price_4k" field.
|
||||
func (_c *GroupCreate) SetImagePrice4k(v float64) *GroupCreate {
|
||||
_c.mutation.SetImagePrice4k(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableImagePrice4k sets the "image_price_4k" field if the given value is not nil.
|
||||
func (_c *GroupCreate) SetNillableImagePrice4k(v *float64) *GroupCreate {
|
||||
if v != nil {
|
||||
_c.SetImagePrice4k(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
|
||||
func (_c *GroupCreate) AddAPIKeyIDs(ids ...int64) *GroupCreate {
|
||||
_c.mutation.AddAPIKeyIDs(ids...)
|
||||
@@ -516,6 +558,18 @@ func (_c *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(group.FieldDefaultValidityDays, field.TypeInt, value)
|
||||
_node.DefaultValidityDays = value
|
||||
}
|
||||
if value, ok := _c.mutation.ImagePrice1k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice1k, field.TypeFloat64, value)
|
||||
_node.ImagePrice1k = &value
|
||||
}
|
||||
if value, ok := _c.mutation.ImagePrice2k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice2k, field.TypeFloat64, value)
|
||||
_node.ImagePrice2k = &value
|
||||
}
|
||||
if value, ok := _c.mutation.ImagePrice4k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice4k, field.TypeFloat64, value)
|
||||
_node.ImagePrice4k = &value
|
||||
}
|
||||
if nodes := _c.mutation.APIKeysIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
@@ -888,6 +942,78 @@ func (u *GroupUpsert) AddDefaultValidityDays(v int) *GroupUpsert {
|
||||
return u
|
||||
}
|
||||
|
||||
// SetImagePrice1k sets the "image_price_1k" field.
|
||||
func (u *GroupUpsert) SetImagePrice1k(v float64) *GroupUpsert {
|
||||
u.Set(group.FieldImagePrice1k, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateImagePrice1k sets the "image_price_1k" field to the value that was provided on create.
|
||||
func (u *GroupUpsert) UpdateImagePrice1k() *GroupUpsert {
|
||||
u.SetExcluded(group.FieldImagePrice1k)
|
||||
return u
|
||||
}
|
||||
|
||||
// AddImagePrice1k adds v to the "image_price_1k" field.
|
||||
func (u *GroupUpsert) AddImagePrice1k(v float64) *GroupUpsert {
|
||||
u.Add(group.FieldImagePrice1k, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearImagePrice1k clears the value of the "image_price_1k" field.
|
||||
func (u *GroupUpsert) ClearImagePrice1k() *GroupUpsert {
|
||||
u.SetNull(group.FieldImagePrice1k)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetImagePrice2k sets the "image_price_2k" field.
|
||||
func (u *GroupUpsert) SetImagePrice2k(v float64) *GroupUpsert {
|
||||
u.Set(group.FieldImagePrice2k, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateImagePrice2k sets the "image_price_2k" field to the value that was provided on create.
|
||||
func (u *GroupUpsert) UpdateImagePrice2k() *GroupUpsert {
|
||||
u.SetExcluded(group.FieldImagePrice2k)
|
||||
return u
|
||||
}
|
||||
|
||||
// AddImagePrice2k adds v to the "image_price_2k" field.
|
||||
func (u *GroupUpsert) AddImagePrice2k(v float64) *GroupUpsert {
|
||||
u.Add(group.FieldImagePrice2k, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearImagePrice2k clears the value of the "image_price_2k" field.
|
||||
func (u *GroupUpsert) ClearImagePrice2k() *GroupUpsert {
|
||||
u.SetNull(group.FieldImagePrice2k)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetImagePrice4k sets the "image_price_4k" field.
|
||||
func (u *GroupUpsert) SetImagePrice4k(v float64) *GroupUpsert {
|
||||
u.Set(group.FieldImagePrice4k, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateImagePrice4k sets the "image_price_4k" field to the value that was provided on create.
|
||||
func (u *GroupUpsert) UpdateImagePrice4k() *GroupUpsert {
|
||||
u.SetExcluded(group.FieldImagePrice4k)
|
||||
return u
|
||||
}
|
||||
|
||||
// AddImagePrice4k adds v to the "image_price_4k" field.
|
||||
func (u *GroupUpsert) AddImagePrice4k(v float64) *GroupUpsert {
|
||||
u.Add(group.FieldImagePrice4k, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearImagePrice4k clears the value of the "image_price_4k" field.
|
||||
func (u *GroupUpsert) ClearImagePrice4k() *GroupUpsert {
|
||||
u.SetNull(group.FieldImagePrice4k)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateNewValues updates the mutable fields using the new values that were set on create.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
@@ -1185,6 +1311,90 @@ func (u *GroupUpsertOne) UpdateDefaultValidityDays() *GroupUpsertOne {
|
||||
})
|
||||
}
|
||||
|
||||
// SetImagePrice1k sets the "image_price_1k" field.
|
||||
func (u *GroupUpsertOne) SetImagePrice1k(v float64) *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.SetImagePrice1k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImagePrice1k adds v to the "image_price_1k" field.
|
||||
func (u *GroupUpsertOne) AddImagePrice1k(v float64) *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.AddImagePrice1k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImagePrice1k sets the "image_price_1k" field to the value that was provided on create.
|
||||
func (u *GroupUpsertOne) UpdateImagePrice1k() *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.UpdateImagePrice1k()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImagePrice1k clears the value of the "image_price_1k" field.
|
||||
func (u *GroupUpsertOne) ClearImagePrice1k() *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.ClearImagePrice1k()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImagePrice2k sets the "image_price_2k" field.
|
||||
func (u *GroupUpsertOne) SetImagePrice2k(v float64) *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.SetImagePrice2k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImagePrice2k adds v to the "image_price_2k" field.
|
||||
func (u *GroupUpsertOne) AddImagePrice2k(v float64) *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.AddImagePrice2k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImagePrice2k sets the "image_price_2k" field to the value that was provided on create.
|
||||
func (u *GroupUpsertOne) UpdateImagePrice2k() *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.UpdateImagePrice2k()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImagePrice2k clears the value of the "image_price_2k" field.
|
||||
func (u *GroupUpsertOne) ClearImagePrice2k() *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.ClearImagePrice2k()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImagePrice4k sets the "image_price_4k" field.
|
||||
func (u *GroupUpsertOne) SetImagePrice4k(v float64) *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.SetImagePrice4k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImagePrice4k adds v to the "image_price_4k" field.
|
||||
func (u *GroupUpsertOne) AddImagePrice4k(v float64) *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.AddImagePrice4k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImagePrice4k sets the "image_price_4k" field to the value that was provided on create.
|
||||
func (u *GroupUpsertOne) UpdateImagePrice4k() *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.UpdateImagePrice4k()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImagePrice4k clears the value of the "image_price_4k" field.
|
||||
func (u *GroupUpsertOne) ClearImagePrice4k() *GroupUpsertOne {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.ClearImagePrice4k()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *GroupUpsertOne) Exec(ctx context.Context) error {
|
||||
if len(u.create.conflict) == 0 {
|
||||
@@ -1648,6 +1858,90 @@ func (u *GroupUpsertBulk) UpdateDefaultValidityDays() *GroupUpsertBulk {
|
||||
})
|
||||
}
|
||||
|
||||
// SetImagePrice1k sets the "image_price_1k" field.
|
||||
func (u *GroupUpsertBulk) SetImagePrice1k(v float64) *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.SetImagePrice1k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImagePrice1k adds v to the "image_price_1k" field.
|
||||
func (u *GroupUpsertBulk) AddImagePrice1k(v float64) *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.AddImagePrice1k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImagePrice1k sets the "image_price_1k" field to the value that was provided on create.
|
||||
func (u *GroupUpsertBulk) UpdateImagePrice1k() *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.UpdateImagePrice1k()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImagePrice1k clears the value of the "image_price_1k" field.
|
||||
func (u *GroupUpsertBulk) ClearImagePrice1k() *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.ClearImagePrice1k()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImagePrice2k sets the "image_price_2k" field.
|
||||
func (u *GroupUpsertBulk) SetImagePrice2k(v float64) *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.SetImagePrice2k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImagePrice2k adds v to the "image_price_2k" field.
|
||||
func (u *GroupUpsertBulk) AddImagePrice2k(v float64) *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.AddImagePrice2k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImagePrice2k sets the "image_price_2k" field to the value that was provided on create.
|
||||
func (u *GroupUpsertBulk) UpdateImagePrice2k() *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.UpdateImagePrice2k()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImagePrice2k clears the value of the "image_price_2k" field.
|
||||
func (u *GroupUpsertBulk) ClearImagePrice2k() *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.ClearImagePrice2k()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImagePrice4k sets the "image_price_4k" field.
|
||||
func (u *GroupUpsertBulk) SetImagePrice4k(v float64) *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.SetImagePrice4k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImagePrice4k adds v to the "image_price_4k" field.
|
||||
func (u *GroupUpsertBulk) AddImagePrice4k(v float64) *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.AddImagePrice4k(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImagePrice4k sets the "image_price_4k" field to the value that was provided on create.
|
||||
func (u *GroupUpsertBulk) UpdateImagePrice4k() *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.UpdateImagePrice4k()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImagePrice4k clears the value of the "image_price_4k" field.
|
||||
func (u *GroupUpsertBulk) ClearImagePrice4k() *GroupUpsertBulk {
|
||||
return u.Update(func(s *GroupUpsert) {
|
||||
s.ClearImagePrice4k()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *GroupUpsertBulk) Exec(ctx context.Context) error {
|
||||
if u.create.err != nil {
|
||||
|
||||
@@ -273,6 +273,87 @@ func (_u *GroupUpdate) AddDefaultValidityDays(v int) *GroupUpdate {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImagePrice1k sets the "image_price_1k" field.
|
||||
func (_u *GroupUpdate) SetImagePrice1k(v float64) *GroupUpdate {
|
||||
_u.mutation.ResetImagePrice1k()
|
||||
_u.mutation.SetImagePrice1k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImagePrice1k sets the "image_price_1k" field if the given value is not nil.
|
||||
func (_u *GroupUpdate) SetNillableImagePrice1k(v *float64) *GroupUpdate {
|
||||
if v != nil {
|
||||
_u.SetImagePrice1k(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImagePrice1k adds value to the "image_price_1k" field.
|
||||
func (_u *GroupUpdate) AddImagePrice1k(v float64) *GroupUpdate {
|
||||
_u.mutation.AddImagePrice1k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImagePrice1k clears the value of the "image_price_1k" field.
|
||||
func (_u *GroupUpdate) ClearImagePrice1k() *GroupUpdate {
|
||||
_u.mutation.ClearImagePrice1k()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImagePrice2k sets the "image_price_2k" field.
|
||||
func (_u *GroupUpdate) SetImagePrice2k(v float64) *GroupUpdate {
|
||||
_u.mutation.ResetImagePrice2k()
|
||||
_u.mutation.SetImagePrice2k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImagePrice2k sets the "image_price_2k" field if the given value is not nil.
|
||||
func (_u *GroupUpdate) SetNillableImagePrice2k(v *float64) *GroupUpdate {
|
||||
if v != nil {
|
||||
_u.SetImagePrice2k(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImagePrice2k adds value to the "image_price_2k" field.
|
||||
func (_u *GroupUpdate) AddImagePrice2k(v float64) *GroupUpdate {
|
||||
_u.mutation.AddImagePrice2k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImagePrice2k clears the value of the "image_price_2k" field.
|
||||
func (_u *GroupUpdate) ClearImagePrice2k() *GroupUpdate {
|
||||
_u.mutation.ClearImagePrice2k()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImagePrice4k sets the "image_price_4k" field.
|
||||
func (_u *GroupUpdate) SetImagePrice4k(v float64) *GroupUpdate {
|
||||
_u.mutation.ResetImagePrice4k()
|
||||
_u.mutation.SetImagePrice4k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImagePrice4k sets the "image_price_4k" field if the given value is not nil.
|
||||
func (_u *GroupUpdate) SetNillableImagePrice4k(v *float64) *GroupUpdate {
|
||||
if v != nil {
|
||||
_u.SetImagePrice4k(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImagePrice4k adds value to the "image_price_4k" field.
|
||||
func (_u *GroupUpdate) AddImagePrice4k(v float64) *GroupUpdate {
|
||||
_u.mutation.AddImagePrice4k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImagePrice4k clears the value of the "image_price_4k" field.
|
||||
func (_u *GroupUpdate) ClearImagePrice4k() *GroupUpdate {
|
||||
_u.mutation.ClearImagePrice4k()
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
|
||||
func (_u *GroupUpdate) AddAPIKeyIDs(ids ...int64) *GroupUpdate {
|
||||
_u.mutation.AddAPIKeyIDs(ids...)
|
||||
@@ -642,6 +723,33 @@ func (_u *GroupUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
if value, ok := _u.mutation.AddedDefaultValidityDays(); ok {
|
||||
_spec.AddField(group.FieldDefaultValidityDays, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ImagePrice1k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice1k, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImagePrice1k(); ok {
|
||||
_spec.AddField(group.FieldImagePrice1k, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.ImagePrice1kCleared() {
|
||||
_spec.ClearField(group.FieldImagePrice1k, field.TypeFloat64)
|
||||
}
|
||||
if value, ok := _u.mutation.ImagePrice2k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice2k, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImagePrice2k(); ok {
|
||||
_spec.AddField(group.FieldImagePrice2k, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.ImagePrice2kCleared() {
|
||||
_spec.ClearField(group.FieldImagePrice2k, field.TypeFloat64)
|
||||
}
|
||||
if value, ok := _u.mutation.ImagePrice4k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice4k, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImagePrice4k(); ok {
|
||||
_spec.AddField(group.FieldImagePrice4k, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.ImagePrice4kCleared() {
|
||||
_spec.ClearField(group.FieldImagePrice4k, field.TypeFloat64)
|
||||
}
|
||||
if _u.mutation.APIKeysCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
@@ -1195,6 +1303,87 @@ func (_u *GroupUpdateOne) AddDefaultValidityDays(v int) *GroupUpdateOne {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImagePrice1k sets the "image_price_1k" field.
|
||||
func (_u *GroupUpdateOne) SetImagePrice1k(v float64) *GroupUpdateOne {
|
||||
_u.mutation.ResetImagePrice1k()
|
||||
_u.mutation.SetImagePrice1k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImagePrice1k sets the "image_price_1k" field if the given value is not nil.
|
||||
func (_u *GroupUpdateOne) SetNillableImagePrice1k(v *float64) *GroupUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetImagePrice1k(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImagePrice1k adds value to the "image_price_1k" field.
|
||||
func (_u *GroupUpdateOne) AddImagePrice1k(v float64) *GroupUpdateOne {
|
||||
_u.mutation.AddImagePrice1k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImagePrice1k clears the value of the "image_price_1k" field.
|
||||
func (_u *GroupUpdateOne) ClearImagePrice1k() *GroupUpdateOne {
|
||||
_u.mutation.ClearImagePrice1k()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImagePrice2k sets the "image_price_2k" field.
|
||||
func (_u *GroupUpdateOne) SetImagePrice2k(v float64) *GroupUpdateOne {
|
||||
_u.mutation.ResetImagePrice2k()
|
||||
_u.mutation.SetImagePrice2k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImagePrice2k sets the "image_price_2k" field if the given value is not nil.
|
||||
func (_u *GroupUpdateOne) SetNillableImagePrice2k(v *float64) *GroupUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetImagePrice2k(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImagePrice2k adds value to the "image_price_2k" field.
|
||||
func (_u *GroupUpdateOne) AddImagePrice2k(v float64) *GroupUpdateOne {
|
||||
_u.mutation.AddImagePrice2k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImagePrice2k clears the value of the "image_price_2k" field.
|
||||
func (_u *GroupUpdateOne) ClearImagePrice2k() *GroupUpdateOne {
|
||||
_u.mutation.ClearImagePrice2k()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImagePrice4k sets the "image_price_4k" field.
|
||||
func (_u *GroupUpdateOne) SetImagePrice4k(v float64) *GroupUpdateOne {
|
||||
_u.mutation.ResetImagePrice4k()
|
||||
_u.mutation.SetImagePrice4k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImagePrice4k sets the "image_price_4k" field if the given value is not nil.
|
||||
func (_u *GroupUpdateOne) SetNillableImagePrice4k(v *float64) *GroupUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetImagePrice4k(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImagePrice4k adds value to the "image_price_4k" field.
|
||||
func (_u *GroupUpdateOne) AddImagePrice4k(v float64) *GroupUpdateOne {
|
||||
_u.mutation.AddImagePrice4k(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImagePrice4k clears the value of the "image_price_4k" field.
|
||||
func (_u *GroupUpdateOne) ClearImagePrice4k() *GroupUpdateOne {
|
||||
_u.mutation.ClearImagePrice4k()
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
|
||||
func (_u *GroupUpdateOne) AddAPIKeyIDs(ids ...int64) *GroupUpdateOne {
|
||||
_u.mutation.AddAPIKeyIDs(ids...)
|
||||
@@ -1594,6 +1783,33 @@ func (_u *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error)
|
||||
if value, ok := _u.mutation.AddedDefaultValidityDays(); ok {
|
||||
_spec.AddField(group.FieldDefaultValidityDays, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ImagePrice1k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice1k, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImagePrice1k(); ok {
|
||||
_spec.AddField(group.FieldImagePrice1k, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.ImagePrice1kCleared() {
|
||||
_spec.ClearField(group.FieldImagePrice1k, field.TypeFloat64)
|
||||
}
|
||||
if value, ok := _u.mutation.ImagePrice2k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice2k, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImagePrice2k(); ok {
|
||||
_spec.AddField(group.FieldImagePrice2k, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.ImagePrice2kCleared() {
|
||||
_spec.ClearField(group.FieldImagePrice2k, field.TypeFloat64)
|
||||
}
|
||||
if value, ok := _u.mutation.ImagePrice4k(); ok {
|
||||
_spec.SetField(group.FieldImagePrice4k, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImagePrice4k(); ok {
|
||||
_spec.AddField(group.FieldImagePrice4k, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.ImagePrice4kCleared() {
|
||||
_spec.ClearField(group.FieldImagePrice4k, field.TypeFloat64)
|
||||
}
|
||||
if _u.mutation.APIKeysCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
|
||||
@@ -215,6 +215,9 @@ var (
|
||||
{Name: "weekly_limit_usd", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,8)"}},
|
||||
{Name: "monthly_limit_usd", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,8)"}},
|
||||
{Name: "default_validity_days", Type: field.TypeInt, Default: 30},
|
||||
{Name: "image_price_1k", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,8)"}},
|
||||
{Name: "image_price_2k", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,8)"}},
|
||||
{Name: "image_price_4k", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,8)"}},
|
||||
}
|
||||
// GroupsTable holds the schema information for the "groups" table.
|
||||
GroupsTable = &schema.Table{
|
||||
@@ -367,6 +370,8 @@ var (
|
||||
{Name: "stream", Type: field.TypeBool, Default: false},
|
||||
{Name: "duration_ms", Type: field.TypeInt, Nullable: true},
|
||||
{Name: "first_token_ms", Type: field.TypeInt, Nullable: true},
|
||||
{Name: "image_count", Type: field.TypeInt, Default: 0},
|
||||
{Name: "image_size", Type: field.TypeString, Nullable: true, Size: 10},
|
||||
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "api_key_id", Type: field.TypeInt64},
|
||||
{Name: "account_id", Type: field.TypeInt64},
|
||||
@@ -382,31 +387,31 @@ var (
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "usage_logs_api_keys_usage_logs",
|
||||
Columns: []*schema.Column{UsageLogsColumns[21]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[23]},
|
||||
RefColumns: []*schema.Column{APIKeysColumns[0]},
|
||||
OnDelete: schema.NoAction,
|
||||
},
|
||||
{
|
||||
Symbol: "usage_logs_accounts_usage_logs",
|
||||
Columns: []*schema.Column{UsageLogsColumns[22]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[24]},
|
||||
RefColumns: []*schema.Column{AccountsColumns[0]},
|
||||
OnDelete: schema.NoAction,
|
||||
},
|
||||
{
|
||||
Symbol: "usage_logs_groups_usage_logs",
|
||||
Columns: []*schema.Column{UsageLogsColumns[23]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[25]},
|
||||
RefColumns: []*schema.Column{GroupsColumns[0]},
|
||||
OnDelete: schema.SetNull,
|
||||
},
|
||||
{
|
||||
Symbol: "usage_logs_users_usage_logs",
|
||||
Columns: []*schema.Column{UsageLogsColumns[24]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[26]},
|
||||
RefColumns: []*schema.Column{UsersColumns[0]},
|
||||
OnDelete: schema.NoAction,
|
||||
},
|
||||
{
|
||||
Symbol: "usage_logs_user_subscriptions_usage_logs",
|
||||
Columns: []*schema.Column{UsageLogsColumns[25]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[27]},
|
||||
RefColumns: []*schema.Column{UserSubscriptionsColumns[0]},
|
||||
OnDelete: schema.SetNull,
|
||||
},
|
||||
@@ -415,32 +420,32 @@ var (
|
||||
{
|
||||
Name: "usagelog_user_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[24]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[26]},
|
||||
},
|
||||
{
|
||||
Name: "usagelog_api_key_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[21]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[23]},
|
||||
},
|
||||
{
|
||||
Name: "usagelog_account_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[22]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[24]},
|
||||
},
|
||||
{
|
||||
Name: "usagelog_group_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[23]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[25]},
|
||||
},
|
||||
{
|
||||
Name: "usagelog_subscription_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[25]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[27]},
|
||||
},
|
||||
{
|
||||
Name: "usagelog_created_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[20]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[22]},
|
||||
},
|
||||
{
|
||||
Name: "usagelog_model",
|
||||
@@ -455,12 +460,12 @@ var (
|
||||
{
|
||||
Name: "usagelog_user_id_created_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[24], UsageLogsColumns[20]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[26], UsageLogsColumns[22]},
|
||||
},
|
||||
{
|
||||
Name: "usagelog_api_key_id_created_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{UsageLogsColumns[21], UsageLogsColumns[20]},
|
||||
Columns: []*schema.Column{UsageLogsColumns[23], UsageLogsColumns[22]},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3384,6 +3384,12 @@ type GroupMutation struct {
|
||||
addmonthly_limit_usd *float64
|
||||
default_validity_days *int
|
||||
adddefault_validity_days *int
|
||||
image_price_1k *float64
|
||||
addimage_price_1k *float64
|
||||
image_price_2k *float64
|
||||
addimage_price_2k *float64
|
||||
image_price_4k *float64
|
||||
addimage_price_4k *float64
|
||||
clearedFields map[string]struct{}
|
||||
api_keys map[int64]struct{}
|
||||
removedapi_keys map[int64]struct{}
|
||||
@@ -4178,6 +4184,216 @@ func (m *GroupMutation) ResetDefaultValidityDays() {
|
||||
m.adddefault_validity_days = nil
|
||||
}
|
||||
|
||||
// SetImagePrice1k sets the "image_price_1k" field.
|
||||
func (m *GroupMutation) SetImagePrice1k(f float64) {
|
||||
m.image_price_1k = &f
|
||||
m.addimage_price_1k = nil
|
||||
}
|
||||
|
||||
// ImagePrice1k returns the value of the "image_price_1k" field in the mutation.
|
||||
func (m *GroupMutation) ImagePrice1k() (r float64, exists bool) {
|
||||
v := m.image_price_1k
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldImagePrice1k returns the old "image_price_1k" field's value of the Group entity.
|
||||
// If the Group object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *GroupMutation) OldImagePrice1k(ctx context.Context) (v *float64, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldImagePrice1k is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldImagePrice1k requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldImagePrice1k: %w", err)
|
||||
}
|
||||
return oldValue.ImagePrice1k, nil
|
||||
}
|
||||
|
||||
// AddImagePrice1k adds f to the "image_price_1k" field.
|
||||
func (m *GroupMutation) AddImagePrice1k(f float64) {
|
||||
if m.addimage_price_1k != nil {
|
||||
*m.addimage_price_1k += f
|
||||
} else {
|
||||
m.addimage_price_1k = &f
|
||||
}
|
||||
}
|
||||
|
||||
// AddedImagePrice1k returns the value that was added to the "image_price_1k" field in this mutation.
|
||||
func (m *GroupMutation) AddedImagePrice1k() (r float64, exists bool) {
|
||||
v := m.addimage_price_1k
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// ClearImagePrice1k clears the value of the "image_price_1k" field.
|
||||
func (m *GroupMutation) ClearImagePrice1k() {
|
||||
m.image_price_1k = nil
|
||||
m.addimage_price_1k = nil
|
||||
m.clearedFields[group.FieldImagePrice1k] = struct{}{}
|
||||
}
|
||||
|
||||
// ImagePrice1kCleared returns if the "image_price_1k" field was cleared in this mutation.
|
||||
func (m *GroupMutation) ImagePrice1kCleared() bool {
|
||||
_, ok := m.clearedFields[group.FieldImagePrice1k]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetImagePrice1k resets all changes to the "image_price_1k" field.
|
||||
func (m *GroupMutation) ResetImagePrice1k() {
|
||||
m.image_price_1k = nil
|
||||
m.addimage_price_1k = nil
|
||||
delete(m.clearedFields, group.FieldImagePrice1k)
|
||||
}
|
||||
|
||||
// SetImagePrice2k sets the "image_price_2k" field.
|
||||
func (m *GroupMutation) SetImagePrice2k(f float64) {
|
||||
m.image_price_2k = &f
|
||||
m.addimage_price_2k = nil
|
||||
}
|
||||
|
||||
// ImagePrice2k returns the value of the "image_price_2k" field in the mutation.
|
||||
func (m *GroupMutation) ImagePrice2k() (r float64, exists bool) {
|
||||
v := m.image_price_2k
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldImagePrice2k returns the old "image_price_2k" field's value of the Group entity.
|
||||
// If the Group object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *GroupMutation) OldImagePrice2k(ctx context.Context) (v *float64, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldImagePrice2k is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldImagePrice2k requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldImagePrice2k: %w", err)
|
||||
}
|
||||
return oldValue.ImagePrice2k, nil
|
||||
}
|
||||
|
||||
// AddImagePrice2k adds f to the "image_price_2k" field.
|
||||
func (m *GroupMutation) AddImagePrice2k(f float64) {
|
||||
if m.addimage_price_2k != nil {
|
||||
*m.addimage_price_2k += f
|
||||
} else {
|
||||
m.addimage_price_2k = &f
|
||||
}
|
||||
}
|
||||
|
||||
// AddedImagePrice2k returns the value that was added to the "image_price_2k" field in this mutation.
|
||||
func (m *GroupMutation) AddedImagePrice2k() (r float64, exists bool) {
|
||||
v := m.addimage_price_2k
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// ClearImagePrice2k clears the value of the "image_price_2k" field.
|
||||
func (m *GroupMutation) ClearImagePrice2k() {
|
||||
m.image_price_2k = nil
|
||||
m.addimage_price_2k = nil
|
||||
m.clearedFields[group.FieldImagePrice2k] = struct{}{}
|
||||
}
|
||||
|
||||
// ImagePrice2kCleared returns if the "image_price_2k" field was cleared in this mutation.
|
||||
func (m *GroupMutation) ImagePrice2kCleared() bool {
|
||||
_, ok := m.clearedFields[group.FieldImagePrice2k]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetImagePrice2k resets all changes to the "image_price_2k" field.
|
||||
func (m *GroupMutation) ResetImagePrice2k() {
|
||||
m.image_price_2k = nil
|
||||
m.addimage_price_2k = nil
|
||||
delete(m.clearedFields, group.FieldImagePrice2k)
|
||||
}
|
||||
|
||||
// SetImagePrice4k sets the "image_price_4k" field.
|
||||
func (m *GroupMutation) SetImagePrice4k(f float64) {
|
||||
m.image_price_4k = &f
|
||||
m.addimage_price_4k = nil
|
||||
}
|
||||
|
||||
// ImagePrice4k returns the value of the "image_price_4k" field in the mutation.
|
||||
func (m *GroupMutation) ImagePrice4k() (r float64, exists bool) {
|
||||
v := m.image_price_4k
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldImagePrice4k returns the old "image_price_4k" field's value of the Group entity.
|
||||
// If the Group object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *GroupMutation) OldImagePrice4k(ctx context.Context) (v *float64, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldImagePrice4k is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldImagePrice4k requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldImagePrice4k: %w", err)
|
||||
}
|
||||
return oldValue.ImagePrice4k, nil
|
||||
}
|
||||
|
||||
// AddImagePrice4k adds f to the "image_price_4k" field.
|
||||
func (m *GroupMutation) AddImagePrice4k(f float64) {
|
||||
if m.addimage_price_4k != nil {
|
||||
*m.addimage_price_4k += f
|
||||
} else {
|
||||
m.addimage_price_4k = &f
|
||||
}
|
||||
}
|
||||
|
||||
// AddedImagePrice4k returns the value that was added to the "image_price_4k" field in this mutation.
|
||||
func (m *GroupMutation) AddedImagePrice4k() (r float64, exists bool) {
|
||||
v := m.addimage_price_4k
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// ClearImagePrice4k clears the value of the "image_price_4k" field.
|
||||
func (m *GroupMutation) ClearImagePrice4k() {
|
||||
m.image_price_4k = nil
|
||||
m.addimage_price_4k = nil
|
||||
m.clearedFields[group.FieldImagePrice4k] = struct{}{}
|
||||
}
|
||||
|
||||
// ImagePrice4kCleared returns if the "image_price_4k" field was cleared in this mutation.
|
||||
func (m *GroupMutation) ImagePrice4kCleared() bool {
|
||||
_, ok := m.clearedFields[group.FieldImagePrice4k]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetImagePrice4k resets all changes to the "image_price_4k" field.
|
||||
func (m *GroupMutation) ResetImagePrice4k() {
|
||||
m.image_price_4k = nil
|
||||
m.addimage_price_4k = nil
|
||||
delete(m.clearedFields, group.FieldImagePrice4k)
|
||||
}
|
||||
|
||||
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by ids.
|
||||
func (m *GroupMutation) AddAPIKeyIDs(ids ...int64) {
|
||||
if m.api_keys == nil {
|
||||
@@ -4536,7 +4752,7 @@ func (m *GroupMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *GroupMutation) Fields() []string {
|
||||
fields := make([]string, 0, 14)
|
||||
fields := make([]string, 0, 17)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, group.FieldCreatedAt)
|
||||
}
|
||||
@@ -4579,6 +4795,15 @@ func (m *GroupMutation) Fields() []string {
|
||||
if m.default_validity_days != nil {
|
||||
fields = append(fields, group.FieldDefaultValidityDays)
|
||||
}
|
||||
if m.image_price_1k != nil {
|
||||
fields = append(fields, group.FieldImagePrice1k)
|
||||
}
|
||||
if m.image_price_2k != nil {
|
||||
fields = append(fields, group.FieldImagePrice2k)
|
||||
}
|
||||
if m.image_price_4k != nil {
|
||||
fields = append(fields, group.FieldImagePrice4k)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -4615,6 +4840,12 @@ func (m *GroupMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.MonthlyLimitUsd()
|
||||
case group.FieldDefaultValidityDays:
|
||||
return m.DefaultValidityDays()
|
||||
case group.FieldImagePrice1k:
|
||||
return m.ImagePrice1k()
|
||||
case group.FieldImagePrice2k:
|
||||
return m.ImagePrice2k()
|
||||
case group.FieldImagePrice4k:
|
||||
return m.ImagePrice4k()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -4652,6 +4883,12 @@ func (m *GroupMutation) OldField(ctx context.Context, name string) (ent.Value, e
|
||||
return m.OldMonthlyLimitUsd(ctx)
|
||||
case group.FieldDefaultValidityDays:
|
||||
return m.OldDefaultValidityDays(ctx)
|
||||
case group.FieldImagePrice1k:
|
||||
return m.OldImagePrice1k(ctx)
|
||||
case group.FieldImagePrice2k:
|
||||
return m.OldImagePrice2k(ctx)
|
||||
case group.FieldImagePrice4k:
|
||||
return m.OldImagePrice4k(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown Group field %s", name)
|
||||
}
|
||||
@@ -4759,6 +4996,27 @@ func (m *GroupMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetDefaultValidityDays(v)
|
||||
return nil
|
||||
case group.FieldImagePrice1k:
|
||||
v, ok := value.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetImagePrice1k(v)
|
||||
return nil
|
||||
case group.FieldImagePrice2k:
|
||||
v, ok := value.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetImagePrice2k(v)
|
||||
return nil
|
||||
case group.FieldImagePrice4k:
|
||||
v, ok := value.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetImagePrice4k(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Group field %s", name)
|
||||
}
|
||||
@@ -4782,6 +5040,15 @@ func (m *GroupMutation) AddedFields() []string {
|
||||
if m.adddefault_validity_days != nil {
|
||||
fields = append(fields, group.FieldDefaultValidityDays)
|
||||
}
|
||||
if m.addimage_price_1k != nil {
|
||||
fields = append(fields, group.FieldImagePrice1k)
|
||||
}
|
||||
if m.addimage_price_2k != nil {
|
||||
fields = append(fields, group.FieldImagePrice2k)
|
||||
}
|
||||
if m.addimage_price_4k != nil {
|
||||
fields = append(fields, group.FieldImagePrice4k)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -4800,6 +5067,12 @@ func (m *GroupMutation) AddedField(name string) (ent.Value, bool) {
|
||||
return m.AddedMonthlyLimitUsd()
|
||||
case group.FieldDefaultValidityDays:
|
||||
return m.AddedDefaultValidityDays()
|
||||
case group.FieldImagePrice1k:
|
||||
return m.AddedImagePrice1k()
|
||||
case group.FieldImagePrice2k:
|
||||
return m.AddedImagePrice2k()
|
||||
case group.FieldImagePrice4k:
|
||||
return m.AddedImagePrice4k()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -4844,6 +5117,27 @@ func (m *GroupMutation) AddField(name string, value ent.Value) error {
|
||||
}
|
||||
m.AddDefaultValidityDays(v)
|
||||
return nil
|
||||
case group.FieldImagePrice1k:
|
||||
v, ok := value.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.AddImagePrice1k(v)
|
||||
return nil
|
||||
case group.FieldImagePrice2k:
|
||||
v, ok := value.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.AddImagePrice2k(v)
|
||||
return nil
|
||||
case group.FieldImagePrice4k:
|
||||
v, ok := value.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.AddImagePrice4k(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Group numeric field %s", name)
|
||||
}
|
||||
@@ -4867,6 +5161,15 @@ func (m *GroupMutation) ClearedFields() []string {
|
||||
if m.FieldCleared(group.FieldMonthlyLimitUsd) {
|
||||
fields = append(fields, group.FieldMonthlyLimitUsd)
|
||||
}
|
||||
if m.FieldCleared(group.FieldImagePrice1k) {
|
||||
fields = append(fields, group.FieldImagePrice1k)
|
||||
}
|
||||
if m.FieldCleared(group.FieldImagePrice2k) {
|
||||
fields = append(fields, group.FieldImagePrice2k)
|
||||
}
|
||||
if m.FieldCleared(group.FieldImagePrice4k) {
|
||||
fields = append(fields, group.FieldImagePrice4k)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -4896,6 +5199,15 @@ func (m *GroupMutation) ClearField(name string) error {
|
||||
case group.FieldMonthlyLimitUsd:
|
||||
m.ClearMonthlyLimitUsd()
|
||||
return nil
|
||||
case group.FieldImagePrice1k:
|
||||
m.ClearImagePrice1k()
|
||||
return nil
|
||||
case group.FieldImagePrice2k:
|
||||
m.ClearImagePrice2k()
|
||||
return nil
|
||||
case group.FieldImagePrice4k:
|
||||
m.ClearImagePrice4k()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Group nullable field %s", name)
|
||||
}
|
||||
@@ -4946,6 +5258,15 @@ func (m *GroupMutation) ResetField(name string) error {
|
||||
case group.FieldDefaultValidityDays:
|
||||
m.ResetDefaultValidityDays()
|
||||
return nil
|
||||
case group.FieldImagePrice1k:
|
||||
m.ResetImagePrice1k()
|
||||
return nil
|
||||
case group.FieldImagePrice2k:
|
||||
m.ResetImagePrice2k()
|
||||
return nil
|
||||
case group.FieldImagePrice4k:
|
||||
m.ResetImagePrice4k()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Group field %s", name)
|
||||
}
|
||||
@@ -7713,6 +8034,9 @@ type UsageLogMutation struct {
|
||||
addduration_ms *int
|
||||
first_token_ms *int
|
||||
addfirst_token_ms *int
|
||||
image_count *int
|
||||
addimage_count *int
|
||||
image_size *string
|
||||
created_at *time.Time
|
||||
clearedFields map[string]struct{}
|
||||
user *int64
|
||||
@@ -9066,6 +9390,111 @@ func (m *UsageLogMutation) ResetFirstTokenMs() {
|
||||
delete(m.clearedFields, usagelog.FieldFirstTokenMs)
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (m *UsageLogMutation) SetImageCount(i int) {
|
||||
m.image_count = &i
|
||||
m.addimage_count = nil
|
||||
}
|
||||
|
||||
// ImageCount returns the value of the "image_count" field in the mutation.
|
||||
func (m *UsageLogMutation) ImageCount() (r int, exists bool) {
|
||||
v := m.image_count
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldImageCount returns the old "image_count" field's value of the UsageLog entity.
|
||||
// If the UsageLog object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *UsageLogMutation) OldImageCount(ctx context.Context) (v int, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldImageCount is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldImageCount requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldImageCount: %w", err)
|
||||
}
|
||||
return oldValue.ImageCount, nil
|
||||
}
|
||||
|
||||
// AddImageCount adds i to the "image_count" field.
|
||||
func (m *UsageLogMutation) AddImageCount(i int) {
|
||||
if m.addimage_count != nil {
|
||||
*m.addimage_count += i
|
||||
} else {
|
||||
m.addimage_count = &i
|
||||
}
|
||||
}
|
||||
|
||||
// AddedImageCount returns the value that was added to the "image_count" field in this mutation.
|
||||
func (m *UsageLogMutation) AddedImageCount() (r int, exists bool) {
|
||||
v := m.addimage_count
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// ResetImageCount resets all changes to the "image_count" field.
|
||||
func (m *UsageLogMutation) ResetImageCount() {
|
||||
m.image_count = nil
|
||||
m.addimage_count = nil
|
||||
}
|
||||
|
||||
// SetImageSize sets the "image_size" field.
|
||||
func (m *UsageLogMutation) SetImageSize(s string) {
|
||||
m.image_size = &s
|
||||
}
|
||||
|
||||
// ImageSize returns the value of the "image_size" field in the mutation.
|
||||
func (m *UsageLogMutation) ImageSize() (r string, exists bool) {
|
||||
v := m.image_size
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldImageSize returns the old "image_size" field's value of the UsageLog entity.
|
||||
// If the UsageLog object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *UsageLogMutation) OldImageSize(ctx context.Context) (v *string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldImageSize is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldImageSize requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldImageSize: %w", err)
|
||||
}
|
||||
return oldValue.ImageSize, nil
|
||||
}
|
||||
|
||||
// ClearImageSize clears the value of the "image_size" field.
|
||||
func (m *UsageLogMutation) ClearImageSize() {
|
||||
m.image_size = nil
|
||||
m.clearedFields[usagelog.FieldImageSize] = struct{}{}
|
||||
}
|
||||
|
||||
// ImageSizeCleared returns if the "image_size" field was cleared in this mutation.
|
||||
func (m *UsageLogMutation) ImageSizeCleared() bool {
|
||||
_, ok := m.clearedFields[usagelog.FieldImageSize]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetImageSize resets all changes to the "image_size" field.
|
||||
func (m *UsageLogMutation) ResetImageSize() {
|
||||
m.image_size = nil
|
||||
delete(m.clearedFields, usagelog.FieldImageSize)
|
||||
}
|
||||
|
||||
// SetCreatedAt sets the "created_at" field.
|
||||
func (m *UsageLogMutation) SetCreatedAt(t time.Time) {
|
||||
m.created_at = &t
|
||||
@@ -9271,7 +9700,7 @@ func (m *UsageLogMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *UsageLogMutation) Fields() []string {
|
||||
fields := make([]string, 0, 25)
|
||||
fields := make([]string, 0, 27)
|
||||
if m.user != nil {
|
||||
fields = append(fields, usagelog.FieldUserID)
|
||||
}
|
||||
@@ -9344,6 +9773,12 @@ func (m *UsageLogMutation) Fields() []string {
|
||||
if m.first_token_ms != nil {
|
||||
fields = append(fields, usagelog.FieldFirstTokenMs)
|
||||
}
|
||||
if m.image_count != nil {
|
||||
fields = append(fields, usagelog.FieldImageCount)
|
||||
}
|
||||
if m.image_size != nil {
|
||||
fields = append(fields, usagelog.FieldImageSize)
|
||||
}
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, usagelog.FieldCreatedAt)
|
||||
}
|
||||
@@ -9403,6 +9838,10 @@ func (m *UsageLogMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.DurationMs()
|
||||
case usagelog.FieldFirstTokenMs:
|
||||
return m.FirstTokenMs()
|
||||
case usagelog.FieldImageCount:
|
||||
return m.ImageCount()
|
||||
case usagelog.FieldImageSize:
|
||||
return m.ImageSize()
|
||||
case usagelog.FieldCreatedAt:
|
||||
return m.CreatedAt()
|
||||
}
|
||||
@@ -9462,6 +9901,10 @@ func (m *UsageLogMutation) OldField(ctx context.Context, name string) (ent.Value
|
||||
return m.OldDurationMs(ctx)
|
||||
case usagelog.FieldFirstTokenMs:
|
||||
return m.OldFirstTokenMs(ctx)
|
||||
case usagelog.FieldImageCount:
|
||||
return m.OldImageCount(ctx)
|
||||
case usagelog.FieldImageSize:
|
||||
return m.OldImageSize(ctx)
|
||||
case usagelog.FieldCreatedAt:
|
||||
return m.OldCreatedAt(ctx)
|
||||
}
|
||||
@@ -9641,6 +10084,20 @@ func (m *UsageLogMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetFirstTokenMs(v)
|
||||
return nil
|
||||
case usagelog.FieldImageCount:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetImageCount(v)
|
||||
return nil
|
||||
case usagelog.FieldImageSize:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetImageSize(v)
|
||||
return nil
|
||||
case usagelog.FieldCreatedAt:
|
||||
v, ok := value.(time.Time)
|
||||
if !ok {
|
||||
@@ -9704,6 +10161,9 @@ func (m *UsageLogMutation) AddedFields() []string {
|
||||
if m.addfirst_token_ms != nil {
|
||||
fields = append(fields, usagelog.FieldFirstTokenMs)
|
||||
}
|
||||
if m.addimage_count != nil {
|
||||
fields = append(fields, usagelog.FieldImageCount)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -9744,6 +10204,8 @@ func (m *UsageLogMutation) AddedField(name string) (ent.Value, bool) {
|
||||
return m.AddedDurationMs()
|
||||
case usagelog.FieldFirstTokenMs:
|
||||
return m.AddedFirstTokenMs()
|
||||
case usagelog.FieldImageCount:
|
||||
return m.AddedImageCount()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -9865,6 +10327,13 @@ func (m *UsageLogMutation) AddField(name string, value ent.Value) error {
|
||||
}
|
||||
m.AddFirstTokenMs(v)
|
||||
return nil
|
||||
case usagelog.FieldImageCount:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.AddImageCount(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown UsageLog numeric field %s", name)
|
||||
}
|
||||
@@ -9885,6 +10354,9 @@ func (m *UsageLogMutation) ClearedFields() []string {
|
||||
if m.FieldCleared(usagelog.FieldFirstTokenMs) {
|
||||
fields = append(fields, usagelog.FieldFirstTokenMs)
|
||||
}
|
||||
if m.FieldCleared(usagelog.FieldImageSize) {
|
||||
fields = append(fields, usagelog.FieldImageSize)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -9911,6 +10383,9 @@ func (m *UsageLogMutation) ClearField(name string) error {
|
||||
case usagelog.FieldFirstTokenMs:
|
||||
m.ClearFirstTokenMs()
|
||||
return nil
|
||||
case usagelog.FieldImageSize:
|
||||
m.ClearImageSize()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown UsageLog nullable field %s", name)
|
||||
}
|
||||
@@ -9991,6 +10466,12 @@ func (m *UsageLogMutation) ResetField(name string) error {
|
||||
case usagelog.FieldFirstTokenMs:
|
||||
m.ResetFirstTokenMs()
|
||||
return nil
|
||||
case usagelog.FieldImageCount:
|
||||
m.ResetImageCount()
|
||||
return nil
|
||||
case usagelog.FieldImageSize:
|
||||
m.ResetImageSize()
|
||||
return nil
|
||||
case usagelog.FieldCreatedAt:
|
||||
m.ResetCreatedAt()
|
||||
return nil
|
||||
|
||||
@@ -521,8 +521,16 @@ func init() {
|
||||
usagelogDescStream := usagelogFields[21].Descriptor()
|
||||
// usagelog.DefaultStream holds the default value on creation for the stream field.
|
||||
usagelog.DefaultStream = usagelogDescStream.Default.(bool)
|
||||
// usagelogDescImageCount is the schema descriptor for image_count field.
|
||||
usagelogDescImageCount := usagelogFields[24].Descriptor()
|
||||
// usagelog.DefaultImageCount holds the default value on creation for the image_count field.
|
||||
usagelog.DefaultImageCount = usagelogDescImageCount.Default.(int)
|
||||
// usagelogDescImageSize is the schema descriptor for image_size field.
|
||||
usagelogDescImageSize := usagelogFields[25].Descriptor()
|
||||
// usagelog.ImageSizeValidator is a validator for the "image_size" field. It is called by the builders before save.
|
||||
usagelog.ImageSizeValidator = usagelogDescImageSize.Validators[0].(func(string) error)
|
||||
// usagelogDescCreatedAt is the schema descriptor for created_at field.
|
||||
usagelogDescCreatedAt := usagelogFields[24].Descriptor()
|
||||
usagelogDescCreatedAt := usagelogFields[26].Descriptor()
|
||||
// usagelog.DefaultCreatedAt holds the default value on creation for the created_at field.
|
||||
usagelog.DefaultCreatedAt = usagelogDescCreatedAt.Default.(func() time.Time)
|
||||
userMixin := schema.User{}.Mixin()
|
||||
|
||||
@@ -72,6 +72,20 @@ func (Group) Fields() []ent.Field {
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,8)"}),
|
||||
field.Int("default_validity_days").
|
||||
Default(30),
|
||||
|
||||
// 图片生成计费配置(antigravity 和 gemini 平台使用)
|
||||
field.Float("image_price_1k").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,8)"}),
|
||||
field.Float("image_price_2k").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,8)"}),
|
||||
field.Float("image_price_4k").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,8)"}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,14 @@ func (UsageLog) Fields() []ent.Field {
|
||||
Optional().
|
||||
Nillable(),
|
||||
|
||||
// 图片生成字段(仅 gemini-3-pro-image 等图片模型使用)
|
||||
field.Int("image_count").
|
||||
Default(0),
|
||||
field.String("image_size").
|
||||
MaxLen(10).
|
||||
Optional().
|
||||
Nillable(),
|
||||
|
||||
// 时间戳(只有 created_at,日志不可修改)
|
||||
field.Time("created_at").
|
||||
Default(time.Now).
|
||||
|
||||
@@ -70,6 +70,10 @@ type UsageLog struct {
|
||||
DurationMs *int `json:"duration_ms,omitempty"`
|
||||
// FirstTokenMs holds the value of the "first_token_ms" field.
|
||||
FirstTokenMs *int `json:"first_token_ms,omitempty"`
|
||||
// ImageCount holds the value of the "image_count" field.
|
||||
ImageCount int `json:"image_count,omitempty"`
|
||||
// ImageSize holds the value of the "image_size" field.
|
||||
ImageSize *string `json:"image_size,omitempty"`
|
||||
// CreatedAt holds the value of the "created_at" field.
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
@@ -159,9 +163,9 @@ func (*UsageLog) scanValues(columns []string) ([]any, error) {
|
||||
values[i] = new(sql.NullBool)
|
||||
case usagelog.FieldInputCost, usagelog.FieldOutputCost, usagelog.FieldCacheCreationCost, usagelog.FieldCacheReadCost, usagelog.FieldTotalCost, usagelog.FieldActualCost, usagelog.FieldRateMultiplier:
|
||||
values[i] = new(sql.NullFloat64)
|
||||
case usagelog.FieldID, usagelog.FieldUserID, usagelog.FieldAPIKeyID, usagelog.FieldAccountID, usagelog.FieldGroupID, usagelog.FieldSubscriptionID, usagelog.FieldInputTokens, usagelog.FieldOutputTokens, usagelog.FieldCacheCreationTokens, usagelog.FieldCacheReadTokens, usagelog.FieldCacheCreation5mTokens, usagelog.FieldCacheCreation1hTokens, usagelog.FieldBillingType, usagelog.FieldDurationMs, usagelog.FieldFirstTokenMs:
|
||||
case usagelog.FieldID, usagelog.FieldUserID, usagelog.FieldAPIKeyID, usagelog.FieldAccountID, usagelog.FieldGroupID, usagelog.FieldSubscriptionID, usagelog.FieldInputTokens, usagelog.FieldOutputTokens, usagelog.FieldCacheCreationTokens, usagelog.FieldCacheReadTokens, usagelog.FieldCacheCreation5mTokens, usagelog.FieldCacheCreation1hTokens, usagelog.FieldBillingType, usagelog.FieldDurationMs, usagelog.FieldFirstTokenMs, usagelog.FieldImageCount:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case usagelog.FieldRequestID, usagelog.FieldModel:
|
||||
case usagelog.FieldRequestID, usagelog.FieldModel, usagelog.FieldImageSize:
|
||||
values[i] = new(sql.NullString)
|
||||
case usagelog.FieldCreatedAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
@@ -334,6 +338,19 @@ func (_m *UsageLog) assignValues(columns []string, values []any) error {
|
||||
_m.FirstTokenMs = new(int)
|
||||
*_m.FirstTokenMs = int(value.Int64)
|
||||
}
|
||||
case usagelog.FieldImageCount:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field image_count", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ImageCount = int(value.Int64)
|
||||
}
|
||||
case usagelog.FieldImageSize:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field image_size", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ImageSize = new(string)
|
||||
*_m.ImageSize = value.String
|
||||
}
|
||||
case usagelog.FieldCreatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||
@@ -481,6 +498,14 @@ func (_m *UsageLog) String() string {
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("image_count=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.ImageCount))
|
||||
builder.WriteString(", ")
|
||||
if v := _m.ImageSize; v != nil {
|
||||
builder.WriteString("image_size=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("created_at=")
|
||||
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
|
||||
builder.WriteByte(')')
|
||||
|
||||
@@ -62,6 +62,10 @@ const (
|
||||
FieldDurationMs = "duration_ms"
|
||||
// FieldFirstTokenMs holds the string denoting the first_token_ms field in the database.
|
||||
FieldFirstTokenMs = "first_token_ms"
|
||||
// FieldImageCount holds the string denoting the image_count field in the database.
|
||||
FieldImageCount = "image_count"
|
||||
// FieldImageSize holds the string denoting the image_size field in the database.
|
||||
FieldImageSize = "image_size"
|
||||
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
||||
FieldCreatedAt = "created_at"
|
||||
// EdgeUser holds the string denoting the user edge name in mutations.
|
||||
@@ -140,6 +144,8 @@ var Columns = []string{
|
||||
FieldStream,
|
||||
FieldDurationMs,
|
||||
FieldFirstTokenMs,
|
||||
FieldImageCount,
|
||||
FieldImageSize,
|
||||
FieldCreatedAt,
|
||||
}
|
||||
|
||||
@@ -188,6 +194,10 @@ var (
|
||||
DefaultBillingType int8
|
||||
// DefaultStream holds the default value on creation for the "stream" field.
|
||||
DefaultStream bool
|
||||
// DefaultImageCount holds the default value on creation for the "image_count" field.
|
||||
DefaultImageCount int
|
||||
// ImageSizeValidator is a validator for the "image_size" field. It is called by the builders before save.
|
||||
ImageSizeValidator func(string) error
|
||||
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
||||
DefaultCreatedAt func() time.Time
|
||||
)
|
||||
@@ -320,6 +330,16 @@ func ByFirstTokenMs(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldFirstTokenMs, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByImageCount orders the results by the image_count field.
|
||||
func ByImageCount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldImageCount, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByImageSize orders the results by the image_size field.
|
||||
func ByImageSize(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldImageSize, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCreatedAt orders the results by the created_at field.
|
||||
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||
|
||||
@@ -175,6 +175,16 @@ func FirstTokenMs(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEQ(FieldFirstTokenMs, v))
|
||||
}
|
||||
|
||||
// ImageCount applies equality check predicate on the "image_count" field. It's identical to ImageCountEQ.
|
||||
func ImageCount(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEQ(FieldImageCount, v))
|
||||
}
|
||||
|
||||
// ImageSize applies equality check predicate on the "image_size" field. It's identical to ImageSizeEQ.
|
||||
func ImageSize(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEQ(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||
func CreatedAt(v time.Time) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEQ(FieldCreatedAt, v))
|
||||
@@ -1100,6 +1110,121 @@ func FirstTokenMsNotNil() predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldNotNull(FieldFirstTokenMs))
|
||||
}
|
||||
|
||||
// ImageCountEQ applies the EQ predicate on the "image_count" field.
|
||||
func ImageCountEQ(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEQ(FieldImageCount, v))
|
||||
}
|
||||
|
||||
// ImageCountNEQ applies the NEQ predicate on the "image_count" field.
|
||||
func ImageCountNEQ(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldNEQ(FieldImageCount, v))
|
||||
}
|
||||
|
||||
// ImageCountIn applies the In predicate on the "image_count" field.
|
||||
func ImageCountIn(vs ...int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldIn(FieldImageCount, vs...))
|
||||
}
|
||||
|
||||
// ImageCountNotIn applies the NotIn predicate on the "image_count" field.
|
||||
func ImageCountNotIn(vs ...int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldNotIn(FieldImageCount, vs...))
|
||||
}
|
||||
|
||||
// ImageCountGT applies the GT predicate on the "image_count" field.
|
||||
func ImageCountGT(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldGT(FieldImageCount, v))
|
||||
}
|
||||
|
||||
// ImageCountGTE applies the GTE predicate on the "image_count" field.
|
||||
func ImageCountGTE(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldGTE(FieldImageCount, v))
|
||||
}
|
||||
|
||||
// ImageCountLT applies the LT predicate on the "image_count" field.
|
||||
func ImageCountLT(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldLT(FieldImageCount, v))
|
||||
}
|
||||
|
||||
// ImageCountLTE applies the LTE predicate on the "image_count" field.
|
||||
func ImageCountLTE(v int) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldLTE(FieldImageCount, v))
|
||||
}
|
||||
|
||||
// ImageSizeEQ applies the EQ predicate on the "image_size" field.
|
||||
func ImageSizeEQ(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEQ(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeNEQ applies the NEQ predicate on the "image_size" field.
|
||||
func ImageSizeNEQ(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldNEQ(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeIn applies the In predicate on the "image_size" field.
|
||||
func ImageSizeIn(vs ...string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldIn(FieldImageSize, vs...))
|
||||
}
|
||||
|
||||
// ImageSizeNotIn applies the NotIn predicate on the "image_size" field.
|
||||
func ImageSizeNotIn(vs ...string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldNotIn(FieldImageSize, vs...))
|
||||
}
|
||||
|
||||
// ImageSizeGT applies the GT predicate on the "image_size" field.
|
||||
func ImageSizeGT(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldGT(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeGTE applies the GTE predicate on the "image_size" field.
|
||||
func ImageSizeGTE(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldGTE(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeLT applies the LT predicate on the "image_size" field.
|
||||
func ImageSizeLT(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldLT(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeLTE applies the LTE predicate on the "image_size" field.
|
||||
func ImageSizeLTE(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldLTE(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeContains applies the Contains predicate on the "image_size" field.
|
||||
func ImageSizeContains(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldContains(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeHasPrefix applies the HasPrefix predicate on the "image_size" field.
|
||||
func ImageSizeHasPrefix(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldHasPrefix(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeHasSuffix applies the HasSuffix predicate on the "image_size" field.
|
||||
func ImageSizeHasSuffix(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldHasSuffix(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeIsNil applies the IsNil predicate on the "image_size" field.
|
||||
func ImageSizeIsNil() predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldIsNull(FieldImageSize))
|
||||
}
|
||||
|
||||
// ImageSizeNotNil applies the NotNil predicate on the "image_size" field.
|
||||
func ImageSizeNotNil() predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldNotNull(FieldImageSize))
|
||||
}
|
||||
|
||||
// ImageSizeEqualFold applies the EqualFold predicate on the "image_size" field.
|
||||
func ImageSizeEqualFold(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEqualFold(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// ImageSizeContainsFold applies the ContainsFold predicate on the "image_size" field.
|
||||
func ImageSizeContainsFold(v string) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldContainsFold(FieldImageSize, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.UsageLog {
|
||||
return predicate.UsageLog(sql.FieldEQ(FieldCreatedAt, v))
|
||||
|
||||
@@ -323,6 +323,34 @@ func (_c *UsageLogCreate) SetNillableFirstTokenMs(v *int) *UsageLogCreate {
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (_c *UsageLogCreate) SetImageCount(v int) *UsageLogCreate {
|
||||
_c.mutation.SetImageCount(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableImageCount sets the "image_count" field if the given value is not nil.
|
||||
func (_c *UsageLogCreate) SetNillableImageCount(v *int) *UsageLogCreate {
|
||||
if v != nil {
|
||||
_c.SetImageCount(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetImageSize sets the "image_size" field.
|
||||
func (_c *UsageLogCreate) SetImageSize(v string) *UsageLogCreate {
|
||||
_c.mutation.SetImageSize(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableImageSize sets the "image_size" field if the given value is not nil.
|
||||
func (_c *UsageLogCreate) SetNillableImageSize(v *string) *UsageLogCreate {
|
||||
if v != nil {
|
||||
_c.SetImageSize(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetCreatedAt sets the "created_at" field.
|
||||
func (_c *UsageLogCreate) SetCreatedAt(v time.Time) *UsageLogCreate {
|
||||
_c.mutation.SetCreatedAt(v)
|
||||
@@ -457,6 +485,10 @@ func (_c *UsageLogCreate) defaults() {
|
||||
v := usagelog.DefaultStream
|
||||
_c.mutation.SetStream(v)
|
||||
}
|
||||
if _, ok := _c.mutation.ImageCount(); !ok {
|
||||
v := usagelog.DefaultImageCount
|
||||
_c.mutation.SetImageCount(v)
|
||||
}
|
||||
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||
v := usagelog.DefaultCreatedAt()
|
||||
_c.mutation.SetCreatedAt(v)
|
||||
@@ -535,6 +567,14 @@ func (_c *UsageLogCreate) check() error {
|
||||
if _, ok := _c.mutation.Stream(); !ok {
|
||||
return &ValidationError{Name: "stream", err: errors.New(`ent: missing required field "UsageLog.stream"`)}
|
||||
}
|
||||
if _, ok := _c.mutation.ImageCount(); !ok {
|
||||
return &ValidationError{Name: "image_count", err: errors.New(`ent: missing required field "UsageLog.image_count"`)}
|
||||
}
|
||||
if v, ok := _c.mutation.ImageSize(); ok {
|
||||
if err := usagelog.ImageSizeValidator(v); err != nil {
|
||||
return &ValidationError{Name: "image_size", err: fmt.Errorf(`ent: validator failed for field "UsageLog.image_size": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "UsageLog.created_at"`)}
|
||||
}
|
||||
@@ -650,6 +690,14 @@ func (_c *UsageLogCreate) createSpec() (*UsageLog, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(usagelog.FieldFirstTokenMs, field.TypeInt, value)
|
||||
_node.FirstTokenMs = &value
|
||||
}
|
||||
if value, ok := _c.mutation.ImageCount(); ok {
|
||||
_spec.SetField(usagelog.FieldImageCount, field.TypeInt, value)
|
||||
_node.ImageCount = value
|
||||
}
|
||||
if value, ok := _c.mutation.ImageSize(); ok {
|
||||
_spec.SetField(usagelog.FieldImageSize, field.TypeString, value)
|
||||
_node.ImageSize = &value
|
||||
}
|
||||
if value, ok := _c.mutation.CreatedAt(); ok {
|
||||
_spec.SetField(usagelog.FieldCreatedAt, field.TypeTime, value)
|
||||
_node.CreatedAt = value
|
||||
@@ -1199,6 +1247,42 @@ func (u *UsageLogUpsert) ClearFirstTokenMs() *UsageLogUpsert {
|
||||
return u
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (u *UsageLogUpsert) SetImageCount(v int) *UsageLogUpsert {
|
||||
u.Set(usagelog.FieldImageCount, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateImageCount sets the "image_count" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsert) UpdateImageCount() *UsageLogUpsert {
|
||||
u.SetExcluded(usagelog.FieldImageCount)
|
||||
return u
|
||||
}
|
||||
|
||||
// AddImageCount adds v to the "image_count" field.
|
||||
func (u *UsageLogUpsert) AddImageCount(v int) *UsageLogUpsert {
|
||||
u.Add(usagelog.FieldImageCount, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetImageSize sets the "image_size" field.
|
||||
func (u *UsageLogUpsert) SetImageSize(v string) *UsageLogUpsert {
|
||||
u.Set(usagelog.FieldImageSize, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateImageSize sets the "image_size" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsert) UpdateImageSize() *UsageLogUpsert {
|
||||
u.SetExcluded(usagelog.FieldImageSize)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearImageSize clears the value of the "image_size" field.
|
||||
func (u *UsageLogUpsert) ClearImageSize() *UsageLogUpsert {
|
||||
u.SetNull(usagelog.FieldImageSize)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateNewValues updates the mutable fields using the new values that were set on create.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
@@ -1720,6 +1804,48 @@ func (u *UsageLogUpsertOne) ClearFirstTokenMs() *UsageLogUpsertOne {
|
||||
})
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (u *UsageLogUpsertOne) SetImageCount(v int) *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.SetImageCount(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImageCount adds v to the "image_count" field.
|
||||
func (u *UsageLogUpsertOne) AddImageCount(v int) *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.AddImageCount(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImageCount sets the "image_count" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsertOne) UpdateImageCount() *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.UpdateImageCount()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImageSize sets the "image_size" field.
|
||||
func (u *UsageLogUpsertOne) SetImageSize(v string) *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.SetImageSize(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImageSize sets the "image_size" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsertOne) UpdateImageSize() *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.UpdateImageSize()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImageSize clears the value of the "image_size" field.
|
||||
func (u *UsageLogUpsertOne) ClearImageSize() *UsageLogUpsertOne {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.ClearImageSize()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *UsageLogUpsertOne) Exec(ctx context.Context) error {
|
||||
if len(u.create.conflict) == 0 {
|
||||
@@ -2407,6 +2533,48 @@ func (u *UsageLogUpsertBulk) ClearFirstTokenMs() *UsageLogUpsertBulk {
|
||||
})
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (u *UsageLogUpsertBulk) SetImageCount(v int) *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.SetImageCount(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddImageCount adds v to the "image_count" field.
|
||||
func (u *UsageLogUpsertBulk) AddImageCount(v int) *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.AddImageCount(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImageCount sets the "image_count" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsertBulk) UpdateImageCount() *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.UpdateImageCount()
|
||||
})
|
||||
}
|
||||
|
||||
// SetImageSize sets the "image_size" field.
|
||||
func (u *UsageLogUpsertBulk) SetImageSize(v string) *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.SetImageSize(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateImageSize sets the "image_size" field to the value that was provided on create.
|
||||
func (u *UsageLogUpsertBulk) UpdateImageSize() *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.UpdateImageSize()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearImageSize clears the value of the "image_size" field.
|
||||
func (u *UsageLogUpsertBulk) ClearImageSize() *UsageLogUpsertBulk {
|
||||
return u.Update(func(s *UsageLogUpsert) {
|
||||
s.ClearImageSize()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *UsageLogUpsertBulk) Exec(ctx context.Context) error {
|
||||
if u.create.err != nil {
|
||||
|
||||
@@ -504,6 +504,47 @@ func (_u *UsageLogUpdate) ClearFirstTokenMs() *UsageLogUpdate {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (_u *UsageLogUpdate) SetImageCount(v int) *UsageLogUpdate {
|
||||
_u.mutation.ResetImageCount()
|
||||
_u.mutation.SetImageCount(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImageCount sets the "image_count" field if the given value is not nil.
|
||||
func (_u *UsageLogUpdate) SetNillableImageCount(v *int) *UsageLogUpdate {
|
||||
if v != nil {
|
||||
_u.SetImageCount(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImageCount adds value to the "image_count" field.
|
||||
func (_u *UsageLogUpdate) AddImageCount(v int) *UsageLogUpdate {
|
||||
_u.mutation.AddImageCount(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImageSize sets the "image_size" field.
|
||||
func (_u *UsageLogUpdate) SetImageSize(v string) *UsageLogUpdate {
|
||||
_u.mutation.SetImageSize(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImageSize sets the "image_size" field if the given value is not nil.
|
||||
func (_u *UsageLogUpdate) SetNillableImageSize(v *string) *UsageLogUpdate {
|
||||
if v != nil {
|
||||
_u.SetImageSize(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImageSize clears the value of the "image_size" field.
|
||||
func (_u *UsageLogUpdate) ClearImageSize() *UsageLogUpdate {
|
||||
_u.mutation.ClearImageSize()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetUser sets the "user" edge to the User entity.
|
||||
func (_u *UsageLogUpdate) SetUser(v *User) *UsageLogUpdate {
|
||||
return _u.SetUserID(v.ID)
|
||||
@@ -603,6 +644,11 @@ func (_u *UsageLogUpdate) check() error {
|
||||
return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "UsageLog.model": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.ImageSize(); ok {
|
||||
if err := usagelog.ImageSizeValidator(v); err != nil {
|
||||
return &ValidationError{Name: "image_size", err: fmt.Errorf(`ent: validator failed for field "UsageLog.image_size": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 {
|
||||
return errors.New(`ent: clearing a required unique edge "UsageLog.user"`)
|
||||
}
|
||||
@@ -738,6 +784,18 @@ func (_u *UsageLogUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
if _u.mutation.FirstTokenMsCleared() {
|
||||
_spec.ClearField(usagelog.FieldFirstTokenMs, field.TypeInt)
|
||||
}
|
||||
if value, ok := _u.mutation.ImageCount(); ok {
|
||||
_spec.SetField(usagelog.FieldImageCount, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImageCount(); ok {
|
||||
_spec.AddField(usagelog.FieldImageCount, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ImageSize(); ok {
|
||||
_spec.SetField(usagelog.FieldImageSize, field.TypeString, value)
|
||||
}
|
||||
if _u.mutation.ImageSizeCleared() {
|
||||
_spec.ClearField(usagelog.FieldImageSize, field.TypeString)
|
||||
}
|
||||
if _u.mutation.UserCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
@@ -1375,6 +1433,47 @@ func (_u *UsageLogUpdateOne) ClearFirstTokenMs() *UsageLogUpdateOne {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImageCount sets the "image_count" field.
|
||||
func (_u *UsageLogUpdateOne) SetImageCount(v int) *UsageLogUpdateOne {
|
||||
_u.mutation.ResetImageCount()
|
||||
_u.mutation.SetImageCount(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImageCount sets the "image_count" field if the given value is not nil.
|
||||
func (_u *UsageLogUpdateOne) SetNillableImageCount(v *int) *UsageLogUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetImageCount(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddImageCount adds value to the "image_count" field.
|
||||
func (_u *UsageLogUpdateOne) AddImageCount(v int) *UsageLogUpdateOne {
|
||||
_u.mutation.AddImageCount(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetImageSize sets the "image_size" field.
|
||||
func (_u *UsageLogUpdateOne) SetImageSize(v string) *UsageLogUpdateOne {
|
||||
_u.mutation.SetImageSize(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableImageSize sets the "image_size" field if the given value is not nil.
|
||||
func (_u *UsageLogUpdateOne) SetNillableImageSize(v *string) *UsageLogUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetImageSize(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearImageSize clears the value of the "image_size" field.
|
||||
func (_u *UsageLogUpdateOne) ClearImageSize() *UsageLogUpdateOne {
|
||||
_u.mutation.ClearImageSize()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetUser sets the "user" edge to the User entity.
|
||||
func (_u *UsageLogUpdateOne) SetUser(v *User) *UsageLogUpdateOne {
|
||||
return _u.SetUserID(v.ID)
|
||||
@@ -1487,6 +1586,11 @@ func (_u *UsageLogUpdateOne) check() error {
|
||||
return &ValidationError{Name: "model", err: fmt.Errorf(`ent: validator failed for field "UsageLog.model": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.ImageSize(); ok {
|
||||
if err := usagelog.ImageSizeValidator(v); err != nil {
|
||||
return &ValidationError{Name: "image_size", err: fmt.Errorf(`ent: validator failed for field "UsageLog.image_size": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 {
|
||||
return errors.New(`ent: clearing a required unique edge "UsageLog.user"`)
|
||||
}
|
||||
@@ -1639,6 +1743,18 @@ func (_u *UsageLogUpdateOne) sqlSave(ctx context.Context) (_node *UsageLog, err
|
||||
if _u.mutation.FirstTokenMsCleared() {
|
||||
_spec.ClearField(usagelog.FieldFirstTokenMs, field.TypeInt)
|
||||
}
|
||||
if value, ok := _u.mutation.ImageCount(); ok {
|
||||
_spec.SetField(usagelog.FieldImageCount, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedImageCount(); ok {
|
||||
_spec.AddField(usagelog.FieldImageCount, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ImageSize(); ok {
|
||||
_spec.SetField(usagelog.FieldImageSize, field.TypeString, value)
|
||||
}
|
||||
if _u.mutation.ImageSizeCleared() {
|
||||
_spec.ClearField(usagelog.FieldImageSize, field.TypeString)
|
||||
}
|
||||
if _u.mutation.UserCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
|
||||
@@ -33,6 +33,10 @@ type CreateGroupRequest struct {
|
||||
DailyLimitUSD *float64 `json:"daily_limit_usd"`
|
||||
WeeklyLimitUSD *float64 `json:"weekly_limit_usd"`
|
||||
MonthlyLimitUSD *float64 `json:"monthly_limit_usd"`
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
ImagePrice1K *float64 `json:"image_price_1k"`
|
||||
ImagePrice2K *float64 `json:"image_price_2k"`
|
||||
ImagePrice4K *float64 `json:"image_price_4k"`
|
||||
}
|
||||
|
||||
// UpdateGroupRequest represents update group request
|
||||
@@ -47,6 +51,10 @@ type UpdateGroupRequest struct {
|
||||
DailyLimitUSD *float64 `json:"daily_limit_usd"`
|
||||
WeeklyLimitUSD *float64 `json:"weekly_limit_usd"`
|
||||
MonthlyLimitUSD *float64 `json:"monthly_limit_usd"`
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
ImagePrice1K *float64 `json:"image_price_1k"`
|
||||
ImagePrice2K *float64 `json:"image_price_2k"`
|
||||
ImagePrice4K *float64 `json:"image_price_4k"`
|
||||
}
|
||||
|
||||
// List handles listing all groups with pagination
|
||||
@@ -139,6 +147,9 @@ func (h *GroupHandler) Create(c *gin.Context) {
|
||||
DailyLimitUSD: req.DailyLimitUSD,
|
||||
WeeklyLimitUSD: req.WeeklyLimitUSD,
|
||||
MonthlyLimitUSD: req.MonthlyLimitUSD,
|
||||
ImagePrice1K: req.ImagePrice1K,
|
||||
ImagePrice2K: req.ImagePrice2K,
|
||||
ImagePrice4K: req.ImagePrice4K,
|
||||
})
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
@@ -174,6 +185,9 @@ func (h *GroupHandler) Update(c *gin.Context) {
|
||||
DailyLimitUSD: req.DailyLimitUSD,
|
||||
WeeklyLimitUSD: req.WeeklyLimitUSD,
|
||||
MonthlyLimitUSD: req.MonthlyLimitUSD,
|
||||
ImagePrice1K: req.ImagePrice1K,
|
||||
ImagePrice2K: req.ImagePrice2K,
|
||||
ImagePrice4K: req.ImagePrice4K,
|
||||
})
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
|
||||
@@ -78,6 +78,9 @@ func GroupFromServiceShallow(g *service.Group) *Group {
|
||||
DailyLimitUSD: g.DailyLimitUSD,
|
||||
WeeklyLimitUSD: g.WeeklyLimitUSD,
|
||||
MonthlyLimitUSD: g.MonthlyLimitUSD,
|
||||
ImagePrice1K: g.ImagePrice1K,
|
||||
ImagePrice2K: g.ImagePrice2K,
|
||||
ImagePrice4K: g.ImagePrice4K,
|
||||
CreatedAt: g.CreatedAt,
|
||||
UpdatedAt: g.UpdatedAt,
|
||||
AccountCount: g.AccountCount,
|
||||
@@ -246,6 +249,8 @@ func UsageLogFromService(l *service.UsageLog) *UsageLog {
|
||||
Stream: l.Stream,
|
||||
DurationMs: l.DurationMs,
|
||||
FirstTokenMs: l.FirstTokenMs,
|
||||
ImageCount: l.ImageCount,
|
||||
ImageSize: l.ImageSize,
|
||||
CreatedAt: l.CreatedAt,
|
||||
User: UserFromServiceShallow(l.User),
|
||||
APIKey: APIKeyFromService(l.APIKey),
|
||||
|
||||
@@ -47,6 +47,11 @@ type Group struct {
|
||||
WeeklyLimitUSD *float64 `json:"weekly_limit_usd"`
|
||||
MonthlyLimitUSD *float64 `json:"monthly_limit_usd"`
|
||||
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
ImagePrice1K *float64 `json:"image_price_1k"`
|
||||
ImagePrice2K *float64 `json:"image_price_2k"`
|
||||
ImagePrice4K *float64 `json:"image_price_4k"`
|
||||
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
@@ -168,6 +173,10 @@ type UsageLog struct {
|
||||
DurationMs *int `json:"duration_ms"`
|
||||
FirstTokenMs *int `json:"first_token_ms"`
|
||||
|
||||
// 图片生成字段
|
||||
ImageCount int `json:"image_count"`
|
||||
ImageSize *string `json:"image_size"`
|
||||
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
User *User `json:"user,omitempty"`
|
||||
|
||||
@@ -67,6 +67,13 @@ type GeminiGenerationConfig struct {
|
||||
TopK *int `json:"topK,omitempty"`
|
||||
ThinkingConfig *GeminiThinkingConfig `json:"thinkingConfig,omitempty"`
|
||||
StopSequences []string `json:"stopSequences,omitempty"`
|
||||
ImageConfig *GeminiImageConfig `json:"imageConfig,omitempty"`
|
||||
}
|
||||
|
||||
// GeminiImageConfig Gemini 图片生成配置(仅 gemini-3-pro-image 支持)
|
||||
type GeminiImageConfig struct {
|
||||
AspectRatio string `json:"aspectRatio,omitempty"` // "1:1", "16:9", "9:16", "4:3", "3:4"
|
||||
ImageSize string `json:"imageSize,omitempty"` // "1K", "2K", "4K"
|
||||
}
|
||||
|
||||
// GeminiThinkingConfig Gemini thinking 配置
|
||||
|
||||
@@ -321,6 +321,9 @@ func groupEntityToService(g *dbent.Group) *service.Group {
|
||||
DailyLimitUSD: g.DailyLimitUsd,
|
||||
WeeklyLimitUSD: g.WeeklyLimitUsd,
|
||||
MonthlyLimitUSD: g.MonthlyLimitUsd,
|
||||
ImagePrice1K: g.ImagePrice1k,
|
||||
ImagePrice2K: g.ImagePrice2k,
|
||||
ImagePrice4K: g.ImagePrice4k,
|
||||
DefaultValidityDays: g.DefaultValidityDays,
|
||||
CreatedAt: g.CreatedAt,
|
||||
UpdatedAt: g.UpdatedAt,
|
||||
|
||||
@@ -43,6 +43,9 @@ func (r *groupRepository) Create(ctx context.Context, groupIn *service.Group) er
|
||||
SetNillableDailyLimitUsd(groupIn.DailyLimitUSD).
|
||||
SetNillableWeeklyLimitUsd(groupIn.WeeklyLimitUSD).
|
||||
SetNillableMonthlyLimitUsd(groupIn.MonthlyLimitUSD).
|
||||
SetNillableImagePrice1k(groupIn.ImagePrice1K).
|
||||
SetNillableImagePrice2k(groupIn.ImagePrice2K).
|
||||
SetNillableImagePrice4k(groupIn.ImagePrice4K).
|
||||
SetDefaultValidityDays(groupIn.DefaultValidityDays)
|
||||
|
||||
created, err := builder.Save(ctx)
|
||||
@@ -80,6 +83,9 @@ func (r *groupRepository) Update(ctx context.Context, groupIn *service.Group) er
|
||||
SetNillableDailyLimitUsd(groupIn.DailyLimitUSD).
|
||||
SetNillableWeeklyLimitUsd(groupIn.WeeklyLimitUSD).
|
||||
SetNillableMonthlyLimitUsd(groupIn.MonthlyLimitUSD).
|
||||
SetNillableImagePrice1k(groupIn.ImagePrice1K).
|
||||
SetNillableImagePrice2k(groupIn.ImagePrice2K).
|
||||
SetNillableImagePrice4k(groupIn.ImagePrice4K).
|
||||
SetDefaultValidityDays(groupIn.DefaultValidityDays).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
const usageLogSelectColumns = "id, user_id, api_key_id, account_id, request_id, model, group_id, subscription_id, input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens, cache_creation_5m_tokens, cache_creation_1h_tokens, input_cost, output_cost, cache_creation_cost, cache_read_cost, total_cost, actual_cost, rate_multiplier, billing_type, stream, duration_ms, first_token_ms, created_at"
|
||||
const usageLogSelectColumns = "id, user_id, api_key_id, account_id, request_id, model, group_id, subscription_id, input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens, cache_creation_5m_tokens, cache_creation_1h_tokens, input_cost, output_cost, cache_creation_cost, cache_read_cost, total_cost, actual_cost, rate_multiplier, billing_type, stream, duration_ms, first_token_ms, image_count, image_size, created_at"
|
||||
|
||||
type usageLogRepository struct {
|
||||
client *dbent.Client
|
||||
@@ -109,6 +109,8 @@ func (r *usageLogRepository) Create(ctx context.Context, log *service.UsageLog)
|
||||
stream,
|
||||
duration_ms,
|
||||
first_token_ms,
|
||||
image_count,
|
||||
image_size,
|
||||
created_at
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
@@ -116,7 +118,8 @@ func (r *usageLogRepository) Create(ctx context.Context, log *service.UsageLog)
|
||||
$8, $9, $10, $11,
|
||||
$12, $13,
|
||||
$14, $15, $16, $17, $18, $19,
|
||||
$20, $21, $22, $23, $24, $25
|
||||
$20, $21, $22, $23, $24,
|
||||
$25, $26, $27
|
||||
)
|
||||
ON CONFLICT (request_id, api_key_id) DO NOTHING
|
||||
RETURNING id, created_at
|
||||
@@ -126,6 +129,7 @@ func (r *usageLogRepository) Create(ctx context.Context, log *service.UsageLog)
|
||||
subscriptionID := nullInt64(log.SubscriptionID)
|
||||
duration := nullInt(log.DurationMs)
|
||||
firstToken := nullInt(log.FirstTokenMs)
|
||||
imageSize := nullString(log.ImageSize)
|
||||
|
||||
var requestIDArg any
|
||||
if requestID != "" {
|
||||
@@ -157,6 +161,8 @@ func (r *usageLogRepository) Create(ctx context.Context, log *service.UsageLog)
|
||||
log.Stream,
|
||||
duration,
|
||||
firstToken,
|
||||
log.ImageCount,
|
||||
imageSize,
|
||||
createdAt,
|
||||
}
|
||||
if err := scanSingleRow(ctx, sqlq, query, args, &log.ID, &log.CreatedAt); err != nil {
|
||||
@@ -1789,6 +1795,8 @@ func scanUsageLog(scanner interface{ Scan(...any) error }) (*service.UsageLog, e
|
||||
stream bool
|
||||
durationMs sql.NullInt64
|
||||
firstTokenMs sql.NullInt64
|
||||
imageCount int
|
||||
imageSize sql.NullString
|
||||
createdAt time.Time
|
||||
)
|
||||
|
||||
@@ -1818,6 +1826,8 @@ func scanUsageLog(scanner interface{ Scan(...any) error }) (*service.UsageLog, e
|
||||
&stream,
|
||||
&durationMs,
|
||||
&firstTokenMs,
|
||||
&imageCount,
|
||||
&imageSize,
|
||||
&createdAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
@@ -1844,6 +1854,7 @@ func scanUsageLog(scanner interface{ Scan(...any) error }) (*service.UsageLog, e
|
||||
RateMultiplier: rateMultiplier,
|
||||
BillingType: int8(billingType),
|
||||
Stream: stream,
|
||||
ImageCount: imageCount,
|
||||
CreatedAt: createdAt,
|
||||
}
|
||||
|
||||
@@ -1866,6 +1877,9 @@ func scanUsageLog(scanner interface{ Scan(...any) error }) (*service.UsageLog, e
|
||||
value := int(firstTokenMs.Int64)
|
||||
log.FirstTokenMs = &value
|
||||
}
|
||||
if imageSize.Valid {
|
||||
log.ImageSize = &imageSize.String
|
||||
}
|
||||
|
||||
return log, nil
|
||||
}
|
||||
@@ -1938,6 +1952,13 @@ func nullInt(v *int) sql.NullInt64 {
|
||||
return sql.NullInt64{Int64: int64(*v), Valid: true}
|
||||
}
|
||||
|
||||
func nullString(v *string) sql.NullString {
|
||||
if v == nil || *v == "" {
|
||||
return sql.NullString{}
|
||||
}
|
||||
return sql.NullString{String: *v, Valid: true}
|
||||
}
|
||||
|
||||
func setToSlice(set map[int64]struct{}) []int64 {
|
||||
out := make([]int64, 0, len(set))
|
||||
for id := range set {
|
||||
|
||||
@@ -98,6 +98,10 @@ type CreateGroupInput struct {
|
||||
DailyLimitUSD *float64 // 日限额 (USD)
|
||||
WeeklyLimitUSD *float64 // 周限额 (USD)
|
||||
MonthlyLimitUSD *float64 // 月限额 (USD)
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
ImagePrice1K *float64
|
||||
ImagePrice2K *float64
|
||||
ImagePrice4K *float64
|
||||
}
|
||||
|
||||
type UpdateGroupInput struct {
|
||||
@@ -111,6 +115,10 @@ type UpdateGroupInput struct {
|
||||
DailyLimitUSD *float64 // 日限额 (USD)
|
||||
WeeklyLimitUSD *float64 // 周限额 (USD)
|
||||
MonthlyLimitUSD *float64 // 月限额 (USD)
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
ImagePrice1K *float64
|
||||
ImagePrice2K *float64
|
||||
ImagePrice4K *float64
|
||||
}
|
||||
|
||||
type CreateAccountInput struct {
|
||||
@@ -507,6 +515,9 @@ func (s *adminServiceImpl) CreateGroup(ctx context.Context, input *CreateGroupIn
|
||||
DailyLimitUSD: dailyLimit,
|
||||
WeeklyLimitUSD: weeklyLimit,
|
||||
MonthlyLimitUSD: monthlyLimit,
|
||||
ImagePrice1K: input.ImagePrice1K,
|
||||
ImagePrice2K: input.ImagePrice2K,
|
||||
ImagePrice4K: input.ImagePrice4K,
|
||||
}
|
||||
if err := s.groupRepo.Create(ctx, group); err != nil {
|
||||
return nil, err
|
||||
@@ -561,6 +572,16 @@ func (s *adminServiceImpl) UpdateGroup(ctx context.Context, id int64, input *Upd
|
||||
if input.MonthlyLimitUSD != nil {
|
||||
group.MonthlyLimitUSD = normalizeLimit(input.MonthlyLimitUSD)
|
||||
}
|
||||
// 图片生成计费配置
|
||||
if input.ImagePrice1K != nil {
|
||||
group.ImagePrice1K = input.ImagePrice1K
|
||||
}
|
||||
if input.ImagePrice2K != nil {
|
||||
group.ImagePrice2K = input.ImagePrice2K
|
||||
}
|
||||
if input.ImagePrice4K != nil {
|
||||
group.ImagePrice4K = input.ImagePrice4K
|
||||
}
|
||||
|
||||
if err := s.groupRepo.Update(ctx, group); err != nil {
|
||||
return nil, err
|
||||
|
||||
197
backend/internal/service/admin_service_group_test.go
Normal file
197
backend/internal/service/admin_service_group_test.go
Normal file
@@ -0,0 +1,197 @@
|
||||
//go:build unit
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// groupRepoStubForAdmin 用于测试 AdminService 的 GroupRepository Stub
|
||||
type groupRepoStubForAdmin struct {
|
||||
created *Group // 记录 Create 调用的参数
|
||||
updated *Group // 记录 Update 调用的参数
|
||||
getByID *Group // GetByID 返回值
|
||||
getErr error // GetByID 返回的错误
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) Create(_ context.Context, g *Group) error {
|
||||
s.created = g
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) Update(_ context.Context, g *Group) error {
|
||||
s.updated = g
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) GetByID(_ context.Context, _ int64) (*Group, error) {
|
||||
if s.getErr != nil {
|
||||
return nil, s.getErr
|
||||
}
|
||||
return s.getByID, nil
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) Delete(_ context.Context, _ int64) error {
|
||||
panic("unexpected Delete call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) DeleteCascade(_ context.Context, _ int64) ([]int64, error) {
|
||||
panic("unexpected DeleteCascade call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) List(_ context.Context, _ pagination.PaginationParams) ([]Group, *pagination.PaginationResult, error) {
|
||||
panic("unexpected List call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) ListWithFilters(_ context.Context, _ pagination.PaginationParams, _, _ string, _ *bool) ([]Group, *pagination.PaginationResult, error) {
|
||||
panic("unexpected ListWithFilters call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) ListActive(_ context.Context) ([]Group, error) {
|
||||
panic("unexpected ListActive call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) ListActiveByPlatform(_ context.Context, _ string) ([]Group, error) {
|
||||
panic("unexpected ListActiveByPlatform call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) ExistsByName(_ context.Context, _ string) (bool, error) {
|
||||
panic("unexpected ExistsByName call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) GetAccountCount(_ context.Context, _ int64) (int64, error) {
|
||||
panic("unexpected GetAccountCount call")
|
||||
}
|
||||
|
||||
func (s *groupRepoStubForAdmin) DeleteAccountGroupsByGroupID(_ context.Context, _ int64) (int64, error) {
|
||||
panic("unexpected DeleteAccountGroupsByGroupID call")
|
||||
}
|
||||
|
||||
// TestAdminService_CreateGroup_WithImagePricing 测试创建分组时 ImagePrice 字段正确传递
|
||||
func TestAdminService_CreateGroup_WithImagePricing(t *testing.T) {
|
||||
repo := &groupRepoStubForAdmin{}
|
||||
svc := &adminServiceImpl{groupRepo: repo}
|
||||
|
||||
price1K := 0.10
|
||||
price2K := 0.15
|
||||
price4K := 0.30
|
||||
|
||||
input := &CreateGroupInput{
|
||||
Name: "test-group",
|
||||
Description: "Test group",
|
||||
Platform: PlatformAntigravity,
|
||||
RateMultiplier: 1.0,
|
||||
ImagePrice1K: &price1K,
|
||||
ImagePrice2K: &price2K,
|
||||
ImagePrice4K: &price4K,
|
||||
}
|
||||
|
||||
group, err := svc.CreateGroup(context.Background(), input)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, group)
|
||||
|
||||
// 验证 repo 收到了正确的字段
|
||||
require.NotNil(t, repo.created)
|
||||
require.NotNil(t, repo.created.ImagePrice1K)
|
||||
require.NotNil(t, repo.created.ImagePrice2K)
|
||||
require.NotNil(t, repo.created.ImagePrice4K)
|
||||
require.InDelta(t, 0.10, *repo.created.ImagePrice1K, 0.0001)
|
||||
require.InDelta(t, 0.15, *repo.created.ImagePrice2K, 0.0001)
|
||||
require.InDelta(t, 0.30, *repo.created.ImagePrice4K, 0.0001)
|
||||
}
|
||||
|
||||
// TestAdminService_CreateGroup_NilImagePricing 测试 ImagePrice 为 nil 时正常创建
|
||||
func TestAdminService_CreateGroup_NilImagePricing(t *testing.T) {
|
||||
repo := &groupRepoStubForAdmin{}
|
||||
svc := &adminServiceImpl{groupRepo: repo}
|
||||
|
||||
input := &CreateGroupInput{
|
||||
Name: "test-group",
|
||||
Description: "Test group",
|
||||
Platform: PlatformAntigravity,
|
||||
RateMultiplier: 1.0,
|
||||
// ImagePrice 字段全部为 nil
|
||||
}
|
||||
|
||||
group, err := svc.CreateGroup(context.Background(), input)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, group)
|
||||
|
||||
// 验证 ImagePrice 字段为 nil
|
||||
require.NotNil(t, repo.created)
|
||||
require.Nil(t, repo.created.ImagePrice1K)
|
||||
require.Nil(t, repo.created.ImagePrice2K)
|
||||
require.Nil(t, repo.created.ImagePrice4K)
|
||||
}
|
||||
|
||||
// TestAdminService_UpdateGroup_WithImagePricing 测试更新分组时 ImagePrice 字段正确更新
|
||||
func TestAdminService_UpdateGroup_WithImagePricing(t *testing.T) {
|
||||
existingGroup := &Group{
|
||||
ID: 1,
|
||||
Name: "existing-group",
|
||||
Platform: PlatformAntigravity,
|
||||
Status: StatusActive,
|
||||
}
|
||||
repo := &groupRepoStubForAdmin{getByID: existingGroup}
|
||||
svc := &adminServiceImpl{groupRepo: repo}
|
||||
|
||||
price1K := 0.12
|
||||
price2K := 0.18
|
||||
price4K := 0.36
|
||||
|
||||
input := &UpdateGroupInput{
|
||||
ImagePrice1K: &price1K,
|
||||
ImagePrice2K: &price2K,
|
||||
ImagePrice4K: &price4K,
|
||||
}
|
||||
|
||||
group, err := svc.UpdateGroup(context.Background(), 1, input)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, group)
|
||||
|
||||
// 验证 repo 收到了更新后的字段
|
||||
require.NotNil(t, repo.updated)
|
||||
require.NotNil(t, repo.updated.ImagePrice1K)
|
||||
require.NotNil(t, repo.updated.ImagePrice2K)
|
||||
require.NotNil(t, repo.updated.ImagePrice4K)
|
||||
require.InDelta(t, 0.12, *repo.updated.ImagePrice1K, 0.0001)
|
||||
require.InDelta(t, 0.18, *repo.updated.ImagePrice2K, 0.0001)
|
||||
require.InDelta(t, 0.36, *repo.updated.ImagePrice4K, 0.0001)
|
||||
}
|
||||
|
||||
// TestAdminService_UpdateGroup_PartialImagePricing 测试仅更新部分 ImagePrice 字段
|
||||
func TestAdminService_UpdateGroup_PartialImagePricing(t *testing.T) {
|
||||
oldPrice2K := 0.15
|
||||
existingGroup := &Group{
|
||||
ID: 1,
|
||||
Name: "existing-group",
|
||||
Platform: PlatformAntigravity,
|
||||
Status: StatusActive,
|
||||
ImagePrice2K: &oldPrice2K, // 已有 2K 价格
|
||||
}
|
||||
repo := &groupRepoStubForAdmin{getByID: existingGroup}
|
||||
svc := &adminServiceImpl{groupRepo: repo}
|
||||
|
||||
// 只更新 1K 价格
|
||||
price1K := 0.10
|
||||
input := &UpdateGroupInput{
|
||||
ImagePrice1K: &price1K,
|
||||
// ImagePrice2K 和 ImagePrice4K 为 nil,不更新
|
||||
}
|
||||
|
||||
group, err := svc.UpdateGroup(context.Background(), 1, input)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, group)
|
||||
|
||||
// 验证:1K 被更新,2K 保持原值,4K 仍为 nil
|
||||
require.NotNil(t, repo.updated)
|
||||
require.NotNil(t, repo.updated.ImagePrice1K)
|
||||
require.InDelta(t, 0.10, *repo.updated.ImagePrice1K, 0.0001)
|
||||
require.NotNil(t, repo.updated.ImagePrice2K)
|
||||
require.InDelta(t, 0.15, *repo.updated.ImagePrice2K, 0.0001) // 原值保持
|
||||
require.Nil(t, repo.updated.ImagePrice4K)
|
||||
}
|
||||
@@ -652,6 +652,9 @@ func (s *AntigravityGatewayService) ForwardGemini(ctx context.Context, c *gin.Co
|
||||
return nil, s.writeGoogleError(c, http.StatusBadRequest, "Request body is empty")
|
||||
}
|
||||
|
||||
// 解析请求以获取 image_size(用于图片计费)
|
||||
imageSize := s.extractImageSize(body)
|
||||
|
||||
switch action {
|
||||
case "generateContent", "streamGenerateContent":
|
||||
// ok
|
||||
@@ -832,6 +835,13 @@ handleSuccess:
|
||||
usage = &ClaudeUsage{}
|
||||
}
|
||||
|
||||
// 判断是否为图片生成模型
|
||||
imageCount := 0
|
||||
if isImageGenerationModel(mappedModel) {
|
||||
// 图片模型按次计费,默认 1 张图片
|
||||
imageCount = 1
|
||||
}
|
||||
|
||||
return &ForwardResult{
|
||||
RequestID: requestID,
|
||||
Usage: *usage,
|
||||
@@ -839,6 +849,8 @@ handleSuccess:
|
||||
Stream: stream,
|
||||
Duration: time.Since(startTime),
|
||||
FirstTokenMs: firstTokenMs,
|
||||
ImageCount: imageCount,
|
||||
ImageSize: imageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -1161,3 +1173,27 @@ func (s *AntigravityGatewayService) handleClaudeStreamingResponse(c *gin.Context
|
||||
|
||||
return &antigravityStreamResult{usage: convertUsage(agUsage), firstTokenMs: firstTokenMs}, nil
|
||||
}
|
||||
|
||||
// extractImageSize 从 Gemini 请求中提取 image_size 参数
|
||||
func (s *AntigravityGatewayService) extractImageSize(body []byte) string {
|
||||
var req antigravity.GeminiRequest
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
return "2K" // 默认 2K
|
||||
}
|
||||
|
||||
if req.GenerationConfig != nil && req.GenerationConfig.ImageConfig != nil {
|
||||
size := strings.ToUpper(strings.TrimSpace(req.GenerationConfig.ImageConfig.ImageSize))
|
||||
if size == "1K" || size == "2K" || size == "4K" {
|
||||
return size
|
||||
}
|
||||
}
|
||||
|
||||
return "2K" // 默认 2K
|
||||
}
|
||||
|
||||
// isImageGenerationModel 判断模型是否为图片生成模型
|
||||
func isImageGenerationModel(model string) bool {
|
||||
modelLower := strings.ToLower(model)
|
||||
return strings.Contains(modelLower, "gemini-3-pro-image") ||
|
||||
strings.Contains(modelLower, "gemini-2.5-flash-image")
|
||||
}
|
||||
|
||||
120
backend/internal/service/antigravity_image_test.go
Normal file
120
backend/internal/service/antigravity_image_test.go
Normal file
@@ -0,0 +1,120 @@
|
||||
//go:build unit
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestIsImageGenerationModel_GeminiProImage 测试 gemini-3-pro-image 识别
|
||||
func TestIsImageGenerationModel_GeminiProImage(t *testing.T) {
|
||||
require.True(t, isImageGenerationModel("gemini-3-pro-image"))
|
||||
require.True(t, isImageGenerationModel("gemini-3-pro-image-preview"))
|
||||
require.True(t, isImageGenerationModel("models/gemini-3-pro-image"))
|
||||
}
|
||||
|
||||
// TestIsImageGenerationModel_GeminiFlashImage 测试 gemini-2.5-flash-image 识别
|
||||
func TestIsImageGenerationModel_GeminiFlashImage(t *testing.T) {
|
||||
require.True(t, isImageGenerationModel("gemini-2.5-flash-image"))
|
||||
require.True(t, isImageGenerationModel("gemini-2.5-flash-image-preview"))
|
||||
}
|
||||
|
||||
// TestIsImageGenerationModel_RegularModel 测试普通模型不被识别为图片模型
|
||||
func TestIsImageGenerationModel_RegularModel(t *testing.T) {
|
||||
require.False(t, isImageGenerationModel("claude-3-opus"))
|
||||
require.False(t, isImageGenerationModel("claude-sonnet-4-20250514"))
|
||||
require.False(t, isImageGenerationModel("gpt-4o"))
|
||||
require.False(t, isImageGenerationModel("gemini-2.5-pro")) // 非图片模型
|
||||
require.False(t, isImageGenerationModel("gemini-2.5-flash"))
|
||||
}
|
||||
|
||||
// TestIsImageGenerationModel_CaseInsensitive 测试大小写不敏感
|
||||
func TestIsImageGenerationModel_CaseInsensitive(t *testing.T) {
|
||||
require.True(t, isImageGenerationModel("GEMINI-3-PRO-IMAGE"))
|
||||
require.True(t, isImageGenerationModel("Gemini-3-Pro-Image"))
|
||||
require.True(t, isImageGenerationModel("GEMINI-2.5-FLASH-IMAGE"))
|
||||
}
|
||||
|
||||
// TestExtractImageSize_ValidSizes 测试有效尺寸解析
|
||||
func TestExtractImageSize_ValidSizes(t *testing.T) {
|
||||
svc := &AntigravityGatewayService{}
|
||||
|
||||
// 1K
|
||||
body := []byte(`{"generationConfig":{"imageConfig":{"imageSize":"1K"}}}`)
|
||||
require.Equal(t, "1K", svc.extractImageSize(body))
|
||||
|
||||
// 2K
|
||||
body = []byte(`{"generationConfig":{"imageConfig":{"imageSize":"2K"}}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
|
||||
// 4K
|
||||
body = []byte(`{"generationConfig":{"imageConfig":{"imageSize":"4K"}}}`)
|
||||
require.Equal(t, "4K", svc.extractImageSize(body))
|
||||
}
|
||||
|
||||
// TestExtractImageSize_CaseInsensitive 测试大小写不敏感
|
||||
func TestExtractImageSize_CaseInsensitive(t *testing.T) {
|
||||
svc := &AntigravityGatewayService{}
|
||||
|
||||
body := []byte(`{"generationConfig":{"imageConfig":{"imageSize":"1k"}}}`)
|
||||
require.Equal(t, "1K", svc.extractImageSize(body))
|
||||
|
||||
body = []byte(`{"generationConfig":{"imageConfig":{"imageSize":"4k"}}}`)
|
||||
require.Equal(t, "4K", svc.extractImageSize(body))
|
||||
}
|
||||
|
||||
// TestExtractImageSize_Default 测试无 imageConfig 返回默认 2K
|
||||
func TestExtractImageSize_Default(t *testing.T) {
|
||||
svc := &AntigravityGatewayService{}
|
||||
|
||||
// 无 generationConfig
|
||||
body := []byte(`{"contents":[]}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
|
||||
// 有 generationConfig 但无 imageConfig
|
||||
body = []byte(`{"generationConfig":{"temperature":0.7}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
|
||||
// 有 imageConfig 但无 imageSize
|
||||
body = []byte(`{"generationConfig":{"imageConfig":{}}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
}
|
||||
|
||||
// TestExtractImageSize_InvalidJSON 测试非法 JSON 返回默认 2K
|
||||
func TestExtractImageSize_InvalidJSON(t *testing.T) {
|
||||
svc := &AntigravityGatewayService{}
|
||||
|
||||
body := []byte(`not valid json`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
|
||||
body = []byte(`{"broken":`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
}
|
||||
|
||||
// TestExtractImageSize_EmptySize 测试空 imageSize 返回默认 2K
|
||||
func TestExtractImageSize_EmptySize(t *testing.T) {
|
||||
svc := &AntigravityGatewayService{}
|
||||
|
||||
body := []byte(`{"generationConfig":{"imageConfig":{"imageSize":""}}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
|
||||
// 空格
|
||||
body = []byte(`{"generationConfig":{"imageConfig":{"imageSize":" "}}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
}
|
||||
|
||||
// TestExtractImageSize_InvalidSize 测试无效尺寸返回默认 2K
|
||||
func TestExtractImageSize_InvalidSize(t *testing.T) {
|
||||
svc := &AntigravityGatewayService{}
|
||||
|
||||
body := []byte(`{"generationConfig":{"imageConfig":{"imageSize":"3K"}}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
|
||||
body = []byte(`{"generationConfig":{"imageConfig":{"imageSize":"8K"}}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
|
||||
body = []byte(`{"generationConfig":{"imageConfig":{"imageSize":"invalid"}}}`)
|
||||
require.Equal(t, "2K", svc.extractImageSize(body))
|
||||
}
|
||||
@@ -295,3 +295,88 @@ func (s *BillingService) ForceUpdatePricing() error {
|
||||
}
|
||||
return fmt.Errorf("pricing service not initialized")
|
||||
}
|
||||
|
||||
// ImagePriceConfig 图片计费配置
|
||||
type ImagePriceConfig struct {
|
||||
Price1K *float64 // 1K 尺寸价格(nil 表示使用默认值)
|
||||
Price2K *float64 // 2K 尺寸价格(nil 表示使用默认值)
|
||||
Price4K *float64 // 4K 尺寸价格(nil 表示使用默认值)
|
||||
}
|
||||
|
||||
// CalculateImageCost 计算图片生成费用
|
||||
// model: 请求的模型名称(用于获取 LiteLLM 默认价格)
|
||||
// imageSize: 图片尺寸 "1K", "2K", "4K"
|
||||
// imageCount: 生成的图片数量
|
||||
// groupConfig: 分组配置的价格(可能为 nil,表示使用默认值)
|
||||
// rateMultiplier: 费率倍数
|
||||
func (s *BillingService) CalculateImageCost(model string, imageSize string, imageCount int, groupConfig *ImagePriceConfig, rateMultiplier float64) *CostBreakdown {
|
||||
if imageCount <= 0 {
|
||||
return &CostBreakdown{}
|
||||
}
|
||||
|
||||
// 获取单价
|
||||
unitPrice := s.getImageUnitPrice(model, imageSize, groupConfig)
|
||||
|
||||
// 计算总费用
|
||||
totalCost := unitPrice * float64(imageCount)
|
||||
|
||||
// 应用倍率
|
||||
if rateMultiplier <= 0 {
|
||||
rateMultiplier = 1.0
|
||||
}
|
||||
actualCost := totalCost * rateMultiplier
|
||||
|
||||
return &CostBreakdown{
|
||||
TotalCost: totalCost,
|
||||
ActualCost: actualCost,
|
||||
}
|
||||
}
|
||||
|
||||
// getImageUnitPrice 获取图片单价
|
||||
func (s *BillingService) getImageUnitPrice(model string, imageSize string, groupConfig *ImagePriceConfig) float64 {
|
||||
// 优先使用分组配置的价格
|
||||
if groupConfig != nil {
|
||||
switch imageSize {
|
||||
case "1K":
|
||||
if groupConfig.Price1K != nil {
|
||||
return *groupConfig.Price1K
|
||||
}
|
||||
case "2K":
|
||||
if groupConfig.Price2K != nil {
|
||||
return *groupConfig.Price2K
|
||||
}
|
||||
case "4K":
|
||||
if groupConfig.Price4K != nil {
|
||||
return *groupConfig.Price4K
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 回退到 LiteLLM 默认价格
|
||||
return s.getDefaultImagePrice(model, imageSize)
|
||||
}
|
||||
|
||||
// getDefaultImagePrice 获取 LiteLLM 默认图片价格
|
||||
func (s *BillingService) getDefaultImagePrice(model string, imageSize string) float64 {
|
||||
basePrice := 0.0
|
||||
|
||||
// 从 PricingService 获取 output_cost_per_image
|
||||
if s.pricingService != nil {
|
||||
pricing := s.pricingService.GetModelPricing(model)
|
||||
if pricing != nil && pricing.OutputCostPerImage > 0 {
|
||||
basePrice = pricing.OutputCostPerImage
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到价格,使用硬编码默认值($0.134,来自 gemini-3-pro-image-preview)
|
||||
if basePrice <= 0 {
|
||||
basePrice = 0.134
|
||||
}
|
||||
|
||||
// 4K 尺寸翻倍
|
||||
if imageSize == "4K" {
|
||||
return basePrice * 2
|
||||
}
|
||||
|
||||
return basePrice
|
||||
}
|
||||
|
||||
149
backend/internal/service/billing_service_image_test.go
Normal file
149
backend/internal/service/billing_service_image_test.go
Normal file
@@ -0,0 +1,149 @@
|
||||
//go:build unit
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestCalculateImageCost_DefaultPricing 测试无分组配置时使用默认价格
|
||||
func TestCalculateImageCost_DefaultPricing(t *testing.T) {
|
||||
svc := &BillingService{} // pricingService 为 nil,使用硬编码默认值
|
||||
|
||||
// 2K 尺寸,默认价格 $0.134
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "2K", 1, nil, 1.0)
|
||||
require.InDelta(t, 0.134, cost.TotalCost, 0.0001)
|
||||
require.InDelta(t, 0.134, cost.ActualCost, 0.0001)
|
||||
|
||||
// 多张图片
|
||||
cost = svc.CalculateImageCost("gemini-3-pro-image", "2K", 3, nil, 1.0)
|
||||
require.InDelta(t, 0.402, cost.TotalCost, 0.0001)
|
||||
}
|
||||
|
||||
// TestCalculateImageCost_GroupCustomPricing 测试分组自定义价格
|
||||
func TestCalculateImageCost_GroupCustomPricing(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
price1K := 0.10
|
||||
price2K := 0.15
|
||||
price4K := 0.30
|
||||
groupConfig := &ImagePriceConfig{
|
||||
Price1K: &price1K,
|
||||
Price2K: &price2K,
|
||||
Price4K: &price4K,
|
||||
}
|
||||
|
||||
// 1K 使用分组价格
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "1K", 2, groupConfig, 1.0)
|
||||
require.InDelta(t, 0.20, cost.TotalCost, 0.0001)
|
||||
|
||||
// 2K 使用分组价格
|
||||
cost = svc.CalculateImageCost("gemini-3-pro-image", "2K", 1, groupConfig, 1.0)
|
||||
require.InDelta(t, 0.15, cost.TotalCost, 0.0001)
|
||||
|
||||
// 4K 使用分组价格
|
||||
cost = svc.CalculateImageCost("gemini-3-pro-image", "4K", 1, groupConfig, 1.0)
|
||||
require.InDelta(t, 0.30, cost.TotalCost, 0.0001)
|
||||
}
|
||||
|
||||
// TestCalculateImageCost_4KDoublePrice 测试 4K 默认价格翻倍
|
||||
func TestCalculateImageCost_4KDoublePrice(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
// 4K 尺寸,默认价格翻倍 $0.134 * 2 = $0.268
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "4K", 1, nil, 1.0)
|
||||
require.InDelta(t, 0.268, cost.TotalCost, 0.0001)
|
||||
}
|
||||
|
||||
// TestCalculateImageCost_RateMultiplier 测试费率倍数
|
||||
func TestCalculateImageCost_RateMultiplier(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
// 费率倍数 1.5x
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "2K", 1, nil, 1.5)
|
||||
require.InDelta(t, 0.134, cost.TotalCost, 0.0001) // TotalCost 不变
|
||||
require.InDelta(t, 0.201, cost.ActualCost, 0.0001) // ActualCost = 0.134 * 1.5
|
||||
|
||||
// 费率倍数 2.0x
|
||||
cost = svc.CalculateImageCost("gemini-3-pro-image", "2K", 2, nil, 2.0)
|
||||
require.InDelta(t, 0.268, cost.TotalCost, 0.0001)
|
||||
require.InDelta(t, 0.536, cost.ActualCost, 0.0001)
|
||||
}
|
||||
|
||||
// TestCalculateImageCost_ZeroCount 测试 imageCount=0
|
||||
func TestCalculateImageCost_ZeroCount(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "2K", 0, nil, 1.0)
|
||||
require.Equal(t, 0.0, cost.TotalCost)
|
||||
require.Equal(t, 0.0, cost.ActualCost)
|
||||
}
|
||||
|
||||
// TestCalculateImageCost_NegativeCount 测试 imageCount=-1
|
||||
func TestCalculateImageCost_NegativeCount(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "2K", -1, nil, 1.0)
|
||||
require.Equal(t, 0.0, cost.TotalCost)
|
||||
require.Equal(t, 0.0, cost.ActualCost)
|
||||
}
|
||||
|
||||
// TestCalculateImageCost_ZeroRateMultiplier 测试费率倍数为 0 时默认使用 1.0
|
||||
func TestCalculateImageCost_ZeroRateMultiplier(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "2K", 1, nil, 0)
|
||||
require.InDelta(t, 0.134, cost.TotalCost, 0.0001)
|
||||
require.InDelta(t, 0.134, cost.ActualCost, 0.0001) // 0 倍率当作 1.0 处理
|
||||
}
|
||||
|
||||
// TestGetImageUnitPrice_GroupPriorityOverDefault 测试分组价格优先于默认价格
|
||||
func TestGetImageUnitPrice_GroupPriorityOverDefault(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
price2K := 0.20
|
||||
groupConfig := &ImagePriceConfig{
|
||||
Price2K: &price2K,
|
||||
}
|
||||
|
||||
// 分组配置了 2K 价格,应该使用分组价格而不是默认的 $0.134
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "2K", 1, groupConfig, 1.0)
|
||||
require.InDelta(t, 0.20, cost.TotalCost, 0.0001)
|
||||
}
|
||||
|
||||
// TestGetImageUnitPrice_PartialGroupConfig 测试分组部分配置时回退默认
|
||||
func TestGetImageUnitPrice_PartialGroupConfig(t *testing.T) {
|
||||
svc := &BillingService{}
|
||||
|
||||
// 只配置 1K 价格
|
||||
price1K := 0.10
|
||||
groupConfig := &ImagePriceConfig{
|
||||
Price1K: &price1K,
|
||||
}
|
||||
|
||||
// 1K 使用分组价格
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "1K", 1, groupConfig, 1.0)
|
||||
require.InDelta(t, 0.10, cost.TotalCost, 0.0001)
|
||||
|
||||
// 2K 回退默认价格 $0.134
|
||||
cost = svc.CalculateImageCost("gemini-3-pro-image", "2K", 1, groupConfig, 1.0)
|
||||
require.InDelta(t, 0.134, cost.TotalCost, 0.0001)
|
||||
|
||||
// 4K 回退默认价格 $0.268 (翻倍)
|
||||
cost = svc.CalculateImageCost("gemini-3-pro-image", "4K", 1, groupConfig, 1.0)
|
||||
require.InDelta(t, 0.268, cost.TotalCost, 0.0001)
|
||||
}
|
||||
|
||||
// TestGetDefaultImagePrice_FallbackHardcoded 测试 PricingService 无数据时使用硬编码默认值
|
||||
func TestGetDefaultImagePrice_FallbackHardcoded(t *testing.T) {
|
||||
svc := &BillingService{} // pricingService 为 nil
|
||||
|
||||
// 1K 和 2K 使用相同的默认价格 $0.134
|
||||
cost := svc.CalculateImageCost("gemini-3-pro-image", "1K", 1, nil, 1.0)
|
||||
require.InDelta(t, 0.134, cost.TotalCost, 0.0001)
|
||||
|
||||
cost = svc.CalculateImageCost("gemini-3-pro-image", "2K", 1, nil, 1.0)
|
||||
require.InDelta(t, 0.134, cost.TotalCost, 0.0001)
|
||||
}
|
||||
@@ -100,6 +100,10 @@ type ForwardResult struct {
|
||||
Stream bool
|
||||
Duration time.Duration
|
||||
FirstTokenMs *int // 首字时间(流式请求)
|
||||
|
||||
// 图片生成计费字段(仅 gemini-3-pro-image 使用)
|
||||
ImageCount int // 生成的图片数量
|
||||
ImageSize string // 图片尺寸 "1K", "2K", "4K"
|
||||
}
|
||||
|
||||
// UpstreamFailoverError indicates an upstream error that should trigger account failover.
|
||||
@@ -1794,25 +1798,40 @@ func (s *GatewayService) RecordUsage(ctx context.Context, input *RecordUsageInpu
|
||||
account := input.Account
|
||||
subscription := input.Subscription
|
||||
|
||||
// 计算费用
|
||||
tokens := UsageTokens{
|
||||
InputTokens: result.Usage.InputTokens,
|
||||
OutputTokens: result.Usage.OutputTokens,
|
||||
CacheCreationTokens: result.Usage.CacheCreationInputTokens,
|
||||
CacheReadTokens: result.Usage.CacheReadInputTokens,
|
||||
}
|
||||
|
||||
// 获取费率倍数
|
||||
multiplier := s.cfg.Default.RateMultiplier
|
||||
if apiKey.GroupID != nil && apiKey.Group != nil {
|
||||
multiplier = apiKey.Group.RateMultiplier
|
||||
}
|
||||
|
||||
cost, err := s.billingService.CalculateCost(result.Model, tokens, multiplier)
|
||||
if err != nil {
|
||||
log.Printf("Calculate cost failed: %v", err)
|
||||
// 使用默认费用继续
|
||||
cost = &CostBreakdown{ActualCost: 0}
|
||||
var cost *CostBreakdown
|
||||
|
||||
// 根据请求类型选择计费方式
|
||||
if result.ImageCount > 0 {
|
||||
// 图片生成计费
|
||||
var groupConfig *ImagePriceConfig
|
||||
if apiKey.Group != nil {
|
||||
groupConfig = &ImagePriceConfig{
|
||||
Price1K: apiKey.Group.ImagePrice1K,
|
||||
Price2K: apiKey.Group.ImagePrice2K,
|
||||
Price4K: apiKey.Group.ImagePrice4K,
|
||||
}
|
||||
}
|
||||
cost = s.billingService.CalculateImageCost(result.Model, result.ImageSize, result.ImageCount, groupConfig, multiplier)
|
||||
} else {
|
||||
// Token 计费
|
||||
tokens := UsageTokens{
|
||||
InputTokens: result.Usage.InputTokens,
|
||||
OutputTokens: result.Usage.OutputTokens,
|
||||
CacheCreationTokens: result.Usage.CacheCreationInputTokens,
|
||||
CacheReadTokens: result.Usage.CacheReadInputTokens,
|
||||
}
|
||||
var err error
|
||||
cost, err = s.billingService.CalculateCost(result.Model, tokens, multiplier)
|
||||
if err != nil {
|
||||
log.Printf("Calculate cost failed: %v", err)
|
||||
cost = &CostBreakdown{ActualCost: 0}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断计费方式:订阅模式 vs 余额模式
|
||||
@@ -1824,6 +1843,10 @@ func (s *GatewayService) RecordUsage(ctx context.Context, input *RecordUsageInpu
|
||||
|
||||
// 创建使用日志
|
||||
durationMs := int(result.Duration.Milliseconds())
|
||||
var imageSize *string
|
||||
if result.ImageSize != "" {
|
||||
imageSize = &result.ImageSize
|
||||
}
|
||||
usageLog := &UsageLog{
|
||||
UserID: user.ID,
|
||||
APIKeyID: apiKey.ID,
|
||||
@@ -1845,6 +1868,8 @@ func (s *GatewayService) RecordUsage(ctx context.Context, input *RecordUsageInpu
|
||||
Stream: result.Stream,
|
||||
DurationMs: &durationMs,
|
||||
FirstTokenMs: result.FirstTokenMs,
|
||||
ImageCount: result.ImageCount,
|
||||
ImageSize: imageSize,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,11 @@ type Group struct {
|
||||
MonthlyLimitUSD *float64
|
||||
DefaultValidityDays int
|
||||
|
||||
// 图片生成计费配置(antigravity 和 gemini 平台使用)
|
||||
ImagePrice1K *float64
|
||||
ImagePrice2K *float64
|
||||
ImagePrice4K *float64
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
|
||||
@@ -47,3 +52,19 @@ func (g *Group) HasWeeklyLimit() bool {
|
||||
func (g *Group) HasMonthlyLimit() bool {
|
||||
return g.MonthlyLimitUSD != nil && *g.MonthlyLimitUSD > 0
|
||||
}
|
||||
|
||||
// GetImagePrice 根据 image_size 返回对应的图片生成价格
|
||||
// 如果分组未配置价格,返回 nil(调用方应使用默认值)
|
||||
func (g *Group) GetImagePrice(imageSize string) *float64 {
|
||||
switch imageSize {
|
||||
case "1K":
|
||||
return g.ImagePrice1K
|
||||
case "2K":
|
||||
return g.ImagePrice2K
|
||||
case "4K":
|
||||
return g.ImagePrice4K
|
||||
default:
|
||||
// 未知尺寸默认按 2K 计费
|
||||
return g.ImagePrice2K
|
||||
}
|
||||
}
|
||||
|
||||
92
backend/internal/service/group_test.go
Normal file
92
backend/internal/service/group_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
//go:build unit
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGroup_GetImagePrice_1K 测试 1K 尺寸返回正确价格
|
||||
func TestGroup_GetImagePrice_1K(t *testing.T) {
|
||||
price := 0.10
|
||||
group := &Group{
|
||||
ImagePrice1K: &price,
|
||||
}
|
||||
|
||||
result := group.GetImagePrice("1K")
|
||||
require.NotNil(t, result)
|
||||
require.InDelta(t, 0.10, *result, 0.0001)
|
||||
}
|
||||
|
||||
// TestGroup_GetImagePrice_2K 测试 2K 尺寸返回正确价格
|
||||
func TestGroup_GetImagePrice_2K(t *testing.T) {
|
||||
price := 0.15
|
||||
group := &Group{
|
||||
ImagePrice2K: &price,
|
||||
}
|
||||
|
||||
result := group.GetImagePrice("2K")
|
||||
require.NotNil(t, result)
|
||||
require.InDelta(t, 0.15, *result, 0.0001)
|
||||
}
|
||||
|
||||
// TestGroup_GetImagePrice_4K 测试 4K 尺寸返回正确价格
|
||||
func TestGroup_GetImagePrice_4K(t *testing.T) {
|
||||
price := 0.30
|
||||
group := &Group{
|
||||
ImagePrice4K: &price,
|
||||
}
|
||||
|
||||
result := group.GetImagePrice("4K")
|
||||
require.NotNil(t, result)
|
||||
require.InDelta(t, 0.30, *result, 0.0001)
|
||||
}
|
||||
|
||||
// TestGroup_GetImagePrice_UnknownSize 测试未知尺寸回退 2K
|
||||
func TestGroup_GetImagePrice_UnknownSize(t *testing.T) {
|
||||
price2K := 0.15
|
||||
group := &Group{
|
||||
ImagePrice2K: &price2K,
|
||||
}
|
||||
|
||||
// 未知尺寸 "3K" 应该回退到 2K
|
||||
result := group.GetImagePrice("3K")
|
||||
require.NotNil(t, result)
|
||||
require.InDelta(t, 0.15, *result, 0.0001)
|
||||
|
||||
// 空字符串也回退到 2K
|
||||
result = group.GetImagePrice("")
|
||||
require.NotNil(t, result)
|
||||
require.InDelta(t, 0.15, *result, 0.0001)
|
||||
}
|
||||
|
||||
// TestGroup_GetImagePrice_NilValues 测试未配置时返回 nil
|
||||
func TestGroup_GetImagePrice_NilValues(t *testing.T) {
|
||||
group := &Group{
|
||||
// 所有 ImagePrice 字段都是 nil
|
||||
}
|
||||
|
||||
require.Nil(t, group.GetImagePrice("1K"))
|
||||
require.Nil(t, group.GetImagePrice("2K"))
|
||||
require.Nil(t, group.GetImagePrice("4K"))
|
||||
require.Nil(t, group.GetImagePrice("unknown"))
|
||||
}
|
||||
|
||||
// TestGroup_GetImagePrice_PartialConfig 测试部分配置
|
||||
func TestGroup_GetImagePrice_PartialConfig(t *testing.T) {
|
||||
price1K := 0.10
|
||||
group := &Group{
|
||||
ImagePrice1K: &price1K,
|
||||
// ImagePrice2K 和 ImagePrice4K 未配置
|
||||
}
|
||||
|
||||
result := group.GetImagePrice("1K")
|
||||
require.NotNil(t, result)
|
||||
require.InDelta(t, 0.10, *result, 0.0001)
|
||||
|
||||
// 2K 和 4K 返回 nil
|
||||
require.Nil(t, group.GetImagePrice("2K"))
|
||||
require.Nil(t, group.GetImagePrice("4K"))
|
||||
}
|
||||
@@ -33,6 +33,7 @@ type LiteLLMModelPricing struct {
|
||||
LiteLLMProvider string `json:"litellm_provider"`
|
||||
Mode string `json:"mode"`
|
||||
SupportsPromptCaching bool `json:"supports_prompt_caching"`
|
||||
OutputCostPerImage float64 `json:"output_cost_per_image"` // 图片生成模型每张图片价格
|
||||
}
|
||||
|
||||
// PricingRemoteClient 远程价格数据获取接口
|
||||
@@ -50,6 +51,7 @@ type LiteLLMRawEntry struct {
|
||||
LiteLLMProvider string `json:"litellm_provider"`
|
||||
Mode string `json:"mode"`
|
||||
SupportsPromptCaching bool `json:"supports_prompt_caching"`
|
||||
OutputCostPerImage *float64 `json:"output_cost_per_image"`
|
||||
}
|
||||
|
||||
// PricingService 动态价格服务
|
||||
@@ -299,6 +301,9 @@ func (s *PricingService) parsePricingData(body []byte) (map[string]*LiteLLMModel
|
||||
if entry.CacheReadInputTokenCost != nil {
|
||||
pricing.CacheReadInputTokenCost = *entry.CacheReadInputTokenCost
|
||||
}
|
||||
if entry.OutputCostPerImage != nil {
|
||||
pricing.OutputCostPerImage = *entry.OutputCostPerImage
|
||||
}
|
||||
|
||||
result[modelName] = pricing
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ type UsageLog struct {
|
||||
DurationMs *int
|
||||
FirstTokenMs *int
|
||||
|
||||
// 图片生成字段
|
||||
ImageCount int
|
||||
ImageSize *string
|
||||
|
||||
CreatedAt time.Time
|
||||
|
||||
User *User
|
||||
|
||||
10
backend/migrations/028_group_image_pricing.sql
Normal file
10
backend/migrations/028_group_image_pricing.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- 为 Antigravity 分组添加图片生成计费配置
|
||||
-- 支持 gemini-3-pro-image 模型的 1K/2K/4K 分辨率按次计费
|
||||
|
||||
ALTER TABLE groups ADD COLUMN IF NOT EXISTS image_price_1k DECIMAL(20,8);
|
||||
ALTER TABLE groups ADD COLUMN IF NOT EXISTS image_price_2k DECIMAL(20,8);
|
||||
ALTER TABLE groups ADD COLUMN IF NOT EXISTS image_price_4k DECIMAL(20,8);
|
||||
|
||||
COMMENT ON COLUMN groups.image_price_1k IS '1K 分辨率图片生成单价 (USD),仅 antigravity 平台使用';
|
||||
COMMENT ON COLUMN groups.image_price_2k IS '2K 分辨率图片生成单价 (USD),仅 antigravity 平台使用';
|
||||
COMMENT ON COLUMN groups.image_price_4k IS '4K 分辨率图片生成单价 (USD),仅 antigravity 平台使用';
|
||||
5
backend/migrations/029_usage_log_image_fields.sql
Normal file
5
backend/migrations/029_usage_log_image_fields.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- 为使用日志添加图片生成统计字段
|
||||
-- 用于记录 gemini-3-pro-image 等图片生成模型的使用情况
|
||||
|
||||
ALTER TABLE usage_logs ADD COLUMN IF NOT EXISTS image_count INT DEFAULT 0;
|
||||
ALTER TABLE usage_logs ADD COLUMN IF NOT EXISTS image_size VARCHAR(10);
|
||||
Reference in New Issue
Block a user