|
@@ -378,14 +378,39 @@
|
|
|
</div>
|
|
|
<!-- <el-progress style="width:80%" :text-inside="true" :stroke-width="24" :percentage="progressData.value"></el-progress> -->
|
|
|
</div>
|
|
|
- <div class="chatAreaLoading" v-else-if="actionTypeLoading">
|
|
|
- <div class="cal_box" :style="{ height: '300px' }">
|
|
|
- <div
|
|
|
- :style="{ width: '100%', height: '100px' }"
|
|
|
- v-loading="true"
|
|
|
- :element-loading-text="actionTypeLoadingText"
|
|
|
- ></div>
|
|
|
- <el-button @click="stopGenerateActionTypes">停止</el-button>
|
|
|
+ <div class="chatAreaLoading" v-else-if="jobContext">
|
|
|
+ <div class="cal_box" :style="{ height: 'fit-content' }">
|
|
|
+ <el-progress
|
|
|
+ type="circle"
|
|
|
+ :percentage="jobContext.progress.percentage"
|
|
|
+ :color="jobContext.status === 'paused' ? '#ff4949' : '#20a0ff'"
|
|
|
+ :format="() => `${jobContext.progress.current}/${jobContext.progress.total}`"
|
|
|
+ ></el-progress>
|
|
|
+ <span v-if="jobContext.status === 'paused' && jobContext.error">{{
|
|
|
+ jobContext.error
|
|
|
+ }}</span>
|
|
|
+ <div :style="{ display: 'flex' }">
|
|
|
+ <el-button
|
|
|
+ v-if="jobContext.status === 'paused'"
|
|
|
+ @click="() => jobContext.restart()"
|
|
|
+ icon="el-icon-video-play"
|
|
|
+ type="primary"
|
|
|
+ >
|
|
|
+ 继续
|
|
|
+ </el-button>
|
|
|
+ <!-- <el-button
|
|
|
+ v-if="jobContext.status === 'running'"
|
|
|
+ icon="el-icon-video-pause"
|
|
|
+ @click="() => jobContext.pause()"
|
|
|
+ >暂停</el-button
|
|
|
+ > -->
|
|
|
+ <el-button
|
|
|
+ type="danger"
|
|
|
+ icon="el-icon-switch-button"
|
|
|
+ @click="() => jobContext.stop()"
|
|
|
+ >终止</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<!-- <el-progress style="width:80%" :text-inside="true" :stroke-width="24" :percentage="progressData.value"></el-progress> -->
|
|
|
</div>
|
|
@@ -603,8 +628,7 @@ export default {
|
|
|
},
|
|
|
chatList: [],
|
|
|
actionTypesMap: {},
|
|
|
- actionTypeLoading: false,
|
|
|
- actionTypeLoadingText: "",
|
|
|
+ jobContext: null,
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
@@ -2310,30 +2334,42 @@ ${JSON.stringify(_list)}
|
|
|
const div = document.createElement("div");
|
|
|
div.innerHTML = content;
|
|
|
const tableRows = _.slice(div.querySelectorAll(`table tbody tr`), 1);
|
|
|
- if (!tableRows.length) {
|
|
|
+ if (!tableRows.length || tableRows[0].cells.length < 7) {
|
|
|
this.$notify.info("没有可编码的内容");
|
|
|
return;
|
|
|
}
|
|
|
- this.actionTypeLoading = true;
|
|
|
- this.generateActionTypesCtrl = new AbortController();
|
|
|
- const signal = this.generateActionTypesCtrl.signal;
|
|
|
- await new Promise((resolve) => {
|
|
|
- this.$nextTick(resolve);
|
|
|
- });
|
|
|
- try {
|
|
|
- tableRows.forEach((i) => {
|
|
|
- while (i.cells.length >= 7) {
|
|
|
- i.removeChild(i.lastElementChild);
|
|
|
- }
|
|
|
- });
|
|
|
- this.actionTypeLoadingText = `( 0/${tableRows.length} )`;
|
|
|
- // large chunk size will cause token limit and slower
|
|
|
- const chunkSize = 30;
|
|
|
- this.actionTypesMap.jsonData[key] = Array.from({ length: tableRows.length });
|
|
|
- // action type fetch by every { chunkSize } rows
|
|
|
- for (const [index, rows] of _.chunk(tableRows, chunkSize).entries()) {
|
|
|
+ const ctrl = new AbortController();
|
|
|
+ this.jobContext = {
|
|
|
+ ctrl,
|
|
|
+ status: "running",
|
|
|
+ restart: () => {},
|
|
|
+ pause: () => {},
|
|
|
+ stop: () => {
|
|
|
+ const err = new Error();
|
|
|
+ err.name = "StopError";
|
|
|
+ this.jobContext.ctrl.abort(err);
|
|
|
+ },
|
|
|
+ progress: {
|
|
|
+ current: 0,
|
|
|
+ currentSize: 0,
|
|
|
+ total: tableRows.length,
|
|
|
+ percentage: 0,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ // large chunk size will cause token limit and slower
|
|
|
+ const chunkSize = 30;
|
|
|
+ this.actionTypesMap.jsonData[key] = Array.from({ length: tableRows.length }).fill(
|
|
|
+ ""
|
|
|
+ );
|
|
|
+
|
|
|
+ const jobs = _.chunk(tableRows, chunkSize).map((rows, index) => {
|
|
|
+ return async (pauseSignal) => {
|
|
|
+ this.jobContext.progress.current = index * chunkSize;
|
|
|
+ this.jobContext.progress.currentSize = rows.length;
|
|
|
+ this.jobContext.progress.percentage =
|
|
|
+ ((index * chunkSize) / tableRows.length) * 100;
|
|
|
const res = await fetch("https://dify.cocorobo.cn/v1/workflows/run", {
|
|
|
- signal,
|
|
|
+ signal: AbortSignal.any([this.jobContext.ctrl.signal, pauseSignal]),
|
|
|
method: "POST",
|
|
|
body: JSON.stringify({
|
|
|
inputs: {
|
|
@@ -2349,13 +2385,13 @@ ${JSON.stringify(_list)}
|
|
|
}),
|
|
|
...config,
|
|
|
}).then((res) => res.json());
|
|
|
- if (signal.aborted) {
|
|
|
- return;
|
|
|
- }
|
|
|
const error = _.get(res, ["data", "error"], null);
|
|
|
+ // test
|
|
|
+ // throw new Error('mock error');
|
|
|
if (error) {
|
|
|
- this.$notify.error(error);
|
|
|
- return;
|
|
|
+ const err = new Error(error);
|
|
|
+ err.name = "DifyError";
|
|
|
+ throw err;
|
|
|
}
|
|
|
const chunkResult = _.get(res, ["data", "outputs", "result"], []);
|
|
|
this.actionTypesMap.jsonData[key].splice(
|
|
@@ -2367,26 +2403,46 @@ ${JSON.stringify(_list)}
|
|
|
transcriptionData: this.transcriptionData.content,
|
|
|
editorBarData: this.editorBarData,
|
|
|
});
|
|
|
- this.actionTypeLoadingText = `( ${index * chunkSize + rows.length}/${
|
|
|
- tableRows.length
|
|
|
- } )`;
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- if (err.name === "AbortError") {
|
|
|
- return;
|
|
|
+ };
|
|
|
+ });
|
|
|
+ while (!this.jobContext.ctrl.signal.aborted && jobs.length > 0) {
|
|
|
+ const job = jobs.shift();
|
|
|
+ while (!this.jobContext.ctrl.signal.aborted) {
|
|
|
+ const pauseCtrl = new AbortController();
|
|
|
+ this.jobContext.pause = () => {
|
|
|
+ const err = new Error();
|
|
|
+ err.name = "PauseError";
|
|
|
+ pauseCtrl.abort(err);
|
|
|
+ };
|
|
|
+ try {
|
|
|
+ await job(pauseCtrl.signal);
|
|
|
+ break;
|
|
|
+ } catch (err) {
|
|
|
+ // console.error(err);
|
|
|
+ if (err.name === "StopError") {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ this.jobContext.status = "paused";
|
|
|
+ if (err.name === "PauseError") {
|
|
|
+ this.jobContext.error = `用户暂停`;
|
|
|
+ } else {
|
|
|
+ this.jobContext.error = `部分生成失败。点击按钮可继续尝试生成`;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const restartPromise = new Promise((resolve, reject) => {
|
|
|
+ this.jobContext.restart = resolve;
|
|
|
+ this.jobContext.ctrl.signal.addEventListener("abort", reject);
|
|
|
+ });
|
|
|
+ await restartPromise;
|
|
|
+ this.jobContext.status = "running";
|
|
|
+ this.jobContext.error = null;
|
|
|
+ } catch (_err) {
|
|
|
+ // nothing to do, just continue
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- console.error(err);
|
|
|
- this.$notify.error(err);
|
|
|
- } finally {
|
|
|
- this.actionTypeLoading = false;
|
|
|
- this.actionTypeLoadingText = "";
|
|
|
- this.generateActionTypesCtrl = undefined;
|
|
|
}
|
|
|
- },
|
|
|
- stopGenerateActionTypes() {
|
|
|
- console.log("stopGenerateActionTypes");
|
|
|
- this.generateActionTypesCtrl && this.generateActionTypesCtrl.abort();
|
|
|
- this.generateActionTypesCtrl = undefined;
|
|
|
+ this.jobContext = null;
|
|
|
},
|
|
|
},
|
|
|
mounted() {},
|