-
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 3 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 |
|---|---|---|
|
|
@@ -74,4 +74,124 @@ 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. Download the Foundry Local model. The default model OCP uses is `Phi-4-mini-instruct-generic-cpu:4`. | ||
|
|
||
| ```bash | ||
| foundry model download Phi-4-mini-instruct-generic-cpu:4 | ||
| ``` | ||
|
|
||
| Alternatively, if you want to run with a different model, say `qwen2.5-7b-instruct-generic-cpu:3`, other than the default one, download it first by running the following command. | ||
|
|
||
| ```bash | ||
| foundry model download qwen2.5-7b-instruct-generic-cpu:3 | ||
| ``` | ||
|
|
||
| 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-instruct-generic-cpu:4`. | ||
|
|
||
| ```bash | ||
| foundry model load Phi-4-mini-instruct-generic-cpu:4 | ||
| ``` | ||
|
|
||
| Alternatively, if you want to run with a different model, say `qwen2.5-7b-instruct-generic-cpu:3`, other than the default one, download it first by running the following command. | ||
|
|
||
| ```bash | ||
| foundry model load qwen2.5-7b-instruct-generic-cpu:3 | ||
| ``` | ||
|
|
||
| 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 default model OCP uses is `Phi-4-mini-instruct-generic-cpu:4`. | ||
|
|
||
|
Contributor
Author
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.
Contributor
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를 사용하지 않습니다.
Contributor
Author
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 \ | ||
| --endpoint http://host.docker.internal:55438/v1 \ | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
|
|
||
| ```powershell | ||
| # PowerShell - from locally built container | ||
| docker run -i --rm -p 8080:8080 openchat-playground:latest ` | ||
| --connector-type FoundryLocal ` | ||
| --endpoint http://host.docker.internal:55438/v1 ` | ||
| --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 \ | ||
| --endpoint http://host.docker.internal:55438/v1 \ | ||
| --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 ` | ||
| --endpoint http://host.docker.internal:55438/v1 ` | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
|
|
||
| Alternatively, if you want to run with a different model, say `qwen2.5-7b-instruct-generic-cpu:3`, make sure you've already downloaded the model by running the `foundry model load qwen2.5-7b-instruct-generic-cpu:3` command. | ||
|
|
||
| ```bash | ||
| # bash/zsh - from locally built container | ||
| docker run -i --rm -p 8080:8080 openchat-playground:latest \ | ||
| --connector-type FoundryLocal \ | ||
| --endpoint http://host.docker.internal:55438/v1 \ | ||
| --model-id qwen2.5-7b-instruct-generic-cpu:3 \ | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
|
|
||
| ```powershell | ||
| # PowerShell - from locally built container | ||
| docker run -i --rm -p 8080:8080 openchat-playground:latest ` | ||
| --connector-type FoundryLocal ` | ||
| --endpoint http://host.docker.internal:55438/v1 ` | ||
| --model-id qwen2.5-7b-instruct-generic-cpu:3 ` | ||
| --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 \ | ||
| --endpoint http://host.docker.internal:55438/v1 \ | ||
| --model-id qwen2.5-7b-instruct-generic-cpu:3 \ | ||
| --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 ` | ||
| --endpoint http://host.docker.internal:55438/v1 ` | ||
| --model-id qwen2.5-7b-instruct-generic-cpu:3 ` | ||
| --disable-foundrylocal-manager | ||
| ``` | ||
|
|
||
|
Contributor
Author
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.
다른 모델 사용에 대한 예시에도
Contributor
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.
Contributor
Author
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 |
|---|---|---|
|
|
@@ -33,6 +33,9 @@ private static readonly (ConnectorType ConnectorType, string Argument, bool IsSw | |
| (ConnectorType.DockerModelRunner, ArgumentOptionConstants.DockerModelRunner.Model, false), | ||
| // Foundry Local | ||
| (ConnectorType.FoundryLocal, ArgumentOptionConstants.FoundryLocal.Alias, false), | ||
| (ConnectorType.FoundryLocal, ArgumentOptionConstants.FoundryLocal.Endpoint, false), | ||
| (ConnectorType.FoundryLocal, ArgumentOptionConstants.FoundryLocal.ModelId, false), | ||
| (ConnectorType.FoundryLocal, ArgumentOptionConstants.FoundryLocal.DisableFoundryLocalManager, false), | ||
|
||
| // Hugging Face | ||
| (ConnectorType.HuggingFace, ArgumentOptionConstants.HuggingFace.BaseUrl, false), | ||
| (ConnectorType.HuggingFace, ArgumentOptionConstants.HuggingFace.Model, false), | ||
|
|
@@ -213,8 +216,13 @@ public static AppSettings Parse(IConfiguration config, string[] args) | |
| case FoundryLocalArgumentOptions foundryLocal: | ||
| settings.FoundryLocal ??= new FoundryLocalSettings(); | ||
| settings.FoundryLocal.Alias = foundryLocal.Alias ?? settings.FoundryLocal.Alias; | ||
| settings.FoundryLocal.Endpoint = foundryLocal.Endpoint ?? settings.FoundryLocal.Endpoint; | ||
| settings.FoundryLocal.ModelId = foundryLocal.ModelId ?? settings.FoundryLocal.ModelId; | ||
| settings.FoundryLocal.DisableFoundryLocalManager = foundryLocal.DisableFoundryLocalManager; | ||
|
|
||
| settings.Model = foundryLocal.Alias ?? settings.FoundryLocal.Alias; | ||
| settings.Model = foundryLocal.DisableFoundryLocalManager | ||
| ? foundryLocal.ModelId ?? settings.FoundryLocal.ModelId | ||
| : foundryLocal.Alias ?? settings.FoundryLocal.Alias; | ||
| break; | ||
|
|
||
| case HuggingFaceArgumentOptions huggingFace: | ||
|
|
@@ -419,12 +427,15 @@ private static void DisplayHelpForDockerModelRunner() | |
|
|
||
| private static void DisplayHelpForFoundryLocal() | ||
| { | ||
| // --model The OpenAI model name. Default to 'gpt-4.1-mini' | ||
| var foregroundColor = Console.ForegroundColor; | ||
| Console.ForegroundColor = ConsoleColor.DarkYellow; | ||
| Console.WriteLine(" ** Foundry Local: **"); | ||
| Console.ForegroundColor = foregroundColor; | ||
|
|
||
| Console.WriteLine(" TBD"); | ||
| Console.WriteLine($" {ArgumentOptionConstants.FoundryLocal.Alias} The alias. Default to 'phi-4-mini'"); | ||
| Console.WriteLine($" {ArgumentOptionConstants.FoundryLocal.Endpoint} The endpoint URL. Default to 'http://127.0.0.1:55438/v1'"); | ||
|
||
| Console.WriteLine($" {ArgumentOptionConstants.FoundryLocal.ModelId} The model ID. Default to 'Phi-4-mini-instruct-generic-cpu:4'"); | ||
| Console.WriteLine(); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,4 +20,20 @@ public class FoundryLocalSettings : LanguageModelSettings | |
| /// Gets or sets the alias of FoundryLocal. | ||
| /// </summary> | ||
| public string? Alias { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the Endpoint of FoundryLocal. | ||
| /// </summary> | ||
| public string? Endpoint { get; set; } | ||
|
||
|
|
||
| /// <summary> | ||
| /// Gets or sets the model ID of FoundryLocal. | ||
| /// </summary> | ||
| public string? ModelId { get; set; } | ||
|
||
|
|
||
| /// <summary> | ||
| /// Gets or sets a value indicating whether to disable the automatic FoundryLocal manager and use a manually configured endpoint. | ||
| /// </summary> | ||
| public bool DisableFoundryLocalManager { get; set; } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,8 @@ public class FoundryLocalConnector(AppSettings settings) : LanguageModelConnecto | |
| { | ||
| private readonly AppSettings _appSettings = settings ?? throw new ArgumentNullException(nameof(settings)); | ||
|
|
||
| private const string ApiKey = "OPENAI_API_KEY"; | ||
|
Contributor
Author
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"; |
||
|
|
||
| /// <inheritdoc/> | ||
| public override bool EnsureLanguageModelSettingsValid() | ||
| { | ||
|
|
@@ -26,9 +28,24 @@ public override bool EnsureLanguageModelSettingsValid() | |
| throw new InvalidOperationException("Missing configuration: FoundryLocal."); | ||
| } | ||
|
|
||
| if (string.IsNullOrWhiteSpace(settings.Alias!.Trim())) | ||
| if (settings.DisableFoundryLocalManager == true) | ||
|
||
| { | ||
| throw new InvalidOperationException("Missing configuration: FoundryLocal:Alias."); | ||
| if (string.IsNullOrWhiteSpace(settings.Endpoint!.Trim()) == true) | ||
| { | ||
| throw new InvalidOperationException("Missing configuration: FoundryLocal:Endpoint is required when DisableFoundryLocalManager is enabled."); | ||
| } | ||
|
|
||
| if (string.IsNullOrWhiteSpace(settings.ModelId!.Trim()) == true) | ||
| { | ||
| throw new InvalidOperationException("Missing configuration: FoundryLocal:ModelId is required when DisableFoundryLocalManager is enabled."); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| if (string.IsNullOrWhiteSpace(settings.Alias!.Trim())) | ||
| { | ||
| throw new InvalidOperationException("Missing configuration: FoundryLocal:Alias is required when DisableFoundryLocalManager is disabled."); | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
|
|
@@ -38,22 +55,41 @@ 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; | ||
|
|
||
| if (settings!.DisableFoundryLocalManager == true) | ||
| { | ||
|
||
| var settingsEndpoint = settings.Endpoint!.Trim() ?? throw new InvalidOperationException("Missing configuration: FoundryLocal:Endpoint."); | ||
| if (Uri.IsWellFormedUriString(settingsEndpoint, UriKind.Absolute) == false) | ||
| { | ||
| throw new UriFormatException($"Invalid URI: The Foundry Local endpoint '{settingsEndpoint}' is not a valid URI."); | ||
| } | ||
| endpoint = new Uri(settingsEndpoint); | ||
| modelId = settings.ModelId!.Trim() ?? throw new InvalidOperationException("Missing configuration: FoundryLocal:ModelId."); | ||
| } | ||
| else | ||
| { | ||
| 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); | ||
|
|
||
| endpoint = manager.Endpoint; | ||
| modelId = model?.ModelId ?? alias; | ||
| } | ||
|
|
||
| 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
Contributor
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 쓰지 않습니다.
Contributor
Author
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; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -134,6 +134,21 @@ public static class FoundryLocal | |
| /// Defines the constant for '--alias'. | ||
| /// </summary> | ||
| public const string Alias = "--alias"; | ||
|
|
||
| /// <summary> | ||
| /// Defines the constant for '--endpoint'. | ||
| /// </summary> | ||
| public const string Endpoint = "--endpoint"; | ||
|
|
||
| /// <summary> | ||
| /// Defines the constant for '--model-id'. | ||
| /// </summary> | ||
| public const string ModelId = "--model-id"; | ||
|
|
||
| /// <summary> | ||
| /// Defines the constant for '--disable-foundrylocal-manager'. | ||
| /// </summary> | ||
| public const string DisableFoundryLocalManager = "--disable-foundrylocal-manager"; | ||
|
||
| } | ||
|
|
||
| /// <summary> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,21 @@ public class FoundryLocalArgumentOptions : ArgumentOptions | |
| /// </summary> | ||
| public string? Alias { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the Endpoint of FoundryLocal. | ||
| /// </summary> | ||
| public string? Endpoint { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the model ID of FoundryLocal. | ||
| /// </summary> | ||
| public string? ModelId { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets a value indicating whether to disable the automatic FoundryLocal manager and use a manually configured endpoint. | ||
| /// </summary> | ||
| public bool DisableFoundryLocalManager { get; set; } | ||
|
|
||
| /// <inheritdoc/> | ||
| protected override void ParseOptions(IConfiguration config, string[] args) | ||
| { | ||
|
|
@@ -23,6 +38,9 @@ protected override void ParseOptions(IConfiguration config, string[] args) | |
| var foundryLocal = settings.FoundryLocal; | ||
|
|
||
| this.Alias ??= foundryLocal?.Alias; | ||
| this.Endpoint ??= foundryLocal?.Endpoint; | ||
| this.ModelId ??= foundryLocal?.ModelId; | ||
| this.DisableFoundryLocalManager = foundryLocal?.DisableFoundryLocalManager ?? false; | ||
|
|
||
| for (var i = 0; i < args.Length; i++) | ||
| { | ||
|
|
@@ -35,6 +53,24 @@ protected override void ParseOptions(IConfiguration config, string[] args) | |
| } | ||
| break; | ||
|
|
||
| case ArgumentOptionConstants.FoundryLocal.Endpoint: | ||
| if (i + 1 < args.Length) | ||
| { | ||
| this.Endpoint = args[++i]; | ||
| } | ||
| break; | ||
|
|
||
| case ArgumentOptionConstants.FoundryLocal.ModelId: | ||
| if (i + 1 < args.Length) | ||
| { | ||
| this.ModelId = args[++i]; | ||
| } | ||
| break; | ||
|
|
||
| case ArgumentOptionConstants.FoundryLocal.DisableFoundryLocalManager: | ||
| this.DisableFoundryLocalManager = true; | ||
|
Comment on lines
58
to
60
Contributor
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. 여기선 스위치로 처리했네요? |
||
| break; | ||
|
|
||
| default: | ||
| break; | ||
| } | ||
|
|
||


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.
우선은
phi-4-mini로 모델을 받고, 가이드 문서 하단에서foundry service listcommand를 통해서 Model ID를 가져오는 흐름으로 문서를 작성했습니다.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.
우리는 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.
Foundry Local SDK 예제 코드 에서도
var chatClient = client.GetChatClient(model?.ModelId);ModelId를 사용하고 있습니다.만약 이와 같이
Alias를 사용하면,client.GetChatClient("phi-4-mini")아래와 같은 에러가 발생합니다.