import asyncio
import os
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import StreamingResponse
from openai import OpenAI
app = FastAPI()
# cors
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)os.environ["OPENAI_API_KEY"] = "<api-key>" # openai api 키를 발급 받아 입력
client = OpenAI(
api_key=os.environ["OPENAI_API_KEY"],
)
def send_gpt(query: str):
return client.chat.completions.create(
model='gpt-3.5-turbo-0125',
temperature=0.0,
messages=[{"role": "user", "content": query}],
max_tokens=1024,
stream=True
)
@app.get("/chat")
async def chat(query: str):
headers = {
"Cache-Control": "no-cache",
"Content-Type": "text/event-stream",
"Transfer-Encoding": "chunked"
}
return StreamingResponse(sse_generator(query), headers=headers)async def sse_generator(query: str):
response = send_gpt(query)
try:
for chunk in response:
content = chunk.choices[0].delta.content
if content is not None:
yield f"data: {content}\n\n"
await asyncio.sleep(0)
else:
yield "data: Done\n\n"
break
except Exception as e:
yield "data: Error processing your request\n\n"
print(e)'use client';
import { useState, useRef } from 'react';
import styles from '../styles/Chat.module.css';
interface Message {
id: number;
text: string[];
sender: 'user' | 'ai';
}
const Chat = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const nextMsgId = useRef<number>(0);
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
if (!input.trim()) return;
const userMessage: Message = { id: nextMsgId.current++, text: [input], sender: 'user' };
setMessages(messages => [...messages, userMessage]);
const aiMessageId: number = nextMsgId.current++;
setMessages(messages => [...messages, { id: aiMessageId, text: [], sender: 'ai' }]);
const eventSource = new EventSource(`http://localhost:8000/chat?query=${encodeURIComponent(input)}`);
eventSource.onmessage = function(event) {
if (event.data !== "Done") {
const newChar = event.data;
setMessages(currentMessages =>
currentMessages.map(msg =>
msg.id === aiMessageId ? { ...msg, text: [...msg.text, newChar] } : msg
)
);
} else {
eventSource.close();
}
};
setInput(''); // 입력 필드 초기화
};
return (
<div className={styles.chatWindow}>
<div className={styles.messages}>
{messages.map((message, index) => (
<div key={index} className={message.sender === 'user' ? styles.messageUser : styles.messageAI}>
<span>{message.text}</span>
</div>
))}
</div>
<form className={styles.inputArea} onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type your message here..."
className={styles.input}
/>
<button type="submit" className={styles.submitBtn}>Send</button>
</form>
</div>
);
};
export default Chat;