Merge pull request #110 from SDSRV-IDP/refactor/review-filter

[refactor] review filter and add max accuray
This commit is contained in:
Đỗ Xuân Tân 2024-04-25 14:24:27 +07:00 committed by GitHub Enterprise
commit e4a4d5e38d
6 changed files with 267 additions and 179 deletions

View File

@ -12,6 +12,7 @@
"English": "English",
"Go to Reports": "Go to Reports",
"Handwritten": "Handwritten",
"Improve OCR": "Improve OCR",
"Inference": "Inference",
"Invalid image": "Invalid image",
"Is Test": "Is Test",
@ -20,7 +21,9 @@
"Logout": "Logout",
"Missing information": "Missing information",
"New Report": "New Report",
"Ocr cannot extract": "Ocr cannot extract",
"Only characters (a-z), (A-Z), (0-9), @, ., +, -, _ are available": "Only characters (a-z), (A-Z), (0-9), @, ., +, -, _ are available",
"Other": "Other",
"Password": "Password",
"Password must have at least 1 lowercase alphabetical character": "Password must have at least 1 lowercase alphabetical character",
"Password must have at least 1 numeric characters": "Password must have at least 1 numeric characters",
@ -33,6 +36,7 @@
"Please specify a username": "Please specify a username",
"Reason for bad quality:": "Reason for bad quality:",
"Recheck": "Recheck",
"Remove this image from the evaluation report": "Remove this image from the evaluation report",
"Report Details": "Report Details",
"Report Filters": "Report Filters",
"Report Type": "Report Type",
@ -41,6 +45,7 @@
"Review": "Review",
"Reviewed": "Reviewed",
"Service temporarily unavailable.": "Service temporarily unavailable.",
"Solution:": "Solution:",
"Something went wrong.": "Something went wrong.",
"Sorry, something went wrong.": "Sorry, something went wrong.",
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
@ -51,15 +56,18 @@
"This field must not have more than {MAX_USERNAME_LENGTH} characters": "This field must not have more than {MAX_USERNAME_LENGTH} characters",
"Too blurry text": "Too blurry text",
"Too small text": "Too small text",
"Update revised result and re-calculate accuracy": "Update revised result and re-calculate accuracy",
"User log in successfully": "User log in successfully",
"Username": "Username",
"Username must not have more than {MAX_USERNAME_LENGTH} characters": "Username must not have more than {MAX_USERNAME_LENGTH} characters",
"Vietnamese": "Vietnamese",
"Wrong Feedback": "Wrong Feedback",
"You are not allowed to upload file bigger than {0}MB.": "You are not allowed to upload file bigger than {0}MB.",
"You are not allowed to upload image bigger than {0}MB.": "You are not allowed to upload image bigger than {0}MB.",
"You are only allowed to upload .zip file.": "You are only allowed to upload .zip file.",
"You are only allowed to upload image or .zip files.": "You are only allowed to upload image or .zip files.",
"You are only allowed to upload {0} file.": "You are only allowed to upload {0} file.",
"You have unsaved changes!": "You have unsaved changes!",
"Your current password has expired. Please change your password to continue.": "Your current password has expired. Please change your password to continue."
"Your current password has expired. Please change your password to continue.": "Your current password has expired. Please change your password to continue.",
"max_accuracy": "Max accuracy"
}

View File

