Skip to content

Commit

Permalink
feat: get all runs at once
Browse files Browse the repository at this point in the history
  • Loading branch information
paulpestov committed Nov 30, 2023
1 parent 364c2d6 commit dd9a4ae
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 109 deletions.
10 changes: 10 additions & 0 deletions src/assets/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,13 @@ h3 {
.p-badge {
background: theme('colors.gray.300');
}

.p-buttonset .p-button:first-of-type:not(:only-of-type) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}

.p-buttonset .p-button:last-of-type:not(:only-of-type) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
65 changes: 25 additions & 40 deletions src/components/Workflows.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
import WorkflowsTable from "@/components/workflows/WorkflowsTable.vue"
import { useI18n } from "vue-i18n"
import { mapGtId, setEvalColors } from "@/helpers/utils"
import { store } from "@/helpers/store"
import Filters from "@/components/workflows/filters/Filters.vue"
import SelectButton from "primevue/selectbutton"
import WorkflowsTimeline from "@/components/workflows/WorkflowsTimeline.vue"
import filtersStore from "@/store/filters-store"
import workflowsStore from "@/store/workflows-store"
const { t } = useI18n()
const data = ref([])
const filteredData = ref([])
const defs = ref({})
const router = useRouter()
const route = useRoute()
const loading = ref(false)
const options = ref([
{ name: t('timeline'), value: 'timeline' },
Expand All @@ -37,54 +37,39 @@
onMounted(async () => {
await router.isReady()
const filtered = options.value.filter((option) => {
loading.value = true
const option = options.value.find((option) => {
return route.query.view && route.query.view === option.value
})
selectedOption.value = filtered.length > 0 ? filtered[0] : options.value[0]
let gtList = store.gtList
if (!gtList.length) {
gtList = await api.getGroundTruth()
store.setGTList(gtList)
}
let workflows = store.workflows
if (!workflows.length) {
workflows = await api.getWorkflows()
store.setWorkflows(workflows)
}
const runs = []
for await (let gt of gtList) {
try {
const latestRuns = await api.getLatestRuns(gt.id,)
if (latestRuns.length > 0) {
runs.push(...latestRuns)
}
} catch (e) {
}
if (option) {
selectedOption.value = option
}
data.value = runs
defs.value = await api.getEvalDefinitions()
workflowsStore.runs = await api.getRuns()
workflowsStore.gt = await api.getGroundTruth()
workflowsStore.workflows = await api.getWorkflows()
filteredData.value = data.value
loading.value = false
setEvalColors(data.value)
setEvalColors(workflowsStore.runs)
})
</script>
<template>
<div class="flex mb-3">
<SelectButton v-model="selectedOption" :options="options" optionLabel="name"></SelectButton>
</div>
<div><Filters /></div>
<div v-if="selectedOption">
<WorkflowsTimeline v-if="selectedOption.value === 'timeline'" />
<WorkflowsTable v-else :data="filteredData" :defs="defs" />
</div>
<template v-if="loading">
Loading...
</template>
<template v-else>
<div class="flex mb-3">
<SelectButton v-model="selectedOption" :options="options" optionLabel="name"></SelectButton>
<Filters class="ml-auto w-1/3"/>
</div>
<div v-if="selectedOption">
<WorkflowsTimeline v-if="selectedOption.value === 'timeline'" />
<WorkflowsTable v-else />
</div>
</template>
</template>

<style scoped>
Expand Down
73 changes: 50 additions & 23 deletions src/components/workflows/WorkflowsTable.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<script setup lang="ts">
import { watch, ref } from "vue"
import { watch, ref, onMounted, computed } from "vue"
import { useI18n } from "vue-i18n"
import { createReadableMetricValue, getEvalColor, mapGtId } from "@/helpers/utils"
import type { EvaluationRun } from "@/types"
import Dropdown from 'primevue/dropdown'
import workflowsStore from "@/store/workflows-store"
import api from "@/helpers/api"
import filtersStore from "@/store/filters-store"
const { t } = useI18n()
const props = defineProps<{
data: EvaluationRun[]
defs: any,
}>()
const groupedData = ref({})
const evals = ref([])
Expand All @@ -22,21 +22,47 @@ const sortOptions = ref([{
}])
const sortBy = ref(sortOptions.value[0])
const latestRuns = ref<EvaluationRun[]>([])
const filteredRuns = ref<EvaluationRun[]>([])
const evalDefinitions = ref([])
const loading = ref(false)
onMounted(async () => {
loading.value = true
latestRuns.value = workflowsStore.getLatestRuns()
evalDefinitions.value = await api.getEvalDefinitions()
setFilteredRuns()
groupRuns(sortBy.value.value)
loading.value = false
})
watch(sortBy, ({ value }) => {
if (value === 'workflows') groupByWorkflows()
else if (value === 'documents') groupByDocuments()
watch(() => filtersStore.gt, () => {
setFilteredRuns()
groupRuns(sortBy.value.value)
})
watch(sortBy, () => {
groupRuns(sortBy.value.value)
})
function setFilteredRuns() {
filteredRuns.value = latestRuns.value.filter(({ metadata }) => filtersStore.gt.findIndex(({ value }) => value === mapGtId(metadata.gt_workspace.id)) > -1)
}
function groupRuns(groupBy: string) {
if (groupBy === 'workflows') groupByWorkflows()
else if (groupBy === 'documents') groupByDocuments()
}
const groupByWorkflows = () => {
groupedData.value = props.data.filter(item => !!(item.metadata.ocr_workflow)).reduce((acc, cur) => {
groupedData.value = filteredRuns.value.filter(item => !!(item.metadata.ocr_workflow)).reduce((acc, cur) => {
const ocrWorkflowId = mapGtId(cur.metadata.ocr_workflow['id'])
const label = cur.metadata.ocr_workflow.label
const label = workflowsStore.getWorkflowById(ocrWorkflowId)?.label
evals.value = Object.keys(cur.evaluation_results.document_wide)
const subject = {
label: cur.metadata.gt_workspace.label,
label: workflowsStore.getGtById(mapGtId(cur.metadata.gt_workspace.id))?.label,
evaluations: Object.keys(cur.evaluation_results.document_wide).map(key => ({
name: key,
value: cur.evaluation_results.document_wide[key]
Expand All @@ -59,12 +85,12 @@ const groupByWorkflows = () => {
}
const groupByDocuments = () => {
groupedData.value = props.data.filter(item => !!(item.metadata.gt_workspace)).reduce((acc, cur) => {
groupedData.value = filteredRuns.value.filter(item => !!(item.metadata.gt_workspace)).reduce((acc, cur) => {
const gtWorkspaceId = mapGtId(cur.metadata.gt_workspace['id'])
const label = cur.metadata.gt_workspace.label
const label = workflowsStore.getGtById(gtWorkspaceId)?.label
evals.value = Object.keys(cur.evaluation_results.document_wide)
const subject = {
label: cur.metadata.ocr_workflow.label,
label: workflowsStore.getWorkflowById(mapGtId(cur.metadata.ocr_workflow['id']))?.label,
evaluations: Object.keys(cur.evaluation_results.document_wide).map(key => ({
name: key,
value: cur.evaluation_results.document_wide[key]
Expand All @@ -85,31 +111,32 @@ const groupByDocuments = () => {
return acc
}, {})
}
watch(() => props.data, groupByDocuments, { immediate: true })
</script>

<template>
<div>
<template v-if="loading">
Loading...
</template>
<template v-else>
<div class="flex mb-4" v-if="evals.length > 0">
<div class="flex items-center ml-auto">
<p class="mr-2">{{ $t('group_by') }}:</p>
<Dropdown v-model="sortBy" :options="sortOptions" optionLabel="label" placeholder="Choose something.." class="" />
</div>
</div>
<table v-if="evals.length > 0" class="w-full border border-collapse text-sm">
<table v-if="evals.length > 0" class="w-full border border-collapse rounded text-sm">
<thead>
<tr>
<th class="p-2 border">{{ sortBy.value === 'documents' ? $t('documents') : $t('workflows') }}</th>
<th class="p-2 border">{{ sortBy.value === 'documents' ? $t('workflows') : $t('documents') }}</th>
<th v-for="(evalKey, i) in evals" :key="i" class="p-2 border">
<span class="def-label flex items-center justify-center cursor-pointer">
{{ defs[evalKey] ? defs[evalKey].label : evalKey }}
{{ evalDefinitions[evalKey] ? evalDefinitions[evalKey].label : evalKey }}
<i-icon name="ink-info"/>
<div class="def-tooltip">
<div class="flex p-2 bg-white border rounded">
{{ defs[evalKey] ? defs[evalKey].short_descr : $t('no_description') }}.
<a v-if="defs[evalKey]" :href="defs[evalKey].url">{{ $t('details') }}</a>
{{ evalDefinitions[evalKey] ? evalDefinitions[evalKey].short_descr : $t('no_description') }}.
<a v-if="evalDefinitions[evalKey]" :href="evalDefinitions[evalKey].url">{{ $t('details') }}</a>
</div>
</div>
</span>
Expand All @@ -119,7 +146,7 @@ watch(() => props.data, groupByDocuments, { immediate: true })
<tbody>
<template v-for="(key, i) in Object.keys(groupedData)" :key="i">
<tr v-for="(subject, j) in groupedData[key].subjects" :key="j">
<td v-if="j === 0" :rowspan="groupedData[key].subjects.length" class="align-top pl-2 border">
<td v-if="j === 0" :rowspan="groupedData[key].subjects.length" class="align-top pl-2 border w-1/3">
<span class="font-bold">{{ groupedData[key].label }}</span>
</td>
<td class="align-top pl-2 border">{{ subject.label }}</td>
Expand All @@ -140,7 +167,7 @@ watch(() => props.data, groupByDocuments, { immediate: true })
</tbody>
</table>
<div v-else>{{ $t('no_table_data') }}</div>
</div>
</template>
</template>

<style scoped lang="scss">
Expand Down
27 changes: 12 additions & 15 deletions src/components/workflows/WorkflowsTimeline.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script setup lang="ts">
import api from '@/helpers/api'
import TimelineItem from "@/components/workflows/timeline/TimelineItem.vue"
import Dropdown from 'primevue/dropdown'
import { computed, onMounted, ref } from "vue"
import { EvaluationMetrics } from '@/helpers/metrics'
import {computed, onMounted, ref, watch} from "vue"
import {EvaluationMetrics, getMaxValueByMetric} from '@/helpers/metrics'
import { useI18n } from "vue-i18n"
import type {DropdownOption, EvaluationResultsDocumentWide, Workflow} from "@/types"
import { DropdownPassThroughStyles } from '@/helpers/pt'
import workflowsStore from '@/store/workflows-store'
import filtersStore from '@/store/filters-store'
import timelineStore from "@/store/timeline-store"
const { t } = useI18n()
const gtList = computed(() => workflowsStore.gt.filter(({ id }) => filtersStore.gt.findIndex(({ value }) => value === id) > -1))
Expand All @@ -19,19 +19,16 @@ const selectedMetricValue = computed<keyof EvaluationResultsDocumentWide>(() =>
onMounted(async () => {
selectedMetric.value = metrics.value[0]
if (!gtList.value.length) {
workflowsStore.gt = await api.getGroundTruth()
filtersStore.gt = workflowsStore.gt.map(({ id, label }) => ({ value: id, label }))
}
workflows.value = workflowsStore.workflows
if (!workflows.value.length) {
workflows.value = await api.getWorkflows()
workflowsStore.workflows = workflows.value
}
})
watch(selectedMetric,
() => timelineStore.setMaxValue(
selectedMetricValue.value,
getMaxValueByMetric(selectedMetricValue.value, workflowsStore.runs)
),
{ immediate: true }
)
</script>

<template>
Expand All @@ -49,7 +46,7 @@ onMounted(async () => {
</div>
<div class="flex flex-col space-y-4">
<template v-if="gtList.length > 0">
<TimelineItem v-for="gt in gtList" :key="gt.id" :gt="gt" :workflows="workflows" :metric="selectedMetricValue" />
<TimelineItem v-for="gt in gtList" :key="gt.id" :gt="gt" :metric="selectedMetricValue" />
</template>
<template v-else>
<div class="my-6">An error has occurred. Please try again later!</div>
Expand Down
5 changes: 3 additions & 2 deletions src/components/workflows/filters/Filters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ onMounted(() => {
:options="gtOptions"
optionLabel="label"
placeholder="Select Ground Truth"
panel-class="max-w-[400px]"
max-selected-labels="3"
panel-class="max-w-[500px]"
max-selected-labels="1"
filter
class="relative"
>
<template #option="{ option }: { option: FilterOption }">
Expand Down
8 changes: 3 additions & 5 deletions src/components/workflows/timeline/MetricAverageChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import timelineStore from "@/store/timeline-store";
const { t } = useI18n()
const props = defineProps<{
gtId: string,
runs: EvaluationRun[],
metric: keyof EvaluationResultsDocumentWide,
startDate: Date,
endDate: Date
Expand All @@ -24,16 +24,14 @@ const runs = ref<EvaluationRun[]>([])
const op = ref<OverlayPanel | null>(null)
onMounted(async () => {
const { gtId } = props
runs.value = await api.getRuns(gtId)
init()
})
watch(() => props.metric, init)
function init() {
if (!runs.value) return
data.value = getTimelineData(runs.value, props.metric)
if (!props.runs) return
data.value = getTimelineData(props.runs, props.metric)
}
function getTimelineData(runs: EvaluationRun[], metric: string): TimelineChartDataPoint[] {
Expand Down
Loading

0 comments on commit dd9a4ae

Please sign in to comment.