合并分支
This commit is contained in:
7818
2026_05_29.log
7818
2026_05_29.log
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
app/assets/appearance-patent-Cb_Fx4da.css
Normal file
1
app/assets/appearance-patent-Cb_Fx4da.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{bN as r}from"./java-modules-B8c-YG5x.js";const n="";function s(e){return r(`${n}/api/brand/expand-folder-recursive`,{folder:e})}export{s as e};
|
||||
import{bN as r}from"./java-modules-WSWRTEaR.js";const n="";function s(e){return r(`${n}/api/brand/expand-folder-recursive`,{folder:e})}export{s as e};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>格式转换 - 数富AI</title>
|
||||
<script type="module" crossorigin src="/assets/convert.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-B8c-YG5x.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-COze15GJ.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-l5anrOZ2.css">
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-WSWRTEaR.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-5GpfAyHD.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-B3hGvRck.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/convert-6oxZNMye.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>数据去重 - 数富AI</title>
|
||||
<script type="module" crossorigin src="/assets/dedupe.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-B8c-YG5x.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-COze15GJ.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-l5anrOZ2.css">
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-WSWRTEaR.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-5GpfAyHD.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-B3hGvRck.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/dedupe-DpfPYQDv.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>删除品牌 - 数富AI</title>
|
||||
<script type="module" crossorigin src="/assets/delete-brand.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-B8c-YG5x.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-COze15GJ.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-WSWRTEaR.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-5GpfAyHD.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/categorized-timers-JPA-olTr.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-l5anrOZ2.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-B3hGvRck.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/delete-brand-DZ3x5hOX.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>数据拆分 - 数富AI</title>
|
||||
<script type="module" crossorigin src="/assets/split.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-B8c-YG5x.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-COze15GJ.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-l5anrOZ2.css">
|
||||
<link rel="modulepreload" crossorigin href="/assets/java-modules-WSWRTEaR.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/brand-5GpfAyHD.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/java-modules-B3hGvRck.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/split-CR1PtDQE.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -36,6 +36,10 @@ public class AppearancePatentCozeClient {
|
||||
private final AtomicLong credentialCursor = new AtomicLong();
|
||||
|
||||
public List<AppearancePatentResultRowDto> inspect(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) {
|
||||
return inspect(rows, prompt, apiKey, null);
|
||||
}
|
||||
|
||||
public List<AppearancePatentResultRowDto> inspect(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey, String patentToken) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
@@ -44,7 +48,7 @@ public class AppearancePatentCozeClient {
|
||||
return rows.stream().map(this::copy).toList();
|
||||
}
|
||||
try {
|
||||
return inspectWithFallback(rows, prompt, apiKey);
|
||||
return inspectWithFallback(rows, prompt, apiKey, patentToken);
|
||||
} catch (Exception ex) {
|
||||
String failureMessage = failureMessage(ex);
|
||||
log.warn("[appearance-patent] coze batch failed size={} err={}", rows.size(), failureMessage);
|
||||
@@ -53,15 +57,16 @@ public class AppearancePatentCozeClient {
|
||||
}
|
||||
|
||||
public CozeSubmitResponse submitWorkflow(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) throws Exception {
|
||||
return submitWorkflow(rows, prompt, apiKey, nextCredential());
|
||||
return submitWorkflow(rows, prompt, apiKey, null, nextCredential());
|
||||
}
|
||||
|
||||
public CozeSubmitResponse submitWorkflow(List<AppearancePatentResultRowDto> rows,
|
||||
String prompt,
|
||||
String apiKey,
|
||||
String patentToken,
|
||||
CozeCredentialRef credential) throws Exception {
|
||||
CozeCredentialRef resolvedCredential = resolveCredential(credential);
|
||||
JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, resolvedCredential));
|
||||
JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, patentToken, resolvedCredential));
|
||||
ensureSuccess(submitRoot);
|
||||
return new CozeSubmitResponse(
|
||||
extractExecuteId(submitRoot),
|
||||
@@ -103,12 +108,12 @@ public class AppearancePatentCozeClient {
|
||||
return rows.stream().map(this::copy).map(row -> markFailed(row, failureMessage)).toList();
|
||||
}
|
||||
|
||||
private List<AppearancePatentResultRowDto> inspectWithFallback(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) {
|
||||
private List<AppearancePatentResultRowDto> inspectWithFallback(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey, String patentToken) {
|
||||
try {
|
||||
if (rows.size() == 1) {
|
||||
return inspectSingleRowWithRetry(rows, prompt, apiKey);
|
||||
return inspectSingleRowWithRetry(rows, prompt, apiKey, patentToken);
|
||||
}
|
||||
InspectAttempt attempt = inspectOnce(rows, prompt, apiKey);
|
||||
InspectAttempt attempt = inspectOnce(rows, prompt, apiKey, patentToken);
|
||||
if (attempt.resolvedCount() < rows.size()) {
|
||||
throw new PartialCozeResultException(attempt.resolvedCount(), rows.size(), attempt.rawResultCount());
|
||||
}
|
||||
@@ -119,17 +124,17 @@ public class AppearancePatentCozeClient {
|
||||
log.warn("[appearance-patent] coze batch fallback split size={} left={} right={} err={}",
|
||||
rows.size(), middle, rows.size() - middle, failureMessage(ex));
|
||||
List<AppearancePatentResultRowDto> merged = new ArrayList<>(rows.size());
|
||||
merged.addAll(inspectPartitionWithFailureFallback(rows.subList(0, middle), prompt, apiKey));
|
||||
merged.addAll(inspectPartitionWithFailureFallback(rows.subList(middle, rows.size()), prompt, apiKey));
|
||||
merged.addAll(inspectPartitionWithFailureFallback(rows.subList(0, middle), prompt, apiKey, patentToken));
|
||||
merged.addAll(inspectPartitionWithFailureFallback(rows.subList(middle, rows.size()), prompt, apiKey, patentToken));
|
||||
return merged;
|
||||
}
|
||||
throw propagate(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private List<AppearancePatentResultRowDto> inspectPartitionWithFailureFallback(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) {
|
||||
private List<AppearancePatentResultRowDto> inspectPartitionWithFailureFallback(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey, String patentToken) {
|
||||
try {
|
||||
return inspectWithFallback(rows, prompt, apiKey);
|
||||
return inspectWithFallback(rows, prompt, apiKey, patentToken);
|
||||
} catch (Exception ex) {
|
||||
String failureMessage = failureMessage(ex);
|
||||
log.warn("[appearance-patent] coze partition failed size={} err={}", rows.size(), failureMessage);
|
||||
@@ -137,12 +142,12 @@ public class AppearancePatentCozeClient {
|
||||
}
|
||||
}
|
||||
|
||||
private List<AppearancePatentResultRowDto> inspectSingleRowWithRetry(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) throws Exception {
|
||||
private List<AppearancePatentResultRowDto> inspectSingleRowWithRetry(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey, String patentToken) throws Exception {
|
||||
AppearancePatentResultRowDto row = rows.getFirst();
|
||||
PartialCozeResultException lastFailure = null;
|
||||
for (int attemptIndex = 1; attemptIndex <= 3; attemptIndex++) {
|
||||
try {
|
||||
InspectAttempt attempt = inspectOnce(rows, prompt, apiKey);
|
||||
InspectAttempt attempt = inspectOnce(rows, prompt, apiKey, patentToken);
|
||||
if (attempt.resolvedCount() == rows.size()) {
|
||||
return attempt.mergedRows();
|
||||
}
|
||||
@@ -173,8 +178,8 @@ public class AppearancePatentCozeClient {
|
||||
throw lastFailure == null ? new PartialCozeResultException(0, rows.size(), 0) : lastFailure;
|
||||
}
|
||||
|
||||
private InspectAttempt inspectOnce(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) throws Exception {
|
||||
String raw = runWorkflowAsyncAndWait(rows, prompt, apiKey);
|
||||
private InspectAttempt inspectOnce(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey, String patentToken) throws Exception {
|
||||
String raw = runWorkflowAsyncAndWait(rows, prompt, apiKey, patentToken);
|
||||
List<CozeResult> results = parseResults(raw);
|
||||
if (rows.size() > 1 && !results.isEmpty() && results.stream().noneMatch(this::hasIdentity)) {
|
||||
throw new PartialCozeResultException(0, rows.size(), results.size());
|
||||
@@ -183,9 +188,9 @@ public class AppearancePatentCozeClient {
|
||||
return new InspectAttempt(raw, merged, resolvedCount(merged), results.size());
|
||||
}
|
||||
|
||||
private String runWorkflowAsyncAndWait(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) throws Exception {
|
||||
private String runWorkflowAsyncAndWait(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey, String patentToken) throws Exception {
|
||||
CozeCredentialRef credential = nextCredential();
|
||||
JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, credential));
|
||||
JsonNode submitRoot = objectMapper.readTree(postWorkflow(rows, prompt, apiKey, patentToken, credential));
|
||||
ensureSuccess(submitRoot);
|
||||
|
||||
String immediateData = extractResultDataText(submitRoot);
|
||||
@@ -229,8 +234,9 @@ public class AppearancePatentCozeClient {
|
||||
private String postWorkflow(List<AppearancePatentResultRowDto> rows,
|
||||
String prompt,
|
||||
String apiKey,
|
||||
String patentToken,
|
||||
CozeCredentialRef credential) {
|
||||
Map<String, Object> parameters = buildParameters(rows, prompt, apiKey);
|
||||
Map<String, Object> parameters = buildParameters(rows, prompt, apiKey, patentToken);
|
||||
Map<String, Object> body = new LinkedHashMap<>();
|
||||
body.put("workflow_id", credential.workflowId());
|
||||
body.put("parameters", parameters);
|
||||
@@ -350,7 +356,7 @@ public class AppearancePatentCozeClient {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
private Map<String, Object> buildParameters(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey) {
|
||||
private Map<String, Object> buildParameters(List<AppearancePatentResultRowDto> rows, String prompt, String apiKey, String patentToken) {
|
||||
List<String> groupKeys = rows.stream().map(row -> nonBlank(row.getGroupKey(), rowKey(row))).toList();
|
||||
List<String> rowIds = rows.stream().map(row -> nonBlank(row.getId(), "")).toList();
|
||||
List<String> asins = rows.stream().map(row -> nonBlank(row.getAsin(), "")).toList();
|
||||
@@ -370,6 +376,9 @@ public class AppearancePatentCozeClient {
|
||||
if (apiKey != null && !apiKey.isBlank()) {
|
||||
parameters.put("api_key", apiKey.trim());
|
||||
}
|
||||
if (patentToken != null && !patentToken.isBlank()) {
|
||||
parameters.put("patent_token", patentToken.trim());
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@@ -383,6 +392,10 @@ public class AppearancePatentCozeClient {
|
||||
if (apiKey instanceof String apiKeyText && !apiKeyText.isBlank()) {
|
||||
maskedParameters.put("api_key", maskSecret(apiKeyText));
|
||||
}
|
||||
Object patentToken = maskedParameters.get("patent_token");
|
||||
if (patentToken instanceof String patentTokenText && !patentTokenText.isBlank()) {
|
||||
maskedParameters.put("patent_token", maskSecret(patentTokenText));
|
||||
}
|
||||
masked.put("parameters", maskedParameters);
|
||||
}
|
||||
return masked;
|
||||
|
||||
@@ -32,4 +32,9 @@ public class AppearancePatentParseRequest {
|
||||
@Schema(description = "传递给 Coze workflow parameters.api_key 的任务级密钥。")
|
||||
@NotBlank(message = "密钥不能为空")
|
||||
private String apiKey;
|
||||
|
||||
@JsonProperty("patent_token")
|
||||
@JsonAlias({"patentToken"})
|
||||
@Schema(description = "传递给 Coze workflow parameters.patent_token 的专利汇令牌。非必填。")
|
||||
private String patentToken;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.List;
|
||||
public class AppearancePatentParsedGroupManifestDto {
|
||||
private String aiPrompt;
|
||||
private String apiKey;
|
||||
private String patentToken;
|
||||
private Integer pageSize;
|
||||
private Integer totalGroups;
|
||||
private Integer totalRows;
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.List;
|
||||
public class AppearancePatentParsedGroupPageDto {
|
||||
private String aiPrompt;
|
||||
private String apiKey;
|
||||
private String patentToken;
|
||||
private Integer page;
|
||||
private Integer pageSize;
|
||||
private Integer totalGroups;
|
||||
|
||||
@@ -17,6 +17,9 @@ public class AppearancePatentParsedPayloadDto {
|
||||
@Schema(description = "传递给 Coze workflow parameters.api_key 的任务级密钥")
|
||||
private String apiKey;
|
||||
|
||||
@Schema(description = "传递给 Coze workflow parameters.patent_token 的专利汇令牌")
|
||||
private String patentToken;
|
||||
|
||||
@Schema(description = "本次解析的源文件列表")
|
||||
private List<AppearancePatentSourceFileDto> sourceFiles = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -218,11 +218,11 @@ public class AppearancePatentTaskService {
|
||||
|
||||
String aggregateScopeKey = buildAggregateScopeKey(sourceFiles);
|
||||
String sourceScopeHash = DigestUtil.sha256Hex(aggregateScopeKey);
|
||||
String parsedPayload = buildParsedPayloadJson(request.getAiPrompt(), request.getApiKey(), sourceFiles, mergedHeaders, allRows);
|
||||
String parsedPayload = buildParsedPayloadJson(request.getAiPrompt(), request.getApiKey(), request.getPatentToken(), sourceFiles, mergedHeaders, allRows);
|
||||
long payloadBuiltAt = System.nanoTime();
|
||||
String parsedPayloadPointer = storeParsedPayload(task.getId(), sourceScopeHash, parsedPayload);
|
||||
long payloadStoredAt = System.nanoTime();
|
||||
task.setResultJson(buildTaskResultJson(request.getAiPrompt(), request.getApiKey(), sourceFiles, parsedPayloadPointer));
|
||||
task.setResultJson(buildTaskResultJson(request.getAiPrompt(), request.getApiKey(), request.getPatentToken(), sourceFiles, parsedPayloadPointer));
|
||||
task.setUpdatedAt(LocalDateTime.now());
|
||||
fileTaskMapper.updateById(task);
|
||||
|
||||
@@ -984,10 +984,11 @@ public class AppearancePatentTaskService {
|
||||
}
|
||||
String prompt = readAiPrompt(task);
|
||||
String apiKey = readApiKey(task);
|
||||
String patentToken = readPatentToken(task);
|
||||
int batchSize = Math.max(1, properties.getCozeBatchSize());
|
||||
List<AppearancePatentResultRowDto> result = new ArrayList<>();
|
||||
for (int i = 0; i < items.size(); i += batchSize) {
|
||||
result.addAll(cozeClient.inspect(items.subList(i, Math.min(i + batchSize, items.size())), prompt, apiKey));
|
||||
result.addAll(cozeClient.inspect(items.subList(i, Math.min(i + batchSize, items.size())), prompt, apiKey, patentToken));
|
||||
if (progressHook != null) {
|
||||
progressHook.run();
|
||||
}
|
||||
@@ -1287,6 +1288,14 @@ public class AppearancePatentTaskService {
|
||||
}
|
||||
}
|
||||
|
||||
private String readPatentToken(FileTaskEntity task) {
|
||||
try {
|
||||
return normalize(readParsedPayload(task).getPatentToken());
|
||||
} catch (Exception ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private void finalizeTask(FileTaskEntity task, String error, int rowCount, boolean assembleWorkbook) {
|
||||
String finalError = error;
|
||||
FileResultEntity result = null;
|
||||
@@ -1592,6 +1601,7 @@ public class AppearancePatentTaskService {
|
||||
}
|
||||
String prompt = readAiPrompt(task);
|
||||
String apiKey = readApiKey(task);
|
||||
String patentToken = readPatentToken(task);
|
||||
int batchSize = Math.max(1, properties.getCozeBatchSize());
|
||||
List<CozeCandidate> candidates = collectPendingCozeCandidates(task, chunks);
|
||||
boolean flushRemainder = isResultSubmissionComplete(task.getId());
|
||||
@@ -1612,7 +1622,7 @@ public class AppearancePatentTaskService {
|
||||
List<AppearancePatentResultRowDto> batchRows = batchCandidates.stream()
|
||||
.map(CozeCandidate::row)
|
||||
.toList();
|
||||
pending |= submitCozeBatch(task, result, job, batchRows, batchIndex, batchTotal, prompt, apiKey, allRowsByBaseId);
|
||||
pending |= submitCozeBatch(task, result, job, batchRows, batchIndex, batchTotal, prompt, apiKey, patentToken, allRowsByBaseId);
|
||||
batchIndex++;
|
||||
}
|
||||
return pending || countPendingCozeStates(task.getId()) > 0;
|
||||
@@ -1626,6 +1636,7 @@ public class AppearancePatentTaskService {
|
||||
int batchTotal,
|
||||
String prompt,
|
||||
String apiKey,
|
||||
String patentToken,
|
||||
Map<String, List<AppearancePatentParsedRowVo>> allRowsByBaseId) {
|
||||
if (batchRows == null || batchRows.isEmpty()) {
|
||||
return false;
|
||||
@@ -1645,7 +1656,7 @@ public class AppearancePatentTaskService {
|
||||
AppearancePatentCozeClient.CozeCredentialRef credential = cozeClient.nextCredential();
|
||||
try {
|
||||
AppearancePatentCozeClient.CozeSubmitResponse submit = submitCozeWorkflowThrottled(
|
||||
batchRows, prompt, apiKey, credential, true);
|
||||
batchRows, prompt, apiKey, patentToken, credential, true);
|
||||
if (submit.immediateData() != null && !submit.immediateData().isBlank()) {
|
||||
List<AppearancePatentResultRowDto> cozeRows = mergeUsableCozeRows(batchRows, submit.immediateData());
|
||||
mergeCozeRowsIntoSubmittedChunks(task, cozeRows, allRowsByBaseId);
|
||||
@@ -1945,7 +1956,7 @@ public class AppearancePatentTaskService {
|
||||
}
|
||||
try {
|
||||
AppearancePatentCozeClient.CozeSubmitResponse submit =
|
||||
submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task),
|
||||
submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task), readPatentToken(task),
|
||||
cozeClient.credentialByName(context.credentialName()), false);
|
||||
Map<String, List<AppearancePatentParsedRowVo>> allRowsByBaseId = loadAllRowsByBaseId(task);
|
||||
if (submit.immediateData() != null && !submit.immediateData().isBlank()) {
|
||||
@@ -1996,6 +2007,7 @@ public class AppearancePatentTaskService {
|
||||
List<AppearancePatentResultRowDto> rows,
|
||||
String prompt,
|
||||
String apiKey,
|
||||
String patentToken,
|
||||
AppearancePatentCozeClient.CozeCredentialRef credential,
|
||||
boolean allowCredentialFallback) throws Exception {
|
||||
int attempts = allowCredentialFallback ? Math.max(1, cozeClient.configuredCredentialCount()) : 1;
|
||||
@@ -2018,7 +2030,7 @@ public class AppearancePatentTaskService {
|
||||
continue;
|
||||
}
|
||||
try (lockHandle; borrowedCredential) {
|
||||
return cozeClient.submitWorkflow(rows, prompt, apiKey, currentCredential);
|
||||
return cozeClient.submitWorkflow(rows, prompt, apiKey, patentToken, currentCredential);
|
||||
} finally {
|
||||
sleepQuietly(COZE_SUBMIT_MIN_INTERVAL_MILLIS);
|
||||
}
|
||||
@@ -2088,7 +2100,7 @@ public class AppearancePatentTaskService {
|
||||
int partIndex = 1;
|
||||
for (List<AppearancePatentResultRowDto> partRows : partitions) {
|
||||
AppearancePatentCozeClient.CozeSubmitResponse submit =
|
||||
submitCozeWorkflowThrottled(partRows, readAiPrompt(task), readApiKey(task),
|
||||
submitCozeWorkflowThrottled(partRows, readAiPrompt(task), readApiKey(task), readPatentToken(task),
|
||||
cozeClient.credentialByName(context.credentialName()), false);
|
||||
if (submit.immediateData() != null && !submit.immediateData().isBlank()) {
|
||||
List<AppearancePatentResultRowDto> cozeRows =
|
||||
@@ -2615,7 +2627,7 @@ public class AppearancePatentTaskService {
|
||||
try {
|
||||
taskFileJobService.touchRunning(context.jobId());
|
||||
AppearancePatentCozeClient.CozeSubmitResponse submit =
|
||||
submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task),
|
||||
submitCozeWorkflowThrottled(batchRows, readAiPrompt(task), readApiKey(task), readPatentToken(task),
|
||||
cozeClient.credentialByName(context.credentialName()), false);
|
||||
Map<String, List<AppearancePatentParsedRowVo>> allRowsByBaseId = loadAllRowsByBaseId(task);
|
||||
if (submit.immediateData() != null && !submit.immediateData().isBlank()) {
|
||||
@@ -3814,10 +3826,11 @@ public class AppearancePatentTaskService {
|
||||
return val == null ? "" : val.replace(String.valueOf((char) 0xFEFF), "").replace((char) 0x3000, ' ').trim().replaceAll("\\s+", " ");
|
||||
}
|
||||
|
||||
private String buildParsedPayloadJson(String aiPrompt, String apiKey, List<AppearancePatentSourceFileDto> sourceFiles, List<String> headers, List<AppearancePatentParsedRowVo> allRows) {
|
||||
private String buildParsedPayloadJson(String aiPrompt, String apiKey, String patentToken, List<AppearancePatentSourceFileDto> sourceFiles, List<String> headers, List<AppearancePatentParsedRowVo> allRows) {
|
||||
AppearancePatentParsedPayloadDto payload = new AppearancePatentParsedPayloadDto();
|
||||
payload.setAiPrompt(normalize(aiPrompt));
|
||||
payload.setApiKey(normalize(apiKey));
|
||||
payload.setPatentToken(normalize(patentToken));
|
||||
payload.setSourceFiles(sourceFiles == null ? List.of() : sourceFiles);
|
||||
payload.setHeaders(headers == null ? List.of() : headers);
|
||||
payload.setItems(List.of());
|
||||
@@ -3826,10 +3839,11 @@ public class AppearancePatentTaskService {
|
||||
return writeJson(payload, "保存解析结果失败");
|
||||
}
|
||||
|
||||
private String buildTaskResultJson(String aiPrompt, String apiKey, List<AppearancePatentSourceFileDto> sourceFiles, String parsedPayloadPointer) {
|
||||
private String buildTaskResultJson(String aiPrompt, String apiKey, String patentToken, List<AppearancePatentSourceFileDto> sourceFiles, String parsedPayloadPointer) {
|
||||
Map<String, Object> payload = new LinkedHashMap<>();
|
||||
payload.put("aiPrompt", normalize(aiPrompt));
|
||||
payload.put("apiKey", normalize(apiKey));
|
||||
payload.put("patentToken", normalize(patentToken));
|
||||
payload.put("sourceFileKeys", sourceFiles == null ? List.of() : sourceFiles.stream()
|
||||
.map(AppearancePatentSourceFileDto::getFileKey)
|
||||
.filter(Objects::nonNull)
|
||||
@@ -3907,6 +3921,7 @@ public class AppearancePatentTaskService {
|
||||
AppearancePatentParsedPayloadDto queuePayload = new AppearancePatentParsedPayloadDto();
|
||||
queuePayload.setAiPrompt(payload.getAiPrompt());
|
||||
queuePayload.setApiKey(payload.getApiKey());
|
||||
queuePayload.setPatentToken(payload.getPatentToken());
|
||||
queuePayload.setGroups(payload.getGroups() == null ? List.of() : payload.getGroups());
|
||||
queuePayload.setItems(List.of());
|
||||
queuePayload.setAllItems(List.of());
|
||||
@@ -3932,6 +3947,7 @@ public class AppearancePatentTaskService {
|
||||
AppearancePatentParsedGroupPageDto vo = new AppearancePatentParsedGroupPageDto();
|
||||
vo.setAiPrompt(payload.getAiPrompt());
|
||||
vo.setApiKey(payload.getApiKey());
|
||||
vo.setPatentToken(payload.getPatentToken());
|
||||
vo.setPage(safePage);
|
||||
vo.setPageSize(safePageSize);
|
||||
vo.setTotalGroups(totalGroups);
|
||||
|
||||
@@ -483,8 +483,11 @@ public class SimilarAsinTaskService {
|
||||
|
||||
public SimilarAsinDashboardVo dashboard(Long userId) {
|
||||
SimilarAsinDashboardVo vo = new SimilarAsinDashboardVo();
|
||||
vo.setPendingTaskCount(countTask(userId, STATUS_RUNNING));
|
||||
vo.setSuccessTaskCount(countTask(userId, STATUS_SUCCESS));
|
||||
long completedWithFile = countCompletedTasksWithResultFile(userId);
|
||||
long rawRunning = countTask(userId, STATUS_RUNNING);
|
||||
long rawSuccess = countTask(userId, STATUS_SUCCESS);
|
||||
vo.setPendingTaskCount(Math.max(0L, rawRunning - completedWithFile));
|
||||
vo.setSuccessTaskCount(rawSuccess + completedWithFile);
|
||||
vo.setFailedTaskCount(countTask(userId, STATUS_FAILED));
|
||||
vo.setProcessedTaskCount(vo.getSuccessTaskCount() + vo.getFailedTaskCount());
|
||||
return vo;
|
||||
@@ -4819,6 +4822,22 @@ public class SimilarAsinTaskService {
|
||||
return count == null ? 0L : count;
|
||||
}
|
||||
|
||||
private long countCompletedTasksWithResultFile(Long userId) {
|
||||
if (userId == null || userId <= 0) {
|
||||
return 0L;
|
||||
}
|
||||
Long count = fileTaskMapper.selectCount(new LambdaQueryWrapper<FileTaskEntity>()
|
||||
.eq(FileTaskEntity::getModuleType, MODULE_TYPE)
|
||||
.eq(FileTaskEntity::getUserId, userId)
|
||||
.eq(FileTaskEntity::getStatus, STATUS_RUNNING)
|
||||
.inSql(FileTaskEntity::getId,
|
||||
"select distinct task_id from file_result " +
|
||||
"where module_type = '" + MODULE_TYPE + "' " +
|
||||
"and user_id = " + userId + " " +
|
||||
"and result_file_url is not null and result_file_url <> ''"));
|
||||
return count == null ? 0L : count;
|
||||
}
|
||||
|
||||
private int countChunks(Long taskId, String scopeHash) {
|
||||
Long count = taskChunkMapper.selectCount(new LambdaQueryWrapper<TaskChunkEntity>()
|
||||
.eq(TaskChunkEntity::getTaskId, taskId)
|
||||
@@ -4861,7 +4880,7 @@ public class SimilarAsinTaskService {
|
||||
SimilarAsinTaskItemVo vo = new SimilarAsinTaskItemVo();
|
||||
vo.setId(task.getId());
|
||||
vo.setTaskNo(task.getTaskNo());
|
||||
vo.setStatus(task.getStatus());
|
||||
vo.setStatus(resolveDisplayTaskStatus(task));
|
||||
vo.setErrorMessage(task.getErrorMessage());
|
||||
vo.setCreatedAt(fmt(task.getCreatedAt()));
|
||||
vo.setUpdatedAt(fmt(task.getUpdatedAt()));
|
||||
@@ -4876,7 +4895,7 @@ public class SimilarAsinTaskService {
|
||||
vo.setSourceFilename(row.getSourceFilename());
|
||||
vo.setResultFilename(row.getResultFilename());
|
||||
vo.setDownloadUrl(buildFreshDownloadUrl(row));
|
||||
vo.setTaskStatus(task == null ? null : task.getStatus());
|
||||
vo.setTaskStatus(resolveDisplayTaskStatus(task, row));
|
||||
attachFileJobState(vo, row, job, task);
|
||||
vo.setSuccess(row.getSuccess() != null && row.getSuccess() == 1);
|
||||
vo.setError(row.getErrorMessage());
|
||||
@@ -4931,6 +4950,13 @@ public class SimilarAsinTaskService {
|
||||
int cozePending = countPendingCozeStates(taskId);
|
||||
boolean uploadComplete = isResultSubmissionComplete(taskId);
|
||||
if (!uploadComplete) {
|
||||
if (canTreatTaskAsCompleted(task, row, job)) {
|
||||
vo.setFileProgressCurrent(1);
|
||||
vo.setFileProgressTotal(1);
|
||||
vo.setFileProgressPercent(100);
|
||||
vo.setFileProgressMessage("结果文件已生成");
|
||||
return;
|
||||
}
|
||||
if (task != null && !STATUS_RUNNING.equals(task.getStatus())) {
|
||||
return;
|
||||
}
|
||||
@@ -5088,6 +5114,42 @@ public class SimilarAsinTaskService {
|
||||
return "等待 Python 回传,已回传 " + Math.max(0, current) + "/" + Math.max(1, total) + " " + safeUnit;
|
||||
}
|
||||
|
||||
private String resolveDisplayTaskStatus(FileTaskEntity task) {
|
||||
return resolveDisplayTaskStatus(task, null);
|
||||
}
|
||||
|
||||
private String resolveDisplayTaskStatus(FileTaskEntity task, FileResultEntity row) {
|
||||
if (task == null) {
|
||||
return null;
|
||||
}
|
||||
if (canTreatTaskAsCompleted(task, row, null)) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
return task.getStatus();
|
||||
}
|
||||
|
||||
private boolean canTreatTaskAsCompleted(FileTaskEntity task, FileResultEntity row, TaskFileJobEntity job) {
|
||||
if (task == null) {
|
||||
return false;
|
||||
}
|
||||
if (STATUS_SUCCESS.equals(task.getStatus())) {
|
||||
return true;
|
||||
}
|
||||
if (!STATUS_RUNNING.equals(task.getStatus())) {
|
||||
return false;
|
||||
}
|
||||
if (row == null) {
|
||||
return false;
|
||||
}
|
||||
if (row.getResultFileUrl() == null || row.getResultFileUrl().isBlank()) {
|
||||
return false;
|
||||
}
|
||||
if (job != null && "FAILED".equals(job.getStatus())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int calculateCozeDisplayTotal(TaskProgressSnapshotEntity snapshot, int observedCozeStates) {
|
||||
int observed = Math.max(0, observedCozeStates);
|
||||
// 小任务 totalCount <= 3 时直接使用 observed,避免 totalCount - 3 → 0 引起进度条 0/0。
|
||||
|
||||
@@ -121,6 +121,13 @@ public class TaskResultFileJobWorker {
|
||||
TaskDistributedLockService.LockHandle lockHandle =
|
||||
taskDistributedLockService.acquire(job.getModuleType(), job.getTaskId(), TaskDistributedLockService.DEFAULT_WAIT_MILLIS);
|
||||
if (lockHandle == null) {
|
||||
TaskFileJobEntity latestOnBusy = taskFileJobService.findById(job.getId());
|
||||
if (latestOnBusy != null && "RUNNING".equals(latestOnBusy.getStatus())) {
|
||||
taskFileJobService.touchRunning(job.getId());
|
||||
log.info("[task-file-job] process skipped because task lock is busy and job is already running jobId={} taskId={} moduleType={} resultId={}",
|
||||
job.getId(), job.getTaskId(), job.getModuleType(), job.getResultId());
|
||||
return;
|
||||
}
|
||||
taskFileJobService.requeue(job.getId(), "Task is busy, waiting for previous task operation");
|
||||
log.info("[task-file-job] process requeued because task lock is busy jobId={} taskId={} moduleType={} resultId={}",
|
||||
job.getId(), job.getTaskId(), job.getModuleType(), job.getResultId());
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
v-model="secretStates[config.key].value"
|
||||
class="secret-input"
|
||||
type="password"
|
||||
placeholder="请输入 Coze 接口密钥"
|
||||
:placeholder="config.placeholder"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
/>
|
||||
@@ -96,21 +96,30 @@ const retentionOptions: Array<{ value: ApiSecretRetention; label: string }> = [
|
||||
{ value: 'forever', label: '长期保留' },
|
||||
]
|
||||
|
||||
const secretConfigs: Array<{ key: ApiSecretModuleKey; title: string; description: string }> = [
|
||||
const secretConfigs: Array<{ key: ApiSecretModuleKey; title: string; description: string; placeholder: string }> = [
|
||||
{
|
||||
key: 'appearance-patent',
|
||||
title: '外观专利密钥',
|
||||
description: '仅用于外观专利检测。',
|
||||
placeholder: '请输入 Coze 接口密钥',
|
||||
},
|
||||
{
|
||||
key: 'appearance-patent-token',
|
||||
title: '专利汇令牌',
|
||||
description: '仅用于外观专利检测,非必填。',
|
||||
placeholder: '请输入专利汇令牌,可留空',
|
||||
},
|
||||
{
|
||||
key: 'similar-asin',
|
||||
title: '货源查询密钥',
|
||||
description: '仅用于货源查询。',
|
||||
placeholder: '请输入 Coze 接口密钥',
|
||||
},
|
||||
]
|
||||
|
||||
const secretStates = ref<Record<ApiSecretModuleKey, SecretState>>({
|
||||
'appearance-patent': emptySecretState(),
|
||||
'appearance-patent-token': emptySecretState(),
|
||||
'similar-asin': emptySecretState(),
|
||||
})
|
||||
|
||||
|
||||
@@ -261,6 +261,10 @@ function effectiveCozeApiKey() {
|
||||
return getStoredApiSecret('appearance-patent').trim()
|
||||
}
|
||||
|
||||
function effectivePatentToken() {
|
||||
return getStoredApiSecret('appearance-patent-token').trim()
|
||||
}
|
||||
|
||||
function maskSecret(secret: string) {
|
||||
if (!secret) return ''
|
||||
if (secret.length <= 10) return '***'
|
||||
@@ -274,6 +278,7 @@ function payloadForDisplay<T extends { data?: Record<string, unknown> }>(payload
|
||||
? {
|
||||
...payload.data,
|
||||
api_key: maskSecret(String(payload.data.api_key || '')),
|
||||
patent_token: maskSecret(String(payload.data.patent_token || '')),
|
||||
}
|
||||
: payload.data,
|
||||
}
|
||||
@@ -406,7 +411,7 @@ async function parseFiles() {
|
||||
originalFilename: f.originalFilename,
|
||||
relativePath: f.relativePath,
|
||||
}))
|
||||
const res = await parseAppearancePatent(files, effectiveAiPrompt(), effectiveCozeApiKey())
|
||||
const res = await parseAppearancePatent(files, effectiveAiPrompt(), effectiveCozeApiKey(), effectivePatentToken())
|
||||
parseResult.value = res
|
||||
queuedTaskSummary.value = null
|
||||
queuePayloadText.value = ''
|
||||
@@ -445,6 +450,7 @@ async function pushToPythonQueue() {
|
||||
taskId,
|
||||
prompt: queueAiPrompt(),
|
||||
api_key: effectiveCozeApiKey(),
|
||||
patent_token: effectivePatentToken(),
|
||||
sourceFileCount: currentParseResult.sourceFileCount || 0,
|
||||
totalRows: currentParseResult.totalRows || 0,
|
||||
acceptedRows: currentParseResult.acceptedRows || 0,
|
||||
|
||||
@@ -1529,6 +1529,7 @@ export interface AppearancePatentParseVo {
|
||||
export interface AppearancePatentParsedPayloadDto {
|
||||
aiPrompt?: string;
|
||||
apiKey?: string;
|
||||
patentToken?: string;
|
||||
sourceFiles?: UploadedFileRef[];
|
||||
headers?: string[];
|
||||
items?: AppearancePatentParsedRow[];
|
||||
@@ -1590,16 +1591,17 @@ export interface AppearancePatentTaskBatchVo {
|
||||
missingTaskIds?: number[];
|
||||
}
|
||||
|
||||
export function parseAppearancePatent(files: UploadedFileRef[], aiPrompt: string, apiKey?: string) {
|
||||
export function parseAppearancePatent(files: UploadedFileRef[], aiPrompt: string, apiKey?: string, patentToken?: string) {
|
||||
return unwrapJavaResponse(
|
||||
post<
|
||||
JavaApiResponse<AppearancePatentParseVo>,
|
||||
{ user_id: number; files: UploadedFileRef[]; ai_prompt: string; api_key?: string }
|
||||
{ user_id: number; files: UploadedFileRef[]; ai_prompt: string; api_key?: string; patent_token?: string }
|
||||
>(`${JAVA_API_PREFIX}/appearance-patent/parse`, {
|
||||
user_id: getCurrentUserId(),
|
||||
files,
|
||||
ai_prompt: aiPrompt,
|
||||
api_key: apiKey,
|
||||
patent_token: patentToken,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type ApiSecretModuleKey = 'appearance-patent' | 'similar-asin'
|
||||
export type ApiSecretModuleKey = 'appearance-patent' | 'appearance-patent-token' | 'similar-asin'
|
||||
|
||||
export type ApiSecretRetention = 'session' | '1d' | '7d' | '30d' | 'forever'
|
||||
|
||||
@@ -19,7 +19,7 @@ export type ApiSecretSnapshot = {
|
||||
|
||||
const STORAGE_PREFIX = 'brand:api-secret'
|
||||
const COMMON_SECRET_KEY = 'common'
|
||||
const MODULE_SECRET_KEYS: ApiSecretModuleKey[] = ['appearance-patent', 'similar-asin']
|
||||
const MODULE_SECRET_KEYS: ApiSecretModuleKey[] = ['appearance-patent', 'appearance-patent-token', 'similar-asin']
|
||||
|
||||
function currentUserStorageId() {
|
||||
if (typeof window === 'undefined') return '0'
|
||||
@@ -115,7 +115,7 @@ function clearLegacyStoredApiSecrets() {
|
||||
function migrateCommonRecord(record: ApiSecretRecord) {
|
||||
if (typeof window === 'undefined') return
|
||||
const storage = record.retention === 'session' ? window.sessionStorage : window.localStorage
|
||||
for (const moduleKey of MODULE_SECRET_KEYS) {
|
||||
for (const moduleKey of ['appearance-patent', 'similar-asin'] satisfies ApiSecretModuleKey[]) {
|
||||
if (!getLiveRecordFromKey(moduleKey)) {
|
||||
storage.setItem(buildStorageKey(moduleKey), JSON.stringify(record))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user