> ## Documentation Index
> Fetch the complete documentation index at: https://wb-21fd5541-feature-automate-reference-docs-generation.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Feedback prod

<Note>
  이것은 대화형 노트북입니다. 로컬에서 실행하거나 아래 링크를 사용할 수 있습니다:

  * [Open in Google Colab](https://colab.research.google.com/github/wandb/weave/blob/master/docs/notebooks/feedback_prod.ipynb)
  * [View source on GitHub](https://github.com/wandb/weave/blob/master/docs/notebooks/feedback_prod.ipynb)
</Note>

##

생성된 LLM 응답을 자동으로 평가하기는 어려울 수 있으므로, 위험 허용 수준에 따라 직접적인 사용자 피드백을 수집하여 개선 영역을 찾을 수 있습니다.

이 튜토리얼에서는 사용자 피드백을 수집하기 위한 예제 앱으로 커스텀 챗봇을 사용할 것입니다.
인터페이스를 구축하기 위해 Streamlit을 사용하고 LLM 상호작용과 피드백을 Weave에 캡처할 것입니다.

## 설정

```python
!pip install weave openai streamlit wandb
!pip install set-env-colab-kaggle-dotenv -q # for env var
python
# Add a .env file with your OpenAI and WandB API keys
from set_env import set_env

_ = set_env("OPENAI_API_KEY")
_ = set_env("WANDB_API_KEY")
```

다음으로, `chatbot.py` 파일을 다음 내용으로 생성합니다:

```python
# chatbot.py

import openai
import streamlit as st
import wandb
from set_env import set_env

import weave

_ = set_env("OPENAI_API_KEY")
_ = set_env("WANDB_API_KEY")

# highlight-next-line
wandb.login()

# highlight-next-line
weave_client = weave.init("feedback-example")
oai_client = openai.OpenAI()

def init_states():
    """Set up session_state keys if they don't exist yet."""
    if "messages" not in st.session_state:
        st.session_state["messages"] = []
    if "calls" not in st.session_state:
        st.session_state["calls"] = []
    if "session_id" not in st.session_state:
        st.session_state["session_id"] = "123abc"

# highlight-next-line
@weave.op
def chat_response(full_history):
    """
    Calls the OpenAI API in streaming mode given the entire conversation history so far.
    full_history is a list of dicts: [{"role":"user"|"assistant","content":...}, ...]
    """
    stream = oai_client.chat.completions.create(
        model="gpt-4", messages=full_history, stream=True
    )
    response_text = st.write_stream(stream)
    return {"response": response_text}

def render_feedback_buttons(call_idx):
    """Renders thumbs up/down and text feedback for the call."""
    col1, col2, col3 = st.columns([1, 1, 4])

    # Thumbs up button
    with col1:
        if st.button("👍", key=f"thumbs_up_{call_idx}"):
            st.session_state.calls[call_idx].feedback.add_reaction("👍")
            st.success("Thanks for the feedback!")

    # Thumbs down button
    with col2:
        if st.button("👎", key=f"thumbs_down_{call_idx}"):
            st.session_state.calls[call_idx].feedback.add_reaction("👎")
            st.success("Thanks for the feedback!")

    # Text feedback
    with col3:
        feedback_text = st.text_input("Feedback", key=f"feedback_input_{call_idx}")
        if (
            st.button("Submit Feedback", key=f"submit_feedback_{call_idx}")
            and feedback_text
        ):
            st.session_state.calls[call_idx].feedback.add_note(feedback_text)
            st.success("Feedback submitted!")

def display_old_messages():
    """Displays the conversation stored in st.session_state.messages with feedback buttons"""
    for idx, message in enumerate(st.session_state.messages):
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

            # If it's an assistant message, show feedback form
            if message["role"] == "assistant":
                # Figure out index of this assistant message in st.session_state.calls
                assistant_idx = (
                    len(
                        [
                            m
                            for m in st.session_state.messages[: idx + 1]
                            if m["role"] == "assistant"
                        ]
                    )
                    - 1
                )
                # Render thumbs up/down & text feedback
                if assistant_idx < len(st.session_state.calls):
                    render_feedback_buttons(assistant_idx)

def display_chat_prompt():
    """Displays the chat prompt input box."""
    if prompt := st.chat_input("Ask me anything!"):
        # Immediately render new user message
        with st.chat_message("user"):
            st.markdown(prompt)

        # Save user message in session
        st.session_state.messages.append({"role": "user", "content": prompt})

        # Prepare chat history for the API
        full_history = [
            {"role": msg["role"], "content": msg["content"]}
            for msg in st.session_state.messages
        ]

        with st.chat_message("assistant"):
            # Attach Weave attributes for tracking of conversation instances
            with weave.attributes(
                {"session": st.session_state["session_id"], "env": "prod"}
            ):
                # Call the OpenAI API (stream)
                result, call = chat_response.call(full_history)

                # Store the assistant message
                st.session_state.messages.append(
                    {"role": "assistant", "content": result["response"]}
                )

                # Store the weave call object to link feedback to the specific response
                st.session_state.calls.append(call)

                # Render feedback buttons for the new message
                new_assistant_idx = (
                    len(
                        [
                            m
                            for m in st.session_state.messages
                            if m["role"] == "assistant"
                        ]
                    )
                    - 1
                )

                # Render feedback buttons
                if new_assistant_idx < len(st.session_state.calls):
                    render_feedback_buttons(new_assistant_idx)

def main():
    st.title("Chatbot with immediate feedback forms")
    init_states()
    display_old_messages()
    display_chat_prompt()

if __name__ == "__main__":
    main()
```

이것을 `streamlit run chatbot.py`로 실행할 수 있습니다.

이제 이 애플리케이션과 상호작용하고 각 응답 후에 피드백 버튼을 클릭할 수 있습니다.
Weave UI를 방문하여 첨부된 피드백을 확인하세요.

## 설명

데코레이터가 적용된 예측 함수를 다음과 같이 고려할 수 있습니다:

```python
import weave

weave.init("feedback-example")

# highlight-next-line
@weave.op
def predict(input_data):
    # Your prediction logic here
    some_result = "hello world"
    return some_result
```

이것을 평소처럼 사용하여 사용자에게 모델 응답을 제공할 수 있습니다:

```python
with weave.attributes(
    {"session": "123abc", "env": "prod"}
):  # attach arbitrary attributes to the call alongside inputs & outputs
    result = predict(input_data="your data here")  # user question through the App UI
```

피드백을 첨부하려면 `call` 객체가 필요합니다. 이는 `.call()` 메서드를 *일반적으로 함수를 호출하는 대신* 사용하여 얻을 수 있습니다:

```python
result, call = predict.call(input_data="your data here")
```

이 호출 객체는 특정 응답에 피드백을 첨부하는 데 필요합니다.
호출을 한 후, 작업의 출력은 위의 `result`를 사용하여 사용할 수 있습니다.

```python
call.feedback.add_reaction("👍")  # user reaction through the App UI
```

## 결론

이 튜토리얼에서는 Streamlit으로 채팅 UI를 구축했으며, 입력 및 출력이 Weave에 캡처되고 사용자 피드백을 캡처하기 위한 👍👎 버튼이 있습니다.
