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