- 
                Notifications
    
You must be signed in to change notification settings  - Fork 23
 
Enable "Foundry Local" to run in local container environment #520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a17f164
              bb4ed17
              618802b
              dd9bd98
              6dae710
              424914d
              d3bbc05
              bdb91f6
              6448667
              2947935
              ecb71d7
              c4ad965
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| # OpenChat Playground with Foundry Local | ||
| 
     | 
||
| This page describes how to run OpenChat Playground (OCP) with Foundry Local models integration. | ||
| This page describes how to run OpenChat Playground (OCP) with [Foundry Local](https://learn.microsoft.com/azure/ai-foundry/foundry-local/what-is-foundry-local) integration. | ||
| 
     | 
||
| ## Get the repository root | ||
| 
     | 
||
| 
        
          
        
         | 
    @@ -18,7 +18,7 @@ This page describes how to run OpenChat Playground (OCP) with Foundry Local mode | |
| 
     | 
||
| ## Run on local machine | ||
| 
     | 
||
| 1. Make sure the Foundry Local server is up and running. | ||
| 1. Make sure the Foundry Local server is up and running with the following command. | ||
| 
     | 
||
| ```bash | ||
| foundry service start | ||
| 
          
            
          
           | 
    @@ -74,4 +74,109 @@ This page describes how to run OpenChat Playground (OCP) with Foundry Local mode | |
| --alias qwen2.5-7b | ||
| ``` | ||
| 
     | 
||
| 1. Open your web browser, navigate to `http://localhost:5280`, and enter prompts. | ||
| 1. Open your web browser, navigate to `http://localhost:5280`, and enter prompts. | ||
| 
     | 
||
| ## Run in local container | ||
| 
     | 
||
| 1. Make sure the Foundry Local server is up and running. | ||
| 
     | 
||
| ```bash | ||
| foundry service start | ||
| ``` | ||
| 
     | 
||
| 1. Get the Foundry Local service port. | ||
| 
     | 
||
| ```bash | ||
| # bash/zsh | ||
| FL_PORT_NUMBER=$(foundry service set --show true | sed -n '/^{/,/^}/p' | jq -r ".serviceSettings.port") | ||
| ``` | ||
| 
     | 
||
| ```powershell | ||
| # PowerShell | ||
| $FL_PORT_NUMBER = (foundry service set --show true | ` | ||
| ForEach-Object { ` | ||
| if ($_ -match '^{') { $capture = $true } ` | ||
| if ($capture) { $_ } ` | ||
| if ($_ -match '^}') { $capture = $false } ` | ||
| } | Out-String | ConvertFrom-Json).serviceSettings.port | ||
| ``` | ||
| 
     | 
||
| 1. Download the Foundry Local model. The default model OCP uses is `phi-4-mini`. | ||
| 
     | 
||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우선은  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우리는 ModelId를 사용하지 않습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Foundry Local SDK 예제 코드 에서도 만약 이와 같이   | 
||
| ```bash | ||
| foundry model download phi-4-mini | ||
| ``` | ||
| 
     | 
||
| Alternatively, if you want to run with a different model, say `qwen2.5-7b`, other than the default one, download it first by running the following command. | ||
| 
     | 
||
| ```bash | ||
| foundry model download qwen2.5-7b | ||
| ``` | ||
| 
     | 
||
| Make sure to follow the model MUST be selected from the CLI output of `foundry model list`. | ||
| 
     | 
||
| 1. Load the Foundry Local model. The default model OCP uses is `phi-4-mini`. | ||
| 
     | 
||
| ```bash | ||
| foundry model load phi-4-mini | ||
| ``` | ||
| 
     | 
||
| Alternatively, if you want to run with a different model, say `qwen2.5-7b`, other than the default one, download it first by running the following command. | ||
| 
     | 
||
| ```bash | ||
| foundry model load qwen2.5-7b | ||
| ``` | ||
| 
     | 
||
| 1. Make sure you are at the repository root. | ||
| 
     | 
||
| ```bash | ||
| cd $REPOSITORY_ROOT | ||
| ``` | ||
| 
     | 
||
| 1. Build a container. | ||
| 
     | 
||
| ```bash | ||
| docker build -f Dockerfile -t openchat-playground:latest . | ||
| ``` | ||
| 
     | 
||
| 1. Run the app. The `{{Model ID}}` refers to the `Model ID` shown in the output of the `foundry service list` command. | ||
| 
     | 
||
| > **NOTE**: Make sure it MUST be the model ID, instead of alias. | ||
| 
     | 
||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우리는 ModelId를 사용하지 않습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
  | 
||
| ```bash | ||
| # bash/zsh - from locally built container | ||
| docker run -i --rm -p 8080:8080 openchat-playground:latest \ | ||
| --connector-type FoundryLocal \ | ||
| --base-url http://host.docker.internal:$FL_PORT_NUMBER/ \ | ||
| --model "Phi-4-mini-instruct-generic-gpu:4" \ | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
| 
     | 
