若干更新迭代
This commit is contained in:
1 parent
deb9cc5bcf
commit
4ac786aafb
64 files changed
+3251
-291
No files matched your search
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -55,6 +56,9 @@ func (p *SettlementProcessor) Advance(ctx context.Context, job jobs.Job) (jobs.J
|
||||
if advanced.Provider == "minimax" && billing.IsMinimaxH3BillingModel(advanced.ReqKey) {
|
||||
return p.settleMinimaxH3(ctx, advanced)
|
||||
}
|
||||
if advanced.Provider == "bailian" && advanced.ReqKey == billing.BailianWan30VideoModel {
|
||||
return p.settleBailianWan30(ctx, advanced)
|
||||
}
|
||||
if advanced.Provider != "seedance" {
|
||||
return advanced, nil
|
||||
}
|
||||
@@ -168,6 +172,9 @@ func (p *SettlementProcessor) settleMinimaxH3(ctx context.Context, job jobs.Job)
|
||||
charge.raw["settledAt"] = p.now().UTC().Format(time.RFC3339Nano)
|
||||
return p.write(ctx, job, charge.raw)
|
||||
}
|
||||
if !usage.hasInputImageCount {
|
||||
usage.inputImageCount = minimaxQuotedInputImageCount(charge.raw, job.RequestPayload)
|
||||
}
|
||||
resolution := minimaxResolution(charge.raw)
|
||||
actualAmount, err := billing.CalculateMinimaxH3ActualAmountFen(billing.MinimaxH3ActualAmountInput{
|
||||
Resolution: resolution, OutputSeconds: usage.outputSeconds, InputVideoSeconds: usage.inputSeconds,
|
||||
@@ -221,6 +228,100 @@ func (p *SettlementProcessor) settleMinimaxH3(ctx context.Context, job jobs.Job)
|
||||
return p.write(ctx, job, charge.raw)
|
||||
}
|
||||
|
||||
func (p *SettlementProcessor) settleBailianWan30(ctx context.Context, job jobs.Job) (jobs.Job, error) {
|
||||
var charge billingState
|
||||
if json.Unmarshal(job.Billing, &charge) != nil {
|
||||
return jobs.Job{}, errors.New("settle Wan 3.0 generation charge")
|
||||
}
|
||||
status, _ := charge.raw["settlementStatus"].(string)
|
||||
if status == "settled" || status == "estimated" {
|
||||
return job, nil
|
||||
}
|
||||
var use usageContext
|
||||
if len(job.UsageContext) != 0 && json.Unmarshal(job.UsageContext, &use) != nil {
|
||||
return jobs.Job{}, errors.New("settle Wan 3.0 generation charge")
|
||||
}
|
||||
quotaExempt := charge.QuotaExempt || use.Source == "platform" && use.Role == "super_admin"
|
||||
chargeReady := charge.Status == "charged" || quotaExempt && charge.Status == "not_charged"
|
||||
if !chargeReady || !quotaExempt && use.OrganizationID == "" {
|
||||
return job, nil
|
||||
}
|
||||
|
||||
outputSeconds := bailianWan30OutputSeconds(job.ResponsePayload)
|
||||
if outputSeconds <= 0 {
|
||||
charge.raw["settlementStatus"] = "estimated"
|
||||
charge.raw["settlementReason"] = "provider_usage_unavailable"
|
||||
charge.raw["settledAt"] = p.now().UTC().Format(time.RFC3339Nano)
|
||||
return p.write(ctx, job, charge.raw)
|
||||
}
|
||||
unitPrice, ok := integer(charge.raw["standardUnitPriceFen"])
|
||||
if !ok {
|
||||
return jobs.Job{}, errors.New("settle Wan 3.0 generation charge")
|
||||
}
|
||||
actualAmount, err := billing.CalculateBailianWan30ActualAmountFen(outputSeconds, unitPrice, numberOrZero(charge.raw["markupMultiplier"]))
|
||||
if err != nil {
|
||||
return jobs.Job{}, errors.New("settle Wan 3.0 generation charge")
|
||||
}
|
||||
delta := actualAmount - charge.AmountFen
|
||||
settledAt := p.now().UTC()
|
||||
var settlementLedgerID string
|
||||
if delta != 0 && !quotaExempt {
|
||||
if p.ledger == nil {
|
||||
return jobs.Job{}, errors.New("settle Wan 3.0 generation charge")
|
||||
}
|
||||
description := capabilityLabel(job.Capability) + "实际用量差额退回"
|
||||
if delta > 0 {
|
||||
description = capabilityLabel(job.Capability) + "实际用量补扣"
|
||||
}
|
||||
posting, postErr := p.ledger.Settle(ctx, billing.SettlementRequest{
|
||||
OrganizationID: use.OrganizationID, AccountID: use.AccountID, JobID: job.ID,
|
||||
DeltaFen: delta, Description: description,
|
||||
Metadata: map[string]any{
|
||||
"operation": "bailian_wan30_actual_settlement", "reservedAmountFen": charge.AmountFen,
|
||||
"actualAmountFen": actualAmount, "outputSeconds": outputSeconds,
|
||||
"resolution": seedanceResolution(charge.raw), "model": job.ReqKey,
|
||||
},
|
||||
})
|
||||
if postErr != nil {
|
||||
return jobs.Job{}, errors.New("settle Wan 3.0 generation charge")
|
||||
}
|
||||
settlementLedgerID = posting.LedgerID
|
||||
if !posting.CreatedAt.IsZero() {
|
||||
settledAt = posting.CreatedAt.UTC()
|
||||
}
|
||||
}
|
||||
charge.raw["amountFen"] = actualAmount
|
||||
charge.raw["settlementStatus"] = "settled"
|
||||
charge.raw["settledAt"] = settledAt.Format(time.RFC3339Nano)
|
||||
if settlementLedgerID != "" {
|
||||
charge.raw["settlementLedgerEntryId"] = settlementLedgerID
|
||||
} else {
|
||||
delete(charge.raw, "settlementLedgerEntryId")
|
||||
}
|
||||
charge.raw["providerUsage"] = map[string]any{
|
||||
"model": job.ReqKey, "resolution": seedanceResolution(charge.raw), "outputSeconds": outputSeconds,
|
||||
"videoPriceFenPerSecond": unitPrice,
|
||||
}
|
||||
return p.write(ctx, job, charge.raw)
|
||||
}
|
||||
|
||||
func bailianWan30OutputSeconds(payload json.RawMessage) float64 {
|
||||
var response struct {
|
||||
Usage map[string]any `json:"usage"`
|
||||
}
|
||||
if json.Unmarshal(payload, &response) != nil {
|
||||
return 0
|
||||
}
|
||||
if milliseconds := numberOrZero(response.Usage["outputMilliseconds"]); milliseconds > 0 {
|
||||
return milliseconds / 1000
|
||||
}
|
||||
seconds := numberOrZero(response.Usage["outputSeconds"])
|
||||
if math.IsNaN(seconds) || math.IsInf(seconds, 0) || seconds <= 0 {
|
||||
return 0
|
||||
}
|
||||
return seconds
|
||||
}
|
||||
|
||||
func (p *SettlementProcessor) settleSeedreamLayers(ctx context.Context, job jobs.Job) (jobs.Job, error) {
|
||||
var charge billingState
|
||||
if json.Unmarshal(job.Billing, &charge) != nil {
|
||||
@@ -325,9 +426,10 @@ func seedanceCompletionTokens(payload json.RawMessage) int64 {
|
||||
}
|
||||
|
||||
type minimaxUsage struct {
|
||||
outputSeconds int64
|
||||
inputSeconds int64
|
||||
inputImageCount int64
|
||||
outputSeconds int64
|
||||
inputSeconds int64
|
||||
inputImageCount int64
|
||||
hasInputImageCount bool
|
||||
}
|
||||
|
||||
func minimaxH3Usage(payload json.RawMessage) minimaxUsage {
|
||||
@@ -339,8 +441,24 @@ func minimaxH3Usage(payload json.RawMessage) minimaxUsage {
|
||||
}
|
||||
outputSeconds, _ := nonNegativeInteger(response.Usage["outputSeconds"])
|
||||
inputSeconds, _ := nonNegativeInteger(response.Usage["inputSeconds"])
|
||||
inputImageCount, _ := nonNegativeInteger(response.Usage["inputImageCount"])
|
||||
return minimaxUsage{outputSeconds: outputSeconds, inputSeconds: inputSeconds, inputImageCount: inputImageCount}
|
||||
inputImageCount, hasInputImageCount := nonNegativeInteger(response.Usage["inputImageCount"])
|
||||
return minimaxUsage{outputSeconds: outputSeconds, inputSeconds: inputSeconds, inputImageCount: inputImageCount, hasInputImageCount: hasInputImageCount}
|
||||
}
|
||||
|
||||
func minimaxQuotedInputImageCount(snapshot map[string]any, requestPayload json.RawMessage) int64 {
|
||||
parameters, _ := snapshot["parameters"].(map[string]any)
|
||||
for _, key := range []string{"inputImageCount", "referenceImageCount"} {
|
||||
if count, ok := nonNegativeInteger(parameters[key]); ok {
|
||||
return count
|
||||
}
|
||||
}
|
||||
var request map[string]any
|
||||
if json.Unmarshal(requestPayload, &request) == nil {
|
||||
if count, ok := nonNegativeInteger(billing.NormalizeBillingParameters(request, nil)["referenceImageCount"]); ok {
|
||||
return count
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func minimaxResolution(snapshot map[string]any) string {
|
||||
|
||||
Reference in new issue
Block a user