Skip to content

Lab: Document Outline Console Application

Keynote

參考資訊

簡介

  • 使用 OpenAI API 和 Jina Reader API 來讀取網頁內容並生成相應的開發文檔,最後將結果保存為兩個 Markdown 文件。

主要功能

  1. 使用 Jina Reader API 從指定的 URI 讀取網頁內容。
  2. 根據 Jina Reader API 產出的資料透過 OpenAI ChatCompletion API 以及自定義提示詞翻譯並生成文檔。
  3. 將生成的內容保存 Markdown 文件。

Http Overview

HTTP 是什麼?

  • MDN: An overview of HTTP

  • HTTP 是用於獲取資源(如 HTML 文件)的通訊協定(Client-Server Protocol)。

  • 它是任何 Web 上數據交換的基礎,並且是一種客戶端-服務器協議,這意味著請求由接收方(通常是 Web 瀏覽器)發起。

  • 從伺服器回應一個完整的文檔通常由多種資源構建,如文本內容、佈局指令、圖像、視頻、腳本等。

    • html
    • css
    • js
    • image
    • video
    • ...

Client and Server

  • 客戶端(Client):發送 HTTP 請求
    • 從客戶端發出的請求訊息通常稱為 request
  • 伺服器(Server):接收 HTTP 請求,並返回 HTTP 回應
    • 而從伺服器返回的訊息稱為 response

INFO

  1. 透過瀏覽器瀏覽一般的網頁,誰是發出請求的客戶端?誰是接收請求的伺服器?
  2. 在 Console Application 想要想要取得外部 API 的資源,誰是客戶端?誰是伺服器?

TIP

透過 Chrome 瀏覽網頁時,如何查看客戶端和服務器之間的 HTTP 請求和回應?

  • 開啟 Chrome 開發者工具(F12 或右鍵選擇「檢查」)
  • 切換到 Network 標籤
  • 刷新網頁,即可看到所有的 HTTP 請求和回應
Chrome Devtool Network

HTTP Flow

  1. 建立 TCP 連接
  1. Client 端發出 HTTP Request Message 包含 Method, URI, Protocol Version, Headers, Body
GET / HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr
...
  1. Server 端回應 HTTP Response Message 包含 Protocol Version, Status Code, Status Text, Headers, Body
HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
Server: Apache
Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
ETag: "51142bc1-7449-479b075b2891b"
Accept-Ranges: bytes
Content-Length: 29769
Content-Type: text/html
...

新增 .NET Console Application 專案

HttpClient in .NET

INFO

  • HttpClient 類別提供了一個基於 HTTP 的網路服務的客戶端實作。
  • HttpClient 類別是一個簡單的類別,用於發送 HTTP 請求和接收 HTTP 回應。

如何閱讀 API 文檔

API Consultant Prompt
markdown
# 角色

你扮演的是一位精通 API 串接技術的專家,能夠提供各種相關的技術支援。

## 技能

### 技能 1: API 設計與開發

- 提供如何設計和開發 RESTful API 的建議。
- 分享使用 .NET Core 開發 API 的最佳實踐。
- 解釋 JWT、OAuth 等驗證和授權機制的實現方法。

### 技能 2: API 測試與調試

- 教授如何使用 Postman 或其他工具進行 API 測試。
- 分享調試 API 的常見技巧。

### 技能 3: API 串接

- 示範如何在 .NET 應用中調用外部 API。
- 講解如何使用 HttpClient 或 RestSharp 進行 API 請求,以及處理 API 回應(解析 JSON/XML)。

### 技能 4: 錯誤處理與性能優化

- 分析 API 的錯誤處理機制。
- 針對提高 API 性能的策略進行講解。

### 技能 5: 版本管理

- 提供如何進行 API 的版本管理的技巧。

### 技能 6: 其他 API 串接相關議題

- 針對特殊 API 串接需求或案例進行分享與討論。
- 教導如何使用 API 文件生成工具(如 Swagger)。

## 侷限

- 僅討論與 API 串接相關的話題。
- 應依照使用者的需求或問題,提供具體的技術支援。
- 對於不熟悉的議題,應進行搜索並學習。
- 儘量避免使用技術術語,除非使用者明確表示他們理解這些詞語。
Result Sample 01
  • 我想要串接以下 https://jina.ai/reader/, 我是第一次閱讀 api 串接文件,請問我應該如何閱讀開發文件
markdown
# 如何閱讀 API 串接文件

## References