||
| ```powershell | ||
| # PowerShell - from locally built container | ||
| docker run -i --rm -p 8080:8080 openchat-playground:latest ` | ||
| --connector-type FoundryLocal ` | ||
| --base-url http://host.docker.internal:$FL_PORT_NUMBER/ ` | ||
| --model {{Model ID}} ` | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
| 
     | 
||
| ```bash | ||
| # bash/zsh - from GitHub Container Registry | ||
| docker run -i --rm -p 8080:8080 ghcr.io/aliencube/open-chat-playground/openchat-playground:latest \ | ||
| --connector-type FoundryLocal \ | ||
| --base-url http://host.docker.internal:$FL_PORT_NUMBER/ \ | ||
| --model {{Model ID}} \ | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
| 
     | 
||
| ```powershell | ||
| # PowerShell - from GitHub Container Registry | ||
| docker run -i --rm -p 8080:8080 ghcr.io/aliencube/open-chat-playground/openchat-playground:latest ` | ||
| --connector-type FoundryLocal ` | ||
| --base-url http://host.docker.internal:$FL_PORT_NUMBER/ ` | ||
| --model {{Model ID}} ` | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
| 
     | 
||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
 다른 모델 사용에 대한 예시에도  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
 client.GetChatClient 메서드에는 파라미터로 model id를 받습니다만, 
 FoundryLocalManager.cs에 이와 같이 있습니다.  | 
||
| 1. Open your web browser, navigate to `http://localhost:8080`, and enter prompts. | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| using System.ClientModel; | ||
| using System.Text.RegularExpressions; | ||
| 
     | 
||
| using Microsoft.AI.Foundry.Local; | ||
| using Microsoft.Extensions.AI; | ||
| 
        
          
        
         | 
    @@ -16,6 +17,10 @@ namespace OpenChat.PlaygroundApp.Connectors; | |
