# Schema

We use `Schema` to define the structure of the data. It is a very important concept in `Promptulate`. The schema is composed of Message and MessageSet classes, which encapsulate the data structure for dialogues and conversations.

## Message

A `Message` is a fundamental building block for dialogues in `Promptulate`. It represents a single unit of communication in a conversation, whether it's from the system, the user, or the assistant (AI). Each `Message` object contains the content of the message and any additional metadata that may be relevant. There are four types of messages:

- `SystemMessage`: Represents messages that provide instructions or context for the conversation, typically not displayed to the end user.
- `UserMessage`: Represents messages that come from the human user, indicating their input or questions.
- `AssistantMessage`: Represents messages generated by the AI assistant in response to the user.
- `CompletionMessage`: Used specifically in the context of OpenAI's API to represent a message that is a completion of a prompt.

> You can see detail code in https://github.com/Undertone0809/promptulate/blob/main/promptulate/schema.py#L19C24-L19C24

Each message type inherits from the `BaseMessage` class, which ensures that every message has a consistent structure and set of properties.

## MessageSet

A `MessageSet` is a collection of `Message` objects that together represent a full conversation or a segment of a conversation. It is the main data structure used to manage the flow of dialogue between the user and the assistant. `MessageSet` provides methods for converting the messages to different formats required by various language models (`LLMType`) or for serialization purposes.

`MessageSet` includes methods for adding new messages of different types to the conversation, such as `add_user_message` or `add_ai_message`, which take the message content as input and create the appropriate `Message` object.

## StreamIterator

A `StreamIterator` is an iterator for the response stream from the LLM model.`StreamIterator` provides methods for converting the messages of stream to different formats required by various language models (`LLMType`) or for serialization purposes.

To use `StreamIterator` ,three parameters are required.

- response_stream: The stream of responses from the LLM model.
- parse_content: The callback function to parse the chunk.
- return_raw_response: A boolean indicating whether to return the raw response

## Example Usage

Here's an example of how you might use `MessageSet` and `Message` in a `Promptulate` application:

```python
import promptulate as pne
from promptulate.schema import AssistantMessage, MessageSet, SystemMessage, UserMessage

messages = MessageSet(
    messages=[
        SystemMessage(content="You are a helpful assitant"),
        UserMessage(content="Hello?"),
    ]
)

llm = pne.ChatOpenAI()
answer: AssistantMessage = llm.predict(messages)
print(answer.content)
print(answer.additional_kwargs)
```

You can also use `MessageSet` to convert a OpenAI type messages:

```python
from promptulate.schema import MessageSet

messages: MessageSet = MessageSet.from_listdict_data([
    {"role": "system", "content": "You are a helpful assitant"},
    {"role": "user", "content": "Hello?"},
])
str_message: str = messages.string_messages
openai_type_msg: list = messages.listdict_messages
```

You can use `MessageSet` to append messages:

```python
from promptulate.schema import MessageSet, SystemMessage, UserMessage

messages = MessageSet(
    messages=[
        SystemMessage(content="You are a helpful assitant"),
        UserMessage(content="Hello?"),
    ]
)
messages.add_ai_message(content="Hello, how can I help you?")
messages.add_user_message(content="I need help with my computer")
```

```python

Here's an example of how you might use `BaseStreamIterator` in a `Promptulate` application:

```python
from promptulate.schema import StreamIterator


# we use qianfan sdk as an example
def parse_content(chunk) -> (str, str):
    content = chunk["result"]
    ret_data = chunk["body"]
    return content, ret_data


def stream():
    return_raw_response = True
    # add chunk message in response
    response = ""
    return StreamIterator(
        response_stream=response,
        parse_content=parse_content,
        return_raw_response=return_raw_response,
    )

```
