backend-junPreP Update(Update whitelist model), front-urlpredictor.jsx UI Update

This commit is contained in:
2025-04-30 02:40:18 +00:00
parent 11839c40c0
commit 8de5238395
27 changed files with 11667 additions and 23864 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -12,10 +12,11 @@
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.1",
"axios": "^1.8.4",
"framer-motion": "^12.9.2",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-icons": "^5.5.0",
"react-scripts": "^3.0.1",
"react-scripts": "^5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
@@ -43,9 +44,11 @@
]
},
"devDependencies": {
"@babel/preset-react": "^7.26.3",
"autoprefixer": "^10.4.21",
"eslint": "^8.57.1",
"postcss": "^8.5.3",
"tailwindcss": "^3.3.5",
"typescript": "^5.3.3"
"typescript": "^4.1.2"
}
}

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>URL 악성 판별기</title>
<title></title>
</head>
<body>
<div id="root"></div>

View File

@@ -5,9 +5,8 @@ import './App.css';
function App() {
return (
<div className="min-h-screen bg-gray-100 flex flex-col justify-center">
<div className="min-h-screen bg-sky-200 flex flex-col justify-center">
<div className="container mx-auto px-4 text-center">
<h1 className="text-3xl font-bold text-blue-600 mb-6">🔍 악성 URL 판별기</h1>
<UrlPredictor />
</div>
</div>

View File

@@ -1,5 +1,7 @@
import React, { useState } from "react";
import axios from "axios";
import { motion } from "framer-motion"; // 애니메이션용
import { FaSearch, FaRedo } from "react-icons/fa"; // 아이콘용
const UrlPredictor = () => {
const [url, setUrl] = useState("");
@@ -26,81 +28,90 @@ const UrlPredictor = () => {
}
};
// 모델 정보 정의 (title + 키)
const models = [
{ key: "old_model", title: "🧠 기존 모델 (Ho)" },
{ key: "new_model", title: "🚀 개선 모델 (Jun)" },
{ key: "model1", title: "HO 모델" },
{ key: "model2", title: "Jun 모델" },
];
return (
<div className="min-h-screen bg-gray-100 p-6">
{!results ? (
<div className="flex justify-center items-center h-full">
<form onSubmit={handleSubmit} className="flex gap-4 w-full max-w-2xl">
<div className="min-h-screen bg-blue-50 p-8">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 h-full">
{/* 왼쪽 입력창 */}
<div className="flex flex-col justify-center items-center gap-6">
<h1 className="text-2x1 font-bold text-blue-700">URL 판별기</h1>
<form onSubmit={handleSubmit} className="flex gap-2 w-full max-w-md">
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="URL을 입력하세요"
className="flex-grow px-4 py-2 border border-gray-300 rounded shadow"
className="flex-grow px-4 py-2 border border-gray-300 rounded-lg shadow-md focus:outline-none focus:ring-2 focus:ring-blue-400"
required
/>
<button
type="submit"
className="bg-blue-600 text-white px-6 py-2 rounded shadow hover:bg-blue-700 transition"
className="bg-blue-600 text-white px-6 py-2 flex items-center gap-2 rounded-lg shadow-md hover:bg-blue-700 transition"
>
검사하기
<FaSearch /> 검사
</button>
</form>
{loading && (
<div className="flex items-center gap-2">
<div className="w-6 h-6 border-4 border-blue-400 border-t-transparent rounded-full animate-spin"></div>
<p className="text-blue-600 font-semibold">분석 ...</p>
</div>
)}
{error && <p className="text-red-500"> {error}</p>}
</div>
) : (
<div className="grid grid-cols-2 gap-6">
{/* 좌측 입력창 */}
<div className="flex flex-col gap-4">
<form onSubmit={handleSubmit} className="flex gap-2">
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
className="flex-grow px-4 py-2 border border-gray-300 rounded shadow"
placeholder="URL을 다시 입력해보세요"
required
/>
<button
type="submit"
className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition"
>
다시 검사
</button>
</form>
{loading && <p>🔍 분석 ...</p>}
{error && <p className="text-red-500"> {error}</p>}
</div>
{/* 우측 결과 반복 렌더링 */}
<div className="flex flex-col gap-4">
{models.map((model) => {
{/* 오른쪽 결과창 */}
<div className="flex flex-col gap-6">
{results ? (
models.map((model) => {
const data = results[model.key];
if (!data) return null;
return (
<div key={model.key} className="bg-white rounded p-4 shadow">
<h2 className="text-lg font-bold mb-2">{model.title}</h2>
<p>
악성 확률: <strong>{(data.prob * 100).toFixed(2)}%</strong>
<motion.div
key={model.key}
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="bg-white rounded-2xl p-6 shadow-lg border border-gray-200"
>
<h2 className="text-xl font-bold mb-4 text-gray-800">{model.title}</h2>
<p className="mb-2 text-gray-700">
악성 확률:{" "}
<strong>
{(data.malicious_probability * 100).toFixed(2)}%
</strong>
</p>
<p>
판별 결과:{" "}
<strong className={data.malicious ? "text-red-600" : "text-green-600"}>
{data.malicious ? "⚠️ 악성 URL" : "✅ 정상 URL"}
<strong
className={
data.is_malicious
? "text-red-600"
: "text-green-600"
}
>
{data.is_malicious ? "⚠️ 악성 URL" : "✅ 정상 URL"}
</strong>
</p>
</div>
</motion.div>
);
})}
</div>
})
) : (
<div className="text-gray-500 flex items-center justify-center h-full">
결과가 여기에 표시됩니다.
</div>
)}
</div>
)}
</div>
</div>
);
};
export default UrlPredictor;
export default UrlPredictor;

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve"
},
"include": [
"src"
]
}