23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
파일명 | 내용 | 비고 |
|---|---|---|
llm.py | 사용할 open llm 모델 선택 | ollama 환경 모델 |
langserv_server.py | 챗봇이 llm 과 통신할 수 있도록 제공 | |
stream_main.py | 챗봇 UI streamlit 코드 |
from langchain_community.chat_models import ChatOllama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
# LangChain이 지원하는 다른 채팅 모델을 사용합니다. 여기서는 Ollama를 사용합니다.
llm = ChatOllama(model="ggml-q5-km:latest")from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware
from typing import List, Union
from langserve.pydantic_v1 import BaseModel, Field
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from langserve import add_routes
from llm import llm as model
app = FastAPI()
# Set all CORS enabled originsapp.add_middleware(
CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], expose_headers=["*"],)
@app.get("/")
async def redirect_root_to_docs():
return RedirectResponse("/llm/playground")
class InputChat(BaseModel):
"""Input for the chat endpoint.""" messages: List[Union[HumanMessage, AIMessage, SystemMessage]] = Field(
..., description="The chat messages representing the current conversation.", )
add_routes(app, model, path="/llm")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)import os
import streamlit as st
from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import LocalFileStore
from langchain_openai import OpenAIEmbeddings
from langchain_community.embeddings.huggingface import HuggingFaceEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.messages import ChatMessage
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders.unstructured import UnstructuredFileLoader
from langchain_community.vectorstores.faiss import FAISS
from langserve import RemoteRunnable
from langchain_openai import ChatOpenAI
from langchain_core.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
# Embedding 설정# USE_BGE_EMBEDDING = True 로 설정시 HuggingFace BAAI/bge-m3 임베딩 사용 (2.7GB 다운로드 시간 걸릴 수 있습니다)# USE_BGE_EMBEDDING = False 로 설정시 OpenAIEmbeddings 사용 (OPENAI_API_KEY 입력 필요. 과금)USE_BGE_EMBEDDING = True# LangServe 모델 설정(EndPoint)# 1) REMOTE 접속: 본인의 REMOTE LANGSERVE 주소 입력# (예시)# LANGSERVE_ENDPOINT = "https://poodle-deep-marmot.ngrok-free.app/llm/"LANGSERVE_ENDPOINT = "https://NGROK에서_할당받은_URL/llm/"# 2) LocalHost 접속: 끝에 붙는 N4XyA 는 각자 다르니# http://localhost:8000/llm/playground 에서 python SDK 에서 확인!# LANGSERVE_ENDPOINT = "http://localhost:8000/llm/c/N4XyA"LANGSERVE_ENDPOINT = "http://localhost:8000/llm/c/N4XyA"# 필수 디렉토리 생성 @Mineruif not os.path.exists(".cache"):
os.mkdir(".cache")
if not os.path.exists(".cache/embeddings"):
os.mkdir(".cache/embeddings")
if not os.path.exists(".cache/files"):
os.mkdir(".cache/files")
# 프롬프트를 자유롭게 수정해 보세요!RAG_PROMPT_TEMPLATE = """당신은 질문에 친절하게 답변하는 AI 입니다. 검색된 다음 문맥을 사용하여 질문에 답하세요. 답을 모른다면 모른다고 답변하세요.Question: {question} Context: {context} Answer:"""st.set_page_config(page_title="OpenLLM local 테스트", page_icon="💬")
st.title("OpenLLM Local 테스트")
if "messages" not in st.session_state:
st.session_state["messages"] = [
ChatMessage(role="assistant", content="무엇을 도와드릴까요?")
]
def print_history():
for msg in st.session_state.messages:
st.chat_message(msg.role).write(msg.content)
def add_history(role, content):
st.session_state.messages.append(ChatMessage(role=role, content=content))
def format_docs(docs):
# 검색한 문서 결과를 하나의 문단으로 합쳐줍니다. return "\n\n".join(doc.page_content for doc in docs)
@st.cache_resource(show_spinner="Embedding file...")
def embed_file(file):
file_content = file.read()
file_path = f"./.cache/files/{file.name}" with open(file_path, "wb") as f:
f.write(file_content)
cache_dir = LocalFileStore(f"./.cache/embeddings/{file.name}")
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", "(?<=\. )", " ", ""], length_function=len, )
loader = UnstructuredFileLoader(file_path)
docs = loader.load_and_split(text_splitter=text_splitter)
if USE_BGE_EMBEDDING:
# BGE Embedding: @Mineru model_name = "BAAI/bge-m3" # GPU Device 설정: # - NVidia GPU: "cuda" # - Mac M1, M2, M3: "mps" # - CPU: "cpu" model_kwargs = {
# "device": "cuda" "device": "mps" # "device": "cpu" }
encode_kwargs = {"normalize_embeddings": True}
embeddings = HuggingFaceEmbeddings(
model_name=model_name, model_kwargs=model_kwargs, encode_kwargs=encode_kwargs, )
cached_embeddings = CacheBackedEmbeddings.from_bytes_store(embeddings, cache_dir)
vectorstore = FAISS.from_documents(docs, embedding=cached_embeddings)
retriever = vectorstore.as_retriever()
return retriever
def format_docs(docs):
# 검색한 문서 결과를 하나의 문단으로 합쳐줍니다. return "\n\n".join(doc.page_content for doc in docs)
with st.sidebar:
file = st.file_uploader(
"파일 업로드", type=["pdf", "txt", "docx"], )
if file:
retriever = embed_file(file)
print_history()
if user_input := st.chat_input():
add_history("user", user_input)
st.chat_message("user").write(user_input)
with st.chat_message("assistant"):
# ngrok remote 주소 설정 ollama = RemoteRunnable(LANGSERVE_ENDPOINT)
chat_container = st.empty()
if file is not None:
prompt = ChatPromptTemplate.from_template(RAG_PROMPT_TEMPLATE)
# 체인을 생성합니다. rag_chain = (
{
"context": retriever | format_docs, "question": RunnablePassthrough(), }
| prompt
| ollama
| StrOutputParser()
)
# 문서에 대한 질의를 입력하고, 답변을 출력합니다. answer = rag_chain.stream(user_input) # 문서에 대한 질의 chunks = []
for chunk in answer:
chunks.append(chunk)
chat_container.markdown("".join(chunks))
add_history("ai", "".join(chunks))
else:
prompt = ChatPromptTemplate.from_template(
"다음의 질문에 간결하게 답변해 주세요:\n{input}" )
# 체인을 생성합니다. chain = prompt | ollama | StrOutputParser()
answer = chain.stream(user_input) # 문서에 대한 질의 chunks = []
for chunk in answer:
chunks.append(chunk)
chat_container.markdown("".join(chunks))
add_history("ai", "".join(chunks))$ python langserv_server.py
INFO: Started server process [28441]
INFO: Waiting for application startup.
__ ___ .__ __. _______ _______. _______ .______ ____ ____ _______
| | / \ | \ | | / _____| / || ____|| _ \ \ \ / / | ____|
| | / ^ \ | \| | | | __ | (----`| |__ | |_) | \ \/ / | |__
| | / /_\ \ | . ` | | | |_ | \ \ | __| | / \ / | __|
| `----./ _____ \ | |\ | | |__| | .----) | | |____ | |\ \----. \ / | |____
|_______/__/ \__\ |__| \__| \______| |_______/ |_______|| _| `._____| \__/ |_______|
LANGSERVE: Playground for chain "/llm/" is live at:
LANGSERVE: │
LANGSERVE: └──> /llm/playground/
LANGSERVE:
LANGSERVE: See all available routes at /docs/
LANGSERVE: ⚠️ Using pydantic 2.7.0. OpenAPI docs for invoke, batch, stream, stream_log endpoints will not be generated. API endpoints and playground should work as expected. If you need to see the docs, you can downgrade to pydantic 1. For example, `pip install pydantic==1.10.13`. See https://github.com/tiangolo/fastapi/issues/10360 for details.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)$ streamlit run stream_main.py --server.port 8080
You can now view your Streamlit app in your browser.
Local URL: http://localhost:8080
Network URL: http://192.168.0.69:8080제1장 KBO 정규시즌
제1조 경기방식
1. 단일 리그제로 각 구단은 144경기(구단간 16차전)씩 총 720경기를 거행한다.
2. 연장전은 12회(KBO 포스트시즌 15회)까지로 하고 승패를 가리지 못할 경우에는 무승부로 한다.
제2조 승률계산법
승률은 승수/(승수+패수)로 한다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.