kopia lustrzana https://github.com/OpenDroneMap/WebODM
Progress display, refactor
rodzic
85c9df1265
commit
b16557037c
|
@ -17,7 +17,14 @@ class CheckTask(APIView):
|
|||
res = TestSafeAsyncResult(celery_task_id)
|
||||
|
||||
if not res.ready():
|
||||
return Response({'ready': False}, status=status.HTTP_200_OK)
|
||||
out = {'ready': False}
|
||||
|
||||
# Copy progress meta
|
||||
if res.state == "PROGRESS":
|
||||
for k in res.info:
|
||||
out[k] = res.info[k]
|
||||
|
||||
return Response(out, status=status.HTTP_200_OK)
|
||||
else:
|
||||
result = res.get()
|
||||
|
||||
|
@ -29,6 +36,9 @@ class CheckTask(APIView):
|
|||
msg = self.on_error(result)
|
||||
return Response({'ready': True, 'error': msg})
|
||||
|
||||
if isinstance(result.get('file'), str) and not os.path.isfile(result.get('file')):
|
||||
return Response({'ready': True, 'error': "Cannot generate file"})
|
||||
|
||||
return Response({'ready': True})
|
||||
|
||||
def on_error(self, result):
|
||||
|
|
|
@ -15,8 +15,8 @@ def run_function_async(func, *args, **kwargs):
|
|||
return eval_async.delay(source, func.__name__, *args, **kwargs)
|
||||
|
||||
|
||||
@app.task
|
||||
def eval_async(source, funcname, *args, **kwargs):
|
||||
@app.task(bind=True)
|
||||
def eval_async(self, source, funcname, *args, **kwargs):
|
||||
"""
|
||||
Run Python code asynchronously using Celery.
|
||||
It's recommended to use run_function_async instead.
|
||||
|
@ -24,4 +24,11 @@ def eval_async(source, funcname, *args, **kwargs):
|
|||
ns = {}
|
||||
code = compile(source, 'file', 'exec')
|
||||
eval(code, ns, ns)
|
||||
|
||||
if kwargs.get("with_progress"):
|
||||
def progress_callback(status, perc):
|
||||
self.update_state(state="PROGRESS", meta={"status": status, "progress": perc})
|
||||
kwargs['progress_callback'] = progress_callback
|
||||
del kwargs['with_progress']
|
||||
|
||||
return ns[funcname](*args, **kwargs)
|
|
@ -1,7 +1,8 @@
|
|||
import $ from 'jquery';
|
||||
|
||||
export default {
|
||||
waitForCompletion: (celery_task_id, cb, checkUrl = "/api/workers/check/") => {
|
||||
waitForCompletion: (celery_task_id, cb, progress_cb) => {
|
||||
const checkUrl = "/api/workers/check/";
|
||||
let errorCount = 0;
|
||||
let url = checkUrl + celery_task_id;
|
||||
|
||||
|
@ -15,6 +16,9 @@ export default {
|
|||
}else if (result.ready){
|
||||
cb();
|
||||
}else{
|
||||
if (typeof progress_cb === "function" && result.progress !== undefined && result.status !== undefined){
|
||||
progress_cb(result.status, result.progress);
|
||||
}
|
||||
// Retry
|
||||
setTimeout(() => check(), 2000);
|
||||
}
|
||||
|
|
|
@ -109,14 +109,6 @@ class TaskContoursGenerate(TaskView):
|
|||
except ContoursException as e:
|
||||
return Response({'error': str(e)}, status=status.HTTP_200_OK)
|
||||
|
||||
class TaskContoursCheck(CheckTask):
|
||||
def on_error(self, result):
|
||||
pass
|
||||
|
||||
def error_check(self, result):
|
||||
contours_file = result.get('file')
|
||||
if not contours_file or not os.path.exists(contours_file):
|
||||
return _('Could not generate contour file. This might be a bug.')
|
||||
|
||||
class TaskContoursDownload(GetTaskResult):
|
||||
pass
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from app.plugins import PluginBase
|
||||
from app.plugins import MountPoint
|
||||
from .api import TaskContoursGenerate
|
||||
from .api import TaskContoursCheck
|
||||
from .api import TaskContoursDownload
|
||||
|
||||
|
||||
|
@ -15,6 +14,5 @@ class Plugin(PluginBase):
|
|||
def api_mount_points(self):
|
||||
return [
|
||||
MountPoint('task/(?P<pk>[^/.]+)/contours/generate', TaskContoursGenerate.as_view()),
|
||||
MountPoint('task/[^/.]+/contours/check/(?P<celery_task_id>.+)', TaskContoursCheck.as_view()),
|
||||
MountPoint('task/[^/.]+/contours/download/(?P<celery_task_id>.+)', TaskContoursDownload.as_view()),
|
||||
]
|
|
@ -241,7 +241,7 @@ export default class ContoursPanel extends React.Component {
|
|||
this.setState({[loadingProp]: false});
|
||||
}
|
||||
}
|
||||
}, `/api/plugins/contours/task/${taskId}/contours/check/`);
|
||||
});
|
||||
}else if (result.error){
|
||||
this.setState({[loadingProp]: false, error: result.error});
|
||||
}else{
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
from rest_framework import serializers
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from app.api.workers import GetTaskResult, TaskResultOutputError, CheckTask
|
||||
from app.api.workers import GetTaskResult, TaskResultOutputError
|
||||
from app.models import Task
|
||||
from app.plugins.views import TaskView
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -34,9 +34,6 @@ class TaskVolume(TaskView):
|
|||
except Exception as e:
|
||||
return Response({'error': str(e)}, status=status.HTTP_200_OK)
|
||||
|
||||
class TaskVolumeCheck(CheckTask):
|
||||
pass
|
||||
|
||||
class TaskVolumeResult(GetTaskResult):
|
||||
def get(self, request, pk=None, celery_task_id=None):
|
||||
task = Task.objects.only('dsm_extent').get(pk=pk)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from app.plugins import MountPoint
|
||||
from app.plugins import PluginBase
|
||||
from .api import TaskVolume, TaskVolumeCheck, TaskVolumeResult
|
||||
from .api import TaskVolume, TaskVolumeResult
|
||||
|
||||
class Plugin(PluginBase):
|
||||
def include_js_files(self):
|
||||
|
@ -12,6 +12,5 @@ class Plugin(PluginBase):
|
|||
def api_mount_points(self):
|
||||
return [
|
||||
MountPoint('task/(?P<pk>[^/.]+)/volume$', TaskVolume.as_view()),
|
||||
MountPoint('task/[^/.]+/volume/check/(?P<celery_task_id>.+)$', TaskVolumeCheck.as_view()),
|
||||
MountPoint('task/(?P<pk>[^/.]+)/volume/get/(?P<celery_task_id>.+)$', TaskVolumeResult.as_view()),
|
||||
]
|
||||
|
|
|
@ -139,7 +139,7 @@ export default class MeasurePopup extends React.Component {
|
|||
else this.setState({volume: parseFloat(volume)});
|
||||
}, `/api/plugins/measure/task/${task.id}/volume/get/`);
|
||||
}
|
||||
}, `/api/plugins/measure/task/${task.id}/volume/check/`);
|
||||
});
|
||||
}else if (result.error){
|
||||
this.setState({error: result.error});
|
||||
}else{
|
||||
|
|
|
@ -2,11 +2,11 @@ import os
|
|||
import json
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from app.plugins.views import TaskView, CheckTask, GetTaskResult, TaskResultOutputError
|
||||
from app.plugins.views import TaskView, GetTaskResult, TaskResultOutputError
|
||||
from app.plugins.worker import run_function_async
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
def detect(orthophoto, model):
|
||||
def detect(orthophoto, model, progress_callback=None):
|
||||
import os
|
||||
from webodm import settings
|
||||
|
||||
|
@ -17,7 +17,7 @@ def detect(orthophoto, model):
|
|||
return {'error': "GeoDeep library is missing"}
|
||||
|
||||
try:
|
||||
return {'output': gdetect(orthophoto, model, output_type='geojson')}
|
||||
return {'output': gdetect(orthophoto, model, output_type='geojson', progress_callback=progress_callback)}
|
||||
except Exception as e:
|
||||
return {'error': str(e)}
|
||||
|
||||
|
@ -34,11 +34,9 @@ class TaskObjDetect(TaskView):
|
|||
if not model in ['cars', 'trees']:
|
||||
return Response({'error': 'Invalid model'}, status=status.HTTP_200_OK)
|
||||
|
||||
celery_task_id = run_function_async(detect, orthophoto, model).task_id
|
||||
return Response({'celery_task_id': celery_task_id}, status=status.HTTP_200_OK)
|
||||
celery_task_id = run_function_async(detect, orthophoto, model, with_progress=True).task_id
|
||||
|
||||
class TaskObjCheck(CheckTask):
|
||||
pass
|
||||
return Response({'celery_task_id': celery_task_id}, status=status.HTTP_200_OK)
|
||||
|
||||
class TaskObjDownload(GetTaskResult):
|
||||
def handle_output(self, output, result, **kwargs):
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from app.plugins import PluginBase
|
||||
from app.plugins import MountPoint
|
||||
from .api import TaskObjDetect
|
||||
from .api import TaskObjCheck
|
||||
from .api import TaskObjDownload
|
||||
|
||||
|
||||
|
@ -15,6 +14,5 @@ class Plugin(PluginBase):
|
|||
def api_mount_points(self):
|
||||
return [
|
||||
MountPoint('task/(?P<pk>[^/.]+)/detect', TaskObjDetect.as_view()),
|
||||
MountPoint('task/[^/.]+/check/(?P<celery_task_id>.+)', TaskObjCheck.as_view()),
|
||||
MountPoint('task/[^/.]+/download/(?P<celery_task_id>.+)', TaskObjDownload.as_view()),
|
||||
]
|
|
@ -28,6 +28,7 @@ export default class ObjDetectPanel extends React.Component {
|
|||
loading: true,
|
||||
task: props.tasks[0] || null,
|
||||
detecting: false,
|
||||
progress: null,
|
||||
objLayer: null,
|
||||
};
|
||||
}
|
||||
|
@ -124,7 +125,7 @@ export default class ObjDetectPanel extends React.Component {
|
|||
}
|
||||
|
||||
handleDetect = () => {
|
||||
this.setState({detecting: true, error: ""});
|
||||
this.setState({detecting: true, error: "", progress: null});
|
||||
const taskId = this.state.task.id;
|
||||
this.saveInputValues();
|
||||
|
||||
|
@ -153,7 +154,9 @@ export default class ObjDetectPanel extends React.Component {
|
|||
}
|
||||
});
|
||||
}
|
||||
}, `/api/plugins/objdetect/task/${taskId}/check/`);
|
||||
}, (_, progress) => {
|
||||
this.setState({progress});
|
||||
});
|
||||
}else if (result.error){
|
||||
this.setState({detecting: false, error: result.error});
|
||||
}else{
|
||||
|
@ -169,7 +172,7 @@ export default class ObjDetectPanel extends React.Component {
|
|||
}
|
||||
|
||||
render(){
|
||||
const { loading, permanentError, objLayer, detecting, model } = this.state;
|
||||
const { loading, permanentError, objLayer, detecting, model, progress } = this.state;
|
||||
const models = [
|
||||
{label: _('Cars'), value: 'cars'},
|
||||
{label: _('Trees'), value: 'trees'},
|
||||
|
@ -189,7 +192,7 @@ export default class ObjDetectPanel extends React.Component {
|
|||
</select>
|
||||
<button onClick={this.handleDetect}
|
||||
disabled={detecting} type="button" className="btn btn-sm btn-primary btn-detect">
|
||||
{detecting ? <i className="fa fa-spin fa-circle-notch"/> : <i className="fa fa-search fa-fw"/>} {_("Detect")}
|
||||
{detecting ? <i className="fa fa-spin fa-circle-notch"/> : <i className="fa fa-search fa-fw"/>} {_("Detect")} {detecting && progress !== null ? ` (${progress.toFixed(0)}%)` : ""}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue