diff --git a/src/api/utils/axios.jsx b/src/api/utils/axios.jsx
index fa7b02a..97d41e7 100644
--- a/src/api/utils/axios.jsx
+++ b/src/api/utils/axios.jsx
@@ -2,28 +2,24 @@ import axios from "axios";
const client = axios.create({
baseURL: import.meta.env.VITE_API_URL,
- timeout: 10000,
+ timeout: 20000,
});
const clientAI = axios.create({
baseURL: import.meta.env.VITE_AI_API_URL,
- timeout: 10000,
+ timeout: 50000,
});
// 요청 인터셉터: 모든 API 요청이 서버로 전송되기 전에 특정 작업을 수행합니다.
client.interceptors.request.use(
(config) => {
// 로컬 스토리지에서 액세스 토큰을 가져옵니다.
- // const accessToken = localStorage.getItem('accessToken');
-
- // // 토큰이 존재하면, 요청 헤더에 'Authorization' 헤더를 추가합니다.
- // if (accessToken) {
- // config.headers.Authorization = `Bearer ${accessToken}`;
- // }
-
- config.headers.Authorization =
- "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0ZjlhMTIzZC02Yzk4LTQ3MWUtODUzNi0wNDA0YWI5ODhmOTUiLCJsb2dpbklkIjoic29ubnkiLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJEhoSEJTS1c4LkUzOFplUW9YaVp1Li5OYTJuWDhra1NaS3dueVV1QnRWTmhOaHpobk1BS3RtIiwiYXV0aCI6IlJPTEVfVVNFUiIsImV4cCI6MTc1Nzc3NzgyNX0.3C7ekn4qdGrxTfQjL1FvNH6AWL_vjbSnNHbid13LsII";
+ const accessToken = localStorage.getItem('accessToken');
+ // 토큰이 존재하면, 요청 헤더에 'Authorization' 헤더를 추가합니다.
+ if (accessToken) {
+ config.headers.Authorization = `Bearer ${accessToken}`;
+ }
return config;
},
(error) => {
@@ -57,16 +53,12 @@ client.interceptors.response.use(
clientAI.interceptors.request.use(
(config) => {
// 로컬 스토리지에서 액세스 토큰을 가져옵니다.
- // const accessToken = localStorage.getItem('accessToken');
-
- // // 토큰이 존재하면, 요청 헤더에 'Authorization' 헤더를 추가합니다.
- // if (accessToken) {
- // config.headers.Authorization = `Bearer ${accessToken}`;
- // }
-
- config.headers.Authorization =
- "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0ZjlhMTIzZC02Yzk4LTQ3MWUtODUzNi0wNDA0YWI5ODhmOTUiLCJsb2dpbklkIjoic29ubnkiLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJEhoSEJTS1c4LkUzOFplUW9YaVp1Li5OYTJuWDhra1NaS3dueVV1QnRWTmhOaHpobk1BS3RtIiwiYXV0aCI6IlJPTEVfVVNFUiIsImV4cCI6MTc1Nzc3NzgyNX0.3C7ekn4qdGrxTfQjL1FvNH6AWL_vjbSnNHbid13LsII";
+ const accessToken = localStorage.getItem('accessToken');
+ // 토큰이 존재하면, 요청 헤더에 'Authorization' 헤더를 추가합니다.
+ if (accessToken) {
+ config.headers.Authorization = `Bearer ${accessToken}`;
+ }
return config;
},
(error) => {
diff --git a/src/components/PerformaceTest/SpecCard.jsx b/src/components/PerformaceTest/SpecCard.jsx
index fbaf940..042d921 100644
--- a/src/components/PerformaceTest/SpecCard.jsx
+++ b/src/components/PerformaceTest/SpecCard.jsx
@@ -3,24 +3,25 @@ import MethodBadge from "../common/MethodBadge";
import { CheckCircle, AlertCircle } from "lucide-react";
import "../../styles/css/PerformanceTest.css";
-export default function SpecCard({ method, url, specData }) {
- console.log("specData:", method, url, specData); // ✅ 여기!
+// 1. 이제 props로 받는 specData는 API 응답의 results 배열에 있는 객체 하나입니다.
+export default function SpecCard({ specData }) {
- if (!specData) return
데이터가 없습니다.
;
+ // 2. 데이터가 없거나, 필요한 summary, raw, inputs 객체가 없는 경우를 위한 방어 코드
+ if (!specData || !specData.summary || !specData.raw || !specData.inputs) {
+ return 스펙 데이터를 표시할 수 없습니다.
;
+ }
- const {
- latencies = {},
- throughput = 0,
- successRatio = "0%",
- statusCodes = {},
- } = specData;
+ // 3. API 응답 구조에 맞게 필요한 값들을 올바른 위치에서 추출합니다.
+ const { inputs, summary, raw } = specData;
+ const { method, url } = inputs;
+ const { successRatioPct, latencyMs, rpsMean, byStatus } = summary;
- const isSuccess =
- successRatio !== "0%" && successRatio !== "0.00%" && successRatio !== 0;
+ // 성공률(successRatioPct)을 기반으로 성공/실패 여부를 판단합니다.
+ const isSuccess = successRatioPct === 100.0;
- // 안전하게 접근
- const formatLatency = (value) =>
- typeof value === "number" ? `${(value / 1e6).toFixed(2)}ms` : "N/A";
+ // 이미 밀리초(ms)인 값을 포맷하는 헬퍼 함수
+ const formatLatencyMs = (value) =>
+ typeof value === "number" ? `${value.toFixed(2)} ms` : "N/A";
return (
- 성공률: {successRatio}
+ {/* summary 객체에서 successRatioPct 값을 가져옵니다. */}
+ 성공률: {successRatioPct.toFixed(2)}%
-
- 평균 응답 시간: {formatLatency(latencies.mean)}
-
-
- 지연 시간 P50: {formatLatency(latencies["50th"])}
-
-
- 지연 시간 P95: {formatLatency(latencies["95th"])}
-
-
- 지연 시간 Max: {formatLatency(latencies.max)}
-
+ {/* summary.latencyMs 객체에서 값을 가져와 표시합니다. */}
+
평균 응답 시간: {formatLatencyMs(latencyMs.mean)}
+
지연 시간 P50: {formatLatencyMs(latencyMs.p50)}
+
지연 시간 P95: {formatLatencyMs(latencyMs.p95)}
+
지연 시간 Max: {formatLatencyMs(latencyMs.max)}
- 처리량(RPS):{" "}
-
- {typeof throughput === "number" ? throughput.toFixed(2) : "N/A"}
-
+ {/* summary 객체에서 rpsMean 값을 가져옵니다. */}
+ 처리량(RPS): {typeof rpsMean === "number" ? rpsMean.toFixed(2) : "N/A"}
상태코드:{" "}
- {Object.keys(statusCodes).length > 0 ? (
- Object.entries(statusCodes).map(([code, count]) => (
-
- {code}({count}){" "}
-
+ {/* summary.byStatus 객체를 사용합니다. */}
+ {Object.keys(byStatus).length > 0 ? (
+ Object.entries(byStatus).map(([code, count]) => (
+ {code}({count})
))
) : (
N/A
@@ -85,4 +76,4 @@ export default function SpecCard({ method, url, specData }) {
);
-}
+}
\ No newline at end of file
diff --git a/src/components/PerformaceTest/TrafficCard.jsx b/src/components/PerformaceTest/TrafficCard.jsx
index 97d2d95..48efcbd 100644
--- a/src/components/PerformaceTest/TrafficCard.jsx
+++ b/src/components/PerformaceTest/TrafficCard.jsx
@@ -1,49 +1,65 @@
import React from "react";
import MethodBadge from "../common/MethodBadge";
-import { Upload, Download, Network } from "lucide-react";
-
+import { CheckCircle, AlertCircle } from "lucide-react";
import "../../styles/css/PerformanceTest.css";
-export default function TrafficCard({ method, url, requests, bytes }) {
- console.log("trafficData:", method, url, requests, bytes); // ✅ 여기!
+export default function TrafficCard({ trafficData }) {
+ console.log("TrafficCard received trafficData:", trafficData);
+
+ // 데이터 유효성 검사
+ if (!trafficData || !trafficData.summary || !trafficData.inputs) {
+ return
트래픽 데이터를 표시할 수 없습니다.
;
+ }
+
+ // 1. 전달받은 trafficData 객체에서 inputs와 summary를 꺼냅니다.
+ const { inputs, summary } = trafficData;
+ // 2. 각각의 객체에서 필요한 값을 최종적으로 추출합니다.
+ const { method, url } = inputs;
+ const { requests, bytes } = summary;
+
+ const isSuccess = requests > 0;
+ const formatBytes = (value) => {
+ if (typeof value !== 'number' || value === 0) return "0 B";
+ const k = 1024;
+ const sizes = ['B', 'KB', 'MB', 'GB'];
+ const i = Math.floor(Math.log(value) / Math.log(k));
+ return parseFloat((value / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+ };
return (
-
+
+
+ {isSuccess ? : }
+ {isSuccess ? "완료" : "실패"}
+
+ {/* 3. 이제 method 값을 정상적으로 사용할 수 있습니다. */}
-
- {/* 예: "SPEC" or "TRAFFIC" */}Traffic
-
+ TRAFFIC
+
+ {/* 4. url 값도 정상적으로 사용할 수 있습니다. */}
API URL : {url}
+
- 총 요청 수:
{requests}
+
총 요청 수: {requests}
-
- 평균 수신 바이트 : {bytes?.in?.mean ?? 0}B
-
-
- 총 수신 바이트 : {bytes?.in?.total ?? 0}B
-
+
총 수신량: {formatBytes(bytes.in.total)}
+
평균 수신량: {formatBytes(bytes.in.mean)}
-
-
- 평균 송신 바이트 : {bytes?.out?.mean ?? 0}B
-
-
- 총 송신 바이트 : {bytes?.out?.total ?? 0}B
-
+
총 송신량: {formatBytes(bytes.out.total)}
+
평균 송신량: {formatBytes(bytes.out.mean)}
);
-}
+}
\ No newline at end of file
diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx
index b1084e0..ff34130 100644
--- a/src/pages/Dashboard.jsx
+++ b/src/pages/Dashboard.jsx
@@ -42,8 +42,8 @@ const Dashboard = ({ setActiveTab, setSpecData, setTrafficData }) => {
},
};
- setSpecData(specData);
- setTrafficData(trafficData);
+ setSpecData(console.log("성능 또 다시 보여줘야돼", specData,), specData);
+ setTrafficData(console.log("트래픽 또 다시 보여줘야돼", trafficData,), trafficData);
setActiveTab("성능 테스트");
};
@@ -84,6 +84,11 @@ const Dashboard = ({ setActiveTab, setSpecData, setTrafficData }) => {
// },
// },
// });
+
+ const [messages, setMessages] = useState([
+ { role: "bot", type: "text", content: "안녕하세요! 무엇을 도와드릴까요?" },
+ ]);
+
const [input, setInput] = useState("");
const messagesEndRef = useRef(null);
const params = useParams();
@@ -116,6 +121,20 @@ const Dashboard = ({ setActiveTab, setSpecData, setTrafficData }) => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
+ const handleNavigateToTest = (data) => {
+
+ console.log('--- handleNavigateToTest ---');
+ console.log('SpecData로 설정될 데이터:', data.specData);
+ console.log('TrafficData로 설정될 데이터:', data.trafficData);
+ console.log('-----------------------------');
+ // specData가 있으면 상태를 업데이트하고, 없으면 null로 설정합니다.
+ setSpecData(data.specData || null);
+ // trafficData가 있으면 상태를 업데이트하고, 없으면 null로 설정합니다.
+ setTrafficData(data.trafficData || null);
+
+ setActiveTab("성능 테스트");
+ };
+
const handleSend = (e) => {
e.preventDefault();
if (!input.trim() || isPending) return; // 로딩 중일 때는 전송 방지
@@ -123,7 +142,8 @@ const Dashboard = ({ setActiveTab, setSpecData, setTrafficData }) => {
const now = new Date();
const userMessage = {
role: "user",
- text: input,
+ type: "text",
+ content: input,
timestamp: now.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
@@ -134,21 +154,39 @@ const Dashboard = ({ setActiveTab, setSpecData, setTrafficData }) => {
const userInput = input;
setInput("");
+
+
// 3. mutate 함수를 호출하여 API 요청을 보냅니다.
postPrompt(
- {
- team_code: teamCode, // 팀 코드 전달",
- prompt: userInput, // 사용자 입력 전달
- },
+ { team_code: teamCode, prompt: userInput },
{
onSuccess: (response) => {
- // 4. API 요청 성공 시, 받은 응답으로 봇 메시지를 추가합니다.
- // 서버 응답이 { reply: "..." } 형태라고 가정합니다.
- const botResponse = {
- role: "bot",
- text: response.output,
- };
- setMessages((prev) => [...prev, botResponse]);
+ const resultsArray = response.output.results || (response.output ? [response.output] : []);
+
+ // 2. spec 또는 traffic 결과를 찾습니다. 둘 중 하나만 있을 수도 있습니다.
+ const specResult = resultsArray.find(r => r.testType === 'spec');
+ const trafficResult = resultsArray.find(r => r.testType === 'traffic');
+
+ // 3. 둘 중 하나라도 결과가 있다면 버튼 메시지를 생성합니다.
+ if (specResult || trafficResult) {
+ const botResponse = {
+ role: 'bot',
+ type: 'performance_test_button',
+ content: {
+ specData: specResult,
+ trafficData: trafficResult
+ }
+ };
+ setMessages(prev => [...prev, botResponse]);
+ } else {
+ // 둘 다 없다면 일반 텍스트 메시지로 처리
+ const botResponse = {
+ role: 'bot',
+ type: 'text',
+ content: response.output || "결과를 이해할 수 없습니다."
+ };
+ setMessages(prev => [...prev, botResponse]);
+ }
},
onError: (error) => {
// 5. API 요청 실패 시, 에러 메시지를 표시합니다.
@@ -172,7 +210,18 @@ const Dashboard = ({ setActiveTab, setSpecData, setTrafficData }) => {
{messages.map((msg, i) => (
-
{msg.text}
+
+ {msg.type === 'text' ? (
+ msg.content
+ ) : msg.type === 'performance_test_button' ? (
+
+ ) : null}
+
{msg.timestamp}
))}
@@ -184,17 +233,6 @@ const Dashboard = ({ setActiveTab, setSpecData, setTrafficData }) => {
- {/* 임시 버튼 */}
-
-
-
-
);