Compare commits
7 Commits
ffba1f30ec
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 59d4ef557b | |||
| b7b1ee51a1 | |||
| ab3a2d967e | |||
| 34c5eeaf63 | |||
| de55c16734 | |||
| 1fbed2febd | |||
| d5206df131 |
27
Dockerfile
27
Dockerfile
@@ -1,5 +1,5 @@
|
|||||||
# 阶段1: 构建
|
# 阶段1: 构建
|
||||||
FROM golang:1.26-alpine AS builder
|
FROM golang:alpine AS builder
|
||||||
|
|
||||||
RUN apk add --no-cache git ca-certificates tzdata
|
RUN apk add --no-cache git ca-certificates tzdata
|
||||||
|
|
||||||
@@ -10,12 +10,6 @@ ENV GO111MODULE=on
|
|||||||
ENV GOPROXY=https://goproxy.cn,direct
|
ENV GOPROXY=https://goproxy.cn,direct
|
||||||
ENV CGO_ENABLED=0
|
ENV CGO_ENABLED=0
|
||||||
ENV GOTOOLCHAIN=auto
|
ENV GOTOOLCHAIN=auto
|
||||||
ENV GOPRIVATE=gitea.com/red-future/common
|
|
||||||
|
|
||||||
# 配置git使用私有Gitea仓库
|
|
||||||
RUN git config --global url."http://x-token-auth:9b31146aa8c10a7cb4f2e49dcee0934a223be1076289810e1ad98b968066c2bc@116.204.74.41:3000/red-future/common.git".insteadOf "https://gitea.com/red-future/common.git" && \
|
|
||||||
git config --global credential.helper store
|
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
@@ -24,25 +18,6 @@ RUN go mod download && go mod tidy
|
|||||||
|
|
||||||
RUN go build -ldflags="-s -w" -o main ./main.go
|
RUN go build -ldflags="-s -w" -o main ./main.go
|
||||||
|
|
||||||
# 阶段2: 运行
|
|
||||||
FROM alpine:3.19
|
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates tzdata
|
|
||||||
|
|
||||||
ENV TZ=Asia/Shanghai
|
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY --from=builder /build/main .
|
|
||||||
COPY --from=builder /build/config.yml ./
|
|
||||||
|
|
||||||
RUN mkdir -p /app/resource/log/run \
|
|
||||||
/app/resource/log/server \
|
|
||||||
&& adduser -D -u 1000 appuser \
|
|
||||||
&& chown -R appuser:appuser /app
|
|
||||||
|
|
||||||
USER appuser
|
|
||||||
|
|
||||||
EXPOSE 3005
|
EXPOSE 3005
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"ai-agent/digital-human/service"
|
"ai-agent/digital-human/service"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"ai-agent/digital-human/service"
|
"ai-agent/digital-human/service"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"ai-agent/digital-human/service"
|
"ai-agent/digital-human/service"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type digitalhuman struct{}
|
type digitalhuman struct{}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"ai-agent/digital-human/service"
|
"ai-agent/digital-human/service"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type video struct{}
|
type video struct{}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/digital-human/consts/public"
|
"ai-agent/digital-human/consts/public"
|
||||||
"ai-agent/digital-human/model/entity"
|
"ai-agent/digital-human/model/entity"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"ai-agent/digital-human/model/entity"
|
"ai-agent/digital-human/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"ai-agent/digital-human/model/entity"
|
"ai-agent/digital-human/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"ai-agent/digital-human/model/entity"
|
"ai-agent/digital-human/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"ai-agent/digital-human/model/entity"
|
"ai-agent/digital-human/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package dto
|
|||||||
import (
|
import (
|
||||||
"ai-agent/digital-human/consts"
|
"ai-agent/digital-human/consts"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package dto
|
|||||||
import (
|
import (
|
||||||
"ai-agent/digital-human/consts"
|
"ai-agent/digital-human/consts"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package dto
|
|||||||
import (
|
import (
|
||||||
"ai-agent/digital-human/consts"
|
"ai-agent/digital-human/consts"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type asyncTaskRefCol struct {
|
type asyncTaskRefCol struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package entity
|
|||||||
import (
|
import (
|
||||||
"ai-agent/digital-human/consts"
|
"ai-agent/digital-human/consts"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type audioCol struct {
|
type audioCol struct {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type customVoiceCol struct {
|
type customVoiceCol struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package entity
|
|||||||
import (
|
import (
|
||||||
"ai-agent/digital-human/consts"
|
"ai-agent/digital-human/consts"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type digitalHumanCol struct {
|
type digitalHumanCol struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package entity
|
|||||||
import (
|
import (
|
||||||
"ai-agent/digital-human/consts"
|
"ai-agent/digital-human/consts"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type videoCol struct {
|
type videoCol struct {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
"github.com/gogf/gf/v2/errors/gerror"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ EOF
|
|||||||
#### 创建 Dockerfile
|
#### 创建 Dockerfile
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cat > Dockerfile << 'EOF'
|
cat > Dockerfile.bak << 'EOF'
|
||||||
FROM python:3.12-slim
|
FROM python:3.12-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
33
go.mod
33
go.mod
@@ -1,19 +1,17 @@
|
|||||||
module ai-agent
|
module ai-agent
|
||||||
|
|
||||||
go 1.26.0
|
go 1.26.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.com/red-future/common v0.0.19
|
gitea.redpowerfuture.com/red-future/common v0.0.23
|
||||||
github.com/cloudwego/eino v0.8.13
|
github.com/cloudwego/eino v0.9.5
|
||||||
github.com/cloudwego/eino-ext/components/model/qwen v0.1.9
|
github.com/cloudwego/eino-ext/components/model/qwen v0.1.9
|
||||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2
|
||||||
github.com/gogf/gf/v2 v2.10.0
|
github.com/gogf/gf/v2 v2.10.2
|
||||||
go.opentelemetry.io/otel/trace v1.38.0
|
go.opentelemetry.io/otel/trace v1.44.0
|
||||||
)
|
)
|
||||||
|
|
||||||
//replace gitea.com/red-future/common => ../common
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/armon/go-metrics v0.4.1 // indirect
|
github.com/armon/go-metrics v0.4.1 // indirect
|
||||||
@@ -64,7 +62,7 @@ require (
|
|||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
github.com/hashicorp/serf v0.10.1 // indirect
|
github.com/hashicorp/serf v0.10.1 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.18.2 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
github.com/magiconair/properties v1.8.10 // indirect
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
@@ -94,20 +92,21 @@ require (
|
|||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||||
github.com/yargevad/filepathx v1.0.0 // indirect
|
github.com/yargevad/filepathx v1.0.0 // indirect
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
go.mongodb.org/mongo-driver/v2 v2.4.0 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.23.0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||||
golang.org/x/arch v0.11.0 // indirect
|
golang.org/x/arch v0.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/net v0.48.0 // indirect
|
golang.org/x/net v0.47.0 // indirect
|
||||||
golang.org/x/sys v0.39.0 // indirect
|
golang.org/x/sys v0.38.0 // indirect
|
||||||
golang.org/x/text v0.32.0 // indirect
|
golang.org/x/text v0.31.0 // indirect
|
||||||
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||||
google.golang.org/grpc v1.75.0 // indirect
|
google.golang.org/grpc v1.75.0 // indirect
|
||||||
|
|||||||
87
go.sum
87
go.sum
@@ -1,8 +1,6 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
gitea.com/red-future/common v0.0.12 h1:whaCAiH33orl0P+oDpxzC4VoNluHKNYKGZ+FcUWw85Q=
|
gitea.redpowerfuture.com/red-future/common v0.0.23 h1:xieoA00iKOCDm5SO9iXn+cSyMKBAlZwI0fuEVPWrHLg=
|
||||||
gitea.com/red-future/common v0.0.12/go.mod h1:3a7cwZNvgpKw5FzE8x5MZImd7NBePGXRGFSMjt90158=
|
gitea.redpowerfuture.com/red-future/common v0.0.23/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY=
|
||||||
gitea.com/red-future/common v0.0.19 h1:9/WrfCFUCeFUYwuhBYF+JOQi5F5xuOy+gVnf2ZvHZu4=
|
|
||||||
gitea.com/red-future/common v0.0.19/go.mod h1:6/nqIucVzmjOyqDTIq71feYBXXFNBy0rFwzaQ0/Ueoo=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
@@ -58,8 +56,8 @@ github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn
|
|||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||||
github.com/cloudwego/eino v0.8.13 h1:z5dhaZNN8TWZbP/lgKxGmF26Ii8fPeUlQCGV/NTtms0=
|
github.com/cloudwego/eino v0.9.5 h1:0Nftjx9gPek/2S/hzm38LVxSjk5/6mqRr3I9VKrKvm4=
|
||||||
github.com/cloudwego/eino v0.8.13/go.mod h1:+2N4nsMPxA6kGBHpH+75JuTfEcGprAMTdsZESrShKpU=
|
github.com/cloudwego/eino v0.9.5/go.mod h1:OBD1mrkfkt/pJa4rkg1P0VnaMeOVl7l8IAdEqY//3IQ=
|
||||||
github.com/cloudwego/eino-ext/components/model/qwen v0.1.9 h1:xCz/mp43JeWqupjPR3zLRArmwC6P29/6lTwbwh1yzYM=
|
github.com/cloudwego/eino-ext/components/model/qwen v0.1.9 h1:xCz/mp43JeWqupjPR3zLRArmwC6P29/6lTwbwh1yzYM=
|
||||||
github.com/cloudwego/eino-ext/components/model/qwen v0.1.9/go.mod h1:slTGTuhzkzhNavf+1UtUg1FvUSA31iNAF+rq1mT4SnI=
|
github.com/cloudwego/eino-ext/components/model/qwen v0.1.9/go.mod h1:slTGTuhzkzhNavf+1UtUg1FvUSA31iNAF+rq1mT4SnI=
|
||||||
github.com/cloudwego/eino-ext/libs/acl/openai v0.1.17 h1:EeVcR1TslRA2IdNW1h/2LaGbPlffwGhQm99jM3zWZiI=
|
github.com/cloudwego/eino-ext/libs/acl/openai v0.1.17 h1:EeVcR1TslRA2IdNW1h/2LaGbPlffwGhQm99jM3zWZiI=
|
||||||
@@ -114,16 +112,16 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
|||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0 h1:39+jbTenm7KBj4hO2C8ANAxVHpX/7OuRDs1VcGC9ylA=
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 h1:u8EpP24GkprogROnJ7htMov9Fc66pTP1eVYrWxiCYOs=
|
||||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0/go.mod h1:B0s0fVzn0W220E8UTpSGzrrGKsop5KcB90twBeLCiz0=
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2/go.mod h1:GmvM3r8GVByVMi4RD2+MCs5+CfxVXPMeT8mVDkAaAXE=
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0 h1:N/F9CuDdUZLoM1nVRqrDE/33pDZuhVxpNY4wYdeIaBs=
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 h1:iTQegT+lEg/wDKvj2mi3W1wrdrwFarjokf88EXVVgu4=
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0/go.mod h1:x6uoJGfZOtirIRQls8xUlYzC6f7T/eULPUa9er368X0=
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2/go.mod h1:ZRw3GNz5cq4uYrW4TPSVyrYWaoqzujKdWro/AOcGBaE=
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 h1:eUqwJ/qNH8lJ6yssiqskazgp1ACQuNU6zXlLOZVuXTQ=
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 h1:eUqwJ/qNH8lJ6yssiqskazgp1ACQuNU6zXlLOZVuXTQ=
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5/go.mod h1:sjQyMry9+0POYZCA6lHXBxO77WoNKkruJpRB4xKqk5k=
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5/go.mod h1:sjQyMry9+0POYZCA6lHXBxO77WoNKkruJpRB4xKqk5k=
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 h1:tHUEZYB5GTqEYYVDYnlGobf1xISARKDE4KHVlgjwTec=
|
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 h1:tHUEZYB5GTqEYYVDYnlGobf1xISARKDE4KHVlgjwTec=
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5/go.mod h1:cfzTn2HS9RDX8f5pUVkbGxUWcSosouqfNQ1G6cY0V88=
|
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5/go.mod h1:cfzTn2HS9RDX8f5pUVkbGxUWcSosouqfNQ1G6cY0V88=
|
||||||
github.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs=
|
github.com/gogf/gf/v2 v2.10.2 h1:46IO0Uc8e85/FqdftJFskfDejJLBL0JBnGS5qOftUu8=
|
||||||
github.com/gogf/gf/v2 v2.10.0/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
github.com/gogf/gf/v2 v2.10.2/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
@@ -171,8 +169,6 @@ github.com/goph/emperror v0.17.2 h1:yLapQcmEsO0ipe9p5TaN22djm3OFV/TfM/fcYP0/J18=
|
|||||||
github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic=
|
github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic=
|
||||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
||||||
@@ -235,8 +231,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
|||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
|
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@@ -290,7 +286,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
@@ -339,8 +334,8 @@ github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6
|
|||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rollbar/rollbar-go v1.0.2/go.mod h1:AcFs5f0I+c71bpHlXNNDbOWJiKwjFDtISeXco0L5PKQ=
|
github.com/rollbar/rollbar-go v1.0.2/go.mod h1:AcFs5f0I+c71bpHlXNNDbOWJiKwjFDtISeXco0L5PKQ=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||||
@@ -393,26 +388,26 @@ github.com/yargevad/filepathx v1.0.0 h1:SYcT+N3tYGi+NvazubCNlvgIPbzAk7i7y2dwg3I5
|
|||||||
github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA=
|
github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5MuFo=
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
||||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
@@ -426,8 +421,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||||
@@ -436,8 +431,8 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
|
|||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -454,8 +449,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -464,8 +459,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -492,17 +487,17 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@@ -512,8 +507,8 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -523,6 +518,8 @@ gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E
|
|||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
|||||||
4
main.go
4
main.go
@@ -8,8 +8,8 @@ import (
|
|||||||
workflowSkillController "ai-agent/workflow/controller/skill"
|
workflowSkillController "ai-agent/workflow/controller/skill"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/http"
|
"gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/jaeger"
|
"gitea.redpowerfuture.com/red-future/common/jaeger"
|
||||||
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
||||||
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,12 +12,16 @@ const (
|
|||||||
const (
|
const (
|
||||||
NodeNameTextModel = "生成文案"
|
NodeNameTextModel = "生成文案"
|
||||||
NodeNameImageModel = "生成图片"
|
NodeNameImageModel = "生成图片"
|
||||||
NodeNameVideoModel = "视频"
|
NodeNameVideoModel = "生成视频"
|
||||||
|
NodeNameSenseOptimize = "语义优化"
|
||||||
|
NodeNameStoryOptimize = "分镜优化"
|
||||||
|
NodeNameScriptOptimize = "剧本优化"
|
||||||
NodeNameAudioModel = "音频"
|
NodeNameAudioModel = "音频"
|
||||||
NodeNameModel = "模型"
|
NodeNameModel = "模型"
|
||||||
NodeNameMerge = "结果合并"
|
NodeNameMerge = "结果合并"
|
||||||
NodeNameJudge = "条件判断"
|
NodeNameJudge = "条件判断"
|
||||||
NodeNameForm = "表单"
|
NodeNameForm = "表单"
|
||||||
|
NodeNameHttp = "HTTP(S)接口"
|
||||||
NodeNameCustomNode = "自定义节点"
|
NodeNameCustomNode = "自定义节点"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,6 +49,9 @@ const (
|
|||||||
NodeTypeTextModel NodeType = "text_model"
|
NodeTypeTextModel NodeType = "text_model"
|
||||||
NodeTypeImageModel NodeType = "image_model"
|
NodeTypeImageModel NodeType = "image_model"
|
||||||
NodeTypeVideoModel NodeType = "video_model"
|
NodeTypeVideoModel NodeType = "video_model"
|
||||||
|
NodeTypeSenseOptimize NodeType = "sense_optimize"
|
||||||
|
NodeTypeStoryOptimize NodeType = "story_optimize"
|
||||||
|
NodeTypeScriptOptimize NodeType = "script_optimize"
|
||||||
NodeTypeAudioModel NodeType = "audio_model"
|
NodeTypeAudioModel NodeType = "audio_model"
|
||||||
|
|
||||||
// 基础
|
// 基础
|
||||||
@@ -53,7 +60,7 @@ const (
|
|||||||
NodeTypeJudge NodeType = "judge"
|
NodeTypeJudge NodeType = "judge"
|
||||||
NodeTypeForm NodeType = "form"
|
NodeTypeForm NodeType = "form"
|
||||||
NodeTypeIntent NodeType = "intent"
|
NodeTypeIntent NodeType = "intent"
|
||||||
|
NodeTypeHttp NodeType = "http"
|
||||||
// 自定义
|
// 自定义
|
||||||
NodeTypeCustomNode NodeType = "custom_node"
|
NodeTypeCustomNode NodeType = "custom_node"
|
||||||
)
|
)
|
||||||
@@ -102,91 +109,3 @@ type NodeGroupItem struct {
|
|||||||
Label string `json:"label"` // 从常量来
|
Label string `json:"label"` // 从常量来
|
||||||
Items []NodeItem `json:"items"`
|
Items []NodeItem `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
//// 文案模型节点定义
|
|
||||||
//func NewTextModelNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeTextModel,
|
|
||||||
// NodeName: NodeNameTextModel,
|
|
||||||
// FormConfig: []ModelItem{},
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 图片模型节点
|
|
||||||
//func NewImageModelNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeImageModel,
|
|
||||||
// NodeName: NodeNameImageModel,
|
|
||||||
// FormConfig: []ModelItem{},
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 音频模型节点
|
|
||||||
//func NewAudioModelNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeAudioModel,
|
|
||||||
// NodeName: NodeNameAudioModel,
|
|
||||||
// FormConfig: []ModelItem{},
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 视频模型节点
|
|
||||||
//func NewVideoModelNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeVideoModel,
|
|
||||||
// NodeName: NodeNameVideoModel,
|
|
||||||
// FormConfig: []ModelItem{},
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 基础模型节点
|
|
||||||
//func NewModelNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeModel,
|
|
||||||
// NodeName: NodeNameModel,
|
|
||||||
// FormConfig: []ModelItem{
|
|
||||||
// {
|
|
||||||
// ModelName: "模型名称",
|
|
||||||
// ModelForm: []NodeFormField{
|
|
||||||
// {Field: "apiKey", Label: FormLabelApiKey, Type: "input", Required: true},
|
|
||||||
// {Field: "model", Label: FormLabelModel, Type: "input", Required: true},
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 判断节点
|
|
||||||
//func NewJudgeNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeJudge,
|
|
||||||
// NodeName: NodeNameJudge,
|
|
||||||
// FormConfig: []ModelItem{
|
|
||||||
// {
|
|
||||||
// ModelName: "判断条件",
|
|
||||||
// ModelForm: []NodeFormField{
|
|
||||||
// {Field: "condition", Label: FormLabelCondition, Type: "input", Required: true},
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 表单参数节点
|
|
||||||
//func NewFormNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeForm,
|
|
||||||
// NodeName: NodeNameForm,
|
|
||||||
// FormConfig: []ModelItem{},
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 自定义节点
|
|
||||||
//func NewCustomNode() NodeItem {
|
|
||||||
// return NodeItem{
|
|
||||||
// NodeCode: NodeTypeCustomNode,
|
|
||||||
// NodeName: NodeNameCustomNode,
|
|
||||||
// FormConfig: []ModelItem{},
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"ai-agent/workflow/service"
|
"ai-agent/workflow/service"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type creationInfo struct{}
|
type creationInfo struct{}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
flowService "ai-agent/workflow/service/flow"
|
flowService "ai-agent/workflow/service/flow"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type flowExecution struct{}
|
type flowExecution struct{}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
flowService "ai-agent/workflow/service/flow"
|
flowService "ai-agent/workflow/service/flow"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
flowService "ai-agent/workflow/service/flow"
|
flowService "ai-agent/workflow/service/flow"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
skillService "ai-agent/workflow/service/skill"
|
skillService "ai-agent/workflow/service/skill"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type skillTemplate struct{}
|
type skillTemplate struct{}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
skillService "ai-agent/workflow/service/skill"
|
skillService "ai-agent/workflow/service/skill"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type skillUser struct{}
|
type skillUser struct{}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
@@ -137,6 +137,7 @@ type ExecuteReq struct {
|
|||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
SkillName string `json:"skillName"`
|
SkillName string `json:"skillName"`
|
||||||
FileUrl []string `json:"fileUrl"`
|
FileUrl []string `json:"fileUrl"`
|
||||||
|
ResultUrl string `json:"resultUrl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExecuteRes struct {
|
type ExecuteRes struct {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package skill
|
package skill
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package skill
|
package skill
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import "gitea.com/red-future/common/beans"
|
import "gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
|
||||||
type CreationInfo struct {
|
type CreationInfo struct {
|
||||||
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段:Id, TenantId, Creator, CreatedAt, Updater, UpdatedAt, DeletedAt
|
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段:Id, TenantId, Creator, CreatedAt, Updater, UpdatedAt, DeletedAt
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileTemp struct {
|
type FileTemp struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package entity
|
|||||||
import (
|
import (
|
||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FlowExecution struct {
|
type FlowExecution struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package entity
|
|||||||
import (
|
import (
|
||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FlowTemplate struct {
|
type FlowTemplate struct {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"ai-agent/workflow/consts/flow"
|
"ai-agent/workflow/consts/flow"
|
||||||
"ai-agent/workflow/consts/node"
|
"ai-agent/workflow/consts/node"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FlowInfo struct {
|
type FlowInfo struct {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SkillTemplate struct {
|
type SkillTemplate struct {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import "gitea.com/red-future/common/beans"
|
import "gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
|
||||||
type SkillUser struct {
|
type SkillUser struct {
|
||||||
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段:Id, TenantId, Creator, CreatedAt, Updater, UpdatedAt, DeletedAt
|
beans.SQLBaseDO `orm:",inherit"` // 嵌入基础字段:Id, TenantId, Creator, CreatedAt, Updater, UpdatedAt, DeletedAt
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/cloudwego/eino/schema"
|
"github.com/cloudwego/eino/schema"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/glog"
|
"github.com/gogf/gf/v2/os/glog"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/cloudwego/eino/compose"
|
"github.com/cloudwego/eino/compose"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
@@ -127,7 +127,7 @@ func (s *flowExecutionService) List(ctx context.Context, req *flowDto.ListFlowEx
|
|||||||
suffix = "图片"
|
suffix = "图片"
|
||||||
case strings.Contains(val, "html") || strings.Contains(val, "HTML"):
|
case strings.Contains(val, "html") || strings.Contains(val, "HTML"):
|
||||||
suffix = "HTML"
|
suffix = "HTML"
|
||||||
case strings.Contains(val, "txt") || len(val) > 50:
|
case strings.Contains(val, "inc") || len(val) > 50:
|
||||||
suffix = "文案"
|
suffix = "文案"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,29 +351,19 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//_, err = flowDao.FlowUserDao.Update(ctx, &flowDto.UpdateFlowUserReq{
|
if isDialogue && !g.IsEmpty(flowInfo) && !g.IsEmpty(req.ResultUrl) {
|
||||||
// Id: req.FlowId,
|
if strings.HasSuffix(gconv.String(req.ResultUrl), ".inc") {
|
||||||
// FlowContent: req.FlowContent,
|
err = TextModelSingleLambda(ctx, req, flowInfo)
|
||||||
// NodeInputParams: req.NodeInputParams,
|
return
|
||||||
//})
|
} else if strings.HasSuffix(gconv.String(req.ResultUrl), ".png") {
|
||||||
//if err != nil {
|
err = ImgModelSingleLambda(ctx, req, flowInfo)
|
||||||
// return nil, err
|
return
|
||||||
//}
|
} else if strings.HasSuffix(gconv.String(req.ResultUrl), ".html") {
|
||||||
|
err = TextImgModelSingleLambda(ctx, req, flowInfo)
|
||||||
//nodeInsert := make([]*nodeDto.CreateNodeExecutionReq, 0, len(flowInfo.NodeInputParams))
|
return
|
||||||
//for _, flowNode := range flowInfo.NodeInputParams {
|
}
|
||||||
// nodeInsert = append(nodeInsert, &nodeDto.CreateNodeExecutionReq{
|
return nil, errors.New("文件格式不支持")
|
||||||
// FlowExecutionId: executionId,
|
}
|
||||||
// NodeId: flowNode.Id,
|
|
||||||
// Status: node.NodeExecutionStatusWait.Code(),
|
|
||||||
// NodeInputParams: flowNode,
|
|
||||||
// TraceId: r.TraceId,
|
|
||||||
// })
|
|
||||||
//}
|
|
||||||
//_, err = nodeDao.NodeExecutionDao.BatchInsert(ctx, nodeInsert)
|
|
||||||
//if err != nil {
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// ✅【第1步】给所有判断节点自动生成意图识别节点
|
// ✅【第1步】给所有判断节点自动生成意图识别节点
|
||||||
@@ -415,7 +405,8 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
// ✅【第2步】构建执行图
|
// ✅【第2步】构建执行图
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
runGraph, err := BuildGraphFromFlowContent(execCtx, req.FlowContent, judge2IntentNodeMap, summaryNodeID)
|
var runGraph compose.Runnable[any, any]
|
||||||
|
runGraph, err = BuildGraphFromFlowContent(execCtx, req.FlowContent, judge2IntentNodeMap, summaryNodeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
executionReq := flowDto.UpdateFlowExecutionReq{
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
Id: executionId,
|
Id: executionId,
|
||||||
@@ -480,9 +471,7 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
|||||||
}
|
}
|
||||||
return nil, fmt.Errorf("执行工作流失败: %v", err)
|
return nil, fmt.Errorf("执行工作流失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildGraphFromFlowContent 根据前端保存的工作流JSON,自动构建执行图
|
// BuildGraphFromFlowContent 根据前端保存的工作流JSON,自动构建执行图
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import (
|
|||||||
"ai-agent/workflow/model/entity"
|
"ai-agent/workflow/model/entity"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
@@ -189,7 +191,12 @@ func (s *flowUserService) List(ctx context.Context, req *flowDto.ListFlowUserReq
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var user *beans.User
|
||||||
|
user, err = utils.GetUserInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Creator = user.UserName
|
||||||
list, total, err := flowDao.FlowUserDao.List(ctx, req)
|
list, total, err := flowDao.FlowUserDao.List(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -9,106 +9,19 @@ import (
|
|||||||
"ai-agent/workflow/model/dto"
|
"ai-agent/workflow/model/dto"
|
||||||
fileDto "ai-agent/workflow/model/dto/file"
|
fileDto "ai-agent/workflow/model/dto/file"
|
||||||
flowDto "ai-agent/workflow/model/dto/flow"
|
flowDto "ai-agent/workflow/model/dto/flow"
|
||||||
"ai-agent/workflow/model/entity"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/gfdb"
|
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetNodeContextContent(execInput *flowDto.FlowExecutionInput, node *entity.FlowNode) (map[string]any, map[string]any, map[string]any) {
|
|
||||||
|
|
||||||
input := make(map[string]any)
|
|
||||||
output := make(map[string]any)
|
|
||||||
model := make(map[string]any)
|
|
||||||
// 1. 有引用 → 取引用节点的字段值
|
|
||||||
if len(node.InputSource) > 0 {
|
|
||||||
for _, source := range node.InputSource {
|
|
||||||
refNodeID := source.NodeId
|
|
||||||
isQuoteOutput := source.QuoteOutput
|
|
||||||
fields := source.Field
|
|
||||||
|
|
||||||
refNode, ok := execInput.ConfigMap[refNodeID]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
inputMap := buildInputMap(refNode)
|
|
||||||
outputMap := mergeOutput(refNode.OutputResult)
|
|
||||||
modelMap := mergeModel(refNode.ModelConfig)
|
|
||||||
if isQuoteOutput {
|
|
||||||
for k, v := range outputMap {
|
|
||||||
output[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(fields) > 0 {
|
|
||||||
// 取指定字段
|
|
||||||
for _, f := range fields {
|
|
||||||
|
|
||||||
if v, ok := inputMap[f]; ok {
|
|
||||||
input[f] = v
|
|
||||||
}
|
|
||||||
if v, ok := modelMap[f]; ok {
|
|
||||||
model[f] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 取全部
|
|
||||||
for k, v := range inputMap {
|
|
||||||
input[k] = v
|
|
||||||
}
|
|
||||||
for k, v := range modelMap {
|
|
||||||
model[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return input, output, model
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildInputMap 从 FormConfig 构造输入map
|
|
||||||
func buildInputMap(node *entity.FlowNode) map[string]any {
|
|
||||||
m := make(map[string]any)
|
|
||||||
for _, item := range node.FormConfig {
|
|
||||||
m[item.Label] = item
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// mergeOutput 合并节点输出 []map → 单map
|
|
||||||
func mergeOutput(output []node.NodeFormField) map[string]any {
|
|
||||||
m := make(map[string]any)
|
|
||||||
for _, item := range output {
|
|
||||||
m[item.Label] = item
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// mergeOutput 合并节点输出 []map → 单map
|
|
||||||
// 合并成你需要的 { key: { value: xxx } } 结构
|
|
||||||
func mergeModel(output node.ModelItem) map[string]any {
|
|
||||||
m := make(map[string]any)
|
|
||||||
|
|
||||||
// 遍历 output.ModelForm 里的每一个 key 和原始值
|
|
||||||
for key, rawValue := range output.ModelForm {
|
|
||||||
// 包装成 { "value": 原始值 }
|
|
||||||
m[key] = map[string]any{
|
|
||||||
"value": rawValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func StartLambda(ctx context.Context, input any) (any, error) {
|
func StartLambda(ctx context.Context, input any) (any, error) {
|
||||||
return input, nil
|
return input, nil
|
||||||
}
|
}
|
||||||
@@ -118,9 +31,14 @@ func FormLambda(ctx context.Context, input any) (any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IntentLambda(ctx context.Context, input any) (any, error) {
|
func IntentLambda(ctx context.Context, input any) (any, error) {
|
||||||
|
return input, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// JudgeLambda 分支判断核心:读取IntentLambda的输出 → 返回目标节点ID做路由
|
||||||
|
func JudgeLambda(ctx context.Context, input any) (string, error) {
|
||||||
nodeInput, ok := input.(*flowDto.NodeExecutionInput)
|
nodeInput, ok := input.(*flowDto.NodeExecutionInput)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("入参类型错误,期望 *flowDto.NodeExecutionInput,实际 %T", input)
|
return "", fmt.Errorf("入参类型错误,期望 *flowDto.NodeExecutionInput,实际 %T", input)
|
||||||
}
|
}
|
||||||
// 1. 直接用你原来的方法(返回两个 map)
|
// 1. 直接用你原来的方法(返回两个 map)
|
||||||
inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
||||||
@@ -132,41 +50,21 @@ func IntentLambda(ctx context.Context, input any) (any, error) {
|
|||||||
}
|
}
|
||||||
for _, valueAny := range outputMap {
|
for _, valueAny := range outputMap {
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||||
if !strings.Contains(field.Field, "html") && !strings.Contains(field.Field, "img") {
|
|
||||||
outputResult = append(outputResult, field)
|
outputResult = append(outputResult, field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for _, valueAny := range modelMap {
|
for _, valueAny := range modelMap {
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||||
outputResult = append(outputResult, field)
|
outputResult = append(outputResult, field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeInput.Config.OutputResult = outputResult
|
|
||||||
|
|
||||||
return nodeInput, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// JudgeLambda 分支判断核心:读取IntentLambda的输出 → 返回目标节点ID做路由
|
|
||||||
func JudgeLambda(ctx context.Context, input any) (string, error) {
|
|
||||||
nodeInput, ok := input.(*flowDto.NodeExecutionInput)
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("入参类型错误,期望 *flowDto.NodeExecutionInput,实际 %T", input)
|
|
||||||
}
|
|
||||||
|
|
||||||
out := new([]node.NodeFormField)
|
|
||||||
err := gconv.Structs(nodeInput.Config.OutputResult, out)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
contextParts := ""
|
contextParts := ""
|
||||||
for _, v := range nodeInput.Config.FormConfig {
|
for _, v := range nodeInput.Config.FormConfig {
|
||||||
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
||||||
}
|
}
|
||||||
if !nodeInput.Global.IsDialogue {
|
if !nodeInput.Global.IsDialogue {
|
||||||
for _, v := range *out {
|
for _, v := range outputResult {
|
||||||
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
contextParts = fmt.Sprintf("%s,%s:%s", contextParts, v.Label, v.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,7 +87,6 @@ func JudgeLambda(ctx context.Context, input any) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
req := flowDto.ComposeMessagesReq{
|
req := flowDto.ComposeMessagesReq{
|
||||||
BuildType: 2,
|
BuildType: 2,
|
||||||
ModelName: getIsChatModel.ModelName,
|
ModelName: getIsChatModel.ModelName,
|
||||||
@@ -224,339 +121,28 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("入参类型错误")
|
return nil, fmt.Errorf("入参类型错误")
|
||||||
}
|
}
|
||||||
|
skillName, from, userFrom := BuildParam(nodeInput)
|
||||||
// 1. 直接用你原来的方法(返回两个 map)
|
outputRes, err := TextNode(ctx, nodeInput.Global.SessionId, nodeInput.Config.ModelConfig.ModelName, skillName, from, userFrom, nodeInput.Config.ModelConfig.ModelResponse, nodeInput.Global.FileUrl)
|
||||||
inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
|
||||||
var outputResult []node.NodeFormField
|
|
||||||
for _, valueAny := range inputMap {
|
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
|
||||||
outputResult = append(outputResult, field)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultUserFrom := make(map[string]any)
|
|
||||||
|
|
||||||
for _, valueAny := range outputMap {
|
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
|
||||||
if !strings.Contains(field.Field, "text_url") && !strings.Contains(field.Field, "img_url") {
|
|
||||||
if strings.Contains(field.Field, "text_content") {
|
|
||||||
field.Value = stripHtmlTags(field.Value, false)
|
|
||||||
}
|
|
||||||
resultUserFrom[field.Label] = field
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, valueAny := range modelMap {
|
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
|
||||||
outputResult = append(outputResult, field)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !nodeInput.Global.IsDialogue {
|
|
||||||
for _, item := range outputResult {
|
|
||||||
resultUserFrom[item.Label] = item
|
|
||||||
}
|
|
||||||
for _, item := range nodeInput.Config.FormConfig {
|
|
||||||
resultUserFrom[item.Label] = item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(nodeInput.Global.Desc) {
|
|
||||||
resultUserFrom["desc"] = node.NodeFormField{
|
|
||||||
Value: nodeInput.Global.Desc,
|
|
||||||
Field: "desc",
|
|
||||||
Label: "描述",
|
|
||||||
Type: "text",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resultFrom := make(map[string]any)
|
|
||||||
for key, item := range nodeInput.Config.ModelConfig.ModelForm {
|
|
||||||
resultFrom[key] = map[string]any{
|
|
||||||
"value": item,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var skillName = nodeInput.Config.SkillName
|
|
||||||
if g.IsEmpty(nodeInput.Config.SkillName) {
|
|
||||||
skillName = nodeInput.Global.SkillName
|
|
||||||
}
|
|
||||||
contentStr := "你是专业内容生成助手,请严格按以下规则输出内容:1、输出标准 HTML 片段,不要 Markdown,不要 ``` 符号,不要多余解释,2、整体用 <div class=\"report-container\"> 包裹,3、主标题使用 <h2 class=\"title\">,4、章节标题使用 <h3 class=\"section-title\">,5、正文段落使用 <p class=\"paragraph\">,6、列表使用 <ul class=\"list\"><li>...</li></ul>,7、重点内容使用 <strong> 加粗,8、段落之间清晰分隔,结构规整,9、如果生成多条文案,每条文案独立用 <div class=\"content-item\" id=\"content-{序号}\"> 包裹(序号从1开始),10、每条文案内部必须在最上方添加一行固定格式:<p class=\"image-count\">需要配图:N 张</p> N 是这条文案需要的图片数量,只能是数字,不能是其他文字,11、只输出 HTML 结构,不输出任何额外文字"
|
|
||||||
resultUserFrom["prompt"] = contentStr
|
|
||||||
|
|
||||||
req := flowDto.ComposeMessagesReq{
|
|
||||||
BuildType: 1,
|
|
||||||
ModelName: nodeInput.Config.ModelConfig.ModelName,
|
|
||||||
SkillName: skillName,
|
|
||||||
Cause: "文案节点",
|
|
||||||
Form: resultFrom,
|
|
||||||
UserForm: resultUserFrom,
|
|
||||||
UserFiles: nodeInput.Global.FileUrl,
|
|
||||||
SessionId: nodeInput.Global.SessionId,
|
|
||||||
}
|
|
||||||
|
|
||||||
msg, err := ComposeMessages(ctx, &req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if g.IsEmpty(msg.Messages) {
|
|
||||||
return nil, fmt.Errorf("msg is empty")
|
|
||||||
}
|
|
||||||
taskResult, err := GatewayTask(ctx, msg.EpicycleId, nodeInput.Config.ModelConfig.ModelName, msg.Messages)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := GetTaskResult(ctx, taskResult)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
mapTaskResult := gconv.Map(result.Text)
|
|
||||||
|
|
||||||
resultContent := ""
|
|
||||||
for key, _ := range nodeInput.Config.ModelConfig.ModelResponse {
|
|
||||||
resultContent = gconv.String(mapTaskResult[key])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拆分多条文案
|
|
||||||
contentList := SplitMultiContents(resultContent)
|
|
||||||
|
|
||||||
outputRes := make([]node.NodeFormField, 0)
|
|
||||||
for i, content := range contentList {
|
|
||||||
// 文案内容:content_0, content_1, content_2...
|
|
||||||
outputRes = append(outputRes, node.NodeFormField{
|
|
||||||
Field: fmt.Sprintf("text_content_%d", i),
|
|
||||||
Value: content,
|
|
||||||
Label: fmt.Sprintf("文案内容_%d", i),
|
|
||||||
Type: "string",
|
|
||||||
Expand: extractImageCount(content),
|
|
||||||
})
|
|
||||||
|
|
||||||
// 1. 去掉 HTML 标签,生成纯文本
|
|
||||||
plainText := stripHtmlTags(content, true)
|
|
||||||
// 2. 上传纯文本到 OSS
|
|
||||||
textFileName := fmt.Sprintf("ai_text_%d_%d.txt", time.Now().UnixMilli(), i)
|
|
||||||
textUrl, err := Upload(ctx, &dto.UploadFileBytesReq{
|
|
||||||
FileBytes: []byte(plainText),
|
|
||||||
FileName: textFileName,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// 3. 把纯文本地址存入输出
|
|
||||||
outputRes = append(outputRes, node.NodeFormField{
|
|
||||||
Field: fmt.Sprintf("%v:text_url:%d", nodeInput.Config.Id, i),
|
|
||||||
Value: textUrl.FileURL,
|
|
||||||
Label: fmt.Sprintf("文案纯文本_txt_%d", i),
|
|
||||||
Type: "string",
|
|
||||||
Expand: extractImageCount(content),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
nodeInput.Config.OutputResult = outputRes
|
nodeInput.Config.OutputResult = outputRes
|
||||||
|
|
||||||
return nodeInput, nil
|
return nodeInput, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 HTML 内容里提取图片数量(例如从 <p class="image-count">需要配图:3 张</p> 拿到 3)
|
|
||||||
func extractImageCount(content string) int {
|
|
||||||
re := regexp.MustCompile(`<p class="image-count">[^\d]*(\d+)[^\d]*</p>`)
|
|
||||||
match := re.FindStringSubmatch(content)
|
|
||||||
if len(match) >= 2 {
|
|
||||||
num, _ := strconv.Atoi(match[1])
|
|
||||||
return num
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// stripHtmlTags 去掉所有HTML标签,保留换行和文本结构,并删除配图标记行
|
|
||||||
func stripHtmlTags(html string, delImageCount bool) string {
|
|
||||||
if delImageCount {
|
|
||||||
// 🔥 第一步:直接删除整个 <p class="image-count">...</p> 标签(包含内容)
|
|
||||||
imageTagRegex := regexp.MustCompile(`<p class="image-count">[\s\S]*?</p>`)
|
|
||||||
html = imageTagRegex.ReplaceAllString(html, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 替换块级标签为换行,保证排版
|
|
||||||
blockTags := regexp.MustCompile(`</?(div|p|h1|h2|h3|h4|h5|h6|li|ul|ol|br|tr|td|th)[^>]*>`)
|
|
||||||
text := blockTags.ReplaceAllString(html, "\n")
|
|
||||||
|
|
||||||
// 2. 去掉所有剩余的 HTML 标签
|
|
||||||
allTags := regexp.MustCompile(`<[^>]+>`)
|
|
||||||
text = allTags.ReplaceAllString(text, "")
|
|
||||||
|
|
||||||
// 4. 清理多余空行(多个换行只保留一个)
|
|
||||||
text = regexp.MustCompile(`\n\s*\n`).ReplaceAllString(text, "\n")
|
|
||||||
|
|
||||||
// 5. 只去掉首尾空白,中间换行保留
|
|
||||||
text = strings.TrimSpace(text)
|
|
||||||
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
// SplitMultiContents 拆分模型返回的多条文案(基于HTML标签分隔)
|
|
||||||
func SplitMultiContents(htmlContent string) []string {
|
|
||||||
var contents []string
|
|
||||||
// 正则匹配<div class="content-item" id="content-{序号}">包裹的内容
|
|
||||||
re := regexp.MustCompile(`<div class="content-item" id="content-\d+">([\s\S]*?)</div>`)
|
|
||||||
matches := re.FindAllStringSubmatch(htmlContent, -1)
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) > 1 {
|
|
||||||
// 清理空内容
|
|
||||||
trimmed := strings.TrimSpace(match[1])
|
|
||||||
if trimmed != "" {
|
|
||||||
contents = append(contents, trimmed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 兜底:如果没有匹配到结构化内容,按换行/分隔符拆分
|
|
||||||
if len(contents) == 0 {
|
|
||||||
contents = strings.Split(htmlContent, "===分隔符===") // 提示词中可新增此兜底规则
|
|
||||||
}
|
|
||||||
return contents
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageModelLambda 构建图片
|
// ImageModelLambda 构建图片
|
||||||
func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
func ImageModelLambda(ctx context.Context, input any) (any, error) {
|
||||||
nodeInput, ok := input.(*flowDto.NodeExecutionInput)
|
nodeInput, ok := input.(*flowDto.NodeExecutionInput)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("入参类型错误")
|
return nil, fmt.Errorf("入参类型错误")
|
||||||
}
|
}
|
||||||
// 1. 直接用你原来的方法(返回两个 map)
|
skillName, from, userFrom := BuildParam(nodeInput)
|
||||||
inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
outputRes, err := ImgNode(ctx, nodeInput.Global.SessionId, nodeInput.Config.ModelConfig.ModelName, skillName, from, userFrom, nodeInput.Config.ModelConfig.ModelResponse, nodeInput.Global.FileUrl)
|
||||||
var outputResult []node.NodeFormField
|
|
||||||
for _, valueAny := range inputMap {
|
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
|
||||||
outputResult = append(outputResult, field)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resultUserFrom := make(map[string]any)
|
|
||||||
|
|
||||||
for _, valueAny := range outputMap {
|
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
|
||||||
if !strings.Contains(field.Field, "text_url") && !strings.Contains(field.Field, "img_url") {
|
|
||||||
if strings.Contains(field.Field, "text_content") {
|
|
||||||
field.Value = stripHtmlTags(field.Value, false)
|
|
||||||
}
|
|
||||||
resultUserFrom[field.Label] = field
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, valueAny := range modelMap {
|
|
||||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
|
||||||
outputResult = append(outputResult, field)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !nodeInput.Global.IsDialogue {
|
|
||||||
for _, item := range outputResult {
|
|
||||||
resultUserFrom[item.Label] = item
|
|
||||||
}
|
|
||||||
for _, item := range nodeInput.Config.FormConfig {
|
|
||||||
resultUserFrom[item.Label] = item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(nodeInput.Global.Desc) {
|
|
||||||
resultUserFrom["desc"] = node.NodeFormField{
|
|
||||||
Value: nodeInput.Global.Desc,
|
|
||||||
Field: "desc",
|
|
||||||
Label: "描述",
|
|
||||||
Type: "text",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resultFrom := make(map[string]any)
|
|
||||||
for key, item := range nodeInput.Config.ModelConfig.ModelForm {
|
|
||||||
resultFrom[key] = map[string]any{
|
|
||||||
"value": item,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var skillName = nodeInput.Config.SkillName
|
|
||||||
if g.IsEmpty(nodeInput.Config.SkillName) {
|
|
||||||
skillName = nodeInput.Global.SkillName
|
|
||||||
}
|
|
||||||
|
|
||||||
req := flowDto.ComposeMessagesReq{
|
|
||||||
BuildType: 1,
|
|
||||||
ModelName: nodeInput.Config.ModelConfig.ModelName,
|
|
||||||
SkillName: skillName,
|
|
||||||
Cause: "图片节点",
|
|
||||||
Form: resultFrom,
|
|
||||||
UserForm: resultUserFrom,
|
|
||||||
UserFiles: nodeInput.Global.FileUrl,
|
|
||||||
SessionId: nodeInput.Global.SessionId,
|
|
||||||
}
|
|
||||||
msg, err := ComposeMessages(ctx, &req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if g.IsEmpty(msg.Messages) {
|
|
||||||
return nil, fmt.Errorf("msg is empty")
|
|
||||||
}
|
|
||||||
taskResult, err := GatewayTask(ctx, msg.EpicycleId, nodeInput.Config.ModelConfig.ModelName, msg.Messages)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := GetTaskResult(ctx, taskResult)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
mapTaskResult := gconv.Map(result.Text)
|
|
||||||
|
|
||||||
imgs := []string{}
|
|
||||||
for key, _ := range nodeInput.Config.ModelConfig.ModelResponse {
|
|
||||||
imgs = gconv.Strings(mapTaskResult[key])
|
|
||||||
}
|
|
||||||
|
|
||||||
var images []string
|
|
||||||
for _, item := range imgs {
|
|
||||||
mapItem := gconv.Map(item)
|
|
||||||
for _, value := range mapItem {
|
|
||||||
values := ""
|
|
||||||
values, ok = value.(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("图片地址类型错误")
|
|
||||||
}
|
|
||||||
// 下载官方临时图片
|
|
||||||
imgBytes, _, err := GetImageBytesFromURL(values)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("下载图片失败: %w", err)
|
|
||||||
}
|
|
||||||
// 构造文件名
|
|
||||||
fileName := fmt.Sprintf("ai_image_%d.png", time.Now().UnixMilli())
|
|
||||||
// 上传到你的OSS(你项目已有的Upload方法)
|
|
||||||
upResp, err := Upload(ctx, &dto.UploadFileBytesReq{
|
|
||||||
FileName: fileName,
|
|
||||||
FileBytes: imgBytes,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("上传OSS失败: %w", err)
|
|
||||||
}
|
|
||||||
images = append(images, upResp.FileURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
url, err := utils.GetFileAddressPrefix(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
outputRes := make([]node.NodeFormField, 0)
|
|
||||||
|
|
||||||
for i, item := range images {
|
|
||||||
// 图片:image_0, image_1, image_2...
|
|
||||||
outputRes = append(outputRes, node.NodeFormField{
|
|
||||||
Field: fmt.Sprintf("image_%d", i),
|
|
||||||
Value: fmt.Sprintf("%s%s", url, item),
|
|
||||||
Label: fmt.Sprintf("图片_%d", i),
|
|
||||||
Type: "string",
|
|
||||||
})
|
|
||||||
// 额外存储关联关系
|
|
||||||
outputRes = append(outputRes, node.NodeFormField{
|
|
||||||
Field: fmt.Sprintf("%v:img_url:%d", nodeInput.Config.Id, i),
|
|
||||||
Value: fmt.Sprintf("%s%s", url, item),
|
|
||||||
Label: fmt.Sprintf("图片_img_%d关联文案ID", i),
|
|
||||||
Type: "string",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
nodeInput.Config.OutputResult = outputRes
|
nodeInput.Config.OutputResult = outputRes
|
||||||
return input, nil
|
return nodeInput, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MergeLambda(ctx context.Context, input any) (any, error) {
|
func MergeLambda(ctx context.Context, input any) (any, error) {
|
||||||
@@ -577,7 +163,7 @@ func MergeLambda(ctx context.Context, input any) (any, error) {
|
|||||||
// 2. 提取所有文案:text_content_0,1,2...
|
// 2. 提取所有文案:text_content_0,1,2...
|
||||||
var contents []node.NodeFormField
|
var contents []node.NodeFormField
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
key := fmt.Sprintf("text_content_%d", i)
|
key := fmt.Sprintf("text_url:%d", i)
|
||||||
val, has := dataMap[key]
|
val, has := dataMap[key]
|
||||||
if !has || val.Value == "" {
|
if !has || val.Value == "" {
|
||||||
break
|
break
|
||||||
@@ -588,7 +174,7 @@ func MergeLambda(ctx context.Context, input any) (any, error) {
|
|||||||
// 3. 提取所有图片:image_0,1,2...
|
// 3. 提取所有图片:image_0,1,2...
|
||||||
var images []string
|
var images []string
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
key := fmt.Sprintf("image_%d", i)
|
key := fmt.Sprintf("img_url:%d", i)
|
||||||
val, has := dataMap[key]
|
val, has := dataMap[key]
|
||||||
if !has || val.Value == "" {
|
if !has || val.Value == "" {
|
||||||
break
|
break
|
||||||
@@ -638,11 +224,15 @@ func MergeLambda(ctx context.Context, input any) (any, error) {
|
|||||||
// 🔥 把现有数据转换成通用 Item 列表(支持:纯文案、纯图片、图文任意组合)
|
// 🔥 把现有数据转换成通用 Item 列表(支持:纯文案、纯图片、图文任意组合)
|
||||||
var allItems []Item
|
var allItems []Item
|
||||||
|
|
||||||
|
url, err := utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// 情况1:有文案 → 按文案条目生成 Item(每条文案+对应图片)
|
// 情况1:有文案 → 按文案条目生成 Item(每条文案+对应图片)
|
||||||
if len(contents) > 0 {
|
if len(contents) > 0 {
|
||||||
for i, val := range contents {
|
for i, val := range contents {
|
||||||
item := Item{
|
item := Item{
|
||||||
Content: val.Value, // 文案
|
Content: url + val.Value, // 文案
|
||||||
Images: textImgMap[i], // 自动绑定该条目的图片(没有则为空切片)
|
Images: textImgMap[i], // 自动绑定该条目的图片(没有则为空切片)
|
||||||
}
|
}
|
||||||
allItems = append(allItems, item)
|
allItems = append(allItems, item)
|
||||||
@@ -668,143 +258,7 @@ func MergeLambda(ctx context.Context, input any) (any, error) {
|
|||||||
// 支持任意来源:文生图、图生文、单独文、单独图、文图合并
|
// 支持任意来源:文生图、图生文、单独文、单独图、文图合并
|
||||||
|
|
||||||
// 生成单条HTML
|
// 生成单条HTML
|
||||||
var htmlBuilder strings.Builder
|
htmlContent := BuildHtml(item.Content, item.Images)
|
||||||
htmlBuilder.WriteString(`
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
font-family: "Microsoft YaHei", "PingFang SC", Arial, sans-serif;
|
|
||||||
background: #f5f5f5;
|
|
||||||
color: #333;
|
|
||||||
line-height: 1.8;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
max-width: 900px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.item {
|
|
||||||
padding: 30px;
|
|
||||||
}
|
|
||||||
.image-group {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
.image-group img {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.image-group img:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.text {
|
|
||||||
padding: 0;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 1.8;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
.text h2 {
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #1a1a1a;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.text h3 {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 20px 0 12px;
|
|
||||||
padding-left: 12px;
|
|
||||||
border-left: 4px solid #409eff;
|
|
||||||
}
|
|
||||||
.text p {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
.text strong {
|
|
||||||
color: #e74c3c;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
.text ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 15px 0;
|
|
||||||
}
|
|
||||||
.text ul li {
|
|
||||||
padding: 10px 0 10px 30px;
|
|
||||||
position: relative;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
.text ul li:before {
|
|
||||||
content: "●";
|
|
||||||
color: #409eff;
|
|
||||||
font-size: 12px;
|
|
||||||
position: absolute;
|
|
||||||
left: 12px;
|
|
||||||
top: 12px;
|
|
||||||
}
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
body {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
.item {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
.text h2 {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
.text h3 {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="item">
|
|
||||||
`)
|
|
||||||
|
|
||||||
// 写入图片(支持0张、1张、多张)
|
|
||||||
if len(item.Images) > 0 {
|
|
||||||
htmlBuilder.WriteString(`<div class="image-group">`)
|
|
||||||
for _, imgUrl := range item.Images {
|
|
||||||
htmlBuilder.WriteString(fmt.Sprintf(`<img src="%s" alt="图片"/>`, imgUrl))
|
|
||||||
}
|
|
||||||
htmlBuilder.WriteString(`</div>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🔥 写入文案前:删除 <p class="image-count">需要配图:X 张</p>
|
|
||||||
if item.Content != "" {
|
|
||||||
// 正则删除整行
|
|
||||||
re := regexp.MustCompile(`<p class="image-count">需要配图:\d+ 张</p>`)
|
|
||||||
cleanContent := re.ReplaceAllString(item.Content, "")
|
|
||||||
|
|
||||||
// 写入清理后的文案
|
|
||||||
htmlBuilder.WriteString(fmt.Sprintf(`<div class="text">%s</div>`, cleanContent))
|
|
||||||
}
|
|
||||||
|
|
||||||
htmlBuilder.WriteString(`</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>`)
|
|
||||||
htmlContent := htmlBuilder.String()
|
|
||||||
|
|
||||||
// 上传OSS(每条独立上传)
|
// 上传OSS(每条独立上传)
|
||||||
fileName := fmt.Sprintf("item_%d_%d.html", idx, time.Now().UnixMilli())
|
fileName := fmt.Sprintf("item_%d_%d.html", idx, time.Now().UnixMilli())
|
||||||
@@ -832,13 +286,13 @@ func MergeLambda(ctx context.Context, input any) (any, error) {
|
|||||||
Type: "text",
|
Type: "text",
|
||||||
},
|
},
|
||||||
node.NodeFormField{
|
node.NodeFormField{
|
||||||
Field: fmt.Sprintf("item_text_%d", idx),
|
Field: fmt.Sprintf("item_txt_url_%d", idx),
|
||||||
Value: item.Content,
|
Value: item.Content,
|
||||||
Label: fmt.Sprintf("条目%d 文案", idx+1),
|
Label: fmt.Sprintf("条目%d 文案", idx+1),
|
||||||
Type: "text",
|
Type: "text",
|
||||||
},
|
},
|
||||||
node.NodeFormField{
|
node.NodeFormField{
|
||||||
Field: fmt.Sprintf("item_images_%d", idx),
|
Field: fmt.Sprintf("item_image_url_%d", idx),
|
||||||
Value: strings.Join(item.Images, ","),
|
Value: strings.Join(item.Images, ","),
|
||||||
Label: fmt.Sprintf("条目%d 图片", idx+1),
|
Label: fmt.Sprintf("条目%d 图片", idx+1),
|
||||||
Type: "text",
|
Type: "text",
|
||||||
@@ -887,9 +341,9 @@ func SummaryLambda(ctx context.Context, input any) (any, error) {
|
|||||||
|
|
||||||
executionReq := flowDto.UpdateFlowExecutionReq{
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
Id: execInput.Global.ExecutionId,
|
Id: execInput.Global.ExecutionId,
|
||||||
|
Status: flow.FlowExecutionStatusSuccess.Code(),
|
||||||
OutputParams: summaryResult,
|
OutputParams: summaryResult,
|
||||||
}
|
}
|
||||||
executionReq.Status = flow.FlowExecutionStatusSuccess.Code()
|
|
||||||
_, err = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
_, err = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
|
|
||||||
if flowInfo != nil {
|
if flowInfo != nil {
|
||||||
|
|||||||
599
workflow/service/flow/lambda_node_imp.go
Normal file
599
workflow/service/flow/lambda_node_imp.go
Normal file
@@ -0,0 +1,599 @@
|
|||||||
|
package flow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ai-agent/workflow/consts/flow"
|
||||||
|
"ai-agent/workflow/consts/node"
|
||||||
|
flowDao "ai-agent/workflow/dao/flow"
|
||||||
|
"ai-agent/workflow/model/dto"
|
||||||
|
flowDto "ai-agent/workflow/model/dto/flow"
|
||||||
|
"ai-agent/workflow/model/entity"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getNodeInfo(flowInfo *entity.FlowExecution) (htmlUrl []string, textModelName string, textResultFrom map[string]any, textModelResponse map[string]any, imgModelName string, imgResultFrom map[string]any, imgModelResponse map[string]any) {
|
||||||
|
textModelName = ""
|
||||||
|
textResultFrom = make(map[string]any)
|
||||||
|
textModelResponse = make(map[string]any)
|
||||||
|
imgModelName = ""
|
||||||
|
imgResultFrom = make(map[string]any)
|
||||||
|
imgModelResponse = make(map[string]any)
|
||||||
|
// 查询节点中是否包含结果合并节点
|
||||||
|
for _, item := range flowInfo.NodeInputParams {
|
||||||
|
if item.NodeCode == node.NodeTypeMerge {
|
||||||
|
for _, outputParamsItem := range flowInfo.OutputParams {
|
||||||
|
outputParamsMap := gconv.Map(outputParamsItem)
|
||||||
|
for _, mapItem := range outputParamsMap {
|
||||||
|
if strings.HasSuffix(gconv.String(mapItem), ".html") {
|
||||||
|
htmlUrl = append(htmlUrl, gconv.String(mapItem))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if item.NodeCode == node.NodeTypeTextModel {
|
||||||
|
textModelName = item.ModelConfig.ModelName
|
||||||
|
textModelResponse = item.ModelConfig.ModelResponse
|
||||||
|
for key, modelFormItem := range item.ModelConfig.ModelForm {
|
||||||
|
textResultFrom[key] = map[string]any{
|
||||||
|
"value": modelFormItem,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if item.NodeCode == node.NodeTypeImageModel {
|
||||||
|
imgModelName = item.ModelConfig.ModelName
|
||||||
|
imgModelResponse = item.ModelConfig.ModelResponse
|
||||||
|
for key, modelFormItem := range item.ModelConfig.ModelForm {
|
||||||
|
imgResultFrom[key] = map[string]any{
|
||||||
|
"value": modelFormItem,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlUrl, textModelName, textResultFrom, textModelResponse, imgModelName, imgResultFrom, imgModelResponse
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextImgModelSingleLambda(ctx context.Context, req *flowDto.ExecuteReq, flowInfo *entity.FlowExecution) (err error) {
|
||||||
|
_, textModelName, textResultFrom, textModelResponse, imgModelName, imgResultFrom, imgModelResponse := getNodeInfo(flowInfo)
|
||||||
|
|
||||||
|
resultUserFrom := make(map[string]any)
|
||||||
|
resultUserFrom["desc"] = req.Desc
|
||||||
|
|
||||||
|
var textNode []node.NodeFormField
|
||||||
|
textNode, err = TextNode(ctx, req.SessionId, textModelName, req.SkillName, textResultFrom, resultUserFrom, textModelResponse, req.FileUrl)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var textContent string
|
||||||
|
var textUrl string
|
||||||
|
for _, item := range textNode {
|
||||||
|
if strings.Contains(item.Field, "text_content") {
|
||||||
|
textContent = StripHtmlTags(item.Value)
|
||||||
|
}
|
||||||
|
if strings.Contains(item.Field, "text_url") {
|
||||||
|
textUrl = item.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultUserFrom["text_content"] = textContent
|
||||||
|
var imgNode []node.NodeFormField
|
||||||
|
imgNode, err = ImgNode(ctx, req.SessionId, imgModelName, req.SkillName, imgResultFrom, resultUserFrom, imgModelResponse, req.FileUrl)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var imgUrl []string
|
||||||
|
for _, item := range imgNode {
|
||||||
|
if strings.Contains(item.Field, "img_url") {
|
||||||
|
imgUrl = append(imgUrl, item.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成单条HTML
|
||||||
|
htmlContent := BuildHtml(textUrl, imgUrl)
|
||||||
|
// 上传OSS(每条独立上传)
|
||||||
|
fileName := fmt.Sprintf("item_%d_%d.html", 0, time.Now().UnixMilli())
|
||||||
|
var ossResult *dto.UploadFileBytesRes
|
||||||
|
ossResult, err = Upload(ctx, &dto.UploadFileBytesReq{
|
||||||
|
FileBytes: []byte(htmlContent),
|
||||||
|
FileName: fileName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("上传OSS成功:%s", ossResult.FileURL)
|
||||||
|
|
||||||
|
var summaryResult []map[string]interface{}
|
||||||
|
for _, outputParamsItem := range flowInfo.OutputParams {
|
||||||
|
mapItem := gconv.Map(outputParamsItem)
|
||||||
|
for _, mapValue := range mapItem {
|
||||||
|
if strings.Contains(req.ResultUrl, gconv.String(mapValue)) {
|
||||||
|
// 生成 毫秒时间戳 作为 KEY
|
||||||
|
timeKey := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
item := make(map[string]interface{})
|
||||||
|
item[timeKey] = ossResult.FileURL
|
||||||
|
summaryResult = append(summaryResult, item)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
summaryResult = append(summaryResult, outputParamsItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !g.IsEmpty(summaryResult) {
|
||||||
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: flowInfo.Id,
|
||||||
|
Status: flow.FlowExecutionStatusSuccess.Code(),
|
||||||
|
OutputParams: summaryResult,
|
||||||
|
}
|
||||||
|
_, err = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImgModelSingleLambda(ctx context.Context, req *flowDto.ExecuteReq, flowInfo *entity.FlowExecution) (err error) {
|
||||||
|
var url string
|
||||||
|
url, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
htmlUrl, _, _, _, imgModelName, imgResultFrom, imgModelResponse := getNodeInfo(flowInfo)
|
||||||
|
|
||||||
|
resultUserFrom := make(map[string]any)
|
||||||
|
resultUserFrom["desc"] = req.Desc
|
||||||
|
|
||||||
|
var imgNode []node.NodeFormField
|
||||||
|
imgNode, err = ImgNode(ctx, req.SessionId, imgModelName, req.SkillName, imgResultFrom, resultUserFrom, imgModelResponse, req.FileUrl)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var imgUrl string
|
||||||
|
for _, item := range imgNode {
|
||||||
|
if strings.Contains(item.Field, "img_url") {
|
||||||
|
imgUrl = item.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var htmlContentUrl string
|
||||||
|
var oldHtmlUrl string
|
||||||
|
if !g.IsEmpty(htmlUrl) {
|
||||||
|
for i, item := range htmlUrl {
|
||||||
|
var htmlBytes []byte
|
||||||
|
htmlBytes, err = GetFileBytesFromURL(url + item)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
htmlContent := string(htmlBytes)
|
||||||
|
|
||||||
|
imgSrcFromHtml := GetAllImgSrcFromHtml(htmlContent)
|
||||||
|
// 3. 标记是否需要替换
|
||||||
|
needReplace := false
|
||||||
|
for _, imgSrc := range imgSrcFromHtml {
|
||||||
|
if imgSrc == req.ResultUrl {
|
||||||
|
needReplace = true
|
||||||
|
break // 找到一个就可以替换
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 如果匹配到,执行替换(把旧的 req.ResultUrl 替换成 新链接)
|
||||||
|
if needReplace {
|
||||||
|
oldHtmlUrl = url + item
|
||||||
|
htmlContent = ReplaceImgSrc(htmlContent, req.ResultUrl, imgUrl)
|
||||||
|
// 上传OSS(每条独立上传)
|
||||||
|
fileName := fmt.Sprintf("item_%d_%d.html", i, time.Now().UnixMilli())
|
||||||
|
var ossResult *dto.UploadFileBytesRes
|
||||||
|
ossResult, err = Upload(ctx, &dto.UploadFileBytesReq{
|
||||||
|
FileBytes: []byte(htmlContent),
|
||||||
|
FileName: fileName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("上传OSS成功:%s", ossResult.FileURL)
|
||||||
|
htmlContentUrl = ossResult.FileURL
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var summaryResult []map[string]interface{}
|
||||||
|
if !g.IsEmpty(imgUrl) {
|
||||||
|
for _, outputParamsItem := range flowInfo.OutputParams {
|
||||||
|
mapItem := gconv.Map(outputParamsItem)
|
||||||
|
for _, mapValue := range mapItem {
|
||||||
|
if strings.Contains(oldHtmlUrl, gconv.String(mapValue)) || strings.Contains(req.ResultUrl, gconv.String(mapValue)) {
|
||||||
|
if strings.Contains(oldHtmlUrl, gconv.String(mapValue)) {
|
||||||
|
// 生成 毫秒时间戳 作为 KEY
|
||||||
|
timeKey := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
item := make(map[string]interface{})
|
||||||
|
item[timeKey] = htmlContentUrl
|
||||||
|
summaryResult = append(summaryResult, item)
|
||||||
|
}
|
||||||
|
if strings.Contains(req.ResultUrl, gconv.String(mapValue)) {
|
||||||
|
// 生成 毫秒时间戳 作为 KEY
|
||||||
|
timeKey := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
item := make(map[string]interface{})
|
||||||
|
item[timeKey] = imgUrl
|
||||||
|
summaryResult = append(summaryResult, item)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
summaryResult = append(summaryResult, outputParamsItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !g.IsEmpty(summaryResult) {
|
||||||
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: flowInfo.Id,
|
||||||
|
Status: flow.FlowExecutionStatusSuccess.Code(),
|
||||||
|
OutputParams: summaryResult,
|
||||||
|
}
|
||||||
|
_, err = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextModelSingleLambda(ctx context.Context, req *flowDto.ExecuteReq, flowInfo *entity.FlowExecution) (err error) {
|
||||||
|
var url string
|
||||||
|
url, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
htmlUrl, textModelName, textResultFrom, textModelResponse, _, _, _ := getNodeInfo(flowInfo)
|
||||||
|
|
||||||
|
resultUserFrom := make(map[string]any)
|
||||||
|
resultUserFrom["desc"] = req.Desc
|
||||||
|
|
||||||
|
var textNode []node.NodeFormField
|
||||||
|
textNode, err = TextNode(ctx, req.SessionId, textModelName, req.SkillName, textResultFrom, resultUserFrom, textModelResponse, req.FileUrl)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var textUrl string
|
||||||
|
for _, item := range textNode {
|
||||||
|
if strings.Contains(item.Field, "text_url") {
|
||||||
|
textUrl = item.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var htmlContentUrl string
|
||||||
|
var oldHtmlUrl string
|
||||||
|
if !g.IsEmpty(htmlUrl) {
|
||||||
|
for i, item := range htmlUrl {
|
||||||
|
var htmlBytes []byte
|
||||||
|
htmlBytes, err = GetFileBytesFromURL(url + item)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
htmlContent := string(htmlBytes)
|
||||||
|
|
||||||
|
// 1) 匹配出 incUrl 的值
|
||||||
|
incRegex := regexp.MustCompile(`incUrl\s*=\s*"([^"]+)"`)
|
||||||
|
match := incRegex.FindStringSubmatch(htmlContent)
|
||||||
|
// 2) 获取模板里原来的 incUrl
|
||||||
|
oldIncUrl := ""
|
||||||
|
if len(match) >= 2 {
|
||||||
|
oldIncUrl = match[1] // 这是模板里的旧链接
|
||||||
|
}
|
||||||
|
// 3) 对比:不一样才替换
|
||||||
|
if oldIncUrl == req.ResultUrl {
|
||||||
|
oldHtmlUrl = url + item
|
||||||
|
// 替换成新的链接
|
||||||
|
htmlContent = incRegex.ReplaceAllString(htmlContent, fmt.Sprintf(`incUrl = "%s"`, url+textUrl))
|
||||||
|
// 上传OSS(每条独立上传)
|
||||||
|
fileName := fmt.Sprintf("item_%d_%d.html", i, time.Now().UnixMilli())
|
||||||
|
var ossResult *dto.UploadFileBytesRes
|
||||||
|
ossResult, err = Upload(ctx, &dto.UploadFileBytesReq{
|
||||||
|
FileBytes: []byte(htmlContent),
|
||||||
|
FileName: fileName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("上传OSS成功:%s", ossResult.FileURL)
|
||||||
|
htmlContentUrl = ossResult.FileURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var summaryResult []map[string]interface{}
|
||||||
|
if !g.IsEmpty(textUrl) {
|
||||||
|
for _, outputParamsItem := range flowInfo.OutputParams {
|
||||||
|
mapItem := gconv.Map(outputParamsItem)
|
||||||
|
for _, mapValue := range mapItem {
|
||||||
|
if strings.Contains(oldHtmlUrl, gconv.String(mapValue)) || strings.Contains(req.ResultUrl, gconv.String(mapValue)) {
|
||||||
|
if strings.Contains(oldHtmlUrl, gconv.String(mapValue)) {
|
||||||
|
// 生成 毫秒时间戳 作为 KEY
|
||||||
|
timeKey := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
item := make(map[string]interface{})
|
||||||
|
item[timeKey] = htmlContentUrl
|
||||||
|
summaryResult = append(summaryResult, item)
|
||||||
|
}
|
||||||
|
if strings.Contains(req.ResultUrl, gconv.String(mapValue)) {
|
||||||
|
// 生成 毫秒时间戳 作为 KEY
|
||||||
|
timeKey := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
item := make(map[string]interface{})
|
||||||
|
item[timeKey] = textUrl
|
||||||
|
summaryResult = append(summaryResult, item)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
summaryResult = append(summaryResult, outputParamsItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !g.IsEmpty(summaryResult) {
|
||||||
|
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||||
|
Id: flowInfo.Id,
|
||||||
|
Status: flow.FlowExecutionStatusSuccess.Code(),
|
||||||
|
OutputParams: summaryResult,
|
||||||
|
}
|
||||||
|
_, err = flowDao.FlowExecutionDao.Update(ctx, &executionReq)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TextNode(ctx context.Context, sessionId, modelName, skillName string, form, userForm, modelResponse map[string]any, fileUrl []string) ([]node.NodeFormField, error) {
|
||||||
|
contentStr := "你是专业内容生成助手,请严格按以下规则输出内容:1、输出标准 HTML 片段,不要 Markdown,不要 ``` 符号,不要多余解释,2、整体用 <div class='report-container'> 包裹,3、主标题使用 <h2 class='title'>,4、章节标题使用 <h3 class='section-title'>,5、正文段落使用 <p class='paragraph'>,6、列表使用 <ul class='list'><li>...</li></ul>,7、重点内容使用 <strong> 加粗,8、段落之间清晰分隔,结构规整,9、如果生成多条文案,每条文案独立用 <div class='content-item' id='content-{序号}'> 包裹(序号从1开始),10、每条文案内部必须在最上方添加一行固定格式:<p class='image-count'>需要配图:N 张</p> N 是这条文案需要的图片数量,只能是数字,不能是其他文字,11、只输出 HTML 结构,不输出任何额外文字"
|
||||||
|
userForm["prompt"] = contentStr
|
||||||
|
|
||||||
|
mapTaskResult, err := GetModelResult(ctx, modelName, skillName, form, userForm, fileUrl, sessionId, "文案生成")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultContent := ""
|
||||||
|
for key, _ := range modelResponse {
|
||||||
|
resultContent = gconv.String(mapTaskResult[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拆分多条文案
|
||||||
|
contentList := SplitMultiContents(resultContent)
|
||||||
|
|
||||||
|
outputRes := make([]node.NodeFormField, 0)
|
||||||
|
for i, contentItem := range contentList {
|
||||||
|
outputRes = append(outputRes, node.NodeFormField{
|
||||||
|
Field: fmt.Sprintf("text_content_%d", i),
|
||||||
|
Value: contentItem,
|
||||||
|
Label: fmt.Sprintf("文案内容_%d", i),
|
||||||
|
Type: "string",
|
||||||
|
Expand: ExtractImageCount(contentItem),
|
||||||
|
})
|
||||||
|
|
||||||
|
// 1. 构建html文本
|
||||||
|
plainText := BuildText(contentItem)
|
||||||
|
// 2. 上传纯文本到 OSS
|
||||||
|
textFileName := fmt.Sprintf("ai_text_%d_%d.inc", time.Now().UnixMilli(), i)
|
||||||
|
var textUrl *dto.UploadFileBytesRes
|
||||||
|
textUrl, err = Upload(ctx, &dto.UploadFileBytesReq{
|
||||||
|
FileBytes: []byte(plainText),
|
||||||
|
FileName: textFileName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 3. 把纯文本地址存入输出
|
||||||
|
outputRes = append(outputRes, node.NodeFormField{
|
||||||
|
Field: fmt.Sprintf("text_url:%d", i),
|
||||||
|
Value: textUrl.FileURL,
|
||||||
|
Label: fmt.Sprintf("文案纯文本_txt_%d", i),
|
||||||
|
Type: "string",
|
||||||
|
Expand: ExtractImageCount(contentItem),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return outputRes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImgNode(ctx context.Context, sessionId, modelName, skillName string, form, userForm, modelResponse map[string]any, fileUrl []string) ([]node.NodeFormField, error) {
|
||||||
|
|
||||||
|
mapTaskResult, err := GetModelResult(ctx, modelName, skillName, form, userForm, fileUrl, sessionId, "图片生成")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultContent []string
|
||||||
|
for key, _ := range modelResponse {
|
||||||
|
resultContent = gconv.Strings(mapTaskResult[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
var images []string
|
||||||
|
for _, item := range resultContent {
|
||||||
|
mapItem := gconv.Map(item)
|
||||||
|
for _, value := range mapItem {
|
||||||
|
values, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("图片地址类型错误")
|
||||||
|
}
|
||||||
|
// 下载官方临时图片
|
||||||
|
var imgBytes []byte
|
||||||
|
imgBytes, err = GetFileBytesFromURL(values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("下载图片失败: %w", err)
|
||||||
|
}
|
||||||
|
// 构造文件名
|
||||||
|
fileName := fmt.Sprintf("ai_image_%d.png", time.Now().UnixMilli())
|
||||||
|
// 上传到你的OSS(你项目已有的Upload方法)
|
||||||
|
var upResp *dto.UploadFileBytesRes
|
||||||
|
upResp, err = Upload(ctx, &dto.UploadFileBytesReq{
|
||||||
|
FileName: fileName,
|
||||||
|
FileBytes: imgBytes,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("上传OSS失败: %w", err)
|
||||||
|
}
|
||||||
|
images = append(images, upResp.FileURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var url string
|
||||||
|
url, err = utils.GetFileAddressPrefix(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
outputRes := make([]node.NodeFormField, 0)
|
||||||
|
|
||||||
|
for i, item := range images {
|
||||||
|
// 图片:image_0, image_1, image_2...
|
||||||
|
outputRes = append(outputRes, node.NodeFormField{
|
||||||
|
Field: fmt.Sprintf("image_%d", i),
|
||||||
|
Value: fmt.Sprintf("%s%s", url, item),
|
||||||
|
Label: fmt.Sprintf("图片_%d", i),
|
||||||
|
Type: "string",
|
||||||
|
})
|
||||||
|
// 额外存储关联关系
|
||||||
|
outputRes = append(outputRes, node.NodeFormField{
|
||||||
|
Field: fmt.Sprintf("img_url:%d", i),
|
||||||
|
Value: fmt.Sprintf("%s%s", url, item),
|
||||||
|
Label: fmt.Sprintf("图片_img_%d关联文案ID", i),
|
||||||
|
Type: "string",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputRes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildParam(nodeInput *flowDto.NodeExecutionInput) (skillName string, resultFrom, resultUserFrom map[string]any) {
|
||||||
|
// 1. 直接用你原来的方法(返回两个 map)
|
||||||
|
inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
||||||
|
var outputResult []node.NodeFormField
|
||||||
|
for _, valueAny := range inputMap {
|
||||||
|
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||||
|
outputResult = append(outputResult, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultUserFrom = make(map[string]any)
|
||||||
|
for _, valueAny := range outputMap {
|
||||||
|
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||||
|
if !strings.Contains(field.Field, "text_url") && !strings.Contains(field.Field, "img_url") {
|
||||||
|
if strings.Contains(field.Field, "text_content") {
|
||||||
|
field.Value = StripHtmlTags(field.Value)
|
||||||
|
}
|
||||||
|
resultUserFrom[field.Label] = field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, valueAny := range modelMap {
|
||||||
|
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||||
|
outputResult = append(outputResult, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !nodeInput.Global.IsDialogue {
|
||||||
|
for _, item := range outputResult {
|
||||||
|
resultUserFrom[item.Label] = item
|
||||||
|
}
|
||||||
|
for _, item := range nodeInput.Config.FormConfig {
|
||||||
|
resultUserFrom[item.Label] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !g.IsEmpty(nodeInput.Global.Desc) {
|
||||||
|
resultUserFrom["desc"] = node.NodeFormField{
|
||||||
|
Value: nodeInput.Global.Desc,
|
||||||
|
Field: "desc",
|
||||||
|
Label: "描述",
|
||||||
|
Type: "text",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultFrom = make(map[string]any)
|
||||||
|
for key, item := range nodeInput.Config.ModelConfig.ModelForm {
|
||||||
|
resultFrom[key] = map[string]any{
|
||||||
|
"value": item,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
skillName = nodeInput.Config.SkillName
|
||||||
|
if g.IsEmpty(nodeInput.Config.SkillName) {
|
||||||
|
skillName = nodeInput.Global.SkillName
|
||||||
|
}
|
||||||
|
|
||||||
|
return skillName, resultFrom, resultUserFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNodeContextContent(execInput *flowDto.FlowExecutionInput, node *entity.FlowNode) (map[string]any, map[string]any, map[string]any) {
|
||||||
|
input := make(map[string]any)
|
||||||
|
output := make(map[string]any)
|
||||||
|
model := make(map[string]any)
|
||||||
|
// 1. 有引用 → 取引用节点的字段值
|
||||||
|
if len(node.InputSource) > 0 {
|
||||||
|
for _, source := range node.InputSource {
|
||||||
|
refNodeID := source.NodeId
|
||||||
|
isQuoteOutput := source.QuoteOutput
|
||||||
|
fields := source.Field
|
||||||
|
|
||||||
|
refNode, ok := execInput.ConfigMap[refNodeID]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inputMap := buildInputMap(refNode)
|
||||||
|
outputMap := mergeOutput(refNode.OutputResult)
|
||||||
|
modelMap := mergeModel(refNode.ModelConfig)
|
||||||
|
if isQuoteOutput {
|
||||||
|
for k, v := range outputMap {
|
||||||
|
output[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(fields) > 0 {
|
||||||
|
// 取指定字段
|
||||||
|
for _, f := range fields {
|
||||||
|
|
||||||
|
if v, ok := inputMap[f]; ok {
|
||||||
|
input[f] = v
|
||||||
|
}
|
||||||
|
if v, ok := modelMap[f]; ok {
|
||||||
|
model[f] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 取全部
|
||||||
|
for k, v := range inputMap {
|
||||||
|
input[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range modelMap {
|
||||||
|
model[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input, output, model
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildInputMap 从 FormConfig 构造输入map
|
||||||
|
func buildInputMap(node *entity.FlowNode) map[string]any {
|
||||||
|
m := make(map[string]any)
|
||||||
|
for _, item := range node.FormConfig {
|
||||||
|
m[item.Label] = item
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeOutput 合并节点输出 []map → 单map
|
||||||
|
func mergeOutput(output []node.NodeFormField) map[string]any {
|
||||||
|
m := make(map[string]any)
|
||||||
|
for _, item := range output {
|
||||||
|
m[item.Label] = item
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeOutput 合并节点输出 []map → 单map
|
||||||
|
func mergeModel(output node.ModelItem) map[string]any {
|
||||||
|
m := make(map[string]any)
|
||||||
|
// 遍历 output.ModelForm 里的每一个 key 和原始值
|
||||||
|
for key, rawValue := range output.ModelForm {
|
||||||
|
// 包装成 { "value": 原始值 }
|
||||||
|
m[key] = map[string]any{
|
||||||
|
"value": rawValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
@@ -9,9 +9,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
@@ -30,6 +33,66 @@ func GetIsChatModel(ctx context.Context) (res *flowDto.GetIsChatModelRes, err er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ComposeMessages(ctx context.Context, req *flowDto.ComposeMessagesReq) (res *flowDto.ComposeMessagesRes, err error) {
|
||||||
|
headers := make(map[string]string)
|
||||||
|
if r := g.RequestFromCtx(ctx); r != nil {
|
||||||
|
for k, v := range r.Request.Header {
|
||||||
|
if len(v) > 0 {
|
||||||
|
headers[k] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = new(flowDto.ComposeMessagesRes)
|
||||||
|
err = commonHttp.Post(ctx, "prompts-core/prompt/composeMessages", headers, res, &req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetModelResult(ctx context.Context, modelName, skillName string, form, userFrom map[string]any, fileUrl []string, sessionId string, cause string) (mapTaskResult map[string]any, err error) {
|
||||||
|
msgReq := flowDto.ComposeMessagesReq{
|
||||||
|
BuildType: 1,
|
||||||
|
ModelName: modelName,
|
||||||
|
SkillName: skillName,
|
||||||
|
Cause: cause,
|
||||||
|
Form: form,
|
||||||
|
UserForm: userFrom,
|
||||||
|
UserFiles: fileUrl,
|
||||||
|
SessionId: sessionId,
|
||||||
|
}
|
||||||
|
msg, err := ComposeMessages(ctx, &msgReq)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if g.IsEmpty(msg.Messages) {
|
||||||
|
return nil, fmt.Errorf("msg is empty")
|
||||||
|
}
|
||||||
|
var taskResult any
|
||||||
|
taskResult, err = GatewayTask(ctx, msg.EpicycleId, modelName, msg.Messages)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var getTaskResult *flowDto.TaskCallback
|
||||||
|
getTaskResult, err = GetTaskResult(ctx, taskResult)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mapTaskResult = gconv.Map(getTaskResult.Text)
|
||||||
|
return mapTaskResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GatewayTask(ctx context.Context, epicycleId int64, model string, content map[string]any) (any, error) {
|
||||||
|
modelTaskId, err := CreateGatewayTask(ctx, &flowDto.CreateTaskReq{
|
||||||
|
ModelName: model,
|
||||||
|
BizName: g.Cfg().MustGet(ctx, "server.name").String(),
|
||||||
|
CallbackUrl: "/flow/execution/modelCallback",
|
||||||
|
RequestPayload: content,
|
||||||
|
EpicycleId: epicycleId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Wait(ctx, modelTaskId)
|
||||||
|
}
|
||||||
|
|
||||||
func CreateGatewayTask(ctx context.Context, req *flowDto.CreateTaskReq) (string, error) {
|
func CreateGatewayTask(ctx context.Context, req *flowDto.CreateTaskReq) (string, error) {
|
||||||
headers := make(map[string]string)
|
headers := make(map[string]string)
|
||||||
if r := g.RequestFromCtx(ctx); r != nil {
|
if r := g.RequestFromCtx(ctx); r != nil {
|
||||||
@@ -48,34 +111,6 @@ func CreateGatewayTask(ctx context.Context, req *flowDto.CreateTaskReq) (string,
|
|||||||
return res.TaskId, nil
|
return res.TaskId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ComposeMessages(ctx context.Context, req *flowDto.ComposeMessagesReq) (res *flowDto.ComposeMessagesRes, err error) {
|
|
||||||
headers := make(map[string]string)
|
|
||||||
if r := g.RequestFromCtx(ctx); r != nil {
|
|
||||||
for k, v := range r.Request.Header {
|
|
||||||
if len(v) > 0 {
|
|
||||||
headers[k] = v[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = new(flowDto.ComposeMessagesRes)
|
|
||||||
err = commonHttp.Post(ctx, "prompts-core/prompt/composeMessages", headers, res, &req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func GatewayTask(ctx context.Context, epicycleId int64, model string, content map[string]any) (any, error) {
|
|
||||||
modelTaskId, err := CreateGatewayTask(ctx, &flowDto.CreateTaskReq{
|
|
||||||
ModelName: model,
|
|
||||||
BizName: g.Cfg().MustGet(ctx, "server.name").String(),
|
|
||||||
CallbackUrl: "/flow/execution/modelCallback",
|
|
||||||
RequestPayload: content,
|
|
||||||
EpicycleId: epicycleId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return Wait(ctx, modelTaskId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTaskResult(ctx context.Context, result any) (*flowDto.TaskCallback, error) {
|
func GetTaskResult(ctx context.Context, result any) (*flowDto.TaskCallback, error) {
|
||||||
task := new(flowDto.TaskCallback)
|
task := new(flowDto.TaskCallback)
|
||||||
if err := gconv.Struct(result, task); err != nil {
|
if err := gconv.Struct(result, task); err != nil {
|
||||||
@@ -113,17 +148,22 @@ func FetchRemoteJsonFile(ctx context.Context, fileUrl string) ([]byte, error) {
|
|||||||
return io.ReadAll(resp.Body)
|
return io.ReadAll(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetImageBytesFromURL(url string) (all []byte, contentType string, err error) {
|
func GetFileBytesFromURL(url string) (all []byte, err error) {
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("请求失败 %s: %v", url, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
all, err = io.ReadAll(resp.Body)
|
if resp.StatusCode != http.StatusOK {
|
||||||
if err != nil {
|
fmt.Printf("请求失败,状态码: %d\n", resp.StatusCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
all, err = io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("读取内容失败 %s: %v", url, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
contentType = resp.Header.Get("Content-Type")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,3 +200,275 @@ func Upload(ctx context.Context, req *dto.UploadFileBytesReq) (*dto.UploadFileBy
|
|||||||
g.Log().Infof(ctx, "[Upload] success url=%s size=%d", res.FileURL, res.FileSize)
|
g.Log().Infof(ctx, "[Upload] success url=%s size=%d", res.FileURL, res.FileSize)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BuildText(text string) string {
|
||||||
|
// 生成单条HTML
|
||||||
|
var htmlBuilder strings.Builder
|
||||||
|
htmlBuilder.WriteString(`
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: "Microsoft YaHei", "PingFang SC", Arial, sans-serif;
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.8;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.item {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.image-group img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.image-group img:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.image-group {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.text h2 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
.text h3 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin: 20px 0 12px;
|
||||||
|
padding-left: 12px;
|
||||||
|
border-left: 4px solid #409eff;
|
||||||
|
}
|
||||||
|
.text p {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
.text strong {
|
||||||
|
color: #e74c3c;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.text ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
.text ul li {
|
||||||
|
padding: 10px 0 10px 30px;
|
||||||
|
position: relative;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
.text ul li:before {
|
||||||
|
content: "●";
|
||||||
|
color: #409eff;
|
||||||
|
font-size: 12px;
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 12px;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.text h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.text h3 {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="item">
|
||||||
|
`)
|
||||||
|
// 🔥 写入文案前:删除 <p class="image-count">需要配图:X 张</p>
|
||||||
|
if text != "" {
|
||||||
|
// 写入清理后的文案
|
||||||
|
htmlBuilder.WriteString(fmt.Sprintf(`<div class="text">%s</div>`, ImageTagRegex(text)))
|
||||||
|
}
|
||||||
|
htmlBuilder.WriteString(`</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`)
|
||||||
|
|
||||||
|
return htmlBuilder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildHtml(text string, images []string) string {
|
||||||
|
var htmlBuilder strings.Builder
|
||||||
|
htmlBuilder.WriteString(`<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: "Microsoft YaHei", sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
line-height: 1.7;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 750px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #fff;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
`)
|
||||||
|
// 写入图片(支持0张、1张、多张)
|
||||||
|
if len(images) > 0 {
|
||||||
|
htmlBuilder.WriteString(`<div class="image-group">`)
|
||||||
|
for _, imgUrl := range images {
|
||||||
|
htmlBuilder.WriteString(fmt.Sprintf(`<img src="%s" alt="图片"/>`, imgUrl))
|
||||||
|
}
|
||||||
|
htmlBuilder.WriteString(`</div>`)
|
||||||
|
}
|
||||||
|
htmlBuilder.WriteString(`
|
||||||
|
<div id="content">加载中...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const incUrl = "` + text + `";
|
||||||
|
fetch(incUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (!res.ok) throw new Error("加载失败");
|
||||||
|
return res.text();
|
||||||
|
})
|
||||||
|
.then(text => {
|
||||||
|
document.getElementById("content").innerHTML = text;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
document.getElementById("content").innerHTML = "加载失败:" + err.message;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>`)
|
||||||
|
|
||||||
|
return htmlBuilder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractImageCount 修复:支持单引号/双引号 + 换行 + 空格
|
||||||
|
func ExtractImageCount(content string) int {
|
||||||
|
// 🔥 关键:支持 class='image-count' (单引号)
|
||||||
|
re := regexp.MustCompile(`<p class=['"]image-count['"][^>]*>.*?(\d+).*?</p>`)
|
||||||
|
match := re.FindStringSubmatch(content)
|
||||||
|
if len(match) >= 2 {
|
||||||
|
num, err := strconv.Atoi(match[1])
|
||||||
|
if err == nil {
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImageTagRegex(html string) string {
|
||||||
|
// 🔥 修复:支持单引号、双引号、空格、换行,100% 删除 <p class='image-count'>
|
||||||
|
imageTagRegex := regexp.MustCompile(`<p class=['"]image-count['"][^>]*>[\s\S]*?</p>`)
|
||||||
|
return imageTagRegex.ReplaceAllString(html, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StripHtmlTags 去掉所有HTML标签,保留换行和文本结构,并删除配图标记行
|
||||||
|
func StripHtmlTags(html string) string {
|
||||||
|
// 1. 替换块级标签为换行,保证排版
|
||||||
|
blockTags := regexp.MustCompile(`</?(div|p|h1|h2|h3|h4|h5|h6|li|ul|ol|br|tr|td|th)[^>]*>`)
|
||||||
|
text := blockTags.ReplaceAllString(html, "\n")
|
||||||
|
|
||||||
|
// 2. 去掉所有剩余的 HTML 标签
|
||||||
|
allTags := regexp.MustCompile(`<[^>]+>`)
|
||||||
|
text = allTags.ReplaceAllString(text, "")
|
||||||
|
|
||||||
|
// 4. 清理多余空行(多个换行只保留一个)
|
||||||
|
text = regexp.MustCompile(`\n\s*\n`).ReplaceAllString(text, "\n")
|
||||||
|
|
||||||
|
// 5. 只去掉首尾空白,中间换行保留
|
||||||
|
text = strings.TrimSpace(text)
|
||||||
|
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitMultiContents 拆分模型返回的多条文案(基于HTML标签分隔)
|
||||||
|
func SplitMultiContents(htmlContent string) []string {
|
||||||
|
var contents []string
|
||||||
|
// 正则匹配<div class="content-item" id="content-{序号}">包裹的内容
|
||||||
|
re := regexp.MustCompile(`<div class="content-item" id="content-\d+">([\s\S]*?)</div>`)
|
||||||
|
matches := re.FindAllStringSubmatch(htmlContent, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
if len(match) > 1 {
|
||||||
|
// 清理空内容
|
||||||
|
trimmed := strings.TrimSpace(match[1])
|
||||||
|
if trimmed != "" {
|
||||||
|
contents = append(contents, trimmed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 兜底:如果没有匹配到结构化内容,按换行/分隔符拆分
|
||||||
|
if len(contents) == 0 {
|
||||||
|
contents = strings.Split(htmlContent, "===分隔符===") // 提示词中可新增此兜底规则
|
||||||
|
}
|
||||||
|
return contents
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllImgSrcFromHtml 先把提取img src的工具方法放在外面
|
||||||
|
func GetAllImgSrcFromHtml(html string) []string {
|
||||||
|
var imgSrcList []string
|
||||||
|
re := regexp.MustCompile(`<img[^>]*src\s*=\s*["']([^"']+)["']`)
|
||||||
|
matchs := re.FindAllStringSubmatch(html, -1)
|
||||||
|
for _, match := range matchs {
|
||||||
|
if len(match) >= 2 {
|
||||||
|
imgSrcList = append(imgSrcList, match[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imgSrcList
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplaceImgSrc 替换img src的方法
|
||||||
|
func ReplaceImgSrc(html string, oldSrc string, newSrc string) string {
|
||||||
|
// 精准替换:找到 <img xxx src="oldSrc" xxx> 并替换
|
||||||
|
re := regexp.MustCompile(`(<img[^>]*src\s*=\s*["'])` + regexp.QuoteMeta(oldSrc) + `(["'])`)
|
||||||
|
return re.ReplaceAllString(html, `${1}`+newSrc+`${2}`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
"github.com/gogf/gf/v2/encoding/gjson"
|
"github.com/gogf/gf/v2/encoding/gjson"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
commonHttp "gitea.com/red-future/common/http"
|
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/utils"
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user