diff --git a/docs/components/component_page.mdx.tpl b/docs/components/component_page.mdx.tpl index 2137e9b9e..84baf6568 100644 --- a/docs/components/component_page.mdx.tpl +++ b/docs/components/component_page.mdx.tpl @@ -12,11 +12,11 @@ mode: "wide" {% if fields %} ## Fields - +
- + diff --git a/docs/framework/ai-module.mdx b/docs/framework/ai-module.mdx index 5bc0a157f..3a74f48d3 100644 --- a/docs/framework/ai-module.mdx +++ b/docs/framework/ai-module.mdx @@ -2,7 +2,23 @@ title: "Writer AI module" --- -This module leverages the Writer SDK to enable applications to interact with large language models (LLMs) in chat or text completion formats. It provides tools to manage conversation states and to dynamically interact with LLMs using both synchronous and asynchronous methods. +This module leverages the [Writer Python SDK](https://pypi.org/project/writer-sdk/) to enable applications to interact with large language models (LLMs) in chat or text completion formats. It provides tools to manage conversation states and to dynamically interact with LLMs using both synchronous and asynchronous methods. + +## Getting your API key +To utilize the Writer AI module, you'll need to configure the `WRITER_API_KEY` environment variable with an API key obtained from AI Studio. Here is a detailed [guide](/api-guides/quickstart) to setup up this key. You will need to select an **API** app under **Developer tools** + +Once you have your API key, set it as an environment variable on your system: + + ``` bash For macOS and Linux +export WRITER_API_KEY=your_api_key_here + ``` +```bash For Windows +set WRITER_API_KEY=your_api_key_here +``` + +You can manage your environment variables using methods that best suit your setup, such as employing tools like [python-dotenv](https://pypi.org/project/python-dotenv/). + +Furthermore, when deploying an application with `writer deploy`, the `WRITER_API_KEY` environment variable is automatically configured with the API key specified during the deployment process. ## Conversation class The `Conversation` class manages LLM communications within a chat framework, storing the conversation history and handling the interactions. @@ -31,37 +47,41 @@ A `Conversation` can be initialized with either a system prompt or a list of pre ```python -# Initialize with a system prompt -conversation = Conversation("You assist Chinese-speaking clients with their questions") +# Initialize with a system prompt for a Financial Analyst specializing in balance sheets +conversation = Conversation("You assist clients with analyzing and understanding their balance sheets") -# Initialize with a history of messages +# Initialize with a history of messages related to balance sheet queries history = [ - {"role": "user", "content": "Hello"}, - {"role": "assistant", "content": "Hi, how can I help?"} + {"role": "user", "content": "Can you explain the liabilities section?"}, + {"role": "assistant", "content": "Certainly! Liabilities are legally binding obligations payable to another entity."} ] + conversation = Conversation(history) -# Initialize with a configuration -config = {'max_tokens': 150, 'temperature': 0.7} -conversation = Conversation("You are a social media expert in the financial industry", config=config) +# Initialize with a configuration suitable for financial analysis discussions +config = {'max_tokens': 200, 'temperature': 0.5} +conversation = Conversation("You provide detailed insights into balance sheet components", config=config) ``` ### Adding messages to conversation Messages can be added to a `Conversation` instance using the `+` operator or the `add` method. ```python -# Using the `+` operator -conversation += {"role": "user", "content": "What's the weather like?"} +# Using the `+` operator to add a balance sheet-related query +conversation += {"role": "user", "content": "Can you break down the assets section of the balance sheet?"} -# Using the `add` method -conversation.add(role="user", content="What's the weather like?") +# Using the `add` method to add a balance sheet-related query +conversation.add(role="user", content="How should I interpret the equity section?") ``` -Addition to `Conversation` only works against `dict` objects that contain `"role"` and `"content"` items. Providing a `"chunk": True` flag into the object will merge it against the last message – appending `"content"` and replacing other values. +Addition to `Conversation` only works against `dict` objects that contain `"role"` and `"content"` items. Providing a `"chunk": True` flag into the object will merge it against the last message - appending `"content"` and replacing other values. ### Completing and streaming Conversations + +When utilizing the `stream_complete` feature, the initial chunk of data returned by the stream is not specifically marked as a "chunk." This is intentional, allowing for the seamless integration of this first piece into the conversation history when appended using the + operator. + -The `complete` and `stream_complete` methods facilitate interaction with the LLM based on the accumulated messages and configuration. These methods execute calls to generate responses and return them in form of a message object, but do not alter the conversation's `messages` list, allowing you to validate or modify the output before deciding to add it to the history. +The `complete` and `stream_complete` methods facilitate interaction with the LLM based on the accumulated messages and configuration. These methods execute calls to generate responses and return them in the form of a message object, but do not alter the conversation's `messages` list, allowing you to validate or modify the output before deciding to add it to the history. ```python complete @@ -78,31 +98,25 @@ for chunk in conversation.stream_complete(): ``` - - - -First chunk of `stream_complete` is not flagged. When using `stream_complete`, the first chunk returned by the stream is not flagged explicitly as a "chunk." This behavior is by design, to seamlessly add this initial chunk into the conversation history if it is appended using the `+` operator. - - -Instance-wide configuration parameters can be complemented or overriden on individual call's level, if a `data` dictionary is provided to the method: +Instance-wide configuration parameters can be complemented or overriden on individual call's level, if a `config` dictionary is provided to the method: ```python # Overriding configuration for a specific call -response = conversation.complete(data={'max_tokens': 200, 'temperature': 0.5}) +response = conversation.complete(config={'max_tokens': 200, 'temperature': 0.5}) ``` ## Text completions without a conversation state -These `complete` and `stream_complete` methods are designed for one-off text completions without the need to manage a conversation state. They return the model's response as a string. Each function accepts a `data` dictionary allowing call-specific configurations. +These `complete` and `stream_complete` methods are designed for one-off text completions without the need to manage a conversation state. They return the model's response as a string. Each function accepts a `config` dictionary allowing call-specific configurations. ```python complete # Using `complete` for a single completion -text_response = complete("Explore the benefits of AI.", data={'temperature': 0.3}) +text_response = complete("Explore the benefits of AI.", config={'temperature': 0.3}) print("Completion:", text_response) ``` ```python stream_complete # Using `stream_complete` for streamed text completions -for text_chunk in stream_complete("Explore the benefits of AI.", data={'temperature': 0.3}): +for text_chunk in stream_complete("Explore the benefits of AI.", config={'temperature': 0.3}): print("Streamed Text:", text_chunk) ``` diff --git a/docs/framework/application-state.mdx b/docs/framework/application-state.mdx index d900c2305..50b65383f 100644 --- a/docs/framework/application-state.mdx +++ b/docs/framework/application-state.mdx @@ -4,9 +4,13 @@ title: "Application state" Each session is assigned a unique application state by the Framework. -## Initialising state +## Initializing state -To set the initial application state, use the `wf.init_state()` method with a dictionary argument. **All user sessions will start with a clone of this initial state**. +To set the initial application state, use the `wf.init_state()` method with a dictionary argument. + + +All user sessions will start with a clone of this initial state. + ```py import writer as wf @@ -26,7 +30,7 @@ In the above example, each session begins with a `counter` at 0. As users intera To access the `counter` value in the Builder, use @{counter}. -### Managing Nested State Elements +### Managing nested state elements To include nested elements in your state, use nested dictionaries: @@ -44,53 +48,25 @@ You can reference nested elements in the Builder as `@{my_app.title}`. ### Backend-only state elements -By default, all of the elements in the session state are sent to the frontend. +By default, all of the elements in the session state are sent to the front-end. -All state elements are transmitted to the frontend by default, regardless of their visibility in the user interface. +All state elements are transmitted to the front-end by default, regardless of their visibility in the user interface. -To keep certain state elements private (backend-only), prefix them with an underscore `_`. This is useful in several scenarios: +To keep certain state elements private (back-end-only), prefix them with an underscore `_`. This is useful in several scenarios: -1. When data synchronization to the frontend is unnecessary. -2. When data cannot be serialized for the frontend, such as database connections. +1. When data synchronization to the front-end is unnecessary. +2. When data cannot be serialized for the front-end, such as database connections. 3. When data is sensitive to the specific session and should remain confidential. -These elements remain in the backend and cannot be accessed from the Builder. - -## Handling non-standard data types - -The frontend cannot directly display complex data types such as Pandas dataframes or Matplotlib figures. Such objects must be serialized before being sent. - - - - Matplotlib figures are converted to PNG data URLs, which can be shown using a standard _Image_ component. - - ```python - wf.init_state({ - "my_matplotlib_fig": fig, - }) - ``` - - The element can be used in an _Image_ component in Builder by setting the source to `@{my_matplotlib_fig}`. Alternatively, as data inside a _File Download_ component. - - - Plotly graphs are converted to Plotly JS specifications, using JSON. They can be used in _Plotly Graph_ components. - - - Altair charts are converted to Vega Lite specifications, based on JSON. They can be used in _Vega Lite Chart_ components. - - - Pandas dataframes are converted to JSON and can be used in _Dataframe_ components. - - - +These elements remain in the back-end and cannot be accessed from the Builder. ## Managing files and binary data -In components where Builder interfaces with external data, such as images, it often requires the use of data URLs. The source for an _Image_ component, for example, can be a standard URL or a data URL. +In components where the Builder interfaces with external data, such as images, it often requires the use of data URLs. The source for an _Image_ component, for example, can be a standard URL or a data URL. -Packing Files and Binary Data: Files and binary data can be converted to data URLs before they are sent to the frontend. Use `wf.pack_file()` and `wf.pack_bytes()` for this purpose. The `mime_type` argument, while optional, specifies the media type, helping the browser to correctly handle the data. +Packing Files and Binary Data: Files and binary data can be converted to data URLs before they are sent to the front-end. Use `wf.pack_file()` and `wf.pack_bytes()` for this purpose. The `mime_type` argument, while optional, specifies the media type, helping the browser to correctly handle the data. ```python import writer as wf @@ -110,3 +86,30 @@ wf.init_state({ "my_raw_bytes": b"\x31\x33\x33\x37", }) ``` + +## Handling non-standard data types + +The front-end cannot directly display complex data types such as Pandas dataframes or Matplotlib figures. Such objects must be serialized before being sent. + + + + Matplotlib figures are converted to PNG data URLs, which can be shown using a standard _Image_ component. + + ```python + wf.init_state({ + "my_matplotlib_fig": fig, + }) + ``` + + The element can be used in an _Image_ component in the Builder by setting the source to `@{my_matplotlib_fig}`. Alternatively, as data inside a _File Download_ component. + + + Plotly graphs are converted to Plotly JS specifications, using JSON. They can be used in _Plotly Graph_ components. + + + Altair charts are converted to Vega Lite specifications, based on JSON. They can be used in _Vega Lite Chart_ components. + + + Pandas dataframes are converted to JSON and can be used in _Dataframe_ components. + + diff --git a/docs/framework/authentication.mdx b/docs/framework/authentication.mdx index 53db8c541..0ab725f0d 100644 --- a/docs/framework/authentication.mdx +++ b/docs/framework/authentication.mdx @@ -2,7 +2,7 @@ title: "Authentication" --- -The Writer framework authentication module allows you to restrict access to your application. +The Writer Framework authentication module allows you to restrict access to your application. Framework will be able to authenticate a user through an identity provider such as Google, Microsoft, Facebook, Github, Auth0, etc. @@ -76,7 +76,7 @@ writer.serve.register_auth(oidc) ### Use pre-configured OIDC -Writer framework provides pre-configured OIDC providers. You can use them directly in your application. +The Writer Framework provides pre-configured OIDC providers. You can use them directly in your application. | Provider | Function | Description | | -------- | ------------------------ | --------------------------------------------------------------------------------------- | @@ -187,7 +187,7 @@ writer.serve.register_auth(oidc, callback=callback) The default authentication error page look like this: - + _streamsync.auth.Unauthorized_ diff --git a/docs/framework/backend-driven-ui.mdx b/docs/framework/backend-driven-ui.mdx index ae09f7c81..e78c4c3f3 100644 --- a/docs/framework/backend-driven-ui.mdx +++ b/docs/framework/backend-driven-ui.mdx @@ -2,15 +2,15 @@ title: "Backend-driven UI" --- -Framework facilitates backend-initiated user interface modifications. These changes are made possible through **Code-Managed Components** (CMCs), distinct from *Builder-Managed Components* (BMCs). +Framework facilitates backend-initiated user interface modifications. These changes are made possible through **Code-Managed Components** (CMCs), distinct from the *Builder-Managed Components* (BMCs). -CMCs, unlike BMCs, are dynamically created and modified via backend code, and cannot be edited (but still can be viewed) within the application builder. It's important to also note that CMCs do not persist in your application's `ui.json` file and exist only during the application runtime, supporting dynamic UI adjustments. +CMCs, unlike BMCs, are dynamically created and modified via back-end code, and cannot be edited (but still can be viewed) within the application builder. It's important to also note that CMCs do not persist in your application's `ui.json` file and exist only during the application runtime, supporting dynamic UI adjustments. To summarise: **CMC** – Code-Managed Component -- created via **application backend**; +- created via **application back-end**; - **cannot be edited** in builder; - is **not saved** to `ui.json`. @@ -98,7 +98,7 @@ with ui.find(container): ### Component methods -UI manager contains methods linked to each frontend component. For example, in previous code snippets we provide a `ui.Text` method, which is used for creating [Text components](https://www.streamsync.cloud/component-list.html#text). +UI manager contains methods linked to each front-end component. For example, in previous code snippets we provide a `ui.Text` method, which is used for creating [Text components](https://www.streamsync.cloud/component-list.html#text). This method expects `content: dict` as first argument, which enables you to set the field properties of the component, through corresponding keys: ```python diff --git a/docs/framework/backend-initiated-actions.mdx b/docs/framework/backend-initiated-actions.mdx index 5867571b8..507af491b 100644 --- a/docs/framework/backend-initiated-actions.mdx +++ b/docs/framework/backend-initiated-actions.mdx @@ -18,7 +18,7 @@ def handle_file_download(state): ## Adding a notification -![Notifications](./images/backend-initiated-actions.notifications.png) +![Notifications](/framework/images/backend-initiated-actions.notifications.png) Framework adds notifications when a runtime error takes place. You can add your own notifications using the `add_notification` method, which takes the `type`, `title` and `message` arguments. `type` must be one of `error`, `warning`, `info`, `success`. diff --git a/docs/framework/builder-basics.mdx b/docs/framework/builder-basics.mdx index 50acc33e7..78489d427 100644 --- a/docs/framework/builder-basics.mdx +++ b/docs/framework/builder-basics.mdx @@ -10,58 +10,51 @@ You can switch modes between _User Interface_, _Code_ and _Preview_ using the bu ### User Interface -![Framework Builder - Mode: User Interface](/framework/images/builder-basics.ui.png) +![Framework Builder - Mode: User Interface](/framework/images/builder-basics.ui.png#framework) The default mode. Allows you to focus on building the interface. ### Code -![Framework Builder - Mode: Code](/framework/images/builder-basics.code.png) +![Framework Builder - Mode: Code](/framework/images/builder-basics.code.png#framework) -This mode displays the code editor and the application log, while still allowing you to access the _Component Tree_ and _Settings_. +This mode displays the **code editor** and the **application log**, while still allowing you to access the _Component Tree_ and _Settings_. -#### Code editor + + + + Code changes are automatically detected. The application will reload whenever a change to a `.py` file inside the app folder is detected. This feature only works in Framework Builder i.e. `edit` mode, not when running the app in `run` mode. + + The built-in code editor for `main.py`, the entry point of your application. This editor is provided for convenience and is ideal for quick edits — but you don't need to rely on it. If you need a more powerful editor or if your codebase is distributed across several files, use a local editor. + + + Exceptions raised by your application are shown here, as log entries. Standard output from your application is also captured and displayed as log entries. + + -The built-in code editor for `main.py`, the entry point of your application. This editor is provided for convenience and is ideal for quick edits —but you don't need to rely on it. - -If you need a more powerful editor or if your codebase is distributed across several files, use a local editor. - - - -Code changes are automatically detected - -The application will reload whenever a change to a `.py` file inside the app folder is detected. This feature only works in Framework Builder i.e. `edit` mode, not when running the app in `run` mode. - - - -#### Application log - -Exceptions raised by your application are shown here, as log entries. Standard output from your application is also captured and displayed as log entries. ### Preview -![Framework Builder - Mode: Preview](/framework/images/builder-basics.preview.png) +![Framework Builder - Mode: Preview](/framework/images/builder-basics.preview.png#framework) The _Preview_ mode shows the application exactly like the user will see it. It allocates the whole width of the viewport to the app. ## Adding and moving components +You can create new components in your app by dragging and dropping items from the Toolkit. Some components, like Sections, can act as parents, while others, such as Text, cannot. Additionally, certain components have placement restrictions—for instance, a Column must be added to a Column Container, and a Sidebar can only be added to a Page. -- Drag and drop components from the _Toolkit_ to the app to create new components. -- Some components can be parents, e.g. _Section_. Others can't, e.g. _Text_. -- Certain components have restrictions. For example, a _Column_ can only be added to a _Column Container_. A _Sidebar_ can only be added to a _Page_. -- By default, components are added in the last position. To add components in a specific position, drag over the desired parent until the insertion lines are shown. - -![Framework Builder - Insertion position](/framework/images/builder-basics.insertion.gif) - -- You can drag and drop existing components within the app, from one parent to another, or within the same parent to reposition them. -- Alternatively, you can use the _Component Tree_ either as source or destination for drag and drop. +By default, components are positioned at the end, but if you need to place them specifically, simply drag them over the desired parent until you see the insertion lines. You can also reorganize existing components by moving them between parents or within the same parent. For more flexibility, the Component Tree can serve both as a source or a destination for your drag and drop actions. ## Selecting a component +Select a component by clicking on it. If you click on a component that's already selected, the click will be treated as an interaction with the app. Two things will happen when a component is selected: -- Select a component by clicking on it. If you click on a component that's already selected, the click will be treated as an interaction with the app. -- Two things will happen when a component is selected. - 1. The _Component Settings_ panel will open on the right. Depending on available screen real estate, the panel will open on top of the app or next to it. - 2. A set of component-specific actions, _Component Shortcuts_, will be displayed on top of the component. + + + The _Component Settings_ panel will open on the right. Depending on available screen real estate, the panel may open on top of the app or next to it. + + + A set of component-specific actions, _Component Shortcuts_, will be displayed on top of the component. + + ## Component settings @@ -69,39 +62,32 @@ Settings are divided into the following sections. Changes to settings can be und ![Framework Builder - Component settings](/framework/images/builder-basics.component-settings.png) -### Properties - -Divided into _General_ and _Style_ categories. Values can include - -- Literals, e.g. `monkey` -- References to application state using the template syntax `@{}`, e.g. `@{my_favourite_animal}`. -- A combination of both, e.g. `My favourite animal is @{my_favourite_animal}`. -- Nested states can be accessed with `.` (dot), e.g. `@{building.height}`. -- Nested elements can be dynamically accessed with `[]`, e.g. `@{building[dynamic_prop]}` will be equivalent to `@{building.height}` when `dynamic_prop` equals `height`. - -Properties are of different types, such as _Text_, _Color_ and _Number_. All property values are stored as text values, then casted when being evaluated. - -### Binding - -![Framework Builder - Binding](/framework/images/builder-basics.binding.png) - -Input components can be bound, in a two-way fashion, to a state element. - -For example, a _Slider Input_ component can be bound to `my_var`. If the value of the slider changes, so does the value of `my_var`. Similarly, if the value of `my_var` changes, the slider is moved automatically to reflect the change. - -To bind an input component, specify the state element. For example, `my_var` or `building.height`. Note that this field should not contain the template syntax, e.g. `my_var` and not `@{my_var}`. - -### Events - -The events generated by this component, with the option of setting event handlers for those. Event handlers are explained in more detail in a separate section of this guide. - -### Visibility - -Whether the component should be displayed. There are three visibility options: - -- Yes. The component is displayed. -- No. The component isn't displayed. Note that hidden components are still part of the HTML code, but aren't shown. -- Custom. Whether the component is displayed or not depends on the value of a state or context element. For example if set to `my_var`, visibility will depend on the value of the `my_var` state element. Note that this field, similarly to Binding, should only contain the state element, e.g. `my_var` and not `@{my_var}`. + + + Divided into _General_ and _Style_ categories. Values can include: + 1. Literals, e.g. `monkey` + 2. References to application state using the template syntax `@{}`, e.g. `@{my_favourite_animal}`. + 3. A combination of both, e.g. `My favourite animal is @{my_favourite_animal}`. + 4. Nested states can be accessed with `.` (dot), e.g. `@{building.height}`. + 5. Nested elements can be dynamically accessed with `[]`, e.g. `@{building[dynamic_prop]}` will be equivalent to `@{building.height}` when `dynamic_prop` equals `height`. + Properties are of different types, such as _Text_, _Color_ and _Number_. All property values are stored as text values, then casted when being evaluated. + + + ![Framework Builder - Binding](/framework/images/builder-basics.binding.png) + Input components can be bound, in a two-way fashion, to a state element. + For example, a _Slider Input_ component can be bound to `my_var`. If the value of the slider changes, so does the value of `my_var`. Similarly, if the value of `my_var` changes, the slider is moved automatically to reflect the change. + To bind an input component, specify the state element. For example, `my_var` or `building.height`. Note that this field should not contain the template syntax, e.g. `my_var` and not `@{my_var}`. + + + The events generated by this component, with the option of setting event handlers for those. Event handlers are explained in more detail in a separate section of this guide. + + + Whether the component should be displayed. There are three visibility options: + 1. Yes. The component is displayed. + 2. No. The component isn't displayed. Note that hidden components are still part of the HTML code but aren't shown. + 3. Custom. Whether the component is displayed or not depends on the value of a state or context element. For example, if set to `my_var`, visibility will depend on the value of the `my_var` state element. Note that this field, similarly to Binding, should only contain the state element, e.g. `my_var` and not `@{my_var}`. + + ## Component shortcuts @@ -109,33 +95,41 @@ Perform a variety of operations on existing components. Options will be grayed o ![Framework Builder - Component shortcuts](/framework/images/builder-basics.component-shortcuts.png) -- _Add_. Adds a child of a given type to this component. -- _Move up_. Decrements the position index of the component, used to sort children in the parent container. -- _Move down_. Increments the position index of the component. -- _Cut_. Cuts the component and places it into Builder's internal clipboard. -- _Copy_. Copies the component and places it into the internal clipboard. -- _Paste_. Pastes the content of the internal clipboard using the selected component as a parent. -- _Go to parent_. Selects the parent of the selected component. -- _Delete_. Deletes this component. + + + Adds a child of a specified type to this component. + + + Decrements the position index of the component, used to sort children within the parent container. + + + Increments the position index of the component. + + + Cuts the component and places it into Builder’s internal clipboard. + + + Copies the component and places it into the internal clipboard. + + + Pastes the content of the internal clipboard using the selected component as a parent. + + + Selects the parent of the selected component. + + + Deletes this component. + + + Just like with changes to settings, these operations can be undone and redone. ## Discovering components -Builder is designed to allow easy discoverability of components. Rather than scouring specifications every time you need to use a component, you can rely on the visual editor to guide you. - -### Short description - -You can hover on the component type to get a tooltip with a short description. - -### Available properties and events - -Looking at _Settings_ will allow you to see which of its properties are configurable. - -### Built-in docs - -Components have short docs built into them. You can expand it by clicking the help icon in Settings. - -### Event handler stub code +The Builder is designed to allow easy discoverability of components. Rather than scouring specifications every time you need to use a component, you can rely on the visual editor to guide you. -Different events need to be handled differently. The built-in stub handlers, which can be found next to each event, can help you get started when writing event handlers. +1. **Short description:** You can hover on the component type to get a tooltip with a short description. +2. **Available properties and events:** Looking at _Settings_ will allow you to see which of its properties are configurable. +3. **Built-in docs:** Components have short docs built into them. You can expand it by clicking the help icon in Settings. +4. **Event handler stub code:** Different events need to be handled differently. The built-in stub handlers, which can be found next to each event, can help you get started when writing event handlers. diff --git a/docs/framework/chat-assistant.mdx b/docs/framework/chat-assistant.mdx index e58608c22..d63a29f40 100644 --- a/docs/framework/chat-assistant.mdx +++ b/docs/framework/chat-assistant.mdx @@ -2,73 +2,69 @@ title: "Chat assistant" --- -In this introductory tutorial, you will use Writer Framework to build an AI chat assistant. +In this introductory tutorial, you'll use the Writer Framework to build an AI chat assistant. -![Finished chat assistant project](/framework/images/tutorial/chat-finished-app.png) +![Finished chat assistant project](/framework/images/tutorial/chat/chat_assistant_1.png) ## Setting up your project ### Creating a Writer app and getting your API key -From the Home screen, click on Build an app. +From the Home screen, click on **Build an app**. -![Writer home screen](/framework/images/tutorial/home.png) +![Writer home screen](/framework/images/tutorial/chat/chat_assistant_2.png) Select Framework as the app type you’d like to create, enabling you to generate keys and build your app with the Writer Framework. -![App type selection](/framework/images/tutorial/app-selection.png) +![App type selection](/framework/images/tutorial/chat/chat_assistant_3.png) -On the next screen, you can edit your Writer application name in the upper left. Underneath “Authenticate with an API key,” click on “Reveal” to see and copy your API key. +On the next screen, you can edit your Writer application name in the upper left. Underneath “Authenticate with an API key,” click on **Reveal** to see and copy your API key. ### Creating the application Next, open your terminal and navigate to the directory where you want to create your application directory. -To pass your API key to Writer Framework, you will need to set an environment variable called `WRITER_API_KEY`. One simple way to do this is by exporting the variable for your terminal session. On Mac and Linux, you can run the following command, replacing `key` with your API key: + + + To pass your API key to the Writer Framework, you need to set an environment variable called `WRITER_API_KEY`. One simple way to do this is by exporting the variable for your terminal session. + + ```sh On macOS/Linux + export WRITER_API_KEY=[key] + ``` -``` -export WRITER_API_KEY=[key] -``` - - -On Windows, use the following: + ```sh On Windows + set WRITER_API_KEY=[key] + ``` + + + + Run the following command to create your application, replacing `chat-assistant` with your desired project name and `ai-starter` with the template you want to use: + ```bash + writer create chat-assistant --template=ai-starter + ``` -``` -set WRITER_API_KEY=[key] -``` + This command sets up a new project called `chat-assistant` in the specified directory. + + + To edit your project, run the below commands. This will bring up the console, where Framework-wide messages and errors will appear, including logs from the API. By default, the Writer Framework Builder is accessible at `localhost:3006`. If that port is in use, you can specify a different port. Open this address in your browser to view your default application setup. + + ```bash Standard port + writer edit chat-assistant + ``` -To create the application, run the following command: + ```bash Custom port + writer edit chat-assistant –port=3007 + ``` + - -``` -writer create chat-assistant --template=ai-starter -``` - - -This command will set up a new project called `chat-assistant` in the specified directory using a template called `ai-starter`. To edit your project, run this command: - - -``` -writer edit chat-assistant -``` + + -This will bring up the console, where Framework-wide messages and errors will appear, including logs from the API. - -By default, the Writer Framework Builder is accessible at `localhost:3006`. If that port is in use, run the `edit` command again with the `port` flag to specify your desired port: - - -``` -writer edit chat-assistant –port=3007 -``` - - -Open this address in your browser to view your default application setup. - ## Creating the UI @@ -84,54 +80,60 @@ wf.init_state({ }) ``` -Click the provided Section component to open its Component Settings and clear out the default title. If you’d like to provide any other instructions or context to the user, you can also drag a Text component into the section. +Click the provided Section component to open its Component settings and clear out the default title. If you’d like to provide any other instructions or context to the user, you can also drag a Text component into the section. Finally, drag a Chatbot component into the Section beneath the Text box. -![Initial UI with text and chatbot](/framework/images/tutorial/chat-initial-ui.png) +![Initial UI with text and chatbot](/framework/images/tutorial/chat/chat_assistant_4.png) ## Updating the code -With the UI built, you can now update your code. +With the UI built, you can now update your code to add chat functionality. -To add chat functionality, first initialize your application state by clearing any default-generated state and adding a `conversation` property set to `writer.ai.Conversation()`. Update the `initial_state` with the following: + + + First, clear any default-generated state and add a `conversation` property set to `writer.ai.Conversation()`. Update your `initial_state` as follows: -```python -wf.init_state({ - // Other state elements above - "conversation": writer.ai.Conversation() -}) -``` + ```python + wf.init_state({ + // Other state elements above + "conversation": writer.ai.Conversation() + }) + ``` -The `Conversation` method can optionally accept a dictionary or a content prompt (e.g. “You are a social media expert in the financial services industry”), but you can also leave it empty to use the defaults. + The `Conversation` method can optionally accept a dictionary or a content prompt (e.g., “You are a social media expert in the financial services industry”), but it can also be left empty to use the defaults. + + + Next, create a handler for incoming messages by adding the `handle_simple_message` handler. This method will manage the chat interactions: -Next, create a handler for the Chatbot component by adding the following `handle_simple_message` handler: + ```python + def handle_simple_message(state, payload): + state["conversation"] += payload + + for chunk in state["conversation"].stream_complete(): + state["conversation"] += chunk + ``` -```python -def handle_simple_message(state, payload): - state["conversation"] += payload - - for chunk in state["conversation"].stream_complete(): - state["conversation"] += chunk -``` + This code uses the streaming function of the `Conversation` method, which is a wrapper for the `chat` API endpoint. Each chunk returned from the stream is added to the `conversation` variable in the application state. + + -The `Conversation` method is a wrapper for the `chat` API endpoint and can be used as a streaming function or a non-streaming function. This code uses the streaming version and adds each chunk that returns from the stream to the conversation variable in the application state. ## Binding to the UI -Click on the chatbot component to open up the Component Settings panel. Bind this chatbot to a conversation variable by adding `@{conversation}` in the Conversation Object property under General. This variable will reference the Writer AI SDK. You can also update properties such as the assistant's initials, the user's initials, and whether the chat uses markdown. +Click on the **chatbot component** to open up the Component settings panel. Bind this chatbot to a conversation variable by adding `@{conversation}` in the Conversation Object property under General. This variable will reference the Writer AI SDK. You can also update properties such as the assistant's initials, the user's initials, and whether the chat uses markdown. -Chatbot conversation object setting +![Finished chat assistant project](/framework/images/tutorial/chat/chat_assistant_5.png) -Finally, attach the handler to the chatbot. In the User Interface, click on the chatbot component to bring up the Component Settings panel. Scroll to the Events section towards the bottom of the pane and choose the `handle_simple_message` handler for the `wf-chatbot-message` event. +Finally, attach the handler to the chatbot. In the User Interface, click on the **chatbot component** to bring up the Component settings panel. Scroll to the Events section towards the bottom of the pane and choose the `handle_simple_message` handler for the `wf-chatbot-message` event. -Chatbot event handler settings +![Finished chat assistant project](/framework/images/tutorial/chat/chat_assistant_6.png) After saving and running your code, click the preview button and type something into your chat assistant. You should see the response appear on the screen as it comes back from the assistant. Congratulations! -![Finished chat assistant project](/framework/images/tutorial/chat-finished-app.png) +![Finished chat assistant project](/framework/images/tutorial/chat/chat_assistant_7.png) ## Deploying the application @@ -144,9 +146,9 @@ writer deploy chat-assistant ``` -Once the application has been deployed, the CLI will return with the URL of your live application. +Once the application is deployed, the CLI will return with the URL of your live application. ## Conclusion -That's all it takes to set up a basic application with the Writer platform. This setup not only demonstrates the platform's capabilities but also provides a foundation on which you can build more complex applications. To learn more, explore the rest of the Writer Framework documentation and the API documentation. \ No newline at end of file +That's all it takes to set up a basic application with the Writer Framework. This setup not only demonstrates the platform's capabilities, but also provides a foundation on which you can build more complex applications. To learn more, explore the rest of the Writer Framework documentation and the API documentation. \ No newline at end of file diff --git a/docs/framework/component-list-link.mdx b/docs/framework/component-list-link.mdx index ff5bafa6b..f261c1a44 100644 --- a/docs/framework/component-list-link.mdx +++ b/docs/framework/component-list-link.mdx @@ -1,4 +1,4 @@ --- title: "Components" -url: "https://writer.mintlify.app//components/column" +url: "https://dev.writer.com/components/column" --- diff --git a/docs/framework/custom-components.mdx b/docs/framework/custom-components.mdx index e30f57e2a..7b092319e 100644 --- a/docs/framework/custom-components.mdx +++ b/docs/framework/custom-components.mdx @@ -8,36 +8,36 @@ They're developed using Vue 3 and TypeScript. Once transpiled, they can be used Custom components behave exactly like built-in ones. -They are just as performant, can contain other components, and offer the same Builder experience. They only differ from built-in components in the way that they're bundled and imported. +They are just as performant, can contain other components, and offer the same the Builder experience. They only differ from built-in components in the way that they're bundled and imported. ## Architecture -Framework frontend compiles to a collection of static assets that is distributed in the Python package. These static assets are then served via FastAPI. +Framework front-end compiles to a collection of static assets that is distributed in the Python package. These static assets are then served via FastAPI. During initialisation time, the server scans the `extensions/` folder in the project folder and looks for `.css` and `.js` files. This folder is also served, similarly to `static/`. If it finds any valid files in `extensions/`, it shares the list with clients and tells them to dynamically import these files during runtime. -_Extensions_ and _custom templates_ are currently synonyms, but this might change in order to accommodate other extension capabilities. +Extensions and custom templates are currently synonyms, but this might change in order to accommodate other extension capabilities. -![Custom Components - Architecture](./images/custom-components.architecture.png) +![Custom Components - Architecture](/framework/images/custom-components.architecture.png) -Dependencies are [_provided_](https://vuejs.org/api/composition-api-dependency-injection.html) using injection symbols and can be _injected_ to be used by the component template. These include `evaluatedFields`, which contain the current values of the editable fields. Injected dependencies are fully typed, making development easier. +Dependencies are [provided](https://vuejs.org/api/composition-api-dependency-injection.html) using injection symbols and can be _injected_ to be used by the component template. These include `evaluatedFields`, which contain the current values of the editable fields. Injected dependencies are fully typed, making development easier. -[Rollup's `external` feature](https://rollupjs.org/configuration-options/#external), invoked via Vite, allows for extensions to be compiled without dependencies and link those during runtime. Therefore, extensions aren't bundled to be standalone, but rather to work as a piece of a puzzle. +[Rollup's external feature](https://rollupjs.org/configuration-options/#external), invoked via Vite, allows for extensions to be compiled without dependencies and link those during runtime. Therefore, extensions aren't bundled to be standalone, but rather to work as a piece of a puzzle. -![Custom Components - External](./images/custom-components.external.png) +![Custom Components - External](/framework/images/custom-components.external.png) ## Anatomy of a template A template defines how a certain component is rendered. For example, `corebutton` defines how _Button_ components are rendered. -Framework component templates are purely frontend-based. **They are Vue 3 templates that extend the Vue specification** via a [custom option](https://vuejs.org/api/utility-types.html#componentcustomoptions), `writer`. This _custom option_ defines all the Framework-specific behaviour of the component. For example, its `fields` property establishes which fields will be editable via Builder. +Framework component templates are purely front-end. They are Vue 3 templates that extend the Vue specification via a [custom option](https://vuejs.org/api/utility-types.html#componentcustomoptions), `writer`. This custom option defines all the Framework-specific behaviour of the component. For example, its `fields` property establishes which fields will be editable via the Builder. ### Simple example This example shows a template for _Bubble Message_, a simple demo component with one editable field, `text`. -```vue +```js
Name TypeDescriptionDescription Options