diff --git a/docs/framework/ai-module.mdx b/docs/framework/ai-module.mdx index 25db2330..a7d2f799 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,35 +47,39 @@ 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. ### 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 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. @@ -78,12 +98,6 @@ 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: ```python diff --git a/docs/framework/application-state.mdx b/docs/framework/application-state.mdx index de93325f..50b65383 100644 --- a/docs/framework/application-state.mdx +++ b/docs/framework/application-state.mdx @@ -6,7 +6,11 @@ Each session is assigned a unique application state by the Framework. ## 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 @@ -58,6 +62,31 @@ To keep certain state elements private (back-end-only), prefix them with an unde These elements remain in the back-end and cannot be accessed from the Builder. +## Managing files and binary data + +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 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 + +# Initialize state with various data types +wf.init_state({ + # Reference a file by its filesystem path + "sales_spreadsheet": wf.pack_file("sales_spreadsheet.xlsx"), + + # Use a file-like object that implements a .read() method + "main_image": wf.pack_file(image_file, mime_type="image/jpeg"), + + # Convert raw bytes specifying a MIME type + "my_bytes": wf.pack_bytes(b"\x31\x33\x33\x37", mime_type="text/plain"), + + # Directly assign raw bytes without a MIME type + "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. @@ -84,29 +113,3 @@ The front-end cannot directly display complex data types such as Pandas datafram Pandas dataframes are converted to JSON and can be used in _Dataframe_ components. - - -## Managing files and binary data - -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 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 - -# Initialize state with various data types -wf.init_state({ - # Reference a file by its filesystem path - "sales_spreadsheet": wf.pack_file("sales_spreadsheet.xlsx"), - - # Use a file-like object that implements a .read() method - "main_image": wf.pack_file(image_file, mime_type="image/jpeg"), - - # Convert raw bytes specifying a MIME type - "my_bytes": wf.pack_bytes(b"\x31\x33\x33\x37", mime_type="text/plain"), - - # Directly assign raw bytes without a MIME type - "my_raw_bytes": b"\x31\x33\x33\x37", -}) -``` diff --git a/docs/framework/backend-initiated-actions.mdx b/docs/framework/backend-initiated-actions.mdx index 5867571b..507af491 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 511842f3..78489d42 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,14 +95,33 @@ 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. @@ -124,18 +129,7 @@ Just like with changes to settings, these operations can be undone and redone. 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. -### 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 - -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/component-list-link.mdx b/docs/framework/component-list-link.mdx index ff5bafa6..2860b4d7 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://writer.mintlify.app/components/column" --- diff --git a/docs/framework/custom-components.mdx b/docs/framework/custom-components.mdx index 529f33fc..7b092319 100644 --- a/docs/framework/custom-components.mdx +++ b/docs/framework/custom-components.mdx @@ -17,27 +17,27 @@ Framework front-end compiles to a collection of static assets that is distribute 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 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. +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