diff --git a/src/config.js b/src/config.js new file mode 100644 index 0000000..3034528 --- /dev/null +++ b/src/config.js @@ -0,0 +1,3 @@ +export const API_BASE_URL = + import.meta.env.VITE_API_BASE_URL || + `${window.location.protocol}//${window.location.hostname}:8010`; diff --git a/src/context/AuthContext.jsx b/src/context/AuthContext.jsx index 74dba97..c42c2e0 100644 --- a/src/context/AuthContext.jsx +++ b/src/context/AuthContext.jsx @@ -1,4 +1,5 @@ import React, { createContext, useContext, useEffect, useState } from 'react'; +import { API_BASE_URL } from '../config'; const AuthContext = createContext(); @@ -15,7 +16,7 @@ export function AuthProvider({ children }) { }, []); const login = async (email, password) => { - const res = await fetch('http://localhost:8010/auth/login', { + const res = await fetch(`${API_BASE_URL}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', @@ -35,7 +36,7 @@ export function AuthProvider({ children }) { const logout = async () => { try { - await fetch('http://localhost:8010/auth/logout', { method: 'POST', credentials: 'include' }); + await fetch(`${API_BASE_URL}/auth/logout`, { method: 'POST', credentials: 'include' }); } catch {} setUser(null); try { localStorage.removeItem('auth_user'); } catch {} diff --git a/src/context/ToolContext.jsx b/src/context/ToolContext.jsx index cbabcf0..781c2f0 100644 --- a/src/context/ToolContext.jsx +++ b/src/context/ToolContext.jsx @@ -1,4 +1,5 @@ import React, { createContext, useState, useContext, useEffect } from 'react'; +import { API_BASE_URL } from '../config'; const ToolContext = createContext(); @@ -16,7 +17,7 @@ export function ToolProvider({ children }) { useEffect(() => { async function load() { try { - const res = await fetch('http://localhost:8010/tools'); + const res = await fetch(`${API_BASE_URL}/tools`); const data = await res.json(); // 'GxP 챗봇'과 'chatgpt' 카드는 도구 목록에서 제거 const filtered = (Array.isArray(data) ? data : []).filter((tool) => !['chatbot_gxp','chatgpt'].includes(tool.id)); diff --git a/src/pages/AiNewsPage.jsx b/src/pages/AiNewsPage.jsx index 87d0f65..a18038b 100644 --- a/src/pages/AiNewsPage.jsx +++ b/src/pages/AiNewsPage.jsx @@ -1,5 +1,6 @@ import React, { useEffect, useRef, useState } from 'react'; import { useAuth } from '../context/AuthContext'; +import { API_BASE_URL } from '../config'; export default function AiNewsPage() { const { user } = useAuth(); @@ -51,7 +52,7 @@ export default function AiNewsPage() { if (newsLoading) return; setNewsLoading(true); try { - const res = await fetch(`http://localhost:8010/community/ai_news?offset=${offset}&limit=10`); + const res = await fetch(`${API_BASE_URL}/community/ai_news?offset=${offset}&limit=10`); if (!res.ok) return; const data = await res.json(); const items = (data.items || []).reverse(); @@ -86,7 +87,7 @@ export default function AiNewsPage() { const submitNews = async () => { if (!newsUrl.trim()) return; - await fetch('http://localhost:8010/community/ai_news', { + await fetch(`${API_BASE_URL}/community/ai_news`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: newsUrl, author_id: String(user?.user_id || ''), author_email: user?.email || null }), diff --git a/src/pages/ChatPage.jsx b/src/pages/ChatPage.jsx index e395e56..b431ab5 100644 --- a/src/pages/ChatPage.jsx +++ b/src/pages/ChatPage.jsx @@ -4,6 +4,7 @@ import DevChatInput from '../tools/dev_chatbot/ChatInput.jsx'; import { marked } from 'marked'; marked.setOptions({ mangle:false, headerIds:false }); import { fetchOpenAIChat, fetchOpenAIImage, classifyRequest } from '../services/openaiService'; +import { API_BASE_URL } from '../config'; // === Chat History Panel 컴포넌트 추가 === function ChatHistoryPanel({ toolId }) { @@ -51,7 +52,7 @@ function FileSidebar() { const loadFiles = async () => { try { - const res = await fetch('http://localhost:8010/files'); + const res = await fetch(`${API_BASE_URL}/files`); const data = await res.json(); setFiles(data.files || []); } catch (_) {} @@ -63,7 +64,7 @@ function FileSidebar() { const handleDelete = async (fname) => { if (!window.confirm(`${fname} 파일을 삭제하시겠습니까?`)) return; - await fetch(`http://localhost:8010/file?filename=${encodeURIComponent(fname)}`, { method: 'DELETE' }); + await fetch(`${API_BASE_URL}/file?filename=${encodeURIComponent(fname)}`, { method: 'DELETE' }); loadFiles(); }; @@ -72,7 +73,7 @@ function FileSidebar() { if (!files.length) return; const formData = new FormData(); files.forEach((f) => formData.append('files', f)); - await fetch('http://localhost:8010/upload_pdf', { method: 'POST', body: formData }); + await fetch(`${API_BASE_URL}/upload_pdf`, { method: 'POST', body: formData }); loadFiles(); }; @@ -270,7 +271,7 @@ export default function ChatPage() { const formData = new FormData(); formData.append('message', userMsg.content); formData.append('tool_id', activeTool.id); - const res = await fetch('http://localhost:8010/chat', { method: 'POST', body: formData }); + const res = await fetch(`${API_BASE_URL}/chat`, { method: 'POST', body: formData }); const data = await res.json(); botContent = data.response; } @@ -364,7 +365,7 @@ function DocTranslationSidebar() { const loadFiles = async () => { try { - const res = await fetch('http://localhost:8010/doc_translation/files'); + const res = await fetch(`${API_BASE_URL}/doc_translation/files`); const data = await res.json(); setFiles(Array.isArray(data) ? data : []); } catch (_) {} @@ -385,7 +386,7 @@ function DocTranslationSidebar() { const formData = new FormData(); files.forEach((f) => formData.append('files', f)); try { - await fetch('http://localhost:8010/doc_translation/upload_doc', { method: 'POST', body: formData }); + await fetch(`${API_BASE_URL}/doc_translation/upload_doc`, { method: 'POST', body: formData }); } finally { document.body.removeChild(input); loadFiles(); @@ -396,12 +397,12 @@ function DocTranslationSidebar() { const handleDelete = async (serverFilename) => { if (!window.confirm(`${extractRealFilename(serverFilename)} 파일을 삭제하시겠습니까?`)) return; - await fetch(`http://localhost:8010/doc_translation/files/${encodeURIComponent(serverFilename)}`, { method: 'DELETE' }); + await fetch(`${API_BASE_URL}/doc_translation/files/${encodeURIComponent(serverFilename)}`, { method: 'DELETE' }); loadFiles(); }; const handleDownload = async (filename) => { - const res = await fetch(`http://localhost:8010/doc_translation/download/${encodeURIComponent(filename)}`); + const res = await fetch(`${API_BASE_URL}/doc_translation/download/${encodeURIComponent(filename)}`); if (!res.ok) return alert('다운로드 실패'); const blob = await res.blob(); const url = URL.createObjectURL(blob); @@ -478,7 +479,7 @@ function DocTranslationChat() { // ChatPage 공통 /chat 엔드포인트의 문서번역 분기와 동일 동작을 위해 model 전달 form.append('tool_id', 'doc_translation'); form.append('model', model === 'internal' ? 'internal' : 'gpt-4o'); - const res = await fetch('http://localhost:8010/chat', { method: 'POST', body: form }); + const res = await fetch(`${API_BASE_URL}/chat`, { method: 'POST', body: form }); const data = await res.json(); const botContent = data.response; setMessages((prev) => { diff --git a/src/pages/QnaPage.jsx b/src/pages/QnaPage.jsx index d28d5e2..afc44fe 100644 --- a/src/pages/QnaPage.jsx +++ b/src/pages/QnaPage.jsx @@ -1,8 +1,9 @@ import React, { useEffect, useState } from 'react'; import { useAuth } from '../context/AuthContext'; +import { API_BASE_URL } from '../config'; async function fetchQnaList() { - const res = await fetch('http://localhost:8010/community/qna'); + const res = await fetch(`${API_BASE_URL}/community/qna`); if (!res.ok) throw new Error('QNA 목록 조회 실패'); return await res.json(); } @@ -22,7 +23,7 @@ export default function QnaPage() { const handleOpen = async (id) => { try { - const res = await fetch(`http://localhost:8010/community/qna/${id}?increase=1`); + const res = await fetch(`${API_BASE_URL}/community/qna/${id}?increase=1`); if (!res.ok) return; const data = await res.json(); setOpenId(id); @@ -33,7 +34,7 @@ export default function QnaPage() { const submitQna = async () => { if (!title.trim() || !content.trim()) return; - const res = await fetch('http://localhost:8010/community/qna', { + const res = await fetch(`${API_BASE_URL}/community/qna`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title, content, author_id: String(user?.user_id || ''), author_email: user?.email || null }), diff --git a/src/tools/dev_chatbot/constants.js b/src/tools/dev_chatbot/constants.js index a66546e..e930ef8 100644 --- a/src/tools/dev_chatbot/constants.js +++ b/src/tools/dev_chatbot/constants.js @@ -1 +1,3 @@ -export const API_BASE_URL = 'http://localhost:8010'; \ No newline at end of file +import { API_BASE_URL as API_BASE } from '../../config'; + +export const API_BASE_URL = API_BASE; \ No newline at end of file