곰믹스 소스코드 수정
This commit is contained in:
189
psdExport_2.js
189
psdExport_2.js
@@ -15,15 +15,15 @@ const examRound = '2505';
|
||||
const dic_or_dpi = 'DIC'
|
||||
// const dic_or_dpi = 'DPI'
|
||||
const examTypes = [
|
||||
// 'A',
|
||||
'B',
|
||||
'C',
|
||||
'A',
|
||||
// 'B',
|
||||
// 'C',
|
||||
// 'D'
|
||||
];
|
||||
|
||||
// testMode가 true일 경우 TEST 폴더에 있는 답안 파일을 읽어옴
|
||||
// const testMode = true;
|
||||
const testMode = false;
|
||||
// const testMode = false;
|
||||
const testMode = true;
|
||||
|
||||
const outputExcelFiles = [];
|
||||
|
||||
@@ -39,7 +39,6 @@ examTypes.forEach(type => {
|
||||
// let outputExcelFile = `./${todayDate}_DIC_${examRound}${type}_채점결과.xlsx`;
|
||||
// if (testMode) {
|
||||
// outputExcelFile = `./00_DIC_${examRound}${type}_TEST.xlsx`;
|
||||
// }
|
||||
|
||||
|
||||
// 답안 폴더 내부에 디렉토리가 아닌 일반 파일이 있을 경우 디렉토리만 필터링 해서 불러옴
|
||||
@@ -81,7 +80,9 @@ examTypes.forEach(type => {
|
||||
|
||||
psdFiles.forEach((psdFile, index) => {
|
||||
const psdPath = path.join('./', studentDir, psdFile);
|
||||
console.log(`Reading ${psdPath}...`);
|
||||
|
||||
console.log('');
|
||||
console.log(`➡️ Reading ${psdPath}...`);
|
||||
try {
|
||||
const psdFileData = psd.fromFile(psdPath);
|
||||
psdFileData.parse();
|
||||
@@ -116,7 +117,9 @@ examTypes.forEach(type => {
|
||||
else {
|
||||
gmepFile.forEach((gmep, index) => {
|
||||
const gmepPath = path.join('./', studentDir, gmep);
|
||||
console.log(`Reading ${gmepPath}...`);
|
||||
|
||||
console.log('');
|
||||
console.log(`➡️ Reading ${gmepPath}...`);
|
||||
|
||||
const xmlString = fs.readFileSync(gmepPath, 'utf8');
|
||||
// XML 문자열을 파싱하여 XML 문서 객체로 변환
|
||||
@@ -169,6 +172,30 @@ outputExcelFiles.forEach((outputFile, index) => {
|
||||
// scoring.json 파일 내에 있는 type에 따라 비교하는 방식이 달라짐
|
||||
// 채점 결과를 scoringResultList 배열에 저장
|
||||
function getGmepScore(gmepData, scoringJson, index) {
|
||||
|
||||
function compareAndScore(userAnswer, rightAnswer, point, key, scoringResult) {
|
||||
let score = 0;
|
||||
|
||||
const isEqual = (typeof rightAnswer === "object" && typeof userAnswer === "object")
|
||||
? JSON.stringify(userAnswer) === JSON.stringify(rightAnswer)
|
||||
: userAnswer == rightAnswer;
|
||||
|
||||
if (isEqual) {
|
||||
score = point;
|
||||
console.log('작성답안: ', userAnswer);
|
||||
console.log('>⭕ 정답: ', rightAnswer);
|
||||
} else {
|
||||
console.log('작성답안: ', userAnswer);
|
||||
console.log('>❌ 오답: ', rightAnswer);
|
||||
}
|
||||
|
||||
scoringResult[key] = score;
|
||||
return score;
|
||||
}
|
||||
function getMediaOrderbyClipIndex(gmepXmlDoc, clipIndex) {
|
||||
|
||||
}
|
||||
|
||||
const gmepXmlDoc = gmepData;
|
||||
const scoringResult = {};
|
||||
|
||||
@@ -188,6 +215,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
||||
const point = scoringData[key].point;
|
||||
const type = scoringData[key].type;
|
||||
const search = scoringData[key].search;
|
||||
const media = scoringData[key].media;
|
||||
const videoStartTime = scoringData.videoStartTime;
|
||||
const openingStartTime = scoringData.openingStartTime;
|
||||
|
||||
@@ -204,14 +232,14 @@ function getGmepScore(gmepData, scoringJson, index) {
|
||||
const subtitleOrder = type === 'video' ? 2 : type === 'opening' ? 1 : null;
|
||||
const startTime = type === 'video' ? videoStartTime : type === 'opening' ? openingStartTime : null;
|
||||
|
||||
let xpathList = [ele, ele2, ele3, existEle];
|
||||
xpathList = xpathList.map(e => e?e
|
||||
let xpathList = [ele, ele2, ele3, existEle];
|
||||
xpathList = xpathList.map(e => e ? e
|
||||
.replace(/{subtitleIndex}/g, subtitleIndex)
|
||||
.replace(/{subtitleOrder}/g, subtitleOrder)
|
||||
.replace(/{startTime}/g, startTime)
|
||||
.replace(/{clipIndex}/g, clipIndex)
|
||||
.replace(/{image}/g, image)
|
||||
:e
|
||||
.replace(/{image}/g, image)
|
||||
: e
|
||||
);
|
||||
[ele, ele2, ele3, existEle] = xpathList;
|
||||
|
||||
@@ -253,92 +281,83 @@ function getGmepScore(gmepData, scoringJson, index) {
|
||||
if (type == "boolean") {
|
||||
scoringResult[key] = result.length > 0 ? point : 0;
|
||||
}
|
||||
else if (type == "array") {
|
||||
// result: Path="동영상.mp4", Path="음악.mp3", Path="이미지2.jpg", Path="이미지1.jpg"
|
||||
// value: 동영상.mp4,이미지1.jpg,이미지3.jpg,이미지2.jpg
|
||||
// result 와 value를 순서대로 비교하여 모두 같으면 점수 point 부여
|
||||
|
||||
// XPath를 사용하여 CRTrackList Name="비디오1" 요소 찾기
|
||||
const trackListNode = xpath.select1('//CRVideoTrackArr/CRTrackList[@Name="비디오1"]', gmepXmlDoc);
|
||||
const values = [];
|
||||
let isSame = true;
|
||||
else if (type == "oneAnswer") {
|
||||
const result = xpath.select1(ele, gmepXmlDoc);
|
||||
|
||||
if (trackListNode) {
|
||||
// CRTrackClip 요소의 ClipIndex를 참조하여 CRClip 요소의 Path와 Type 출력
|
||||
// @Length(클립재생길이) 5프레임 이하, @ClipLength -1인 항목은 제외
|
||||
// 10프레임은 타임라인상 눈에 잘 보여서 5프레임으로 우선 수정
|
||||
const clipIndexes = xpath.select('CRTrackClip[not(@Length<="5" and @ClipLength="-1")]/@ClipIndex'
|
||||
, trackListNode);
|
||||
clipIndexes.forEach(indexNode => {
|
||||
const clipIndex = parseInt(indexNode.value, 10) + 1; // XPath는 1-based index를 사용
|
||||
console.log(`clipIndex: ${clipIndex}`);
|
||||
if (clipIndex === 0) {
|
||||
return;
|
||||
}
|
||||
const clipPathNode = xpath.select1(`//CRClipArr/CRClip[${clipIndex}]/@Path`, gmepXmlDoc);
|
||||
const motionClipPathNode = xpath.select1(`//CRClipArr/CRClip[${clipIndex}]/CRCUnitArr/@Path`, gmepXmlDoc);
|
||||
const notUndefinedClipNode = clipPathNode ?? motionClipPathNode;
|
||||
|
||||
if (notUndefinedClipNode === undefined) {
|
||||
return;
|
||||
}
|
||||
values.push(notUndefinedClipNode.value);
|
||||
});
|
||||
// values에 값이 있는지 확인
|
||||
if (values.length == 0 || values.length < 4) {
|
||||
console.log('values length 0');
|
||||
scoringResult[key] = 0;
|
||||
continue;
|
||||
}
|
||||
values.forEach((v, i) => {
|
||||
console.log(`values: ${v} value: ${rightAnswer[i]}`);
|
||||
if (rightAnswer[i] !== v) {
|
||||
isSame = false;
|
||||
}
|
||||
});
|
||||
totalScore += isSame ? point : 0;
|
||||
scoringResult[key] = isSame ? point : 0;
|
||||
} else {
|
||||
console.log('CRTrackList with Name="비디오1" not found.');
|
||||
scoringResult[key] = 0;
|
||||
let userAnswer = {};
|
||||
if ("speed" in rightAnswer) {
|
||||
userAnswer = {
|
||||
"speed": result ? result.value : null,
|
||||
};
|
||||
}
|
||||
else {
|
||||
userAnswer = result ? result.value : null;
|
||||
}
|
||||
|
||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||
}
|
||||
else if (type == "startend") {
|
||||
console.log('type:', type);
|
||||
const start = scoringData[key].start;
|
||||
const end = scoringData[key].end;
|
||||
// XPath를 사용하여 CRClip 요소 중 Path가 '동영상.mp4'인 요소의 위치 찾기
|
||||
const clipIndexNode = xpath.select1(ele, gmepXmlDoc);
|
||||
console.log(`clipIndexNode: ${clipIndexNode}`);
|
||||
// [3-1] 문항
|
||||
|
||||
// XPath를 사용하여 해당 ClipIndex를 사용하는 CRTrackClip 요소 찾기
|
||||
const trackClipNodes = xpath.select1(`//CRTrackClip[@ClipIndex='${clipIndexNode}']`, gmepXmlDoc);
|
||||
else if (type == "mediaOrder") {
|
||||
// 미디어 순서를 저장할 배열
|
||||
const mediaOrderList = [];
|
||||
|
||||
if (!trackClipNodes) {
|
||||
// 미디어의 인덱스 순서
|
||||
const clipIndexOrder = xpath.select(ele, gmepXmlDoc);
|
||||
clipIndexOrder.forEach((clipIndex) => {
|
||||
CRClipIndex = parseInt(clipIndex.value, 10) + 1; // XPath는 1-based index를 사용
|
||||
|
||||
// 인덱스 순서에 따른 CRClip 요소의 Path를 찾기
|
||||
const mediaPath = xpath.select1(`//CRClipArr/CRClip[${CRClipIndex}]/@Path`, gmepXmlDoc);
|
||||
// 만약 CRClip 요소가 motion clip인 경우 CRCUnitArr의 Path를 찾기
|
||||
if (mediaPath == null) {
|
||||
const motionClipPath = xpath.select1(`//CRClipArr/CRClip[${CRClipIndex}]/CRCUnitArr/@Path`, gmepXmlDoc);
|
||||
if (motionClipPath !== null) {
|
||||
mediaOrderList.push(motionClipPath.value);
|
||||
}
|
||||
}
|
||||
else if (mediaPath != null) {
|
||||
mediaOrderList.push(mediaPath.value);
|
||||
}
|
||||
});
|
||||
const userAnswer = mediaOrderList;
|
||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||
}
|
||||
|
||||
else if (type == "startEnd") {
|
||||
// CRClipArr/CRClip 요소의 Path속성 리스트를 구함
|
||||
// 모션 클립 이미지도 고려해 처리
|
||||
const mediaPathList = xpath.select("//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path", gmepXmlDoc);
|
||||
|
||||
// "동영상.mp4"의 clipIndex를 구함
|
||||
let clipIndex = mediaPathList.findIndex(mediaPath => mediaPath.value === media);
|
||||
// clipIndex가 -1이면 해당 미디어가 존재하지 않는 것
|
||||
if (clipIndex === -1) {
|
||||
scoringResult[key] = 0;
|
||||
continue;
|
||||
}
|
||||
const posNode = xpath.select1('@Pos', trackClipNodes);
|
||||
const lengthNode = xpath.select1('@Length', trackClipNodes);
|
||||
console.log(`Pos: ${posNode.value}, Length: ${lengthNode.value}`);
|
||||
|
||||
scoringResult[key] = posNode.value === start && lengthNode.value === end ? point : 0;
|
||||
totalScore += posNode.value === start && lengthNode.value === end ? point : 0;
|
||||
else {
|
||||
// //CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='동영상.mp4'] 요소를 찾음
|
||||
const trackClipNode = xpath.select1(`//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='${clipIndex}']`, gmepXmlDoc);
|
||||
if (!trackClipNode) {
|
||||
scoringResult[key] = 0;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// CRTrackClip 요소의 Pos(시작시간)과 Length(재생길이)를 구함
|
||||
const pos = xpath.select1('@Pos', trackClipNode);
|
||||
const length = xpath.select1('@Length', trackClipNode);
|
||||
const userAnswer = { start: pos.value, end: length.value }
|
||||
|
||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// else if (type == "video") {
|
||||
// const result = xpath.select(ele, gmepXmlDoc);
|
||||
// const length = scoringData[key].length;
|
||||
|
||||
// // 결과는 배열로 나오는데 2개 일 경우가 있음
|
||||
// if (result.length !== length) {
|
||||
// scoringResult[key] = 0;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// scoringResult[key] = point;
|
||||
// totalScore += point;
|
||||
// }
|
||||
else if (type == "color") {
|
||||
const result = xpath.select(ele, gmepXmlDoc);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user