From 9e623724bd4611b094e9d6d17501bdcd1c9f840d Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 3 Nov 2025 16:09:08 +0800 Subject: [PATCH 01/13] first commit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0f5fa2d27..2213eedc1 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ release/deployment/helm-chart/umbrella/Chart.lock **/kitex_remote_config.json .coda/ +.coco backend/script/errorx/.env .cursor/ AGENTS.md \ No newline at end of file From 484f5470beca3ae2bdcd14ab189119a583619324 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 3 Nov 2025 16:25:54 +0800 Subject: [PATCH 02/13] add start/end time --- .../evaluation/application/experiment_app.go | 11 ++++++- .../domain/component/rpc/trace_agent.go | 2 +- .../modules/evaluation/domain/entity/event.go | 8 +++-- .../domain/service/insight_analysis.go | 4 +-- .../domain/service/insight_analysis_impl.go | 30 +++++++++++-------- .../infra/mq/rocket/consumer/expt_export.go | 2 +- .../evaluation/infra/rpc/agent/agent.go | 2 +- 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/backend/modules/evaluation/application/experiment_app.go b/backend/modules/evaluation/application/experiment_app.go index 0084651ee..f87c1002f 100644 --- a/backend/modules/evaluation/application/experiment_app.go +++ b/backend/modules/evaluation/application/experiment_app.go @@ -1129,12 +1129,21 @@ func (e *experimentApplication) InsightAnalysisExperiment(ctx context.Context, r if err != nil { return nil, err } + + var startTime, endTime *int64 + if got.StartAt != nil { + startTime = gptr.Of(got.StartAt.Unix()) + } + if got.EndAt != nil { + endTime = gptr.Of(got.EndAt.Unix()) + } + recordID, err := e.CreateAnalysisRecord(ctx, &entity.ExptInsightAnalysisRecord{ SpaceID: req.GetWorkspaceID(), ExptID: req.GetExptID(), CreatedBy: session.UserID, Status: entity.InsightAnalysisStatus_Running, - }, session) + }, session, gptr.Indirect(startTime), gptr.Indirect(endTime)) if err != nil { return nil, err } diff --git a/backend/modules/evaluation/domain/component/rpc/trace_agent.go b/backend/modules/evaluation/domain/component/rpc/trace_agent.go index 658736cae..97e30910c 100644 --- a/backend/modules/evaluation/domain/component/rpc/trace_agent.go +++ b/backend/modules/evaluation/domain/component/rpc/trace_agent.go @@ -11,6 +11,6 @@ import ( //go:generate mockgen -destination=mocks/trace_agent.go -package=mocks . IAgentAdapter type IAgentAdapter interface { - CallTraceAgent(ctx context.Context, spaceID int64, url string) (int64, error) + CallTraceAgent(ctx context.Context, spaceID int64, url string, startTime, endTime int64) (int64, error) GetReport(ctx context.Context, spaceID, reportID int64) (report string, status entity.ReportStatus, err error) } diff --git a/backend/modules/evaluation/domain/entity/event.go b/backend/modules/evaluation/domain/entity/event.go index 05d309766..3e8b6bc95 100644 --- a/backend/modules/evaluation/domain/entity/event.go +++ b/backend/modules/evaluation/domain/entity/event.go @@ -120,9 +120,11 @@ type ExportCSVEvent struct { ExperimentID int64 SpaceID int64 - Session *Session - ExportScene ExportScene - CreatedAt int64 + Session *Session + ExportScene ExportScene + CreatedAt int64 + ExptStartTime int64 // Unix Time + ExptEndTime int64 // Unix Time } type ExportScene int diff --git a/backend/modules/evaluation/domain/service/insight_analysis.go b/backend/modules/evaluation/domain/service/insight_analysis.go index e345fd7be..623dca355 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis.go +++ b/backend/modules/evaluation/domain/service/insight_analysis.go @@ -10,8 +10,8 @@ import ( ) type IExptInsightAnalysisService interface { - CreateAnalysisRecord(ctx context.Context, record *entity.ExptInsightAnalysisRecord, session *entity.Session) (int64, error) - GenAnalysisReport(ctx context.Context, spaceID, exptID, recordID, CreateAt int64) error + CreateAnalysisRecord(ctx context.Context, record *entity.ExptInsightAnalysisRecord, session *entity.Session, startTime, endTime int64) (int64, error) + GenAnalysisReport(ctx context.Context, spaceID, exptID, recordID, CreateAt, startTime, endTime int64) error GetAnalysisRecordByID(ctx context.Context, spaceID, exptID, recordID int64, session *entity.Session) (*entity.ExptInsightAnalysisRecord, error) ListAnalysisRecord(ctx context.Context, spaceID, exptID int64, page entity.Page, session *entity.Session) ([]*entity.ExptInsightAnalysisRecord, int64, error) DeleteAnalysisRecord(ctx context.Context, spaceID, exptID, recordID int64) error diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl.go b/backend/modules/evaluation/domain/service/insight_analysis_impl.go index 9f5869464..1c83290f0 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl.go @@ -55,18 +55,20 @@ func NewInsightAnalysisService(repo repo.IExptInsightAnalysisRecordRepo, } } -func (e ExptInsightAnalysisServiceImpl) CreateAnalysisRecord(ctx context.Context, record *entity.ExptInsightAnalysisRecord, session *entity.Session) (int64, error) { +func (e ExptInsightAnalysisServiceImpl) CreateAnalysisRecord(ctx context.Context, record *entity.ExptInsightAnalysisRecord, session *entity.Session, startTime, endTime int64) (int64, error) { recordID, err := e.repo.CreateAnalysisRecord(ctx, record) if err != nil { return 0, err } exportEvent := &entity.ExportCSVEvent{ - ExportID: recordID, - ExperimentID: record.ExptID, - SpaceID: record.SpaceID, - ExportScene: entity.ExportSceneInsightAnalysis, - CreatedAt: time.Now().Unix(), + ExportID: recordID, + ExperimentID: record.ExptID, + SpaceID: record.SpaceID, + ExportScene: entity.ExportSceneInsightAnalysis, + CreatedAt: time.Now().Unix(), + ExptStartTime: startTime, + ExptEndTime: endTime, } err = e.exptPublisher.PublishExptExportCSVEvent(ctx, exportEvent, gptr.Of(time.Second*3)) if err != nil { @@ -76,7 +78,7 @@ func (e ExptInsightAnalysisServiceImpl) CreateAnalysisRecord(ctx context.Context return recordID, nil } -func (e ExptInsightAnalysisServiceImpl) GenAnalysisReport(ctx context.Context, spaceID, exptID, recordID, CreateAt int64) (err error) { +func (e ExptInsightAnalysisServiceImpl) GenAnalysisReport(ctx context.Context, spaceID, exptID, recordID, CreateAt, startTime, endTime int64) (err error) { analysisRecord, err := e.repo.GetAnalysisRecordByID(ctx, spaceID, exptID, recordID) if err != nil { return err @@ -125,7 +127,7 @@ func (e ExptInsightAnalysisServiceImpl) GenAnalysisReport(ctx context.Context, s return err } - reportID, err := e.agentAdapter.CallTraceAgent(ctx, spaceID, url) + reportID, err := e.agentAdapter.CallTraceAgent(ctx, spaceID, url, startTime, endTime) if err != nil { return err } @@ -135,11 +137,13 @@ func (e ExptInsightAnalysisServiceImpl) GenAnalysisReport(ctx context.Context, s // 发送时间检查分析报告生成状态 exportEvent := &entity.ExportCSVEvent{ - ExportID: recordID, - ExperimentID: exptID, - SpaceID: spaceID, - ExportScene: entity.ExportSceneInsightAnalysis, - CreatedAt: CreateAt, + ExportID: recordID, + ExperimentID: exptID, + SpaceID: spaceID, + ExportScene: entity.ExportSceneInsightAnalysis, + CreatedAt: CreateAt, + ExptStartTime: startTime, // 传递开始时间 + ExptEndTime: endTime, // 传递结束时间 } err = e.exptPublisher.PublishExptExportCSVEvent(ctx, exportEvent, gptr.Of(time.Minute*3)) if err != nil { diff --git a/backend/modules/evaluation/infra/mq/rocket/consumer/expt_export.go b/backend/modules/evaluation/infra/mq/rocket/consumer/expt_export.go index 07e44f0fa..b3a3603b8 100644 --- a/backend/modules/evaluation/infra/mq/rocket/consumer/expt_export.go +++ b/backend/modules/evaluation/infra/mq/rocket/consumer/expt_export.go @@ -53,7 +53,7 @@ func (e *ExptExportConsumer) HandleMessage(ctx context.Context, ext *mq.MessageE func (e *ExptExportConsumer) handleEvent(ctx context.Context, event *entity.ExportCSVEvent) (err error) { switch event.ExportScene { case entity.ExportSceneInsightAnalysis: - err = e.exptInsightAnalysisService.GenAnalysisReport(ctx, event.SpaceID, event.ExperimentID, event.ExportID, event.CreatedAt) + err = e.exptInsightAnalysisService.GenAnalysisReport(ctx, event.SpaceID, event.ExperimentID, event.ExportID, event.CreatedAt, event.ExptStartTime, event.ExptEndTime) if err != nil { logs.CtxError(ctx, "ExptExportConsumer GenAnalysisReport fail, expt_id:%v, err: %v", event.ExperimentID, err) return nil diff --git a/backend/modules/evaluation/infra/rpc/agent/agent.go b/backend/modules/evaluation/infra/rpc/agent/agent.go index c5b9e529f..bea8d450e 100644 --- a/backend/modules/evaluation/infra/rpc/agent/agent.go +++ b/backend/modules/evaluation/infra/rpc/agent/agent.go @@ -18,7 +18,7 @@ func NewAgentAdapter() rpc.IAgentAdapter { return &AgentAdapter{} } -func (a AgentAdapter) CallTraceAgent(ctx context.Context, spaceID int64, url string) (int64, error) { +func (a AgentAdapter) CallTraceAgent(ctx context.Context, spaceID int64, url string, startTime, endTime int64) (int64, error) { return 0, errorx.NewByCode(errno.CommonInternalErrorCode, errorx.WithExtraMsg("CallTraceAgent not implement")) } From d331698bd52acf6180c88c494a383203d6d1002a Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 3 Nov 2025 18:22:02 +0800 Subject: [PATCH 03/13] fix ut --- .../application/experiment_app_test.go | 17 +++++++++++++---- .../domain/component/rpc/mocks/trace_agent.go | 8 ++++---- .../service/insight_analysis_impl_test.go | 10 +++++----- .../domain/service/mocks/insight_analysis.go | 16 ++++++++-------- .../evaluation/infra/rpc/agent/agent_test.go | 2 +- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/backend/modules/evaluation/application/experiment_app_test.go b/backend/modules/evaluation/application/experiment_app_test.go index 7512843de..99416658f 100644 --- a/backend/modules/evaluation/application/experiment_app_test.go +++ b/backend/modules/evaluation/application/experiment_app_test.go @@ -10,6 +10,7 @@ import ( "reflect" "strconv" "testing" + "time" "github.com/bytedance/gg/gptr" "github.com/stretchr/testify/assert" @@ -3736,11 +3737,15 @@ func TestInsightAnalysisExperiment(t *testing.T) { t.Run("成功创建洞察分析", func(t *testing.T) { // Mock the manager.Get call - mockManager.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&entity.Experiment{CreatedBy: "test-user"}, nil) + mockManager.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&entity.Experiment{ + CreatedBy: "test-user", + StartAt: &[]time.Time{time.Now()}[0], + EndAt: &[]time.Time{time.Now()}[0], + }, nil) // Mock the auth.AuthorizationWithoutSPI call mockAuth.EXPECT().AuthorizationWithoutSPI(gomock.Any(), gomock.Any()).Return(nil) // Mock the CreateAnalysisRecord call - mockInsightService.EXPECT().CreateAnalysisRecord(gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(123), nil) + mockInsightService.EXPECT().CreateAnalysisRecord(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(123), nil) _, err := app.InsightAnalysisExperiment(ctx, req) assert.NoError(t, err) @@ -3764,9 +3769,13 @@ func TestInsightAnalysisExperiment(t *testing.T) { }) t.Run("创建分析记录失败", func(t *testing.T) { - mockManager.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&entity.Experiment{CreatedBy: "test-user"}, nil) + mockManager.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&entity.Experiment{ + CreatedBy: "test-user", + StartAt: &[]time.Time{time.Now()}[0], + EndAt: &[]time.Time{time.Now()}[0], + }, nil) mockAuth.EXPECT().AuthorizationWithoutSPI(gomock.Any(), gomock.Any()).Return(nil) - mockInsightService.EXPECT().CreateAnalysisRecord(gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(0), errors.New("create analysis record error")) + mockInsightService.EXPECT().CreateAnalysisRecord(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(0), errors.New("create analysis record error")) _, err := app.InsightAnalysisExperiment(ctx, req) assert.Error(t, err) diff --git a/backend/modules/evaluation/domain/component/rpc/mocks/trace_agent.go b/backend/modules/evaluation/domain/component/rpc/mocks/trace_agent.go index 509b8a761..8ba43466c 100644 --- a/backend/modules/evaluation/domain/component/rpc/mocks/trace_agent.go +++ b/backend/modules/evaluation/domain/component/rpc/mocks/trace_agent.go @@ -42,18 +42,18 @@ func (m *MockIAgentAdapter) EXPECT() *MockIAgentAdapterMockRecorder { } // CallTraceAgent mocks base method. -func (m *MockIAgentAdapter) CallTraceAgent(ctx context.Context, spaceID int64, url string) (int64, error) { +func (m *MockIAgentAdapter) CallTraceAgent(ctx context.Context, spaceID int64, url string, startTime, endTime int64) (int64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CallTraceAgent", ctx, spaceID, url) + ret := m.ctrl.Call(m, "CallTraceAgent", ctx, spaceID, url, startTime, endTime) ret0, _ := ret[0].(int64) ret1, _ := ret[1].(error) return ret0, ret1 } // CallTraceAgent indicates an expected call of CallTraceAgent. -func (mr *MockIAgentAdapterMockRecorder) CallTraceAgent(ctx, spaceID, url any) *gomock.Call { +func (mr *MockIAgentAdapterMockRecorder) CallTraceAgent(ctx, spaceID, url, startTime, endTime any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallTraceAgent", reflect.TypeOf((*MockIAgentAdapter)(nil).CallTraceAgent), ctx, spaceID, url) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallTraceAgent", reflect.TypeOf((*MockIAgentAdapter)(nil).CallTraceAgent), ctx, spaceID, url, startTime, endTime) } // GetReport mocks base method. diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl_test.go b/backend/modules/evaluation/domain/service/insight_analysis_impl_test.go index d4b434070..dbf918b6e 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl_test.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl_test.go @@ -134,7 +134,7 @@ func TestExptInsightAnalysisServiceImpl_CreateAnalysisRecord(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.setup() - result, err := service.CreateAnalysisRecord(ctx, tt.record, tt.session) + result, err := service.CreateAnalysisRecord(ctx, tt.record, tt.session, 0, 0) if tt.wantErr { assert.Error(t, err) } else { @@ -172,7 +172,7 @@ func TestExptInsightAnalysisServiceImpl_GenAnalysisReport(t *testing.T) { }, nil) mocks.exptResultExportService.EXPECT().DoExportCSV(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) mocks.fileClient.EXPECT().SignDownloadReq(gomock.Any(), gomock.Any(), gomock.Any()).Return("http://test-url.com", make(map[string][]string), nil) - mocks.agentAdapter.EXPECT().CallTraceAgent(gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(123), nil) + mocks.agentAdapter.EXPECT().CallTraceAgent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(123), nil) mocks.publisher.EXPECT().PublishExptExportCSVEvent(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) mocks.repo.EXPECT().UpdateAnalysisRecord(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) }, @@ -266,7 +266,7 @@ func TestExptInsightAnalysisServiceImpl_GenAnalysisReport(t *testing.T) { }, nil) mocks.exptResultExportService.EXPECT().DoExportCSV(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) mocks.fileClient.EXPECT().SignDownloadReq(gomock.Any(), gomock.Any(), gomock.Any()).Return("http://test-url.com", make(map[string][]string), nil) - mocks.agentAdapter.EXPECT().CallTraceAgent(gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(0), errors.New("agent error")) + mocks.agentAdapter.EXPECT().CallTraceAgent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(0), errors.New("agent error")) mocks.repo.EXPECT().UpdateAnalysisRecord(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, record *entity.ExptInsightAnalysisRecord, opts ...db.Option) error { assert.Equal(t, entity.InsightAnalysisStatus_Failed, record.Status) return nil @@ -289,7 +289,7 @@ func TestExptInsightAnalysisServiceImpl_GenAnalysisReport(t *testing.T) { }, nil) mocks.exptResultExportService.EXPECT().DoExportCSV(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) mocks.fileClient.EXPECT().SignDownloadReq(gomock.Any(), gomock.Any(), gomock.Any()).Return("http://test-url.com", make(map[string][]string), nil) - mocks.agentAdapter.EXPECT().CallTraceAgent(gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(123), nil) + mocks.agentAdapter.EXPECT().CallTraceAgent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(int64(123), nil) mocks.publisher.EXPECT().PublishExptExportCSVEvent(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("publish error")) mocks.repo.EXPECT().UpdateAnalysisRecord(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, record *entity.ExptInsightAnalysisRecord, opts ...db.Option) error { assert.Equal(t, entity.InsightAnalysisStatus_Failed, record.Status) @@ -325,7 +325,7 @@ func TestExptInsightAnalysisServiceImpl_GenAnalysisReport(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.setup() - err := service.GenAnalysisReport(ctx, tt.spaceID, tt.exptID, tt.recordID, tt.createAt) + err := service.GenAnalysisReport(ctx, tt.spaceID, tt.exptID, tt.recordID, tt.createAt, 0, 0) if tt.wantErr { assert.Error(t, err) } else { diff --git a/backend/modules/evaluation/domain/service/mocks/insight_analysis.go b/backend/modules/evaluation/domain/service/mocks/insight_analysis.go index 78d1223d8..7c8ad5c62 100644 --- a/backend/modules/evaluation/domain/service/mocks/insight_analysis.go +++ b/backend/modules/evaluation/domain/service/mocks/insight_analysis.go @@ -36,18 +36,18 @@ func (m *MockIExptInsightAnalysisService) EXPECT() *MockIExptInsightAnalysisServ } // CreateAnalysisRecord mocks base method. -func (m *MockIExptInsightAnalysisService) CreateAnalysisRecord(arg0 context.Context, arg1 *entity.ExptInsightAnalysisRecord, arg2 *entity.Session) (int64, error) { +func (m *MockIExptInsightAnalysisService) CreateAnalysisRecord(arg0 context.Context, arg1 *entity.ExptInsightAnalysisRecord, arg2 *entity.Session, arg3, arg4 int64) (int64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAnalysisRecord", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateAnalysisRecord", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(int64) ret1, _ := ret[1].(error) return ret0, ret1 } // CreateAnalysisRecord indicates an expected call of CreateAnalysisRecord. -func (mr *MockIExptInsightAnalysisServiceMockRecorder) CreateAnalysisRecord(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockIExptInsightAnalysisServiceMockRecorder) CreateAnalysisRecord(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAnalysisRecord", reflect.TypeOf((*MockIExptInsightAnalysisService)(nil).CreateAnalysisRecord), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAnalysisRecord", reflect.TypeOf((*MockIExptInsightAnalysisService)(nil).CreateAnalysisRecord), arg0, arg1, arg2, arg3, arg4) } // DeleteAnalysisRecord mocks base method. @@ -79,17 +79,17 @@ func (mr *MockIExptInsightAnalysisServiceMockRecorder) FeedbackExptInsightAnalys } // GenAnalysisReport mocks base method. -func (m *MockIExptInsightAnalysisService) GenAnalysisReport(arg0 context.Context, arg1, arg2, arg3, arg4 int64) error { +func (m *MockIExptInsightAnalysisService) GenAnalysisReport(arg0 context.Context, arg1, arg2, arg3, arg4, arg5, arg6 int64) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GenAnalysisReport", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "GenAnalysisReport", arg0, arg1, arg2, arg3, arg4, arg5, arg6) ret0, _ := ret[0].(error) return ret0 } // GenAnalysisReport indicates an expected call of GenAnalysisReport. -func (mr *MockIExptInsightAnalysisServiceMockRecorder) GenAnalysisReport(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockIExptInsightAnalysisServiceMockRecorder) GenAnalysisReport(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenAnalysisReport", reflect.TypeOf((*MockIExptInsightAnalysisService)(nil).GenAnalysisReport), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenAnalysisReport", reflect.TypeOf((*MockIExptInsightAnalysisService)(nil).GenAnalysisReport), arg0, arg1, arg2, arg3, arg4, arg5, arg6) } // GetAnalysisRecordByID mocks base method. diff --git a/backend/modules/evaluation/infra/rpc/agent/agent_test.go b/backend/modules/evaluation/infra/rpc/agent/agent_test.go index 295820750..eaa88f63c 100644 --- a/backend/modules/evaluation/infra/rpc/agent/agent_test.go +++ b/backend/modules/evaluation/infra/rpc/agent/agent_test.go @@ -34,7 +34,7 @@ func TestAgentAdapter_CallTraceAgent(t *testing.T) { ctx := context.Background() adapter, ctx := tt.setup(ctx) - result, err := adapter.CallTraceAgent(ctx, 123, "http://example.com") + result, err := adapter.CallTraceAgent(ctx, 123, "http://example.com", 0, 0) if tt.wantErr { assert.Error(t, err) From 92b7c1e0ac7abee5c2649fdcd588fb90a70042c3 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 3 Nov 2025 22:07:00 +0800 Subject: [PATCH 04/13] fix time in miliseconds --- backend/modules/evaluation/application/experiment_app.go | 4 ++-- .../evaluation/domain/service/insight_analysis_impl.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/modules/evaluation/application/experiment_app.go b/backend/modules/evaluation/application/experiment_app.go index f87c1002f..417b9475c 100644 --- a/backend/modules/evaluation/application/experiment_app.go +++ b/backend/modules/evaluation/application/experiment_app.go @@ -1132,10 +1132,10 @@ func (e *experimentApplication) InsightAnalysisExperiment(ctx context.Context, r var startTime, endTime *int64 if got.StartAt != nil { - startTime = gptr.Of(got.StartAt.Unix()) + startTime = gptr.Of(got.StartAt.UnixMilli()) } if got.EndAt != nil { - endTime = gptr.Of(got.EndAt.Unix()) + endTime = gptr.Of(got.EndAt.UnixMilli()) } recordID, err := e.CreateAnalysisRecord(ctx, &entity.ExptInsightAnalysisRecord{ diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl.go b/backend/modules/evaluation/domain/service/insight_analysis_impl.go index 1c83290f0..76b4295f9 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl.go @@ -142,8 +142,8 @@ func (e ExptInsightAnalysisServiceImpl) GenAnalysisReport(ctx context.Context, s SpaceID: spaceID, ExportScene: entity.ExportSceneInsightAnalysis, CreatedAt: CreateAt, - ExptStartTime: startTime, // 传递开始时间 - ExptEndTime: endTime, // 传递结束时间 + ExptStartTime: startTime, + ExptEndTime: endTime, } err = e.exptPublisher.PublishExptExportCSVEvent(ctx, exportEvent, gptr.Of(time.Minute*3)) if err != nil { From e0608a6167ee60fd9384182164dbcb40508d44f7 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 10 Nov 2025 20:01:00 +0800 Subject: [PATCH 05/13] running for 3h+ is thought failed --- .../domain/entity/expt_insight_analysis_record.go | 4 ++++ .../evaluation/domain/service/insight_analysis_impl.go | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go b/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go index ff35af7c8..3f2272f1f 100644 --- a/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go +++ b/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go @@ -14,6 +14,10 @@ const ( InsightAnalysisStatus_Failed InsightAnalysisStatus = 3 ) +const ( + ThreeHour = 3 * time.Hour +) + type ExptInsightAnalysisRecord struct { ID int64 SpaceID int64 diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl.go b/backend/modules/evaluation/domain/service/insight_analysis_impl.go index 76b4295f9..d89771652 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl.go @@ -158,6 +158,14 @@ func (e ExptInsightAnalysisServiceImpl) checkAnalysisReportGenStatus(ctx context if err != nil { return err } + + // 超过3小时,未生成分析报告,认为是失败 + if status == entity.ReportStatus_Running && record.CreatedAt.Add(entity.ThreeHour).Unix() >= CreateAt { + record.Status = entity.InsightAnalysisStatus_Failed + logs.CtxWarn(ctx, "checkAnalysisReportGenStatus found timeout event, expt_id: %v, record_id: %v", record.ExptID, record.ID) + return e.repo.UpdateAnalysisRecord(ctx, record) + } + if status == entity.ReportStatus_Failed { record.Status = entity.InsightAnalysisStatus_Failed return e.repo.UpdateAnalysisRecord(ctx, record) From 6b2dfad7d3a405c0821e4b61d806602ff8f0cb03 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 10 Nov 2025 20:54:33 +0800 Subject: [PATCH 06/13] fix time out --- .../modules/evaluation/domain/service/insight_analysis_impl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl.go b/backend/modules/evaluation/domain/service/insight_analysis_impl.go index d89771652..90916b03c 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl.go @@ -160,7 +160,7 @@ func (e ExptInsightAnalysisServiceImpl) checkAnalysisReportGenStatus(ctx context } // 超过3小时,未生成分析报告,认为是失败 - if status == entity.ReportStatus_Running && record.CreatedAt.Add(entity.ThreeHour).Unix() >= CreateAt { + if status == entity.ReportStatus_Running && record.CreatedAt.Add(entity.ThreeHour).Unix() <= time.Now().Unix() { record.Status = entity.InsightAnalysisStatus_Failed logs.CtxWarn(ctx, "checkAnalysisReportGenStatus found timeout event, expt_id: %v, record_id: %v", record.ExptID, record.ID) return e.repo.UpdateAnalysisRecord(ctx, record) From ffc816e88224df1ff0842b4714af56f66a55180a Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 10 Nov 2025 21:32:42 +0800 Subject: [PATCH 07/13] fix session, try another way to inject CreateBy --- backend/modules/evaluation/application/experiment_app.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/modules/evaluation/application/experiment_app.go b/backend/modules/evaluation/application/experiment_app.go index 417b9475c..932312b12 100644 --- a/backend/modules/evaluation/application/experiment_app.go +++ b/backend/modules/evaluation/application/experiment_app.go @@ -10,6 +10,7 @@ import ( "time" "github.com/bytedance/gg/gptr" + loopsession "github.com/coze-dev/coze-loop/backend/infra/middleware/session" "github.com/coze-dev/coze-loop/backend/infra/backoff" "github.com/coze-dev/coze-loop/backend/infra/idgen" @@ -1113,6 +1114,12 @@ func (e *experimentApplication) InsightAnalysisExperiment(ctx context.Context, r session = &entity.Session{ UserID: strconv.FormatInt(gptr.Indirect(req.Session.UserID), 10), } + } else { + logs.CtxInfo(ctx, "InsightAnalysisExperiment found empty userID, expt_id: %v, workspace_id: %v", req.GetExptID(), req.GetWorkspaceID()) + userId := loopsession.UserIDInCtxOrEmpty(ctx) + session = &entity.Session{ + UserID: userId, + } } got, err := e.manager.Get(ctx, req.GetExptID(), req.GetWorkspaceID(), session) if err != nil { From 030503a0aadc590af8775a417deebfbb48305f78 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Mon, 10 Nov 2025 22:03:11 +0800 Subject: [PATCH 08/13] Revert "fix session, try another way to inject CreateBy" This reverts commit 3416ed5eb2b11fd8b5c6b2b2ac9d440a11e940b9. --- backend/modules/evaluation/application/experiment_app.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/backend/modules/evaluation/application/experiment_app.go b/backend/modules/evaluation/application/experiment_app.go index 932312b12..417b9475c 100644 --- a/backend/modules/evaluation/application/experiment_app.go +++ b/backend/modules/evaluation/application/experiment_app.go @@ -10,7 +10,6 @@ import ( "time" "github.com/bytedance/gg/gptr" - loopsession "github.com/coze-dev/coze-loop/backend/infra/middleware/session" "github.com/coze-dev/coze-loop/backend/infra/backoff" "github.com/coze-dev/coze-loop/backend/infra/idgen" @@ -1114,12 +1113,6 @@ func (e *experimentApplication) InsightAnalysisExperiment(ctx context.Context, r session = &entity.Session{ UserID: strconv.FormatInt(gptr.Indirect(req.Session.UserID), 10), } - } else { - logs.CtxInfo(ctx, "InsightAnalysisExperiment found empty userID, expt_id: %v, workspace_id: %v", req.GetExptID(), req.GetWorkspaceID()) - userId := loopsession.UserIDInCtxOrEmpty(ctx) - session = &entity.Session{ - UserID: userId, - } } got, err := e.manager.Get(ctx, req.GetExptID(), req.GetWorkspaceID(), session) if err != nil { From c373fcfb5f16bf27d5e34a7c83b5e49f4d014ceb Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Tue, 11 Nov 2025 11:46:03 +0800 Subject: [PATCH 09/13] fix timeout --- .../evaluation/domain/service/insight_analysis_impl.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl.go b/backend/modules/evaluation/domain/service/insight_analysis_impl.go index 90916b03c..acd734a61 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl.go @@ -207,6 +207,15 @@ func (e ExptInsightAnalysisServiceImpl) GetAnalysisRecordByID(ctx context.Contex return nil, err } + if analysisRecord.Status == entity.InsightAnalysisStatus_Running && analysisRecord.CreatedAt.Add(entity.ThreeHour).Unix() < time.Now().Unix() { + analysisRecord.Status = entity.InsightAnalysisStatus_Failed + err = e.repo.UpdateAnalysisRecord(ctx, analysisRecord) + if err != nil { + logs.CtxError(ctx, "GetAnalysisRecordByID: UpdateAnalysisRecord failed: %v", err) + } + return analysisRecord, err + } + if analysisRecord.Status == entity.InsightAnalysisStatus_Running || analysisRecord.Status == entity.InsightAnalysisStatus_Failed { return analysisRecord, nil From 6f4440d5e333cba8d3e03f8339bb2e4066d89ee5 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Tue, 11 Nov 2025 19:33:10 +0800 Subject: [PATCH 10/13] timeout change to 2hour --- .../evaluation/domain/entity/expt_insight_analysis_record.go | 2 +- .../evaluation/domain/service/insight_analysis_impl.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go b/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go index 3f2272f1f..bfb50f901 100644 --- a/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go +++ b/backend/modules/evaluation/domain/entity/expt_insight_analysis_record.go @@ -15,7 +15,7 @@ const ( ) const ( - ThreeHour = 3 * time.Hour + InsightAnalysisRunningTimeout = 2 * time.Hour ) type ExptInsightAnalysisRecord struct { diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl.go b/backend/modules/evaluation/domain/service/insight_analysis_impl.go index acd734a61..ca46d1be9 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl.go @@ -160,7 +160,7 @@ func (e ExptInsightAnalysisServiceImpl) checkAnalysisReportGenStatus(ctx context } // 超过3小时,未生成分析报告,认为是失败 - if status == entity.ReportStatus_Running && record.CreatedAt.Add(entity.ThreeHour).Unix() <= time.Now().Unix() { + if status == entity.ReportStatus_Running && record.CreatedAt.Add(entity.InsightAnalysisRunningTimeout).Unix() <= time.Now().Unix() { record.Status = entity.InsightAnalysisStatus_Failed logs.CtxWarn(ctx, "checkAnalysisReportGenStatus found timeout event, expt_id: %v, record_id: %v", record.ExptID, record.ID) return e.repo.UpdateAnalysisRecord(ctx, record) @@ -207,7 +207,7 @@ func (e ExptInsightAnalysisServiceImpl) GetAnalysisRecordByID(ctx context.Contex return nil, err } - if analysisRecord.Status == entity.InsightAnalysisStatus_Running && analysisRecord.CreatedAt.Add(entity.ThreeHour).Unix() < time.Now().Unix() { + if analysisRecord.Status == entity.InsightAnalysisStatus_Running && analysisRecord.CreatedAt.Add(entity.InsightAnalysisRunningTimeout).Unix() < time.Now().Unix() { analysisRecord.Status = entity.InsightAnalysisStatus_Failed err = e.repo.UpdateAnalysisRecord(ctx, analysisRecord) if err != nil { From 5f2ffb209edbbb33a2fcf6086d659bdf19afb414 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Wed, 12 Nov 2025 12:17:46 +0800 Subject: [PATCH 11/13] =?UTF-8?q?feat:=20[Coda]=20=E5=BC=BA=E5=88=B6?= =?UTF-8?q?=E8=AF=BB=E4=B8=BB=E5=BA=93=E6=94=AF=E6=92=91=E6=B4=9E=E5=AF=9F?= =?UTF-8?q?=E5=8F=8D=E9=A6=88=20(LogID:=20202511121049110100911082412387DA?= =?UTF-8?q?E)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Coda --- .../platestwrite/latest_write_tracker.go | 3 + .../evaluation/application/wire_gen.go | 4 +- .../expt_insight_analysis_record.go | 141 ++++++++++++++++-- .../expt_insight_analysis_record_test.go | 131 +++++++++++++++- .../expt_insight_analysis_feedback_comment.go | 25 +++- .../expt_insight_analysis_feedback_vote.go | 8 +- .../mysql/expt_insight_analysis_record.go | 8 +- .../expt_insight_analysis_feedback_comment.go | 33 +++- .../expt_insight_analysis_feedback_vote.go | 13 +- .../mocks/expt_insight_analysis_record.go | 13 +- 10 files changed, 335 insertions(+), 44 deletions(-) diff --git a/backend/infra/platestwrite/latest_write_tracker.go b/backend/infra/platestwrite/latest_write_tracker.go index dd4707b02..24e1df987 100644 --- a/backend/infra/platestwrite/latest_write_tracker.go +++ b/backend/infra/platestwrite/latest_write_tracker.go @@ -136,4 +136,7 @@ const ( ResourceTypeTarget ResourceType = "eval_target" ResourceTypeTargetVersion ResourceType = "eval_target_version" ResourceTypeEvaluator ResourceType = "evaluator" + + ResourceTypeExptInsightAnalysisRecord ResourceType = "expt_insight_analysis_record" + ResourceTypeExptInsightAnalysisFeedback ResourceType = "expt_insight_analysis_feedback" ) diff --git a/backend/modules/evaluation/application/wire_gen.go b/backend/modules/evaluation/application/wire_gen.go index 701d4b2ae..4fb69d4ba 100644 --- a/backend/modules/evaluation/application/wire_gen.go +++ b/backend/modules/evaluation/application/wire_gen.go @@ -156,7 +156,7 @@ func InitExperimentApplication(ctx context.Context, idgen2 idgen.IIDGenerator, d iExptInsightAnalysisRecordDAO := mysql.NewExptInsightAnalysisRecordDAO(db2) iExptInsightAnalysisFeedbackCommentDAO := mysql.NewExptInsightAnalysisFeedbackCommentDAO(db2) iExptInsightAnalysisFeedbackVoteDAO := mysql.NewExptInsightAnalysisFeedbackVoteDAO(db2) - iExptInsightAnalysisRecordRepo := experiment.NewExptInsightAnalysisRecordRepo(iExptInsightAnalysisRecordDAO, iExptInsightAnalysisFeedbackCommentDAO, iExptInsightAnalysisFeedbackVoteDAO, idgen2) + iExptInsightAnalysisRecordRepo := experiment.NewExptInsightAnalysisRecordRepo(iExptInsightAnalysisRecordDAO, iExptInsightAnalysisFeedbackCommentDAO, iExptInsightAnalysisFeedbackVoteDAO, idgen2, iLatestWriteTracker) iAgentAdapter := agent.NewAgentAdapter() iNotifyRPCAdapter := notify.NewNotifyRPCAdapter() iExptInsightAnalysisService := service.NewInsightAnalysisService(iExptInsightAnalysisRecordRepo, exptEventPublisher, objectStorage, iAgentAdapter, iExptResultExportService, iNotifyRPCAdapter, iUserProvider, iExperimentRepo) @@ -326,7 +326,7 @@ func InitEvalOpenAPIApplication(ctx context.Context, configFactory conf.IConfigL iExptInsightAnalysisRecordDAO := mysql.NewExptInsightAnalysisRecordDAO(db2) iExptInsightAnalysisFeedbackCommentDAO := mysql.NewExptInsightAnalysisFeedbackCommentDAO(db2) iExptInsightAnalysisFeedbackVoteDAO := mysql.NewExptInsightAnalysisFeedbackVoteDAO(db2) - iExptInsightAnalysisRecordRepo := experiment.NewExptInsightAnalysisRecordRepo(iExptInsightAnalysisRecordDAO, iExptInsightAnalysisFeedbackCommentDAO, iExptInsightAnalysisFeedbackVoteDAO, idgen2) + iExptInsightAnalysisRecordRepo := experiment.NewExptInsightAnalysisRecordRepo(iExptInsightAnalysisRecordDAO, iExptInsightAnalysisFeedbackCommentDAO, iExptInsightAnalysisFeedbackVoteDAO, idgen2, iLatestWriteTracker) iAgentAdapter := agent.NewAgentAdapter() iNotifyRPCAdapter := notify.NewNotifyRPCAdapter() iExptInsightAnalysisService := service.NewInsightAnalysisService(iExptInsightAnalysisRecordRepo, exptEventPublisher, objectStorage, iAgentAdapter, iExptResultExportService, iNotifyRPCAdapter, iUserProvider, iExperimentRepo) diff --git a/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record.go b/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record.go index de1355145..ff0c48ea2 100644 --- a/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record.go +++ b/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record.go @@ -5,9 +5,11 @@ package experiment import ( "context" + "fmt" "github.com/coze-dev/coze-loop/backend/infra/db" "github.com/coze-dev/coze-loop/backend/infra/idgen" + "github.com/coze-dev/coze-loop/backend/infra/platestwrite" "github.com/coze-dev/coze-loop/backend/modules/evaluation/domain/entity" "github.com/coze-dev/coze-loop/backend/modules/evaluation/domain/repo" "github.com/coze-dev/coze-loop/backend/modules/evaluation/infra/repo/experiment/mysql" @@ -19,6 +21,7 @@ type ExptInsightAnalysisRecordRepo struct { exptInsightAnalysisFeedbackCommentDAO mysql.IExptInsightAnalysisFeedbackCommentDAO exptInsightAnalysisFeedbackVoteDAO mysql.IExptInsightAnalysisFeedbackVoteDAO idgenerator idgen.IIDGenerator + writeTracker platestwrite.ILatestWriteTracker } func NewExptInsightAnalysisRecordRepo( @@ -26,12 +29,14 @@ func NewExptInsightAnalysisRecordRepo( exptInsightAnalysisFeedbackCommentDAO mysql.IExptInsightAnalysisFeedbackCommentDAO, exptInsightAnalysisFeedbackVoteDAO mysql.IExptInsightAnalysisFeedbackVoteDAO, idgenerator idgen.IIDGenerator, + writeTracker platestwrite.ILatestWriteTracker, ) repo.IExptInsightAnalysisRecordRepo { return &ExptInsightAnalysisRecordRepo{ exptInsightAnalysisRecordDAO: exptInsightAnalysisRecordDAO, exptInsightAnalysisFeedbackCommentDAO: exptInsightAnalysisFeedbackCommentDAO, exptInsightAnalysisFeedbackVoteDAO: exptInsightAnalysisFeedbackVoteDAO, idgenerator: idgenerator, + writeTracker: writeTracker, } } @@ -47,15 +52,34 @@ func (e ExptInsightAnalysisRecordRepo) CreateAnalysisRecord(ctx context.Context, return 0, err } + if e.writeTracker != nil { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisRecord, id, + platestwrite.SetWithSearchParam(buildRecordSearchParam(record.SpaceID, record.ExptID))) + } + return id, nil } func (e ExptInsightAnalysisRecordRepo) UpdateAnalysisRecord(ctx context.Context, record *entity.ExptInsightAnalysisRecord, opts ...db.Option) error { - return e.exptInsightAnalysisRecordDAO.Update(ctx, convert.ExptInsightAnalysisRecordDOToPO(record), opts...) + if err := e.exptInsightAnalysisRecordDAO.Update(ctx, convert.ExptInsightAnalysisRecordDOToPO(record), opts...); err != nil { + return err + } + + if e.writeTracker != nil { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisRecord, record.ID, + platestwrite.SetWithSearchParam(buildRecordSearchParam(record.SpaceID, record.ExptID))) + } + + return nil } func (e ExptInsightAnalysisRecordRepo) GetAnalysisRecordByID(ctx context.Context, spaceID, exptID, recordID int64) (*entity.ExptInsightAnalysisRecord, error) { - po, err := e.exptInsightAnalysisRecordDAO.GetByID(ctx, spaceID, exptID, recordID) + opts := make([]db.Option, 0) + if e.needForceMasterByRecord(ctx, platestwrite.ResourceTypeExptInsightAnalysisRecord, recordID, buildRecordSearchParam(spaceID, exptID)) { + opts = append(opts, db.WithMaster()) + } + + po, err := e.exptInsightAnalysisRecordDAO.GetByID(ctx, spaceID, exptID, recordID, opts...) if err != nil { return nil, err } @@ -64,7 +88,11 @@ func (e ExptInsightAnalysisRecordRepo) GetAnalysisRecordByID(ctx context.Context } func (e ExptInsightAnalysisRecordRepo) ListAnalysisRecord(ctx context.Context, spaceID, exptID int64, page entity.Page) ([]*entity.ExptInsightAnalysisRecord, int64, error) { - pos, total, err := e.exptInsightAnalysisRecordDAO.List(ctx, spaceID, exptID, page) + opts := make([]db.Option, 0) + if e.needForceMasterByRecord(ctx, platestwrite.ResourceTypeExptInsightAnalysisRecord, 0, buildRecordSearchParam(spaceID, exptID)) { + opts = append(opts, db.WithMaster()) + } + pos, total, err := e.exptInsightAnalysisRecordDAO.List(ctx, spaceID, exptID, page, opts...) if err != nil { return nil, 0, err } @@ -77,7 +105,14 @@ func (e ExptInsightAnalysisRecordRepo) ListAnalysisRecord(ctx context.Context, s } func (e ExptInsightAnalysisRecordRepo) DeleteAnalysisRecord(ctx context.Context, spaceID, exptID, recordID int64) error { - return e.exptInsightAnalysisRecordDAO.Delete(ctx, spaceID, exptID, recordID) + if err := e.exptInsightAnalysisRecordDAO.Delete(ctx, spaceID, exptID, recordID); err != nil { + return err + } + if e.writeTracker != nil { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisRecord, recordID, + platestwrite.SetWithSearchParam(buildRecordSearchParam(spaceID, exptID))) + } + return nil } func (e ExptInsightAnalysisRecordRepo) CreateFeedbackComment(ctx context.Context, feedbackComment *entity.ExptInsightAnalysisFeedbackComment, opts ...db.Option) error { @@ -86,15 +121,33 @@ func (e ExptInsightAnalysisRecordRepo) CreateFeedbackComment(ctx context.Context return err } feedbackComment.ID = id - return e.exptInsightAnalysisFeedbackCommentDAO.Create(ctx, convert.ExptInsightAnalysisFeedbackCommentDOToPO(feedbackComment), opts...) + if err := e.exptInsightAnalysisFeedbackCommentDAO.Create(ctx, convert.ExptInsightAnalysisFeedbackCommentDOToPO(feedbackComment), opts...); err != nil { + return err + } + if e.writeTracker != nil { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, feedbackComment.AnalysisRecordID, + platestwrite.SetWithSearchParam(buildFeedbackSearchParam(feedbackComment.SpaceID, feedbackComment.ExptID, feedbackComment.AnalysisRecordID))) + } + return nil } func (e ExptInsightAnalysisRecordRepo) UpdateFeedbackComment(ctx context.Context, feedbackComment *entity.ExptInsightAnalysisFeedbackComment, opts ...db.Option) error { - return e.exptInsightAnalysisFeedbackCommentDAO.Update(ctx, convert.ExptInsightAnalysisFeedbackCommentDOToPO(feedbackComment), opts...) + if err := e.exptInsightAnalysisFeedbackCommentDAO.Update(ctx, convert.ExptInsightAnalysisFeedbackCommentDOToPO(feedbackComment), opts...); err != nil { + return err + } + if e.writeTracker != nil { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, feedbackComment.AnalysisRecordID, + platestwrite.SetWithSearchParam(buildFeedbackSearchParam(feedbackComment.SpaceID, feedbackComment.ExptID, feedbackComment.AnalysisRecordID))) + } + return nil } func (e ExptInsightAnalysisRecordRepo) GetFeedbackCommentByRecordID(ctx context.Context, spaceID, exptID, recordID int64, opts ...db.Option) (*entity.ExptInsightAnalysisFeedbackComment, error) { - po, err := e.exptInsightAnalysisFeedbackCommentDAO.GetByRecordID(ctx, spaceID, exptID, recordID, opts...) + innerOpts := append([]db.Option{}, opts...) + if e.needForceMasterByRecord(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, recordID, buildFeedbackSearchParam(spaceID, exptID, recordID)) && !db.ContainWithMasterOpt(innerOpts) { + innerOpts = append(innerOpts, db.WithMaster()) + } + po, err := e.exptInsightAnalysisFeedbackCommentDAO.GetByRecordID(ctx, spaceID, exptID, recordID, innerOpts...) if err != nil { return nil, err } @@ -102,7 +155,22 @@ func (e ExptInsightAnalysisRecordRepo) GetFeedbackCommentByRecordID(ctx context. } func (e ExptInsightAnalysisRecordRepo) DeleteFeedbackComment(ctx context.Context, spaceID, exptID, commentID int64) error { - return e.exptInsightAnalysisFeedbackCommentDAO.Delete(ctx, spaceID, exptID, commentID) + po, err := e.exptInsightAnalysisFeedbackCommentDAO.GetByID(ctx, spaceID, exptID, commentID, db.WithMaster()) + if err != nil { + return err + } + if err := e.exptInsightAnalysisFeedbackCommentDAO.Delete(ctx, spaceID, exptID, commentID); err != nil { + return err + } + recordID := int64(0) + if po.AnalysisRecordID != nil { + recordID = *po.AnalysisRecordID + } + if e.writeTracker != nil && recordID > 0 { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, recordID, + platestwrite.SetWithSearchParam(buildFeedbackSearchParam(po.SpaceID, po.ExptID, recordID))) + } + return nil } func (e ExptInsightAnalysisRecordRepo) CreateFeedbackVote(ctx context.Context, feedbackVote *entity.ExptInsightAnalysisFeedbackVote, opts ...db.Option) error { @@ -111,15 +179,33 @@ func (e ExptInsightAnalysisRecordRepo) CreateFeedbackVote(ctx context.Context, f return err } feedbackVote.ID = id - return e.exptInsightAnalysisFeedbackVoteDAO.Create(ctx, convert.ExptInsightAnalysisFeedbackVoteDOToPO(feedbackVote), opts...) + if err := e.exptInsightAnalysisFeedbackVoteDAO.Create(ctx, convert.ExptInsightAnalysisFeedbackVoteDOToPO(feedbackVote), opts...); err != nil { + return err + } + if e.writeTracker != nil { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, feedbackVote.AnalysisRecordID, + platestwrite.SetWithSearchParam(buildFeedbackSearchParam(feedbackVote.SpaceID, feedbackVote.ExptID, feedbackVote.AnalysisRecordID))) + } + return nil } func (e ExptInsightAnalysisRecordRepo) UpdateFeedbackVote(ctx context.Context, feedbackVote *entity.ExptInsightAnalysisFeedbackVote, opts ...db.Option) error { - return e.exptInsightAnalysisFeedbackVoteDAO.Update(ctx, convert.ExptInsightAnalysisFeedbackVoteDOToPO(feedbackVote), opts...) + if err := e.exptInsightAnalysisFeedbackVoteDAO.Update(ctx, convert.ExptInsightAnalysisFeedbackVoteDOToPO(feedbackVote), opts...); err != nil { + return err + } + if e.writeTracker != nil { + e.writeTracker.SetWriteFlag(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, feedbackVote.AnalysisRecordID, + platestwrite.SetWithSearchParam(buildFeedbackSearchParam(feedbackVote.SpaceID, feedbackVote.ExptID, feedbackVote.AnalysisRecordID))) + } + return nil } func (e ExptInsightAnalysisRecordRepo) GetFeedbackVoteByUser(ctx context.Context, spaceID, exptID, recordID int64, userID string, opts ...db.Option) (*entity.ExptInsightAnalysisFeedbackVote, error) { - po, err := e.exptInsightAnalysisFeedbackVoteDAO.GetByUser(ctx, spaceID, exptID, recordID, userID, opts...) + innerOpts := append([]db.Option{}, opts...) + if e.needForceMasterByRecord(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, recordID, buildFeedbackSearchParam(spaceID, exptID, recordID)) && !db.ContainWithMasterOpt(innerOpts) { + innerOpts = append(innerOpts, db.WithMaster()) + } + po, err := e.exptInsightAnalysisFeedbackVoteDAO.GetByUser(ctx, spaceID, exptID, recordID, userID, innerOpts...) if err != nil { return nil, err } @@ -127,11 +213,19 @@ func (e ExptInsightAnalysisRecordRepo) GetFeedbackVoteByUser(ctx context.Context } func (e ExptInsightAnalysisRecordRepo) CountFeedbackVote(ctx context.Context, spaceID, exptID, recordID int64) (int64, int64, error) { - return e.exptInsightAnalysisFeedbackVoteDAO.Count(ctx, spaceID, exptID, recordID) + opts := make([]db.Option, 0) + if e.needForceMasterByRecord(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, recordID, buildFeedbackSearchParam(spaceID, exptID, recordID)) { + opts = append(opts, db.WithMaster()) + } + return e.exptInsightAnalysisFeedbackVoteDAO.Count(ctx, spaceID, exptID, recordID, opts...) } func (e ExptInsightAnalysisRecordRepo) List(ctx context.Context, spaceID, exptID, recordID int64, page entity.Page) ([]*entity.ExptInsightAnalysisFeedbackComment, int64, error) { - pos, total, err := e.exptInsightAnalysisFeedbackCommentDAO.List(ctx, spaceID, exptID, recordID, page) + opts := make([]db.Option, 0) + if e.needForceMasterByRecord(ctx, platestwrite.ResourceTypeExptInsightAnalysisFeedback, recordID, buildFeedbackSearchParam(spaceID, exptID, recordID)) { + opts = append(opts, db.WithMaster()) + } + pos, total, err := e.exptInsightAnalysisFeedbackCommentDAO.List(ctx, spaceID, exptID, recordID, page, opts...) if err != nil { return nil, 0, err } @@ -141,3 +235,24 @@ func (e ExptInsightAnalysisRecordRepo) List(ctx context.Context, spaceID, exptID } return dos, total, nil } + +func (e ExptInsightAnalysisRecordRepo) needForceMasterByRecord(ctx context.Context, resourceType platestwrite.ResourceType, resourceID int64, searchParam string) bool { + if e.writeTracker == nil { + return false + } + if resourceID > 0 && e.writeTracker.CheckWriteFlagByID(ctx, resourceType, resourceID) { + return true + } + if searchParam != "" && e.writeTracker.CheckWriteFlagBySearchParam(ctx, resourceType, searchParam) { + return true + } + return false +} + +func buildRecordSearchParam(spaceID, exptID int64) string { + return fmt.Sprintf("%d:%d", spaceID, exptID) +} + +func buildFeedbackSearchParam(spaceID, exptID, recordID int64) string { + return fmt.Sprintf("%d:%d:%d", spaceID, exptID, recordID) +} diff --git a/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record_test.go b/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record_test.go index a8070373b..30a829500 100644 --- a/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record_test.go +++ b/backend/modules/evaluation/infra/repo/experiment/expt_insight_analysis_record_test.go @@ -11,7 +11,9 @@ import ( "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" + "github.com/coze-dev/coze-loop/backend/infra/db" mockidgen "github.com/coze-dev/coze-loop/backend/infra/idgen/mocks" + platestwritemocks "github.com/coze-dev/coze-loop/backend/infra/platestwrite/mocks" "github.com/coze-dev/coze-loop/backend/modules/evaluation/domain/entity" "github.com/coze-dev/coze-loop/backend/modules/evaluation/infra/repo/experiment/mysql/gorm_gen/model" "github.com/coze-dev/coze-loop/backend/modules/evaluation/infra/repo/experiment/mysql/mocks" @@ -23,6 +25,7 @@ type testMocks struct { feedbackCommentDAO *mocks.MockIExptInsightAnalysisFeedbackCommentDAO feedbackVoteDAO *mocks.MockIExptInsightAnalysisFeedbackVoteDAO idGenerator *mockidgen.MockIIDGenerator + writeTracker *platestwritemocks.MockILatestWriteTracker } func newTestExptInsightAnalysisRecordRepo(ctrl *gomock.Controller) (*ExptInsightAnalysisRecordRepo, *testMocks) { @@ -31,6 +34,7 @@ func newTestExptInsightAnalysisRecordRepo(ctrl *gomock.Controller) (*ExptInsight feedbackCommentDAO: mocks.NewMockIExptInsightAnalysisFeedbackCommentDAO(ctrl), feedbackVoteDAO: mocks.NewMockIExptInsightAnalysisFeedbackVoteDAO(ctrl), idGenerator: mockidgen.NewMockIIDGenerator(ctrl), + writeTracker: platestwritemocks.NewMockILatestWriteTracker(ctrl), } repo := &ExptInsightAnalysisRecordRepo{ @@ -38,16 +42,29 @@ func newTestExptInsightAnalysisRecordRepo(ctrl *gomock.Controller) (*ExptInsight exptInsightAnalysisFeedbackCommentDAO: mocks.feedbackCommentDAO, exptInsightAnalysisFeedbackVoteDAO: mocks.feedbackVoteDAO, idgenerator: mocks.idGenerator, + writeTracker: mocks.writeTracker, } return repo, mocks } +func expectWriteFlagAny(m *testMocks) { + m.writeTracker.EXPECT().SetWriteFlag(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() +} + +func expectNoWriteFlagRead(m *testMocks) { + m.writeTracker.EXPECT().CheckWriteFlagByID(gomock.Any(), gomock.Any(), gomock.Any()).Return(false).AnyTimes() + m.writeTracker.EXPECT().CheckWriteFlagBySearchParam(gomock.Any(), gomock.Any(), gomock.Any()).Return(false).AnyTimes() +} + func TestExptInsightAnalysisRecordRepo_CreateAnalysisRecord(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) + expectWriteFlagAny(mocks) + expectWriteFlagAny(mocks) record := &entity.ExptInsightAnalysisRecord{ SpaceID: 1, @@ -72,6 +89,9 @@ func TestExptInsightAnalysisRecordRepo_UpdateAnalysisRecord(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) + expectWriteFlagAny(mocks) + expectWriteFlagAny(mocks) record := &entity.ExptInsightAnalysisRecord{ ID: 1, @@ -93,8 +113,9 @@ func TestExptInsightAnalysisRecordRepo_GetAnalysisRecordByID(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) - mocks.analysisRecordDAO.EXPECT().GetByID(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).Return(&model.ExptInsightAnalysisRecord{ + mocks.analysisRecordDAO.EXPECT().GetByID(gomock.Any(), int64(1), int64(1), int64(1)).Return(&model.ExptInsightAnalysisRecord{ ID: 1, SpaceID: 1, ExptID: 1, @@ -111,11 +132,34 @@ func TestExptInsightAnalysisRecordRepo_GetAnalysisRecordByID(t *testing.T) { assert.Equal(t, int64(1), record.ID) } +func TestExptInsightAnalysisRecordRepo_GetAnalysisRecordByID_ForceMaster(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + + mocks.writeTracker.EXPECT().CheckWriteFlagByID(gomock.Any(), gomock.Any(), int64(1)).Return(true) + mocks.writeTracker.EXPECT().CheckWriteFlagBySearchParam(gomock.Any(), gomock.Any(), gomock.Any()).Return(false).AnyTimes() + mocks.analysisRecordDAO.EXPECT().GetByID(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).DoAndReturn( + func(_ context.Context, _ int64, _ int64, _ int64, opts ...db.Option) (*model.ExptInsightAnalysisRecord, error) { + assert.True(t, db.ContainWithMasterOpt(opts)) + return &model.ExptInsightAnalysisRecord{ID: 1, SpaceID: 1, ExptID: 1}, nil + }, + ) + + record, err := repo.GetAnalysisRecordByID(context.Background(), 1, 1, 1) + + assert.NoError(t, err) + assert.NotNil(t, record) + assert.Equal(t, int64(1), record.ID) +} + func TestExptInsightAnalysisRecordRepo_ListAnalysisRecord(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) mocks.analysisRecordDAO.EXPECT().List(gomock.Any(), int64(1), int64(1), entity.NewPage(1, 10)).Return([]*model.ExptInsightAnalysisRecord{ { @@ -140,6 +184,7 @@ func TestExptInsightAnalysisRecordRepo_DeleteAnalysisRecord(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) mocks.analysisRecordDAO.EXPECT().Delete(gomock.Any(), int64(1), int64(1), int64(1)).Return(nil) @@ -153,6 +198,7 @@ func TestExptInsightAnalysisRecordRepo_CreateFeedbackComment(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) comment := &entity.ExptInsightAnalysisFeedbackComment{ SpaceID: 1, @@ -176,6 +222,7 @@ func TestExptInsightAnalysisRecordRepo_UpdateFeedbackComment(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) comment := &entity.ExptInsightAnalysisFeedbackComment{ ID: 1, @@ -197,7 +244,14 @@ func TestExptInsightAnalysisRecordRepo_DeleteFeedbackComment(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) + mocks.feedbackCommentDAO.EXPECT().GetByID(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).Return(&model.ExptInsightAnalysisFeedbackComment{ + ID: 1, + SpaceID: 1, + ExptID: 1, + AnalysisRecordID: ptr.Of(int64(1)), + }, nil) mocks.feedbackCommentDAO.EXPECT().Delete(gomock.Any(), int64(1), int64(1), int64(1)).Return(nil) err := repo.DeleteFeedbackComment(context.Background(), 1, 1, 1) @@ -205,11 +259,26 @@ func TestExptInsightAnalysisRecordRepo_DeleteFeedbackComment(t *testing.T) { assert.NoError(t, err) } +func TestExptInsightAnalysisRecordRepo_DeleteFeedbackComment_GetByIDError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) + + mocks.feedbackCommentDAO.EXPECT().GetByID(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).Return(nil, assert.AnError) + + err := repo.DeleteFeedbackComment(context.Background(), 1, 1, 1) + + assert.Error(t, err) +} + func TestExptInsightAnalysisRecordRepo_CreateFeedbackVote(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) vote := &entity.ExptInsightAnalysisFeedbackVote{ SpaceID: 1, @@ -233,6 +302,7 @@ func TestExptInsightAnalysisRecordRepo_UpdateFeedbackVote(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectWriteFlagAny(mocks) vote := &entity.ExptInsightAnalysisFeedbackVote{ ID: 1, @@ -254,8 +324,9 @@ func TestExptInsightAnalysisRecordRepo_GetFeedbackVoteByUser(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) - mocks.feedbackVoteDAO.EXPECT().GetByUser(gomock.Any(), int64(1), int64(1), int64(1), "user123", gomock.Any()).Return(&model.ExptInsightAnalysisFeedbackVote{ + mocks.feedbackVoteDAO.EXPECT().GetByUser(gomock.Any(), int64(1), int64(1), int64(1), "user123").Return(&model.ExptInsightAnalysisFeedbackVote{ ID: 1, SpaceID: 1, ExptID: 1, @@ -278,6 +349,7 @@ func TestExptInsightAnalysisRecordRepo_CountFeedbackVote(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) mocks.feedbackVoteDAO.EXPECT().Count(gomock.Any(), int64(1), int64(1), int64(1)).Return(int64(3), int64(2), nil) @@ -288,11 +360,34 @@ func TestExptInsightAnalysisRecordRepo_CountFeedbackVote(t *testing.T) { assert.Equal(t, int64(2), downVoteCount) } +func TestExptInsightAnalysisRecordRepo_CountFeedbackVote_ForceMaster(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + + mocks.writeTracker.EXPECT().CheckWriteFlagByID(gomock.Any(), gomock.Any(), gomock.Any()).Return(false).AnyTimes() + mocks.writeTracker.EXPECT().CheckWriteFlagBySearchParam(gomock.Any(), gomock.Any(), gomock.Any()).Return(true) + mocks.feedbackVoteDAO.EXPECT().Count(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).DoAndReturn( + func(_ context.Context, _ int64, _ int64, _ int64, opts ...db.Option) (int64, int64, error) { + assert.True(t, db.ContainWithMasterOpt(opts)) + return 3, 2, nil + }, + ) + + upVoteCount, downVoteCount, err := repo.CountFeedbackVote(context.Background(), 1, 1, 1) + + assert.NoError(t, err) + assert.Equal(t, int64(3), upVoteCount) + assert.Equal(t, int64(2), downVoteCount) +} + func TestExptInsightAnalysisRecordRepo_List(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) mocks.feedbackCommentDAO.EXPECT().List(gomock.Any(), int64(1), int64(1), int64(1), entity.NewPage(1, 10)).Return([]*model.ExptInsightAnalysisFeedbackComment{ { @@ -411,8 +506,9 @@ func TestExptInsightAnalysisRecordRepo_GetFeedbackCommentByRecordID(t *testing.T defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) - mocks.feedbackCommentDAO.EXPECT().GetByRecordID(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).Return(&model.ExptInsightAnalysisFeedbackComment{ + mocks.feedbackCommentDAO.EXPECT().GetByRecordID(gomock.Any(), int64(1), int64(1), int64(1)).Return(&model.ExptInsightAnalysisFeedbackComment{ ID: 1, SpaceID: 1, ExptID: 1, @@ -430,13 +526,36 @@ func TestExptInsightAnalysisRecordRepo_GetFeedbackCommentByRecordID(t *testing.T assert.Equal(t, int64(1), comment.ID) } +func TestExptInsightAnalysisRecordRepo_GetFeedbackCommentByRecordID_ForceMaster(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + + mocks.writeTracker.EXPECT().CheckWriteFlagByID(gomock.Any(), gomock.Any(), int64(1)).Return(true) + mocks.writeTracker.EXPECT().CheckWriteFlagBySearchParam(gomock.Any(), gomock.Any(), gomock.Any()).Return(false).AnyTimes() + mocks.feedbackCommentDAO.EXPECT().GetByRecordID(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).DoAndReturn( + func(_ context.Context, _ int64, _ int64, _ int64, opts ...db.Option) (*model.ExptInsightAnalysisFeedbackComment, error) { + assert.True(t, db.ContainWithMasterOpt(opts)) + return &model.ExptInsightAnalysisFeedbackComment{ID: 1, SpaceID: 1, ExptID: 1, AnalysisRecordID: ptr.Of(int64(1))}, nil + }, + ) + + comment, err := repo.GetFeedbackCommentByRecordID(context.Background(), 1, 1, 1) + + assert.NoError(t, err) + assert.NotNil(t, comment) + assert.Equal(t, int64(1), comment.ID) +} + func TestExptInsightAnalysisRecordRepo_GetFeedbackCommentByRecordID_Error(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) - mocks.feedbackCommentDAO.EXPECT().GetByRecordID(gomock.Any(), int64(1), int64(1), int64(1), gomock.Any()).Return(nil, assert.AnError) + mocks.feedbackCommentDAO.EXPECT().GetByRecordID(gomock.Any(), int64(1), int64(1), int64(1)).Return(nil, assert.AnError) comment, err := repo.GetFeedbackCommentByRecordID(context.Background(), 1, 1, 1) @@ -449,8 +568,9 @@ func TestExptInsightAnalysisRecordRepo_GetFeedbackVoteByUser_Error(t *testing.T) defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) - mocks.feedbackVoteDAO.EXPECT().GetByUser(gomock.Any(), int64(1), int64(1), int64(1), "user123", gomock.Any()).Return(nil, assert.AnError) + mocks.feedbackVoteDAO.EXPECT().GetByUser(gomock.Any(), int64(1), int64(1), int64(1), "user123").Return(nil, assert.AnError) vote, err := repo.GetFeedbackVoteByUser(context.Background(), 1, 1, 1, "user123") @@ -463,6 +583,7 @@ func TestExptInsightAnalysisRecordRepo_List_Error(t *testing.T) { defer ctrl.Finish() repo, mocks := newTestExptInsightAnalysisRecordRepo(ctrl) + expectNoWriteFlagRead(mocks) mocks.feedbackCommentDAO.EXPECT().List(gomock.Any(), int64(1), int64(1), int64(1), entity.NewPage(1, 10)).Return(nil, int64(0), assert.AnError) diff --git a/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_comment.go b/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_comment.go index 33944ba43..b495b1e7a 100644 --- a/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_comment.go +++ b/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_comment.go @@ -19,8 +19,9 @@ type IExptInsightAnalysisFeedbackCommentDAO interface { Create(ctx context.Context, feedbackComment *model.ExptInsightAnalysisFeedbackComment, opts ...db.Option) error Update(ctx context.Context, feedbackComment *model.ExptInsightAnalysisFeedbackComment, opts ...db.Option) error GetByRecordID(ctx context.Context, spaceID, exptID, recordID int64, opts ...db.Option) (*model.ExptInsightAnalysisFeedbackComment, error) + GetByID(ctx context.Context, spaceID, exptID, commentID int64, opts ...db.Option) (*model.ExptInsightAnalysisFeedbackComment, error) Delete(ctx context.Context, spaceID, exptID, commentID int64) error - List(ctx context.Context, spaceID, exptID, recordID int64, page entity.Page) ([]*model.ExptInsightAnalysisFeedbackComment, int64, error) + List(ctx context.Context, spaceID, exptID, recordID int64, page entity.Page, opts ...db.Option) ([]*model.ExptInsightAnalysisFeedbackComment, int64, error) } func NewExptInsightAnalysisFeedbackCommentDAO(db db.Provider) IExptInsightAnalysisFeedbackCommentDAO { @@ -50,7 +51,7 @@ func (e exptInsightAnalysisFeedbackCommentDAO) Update(ctx context.Context, feedb } func (e exptInsightAnalysisFeedbackCommentDAO) GetByRecordID(ctx context.Context, spaceID, exptID, recordID int64, opts ...db.Option) (*model.ExptInsightAnalysisFeedbackComment, error) { - db := e.db.NewSession(ctx) + db := e.db.NewSession(ctx, opts...) q := query.Use(db).ExptInsightAnalysisFeedbackComment feedbackVote, err := q.WithContext(ctx).Where( @@ -65,6 +66,22 @@ func (e exptInsightAnalysisFeedbackCommentDAO) GetByRecordID(ctx context.Context return feedbackVote, nil } +func (e exptInsightAnalysisFeedbackCommentDAO) GetByID(ctx context.Context, spaceID, exptID, commentID int64, opts ...db.Option) (*model.ExptInsightAnalysisFeedbackComment, error) { + db := e.db.NewSession(ctx, opts...) + q := query.Use(db).ExptInsightAnalysisFeedbackComment + + comment, err := q.WithContext(ctx).Where( + q.SpaceID.Eq(spaceID), + q.ExptID.Eq(exptID), + q.ID.Eq(commentID), + ).First() + if err != nil { + return nil, errorx.Wrapf(err, "exptInsightAnalysisFeedbackCommentDAO GetByID fail, commentID: %v", commentID) + } + + return comment, nil +} + func (e exptInsightAnalysisFeedbackCommentDAO) Delete(ctx context.Context, spaceID, exptID, commentID int64) error { po := &model.ExptInsightAnalysisFeedbackComment{} db := e.db.NewSession(ctx) @@ -77,12 +94,12 @@ func (e exptInsightAnalysisFeedbackCommentDAO) Delete(ctx context.Context, space return nil } -func (e exptInsightAnalysisFeedbackCommentDAO) List(ctx context.Context, spaceID, exptID, recordID int64, page entity.Page) ([]*model.ExptInsightAnalysisFeedbackComment, int64, error) { +func (e exptInsightAnalysisFeedbackCommentDAO) List(ctx context.Context, spaceID, exptID, recordID int64, page entity.Page, opts ...db.Option) ([]*model.ExptInsightAnalysisFeedbackComment, int64, error) { var ( finds []*model.ExptInsightAnalysisFeedbackComment total int64 ) - db := e.db.NewSession(ctx).Model(&model.ExptInsightAnalysisFeedbackComment{}). + db := e.db.NewSession(ctx, opts...).Model(&model.ExptInsightAnalysisFeedbackComment{}). Where("space_id =?", spaceID). Where("expt_id =?", exptID). Where("analysis_record_id =?", recordID).Order("created_at DESC") diff --git a/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_vote.go b/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_vote.go index a22fcd40e..799b3073b 100644 --- a/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_vote.go +++ b/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_feedback_vote.go @@ -23,7 +23,7 @@ type IExptInsightAnalysisFeedbackVoteDAO interface { Create(ctx context.Context, feedbackVote *model.ExptInsightAnalysisFeedbackVote, opts ...db.Option) error Update(ctx context.Context, feedbackVote *model.ExptInsightAnalysisFeedbackVote, opts ...db.Option) error GetByUser(ctx context.Context, spaceID, exptID, recordID int64, userID string, opts ...db.Option) (*model.ExptInsightAnalysisFeedbackVote, error) - Count(ctx context.Context, spaceID, exptID, recordID int64) (int64, int64, error) + Count(ctx context.Context, spaceID, exptID, recordID int64, opts ...db.Option) (int64, int64, error) } func NewExptInsightAnalysisFeedbackVoteDAO(db db.Provider) IExptInsightAnalysisFeedbackVoteDAO { @@ -59,7 +59,7 @@ func (e exptInsightAnalysisFeedbackVoteDAO) Update(ctx context.Context, feedback } func (e exptInsightAnalysisFeedbackVoteDAO) GetByUser(ctx context.Context, spaceID, exptID, recordID int64, userID string, opts ...db.Option) (*model.ExptInsightAnalysisFeedbackVote, error) { - db := e.db.NewSession(ctx) + db := e.db.NewSession(ctx, opts...) q := query.Use(db).ExptInsightAnalysisFeedbackVote feedbackVote, err := q.WithContext(ctx).Where( @@ -78,8 +78,8 @@ func (e exptInsightAnalysisFeedbackVoteDAO) GetByUser(ctx context.Context, space return feedbackVote, nil } -func (e exptInsightAnalysisFeedbackVoteDAO) Count(ctx context.Context, spaceID, exptID, recordID int64) (int64, int64, error) { - db := e.db.NewSession(ctx) +func (e exptInsightAnalysisFeedbackVoteDAO) Count(ctx context.Context, spaceID, exptID, recordID int64, opts ...db.Option) (int64, int64, error) { + db := e.db.NewSession(ctx, opts...) type VoteStatistic struct { UpvoteCount int64 `json:"upvote_count"` DownvoteCount int64 `json:"downvote_count"` diff --git a/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_record.go b/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_record.go index a19161106..7cf1e4714 100644 --- a/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_record.go +++ b/backend/modules/evaluation/infra/repo/experiment/mysql/expt_insight_analysis_record.go @@ -19,7 +19,7 @@ type IExptInsightAnalysisRecordDAO interface { Create(ctx context.Context, record *model.ExptInsightAnalysisRecord, opts ...db.Option) error Update(ctx context.Context, record *model.ExptInsightAnalysisRecord, opts ...db.Option) error GetByID(ctx context.Context, spaceID, exptID, recordID int64, opts ...db.Option) (*model.ExptInsightAnalysisRecord, error) - List(ctx context.Context, spaceID, exptID int64, page entity.Page) ([]*model.ExptInsightAnalysisRecord, int64, error) + List(ctx context.Context, spaceID, exptID int64, page entity.Page, opts ...db.Option) ([]*model.ExptInsightAnalysisRecord, int64, error) Delete(ctx context.Context, spaceID, exptID, recordID int64) error } @@ -50,7 +50,7 @@ func (e exptInsightAnalysisRecordDAO) Update(ctx context.Context, record *model. } func (e exptInsightAnalysisRecordDAO) GetByID(ctx context.Context, spaceID, exptID, recordID int64, opts ...db.Option) (*model.ExptInsightAnalysisRecord, error) { - db := e.db.NewSession(ctx) + db := e.db.NewSession(ctx, opts...) q := query.Use(db).ExptInsightAnalysisRecord record, err := q.WithContext(ctx).Where( @@ -65,13 +65,13 @@ func (e exptInsightAnalysisRecordDAO) GetByID(ctx context.Context, spaceID, expt return record, nil } -func (e exptInsightAnalysisRecordDAO) List(ctx context.Context, spaceID, exptID int64, page entity.Page) ([]*model.ExptInsightAnalysisRecord, int64, error) { +func (e exptInsightAnalysisRecordDAO) List(ctx context.Context, spaceID, exptID int64, page entity.Page, opts ...db.Option) ([]*model.ExptInsightAnalysisRecord, int64, error) { var ( finds []*model.ExptInsightAnalysisRecord total int64 ) - db := e.db.NewSession(ctx).Model(&model.ExptInsightAnalysisRecord{}).Where("space_id = ?", spaceID).Where("expt_id = ?", exptID) + db := e.db.NewSession(ctx, opts...).Model(&model.ExptInsightAnalysisRecord{}).Where("space_id = ?", spaceID).Where("expt_id = ?", exptID) db = db.Order("created_at desc") // 总记录数 diff --git a/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_comment.go b/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_comment.go index faee0a332..187b29441 100644 --- a/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_comment.go +++ b/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_comment.go @@ -90,10 +90,34 @@ func (mr *MockIExptInsightAnalysisFeedbackCommentDAOMockRecorder) GetByRecordID( return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByRecordID", reflect.TypeOf((*MockIExptInsightAnalysisFeedbackCommentDAO)(nil).GetByRecordID), varargs...) } +// GetByID mocks base method. +func (m *MockIExptInsightAnalysisFeedbackCommentDAO) GetByID(arg0 context.Context, arg1, arg2, arg3 int64, arg4 ...db.Option) (*model.ExptInsightAnalysisFeedbackComment, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetByID", varargs...) + ret0, _ := ret[0].(*model.ExptInsightAnalysisFeedbackComment) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByID indicates an expected call of GetByID. +func (mr *MockIExptInsightAnalysisFeedbackCommentDAOMockRecorder) GetByID(arg0, arg1, arg2, arg3 interface{}, arg4 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockIExptInsightAnalysisFeedbackCommentDAO)(nil).GetByID), varargs...) +} + // List mocks base method. -func (m *MockIExptInsightAnalysisFeedbackCommentDAO) List(arg0 context.Context, arg1, arg2, arg3 int64, arg4 entity.Page) ([]*model.ExptInsightAnalysisFeedbackComment, int64, error) { +func (m *MockIExptInsightAnalysisFeedbackCommentDAO) List(arg0 context.Context, arg1, arg2, arg3 int64, arg4 entity.Page, arg5 ...db.Option) ([]*model.ExptInsightAnalysisFeedbackComment, int64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "List", arg0, arg1, arg2, arg3, arg4) + varargs := []interface{}{arg0, arg1, arg2, arg3, arg4} + for _, a := range arg5 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "List", varargs...) ret0, _ := ret[0].([]*model.ExptInsightAnalysisFeedbackComment) ret1, _ := ret[1].(int64) ret2, _ := ret[2].(error) @@ -101,9 +125,10 @@ func (m *MockIExptInsightAnalysisFeedbackCommentDAO) List(arg0 context.Context, } // List indicates an expected call of List. -func (mr *MockIExptInsightAnalysisFeedbackCommentDAOMockRecorder) List(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockIExptInsightAnalysisFeedbackCommentDAOMockRecorder) List(arg0, arg1, arg2, arg3, arg4 interface{}, arg5 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockIExptInsightAnalysisFeedbackCommentDAO)(nil).List), arg0, arg1, arg2, arg3, arg4) + varargs := append([]interface{}{arg0, arg1, arg2, arg3, arg4}, arg5...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockIExptInsightAnalysisFeedbackCommentDAO)(nil).List), varargs...) } // Update mocks base method. diff --git a/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_vote.go b/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_vote.go index addd54589..2c12c6390 100644 --- a/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_vote.go +++ b/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_feedback_vote.go @@ -37,9 +37,13 @@ func (m *MockIExptInsightAnalysisFeedbackVoteDAO) EXPECT() *MockIExptInsightAnal } // Count mocks base method. -func (m *MockIExptInsightAnalysisFeedbackVoteDAO) Count(arg0 context.Context, arg1, arg2, arg3 int64) (int64, int64, error) { +func (m *MockIExptInsightAnalysisFeedbackVoteDAO) Count(arg0 context.Context, arg1, arg2, arg3 int64, arg4 ...db.Option) (int64, int64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Count", arg0, arg1, arg2, arg3) + varargs := []interface{}{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Count", varargs...) ret0, _ := ret[0].(int64) ret1, _ := ret[1].(int64) ret2, _ := ret[2].(error) @@ -47,9 +51,10 @@ func (m *MockIExptInsightAnalysisFeedbackVoteDAO) Count(arg0 context.Context, ar } // Count indicates an expected call of Count. -func (mr *MockIExptInsightAnalysisFeedbackVoteDAOMockRecorder) Count(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockIExptInsightAnalysisFeedbackVoteDAOMockRecorder) Count(arg0, arg1, arg2, arg3 interface{}, arg4 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Count", reflect.TypeOf((*MockIExptInsightAnalysisFeedbackVoteDAO)(nil).Count), arg0, arg1, arg2, arg3) + varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Count", reflect.TypeOf((*MockIExptInsightAnalysisFeedbackVoteDAO)(nil).Count), varargs...) } // Create mocks base method. diff --git a/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_record.go b/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_record.go index ccffbe7fc..d27da1fab 100644 --- a/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_record.go +++ b/backend/modules/evaluation/infra/repo/experiment/mysql/mocks/expt_insight_analysis_record.go @@ -91,9 +91,13 @@ func (mr *MockIExptInsightAnalysisRecordDAOMockRecorder) GetByID(arg0, arg1, arg } // List mocks base method. -func (m *MockIExptInsightAnalysisRecordDAO) List(arg0 context.Context, arg1, arg2 int64, arg3 entity.Page) ([]*model.ExptInsightAnalysisRecord, int64, error) { +func (m *MockIExptInsightAnalysisRecordDAO) List(arg0 context.Context, arg1, arg2 int64, arg3 entity.Page, arg4 ...db.Option) ([]*model.ExptInsightAnalysisRecord, int64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "List", arg0, arg1, arg2, arg3) + varargs := []interface{}{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "List", varargs...) ret0, _ := ret[0].([]*model.ExptInsightAnalysisRecord) ret1, _ := ret[1].(int64) ret2, _ := ret[2].(error) @@ -101,9 +105,10 @@ func (m *MockIExptInsightAnalysisRecordDAO) List(arg0 context.Context, arg1, arg } // List indicates an expected call of List. -func (mr *MockIExptInsightAnalysisRecordDAOMockRecorder) List(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockIExptInsightAnalysisRecordDAOMockRecorder) List(arg0, arg1, arg2, arg3 interface{}, arg4 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockIExptInsightAnalysisRecordDAO)(nil).List), arg0, arg1, arg2, arg3) + varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockIExptInsightAnalysisRecordDAO)(nil).List), varargs...) } // Update mocks base method. From a07fff1cc472f9715384c61e30214c7aca4e3990 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Wed, 12 Nov 2025 14:21:27 +0800 Subject: [PATCH 12/13] wire gen --- backend/modules/evaluation/application/wire_gen.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/modules/evaluation/application/wire_gen.go b/backend/modules/evaluation/application/wire_gen.go index 4fb69d4ba..7a90a96f2 100644 --- a/backend/modules/evaluation/application/wire_gen.go +++ b/backend/modules/evaluation/application/wire_gen.go @@ -235,7 +235,7 @@ func InitEvalTargetApplication(ctx context.Context, idgen2 idgen.IIDGenerator, d return evalTargetService } -func InitEvalOpenAPIApplication(ctx context.Context, configFactory conf.IConfigLoaderFactory, rmqFactory mq.IFactory, cmdable redis.Cmdable, idgen2 idgen.IIDGenerator, db2 db.Provider, client promptmanageservice.Client, executeClient promptexecuteservice.Client, authClient authservice.Client, meter metrics.Meter, dataClient datasetservice.Client, userClient userservice.Client, llmClient llmruntimeservice.Client, tagClient tagservice.Client, limiterFactory limiter.IRateLimiterFactory, objectStorage fileserver.ObjectStorage, auditClient audit.IAuditService, benefitService benefit.IBenefitService, ckProvider ck.Provider) (IEvalOpenAPIApplication, error) { +func InitEvalOpenAPIApplication(ctx context.Context, configFactory conf.IConfigLoaderFactory, rmqFactory mq.IFactory, cmdable redis.Cmdable, idgen2 idgen.IIDGenerator, db2 db.Provider, client promptmanageservice.Client, executeClient promptexecuteservice.Client, authClient authservice.Client, meter metrics.Meter, dataClient datasetservice.Client, userClient userservice.Client, llmClient llmruntimeservice.Client, tagClient tagservice.Client, limiterFactory limiter.IRateLimiterFactory, objectStorage fileserver.ObjectStorage, auditClient audit.IAuditService, benefitService benefit.IBenefitService, ckProvider ck.Provider) (evaluation.EvalOpenAPIService, error) { iEvalAsyncDAO := dao.NewEvalAsyncDAO(cmdable) iEvalAsyncRepo := experiment.NewEvalAsyncRepo(iEvalAsyncDAO) exptEventPublisher, err := producer.NewExptEventPublisher(ctx, configFactory, rmqFactory) @@ -331,8 +331,8 @@ func InitEvalOpenAPIApplication(ctx context.Context, configFactory conf.IConfigL iNotifyRPCAdapter := notify.NewNotifyRPCAdapter() iExptInsightAnalysisService := service.NewInsightAnalysisService(iExptInsightAnalysisRecordRepo, exptEventPublisher, objectStorage, iAgentAdapter, iExptResultExportService, iNotifyRPCAdapter, iUserProvider, iExperimentRepo) iExperimentApplication := NewExperimentApplication(exptAggrResultService, exptResultService, iExptManager, exptSchedulerEvent, exptItemEvalEvent, idgen2, componentIConfiger, iAuthProvider, userInfoService, iEvalTargetService, evaluationSetItemService, iExptAnnotateService, iTagRPCAdapter, iExptResultExportService, iExptInsightAnalysisService) - v3 := NewEvalOpenAPIApplication(iEvalAsyncRepo, exptEventPublisher, iEvalTargetService, iAuthProvider, iEvaluationSetService, evaluationSetVersionService, evaluationSetItemService, evaluationSetSchemaService, openAPIEvaluationMetrics, userInfoService, iExperimentApplication, iExptManager, exptResultService, exptAggrResultService, evaluatorService) - return v3, nil + evalOpenAPIService := NewEvalOpenAPIApplication(iEvalAsyncRepo, exptEventPublisher, iEvalTargetService, iAuthProvider, iEvaluationSetService, evaluationSetVersionService, evaluationSetItemService, evaluationSetSchemaService, openAPIEvaluationMetrics, userInfoService, iExperimentApplication, iExptManager, exptResultService, exptAggrResultService, evaluatorService) + return evalOpenAPIService, nil } // wire.go: From 1b59b039e68e66d9d34e5b1b0cf291e379624025 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Wed, 12 Nov 2025 14:40:47 +0800 Subject: [PATCH 13/13] first record of ListExptInsightAnalysisRecord would contain feedback info for frontend display --- .../evaluation/application/experiment_app.go | 4 ++- .../domain/service/insight_analysis_impl.go | 35 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/backend/modules/evaluation/application/experiment_app.go b/backend/modules/evaluation/application/experiment_app.go index 417b9475c..88778c254 100644 --- a/backend/modules/evaluation/application/experiment_app.go +++ b/backend/modules/evaluation/application/experiment_app.go @@ -1160,7 +1160,6 @@ func (e *experimentApplication) ListExptInsightAnalysisRecord(ctx context.Contex UserID: strconv.FormatInt(gptr.Indirect(req.Session.UserID), 10), } } - err = e.auth.Authorization(ctx, &rpc.AuthorizationParam{ ObjectID: strconv.FormatInt(req.WorkspaceID, 10), SpaceID: req.WorkspaceID, @@ -1169,6 +1168,9 @@ func (e *experimentApplication) ListExptInsightAnalysisRecord(ctx context.Contex if err != nil { return nil, err } + + // First record contains the upvote/downvote count info for display purpose, + // Other records' feedback is not necessary for this list api records, total, err := e.ListAnalysisRecord(ctx, req.GetWorkspaceID(), req.GetExptID(), entity.NewPage(int(req.GetPageNumber()), int(req.GetPageSize())), session) if err != nil { return nil, err diff --git a/backend/modules/evaluation/domain/service/insight_analysis_impl.go b/backend/modules/evaluation/domain/service/insight_analysis_impl.go index ca46d1be9..ec45b6b27 100644 --- a/backend/modules/evaluation/domain/service/insight_analysis_impl.go +++ b/backend/modules/evaluation/domain/service/insight_analysis_impl.go @@ -275,7 +275,40 @@ func (e ExptInsightAnalysisServiceImpl) notifyAnalysisComplete(ctx context.Conte } func (e ExptInsightAnalysisServiceImpl) ListAnalysisRecord(ctx context.Context, spaceID, exptID int64, page entity.Page, session *entity.Session) ([]*entity.ExptInsightAnalysisRecord, int64, error) { - return e.repo.ListAnalysisRecord(ctx, spaceID, exptID, page) + analysisRecords, total, err := e.repo.ListAnalysisRecord(ctx, spaceID, exptID, page) + if err != nil { + return nil, 0, err + } + if total == 0 { + return analysisRecords, total, nil + } + + firstAnalysisRecord := analysisRecords[0] + + upvoteCount, downvoteCount, err := e.repo.CountFeedbackVote(ctx, spaceID, exptID, firstAnalysisRecord.ID) + if err != nil { + // side path, don't block the main flow + logs.CtxWarn(ctx, "CountFeedbackVote failed for space_id: %v, expt_id: %v, record_id: %v, err=%v", spaceID, exptID, firstAnalysisRecord.ID, err) + return analysisRecords, total, nil + } + + curUserFeedbackVote, err := e.repo.GetFeedbackVoteByUser(ctx, spaceID, exptID, firstAnalysisRecord.ID, session.UserID) + if err != nil { + // side path, don't block the main flow + logs.CtxWarn(ctx, "GetFeedbackVoteByUser failed for space_id: %v, expt_id: %v, record_id: %v, err=%v", spaceID, exptID, firstAnalysisRecord.ID, err) + return analysisRecords, total, nil + } + firstAnalysisRecord.ExptInsightAnalysisFeedback = entity.ExptInsightAnalysisFeedback{ + UpvoteCount: upvoteCount, + DownvoteCount: downvoteCount, + CurrentUserVoteType: entity.None, + } + firstAnalysisRecord.ExptInsightAnalysisFeedback.CurrentUserVoteType = entity.None + if curUserFeedbackVote != nil { + firstAnalysisRecord.ExptInsightAnalysisFeedback.CurrentUserVoteType = curUserFeedbackVote.VoteType + } + + return analysisRecords, total, nil } func (e ExptInsightAnalysisServiceImpl) DeleteAnalysisRecord(ctx context.Context, spaceID, exptID, recordID int64) error {