Latest Posts

2024年7月9日 星期二

使用Ollama與Open WebUI在本地端部署Llama3大語言模型

文/恆逸資深講師 申建忠

Ollama是一個使用Go語言開發的本地端大語言模型框架,可以在本地端執行多種開放原始碼的大語言模型,如:Llama 3、Mistral、Gemma等。其中Meta Llama 3以15T語料進行訓練,模型效果號稱無限接近ChatGPT4。

本文介紹如何在本地端安裝Ollama與Open WebUI,並使用Ollama運行Meta Llama 3:8b模型。

首先至Ollama官網(https://ollama.com)下載對應版本的ollama執行檔,下載完成後直接點擊安裝即可。本文以Apple Macbook pro 2018為例。

安裝完成後,請點擊ollama執行檔啟動ollama設定。
依下面圖示,由左向右便可設定完成。

2024年7月5日 星期五

2024年7月2日 星期二

Anycast的用途說明【冤枉呀!人不是我殺的】

 

邱顯智 Ozzy Chiou

  • 恆逸教育訓練中心-資深講師
  • 技術分類:網路管理與通訊應用

 


剛接觸IPv6的朋友應該知道IPv6封包的傳遞方式有三種:Unicast(單播)、Multicast(群播)與Anycast(任一播),取消了傳統IPv4的Broadcast(廣播),於是很多朋友就直覺得誤以為Anycast是用來取代Broadcast的新技術,這個誤會可大了。

其實Anycast並不是IPv6的新技術,IPv4早就已經在用了,只是沒有大聲嚷嚷而己,最具代表性的範例就是Google的8.8.8.8以及8.8.4.4這兩台公用DNS伺服器,這是經過Google正式官宣使用Anycast技術的案例。

Google在世界各地建置了許多資料中心,在這些資料中心裡也建置了許多IP地址都是8.8.8.8或8.8.4.4的DNS伺服器,因此,如果您使用8.8.8.8或是8.8.4.4當做您的DNS伺服器的時候,BGP路由就會根據您所在的位置,將您的名稱解析查詢導向到離您最近的Google公用DNS伺服器。 所以Anycast的特性如下:

  • 1-to-Nearest:傳送到最接近的主機,最接近的主機則是交由路由協定(例如BGP)選擇的最佳路徑來決定。
  • 與Unicast共用同一段IP地址空間,如上述8.8.8.8以及8.8.4.4這兩個地址傳統是屬於IPv4的Class A地址,但是也可以用於Anycast之用,在Cisco路由器上,您只要在配置IPv6地址命令加上Anycast參數,該地址即可搖身一變改為Anycast的用途。
  • 允許多台主機配置同一個IP地址:一般的Unicast地址不可以有兩台主機配置同一個IP地址,否則會造成IP地址衝突的狀況,Anycast地址則無此限制。
  • 適合用於需要Load-sharing的服務:如果您的伺服器在公眾雲上面,您可以透過指定伺服器所在的Region,將用戶造訪的流量導向到最鄰近的伺服器,達到地理位置上的流量分散。甚至,這樣的配置也可以用來稀釋分散式阻斷服務(Distributed Denial-of-Service)攻擊的流量,減緩遭受DDoS攻擊的影響。

您可在下列課程中了解更多技巧喔!

2024年6月24日 星期一

手動設定可用性群組 - Azure VM 上的 SQL Server(上)

文/恆逸資深講師 楊先民
本文章是在說明如何為 Azure VM 上的 SQL Server,在單一子網路內建立 Always On 可用性群組。
整個內容會建立一個在兩部 SQL Server 執行個體上都有一份資料庫複本的可用性群組。
你也可以使用 Azure 入口網站PowerShell 或 Azure CLI,或使用 Azure 快速入門範本以自動完成這些步驟。
以下是完成這個練習的必需需求:

2024年6月13日 星期四

企業最熱話題:ESG永續發展,最推薦的綠領人才課程:ISO 14064溫室氣體主導查證師/確證師訓練課程




氣候變遷議題備受全球關注,企業被要求更透明地揭露溫室氣體排放資訊。許多國家政府已意識到必須採取行動因應環境挑戰,紛紛推動碳定價等政策,未來企業將面臨支付碳排放費用的壓力。有效進行溫室氣體盤查並落實碳管理,將成為企業永續經營不可或缺的一環。

2024年6月12日 星期三

在Blazor使用Fluent UI元件-5

作 者:恆逸資深講師 許薰尹

在本站《在Blazor使用Fluent UI元件 - 4》一文介紹如何在現有的Blazor專案中,手動加入Fluent UI元件 ,並使用「FluentDialog」元件設計確認刪除的對話盒。在這一篇文章中,我們將介紹延續這系列文章的情境,介紹該如何自訂對話盒,以便讓其它元件能夠重複使用這個對話盒。

設計MyDialog


首先讓我們使用元件來自訂對話盒,元件的程式碼可放在專案根目錄下的「Shared」資料夾。從「Solution Explorer」視窗 - 專案名稱上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」選項,將新建立的資料夾命名為「Shared」。

在「Shared」資料夾中加入Razor元件,從「Solution Explorer」視窗 -「Shared」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Razro Component」項目,將元件名稱命為「MyDialog.razor」,然後在檔案中加入以下程式碼:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@using Microsoft.FluentUI.AspNetCore.Components
@implements IDialogContentComponent<FluentUIDataGrid.Models.Customer>
 
@* Header *@
<FluentDialogHeader ShowDismiss = "true">
  <FluentStack VerticalAlignment = "VerticalAlignment.Center">
    <FluentIcon Value = "@(new Icons.Regular.Size24.WindowApps())" />
    <FluentLabel Typo = "Typography.PaneHeader">
        @Dialog.Instance.Parameters.Title
    </FluentLabel>
  </FluentStack>
</FluentDialogHeader>
 
@* Footer *@
<FluentDialogFooter>
  <FluentButton Appearance = "Appearance.Accent" OnClick = "@DeleteAsync"> Delete </FluentButton>
  <FluentButton Appearance = "Appearance.Neutral" OnClick = "@CancelAsync"> Cancel </FluentButton>
</FluentDialogFooter>
 
@* Body *@
<FluentDialogBody>
  <FluentTextField @bind-Value = "@Content.CustomerId"> CustomerId: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.CompanyName"> CompanyName: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.ContactName"> ContactName: </FluentTextField>
</FluentDialogBody>
 
@code {
  [Parameter]
  public FluentUIDataGrid.Models.Customer Content { get; set; } = default!;
 
  [CascadingParameter]
  public FluentDialog Dialog { get; set; } = default!;
 
  private async Task DeleteAsync() {
    await Dialog.CloseAsync( Content );
  }
 
  private async Task CancelAsync() {
    await Dialog.CancelAsync( );
  }
}




分別說明如下,以下這兩行程式碼是在引入了必要的命名空間,並且實作了「IDialogContentComponent」介面,該介面的泛型參數是「FluentUIDataGrid.Models.Customer」:

1
2
@using Microsoft.FluentUI.AspNetCore.Components
@implements IDialogContentComponent<FluentUIDataGrid.Models.Customer>



以下程式碼建立了自訂對話盒的標題部分。「FluentDialogHeader」是對話盒的標題,「ShowDismiss」屬性設為「true」表示可以關閉對話盒。「FluentStack」是一個容器類型的元件,裡面包含了一個圖示(FluentIcon)和一個標籤(FluentLabel),這個標籤顯示的是對話盒的標題:

1
2
3
4
5
6
7
8
9
@* Header *@
<FluentDialogHeader ShowDismiss = "true">
  <FluentStack VerticalAlignment = "VerticalAlignment.Center">
    <FluentIcon Value = "@(new Icons.Regular.Size24.WindowApps())" />
    <FluentLabel Typo = "Typography.PaneHeader">
        @Dialog.Instance.Parameters.Title
    </FluentLabel>
  </FluentStack>
</FluentDialogHeader>



以下程式碼建立對話盒的尾部部分。「FluentDialogFooter」是對話盒的底部,裡面包含了兩個按鈕,一個是刪除按鈕,點擊後會執行「DeleteAsync」方法,另一個是取消按鈕,點擊後會執行「CancelAsync」方法。

1
2
3
4
5
@* Footer *@
<FluentDialogFooter>
  <FluentButton Appearance = "Appearance.Accent" OnClick = "@DeleteAsync"> Delete </FluentButton>
  <FluentButton Appearance = "Appearance.Neutral" OnClick = "@CancelAsync"> Cancel </FluentButton>
</FluentDialogFooter>


以下程式碼建立對話盒的主體部分。「FluentDialogBody」是對話盒的主體,裡面包含了三個文字欄位,分別繫結到「Content」物件的「CustomerId」、「CompanyName」和「ContactName」屬性。

 

 

1
2
3
4
5
6
@* Body *@
<FluentDialogBody>
  <FluentTextField @bind-Value = "@Content.CustomerId"> Id: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.CompanyName"> CompanyName: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.ContactName"> ContactName: </FluentTextField>
</FluentDialogBody>

 

 


以下程式碼定義一些屬性和方法。「Content」屬性是一個參數,它的類型是「FluentUIDataGrid.Models.Customer」。「Dialog」性是一個「CascadingParameter」參數,它的類型是「FluentDialog」。「DeleteAsync」方法是在刪除按鈕被按下時執行,它會關閉對話盒並傳遞「Content」物件。「CancelAsync」方法是在取消按鈕被按下時執行,它會取消對話盒。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@code {
  [Parameter]
  public FluentUIDataGrid.Models.Customer Content { get; set; } = default!;
 
  [CascadingParameter]
  public FluentDialog Dialog { get; set; } = default!;
 
  private async Task DeleteAsync() {
    await Dialog.CloseAsync( Content );
  }
 
  private async Task CancelAsync() {
    await Dialog.CancelAsync( );
  }
}

 

 


下一步在「MyDataGridComponent.razor」元件中使用「MyDialog」對話盒。參考以下程式碼,當按下「FluentDataGrid 」任一筆資料右方的刪除按鈕時,便叫用「DialogService.ShowDialogAsync()」方法顯示自訂對話盒:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
@using FluentUIDataGrid.Models
@using Microsoft.EntityFrameworkCore
@inject NorthwindContext DbContext
@inject IDialogService DialogService
<h3>MyDataGridComponent</h3>
<FluentDataGrid  TGridItem = "Customer" Items = "Customers" GridTemplateColumns = "1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr">
  <PropertyColumn Property = "@(c => c.CustomerId)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.CompanyName)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.ContactName)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.ContactTitle)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.Address)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.City)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.Country)" Sortable = "true" />
  <TemplateColumn Title = "Actions">
    <FluentButton IconStart = "@(new Icons.Regular.Size20.Delete())" OnClick = "@( () => DeleteClicked(context) )">
      Delete
    </FluentButton>
  </TemplateColumn>
</FluentDataGrid>
 
 
@code {
 
  public async Task DeleteClicked( Customer customer ) {
    var dialog = await DialogService.ShowDialogAsync<FluentUIDataGrid.Shared.MyDialog>(
      customer, new DialogParameters {
          Height = "240px",
          Title = $"Delete Customer : { customer.CustomerId }",
          PreventDismissOnOverlayClick = true,
          PreventScroll = true
        } );
 
    var result = await dialog.Result;
    if ( !result.Cancelled && result.Data != null ) {
      var c = await DbContext.Customers.FirstOrDefaultAsync( c => c.CustomerId == customer.CustomerId );
      DbContext.Customers.Remove( c );
      if ( c is not null ) {
        await DbContext.SaveChangesAsync( );
      }
    }
  }
 
 
  public IQueryable<Customer> Customers { get; set; } = null!;
  protected override async Task OnInitializedAsync() {
 
    await Task.Run( () => {
      Customers = DbContext.Customers.AsQueryable( );
    } );
  }
}
 
<style>
  .dialog-box {
    background-color: #f2f2f2;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 10px;
    margin-bottom: 10px;
  }
 
  .dialog-title {
    font-size: 18px;
    font-weight: bold;
    margin-bottom: 10px;
  }
 
  .dialog-buttons {
    margin-top: 10px;
  }
 
    .dialog-buttons button {
      margin-right: 10px;
    }
</style>

 

 

 

分別說明如下,以下這段程式碼,叫用「DialogService.ShowDialogAsync()」方法顯示對話盒,傳入了一個「customer」物件和一個「DialogParameters」物件來設定對話盒的參數,「Height」設定高度、「Title」設定標題、「PreventDismissOnOverlayClick」是否防止點選背景來關閉對話盒,「PreventDismissOnOverlayClick」設定為「true」時不可以點選背景來關閉對話盒;「PreventDismissOnOverlayClick」設為「false」則可以點選背景來關閉對話盒、「PreventScroll」用來設定是否防止滾動。

 

 

1
2
3
4
5
6
7
var dialog = await DialogService.ShowDialogAsync<FluentUIDataGrid.Shared.MyDialog>(
      customer, new DialogParameters {
          Height = "240px",
          Title = $"Delete Customer : { customer.CustomerId }",
          PreventDismissOnOverlayClick = true,
          PreventScroll = true
        } );

 


以下這行程式碼是在等待對話盒關閉並獲取結果,如果對話盒沒有被取消且返回的資料不為空,則進行以下操作:首先,從資料庫中找尋與當前「customer」的「CustomerId」相符的「Customer」物件。然後,從「DbContext.Customers」移除該筆資料。最後,如果「CustomerId」相符的資料存在於資料庫,則刪除資料庫的資料:

 

 

1
2
3
4
5
6
7
8
var result = await dialog.Result;
if ( !result.Cancelled && result.Data != null ) {
  var c = await DbContext.Customers.FirstOrDefaultAsync( c => c.CustomerId == customer.CustomerId );
  DbContext.Customers.Remove( c );
  if ( c is not null ) {
    await DbContext.SaveChangesAsync( );
  }
}

 

這個範例的執行結果請參考下圖所示:


圖 1:自訂對話盒。