Change AI Models list.

main
dongjin kim 7 months ago
parent 4f4aea15e2
commit 1083d0bee1

@ -36,50 +36,61 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
// ========== AI 모델 업로드 로직 시작 ==========
// ========== [수정됨] AI 모델 업로드 로직 시작 ==========
if (contentModels) {
const modelTable = contentModels.querySelector('.model-table');
if (modelTable) {
modelTable.addEventListener('click', (event) => {
// '시작'(업로드) 버튼이 클릭되었는지 확인
if (event.target.classList.contains('btn-action')) {
event.preventDefault(); // 기본 동작 방지
const startButton = event.target;
// 클릭된 버튼이 속한 테이블 행(tr)을 찾음
const row = startButton.closest('tr');
// 해당 행에서 파일 입력(input) 요소를 찾음
const fileInput = row.querySelector('.hidden-file-input');
// 해당 행의 모델 번호와 역할을 가져옴
const modelId = row.querySelector('td:first-child').textContent;
const modelRole = row.querySelector('td:nth-child(2)').textContent;
// 전역 업로드 관련 요소 가져오기
const globalFileInput = document.getElementById('global-file-input');
const fileNameDisplay = document.getElementById('file-name-display');
const globalUploadButton = document.getElementById('global-upload-button');
// '찾아보기'로 파일 선택 시
if (globalFileInput && fileNameDisplay) {
globalFileInput.addEventListener('change', () => {
if (globalFileInput.files.length > 0) {
const file = globalFileInput.files[0];
// 파일 확장자 확인
if (!file.name.endsWith('.aiwbin')) {
alert('잘못된 파일 형식입니다. .aiwbin 파일만 선택할 수 있습니다.');
globalFileInput.value = ''; // 파일 선택 초기화
fileNameDisplay.textContent = '선택된 파일 없음';
} else {
// 파일명 표시
fileNameDisplay.textContent = file.name;
}
} else {
fileNameDisplay.textContent = '선택된 파일 없음';
}
});
}
// '업로드' 버튼 클릭 시
if (globalUploadButton && globalFileInput) {
globalUploadButton.addEventListener('click', () => {
// 파일이 선택되었는지 확인
if (fileInput.files.length === 0) {
if (globalFileInput.files.length === 0) {
alert('먼저 .aiwbin 파일을 선택해주세요.');
return;
}
const file = fileInput.files[0];
const file = globalFileInput.files[0];
// 파일 확장자 확인 (클라이언트 측)
// (이중 확인) 파일 확장자 확인
if (!file.name.endsWith('.aiwbin')) {
alert('잘못된 파일 형식입니다. .aiwbin 파일만 업로드할 수 있습니다.');
fileInput.value = ''; // 파일 선택 초기화
globalFileInput.value = '';
fileNameDisplay.textContent = '선택된 파일 없음';
return;
}
// FormData 객체 생성
const formData = new FormData();
formData.append('modelFile', file); // 'modelFile'은 server.js와 일치해야 함
formData.append('modelId', modelId);
formData.append('modelRole', modelRole);
// [제거됨] modelId, modelRole 전송 로직
// 업로드 중 버튼 비활성화
startButton.disabled = true;
startButton.textContent = '업로드 중...';
globalUploadButton.disabled = true;
globalUploadButton.textContent = '업로드 중...';
// Fetch API를 사용하여 파일 업로드
fetch('/upload-model', {
@ -89,8 +100,9 @@ document.addEventListener('DOMContentLoaded', () => {
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
alert(`업로드 성공!\n모델: ${modelRole}\n파일: ${file.name}`);
fileInput.value = ''; // 파일 선택 초기화
alert(`업로드 성공!\n파일: ${file.name}`);
globalFileInput.value = ''; // 파일 선택 초기화
fileNameDisplay.textContent = '선택된 파일 없음';
} else {
alert(`업로드 실패: ${data.message}`);
}
@ -101,10 +113,9 @@ document.addEventListener('DOMContentLoaded', () => {
})
.finally(() => {
// 버튼 다시 활성화
startButton.disabled = false;
startButton.textContent = '시작';
globalUploadButton.disabled = false;
globalUploadButton.textContent = '업로드';
});
}
});
}
}
@ -318,3 +329,4 @@ document.addEventListener('DOMContentLoaded', () => {
// ========== video-test.html 스크립트 추가 끝 ==========
});
//<!--2025.11.12 15:56-->

@ -67,121 +67,57 @@
<div id="content-models" class="tab-content">
<div class="toolbar">
<button>새로고침</button>
<label>AI 모델파일 관리 </label>
<input type="file" id="global-file-input" class="hidden-file-input" accept=".aiwbin">
<label for="global-file-input" class="btn-browse">찾아보기</label>
<span id="file-name-display">선택된 파일 없음</span>
<button id="global-upload-button" class="btn-action">업로드</button>
<button class="refresh-button">새로고침</button>
</div>
<table class="model-table">
<thead>
<tr>
<th>번호</th>
<th>Al Model 역할</th>
<th>현재 버전</th>
<th>변경</th>
<th>업데이트</th>
<th>파일명</th> <th>현재 버전</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>객체 탐지/ 분류</td>
<td>0.1</td>
<td>
<input type="file" id="file-upload-1" class="hidden-file-input"/>
<label for="file-upload-1" class="btn-browse">찾아보기</label>
</td>
<td>
<button class="btn-action">시작</button>
</td>
<td>-</td> <td>v1.0</td>
<td>
<button class="btn-delete">삭제</button>
</td>
</tr>
<tr>
<td>2</td>
<td>사람 얼굴/인상착의 인식</td>
<td>0.1</td>
<td>
<input type="file" id="file-upload-2" class="hidden-file-input"/>
<label for="file-upload-2" class="btn-browse">찾아보기</label>
</td>
<td>
<button class="btn-action">시작</button>
</td>
<td>
<button class="btn-delete">삭제</button>
</td>
</tr>
<tr>
<td>3</td>
<td>이상행동(쓰러짐, 폭행) 감지</td>
<td>0.1</td>
<td>
<input type="file" id="file-upload-3" class="hidden-file-input"/>
<label for="file-upload-3" class="btn-browse">찾아보기</label>
</td>
<td>
<button class="btn-action">시작</button>
</td>
<td>-</td> <td>v1.0</td>
<td>
<button class="btn-delete">삭제</button>
</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>집합 군중 위험 인식</td>
<td>0.1</td>
<td>
<input type="file" id="file-upload-4" class="hidden-file-input"/>
<label for="file-upload-4" class="btn-browse">찾아보기</label>
</td>
<td>
<button class="btn-action">시작</button>
</td>
<td>-</td> <td>v1.0</td>
<td>
<button class="btn-delete">삭제</button>
</td>
</tr>
<tr>
<td>5</td>
<td>4</td>
<td>화재(불꽃, 연기) 감지</td>
<td></td>
<td>
<input type="file" id="file-upload-5" class="hidden-file-input"/>
<label for="file-upload-5" class="btn-browse">찾아보기</label>
</td>
<td>
<button class="btn-action">시작</button>
</td>
<td>-</td> <td>-</td>
<td>
<button class="btn-delete">삭제</button>
</td>
</tr>
<tr>
<td>6</td>
<td>5</td>
<td>차량 번호판/ 차종 인식</td>
<td></td>
<td>
<input type="file" id="file-upload-6" class="hidden-file-input"/>
<label for="file-upload-6" class="btn-browse">찾아보기</label>
</td>
<td>
<button class="btn-action">시작</button>
</td>
<td>
<button class="btn-delete">삭제</button>
</td>
</tr>
<tr>
<td>7</td>
<td>영상내 얼굴 비식별화</td>
<td></td>
<td>
<input type="file" id="file-upload-7" class="hidden-file-input"/>
<label for="file-upload-7" class="btn-browse">찾아보기</label>
</td>
<td>
<button class="btn-action">시작</button>
</td>
<td>-</td> <td>-</td>
<td>
<button class="btn-delete">삭제</button>
</td>
@ -194,3 +130,4 @@
<script src="app.js"></script>
</body>
</html>
<!--2025.11.12 15:56-->

@ -278,12 +278,39 @@ main {
}
/* 2-2. AI Models 탭 (PDF 3페이지) */
/* ... (기존 AI Models 탭 스타일 동일) ... */
/* [수정됨] .toolbar 스타일 */
.toolbar {
/* [수정] flexbox로 변경 */
display: flex;
justify-content: flex-end; /* 기존 text-align: right와 동일한 효과 */
align-items: center;
gap: 10px; /* 요소 간 간격 */
margin-bottom: 1rem;
text-align: right;
/* text-align: right; -- 제거 */
}
/* [추가됨] 새로고침 버튼을 맨 오른쪽으로 밀기 */
.toolbar .refresh-button {
margin-left: auto;
}
/* [추가됨] 파일명 표시 레이블 */
#file-name-display {
font-size: 0.9rem;
color: #555;
background-color: #f9f9f9;
border: 1px solid #ddd;
padding: 5px 10px;
border-radius: 4px;
min-width: 350px;
text-align: left;
font-style: italic;
/* 버튼과 높이를 맞추기 위한 line-height */
line-height: 1.4;
}
.hidden-file-input {
display: none;
}
@ -306,13 +333,13 @@ main {
background-color: #f9f9f9;
}
/* [수정됨] nth-child 선택자 수정 (컬럼 1, 4 중앙 정렬) */
.model-table td:nth-child(1),
.model-table td:nth-child(3) {
.model-table td:nth-child(4) {
text-align: center;
}
.model-table td:nth-child(4),
.model-table td:nth-child(5),
.model-table td:nth-child(6) {
/* [수정됨] nth-child 선택자 수정 (컬럼 5 '삭제' 중앙 정렬) */
.model-table td:nth-child(5) {
text-align: center;
}
@ -349,3 +376,4 @@ main {
border: 2px solid red; /* 요청된 빨간색 테두리 */
box-sizing: border-box; /* 테두리 포함 크기 계산 */
}
/*<!--2025.11.12 15:56-->*/

@ -123,7 +123,7 @@ app.post('/set-model', (req, res) => {
// --- 스크립트 실행 끝 ---
});
// [추가] 7. 모델 파일 업로드 엔드포인트
// [수정됨] 7. 모델 파일 업로드 엔드포인트
// 'modelFile'은 app.js의 FormData.append('modelFile', ...)와 일치해야 합니다.
app.post('/upload-model', (req, res) => {
@ -146,12 +146,12 @@ app.post('/upload-model', (req, res) => {
return res.status(400).json({ status: 'error', message: '업로드할 파일을 찾을 수 없습니다.' });
}
// 폼 데이터로 함께 전송된 모델 정보 (modelId, modelRole)
const modelId = req.body.modelId;
const modelRole = req.body.modelRole;
// [제거됨] 폼 데이터로 함께 전송된 모델 정보 (modelId, modelRole)
// const modelId = req.body.modelId;
// const modelRole = req.body.modelRole;
console.log(`[서버] 파일 업로드 성공:`);
console.log(` - 모델 ID: ${modelId} (${modelRole})`);
// [제거됨] console.log(` - 모델 ID: ${modelId} (${modelRole})`);
console.log(` - 원본 파일명: ${req.file.originalname}`);
console.log(` - 저장 경로: ${req.file.path}`);
@ -169,3 +169,4 @@ app.post('/upload-model', (req, res) => {
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});
<!--2025.11.12 15:56-->
Loading…
Cancel
Save