<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rocky LIU Yan</title>
    <description>The latest articles on DEV Community by Rocky LIU Yan (@rockfire).</description>
    <link>https://dev.to/rockfire</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1481849%2Fef98a0f5-b8de-4125-a2a5-e8e407cbf879.jpg</url>
      <title>DEV Community: Rocky LIU Yan</title>
      <link>https://dev.to/rockfire</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rockfire"/>
    <language>en</language>
    <item>
      <title>AI Elements: PromptInput Component Design and Testing Framework</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Tue, 30 Dec 2025 05:49:04 +0000</pubDate>
      <link>https://dev.to/rockfire/ai-elements-promptinput-component-design-and-testing-framework-gma</link>
      <guid>https://dev.to/rockfire/ai-elements-promptinput-component-design-and-testing-framework-gma</guid>
      <description>&lt;p&gt;Within the broader context of the "AI Elements and Testing Library Core Knowledge System," the sources categorize the PromptInput component across three dimensions: design philosophy, functional architecture, and user-centric testing strategies.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI Elements Perspective: A Highly Flexible Compound Interaction System
From the perspective of AI Elements, PromptInput is not merely a simple text box but a complex form system specifically designed for Large Language Model (LLM) interactions.
• Compound Component Pattern: This component utilizes a flexible composition of sub-components, including PromptInputTextarea, PromptInputSubmit, and PromptInputAttachments. This allows developers to customize UI layouts for diverse needs, such as chatbots or code generation tools.
• Dual-Mode State Management: The sources highlight support for both "self-managed" (local state) and "provider-managed" (lifted state) modes . This design allows it to function as a standalone component or coordinate with complex external business logic (like model selectors or web search toggles) via the PromptInputProvider .
• Addressing AI-Specific Pain Points:
◦ IME Composition Handling: To address issues with input methods like Japanese (Issue #21), the component identifies the isComposing state to prevent accidental submissions before a character is finalized .
◦ Race Condition Prevention: When processing asynchronous file conversions (Blob to Data URL), the system prevents data loss by capturing the current text and resetting the form immediately .&lt;/li&gt;
&lt;li&gt;Testing Library Perspective: Semantic and Accessibility-Based Validation
The core principle of the Testing Library is that "tests should simulate how users interact with the code as much as possible" . Applying this to PromptInput, the sources emphasize the following validation logic:
• Prioritize Semantic Queries: Testing should follow a query hierarchy.
◦ getByRole: This is the preferred method for locating buttons (submit, attachments) and inputs, ensuring the UI is friendly to assistive technologies like screen readers .
◦ getByLabelText: Since PromptInput is essentially a form system, locating the input via its label is the best way to simulate real user behavior .
• Asynchronous Behavior Handling: Given that AI responses involve streaming states or file uploads, tests utilize asynchronous APIs like findBy... or waitFor to track DOM changes, such as the submit button icon switching from "loading" to "send" .
• Avoid Non-Semantic Queries: The sources explicitly discourage testing via classes or IDs (e.g., querySelector) because these are invisible to the user. testId should only be used as a last resort .&lt;/li&gt;
&lt;li&gt;The Intersection: Test-Driven Interaction Quality
The PromptInput test suite (e.g., prompt-input.test.tsx) represents the convergence of these two knowledge systems .
• Full Scenario Coverage: Tests go beyond basic rendering to cover advanced interactions like file validation (max count, size, type limits), drag-and-drop (global and local), and pasting files from the clipboard .
• State and Icon Mapping: The PromptInputSubmit component automatically switches icons based on the AI SDK status (e.g., submitted maps to a loading animation, while streaming maps to a stop square) . Tests verify the state machine by asserting the correct roles or text are present.
• Environment Mocking: To function in a test environment, browser-specific APIs—such as the Web Speech API (for voice recognition buttons) and the Clipboard API—must be mocked .&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Analogy for Understanding: If AI Elements (PromptInput) is a high-performance off-road vehicle equipped with complex power distribution systems (dual-mode state) and specialized parts for rough terrain (IME handling, file systems), then the Testing Library is a rigorous vehicle inspection standard. It doesn't care about the specific screw sizes under the hood (internal implementation/IDs/Classes); it only cares if the car moves forward when you hit the gas (user interaction) and if the dashboard is legible to everyone, including those with visual impairments (accessibility queries). Only by passing this "simulated real-world driving" test is the vehicle considered safe and reliable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vercel/ai-elements/blob/f0625b5ef32564067292661341f63cfe2d7432cb/packages/elements/src/prompt-input.tsx#L618" rel="noopener noreferrer"&gt;https://github.com/vercel/ai-elements/blob/f0625b5ef32564067292661341f63cfe2d7432cb/packages/elements/src/prompt-input.tsx#L618&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ai-sdk.dev/elements/examples/chatbot" rel="noopener noreferrer"&gt;https://ai-sdk.dev/elements/examples/chatbot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://deepwiki.com/vercel/ai-elements/4.1-promptinput-component" rel="noopener noreferrer"&gt;https://deepwiki.com/vercel/ai-elements/4.1-promptinput-component&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://testing-library.com/docs/queries/about/#screen" rel="noopener noreferrer"&gt;https://testing-library.com/docs/queries/about/#screen&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aichat</category>
    </item>
    <item>
      <title>Ingesting Data in F# with Aether: A Practical Guide to Using Lenses, Prisms, and Morphisms</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Wed, 18 Dec 2024 08:49:08 +0000</pubDate>
      <link>https://dev.to/rockfire/simplifying-data-manipulation-in-net-f-with-aether-a-practical-guide-to-using-lenses-prisms-5092</link>
      <guid>https://dev.to/rockfire/simplifying-data-manipulation-in-net-f-with-aether-a-practical-guide-to-using-lenses-prisms-5092</guid>
      <description>&lt;p&gt;In the world of functional programming, dealing with immutable and deeply nested data structures can quickly become cumbersome. Without the right tools, these data structures require complex, repetitive code for accessing and modifying their values. &lt;strong&gt;Aether&lt;/strong&gt; is a powerful .NET library that addresses these challenges by providing &lt;strong&gt;Lenses&lt;/strong&gt;, &lt;strong&gt;Prisms&lt;/strong&gt;, and &lt;strong&gt;Morphism&lt;/strong&gt; tools to streamline data manipulation. This guide will walk you through the basics of Aether, including how to use its key concepts effectively, along with practical examples to get you started.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Aether?
&lt;/h3&gt;

&lt;p&gt;Aether simplifies working with immutable data and deeply nested structures. It provides a set of tools that help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access and modify deeply nested data with minimal boilerplate code.&lt;/li&gt;
&lt;li&gt;Work with uncertain or variant data types safely (e.g., &lt;code&gt;Option&lt;/code&gt; or &lt;code&gt;Result&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Create more declarative and readable code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By leveraging &lt;strong&gt;Lenses&lt;/strong&gt;, &lt;strong&gt;Prisms&lt;/strong&gt;, and &lt;strong&gt;Morphism&lt;/strong&gt;, Aether lets you focus on the logic of your application without being bogged down by repetitive data access patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;To start using Aether in your .NET project, simply install the package via NuGet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Aether
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Concepts in Aether
&lt;/h3&gt;

&lt;p&gt;Before diving into examples, let’s briefly explain the core concepts you'll be working with in Aether:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lenses&lt;/strong&gt;: Lenses allow you to focus on a specific part of a data structure (like a field in a tuple or a record). They provide functions for getting and setting values within a structure without needing to manually handle the nested fields.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prisms&lt;/strong&gt;: Prisms are used to handle data that can have multiple shapes, like &lt;code&gt;Option&lt;/code&gt; or &lt;code&gt;Either&lt;/code&gt; types. They offer a safe way to access values inside these types, while handling the possibility of absence or error cases gracefully.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Morphism&lt;/strong&gt;: Morphism refers to transformations that allow you to map or modify values across different data structures or types. It's useful for applying a function to elements inside a collection or converting between different shapes of data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Code
&lt;/h3&gt;

&lt;p&gt;Here’s a practical example of using Aether to manipulate various data types in a functional way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;Aether&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Aether&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Operators&lt;/span&gt;

&lt;span class="c1"&gt;// Define a tuple type for Point&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;

&lt;span class="c1"&gt;// Create a Point tuple (X and Y coordinates)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// X=10, Y=20&lt;/span&gt;

&lt;span class="c1"&gt;// Use fst_ lens to set and get the first element of the Point tuple (X coordinate)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;newX&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;updatedP&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;fst_&lt;/span&gt; &lt;span class="n"&gt;newX&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="c1"&gt;// Updated Point: (5.0, 20.0)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;xValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;fst_&lt;/span&gt; &lt;span class="n"&gt;updatedP&lt;/span&gt; &lt;span class="c1"&gt;// Get the updated X coordinate: 5.0&lt;/span&gt;

&lt;span class="c1"&gt;// Convert a list to an array&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fst&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array_&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt; &lt;span class="c1"&gt;// Using the first function to convert to an array&lt;/span&gt;

&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"array = %A"&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;

&lt;span class="c1"&gt;// Convert the array back to a list&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;list'&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;snd&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array_&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="c1"&gt;// Using the second function to convert back to a list&lt;/span&gt;

&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"list' = %A"&lt;/span&gt; &lt;span class="n"&gt;list'&lt;/span&gt;

&lt;span class="c1"&gt;// Create a list of integers&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;intList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// Use List.head_ prism to get the first element of the list&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;headValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head_&lt;/span&gt; &lt;span class="n"&gt;intList&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;

&lt;span class="c1"&gt;// Use List.tail_ prism to get the remaining part of the list&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tailList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tail_&lt;/span&gt; &lt;span class="n"&gt;intList&lt;/span&gt; &lt;span class="c1"&gt;// [2; 3]&lt;/span&gt;

&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"tailList = %A"&lt;/span&gt; &lt;span class="n"&gt;tailList&lt;/span&gt;

&lt;span class="c1"&gt;// Create a Map&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofList&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="s2"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// Use Map.key_ prism to get the value for a specific key&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;keyValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key_&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;

&lt;span class="c1"&gt;// Update a specific key's value in the Map&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;updatedMap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key_&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="c1"&gt;// map ["a", 1; "b", 5; "c", 3]&lt;/span&gt;

&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"updatedMap = %A"&lt;/span&gt; &lt;span class="n"&gt;updatedMap&lt;/span&gt;

&lt;span class="c1"&gt;// Define an Option type&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;optionValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt;

&lt;span class="c1"&gt;// Use Option.value_ prism to get the value inside the Option&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;valueOptic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="nn"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_&lt;/span&gt; &lt;span class="n"&gt;optionValue&lt;/span&gt; &lt;span class="c1"&gt;// "Hello World"&lt;/span&gt;
&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"The value is: %A"&lt;/span&gt; &lt;span class="n"&gt;valueOptic&lt;/span&gt;

&lt;span class="c1"&gt;// Update the value inside the Option&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;updatedOptionValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Optic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="nn"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_&lt;/span&gt; &lt;span class="s2"&gt;"Hello Aether!"&lt;/span&gt; &lt;span class="n"&gt;optionValue&lt;/span&gt; &lt;span class="c1"&gt;// Some "Hello Aether!"&lt;/span&gt;

&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"The updated value is: %A"&lt;/span&gt; &lt;span class="n"&gt;updatedOptionValue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array = [|1; 2; 3|]
list' = [1; 2; 3]
tailList = Some [2; 3]
updatedMap = map [("a", 1); ("b", 5); ("c", 3)]
The value is: Some "Hello World"
The updated value is: Some "Hello Aether!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation of Key Operations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;fst_&lt;/code&gt; and &lt;code&gt;snd_&lt;/code&gt;&lt;/strong&gt;: These are lenses that focus on the first and second elements of a tuple, respectively. With these lenses, you can access or modify specific parts of a tuple without breaking its structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;List.head_&lt;/code&gt; and &lt;code&gt;List.tail_&lt;/code&gt;&lt;/strong&gt;: These are prisms that focus on the head (first element) and tail (remaining elements) of a list. They are useful for working with lists where the first element may be present or absent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;Map.key_&lt;/code&gt;&lt;/strong&gt;: This is a prism used to focus on a specific key in a &lt;code&gt;Map&lt;/code&gt;. It allows you to access or update values associated with that key in a functional way.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;Option.value_&lt;/code&gt;&lt;/strong&gt;: This is a prism used to focus on the value inside an &lt;code&gt;Option&lt;/code&gt; (such as &lt;code&gt;Some&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt;). It enables you to safely access or update the value, while handling cases where the value might be absent.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Use Aether?
&lt;/h3&gt;

&lt;p&gt;Aether offers a clean, functional approach to managing data in .NET, especially when you're dealing with complex or immutable structures. Here are some reasons to consider using Aether:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clarity and Declarative Code&lt;/strong&gt;: Aether's use of Lenses, Prisms, and Morphisms allows for more readable and declarative code when manipulating data structures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less Boilerplate&lt;/strong&gt;: Instead of writing manual functions for accessing and updating nested data, you can use Aether's built-in tools to simplify the process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong Functional Principles&lt;/strong&gt;: Aether aligns well with functional programming principles, allowing you to handle immutable data and complex transformations in a more predictable way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real-World Use Cases
&lt;/h3&gt;

&lt;p&gt;While the examples above are simple, Aether shines in more complex scenarios. For instance, imagine you have deeply nested JSON-like data or a complex domain model where accessing and modifying specific fields is error-prone and repetitive. Aether’s tools help you focus on the task at hand while abstracting away the boilerplate code involved in data manipulation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Aether provides a concise and functional way to manipulate data in .NET, especially when dealing with complex or immutable data structures. By utilizing &lt;strong&gt;Lenses&lt;/strong&gt;, &lt;strong&gt;Prisms&lt;/strong&gt;, and &lt;strong&gt;Morphism&lt;/strong&gt;, you can make your code more readable, maintainable, and less error-prone. If you often find yourself writing repetitive code to access or update data, Aether might be the right tool to simplify your workflow.&lt;/p&gt;

&lt;p&gt;To get the most out of Aether, explore the official documentation and check out some advanced patterns. If you're working with other functional libraries like &lt;a href="https://github.com/fsprojects/FsToolkit.ErrorHandling" rel="noopener noreferrer"&gt;FsToolkit.ErrorHandling&lt;/a&gt;, Aether integrates seamlessly with them to provide even more flexibility.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>fsharp</category>
      <category>lambda</category>
    </item>
    <item>
      <title>.NET Cross-Platform Web Desktop App Frameworks as Electron Alternatives</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Wed, 18 Dec 2024 06:07:58 +0000</pubDate>
      <link>https://dev.to/rockfire/net-cross-platform-web-desktop-app-framework-to-replace-electron-1np2</link>
      <guid>https://dev.to/rockfire/net-cross-platform-web-desktop-app-framework-to-replace-electron-1np2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The main goal is to replace Electron. After trying many similar projects, I ultimately selected two representative open-source projects to introduce to everyone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Comparative Analysis: &lt;strong&gt;OutSystems WebView&lt;/strong&gt; vs &lt;strong&gt;Photino.Blazor&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When developing modern desktop applications, developers often choose WebView technology to embed web pages or use web technologies to build applications. This article compares two open-source projects: &lt;strong&gt;OutSystems WebView&lt;/strong&gt; and &lt;strong&gt;Photino.Blazor&lt;/strong&gt;, both of which provide the ability to embed web content in desktop applications, but differ in their implementation approaches and target platforms.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Project Background
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OutSystems WebView&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Link&lt;/strong&gt;: &lt;a href="https://github.com/OutSystems/WebView" rel="noopener noreferrer"&gt;OutSystems WebView&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: OutSystems WebView is a component based on the .NET technology stack, designed to embed web pages in desktop applications. It provides a cross-platform WebView implementation that supports both Windows and macOS. Its primary goal is to enable developers to easily display and interact with web content within desktop applications while integrating with native functionalities.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Photino.Blazor&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Link&lt;/strong&gt;: &lt;a href="https://github.com/tryphotino/photino.Blazor" rel="noopener noreferrer"&gt;Photino.Blazor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: Photino is a lightweight desktop application framework that allows developers to build native applications using web technologies (HTML, CSS, JavaScript). Photino.Blazor is a support library for integrating Blazor (a .NET-based web framework) into Photino, enabling developers to build cross-platform desktop applications. Unlike traditional frameworks like Electron or NW.js, Photino uses a native WebView implementation, aiming to provide a smaller, more efficient desktop application.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  2. Technical Comparison
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;OutSystems WebView&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Photino.Blazor&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Framework Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;.NET (cross-platform, supports macOS and Windows)&lt;/td&gt;
&lt;td&gt;Blazor (based on .NET)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main Functionality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Embed web content in desktop applications, support for native code integration&lt;/td&gt;
&lt;td&gt;Build cross-platform native desktop apps using web technologies with Blazor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Platform Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Windows, macOS&lt;/td&gt;
&lt;td&gt;Windows, macOS, Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on Chromium or WebKit engines, relatively heavy&lt;/td&gt;
&lt;td&gt;Lightweight, based on native WebView, optimized for performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Development Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Primarily for enterprise-level applications and large projects&lt;/td&gt;
&lt;td&gt;Ideal for developers who want to use Blazor for cross-platform apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;External Dependencies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on .NET and WebView components&lt;/td&gt;
&lt;td&gt;Depends on .NET Core and WebView (Chromium or WebKit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User Interface&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Flexible, can use web technologies (HTML/CSS/JS)&lt;/td&gt;
&lt;td&gt;Fully integrated with Blazor, supports UI design with C# and HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open Source License&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MIT License&lt;/td&gt;
&lt;td&gt;MIT License&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  3. Features and Characteristics
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OutSystems WebView&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native Functionality Integration&lt;/strong&gt;: The project is designed to embed web content in native applications, enabling developers to access native OS functionalities such as file systems, notifications, and system resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Platform Support&lt;/strong&gt;: Supports Windows and macOS, leveraging .NET as the development framework, making it easier for enterprise developers to integrate WebView into existing tech stacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-Level Applications&lt;/strong&gt;: OutSystems WebView is more suited for enterprise-level applications and projects that require extensive integration with native functionality.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Photino.Blazor&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight&lt;/strong&gt;: Compared to Electron and other traditional frameworks, Photino is designed to offer a smaller, faster solution for desktop application development. It has a much smaller footprint and lower memory usage, making it ideal for lightweight desktop applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blazor Support&lt;/strong&gt;: Through Photino.Blazor, developers can directly use Blazor to build desktop applications, which is particularly attractive for C# developers. Blazor’s component-based approach allows developers to design UIs using familiar technologies and seamlessly integrate server-side logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform Support&lt;/strong&gt;: In addition to Windows and macOS, Photino.Blazor supports Linux, expanding its cross-platform capabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  4. Use Cases
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OutSystems WebView&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suitable for development teams already using OutSystems or .NET-based tech stacks.&lt;/li&gt;
&lt;li&gt;Ideal for enterprise-level applications that require strong native functionality and stability.&lt;/li&gt;
&lt;li&gt;Perfect for embedding existing web applications or web pages into desktop environments.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Photino.Blazor&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perfect for developers looking to build cross-platform desktop applications using Blazor and .NET technologies.&lt;/li&gt;
&lt;li&gt;Well-suited for lightweight, performance-focused desktop applications that don’t require large frameworks like Electron.&lt;/li&gt;
&lt;li&gt;Ideal for rapidly developing desktop applications that need to run on Windows, macOS, and Linux.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  5. Pros and Cons Analysis
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OutSystems WebView&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Strong support for native functionality and deep integration.&lt;/li&gt;
&lt;li&gt;Enterprise-level support and easy integration with .NET environments.&lt;/li&gt;
&lt;li&gt;Good cross-platform support, especially for embedding web applications into desktop environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Heavier compared to Photino, relying on more external libraries.&lt;/li&gt;
&lt;li&gt;Performance may not be as lightweight as Photino.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Photino.Blazor&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Lightweight, ideal for building fast and efficient applications.&lt;/li&gt;
&lt;li&gt;Perfectly integrated with Blazor, making it a great choice for C# developers.&lt;/li&gt;
&lt;li&gt;Shorter development cycles, enabling quick deployment of cross-platform desktop applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Compared to more established solutions like Electron, its community support and ecosystem are relatively smaller.&lt;/li&gt;
&lt;li&gt;More suited for lightweight applications; complex applications may require more flexibility than what Photino offers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  6. Conclusion
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OutSystems WebView&lt;/strong&gt; is better suited for developers who need strong native functionality integration, cross-platform support, and enterprise-grade applications. It relies on the .NET tech stack and offers deep integration with native OS features, making it ideal for large-scale, stable projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Photino.Blazor&lt;/strong&gt; is better for developers who want to quickly develop lightweight, cross-platform desktop applications using Blazor and .NET technologies. Its small size and fast performance make it ideal for building rapid, efficient applications without the overhead of heavier frameworks like Electron.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The choice between the two frameworks depends on the specific requirements of the project, the existing technology stack, and the developer’s preferred tools. If the goal is to build an enterprise-grade, highly integrated application with native features, &lt;strong&gt;OutSystems WebView&lt;/strong&gt; would be the better choice. On the other hand, if you are looking for a lightweight, performant solution for developing cross-platform desktop apps with Blazor, &lt;strong&gt;Photino.Blazor&lt;/strong&gt; is a promising option.&lt;/p&gt;

</description>
      <category>electron</category>
      <category>dotnet</category>
      <category>avaloniaui</category>
    </item>
    <item>
      <title>Implementing Full Transparency No Frame and Acrylic Effects in Avalonia UI</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Wed, 18 Dec 2024 05:11:41 +0000</pubDate>
      <link>https://dev.to/rockfire/implementing-transparency-and-acrylic-effects-in-avalonia-ui-5e2p</link>
      <guid>https://dev.to/rockfire/implementing-transparency-and-acrylic-effects-in-avalonia-ui-5e2p</guid>
      <description>&lt;p&gt;Avalonia UI offers powerful capabilities for creating modern, visually appealing applications with transparency and acrylic (blur) effects. In this post, we'll explore how to implement these effects in your Avalonia applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Basics
&lt;/h2&gt;

&lt;p&gt;There are two main types of transparency effects we can achieve in Avalonia UI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Acrylic (blur) effect - similar to frosted glass&lt;/li&gt;
&lt;li&gt;Full transparency - completely transparent window frame&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Acrylic (Blur) Effect
&lt;/h3&gt;

&lt;p&gt;To create a window with an acrylic blur effect, use the following XAML code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Window ExtendClientAreaChromeHints="NoChrome"
        TransparencyLevelHint="AcrylicBlur"
        Background="Transparent"
        ExtendClientAreaToDecorationsHint="True"&amp;gt;
    &amp;lt;!-- Your content here --&amp;gt;
&amp;lt;/Window&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Full Transparency
&lt;/h3&gt;

&lt;p&gt;For a fully transparent window, modify the &lt;code&gt;TransparencyLevelHint&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Window ExtendClientAreaChromeHints="NoChrome"
        TransparencyLevelHint="Transparent"
        Background="Transparent"
        ExtendClientAreaToDecorationsHint="True"&amp;gt;
    &amp;lt;!-- Your content here --&amp;gt;
&amp;lt;/Window&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Properties Explained
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ExtendClientAreaChromeHints="NoChrome"&lt;/code&gt;: Removes the default window chrome&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TransparencyLevelHint&lt;/code&gt;: Specifies the type of transparency

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AcrylicBlur&lt;/code&gt;: Creates a frosted glass effect&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Transparent&lt;/code&gt;: Makes the window fully transparent&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;Background="Transparent"&lt;/code&gt;: Sets the window background to transparent&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;ExtendClientAreaToDecorationsHint="True"&lt;/code&gt;: Extends the client area to include window decorations&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Consider performance implications when using transparency&lt;/li&gt;
&lt;li&gt;Test on different operating systems as effects may vary&lt;/li&gt;
&lt;li&gt;Ensure content remains readable with transparent backgrounds&lt;/li&gt;
&lt;li&gt;Use appropriate contrast for better user experience&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing transparency and acrylic effects in Avalonia UI is straightforward and can significantly enhance your application's visual appeal. Choose the appropriate effect based on your application's needs and performance requirements.&lt;/p&gt;

&lt;p&gt;Remember that these effects might behave differently across various platforms and operating systems, so always test thoroughly on your target platforms.&lt;/p&gt;

&lt;h1&gt;
  
  
  avalonia #ui #dotnet #desktop #development
&lt;/h1&gt;

</description>
      <category>avaloniaui</category>
      <category>dotnet</category>
      <category>wpf</category>
    </item>
    <item>
      <title>Unlocking High-Performance AI Computing with F#: A Comprehensive Guide</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Tue, 03 Dec 2024 01:36:07 +0000</pubDate>
      <link>https://dev.to/rockfire/unlocking-high-performance-computing-with-f-a-comprehensive-guide-53n2</link>
      <guid>https://dev.to/rockfire/unlocking-high-performance-computing-with-f-a-comprehensive-guide-53n2</guid>
      <description>&lt;p&gt;In the world of scientific computing, performance and efficiency are crucial. Whether you’re dealing with large datasets, complex calculations, or high-performance tasks, finding the right tool for the job can make all the difference. Today, we explore how F# stands out as a powerful alternative, combining the simplicity of Python with the performance of .NET, making it an excellent choice for specific high-performance computing tasks.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Why F#? Understanding the Landscape&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When it comes to scientific computing, you often have to balance ease of use with performance. Let’s break down the most common tools used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt;: Loved for its simplicity and readability, Python is a go-to language for many. However, it can struggle with performance, especially in CPU-bound tasks, due to the Global Interpreter Lock (GIL).🐍&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C++&lt;/strong&gt;: This language is known for its speed and control, making it perfect for performance-critical applications. But with its steep learning curve and complex syntax, it’s not always the easiest to work with.📈&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, where does &lt;strong&gt;F#&lt;/strong&gt; come into play?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;F#&lt;/strong&gt; blends the best of both worlds. It combines Python's straightforward syntax with the speed and efficiency of the .NET ecosystem, making it ideal for performance-sensitive applications. 🚀&lt;/li&gt;
&lt;li&gt;It’s cross-platform, statically typed, and supports functional programming, making it easier to write clean, efficient, and maintainable code.✨&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Though Python and C++ are still the go-to choices for most projects, F# offers distinct advantages for specific use cases, particularly in scientific and numerical computing.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Key Features of F# That Set It Apart&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So, why should you consider F# for your next project? Let’s take a closer look at its core features:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Familiar Syntax&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;F# has a syntax that feels familiar to Python developers, making it easy to pick up, especially for those who prefer clean, readable code. It also supports interactive development (REPL), allowing for a seamless, exploratory coding experience.💻&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Strong Typing &amp;amp; Functional Programming&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;One of F#'s biggest strengths is its strong, static typing, which helps catch errors early in the development process. Combined with its emphasis on functional programming, F# is ideal for tasks like mathematical modeling and data analysis, where maintaining accuracy and clarity is key.🧑‍💻&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Integration with .NET Ecosystem&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The .NET ecosystem offers an incredibly powerful set of tools that can elevate your development experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python.NET&lt;/strong&gt;: F# can seamlessly integrate with Python libraries, allowing you to reuse your existing Python code and libraries. 🔗&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ML.NET and ONNX&lt;/strong&gt;: These tools help accelerate machine learning tasks, enabling high-performance inference for models, even in resource-constrained environments.⚡&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradio.NET&lt;/strong&gt;: If you're building interactive user interfaces, Gradio.NET allows you to quickly create cross-platform UIs that are both functional and user-friendly.🎨&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While F# has many benefits, it’s important to note that its ecosystem is still growing, and may not be as extensive as Python’s or C++’s. But for performance-critical and specialized tasks, it’s hard to beat.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;How to Migrate to F# – Step by Step&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you’re considering migrating from Python to F#, here are a few strategies to make the transition smoother:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Leverage Python.NET for a Gradual Migration&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You don’t need to abandon your Python codebase to start using F#. With Python.NET, you can call Python code from F# without breaking your existing projects. Start by migrating performance-sensitive modules and gradually transition your code as you get more comfortable with F#.🔄&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Boost Performance with ML.NET and ONNX&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;For tasks like machine learning inference, F# integrates smoothly with &lt;strong&gt;ML.NET&lt;/strong&gt; and &lt;strong&gt;ONNX&lt;/strong&gt;. These tools can replace Python-based bottlenecks, improving performance significantly—ideal for edge devices or real-time applications.⚡&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Build Cross-Platform UIs with Gradio.NET&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If you’ve been using Python’s Gradio to build UIs, you’ll love &lt;strong&gt;Gradio.NET&lt;/strong&gt;. It allows you to quickly create interactive interfaces that run seamlessly across different platforms, making it easy to showcase your work with minimal effort.🎯&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Code Examples: F# in Action&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here’s a look at some real-world applications of F# in scientific computing and AI:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Calling Python Libraries with Python.NET&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;With &lt;strong&gt;Python.NET&lt;/strong&gt;, you can call Python libraries directly from F#, making it easy to integrate Python’s rich ecosystem into your F# projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Python&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Runtime&lt;/span&gt;
&lt;span class="nn"&gt;PythonEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Initialize&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Py&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"numpy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;([|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|])&lt;/span&gt;
&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"Numpy Array: %A"&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;: This allows you to seamlessly use Python libraries within F#, enabling a gradual migration of your Python code without losing functionality.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Inference with ML.NET and ONNX&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;For high-performance machine learning, &lt;strong&gt;ML.NET&lt;/strong&gt; and &lt;strong&gt;ONNX&lt;/strong&gt; are excellent choices. Here’s an example of how to load a pre-trained ONNX model and perform inference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nn"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ML&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;mlContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MLContext&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mlContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"model.onnx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"Model loaded successfully."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;: This simple code snippet showcases how easy it is to leverage ONNX models for high-performance tasks using F#.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Building a Simple Gradio.NET Interface&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If you want to quickly build interactive UIs, &lt;strong&gt;Gradio.NET&lt;/strong&gt; is an excellent tool. Here’s how you can create a simple text-based interface in no time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;Gradio&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greet&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sprintf&lt;/span&gt; &lt;span class="s2"&gt;"Hello %s"&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;Launch&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;: This code demonstrates how easy it is to create a functional, cross-platform interface in F# using Gradio.NET.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Final Thoughts &amp;amp; Action Plan&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;F# is a powerful, versatile tool that bridges the best of Python’s ease of use with the performance of the .NET ecosystem. It’s especially well-suited for high-performance computing, data analysis, and machine learning tasks, but its ecosystem is still smaller compared to Python or C++.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Action Plan&lt;/strong&gt;:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For Beginners&lt;/strong&gt;: Start by integrating Python.NET to reuse your existing Python code. Gradually explore F# as you become more comfortable.🌱&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For Developers&lt;/strong&gt;: Dive into F# and the .NET toolchain for performance-critical applications and complex scientific tasks.🛠️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore Resources&lt;/strong&gt;: Check out the F# documentation and explore libraries like ML.NET and Gradio.NET for more examples.📚&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro Tip&lt;/strong&gt;: Begin with small-scale experiments and evaluate F#'s effectiveness before scaling it up for larger projects.⚡&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This blog article is designed to provide a clear, engaging, and actionable introduction to using F# for scientific computing. By blending accessible language with technical depth, it aims to both inform and inspire developers to consider F# for their next high-performance project.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>python</category>
      <category>llm</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>How to Use the `ImmutableArray&lt;T&gt;.Builder` Extension Method `ToFrozenDictionary` to Create Efficient Immutable Dictionaries</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Mon, 09 Sep 2024 01:48:03 +0000</pubDate>
      <link>https://dev.to/rockfire/how-to-use-the-immutablearraybuilder-extension-method-tofrozendictionary-to-create-efficient-immutable-dictionaries-4b5a</link>
      <guid>https://dev.to/rockfire/how-to-use-the-immutablearraybuilder-extension-method-tofrozendictionary-to-create-efficient-immutable-dictionaries-4b5a</guid>
      <description>&lt;p&gt;&lt;code&gt;ImmutableArray&amp;lt;T&amp;gt;.Builder&lt;/code&gt; is a class in .NET designed for building immutable arrays (&lt;code&gt;ImmutableArray&amp;lt;T&amp;gt;&lt;/code&gt;). It provides an efficient way to construct immutable arrays without repeatedly creating new instances. In .NET 8, you can use the &lt;code&gt;ToFrozenDictionary&lt;/code&gt; extension method to build a &lt;code&gt;FrozenDictionary&lt;/code&gt; from an &lt;code&gt;ImmutableArray&amp;lt;T&amp;gt;.Builder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ToFrozenDictionary&lt;/code&gt; extension method can be used to convert elements from an &lt;code&gt;ImmutableArray&amp;lt;T&amp;gt;.Builder&lt;/code&gt; instance into an immutable &lt;code&gt;FrozenDictionary&amp;lt;TKey, TValue&amp;gt;&lt;/code&gt;. This method is highly efficient for dictionaries that need frequent read access and will not be modified afterward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;Below is an example of how to use the &lt;code&gt;ToFrozenDictionary&lt;/code&gt; extension method to convert an &lt;code&gt;ImmutableArray&amp;lt;T&amp;gt;.Builder&lt;/code&gt; into a &lt;code&gt;FrozenDictionary&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Immutable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Frozen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create an ImmutableArray Builder&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ImmutableArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"banana"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"cherry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Use ToFrozenDictionary method to convert Builder to FrozenDictionary&lt;/span&gt;
        &lt;span class="n"&gt;FrozenDictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;frozenDict&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToFrozenDictionary&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Access elements in FrozenDictionary&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozenDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;   &lt;span class="c1"&gt;// Output: 1&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozenDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"banana"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;  &lt;span class="c1"&gt;// Output: 2&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozenDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"cherry"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;  &lt;span class="c1"&gt;// Output: 3&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Explanation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create an &lt;code&gt;ImmutableArray&amp;lt;T&amp;gt;.Builder&lt;/code&gt; instance&lt;/strong&gt;: Create a Builder instance for an &lt;code&gt;ImmutableArray&lt;/code&gt; and add key-value pairs to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Call the &lt;code&gt;ToFrozenDictionary&lt;/code&gt; method&lt;/strong&gt;: Use the &lt;code&gt;ToFrozenDictionary&lt;/code&gt; extension method to convert the &lt;code&gt;builder&lt;/code&gt; instance into a &lt;code&gt;FrozenDictionary&amp;lt;TKey, TValue&amp;gt;&lt;/code&gt;. This method converts the content of the &lt;code&gt;ImmutableArray&lt;/code&gt; into an immutable dictionary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access the &lt;code&gt;FrozenDictionary&lt;/code&gt;&lt;/strong&gt;: The &lt;code&gt;FrozenDictionary&lt;/code&gt; provides quick read access, making it suitable for scenarios involving frequent lookups.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Using Custom Key Selector and Equality Comparer
&lt;/h3&gt;

&lt;p&gt;You can specify a custom key selector and an equality comparer when using &lt;code&gt;ToFrozenDictionary&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Immutable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Frozen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ImmutableArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Charlie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;35&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert Builder to FrozenDictionary using custom key selector and equality comparer&lt;/span&gt;
        &lt;span class="n"&gt;FrozenDictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;frozenDict&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToFrozenDictionary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// Key selector&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// Value selector&lt;/span&gt;

        &lt;span class="c1"&gt;// Access elements in FrozenDictionary&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozenDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 30&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozenDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// Output: 25&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;ImmutableArray&amp;lt;T&amp;gt;.Builder&lt;/code&gt; and the &lt;code&gt;ToFrozenDictionary&lt;/code&gt; method, you can efficiently create an immutable and fast-access dictionary, particularly useful in scenarios involving frequent reads but no further modifications to the data structure.&lt;/p&gt;

</description>
      <category>dotnet</category>
    </item>
    <item>
      <title>Introducing F# with Semantic Kernel: Simplifying AI App Development with the Pipeline Pattern</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Thu, 05 Sep 2024 07:15:39 +0000</pubDate>
      <link>https://dev.to/rockfire/introducing-f-with-semantic-kernel-simplifying-ai-app-development-with-the-pipeline-pattern--2b33</link>
      <guid>https://dev.to/rockfire/introducing-f-with-semantic-kernel-simplifying-ai-app-development-with-the-pipeline-pattern--2b33</guid>
      <description>&lt;p&gt;This blog base from C# version &lt;a href="https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/GettingStarted/Step8_Pipelining.cs" rel="noopener noreferrer"&gt;https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/GettingStarted/Step8_Pipelining.cs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;F# code is here &lt;a href="https://github.com/rocklau/fsharpPlayground" rel="noopener noreferrer"&gt;https://github.com/rocklau/fsharpPlayground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing F# with Semantic Kernel: Simplifying AI App Development with the Pipeline Pattern
&lt;/h2&gt;

&lt;p&gt;As developers, we are continuously looking for tools and frameworks that can help us streamline our workflows and build efficient applications. In the realm of AI app development, Microsoft's &lt;a href="https://github.com/microsoft/semantic-kernel" rel="noopener noreferrer"&gt;Semantic Kernel (SK)&lt;/a&gt; has emerged as a powerful framework to simplify the integration of AI capabilities into applications. Coupling this with the functional programming prowess of F#, we can create robust, maintainable, and scalable AI solutions. Today, we'll explore how to harness the pipeline pattern in F# with SK to develop AI apps more easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why F# and Semantic Kernel?
&lt;/h3&gt;

&lt;p&gt;F# is a functional-first programming language that empowers developers to write concise, expressive, and high-performance code. It shines in scenarios requiring complex data manipulations, asynchronous programming, and domain-specific languages (DSLs).&lt;/p&gt;

&lt;p&gt;Semantic Kernel, on the other hand, is a developer kit from Microsoft designed to enable rapid embedding of AI functionalities within applications. It abstracts many complexities associated with AI model integration and provides a range of tools for building intelligent systems effortlessly.&lt;/p&gt;

&lt;p&gt;Combining F# with Semantic Kernel allows us to leverage the pipeline pattern, a well-known functional programming construct, to process data through a sequence of operations seamlessly. Let's delve into the practical implementation of this approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing the Pipeline Pattern
&lt;/h3&gt;

&lt;p&gt;Here's a step-by-step guide on how to implement a simple pipeline pattern using F# and Semantic Kernel.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Define Custom Types and Functions
&lt;/h4&gt;

&lt;p&gt;First, we set up our custom types and essential functions. We define a &lt;code&gt;JsonValue&lt;/code&gt; type to represent different JSON structures and a &lt;code&gt;JsonSchema&lt;/code&gt; type for schema validation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;JsonValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JsonArray&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;JsonValue&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JsonString&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JsonNumber&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JsonBool&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JsonNull&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;JsonSchema&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaObject&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonSchema&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaArray&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;JsonSchema&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaString&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaNumber&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaBool&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaNull&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaRequired&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nc"&gt;JsonSchema&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we define a context type and a result type to handle the outcomes of our operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. JSON Value Conversion and Validation
&lt;/h4&gt;

&lt;p&gt;We then create functions to convert JSON elements to our &lt;code&gt;JsonValue&lt;/code&gt; types and validate JSON against schemas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;rec&lt;/span&gt; &lt;span class="n"&gt;toJsonValue&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonElement&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;JsonValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;jsonElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ValueKind&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;jsonElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EnumerateObject&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;toJsonValue&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofSeq&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;jsonElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EnumerateArray&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;toJsonValue&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofSeq&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonArray&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonString&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetString&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonNumber&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetDouble&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;True&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonBool&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;False&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonBool&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Null&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;JsonNull&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;failwith&lt;/span&gt; &lt;span class="s2"&gt;"Unsupported JSON value kind"&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;rec&lt;/span&gt; &lt;span class="n"&gt;validateJson&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonSchema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JsonValue&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaObject&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;valueSchema&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TryFind&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validateJson&lt;/span&gt; &lt;span class="n"&gt;valueSchema&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valueSchema&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;SchemaRequired&lt;/span&gt; &lt;span class="o"&gt;_)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaArray&lt;/span&gt; &lt;span class="n"&gt;itemSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonArray&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validateJson&lt;/span&gt; &lt;span class="n"&gt;itemSchema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonString&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonNumber&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaBool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonBool&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaNull&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonNull&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SchemaRequired&lt;/span&gt; &lt;span class="n"&gt;innerSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validateJson&lt;/span&gt; &lt;span class="n"&gt;innerSchema&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Creating Contexts and JSON Operations
&lt;/h4&gt;

&lt;p&gt;We create functions to build contexts and perform JSON operations like addition, multiplication, and squaring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;createContextWithNewValue&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;JsonDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Parse&lt;/span&gt;&lt;span class="o"&gt;($&lt;/span&gt;&lt;span class="s2"&gt;"{{ &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: {newValue} }}"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;RootElement&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Input&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;jsonOperation&lt;/span&gt; &lt;span class="n"&gt;opFunc&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;GetInt32&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opFunc&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;createContextWithNewValue&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Message&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addOne&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonOperation&lt;/span&gt; &lt;span class="o"&gt;((+)&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;multiplyByTwo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonOperation&lt;/span&gt; &lt;span class="o"&gt;((*)&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonOperation&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Mapping Functions and Defining the Pipeline
&lt;/h4&gt;

&lt;p&gt;We map function names to actual functions and define our pipeline function which processes data through these functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;functionMap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"addOne"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addOne&lt;/span&gt;
      &lt;span class="s2"&gt;"multiplyByTwo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;multiplyByTwo&lt;/span&gt;
      &lt;span class="s2"&gt;"square"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;square&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofList&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;toFunction&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryFind&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;functionMap&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sprintf&lt;/span&gt; &lt;span class="s2"&gt;"Function %s not found"&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="n"&gt;functions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;validateSchema&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;validatedContext&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;functions&lt;/span&gt;
        &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fold&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="n"&gt;funcName&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
            &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;toFunction&lt;/span&gt; &lt;span class="n"&gt;funcName&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;validatedContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Implementing and Testing the Pipeline
&lt;/h4&gt;

&lt;p&gt;Finally, we implement and test our pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;schemaJson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SchemaObject&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofList&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SchemaRequired&lt;/span&gt; &lt;span class="nc"&gt;SchemaNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initialContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createContextWithNewValue&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;functionNames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[|&lt;/span&gt; &lt;span class="s2"&gt;"addOne"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="s2"&gt;"multiplyByTwo"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="s2"&gt;"square"&lt;/span&gt; &lt;span class="p"&gt;|]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;resultContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="n"&gt;schemaJson&lt;/span&gt; &lt;span class="n"&gt;initialContext&lt;/span&gt; &lt;span class="n"&gt;functionNames&lt;/span&gt;

&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;resultContext&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"Result: %s"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToString&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"Error: %s"&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrating with Semantic Kernel
&lt;/h3&gt;

&lt;p&gt;To make our AI app more realistic, we integrate it with the Semantic Kernel by creating a plugin and utilizing OpenAI models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Calculate&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt;    
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="o"&gt;([&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"input number"&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"choose from addOne multiplyByTwo square"&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt; &lt;span class="n"&gt;functionNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="bp"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;schemaJson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SchemaObject&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ofList&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SchemaRequired&lt;/span&gt; &lt;span class="nc"&gt;SchemaNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initialContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createContextWithNewValue&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;resultContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="n"&gt;schemaJson&lt;/span&gt; &lt;span class="n"&gt;initialContext&lt;/span&gt; &lt;span class="n"&gt;functionNames&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;resultContext&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Success&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sprintf&lt;/span&gt; &lt;span class="s2"&gt;"Result: %s"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToString&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Failure&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sprintf&lt;/span&gt; &lt;span class="s2"&gt;"Error: %s"&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sk-"&lt;/span&gt;  
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gpt-4o-mini"&lt;/span&gt; 
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;chat_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://api.openai.com/v1/chat/completions"&lt;/span&gt; 
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_url&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddFromType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Calculate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;()&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;asyncEx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAIPromptExecutionSettings&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToolCallBehavior&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nn"&gt;ToolCallBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AutoInvokeKernelFunctions&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KernelArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"Plugins count : %d"&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Count&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;response2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InvokePromptAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Calculate: input 3 to Pipeline [addOne addOne]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RunSynchronously&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;By leveraging the power of F# and the versatility of Semantic Kernel, we can create AI applications following the pipeline pattern efficiently. This combination not only simplifies our development process but also ensures our applications are maintainable, scalable, and robust. Whether you're new to F# or Semantic Kernel, diving into this pattern can significantly enhance your ability to build sophisticated AI solutions with minimal complexity. Happy coding!&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Building a Semantic Kernel with F# for Enhanced AI Interaction</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Wed, 28 Aug 2024 08:03:55 +0000</pubDate>
      <link>https://dev.to/rockfire/building-a-semantic-kernel-with-f-for-enhanced-ai-interaction-302m</link>
      <guid>https://dev.to/rockfire/building-a-semantic-kernel-with-f-for-enhanced-ai-interaction-302m</guid>
      <description>&lt;p&gt;This blog base from &lt;a href="https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/GettingStarted/Step2_Add_Plugins.cs" rel="noopener noreferrer"&gt;https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/GettingStarted/Step2_Add_Plugins.cs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;F# code is here &lt;a href="https://github.com/rocklau/fsharpPlayground" rel="noopener noreferrer"&gt;https://github.com/rocklau/fsharpPlayground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the age of artificial intelligence, leveraging powerful tools to interact seamlessly with users is crucial. Semantic Kernels serve as versatile frameworks that enable AI models to comprehend and respond to queries intelligently. In this blog post, we’ll explore how to create a Semantic Kernel using F#, integrating plugins to enhance functionality and improve user interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Semantic Kernel
&lt;/h2&gt;

&lt;p&gt;The foundation of our Semantic Kernel is built on several key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Time Information Plugin&lt;/strong&gt;: This plugin retrieves the current time in UTC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Widget Factory Plugin&lt;/strong&gt;: This plugin allows users to create widgets with specified types and colors.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's take a look at the code implementation for these plugins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time Information Plugin
&lt;/h3&gt;

&lt;p&gt;This simple plugin is designed to provide the current UTC time, making it accessible for any application requiring time-related information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;TimeInformationPlugin&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Retrieves the current time in UTC."&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt;
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetCurrentUtcTime&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"R"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Widget Factory Plugin
&lt;/h3&gt;

&lt;p&gt;The widget factory plugin is more complex, allowing users to generate custom widgets based on their preferences. The plugin utilizes enumerated types to specify widget characteristics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;WidgetType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"A widget that is useful."&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt; &lt;span class="nc"&gt;Useful&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"A widget that is decorative."&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt; &lt;span class="nc"&gt;Decorative&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;WidgetColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Use when creating a red item."&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt; &lt;span class="nc"&gt;Red&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Use when creating a green item."&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt; &lt;span class="nc"&gt;Green&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Use when creating a blue item."&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt; &lt;span class="nc"&gt;Blue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;WidgetDetails&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SerialNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WidgetType&lt;/span&gt;
        &lt;span class="nc"&gt;Colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WidgetColor&lt;/span&gt;&lt;span class="bp"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;WidgetFactoryPlugin&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Creates a new widget of the specified type and colors"&lt;/span&gt;&lt;span class="o"&gt;)&amp;gt;]&lt;/span&gt;    
    &lt;span class="k"&gt;member&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widgetType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WidgetType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;widgetColors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WidgetColor&lt;/span&gt;&lt;span class="bp"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;"{widgetType}-{String.Join('-',widgetColors)}-{Guid.NewGuid()}"&lt;/span&gt;
        &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WriteLine&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;"Call a widget {number}"&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;SerialNumber&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
            &lt;span class="nc"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;widgetType&lt;/span&gt;
            &lt;span class="nc"&gt;Colors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;widgetColors&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring the Kernel
&lt;/h3&gt;

&lt;p&gt;After implementing the plugins, we construct the kernel and register our plugins. This is achieved by configuring the OpenAI API for chat functionalities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CreateBuilder&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gpt-4o-mini"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://api.chatgpt.com/v1/chat/completions"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sk-"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddFromType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeInformationPlugin&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AddFromType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WidgetFactoryPlugin&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Use Cases
&lt;/h2&gt;

&lt;p&gt;Once the kernel and plugins are set up, we can create various examples to demonstrate their capabilities. Below are a few examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1: Basic Interaction
&lt;/h3&gt;

&lt;p&gt;In this example, we query the kernel about the color of the sky.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;example1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"example1"&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InvokePromptAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"What color is the sky?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WriteLine&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 2: Streaming Responses
&lt;/h3&gt;

&lt;p&gt;We can also create streaming interactions, which allow us to get real-time responses from the AI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;example2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;asyncEx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s2"&gt;"example2"&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KernelArguments&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"topic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"forest"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InvokePromptStreamingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"What color is {{$topic}}?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 3: Using Plugins
&lt;/h3&gt;

&lt;p&gt;We can directly utilize our plugins within prompts. For instance, we can retrieve the current UTC time and ask how many days remain until Christmas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;example4&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;asyncEx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InvokePromptAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"The current time is {{TimeInformationPlugin.GetCurrentUtcTime}}. How many days until Christmas?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WriteLine&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 5: Creating Widgets
&lt;/h3&gt;

&lt;p&gt;Finally, we can automatically invoke functions to create customizable widgets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight fsharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;example5&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;asyncEx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAIPromptExecutionSettings&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToolCallBehavior&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nn"&gt;ToolCallBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AutoInvokeKernelFunctions&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KernelArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;response2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InvokePromptAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Create a beautiful scarlet colored widget for me."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="nn"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog, we've explored how to build a Semantic Kernel using F#. By combining plugins with real-time AI interaction, we can create dynamic applications that respond intuitively to user queries. This framework not only enhances user experiences but also opens doors to countless possibilities for future developments in AI interactions.&lt;/p&gt;

&lt;p&gt;Feel free to expand upon this framework, experiment with additional plugins, and integrate it into your own applications to fully realize the capabilities of semantic technology and AI!&lt;/p&gt;

</description>
      <category>semantickernel</category>
      <category>langchain</category>
      <category>llm</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Smooth Streaming Control with System.Threading.Channels in GPT API Programming</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Mon, 12 Aug 2024 09:54:00 +0000</pubDate>
      <link>https://dev.to/rockfire/efficient-streaming-control-with-systemthreadingchannels-in-better-gpt-api-4l67</link>
      <guid>https://dev.to/rockfire/efficient-streaming-control-with-systemthreadingchannels-in-better-gpt-api-4l67</guid>
      <description>&lt;p&gt;In today’s digital world, real-time interactions are becoming increasingly essential, especially in applications that leverage powerful AI models like OpenAI’s GPT-4. One of the significant advancements in .NET that ensures smooth and efficient handling of streaming data is the System.Threading.Channels library. This blog explores how to harness this feature to improve streaming control when interacting.&lt;/p&gt;

&lt;p&gt;What is System.Threading.Channels?&lt;/p&gt;

&lt;p&gt;System.Threading.Channels is a modern concurrency primitive provided in .NET for handling asynchronous messaging between producer and consumer tasks. It allows developers to implement robust and scalable applications that require real-time updates without blocking the main execution flow.&lt;/p&gt;

&lt;p&gt;Why Use Channels for Streaming?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Asynchronous Message HandlingUtilizing channels helps decouple the production of messages from their consumption. In an interactive chat scenario, the producer (responsible for generating responses) can run independently of the consumer (which handles display logic). This means users can continue to interact with the application while responses are being processed in the background.&lt;/li&gt;
&lt;li&gt;Efficient Backpressure ManagementA critical feature of channels is their ability to manage backpressure effectively. In scenarios where the producer is generating messages faster than the consumer can process them, channels prevent overloading. This is crucial for maintaining application responsiveness and ensures that the system remains stable under varying loads.&lt;/li&gt;
&lt;li&gt;Flow ControlDevelopers can set constraints for the channel to regulate the maximum number of messages being queued. This enables precise control over resource allocation, preventing excessive memory consumption and ensuring that the application runs smoothly even during peak activity periods.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How It Works: A Breakdown of the Code&lt;/p&gt;

&lt;p&gt;Let’s look at how to implement it.&lt;/p&gt;

&lt;p&gt;Producer Task&lt;/p&gt;

&lt;p&gt;The producer task fetches updates from the GPT model and sends them to the channel. Here’s a snippet demonstrating this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;messageCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InvokePromptStreamingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageCount&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;messageCount&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
        &lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Output"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
            &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Refresh&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, the producer retrieves responses asynchronously and updates the display in real-time as messages are received, maintaining an engaging user experience.&lt;/p&gt;

&lt;p&gt;Consumer Task&lt;/p&gt;

&lt;p&gt;The consumer task reads messages from the channel and processes them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;totalLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;totalLength&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Further processing of the message...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;By&lt;/span&gt; &lt;span class="n"&gt;separating&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;handling&lt;/span&gt; &lt;span class="n"&gt;incoming&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;developers&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;keep&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;responsive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allowing&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fluid&lt;/span&gt; &lt;span class="n"&gt;interactions&lt;/span&gt; &lt;span class="n"&gt;without&lt;/span&gt; &lt;span class="n"&gt;lag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;Performance&lt;/span&gt; &lt;span class="n"&gt;Monitoring&lt;/span&gt;

&lt;span class="n"&gt;Monitoring&lt;/span&gt; &lt;span class="n"&gt;performance&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;essential&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;track&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="n"&gt;like&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;latency&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;optimize&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;For&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Request Time: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feedback loop enhances the development and user experience by providing insights into application performance.&lt;/p&gt;

&lt;p&gt;Components&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;OpenAI Chat Completion(Microsoft.SemanticKernel): The application integrates with OpenAI’s API to leverage the GPT-4 model for generating responses based on user input.&lt;/li&gt;
&lt;li&gt;Spectre.Console: Used to create a visually appealing console interface, allowing for dynamic updates and rendering of text.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;Using System.Threading.Channels for enhanced streaming control  significantly improves performance, user experience, and stability. By implementing this powerful feature, developers can create real-time, interactive applications that seamlessly handle the demands of modern users.&lt;/p&gt;

&lt;p&gt;If you’re building an application that requires real-time updates or interactions with AI models, consider adopting System.Threading.Channels for a smoother, more efficient experience. Happy coding!&lt;/p&gt;

&lt;p&gt;Full code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// See https://aka.ms/new-console-template for more information&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Spectre.Console&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Channels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create a kernel with OpenAI chat completion&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sk-"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-4o-mini"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chat_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://api.chatgpt.com/v1/chat/completions"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#pragma warning disable SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt;
                   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="cp"&gt;#pragma warning restore SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
&lt;/span&gt;&lt;span class="c1"&gt;//kernel.PromptRenderFilters.Add(new PromptRenderLoggingFilter());&lt;/span&gt;

&lt;span class="c1"&gt;// Create the layout&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Root"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SplitColumns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Left"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;SplitRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Right"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Right"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Ratio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Left"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Right"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;Stopwatch&lt;/span&gt; &lt;span class="n"&gt;gapWatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Stopwatch&lt;/span&gt; &lt;span class="n"&gt;origanWatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;AnsiConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;


    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AnsiConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ask&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"Let's talk, What do you want?:rocket: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;



    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateUnbounded&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="n"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;sourceText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;targetText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;




    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AnsiConsole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Live&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Left"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                     &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                         &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                             &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Loading:fire:"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                                             &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                                         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
             &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Refresh&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


             &lt;span class="c1"&gt;// AnsiConsole.Write(layout);&lt;/span&gt;

             &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                     &lt;span class="p"&gt;{&lt;/span&gt;
                         &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                         &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InvokePromptStreamingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                         &lt;span class="p"&gt;{&lt;/span&gt;
                             &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;origanWatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                             &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
                             &lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                             &lt;span class="c1"&gt;// Update the left column&lt;/span&gt;
                             &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Left"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                     &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                         &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                             &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
                                             &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                                         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                             &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Refresh&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


                             &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                         &lt;span class="p"&gt;}&lt;/span&gt;
                         &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                         &lt;span class="n"&gt;origanWatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                         &lt;span class="n"&gt;gapWatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                     &lt;span class="p"&gt;});&lt;/span&gt;



             &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
             &lt;span class="p"&gt;{&lt;/span&gt;
                 &lt;span class="c1"&gt;//0.0014 rate/per 1k&lt;/span&gt;
                 &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                 &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;baseDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;//400&lt;/span&gt;
                 &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                 &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;//30&lt;/span&gt;
                 &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                 &lt;span class="p"&gt;{&lt;/span&gt;



                     &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


                     &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;radio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                     &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;smooth_delay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;minDelay&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baseDelay&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;baseDelay&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;radio&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


                     &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxDelay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minDelay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;smooth_delay&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

                     &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                         &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                             &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                 &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"delay:[red]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;[/] text length:[red]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;[/] left:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; speed: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;smooth_delay&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; radio:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;radio&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  word_len: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; "&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                                 &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;



                     &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
                     &lt;span class="n"&gt;targetText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
                                              &lt;span class="c1"&gt;//  if (!response.HttpContext.RequestAborted.IsCancellationRequested) &lt;/span&gt;
                                              &lt;span class="c1"&gt;//  {&lt;/span&gt;
                                              &lt;span class="c1"&gt;//       &lt;/span&gt;
                                              &lt;span class="c1"&gt;//      await response.WriteAsync($"data: {text[i]}\n\n");&lt;/span&gt;
                                              &lt;span class="c1"&gt;//      await response.Body.FlushAsync();  &lt;/span&gt;
                                              &lt;span class="c1"&gt;//  }&lt;/span&gt;

                     &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Right"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                         &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                             &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                 &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
                                 &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                     &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Refresh&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;



                 &lt;span class="p"&gt;}&lt;/span&gt;

             &lt;span class="p"&gt;});&lt;/span&gt;
             &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

             &lt;span class="n"&gt;gapWatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
             &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gapWatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
             &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                          &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                              &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"origan:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;origanWatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;gap: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;gapWatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; "&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

                              &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Expand&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

         &lt;span class="p"&gt;});&lt;/span&gt;



&lt;span class="p"&gt;}&lt;/span&gt;



&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All text has been processed."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code implements a dynamic text display system with variable delay, similar to a typewriter effect. Here's the summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It processes text chunk by chunk with a dynamic delay between each chunk&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Key variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;baseDelay&lt;/code&gt;: Starting delay (100ms)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minDelay&lt;/code&gt;: Minimum delay (0ms)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxDelay&lt;/code&gt;: Maximum delay (20ms)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The delay calculation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gets shorter as more text is displayed (&lt;code&gt;count&lt;/code&gt; increases)&lt;/li&gt;
&lt;li&gt;Uses a ratio (&lt;code&gt;radio&lt;/code&gt;) to accelerate for longer remaining text&lt;/li&gt;
&lt;li&gt;&lt;code&gt;smooth_delay = (baseDelay - (progress * baseDelay / total)) / ratio&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Speed adjustments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speeds up when more than 100 characters remain&lt;/li&gt;
&lt;li&gt;Maintains minimum and maximum delay boundaries&lt;/li&gt;
&lt;li&gt;Updates progress info in UI panel&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In simple terms: it starts slow and gradually speeds up as it approaches the end, ensuring smooth text display with adaptive pacing.&lt;/p&gt;

</description>
      <category>semantickernel</category>
      <category>llm</category>
      <category>dotnet</category>
      <category>spectreconsole</category>
    </item>
    <item>
      <title>Aspire Three Ways to Implement Service Discovery for Non-.NET APIs micro-services</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Wed, 24 Jul 2024 06:58:31 +0000</pubDate>
      <link>https://dev.to/rockfire/aspire-three-ways-of-registry-service-discovery-for-non-net-microservices-234</link>
      <guid>https://dev.to/rockfire/aspire-three-ways-of-registry-service-discovery-for-non-net-microservices-234</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Resource type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AddProject&lt;/td&gt;
&lt;td&gt;ProjectResource&lt;/td&gt;
&lt;td&gt;A .NET project, for example ASP.NET Core web apps.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AddContainer&lt;/td&gt;
&lt;td&gt;ContainerResource&lt;/td&gt;
&lt;td&gt;A container image, such as a Docker image.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AddExecutable&lt;/td&gt;
&lt;td&gt;ExecutableResource&lt;/td&gt;
&lt;td&gt;An executable file.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Aspire provides three resource types: Project, Container, and Executable. However, service discovery is only enabled by default for Project resources.&lt;/p&gt;

&lt;p&gt;To build web API microservices in languages other than .NET, we can utilize the &lt;code&gt;IResourceWithServiceDiscovery&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;Here, we demonstrate Aspire's non-.NET Web API service discovery approach using a Bun web API (similar to Node.js). Three code examples illustrate different methods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project File Location:&lt;/strong&gt; &lt;code&gt;.. /runner&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Container Resource with Service Discovery
&lt;/h2&gt;

&lt;p&gt;We'll inherit from both the container resource and the service discovery interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BunContainerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;ContainerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;IResourceWithServiceDiscovery&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;AppHost&lt;/code&gt;, we add the container resource with details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bun&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BunContainerResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"runner"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"oven/bun"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"distroless"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithBindMount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".. /runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/home/bun/app/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--hot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/home/bun/app/src/index.ts"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Also, Replace WithImage to WithDockerfile &lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithDockerfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../runner"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To interact with the Bun service, register &lt;code&gt;RunnerApiClient&lt;/code&gt; with a base URL dynamically constructed using service discovery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHttpClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RunnerApiClient&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"http://runner"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Executable Resource with Service Discovery
&lt;/h2&gt;

&lt;p&gt;Define a class for discoverable executable resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BunExecuteableResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;projectDirectory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;ExecutableResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;projectDirectory&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;IResourceWithServiceDiscovery&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;AppHost&lt;/code&gt;, register the executable resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bunProject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BunExecuteableResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"bun"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".. /runner"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bun&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bunProject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Yarp Proxy Integration with .NET Web API
&lt;/h2&gt;

&lt;p&gt;If you have an existing .NET Web API project, it might already have a built-in Yarp proxy for service exposure. Here's how to configure Yarp:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yarp Configuration (JSON):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"destination1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can start the Bun service directly within &lt;code&gt;AppHost&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bun&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddExecutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"runner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"bun"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".. /runner"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, reference the service's endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bun&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"runner"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>dotnet</category>
      <category>aspire</category>
    </item>
    <item>
      <title>Easily Develop a GPTs Chat App with Hono, Bun, and HTMX</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Wed, 29 May 2024 10:34:42 +0000</pubDate>
      <link>https://dev.to/rockfire/easy-to-dev-a-gpts-chat-app-p4l</link>
      <guid>https://dev.to/rockfire/easy-to-dev-a-gpts-chat-app-p4l</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foi3qt4lm0pf2echhn4ty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foi3qt4lm0pf2echhn4ty.png" alt="Image description" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;htmx -&amp;gt; http --&amp;gt; hono --&amp;gt; gpt&lt;/p&gt;

&lt;p&gt;code here: &lt;a href="https://github.com/rocklau/gpts-chat-app" rel="noopener noreferrer"&gt;https://github.com/rocklau/gpts-chat-app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a chat application that allows users to interact with multi AIs through a simple and intuitive interface. There is also a human channel chat feature that needs a bug fix. You might consider switching to Tailwind CSS for styling. This repository is intended for learning purposes only.&lt;/p&gt;

&lt;p&gt;Thanks for open source with  htmx hono bun mitata openai cherry-markdown&lt;/p&gt;

&lt;p&gt;Directory Structure&lt;br&gt;
The project directory is organized as follows:&lt;/p&gt;

&lt;p&gt;static/:&lt;br&gt;
index.html: Main HTML file for the application. have htmx and js logic.&lt;br&gt;
src/:&lt;br&gt;
index.tsx: Entry point of the application, core server logic.&lt;br&gt;
GptChat.tsx: Component for the GPT chat interface.&lt;br&gt;
models.tsx: Configuration for the AI models.&lt;br&gt;
benmarking.tsx: Benchmarking scripts for performance testing gpt models.&lt;br&gt;
HumanChat.tsx: Component for human-to-human chat interface. have bug&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Best Three Open Source JSON RPC Projects(Kiota, Hono, tRPC) -- easier to dev client json code</title>
      <dc:creator>Rocky LIU Yan</dc:creator>
      <pubDate>Thu, 23 May 2024 06:54:57 +0000</pubDate>
      <link>https://dev.to/rockfire/best-three-open-source-json-rpc-projects-easier-to-dev-client-json-code-32j7</link>
      <guid>https://dev.to/rockfire/best-three-open-source-json-rpc-projects-easier-to-dev-client-json-code-32j7</guid>
      <description>&lt;p&gt;Recommend Project: Kiota, Hono, tRPC&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are two good benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid manual alignment of JSON interfaces&lt;/li&gt;
&lt;li&gt;The rise of edge services blurs the lines between client/server.
First and foremost is Next.js’s introduction of server actions this year.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Other JavaScript frameworks also have similar capabilities:&lt;br&gt;
hono.dev,&lt;br&gt;
trpc.io&lt;br&gt;
They all enable front-end and back-end to call a unified set of functions, known as RPC (Remote Procedure Call). For example, &lt;code&gt;client.posts.get()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Microsoft also has an open-source project named Kiota, which generates cross-language client RPC code based on OpenAPI schemas.&lt;/p&gt;

&lt;p&gt;These libraries have similar usage patterns but different focuses.&lt;/p&gt;

&lt;p&gt;microsoft/kiota:&lt;br&gt;&lt;br&gt;
Below are the client languages that Kiota can generate based on OpenAPI. &lt;br&gt;
Supported languages  CSharp Go Java PHP Python Ruby Swift TypeScript JavaScript&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7qczai8uebvegk967vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7qczai8uebvegk967vl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