@ -12,6 +12,7 @@
"English": "Tiếng Anh",
"Go to Reports": "",
"Handwritten": "",
"Improve OCR": "",
"Inference": "",
"Invalid image": "",
"Is Test": "",
@ -20,7 +21,9 @@
"Logout": "Đăng xuất",
"Missing information": "",
"New Report": "",
"Ocr cannot extract": "",
"Only characters (a-z), (A-Z), (0-9), @, ., +, -, _ are available": "Chỉ cho phép các ký tự (a-z), (A-Z), (0-9), @, ., +, -, _",
"Other": "",
"Password": "Mật khẩu",
"Password must have at least 1 lowercase alphabetical character": "Mật khẩu phải chứa ít nhất một chữ cái in thường",
"Password must have at least 1 numeric characters": "Mật khẩu phải chứa ít nhất một chữ số",
@ -33,6 +36,7 @@
"Please specify a username": "Vui lòng nhập một tên tài khoản",
"Reason for bad quality:": "",
"Recheck": "",
"Remove this image from the evaluation report": "",
"Report Details": "",
"Report Filters": "",
"Report Type": "",
@ -41,6 +45,7 @@
"Review": "",
"Reviewed": "",
"Service temporarily unavailable.": "Dịch vụ máy chủ hiện tại không sẵn sàng.",
"Solution:": "",
"Something went wrong.": "Có lỗi xảy ra",
"Sorry, something went wrong.": "Hệ thống gặp lỗi",
"Sorry, the page you visited does not exist.": "Trang bạn muốn truy cập không tồn tại",
@ -51,15 +56,18 @@
"This field must not have more than {MAX_USERNAME_LENGTH} characters": "Độ dài chuỗi không được vượt quá {MAX_USERNAME_LENGTH} kí tự",
"Too blurry text": "",
"Too small text": "",
"Update revised result and re-calculate accuracy": "",
"User log in successfully": "Đăng nhập thành công",
"Username": "Tên tài khoản",
"Username must not have more than {MAX_USERNAME_LENGTH} characters": "Tên tài khoản không được chứa nhiều hơn {MAX_USERNAME_LENGTH} kí tự",
"Vietnamese": "Tiếng Việt",
"Wrong Feedback": "",
"You are not allowed to upload file bigger than {0}MB.": "Bạn không được phép tải lên tệp lớn hơn {0} MB.",
"You are not allowed to upload image bigger than {0}MB.": "Bạn không được phép tải lên hình ảnh lớn hơn {0} MB.",
"You are only allowed to upload .zip file.": "Bạn chỉ được phép tải lên tập tin .zip.",
"You are only allowed to upload image or .zip files.": "Bạn chỉ được phép tải lên hình ảnh hoặc .zip.",
"You are only allowed to upload {0} file.": "Bạn chỉ được phép tải lên {0}.",
"You have unsaved changes!": "Bạn có những thay đổi chưa được lưu!",
"Your current password has expired. Please change your password to continue.": ""
"Your current password has expired. Please change your password to continue.": "",
"max_accuracy": "Độ chính xác tối đa"
}

View File