**Resource 1:**: [Jina AI Reader API Documentation](https://jina.ai/reader/)

----------------

## Outline

### Topic 1: 了解 API 文件的結構

1. 介紹 API 文件的常見結構。
2. 了解每個部分的功能和重要性。

### Topic 2: 基本概念與術語

1. 介紹 API 中常見的術語,如 Endpoint、HTTP 方法、狀態碼等。
2. 解釋這些術語在 API 串接中的應用。

### Topic 3: 開始使用 API

1. 如何獲取 API 金鑰或憑證。
2. 如何進行基本的 API 請求。

### Topic 4: 進階使用

1. 如何處理 API 回應。
2. 如何進行錯誤處理與調試。

### Topic 5: 安全性與最佳實踐

1. 介紹 API 安全性的基本概念。
2. 分享一些 API 串接的最佳實踐。

----------------

## Step-by-step Tutorial

### Step 1: 了解 API 文件的結構

1. **首頁**:通常會有 API 的簡介和一些基本信息。
2. **快速開始**:提供一些簡單的示例,幫助你快速上手。
3. **API 參考**:詳細列出所有可用的 API Endpoint 及其參數。
4. **認證與授權**:說明如何獲取和使用 API 金鑰或憑證。
5. **錯誤碼**:列出可能的錯誤碼及其含義。

### Step 2: 基本概念與術語

1. **Endpoint**:API 提供的 URL,用於訪問特定的資源或功能。
2. **HTTP 方法**:如 GET、POST、PUT、DELETE 等,表示不同的操作。
3. **狀態碼**:如 200(成功)、404(未找到)、500(伺服器錯誤)等,用於表示請求的結果。

### Step 3: 開始使用 API

1. **獲取 API 金鑰**:通常需要在 API 提供者的網站上註冊並獲取金鑰。
2. **進行基本請求**:使用工具如 Postman 或 curl,發送一個簡單的請求來測試 API。

### Step 4: 進階使用

1. **處理 API 回應**:學習如何解析 JSON 或 XML 格式的回應數據。
2. **錯誤處理與調試**:了解常見的錯誤類型及其解決方法,使用調試工具來分析問題。

### Step 5: 安全性與最佳實踐

1. **API 安全性**:確保 API 金鑰的安全,不要在公開的代碼庫中暴露。
2. **最佳實踐**:如使用環境變量存儲敏感信息、實施重試機制等。

希望這些步驟能幫助你更好地理解和使用 Jina AI Reader 的 API 文件。如果有任何具體問題,隨時告訴我!
Result Sample 02
  • 我想要開發一個 dotnet console application, 想要串接 jina reader API, 串接文件是 https://jina.ai/reader/ 請提供我相關串接程式範例
markdown
# 使用 Jina Reader API 的 .NET Console Application 範例

## References

**Resource 1:**: [Jina Reader API Documentation](https://jina.ai/reader/)

----------------

## Outline

### Topic 1: 簡介

1. 介紹 Jina Reader API 的功能與用途。
2. 說明如何在 .NET Console Application 中串接該 API。

### Topic 2: 開發環境設置

1. 安裝 .NET SDK。
2. 建立新的 .NET Console Application 專案。

### Topic 3: 串接 Jina Reader API

1. 使用 HttpClient 發送 HTTP 請求。
2. 處理 API 回應並解析 JSON。

### Topic 4: 範例程式碼

1. 完整的 .NET Console Application 範例程式碼。

----------------

## Step-by-step Tutorial

### Step 1: 簡介

Jina Reader API 是一個免費且不需要 API 金鑰的服務,能夠將任何 URL 轉換為適合 LLM(大規模語言模型)輸入的乾淨文本。這對於需要從網頁獲取高質量內容的應用非常有用。

### Step 2: 開發環境設置

1. **安裝 .NET SDK**

- 前往 [.NET 官網](https://dotnet.microsoft.com/download) 下載並安裝最新版本的 .NET SDK。

2. **建立新的 .NET Console Application 專案**

- 打開命令提示字元或終端機,執行以下命令來建立新的專案:
  ```bash
  dotnet new console -n JinaReaderExample
  cd JinaReaderExample

Step 3: 串接 Jina Reader API

  1. 使用 HttpClient 發送 HTTP 請求
  • 在專案中安裝 System.Net.Http 套件(如果尚未安裝):
    bash
    dotnet add package System.Net.Http
  1. 處理 API 回應並解析 JSON
  • 使用 HttpClient 發送請求並處理回應。

Step 4: 範例程式碼

以下是完整的 .NET Console Application 範例程式碼,展示如何串接 Jina Reader API:

csharp
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace JinaReaderExample
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // 要處理的 URL
            string url = "https://example.com";
            string readerApiUrl = $"https://r.jina.ai/{url}";

            using (HttpClient client = new HttpClient())
            {
                try
                {
                    // 發送 GET 請求
                    HttpResponseMessage response = await client.GetAsync(readerApiUrl);
                    response.EnsureSuccessStatusCode();

                    // 讀取回應內容
                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine("Processed Content:");
                    Console.WriteLine(responseBody);
                }
                catch (HttpRequestException e)
                {
                    Console.WriteLine("Request error:");
                    Console.WriteLine(e.Message);
                }
            }
        }
    }
}

Step 5: 執行應用程式

  1. 在命令提示字元或終端機中,執行以下命令來編譯並運行應用程式:

    bash
    dotnet run
  2. 應用程式將會發送請求到 Jina Reader API,並在控制台中顯示處理後的內容。

這樣,你就完成了一個簡單的 .NET Console Application,並成功串接了 Jina Reader API。

Jina Reader API 簡介

討論
  • 什麼是 Jina Reader API?
  • 如何透過瀏覽器直接呼叫此 Jina Reader API?
  • 經由 Jina Reader API 產出的文檔位什麼對於 LLM 非常容易解讀?
  • 如何透過在 Console Application 中呼叫此 Jina Reader API?
  • 呼叫 Jina Reader API 的 Request Header 參數代表什麼涵義?

透過 HttpClient 請求 Jina Reader API

Code Sample
csharp
private static async Task<string> GetJinaReadApiResponse(string uri)
{
    try
    {
        using HttpResponseMessage response = await client.GetAsync(uri);
        response.EnsureSuccessStatusCode();
        string responseBody = await response.Content.ReadAsStringAsync();
        //string responseBody = await client.GetStringAsync(uri);
        return responseBody;
    }
    catch (Exception e)
    {
        Console.WriteLine("Message :{0} ", e.Message);
        return null;
    }
}

API and SDK

Install OpenAI .NET SDK (2.0.0-beta.4)

.NET OpenAI SDK ChatCompletion Sample

csharp
private static async Task<string> GetChatCompletionAsync(string prompt)
{
    try
    {
        ChatClient openClient = new(model: "gpt-4o", "sk-??");
        ChatCompletion completion = await openClient.CompleteChatAsync(prompt);
        return $"{completion}";
    }
    catch (Exception ex)
    {
        Console.WriteLine($"open ai chat completion api exception: {ex.Message}");
        return null;
    }
}
Code Sample
csharp
using System.ClientModel;
using System.Text;
using OpenAI.Chat;

namespace PE02.DocumentOutliner;

class Program
{
    private static readonly string JinaReaderApiPrefix = "https://r.jina.ai/";
    private static readonly string OpenAiApiKey = "sk-??";

    static async Task Main(string[] args)
    {
        var url = "https://stackoverflow.com/questions/33164725/confusion-between-isnan-and-number-isnan-in-javascript";
        var dateTimeString = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
        var jinaFileName = "jina.md";
        var openAiFileName = "openai.md";

        var jinaApiResponse = await GetJinaReaderApiResponse(url);

        if (!string.IsNullOrEmpty(jinaApiResponse))
        {
            await File.WriteAllTextAsync($"{dateTimeString}-{jinaFileName}", jinaApiResponse);
        }

        var openAiResponse = await GetChatCompletionSteaming(jinaApiResponse);
        if (!string.IsNullOrEmpty(openAiResponse))
        {
            await File.WriteAllTextAsync($"{dateTimeString}-{openAiFileName}", openAiResponse);
        }
    }

    private static async Task<string> GetJinaReaderApiResponse(string uri)
    {
        try
        {
            string requestUrl = $"{JinaReaderApiPrefix}{uri}";
            using HttpClient client = new HttpClient();
            // Add DOM element selector to extract the content from the page
            client.DefaultRequestHeaders.Add("X-Target-Selector", "#content");
            HttpResponseMessage response = await client.GetAsync(requestUrl);
            response.EnsureSuccessStatusCode();
            string responseBody = await response.Content.ReadAsStringAsync();
            return responseBody;
        }
        catch (Exception e)
        {
            Console.WriteLine($"Unexpected error: {e.Message}");
            return null;
        }
    }

    private static async Task<string> GetChatCompletion(string source)
    {
        try
        {
            ChatClient client = new(model: "gpt-4o", OpenAiApiKey);
            var assistantPrompt =
                """
                You are a senior web developer reading a document from providing document source.
                You need to create an development document for a coding student.
                Please provide step by step instructions and clear explanations for each step.
                Please generate output in a markdown format and output using traditional chinese.
                =================
                """;
            var prompt = $"{assistantPrompt}{source}";
            ChatCompletion completion = await client.CompleteChatAsync(prompt);
            return $"{completion}";
        }
        catch (Exception e)
        {
            Console.WriteLine($"Unexpected error: {e.Message}");
            return null;
        }
    }

    private static async Task<string> GetChatCompletionSteaming(string source)
    {
        try
        {
            StringBuilder result = new();
            var assistantPrompt =
                """
                You are a senior web developer reading a document from providing document source.
                You need to create an development document for a coding student.
                Please provide step by step instructions and clear explanations for each step.
                Please generate output in a markdown format and output using traditional chinese.
                =================
                """;
            var prompt = $"{assistantPrompt}{source}";
            ChatClient client = new(model: "gpt-4o", OpenAiApiKey);
            AsyncResultCollection<StreamingChatCompletionUpdate> updates
                = client.CompleteChatStreamingAsync(prompt);
            await foreach (StreamingChatCompletionUpdate update in updates)
            {
                foreach (ChatMessageContentPart updatePart in update.ContentUpdate)
                {
                    Console.Write(updatePart.Text);
                    result.Append(updatePart.Text);
                }
            }

            return result.ToString();
        }
        catch (Exception e)
        {
            Console.WriteLine($"Unexpected error: {e.Message}");
            return null;
        }
    }
}