| /// <param name="settings"><see cref="AppSettings"/> instance.</param> | ||
| public class FoundryLocalConnector(AppSettings settings) : LanguageModelConnector(settings.FoundryLocal) | ||
| { | ||
| private const string ApiKey = "OPENAI_API_KEY"; | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 
 public string ApiKey { get; internal set; } = "OPENAI_API_KEY"; | 
||
| 
     | 
||
| private static readonly Regex modelIdSuffix = new(":[0-9]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); | ||
| 
     | 
||
| private readonly AppSettings _appSettings = settings ?? throw new ArgumentNullException(nameof(settings)); | ||
| 
     | 
||
| /// <inheritdoc/> | ||
| 
        
          
        
         | 
    @@ -26,9 +31,21 @@ public override bool EnsureLanguageModelSettingsValid() | |
| throw new InvalidOperationException("Missing configuration: FoundryLocal."); | ||
| } | ||
| 
     | 
||
| if (string.IsNullOrWhiteSpace(settings.Alias!.Trim())) | ||
| if (settings.DisableFoundryLocalManager == true && | ||
| string.IsNullOrWhiteSpace(settings.BaseUrl!.Trim()) == true) | ||
| { | ||
| throw new InvalidOperationException("Missing configuration: FoundryLocal:Alias."); | ||
| throw new InvalidOperationException("Missing configuration: FoundryLocal:BaseUrl is required when DisableFoundryLocalManager is enabled."); | ||
| } | ||
| 
     | 
||
| if (string.IsNullOrWhiteSpace(settings.AliasOrModel!.Trim()) == true) | ||
| { | ||
| throw new InvalidOperationException("Missing configuration: FoundryLocal:AliasOrModel."); | ||
| } | ||
| 
     | 
||
| if (settings.DisableFoundryLocalManager == true && | ||
| modelIdSuffix.IsMatch(settings.AliasOrModel!.Trim()!) == false) | ||
| { | ||
| throw new InvalidOperationException("When DisableFoundryLocalManager is true, FoundryLocal:AliasOrModel must be the exact model name with version suffix."); | ||
| } | ||
| 
     | 
||
| return true; | ||
| 
        
          
        
         | 
    @@ -38,23 +55,53 @@ public override bool EnsureLanguageModelSettingsValid() | |
| public override async Task<IChatClient> GetChatClientAsync() | ||
| { | ||
| var settings = this.Settings as FoundryLocalSettings; | ||
| var alias = settings!.Alias!.Trim() ?? throw new InvalidOperationException("Missing configuration: FoundryLocal:Alias."); | ||
| 
     | 
||
| var manager = await FoundryLocalManager.StartModelAsync(aliasOrModelId: alias).ConfigureAwait(false); | ||
| var model = await manager.GetModelInfoAsync(aliasOrModelId: alias).ConfigureAwait(false); | ||
| (Uri? endpoint, string? modelId) = settings!.DisableFoundryLocalManager == true | ||
| ? ParseFromModelId(settings) | ||
| : await ParseFromManagerAsync(settings).ConfigureAwait(false); | ||
| 
     | 
||
| var credential = new ApiKeyCredential(manager.ApiKey); | ||
| var credential = new ApiKeyCredential(ApiKey); | ||
| var options = new OpenAIClientOptions() | ||
| { | ||
| Endpoint = manager.Endpoint, | ||
| Endpoint = endpoint, | ||
| }; | ||
| 
     | 
||
| var client = new OpenAIClient(credential, options); | ||
| var chatClient = client.GetChatClient(model?.ModelId) | ||
| var chatClient = client.GetChatClient(modelId) | ||
| .AsIChatClient(); | ||
| 
     | 
||
| Console.WriteLine($"The {this._appSettings.ConnectorType} connector created with model: {alias}"); | ||
| Console.WriteLine($"The {this._appSettings.ConnectorType} connector created with model: {modelId}"); | ||
| 
         
      Comment on lines
    
      +70
     to 
      +73
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. modelId 쓰지 않습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. client.GetChatClient 에서 alias 값을 그대로 사용하면, 에러가 발생합니다.  | 
||
| 
     | 
||
| return chatClient; | ||
| } | ||
| 
     | 
||
| private static (Uri? endpoint, string? modelId) ParseFromModelId(FoundryLocalSettings settings) | ||
| { | ||
| var baseUrl = settings.BaseUrl!.Trim() ?? throw new InvalidOperationException("Missing configuration: FoundryLocal:BaseUrl."); | ||
| if (Uri.IsWellFormedUriString(baseUrl, UriKind.Absolute) == false) | ||
| { | ||
| throw new UriFormatException($"Invalid URI: The Foundry Local base URL '{baseUrl}' is not a valid URI."); | ||
| } | ||
| 
     | 
||
| var endpoint = new Uri($"{baseUrl.TrimEnd('/')}/v1"); | ||
| var modelId = settings.AliasOrModel!.Trim() ?? throw new InvalidOperationException("Missing configuration: FoundryLocal:AliasOrModel."); | ||
| if (modelIdSuffix.IsMatch(modelId) == false) | ||
| { | ||
| throw new InvalidOperationException("When DisableFoundryLocalManager is true, FoundryLocal:AliasOrModel must be the exact model name with version suffix."); | ||
| } | ||
| 
     | 
||
| return (endpoint, modelId); | ||
| } | ||
| 
     | 
||
| private static async Task<(Uri? endpoint, string? modelId)> ParseFromManagerAsync(FoundryLocalSettings settings) | ||
| { | ||
| var alias = settings!.AliasOrModel!.Trim() ?? throw new InvalidOperationException("Missing configuration: FoundryLocal:AliasOrModel."); | ||
| var manager = await FoundryLocalManager.StartModelAsync(aliasOrModelId: alias).ConfigureAwait(false); | ||
| var model = await manager.GetModelInfoAsync(aliasOrModelId: alias).ConfigureAwait(false); | ||
| 
     | 
||
| var endpoint = manager.Endpoint; | ||
| var modelId = model!.ModelId; | ||
| 
     | 
||
| return (endpoint, modelId); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Port가 랜덤으로 뽑히는 것 같습니다.
그래서 명시적으로
55438로 set 을 하는 가이드 문구를 추가 했습니다.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
foundry service set --port같은 명령어를 이용하면 우리가 정할 수 있기는 합니다.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
appsettings.josn의 기본 값인
55438입니다.foundry local startcommand 에서 나온 port를 입력해 주세요.55438로 할 테니 사용자 여러분께서 맞춰주세요.이렇게 두 가지 방법으로 가이드를 줄 수 있을 것 같은데 후자가 조금 더 편할 것 같아서
foundry service set --port로 했습니다.그리고 다른 port를 사용하는 방법을 추가로 문서에 넣었습니다.
추가로
55438은 작업 당시에 foundry local start 에서 나온 랜덤으로 선택된 port 입니다.