@ -0,0 +1,83 @@
import { DownloadOutlined } from "@ant-design/icons";
import { Button } from "antd";
const FileCard = ({ file, isSelected, onClick, setIsReasonModalOpen }) => {
const fileName = file['File Name'];
return (
<div
style={{
border: '1px solid #ccc',
width: '200px',
backgroundColor: isSelected ? '#d4ecff' : '#fff',
padding: '4px 8px',
marginRight: '4px',
marginTop: '2px',
position: 'relative',
height: '100px',
overflow: 'hidden',
}}
onClick={onClick}
>
<div>
<span
style={{
fontSize: '12px',
color: '#333',
fontWeight: 'bold',
padding: '4px 8px',
cursor: 'default',
}}
>
{file['Doc Type'].toUpperCase()}
</span>
<span
style={{
fontSize: '12px',
color: '#aaa',
fontWeight: 'bold',
padding: '4px 8px',
cursor: 'default',
maxWidth: '50px',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{fileName ? fileName.substring(0, 25).replace('temp_', '') : fileName}
</span>
</div>
<div
style={{
padding: '4px',
position: 'absolute',
bottom: 2,
right: 2,
}}
>
<Button
style={{
margin: '4px 2px',
}}
onClick={() => {
setIsReasonModalOpen(true);
}}
>
Review
</Button>
<Button
style={{
margin: '4px 2px',
}}
onClick={() => {
const downloadUrl = file['File URL'];
window.open(downloadUrl, '_blank');
}}
>
<DownloadOutlined />
</Button>
</div>
</div>
);
};
export default FileCard;

View File

@ -0,0 +1,79 @@
import { baseURL } from 'request/api';
export const fetchAllRequests = async (
filterDateRange,
filterSubsidiaries,
filterReviewState,
filterIncludeTests,
page = 1,
page_size = 20,
max_accuracy = 100
) => {
const startDate =
filterDateRange && filterDateRange[0] ? filterDateRange[0] : '';
const endDate =
filterDateRange && filterDateRange[1] ? filterDateRange[1] : '';
let filterStr = '';
filterStr += `page=${page}&page_size=${page_size}&`;
if (filterSubsidiaries) {
filterStr += `subsidiary=${filterSubsidiaries}&`;
}
if (filterReviewState) {
filterStr += `is_reviewed=${filterReviewState}&`;
}
if (filterIncludeTests) {
filterStr += `includes_test=${filterIncludeTests}&`;
}
if (startDate && endDate) {
filterStr += `start_date=${startDate}&end_date=${endDate}&`;
}
filterStr += `max_accuracy=${max_accuracy}`
const token = localStorage.getItem('sbt-token') || '';
const data = await fetch(`${baseURL}/ctel/request_list/?${filterStr}`, {
method: 'GET',
headers: {
Authorization: `${JSON.parse(token)}`,
},
}).then(async (res) => {
const data = await res.json();
return data;
});
return data;
};
export const updateRevisedData = async (
requestID: any,
newRevisedData: any,
) => {
// const requestID = ;
const token = localStorage.getItem('sbt-token') || '';
const result = await fetch(`${baseURL}/ctel/request/${requestID}/`, {
method: 'POST',
headers: {
Authorization: `${JSON.parse(token)}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
reviewed_result: newRevisedData,
}),
}).catch((error) => {
console.log(error);
throw error;
});
if (result.status != 200) {
throw new Error('Could not update revised data');
}
};
export const fetchRequest = async (id) => {
const token = localStorage.getItem('sbt-token') || '';
const response = await fetch(`${baseURL}/ctel/request/${id}/`, {
method: 'GET',
headers: {
Authorization: `${JSON.parse(token)}`,
},
});
return await (
await response.json()
).subscription_requests[0];
};

View File

@ -3,17 +3,18 @@ import {
ArrowRightOutlined,
CheckCircleOutlined,
ClockCircleFilled,
DownloadOutlined,
FullscreenExitOutlined,
FullscreenOutlined,
} from '@ant-design/icons';
import { t } from '@lingui/macro';
import { Viewer } from '@react-pdf-viewer/core';
import type { GetRef } from 'antd';
import {
Button,
DatePicker,
Form,
Input,
InputNumber,
Layout,
message,
Modal,
@ -28,15 +29,15 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { baseURL } from 'request/api';
import styled from 'styled-components';
// Import the main component
import { Viewer } from '@react-pdf-viewer/core';
// Import the styles
import '@react-pdf-viewer/core/lib/styles/index.css';
import { badQualityReasonSubmit } from 'request';
import { normalizeData } from 'utils/field-value-process';
import { fetchAllRequests, fetchRequest } from './api';
import { counter_measure_map } from './consts';
import FileCard from './FileCard';
const { Sider, Content } = Layout;
const siderStyle: React.CSSProperties = {
@ -146,137 +147,6 @@ const EditableCell: React.FC<EditableCellProps> = ({
// type EditableTableProps = Parameters<typeof Table>[0];
const FileCard = ({ file, isSelected, onClick, setIsReasonModalOpen }) => {
const fileName = file['File Name'];
return (
<div
style={{
border: '1px solid #ccc',
width: '200px',
backgroundColor: isSelected ? '#d4ecff' : '#fff',
padding: '4px 8px',
marginRight: '4px',
marginTop: '2px',
position: 'relative',
height: '100px',
overflow: 'hidden',
}}
onClick={onClick}
>
<div>
<span
style={{
fontSize: '12px',
color: '#333',
fontWeight: 'bold',
padding: '4px 8px',
cursor: 'default',
}}
>
{file['Doc Type'].toUpperCase()}
</span>
<span
style={{
fontSize: '12px',
color: '#aaa',
fontWeight: 'bold',
padding: '4px 8px',
cursor: 'default',
maxWidth: '50px',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{fileName ? fileName.substring(0, 25).replace('temp_', '') : fileName}
</span>
</div>
<div
style={{
padding: '4px',
position: 'absolute',
bottom: 2,
right: 2,
}}
>
<Button
style={{
margin: '4px 2px',
}}
onClick={() => {
setIsReasonModalOpen(true);
}}
>
Review
</Button>
<Button
style={{
margin: '4px 2px',
}}
onClick={() => {
const downloadUrl = file['File URL'];
window.open(downloadUrl, '_blank');
}}
>
<DownloadOutlined />
</Button>
</div>
</div>
);
};
const fetchAllRequests = async (
filterDateRange,
filterSubsidiaries,
filterReviewState,
filterIncludeTests,
page = 1,
page_size = 20,
) => {
const startDate =
filterDateRange && filterDateRange[0] ? filterDateRange[0] : '';
const endDate =
filterDateRange && filterDateRange[1] ? filterDateRange[1] : '';
let filterStr = '';
filterStr += `page=${page}&page_size=${page_size}&`;
if (filterSubsidiaries) {
filterStr += `subsidiary=${filterSubsidiaries}&`;
}
if (filterReviewState) {
filterStr += `is_reviewed=${filterReviewState}&`;
}
if (filterIncludeTests) {
filterStr += `includes_test=${filterIncludeTests}&`;
}
if (startDate && endDate) {
filterStr += `start_date=${startDate}&end_date=${endDate}&`;
}
const token = localStorage.getItem('sbt-token') || '';
const data = await fetch(`${baseURL}/ctel/request_list/?${filterStr}`, {
method: 'GET',
headers: {
Authorization: `${JSON.parse(token)}`,
},
}).then(async (res) => {
const data = await res.json();
return data;
});
return data;
};
const fetchRequest = async (id) => {
const token = localStorage.getItem('sbt-token') || '';
const response = await fetch(`${baseURL}/ctel/request/${id}/`, {
method: 'GET',
headers: {
Authorization: `${JSON.parse(token)}`,
},
});
return await (
await response.json()
).subscription_requests[0];
};
const ReviewPage = () => {
const [loading, setLoading] = useState(false);
const [fullscreen, setFullscreen] = useState(false);
@ -290,9 +160,10 @@ const ReviewPage = () => {
const [filterDateRange, setFilterDateRange] = useState(['', '']);
const [filterSubsidiaries, setFilterSubsidiaries] = useState('SEAO');
const [filterAccuracy, setFilterAccuracy] = useState(100);
const [filterReviewState, setFilterReviewState] = useState('all');
const [filterIncludeTests, setFilterIncludesTests] = useState('true');
const [requests, setRequests] = useState([]);
// const [requests, setRequests] = useState([]);
const [currentRequest, setCurrentRequest] = useState(null);
const [currentRequestIndex, setCurrentRequestIndex] = useState(1);
const [hasNextRequest, setHasNextRequest] = useState(true);
@ -339,17 +210,20 @@ const ReviewPage = () => {
filterReviewState,
filterIncludeTests,
requestIndex,
2,
1,
filterAccuracy
)
.then((data) => {
setRequests(data?.subscription_requests);
setHasNextRequest(data?.subscription_requests.length > 1);
// setRequests(data?.subscription_requests);
// setHasNextRequest(data?.subscription_requests.length > 1);
setTotalPages(data?.page?.total_requests);
setHasNextRequest(requestIndex < data?.page?.total_requests);
const requestData = fetchRequest(
data?.subscription_requests[0].RequestID,
);
requestData
.then(async (data) => {
console.log('🚀 ~ .then ~ data:', data);
if (data) setCurrentRequest(data);
const predicted =
data && data['Predicted Result'] ? data['Predicted Result'] : {};
@ -406,11 +280,13 @@ const ReviewPage = () => {
filterReviewState,
filterIncludeTests,
1,
2,
1,
filterAccuracy
).then((data) => {
setTotalPages(data?.page?.total_requests);
setRequests(data?.subscription_requests);
setHasNextRequest(data?.subscription_requests.length > 1);
// setRequests(data?.subscription_requests);
// setHasNextRequest(data?.subscription_requests.length > 1);
setHasNextRequest(1 < data?.page?.total_requests);
const firstRequest = fetchRequest(
data?.subscription_requests[0].RequestID,
);
@ -432,11 +308,12 @@ const ReviewPage = () => {
filterReviewState,
filterIncludeTests,
1,
2,
1,
filterAccuracy
).then((data) => {
setTotalPages(data?.page?.total_requests);
setRequests(data?.subscription_requests);
setHasNextRequest(data?.subscription_requests.length > 1);
// setRequests(data?.subscription_requests);
setHasNextRequest(1 < data?.page?.total_requests);
const firstRequest = fetchRequest(
data?.subscription_requests[0].RequestID,
);
@ -969,6 +846,13 @@ const ReviewPage = () => {
: ''
}
/>
<Input
size='small'
addonBefore='Raw accuracy'
style={{ marginBottom: '4px' }}
readOnly
value={currentRequest ? currentRequest['raw_accuracy'] : ''}
/>
<div
style={{
marginBottom: '8px',
@ -1026,7 +910,7 @@ const ReviewPage = () => {
},
]}
style={{
marginBottom: 10,
marginBottom: 24,
}}
>
<DatePicker.RangePicker
@ -1036,6 +920,16 @@ const ReviewPage = () => {
style={{ width: 200 }}
/>
</Form.Item>
<div
style={{
marginTop: 10,
display: 'flex',
justifyContent: 'space-between',
marginLeft: 0,
padding: 0,
}}
>
<Form.Item
name='subsidiary'
label={t`Subsidiary`}
@ -1045,9 +939,6 @@ const ReviewPage = () => {
message: 'Please select a subsidiary',
},
]}
style={{
marginBottom: 10,
}}
>
<Select
placeholder='Select a subsidiary'
@ -1066,10 +957,29 @@ const ReviewPage = () => {
onChange={setFilterSubsidiaries}
/>
</Form.Item>
<Form.Item
name='max_accuracy'
label={t`max_accuracy` + ' (1-100)'}
rules={[
{
required: true,
message: 'Please select max accuracy',
},
]}
>
<InputNumber
min={1}
max={100}
defaultValue={filterAccuracy}
onChange={(value) => setFilterAccuracy(value)}
/>
</Form.Item>
</div>
<div
style={{
marginTop: 10,
display: 'flex',
justifyContent: 'space-between',
marginLeft: 0,
padding: 0,
}}

View File

@ -11,8 +11,8 @@ const environment = process.env.NODE_ENV;
const AXIOS_TIMEOUT_MS = 30 * 60 * 1000; // This config sastified long-live upload file request
const EXPIRED_PASSWORD_SIGNAL = 'expired_password';
// export const baseURL = environment === 'development' ? 'http://42.96.42.13:9881/api' : '/api';
export const baseURL = '/api';
export const baseURL = environment === 'development' ? 'http://107.120.133.27:9881/api' : '/api';
// export const baseURL = '/api';
export const API = axios.create({