diff options
| -rw-r--r-- | app/[lng]/test/agentforce-poc-faq/page.tsx | 62 | ||||
| -rw-r--r-- | app/[lng]/test/agentforce-poc-summary/page.tsx | 291 | ||||
| -rw-r--r-- | lib/dashboard/dashboard-client.tsx | 79 |
3 files changed, 1 insertions, 431 deletions
diff --git a/app/[lng]/test/agentforce-poc-faq/page.tsx b/app/[lng]/test/agentforce-poc-faq/page.tsx deleted file mode 100644 index 493828d6..00000000 --- a/app/[lng]/test/agentforce-poc-faq/page.tsx +++ /dev/null @@ -1,62 +0,0 @@ -'use client' - -import { useState, useRef } from 'react' - -export default function AgentforcePocPage() { - const [isLoading, setIsLoading] = useState(true) - const iframeRef = useRef<HTMLIFrameElement>(null) - - const handleIframeLoad = () => { - setIsLoading(false) - } - - const refreshIframe = () => { - if (iframeRef.current) { - setIsLoading(true) - iframeRef.current.src = iframeRef.current.src - } - } - - return ( - <div className="min-h-screen bg-gray-50 p-4"> - <div className="max-w-7xl mx-auto"> - <div className="mb-6 flex items-center justify-between"> - <h1 className="text-3xl font-bold text-gray-900"> - Agentforce POC - </h1> - <button - onClick={refreshIframe} - className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors" - > - 새로고침 - </button> - </div> - - <div className="bg-white rounded-lg shadow-lg overflow-hidden"> - {isLoading && ( - <div className="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center z-10"> - <div className="text-center"> - <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div> - <p className="text-gray-600">로딩 중...</p> - </div> - </div> - )} - - <div className="relative" style={{ height: '800px' }}> - <iframe - ref={iframeRef} - src="/agentforce-poc.html" - title="Agentforce POC" - className="w-full h-full border-0" - onLoad={handleIframeLoad} - /> - </div> - </div> - - <div className="mt-4 text-sm text-gray-500 text-center"> - 이 페이지는 Salesforce Agentforce POC를 iframe으로 표시합니다. - </div> - </div> - </div> - ) -}
\ No newline at end of file diff --git a/app/[lng]/test/agentforce-poc-summary/page.tsx b/app/[lng]/test/agentforce-poc-summary/page.tsx deleted file mode 100644 index fc504cd3..00000000 --- a/app/[lng]/test/agentforce-poc-summary/page.tsx +++ /dev/null @@ -1,291 +0,0 @@ -"use client"; - -import * as React from "react"; -import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Plus, Trash2, Send, Loader2 } from "lucide-react"; -import { toast } from "sonner"; - -interface ChatMessage { - id: string; - sender: "SHI" | "Partner"; - message: string; -} - -interface SummaryResponse { - issue: string; - request: string; - summary: string; -} - -export default function AgentForcePOCSummaryPage() { - const [messages, setMessages] = useState<ChatMessage[]>([ - { - id: "1", - sender: "SHI", - message: "최근 입고된 발전기 제어반 견적서에서 납기 조건 누락을 확인했습니다. 계약 전 꼭 납기 포함한 수정본 제출 부탁드립니다." - }, - { - id: "2", - sender: "Partner", - message: "네, 누락 사항 확인 후 납기 조건 명시하여 오늘 중으로 재제출 하겠습니다." - }, - { - id: "3", - sender: "SHI", - message: "감사합니다. 납기 조건은 계약 핵심 조항입니다. 반드시 반영해 주세요." - } - ]); - - const [summaryResult, setSummaryResult] = useState<SummaryResponse | null>(null); - const [isLoading, setIsLoading] = useState(false); - - // 새 메시지 추가 - const addMessage = () => { - const newMessage: ChatMessage = { - id: Date.now().toString(), - sender: "SHI", - message: "" - }; - setMessages([...messages, newMessage]); - }; - - // 메시지 삭제 - const removeMessage = (id: string) => { - if (messages.length > 1) { - setMessages(messages.filter(msg => msg.id !== id)); - } else { - toast.error("최소 1개의 메시지는 유지해야 합니다."); - } - }; - - // 메시지 업데이트 - const updateMessage = (id: string, field: keyof ChatMessage, value: string) => { - setMessages(messages.map(msg => - msg.id === id ? { ...msg, [field]: value } : msg - )); - }; - - // 요약 API 호출 - const handleSummarize = async () => { - // 유효성 검사 - const emptyMessages = messages.filter(msg => !msg.message.trim()); - if (emptyMessages.length > 0) { - toast.error("모든 메시지를 입력해주세요."); - return; - } - - setIsLoading(true); - try { - // 토큰 가져오기 - const tokenResponse = await fetch('https://pyheroku-d21d18e4f257.herokuapp.com/api/getToken', { - method: 'POST' - }); - - if (!tokenResponse.ok) { - throw new Error('토큰을 가져오는데 실패했습니다.'); - } - - const tokenData = await tokenResponse.json(); - const accessToken = tokenData.access_token; - - if (!accessToken) { - throw new Error('토큰이 없습니다.'); - } - - // 요약 API 호출 - const summaryResponse = await fetch(`https://connect-flow-8014--ps.sandbox.my.salesforce.com/services/apexrest/summarizeChat/`, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${accessToken}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - chatlog: JSON.stringify(messages.map(msg => ({ - sender: msg.sender, - message: msg.message - }))) - }) - }); - - if (!summaryResponse.ok) { - throw new Error(`API 호출 실패: ${summaryResponse.status}`); - } - - const result = await summaryResponse.json(); - setSummaryResult(result); - toast.success("요약이 완료되었습니다."); - } catch (error) { - console.error('요약 API 호출 실패:', error); - toast.error(`요약 중 오류가 발생했습니다: ${error instanceof Error ? error.message : '알 수 없는 오류'}`); - } finally { - setIsLoading(false); - } - }; - - return ( - <div className="container mx-auto py-8 space-y-6"> - <div className="text-center space-y-2"> - <h1 className="text-3xl font-bold">AgentForce POC 요약 테스트</h1> - <p className="text-muted-foreground"> - 대화 기록을 입력하고 AI 요약 기능을 테스트해보세요 - </p> - </div> - - <div className="grid grid-cols-1 lg:grid-cols-2 gap-6"> - {/* 입력 섹션 */} - <Card> - <CardHeader> - <CardTitle className="flex items-center justify-between"> - 대화 기록 입력 - <Button onClick={addMessage} size="sm" variant="outline"> - <Plus className="h-4 w-4 mr-2" /> - 메시지 추가 - </Button> - </CardTitle> - </CardHeader> - <CardContent className="space-y-4"> - {messages.map((message, index) => ( - <div key={message.id} className="space-y-2 p-4 border rounded-lg"> - <div className="flex items-center justify-between"> - <div className="flex items-center gap-2"> - <Badge variant={message.sender === "SHI" ? "default" : "secondary"}> - {message.sender} - </Badge> - <span className="text-sm text-muted-foreground">메시지 {index + 1}</span> - </div> - <Button - onClick={() => removeMessage(message.id)} - size="sm" - variant="ghost" - className="text-red-500 hover:text-red-700" - > - <Trash2 className="h-4 w-4" /> - </Button> - </div> - - <div className="space-y-2"> - <div className="flex gap-2"> - <Button - size="sm" - variant={message.sender === "SHI" ? "default" : "outline"} - onClick={() => updateMessage(message.id, "sender", "SHI")} - > - SHI - </Button> - <Button - size="sm" - variant={message.sender === "Partner" ? "default" : "outline"} - onClick={() => updateMessage(message.id, "sender", "Partner")} - > - Partner - </Button> - </div> - - <Textarea - value={message.message} - onChange={(e) => updateMessage(message.id, "message", e.target.value)} - placeholder="메시지를 입력하세요..." - className="min-h-20" - /> - </div> - </div> - ))} - - <Button - onClick={handleSummarize} - disabled={isLoading} - className="w-full" - > - {isLoading ? ( - <> - <Loader2 className="h-4 w-4 mr-2 animate-spin" /> - 요약 중... - </> - ) : ( - <> - <Send className="h-4 w-4 mr-2" /> - 요약하기 - </> - )} - </Button> - </CardContent> - </Card> - - {/* 결과 섹션 */} - <Card> - <CardHeader> - <CardTitle>요약 결과</CardTitle> - </CardHeader> - <CardContent className="space-y-4"> - {summaryResult ? ( - <div className="space-y-4"> - <div className="space-y-2"> - <h4 className="font-semibold text-sm text-muted-foreground">이슈</h4> - <div className="p-3 bg-muted rounded-md"> - {summaryResult.issue} - </div> - </div> - - <div className="space-y-2"> - <h4 className="font-semibold text-sm text-muted-foreground">요청</h4> - <div className="p-3 bg-muted rounded-md"> - {summaryResult.request} - </div> - </div> - - <div className="space-y-2"> - <h4 className="font-semibold text-sm text-muted-foreground">요약 메시지</h4> - <div className="p-3 bg-muted rounded-md"> - {summaryResult.summary} - </div> - </div> - </div> - ) : ( - <div className="text-center py-8 text-muted-foreground"> - <Send className="h-12 w-12 mx-auto mb-4 opacity-50" /> - <p>요약하기 버튼을 클릭하여 결과를 확인하세요</p> - </div> - )} - </CardContent> - </Card> - </div> - - {/* 미리보기 섹션 */} - <Card> - <CardHeader> - <CardTitle>API 요청 미리보기</CardTitle> - </CardHeader> - <CardContent> - <div className="space-y-4"> - <div> - <h4 className="font-semibold text-sm text-muted-foreground mb-2">Request Body</h4> - <pre className="bg-muted p-4 rounded-md text-sm overflow-x-auto"> - {JSON.stringify({ - conversation: JSON.stringify(messages.map(msg => ({ - sender: msg.sender, - message: msg.message - }))) - }, null, 2)} - </pre> - </div> - - {/* <div> - <h4 className="font-semibold text-sm text-muted-foreground mb-2">Headers</h4> - <pre className="bg-muted p-4 rounded-md text-sm overflow-x-auto"> - {JSON.stringify({ - 'Authorization': 'Bearer {access_token}', - 'Content-Type': 'application/json' - }, null, 2)} - </pre> - </div> */} - </div> - </CardContent> - </Card> - </div> - ); -} diff --git a/lib/dashboard/dashboard-client.tsx b/lib/dashboard/dashboard-client.tsx index 29660778..fef279e5 100644 --- a/lib/dashboard/dashboard-client.tsx +++ b/lib/dashboard/dashboard-client.tsx @@ -1,16 +1,6 @@ "use client"; -import { useState, useTransition, useEffect } from "react"; - -// Lightning 전역 객체 타입 선언 -declare global { - interface Window { - $Lightning: { - use: (appName: string, callback: () => void, salesforceUrl: string, accessToken: string) => void; - createComponent: (componentName: string, attributes: any, container: string, callback: (cmp: any) => void) => void; - }; - } -} +import { useState, useTransition } from "react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; import { RefreshCw } from "lucide-react"; @@ -30,71 +20,6 @@ export function DashboardClient({ initialData }: DashboardClientProps) { const [data, setData] = useState<DashboardData>(initialData); const [isPending, startTransition] = useTransition(); - // AgentForce POC Chatbot 초기화 - useEffect(() => { - // Lightning 스크립트 로드 - const script = document.createElement('script'); - script.src = 'https://connect-flow-8014--ps.sandbox.lightning.force.com/lightning/lightning.out.js'; - script.onload = () => { - // 스크립트 로드 후 채팅봇 초기화 - initializeChatbot(); - }; - document.head.appendChild(script); - - return () => { - // 컴포넌트 언마운트 시 스크립트 제거 - const existingScript = document.querySelector('script[src*="lightning.out.js"]'); - if (existingScript) { - existingScript.remove(); - } - }; - }, []); - - const initializeChatbot = async () => { - try { - const myApiUrl = 'https://pyheroku-d21d18e4f257.herokuapp.com/api/getToken'; - const salesforceUrl = 'https://connect-flow-8014--ps.sandbox.lightning.force.com/'; - const appName = 'c:zzChatBot_Aura'; - const componentContainer = 'agentforceChatbotDivId'; - - const response = await fetch(myApiUrl, { method: 'POST' }); - if (!response.ok) { - const errorData = await response.json(); - throw new Error(`백엔드 API 에러 (Status: ${response.status}): ${JSON.stringify(errorData)}`); - } - - const data = await response.json(); - const accessToken = data.access_token; - if (!accessToken) { - throw new Error("응답 데이터에 access_token이 없습니다."); - } - - console.log("백엔드를 통해 안전하게 토큰을 받았습니다:", accessToken); - - const lwcAttributes = { - isDarkMode: true, - chatbot_width: '500px', - chatbot_height: '700px' - }; - - window.$Lightning.use(appName, - () => { - window.$Lightning.createComponent( - "c:sj_Chatbot", - lwcAttributes, - componentContainer, - (cmp: any) => { - console.log('salesforce chatbot'); - } - ); - }, - salesforceUrl, - accessToken - ); - } catch (error) { - console.error('전체 프로세스 호출 실패:', error); - } - }; console.log(data) @@ -139,8 +64,6 @@ export function DashboardClient({ initialData }: DashboardClientProps) { return ( <div className="space-y-6"> - {/* AgentForce POC Chatbot - 우측하단 고정 */} - <div id="agentforceChatbotDivId" className="fixed bottom-4 right-4 z-50"></div> {/* 헤더 */} <div className="flex items-center justify-between"> <div> |
