backend-junPreP Update(Update whitelist model), front-urlpredictor.jsx UI Update
This commit is contained in:
34744
react-url-checker/package-lock.json
generated
34744
react-url-checker/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
3
react-url-checker/src/App.js
vendored
3
react-url-checker/src/App.js
vendored
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
26
react-url-checker/tsconfig (copy 1).json
Normal file
26
react-url-checker/tsconfig (copy 1).json
Normal 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"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user