From 994e125442ddb8c98ec3b5fd3db51dea1496eda1 Mon Sep 17 00:00:00 2001 From: fukuoka-t Date: Fri, 26 Jun 2026 16:55:42 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E7=94=BB=E9=9D=A2=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release-upload-zip.yml | 24 +--- SampleCSharpUI/App.config | 18 +-- .../Converters/Boolean2CollapsedConverter.cs | 2 +- .../Converters/Boolean2VisibilityConverter.cs | 2 +- .../Converters/Null2CollapsedConverter.cs | 2 +- .../Converters/Null2FalseConverter.cs | 2 +- .../RoleToHorizontalAlignmentConverter.cs | 4 +- SampleCSharpUI/Models/ChatModel.cs | 113 +++++++++++++----- SampleCSharpUI/Properties/AssemblyInfo.cs | 4 +- .../Properties/Resources.Designer.cs | 18 +++ SampleCSharpUI/Properties/Resources.resx | 6 + SampleCSharpUI/SampleCSharpUI.csproj | 82 +++++++------ SampleCSharpUI/ViewModels/LoginViewModel.cs | 75 ++++++++++++ SampleCSharpUI/ViewModels/MainViewModel.cs | 29 ++--- SampleCSharpUI/Views/LoginWindow.xaml | 57 +++++++++ SampleCSharpUI/Views/LoginWindow.xaml.cs | 35 ++++++ SampleCSharpUI/Views/MainWindow.xaml.cs | 19 ++- SampleCSharpUI/packages.config | 37 +++--- 18 files changed, 391 insertions(+), 138 deletions(-) create mode 100644 SampleCSharpUI/ViewModels/LoginViewModel.cs create mode 100644 SampleCSharpUI/Views/LoginWindow.xaml create mode 100644 SampleCSharpUI/Views/LoginWindow.xaml.cs diff --git a/.github/workflows/release-upload-zip.yml b/.github/workflows/release-upload-zip.yml index d360e21..6e8c067 100644 --- a/.github/workflows/release-upload-zip.yml +++ b/.github/workflows/release-upload-zip.yml @@ -46,25 +46,13 @@ jobs: -Path SampleCSharpUI/bin/Release/* ` -DestinationPath SampleCSharpUI-${{ github.ref_name }}.zip - # Release 作成(タグ名を使用) - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Release を作成または更新し、ZIP を添付 + - name: Create or Update Release and Upload ZIP + uses: softprops/action-gh-release@v3 with: tag_name: ${{ github.ref_name }} - release_name: Release ${{ github.ref_name }} + name: Release ${{ github.ref_name }} draft: false prerelease: false - - # ZIP を Release に Upload(ご指定どおり) - - name: Upload ZIP to Release - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: SampleCSharpUI-${{ github.ref_name }}.zip - asset_name: SampleCSharpUI-${{ github.ref_name }}.zip - asset_content_type: application/zip + overwrite_files: true + files: SampleCSharpUI-${{ github.ref_name }}.zip diff --git a/SampleCSharpUI/App.config b/SampleCSharpUI/App.config index 4cab0d1..29f0bde 100644 --- a/SampleCSharpUI/App.config +++ b/SampleCSharpUI/App.config @@ -11,7 +11,7 @@ - + @@ -23,11 +23,11 @@ - + - + @@ -35,19 +35,23 @@ - + - + - + - + + + + + diff --git a/SampleCSharpUI/Converters/Boolean2CollapsedConverter.cs b/SampleCSharpUI/Converters/Boolean2CollapsedConverter.cs index cfe8f6b..04f08bd 100644 --- a/SampleCSharpUI/Converters/Boolean2CollapsedConverter.cs +++ b/SampleCSharpUI/Converters/Boolean2CollapsedConverter.cs @@ -5,7 +5,7 @@ namespace SampleCSharpUI.Converters { - internal class Boolean2CollapsedConverter : IValueConverter + public class Boolean2CollapsedConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/SampleCSharpUI/Converters/Boolean2VisibilityConverter.cs b/SampleCSharpUI/Converters/Boolean2VisibilityConverter.cs index 227e552..16b720e 100644 --- a/SampleCSharpUI/Converters/Boolean2VisibilityConverter.cs +++ b/SampleCSharpUI/Converters/Boolean2VisibilityConverter.cs @@ -5,7 +5,7 @@ namespace SampleCSharpUI.Converters { - internal class Boolean2VisibilityConverter : IValueConverter + public class Boolean2VisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/SampleCSharpUI/Converters/Null2CollapsedConverter.cs b/SampleCSharpUI/Converters/Null2CollapsedConverter.cs index 559a3db..39d2696 100644 --- a/SampleCSharpUI/Converters/Null2CollapsedConverter.cs +++ b/SampleCSharpUI/Converters/Null2CollapsedConverter.cs @@ -9,7 +9,7 @@ namespace SampleCSharpUI.Converters { - internal class Null2CollapsedConverter : IValueConverter + public class Null2CollapsedConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/SampleCSharpUI/Converters/Null2FalseConverter.cs b/SampleCSharpUI/Converters/Null2FalseConverter.cs index 211a8dd..a2f1993 100644 --- a/SampleCSharpUI/Converters/Null2FalseConverter.cs +++ b/SampleCSharpUI/Converters/Null2FalseConverter.cs @@ -9,7 +9,7 @@ namespace SampleCSharpUI.Converters { - internal class Null2FalseConverter : IValueConverter + public class Null2FalseConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/SampleCSharpUI/Converters/RoleToHorizontalAlignmentConverter.cs b/SampleCSharpUI/Converters/RoleToHorizontalAlignmentConverter.cs index c22ec3b..5f80557 100644 --- a/SampleCSharpUI/Converters/RoleToHorizontalAlignmentConverter.cs +++ b/SampleCSharpUI/Converters/RoleToHorizontalAlignmentConverter.cs @@ -5,7 +5,7 @@ namespace SampleCSharpUI.Converters { - internal class RoleToHorizontalAlignmentConverter : IValueConverter + public class RoleToHorizontalAlignmentConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { @@ -16,7 +16,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn } else { - return Visibility.Collapsed; + return HorizontalAlignment.Left; } } diff --git a/SampleCSharpUI/Models/ChatModel.cs b/SampleCSharpUI/Models/ChatModel.cs index b5e4aee..a33fd72 100644 --- a/SampleCSharpUI/Models/ChatModel.cs +++ b/SampleCSharpUI/Models/ChatModel.cs @@ -515,7 +515,7 @@ internal async Task SendMessageAsync(string id, string inputText) /// /// ルームID /// 入力 - internal async Task SendMessageStreamingAsync(string id, string inputText) + internal async Task SendRoomMessageStreamingAsync(string id, string inputText) { var content = inputText ?? string.Empty; if (!string.IsNullOrWhiteSpace(content)) @@ -526,43 +526,56 @@ internal async Task SendMessageStreamingAsync(string id, string inputText) content = content, }; + // 質問のメッセージ追加 + this.SetMessage("user", content, DateTime.UtcNow.ToLocalTime(), new List()); + // ここで body を JSON 文字列にシリアライズして変数に格納する using (var ms = new MemoryStream()) { var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(APIData.TChatMessage)); { serializer.WriteObject(ms, body); - var bodyJsonString = Encoding.UTF8.GetString(ms.ToArray()); - var jsonString = await HttpHelper.PostRequestAsync($"/api/v1/chats/{id}/messages", this.IdToken, bodyJsonString); - using (var json = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonString))) + + // Streaming回答表示完了待ち + while (this.IsStreaming) { - var ser = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(APIData.TChatMessage)); + await Task.Delay(100); + } + this.IsStreaming = true; + + try + { + var bodyJsonString = Encoding.UTF8.GetString(ms.ToArray()); + var jsonString = await HttpHelper.PostRequestAsync($"/api/v1/chats/{id}/messages", this.IdToken, bodyJsonString); + using (var json = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonString))) { - // 質問のメッセージ追加 - var item = ser.ReadObject(json) as APIData.TChatMessage; - if (item?.role != null) - { - this.SetMessage(item.role, - item.content, - DateTimeOffset.FromUnixTimeMilliseconds(item.timeunix).ToLocalTime().DateTime, - item.ref_chunks is null ? new List() : item.ref_chunks?.Select((x) => x.text.Replace("\n\n", "\n")).ToList()); - } - else + var ser = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(APIData.TChatMessage)); { - throw new Exception(jsonString); + // 回答のメッセージ追加 + var item = ser.ReadObject(json) as APIData.TChatMessage; + if (item?.role != null) + { + // 質問は送信できたので回答のStreamingを待ち合わせる + } + else + { + // ここでLLM-GRでのBlockメッセージが返却される + this.SetMessage("ai", jsonString, DateTime.UtcNow.ToLocalTime(), new List()); + + // 待ち合わせ処理をSKIPする + throw new Exception(jsonString); + } } + json.Close(); + + // 最新行表示 + OnPropertyChanged("Messages_Item"); } - json.Close(); - // 最新行表示 + // AIからの回答取得 + var msgId = this.SetMessage("ai", Resources.Streaming, DateTime.UtcNow.ToLocalTime(), new List()); OnPropertyChanged("Messages_Item"); - } - // AIからの回答取得 - var msgId = this.SetMessage("ai", Resources.Streaming, DateTime.UtcNow.ToLocalTime(), new List()); - OnPropertyChanged("Messages_Item"); - try - { // Stream受信イベントハンドラー登録 HttpHelper.StreamEventReceived += async (s, e) => { @@ -626,11 +639,11 @@ internal async Task SendMessageStreamingAsync(string id, string inputText) } OnPropertyChanged("Messages_Item"); } - catch + catch (Exception ex) { this.IsStreaming = false; - // エラー発生時はAI回答欄を削除する。 - this.Messages.Remove(this.Messages.Where((x) => x.Id == msgId).FirstOrDefault()); + // エラー発生時はAI回答欄にエラーを表示する(チャットルームの履歴が保持されるので、エラーは一時的なものとして扱う)。 + this.SetMessage(msgId, "ai", ex.Message, DateTime.UtcNow.ToLocalTime(), new List()); // エラー伝搬は省略(必要であればイベントを定義して伝搬すること) //throw ex; @@ -644,9 +657,9 @@ internal async Task SendMessageStreamingAsync(string id, string inputText) catch (Exception ex) { this.IsStreaming = false; - // エラー発生時はAI回答欄を削除し、exceptionを投げる - this.Messages.Remove(this.Messages.Where((x) => x.Id == msgId).FirstOrDefault()); - throw ex; + + // エラー伝搬は省略(必要であればイベントを定義して伝搬すること) + //throw ex; } } } @@ -1003,6 +1016,46 @@ internal async Task SaveMessagesAsMarkdownAsync(string path) } #endregion + /// + /// 入力する + /// + /// + /// + internal async Task SendAsync(string content, string filePath) + { + if (!string.IsNullOrWhiteSpace(content)) + { + try + { + if (!string.IsNullOrEmpty(this.SelectedChatRoom?.ID)) + { + await this.SendRoomMessageStreamingAsync(this.SelectedChatRoom.ID, content); + + // Streaming回答表示完了待ち + while (this.IsStreaming) + { + await Task.Delay(100); + } + } + else if (string.IsNullOrEmpty(filePath)) + { + await this.SendMessageAsync(this.Messages.ToList(), (float)0.5, 1024, content); + OnPropertyChanged("IsStreaming"); + } + else + { + await this.SendMessageWithFileAsync(this.Messages.ToList(), (float)0.5, 1024, content, filePath); + OnPropertyChanged("IsStreaming"); + } + } + catch + { + // 追加失敗時は無視(必要であればログ追加) + } + } + } + + // プロパティが変更されたときに通知するイベント public event PropertyChangedEventHandler PropertyChanged; diff --git a/SampleCSharpUI/Properties/AssemblyInfo.cs b/SampleCSharpUI/Properties/AssemblyInfo.cs index 7949290..da302ce 100644 --- a/SampleCSharpUI/Properties/AssemblyInfo.cs +++ b/SampleCSharpUI/Properties/AssemblyInfo.cs @@ -48,5 +48,5 @@ // ビルド番号 // リビジョン // -[assembly: AssemblyVersion("1.3.0.0")] -[assembly: AssemblyFileVersion("1.3.0.0")] +[assembly: AssemblyVersion("1.3.2.0")] +[assembly: AssemblyFileVersion("1.3.2.0")] diff --git a/SampleCSharpUI/Properties/Resources.Designer.cs b/SampleCSharpUI/Properties/Resources.Designer.cs index 0ca83d3..ed6027a 100644 --- a/SampleCSharpUI/Properties/Resources.Designer.cs +++ b/SampleCSharpUI/Properties/Resources.Designer.cs @@ -303,6 +303,24 @@ public static string InvalidFileType { } } + /// + /// ログイン に類似しているローカライズされた文字列を検索します。 + /// + public static string Login { + get { + return ResourceManager.GetString("Login", resourceCulture); + } + } + + /// + /// [ログイン]をクリックして、事前に設定した内容で認証を行ってください。 に類似しているローカライズされた文字列を検索します。 + /// + public static string LoginRemarks { + get { + return ResourceManager.GetString("LoginRemarks", resourceCulture); + } + } + /// /// ルーム管理 に類似しているローカライズされた文字列を検索します。 /// diff --git a/SampleCSharpUI/Properties/Resources.resx b/SampleCSharpUI/Properties/Resources.resx index 4fd2ba1..03fe1b0 100644 --- a/SampleCSharpUI/Properties/Resources.resx +++ b/SampleCSharpUI/Properties/Resources.resx @@ -300,4 +300,10 @@ 添付を削除 + + ログイン + + + [ログイン]をクリックして、事前に設定した内容で認証を行ってください。 + \ No newline at end of file diff --git a/SampleCSharpUI/SampleCSharpUI.csproj b/SampleCSharpUI/SampleCSharpUI.csproj index 738907a..a2cd0e5 100644 --- a/SampleCSharpUI/SampleCSharpUI.csproj +++ b/SampleCSharpUI/SampleCSharpUI.csproj @@ -55,54 +55,57 @@ Images\GAP_ICON2.ico - - ..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.9\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll - - ..\packages\Microsoft.Bcl.TimeProvider.10.0.0\lib\net462\Microsoft.Bcl.TimeProvider.dll + + ..\packages\Microsoft.Bcl.Cryptography.10.0.9\lib\net462\Microsoft.Bcl.Cryptography.dll - - ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.10.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + ..\packages\Microsoft.Bcl.TimeProvider.10.0.9\lib\net462\Microsoft.Bcl.TimeProvider.dll - - ..\packages\Microsoft.Extensions.Logging.Abstractions.10.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.10.0.9\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll - - ..\packages\Microsoft.Identity.Client.4.79.2\lib\net472\Microsoft.Identity.Client.dll + + ..\packages\Microsoft.Extensions.Logging.Abstractions.10.0.9\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll - - ..\packages\Microsoft.IdentityModel.Abstractions.8.15.0\lib\net472\Microsoft.IdentityModel.Abstractions.dll + + ..\packages\Microsoft.Identity.Client.4.81.0\lib\net472\Microsoft.Identity.Client.dll - - ..\packages\Microsoft.IdentityModel.JsonWebTokens.8.15.0\lib\net472\Microsoft.IdentityModel.JsonWebTokens.dll + + ..\packages\Microsoft.IdentityModel.Abstractions.8.19.1\lib\net472\Microsoft.IdentityModel.Abstractions.dll - - ..\packages\Microsoft.IdentityModel.Logging.8.15.0\lib\net472\Microsoft.IdentityModel.Logging.dll + + ..\packages\Microsoft.IdentityModel.JsonWebTokens.8.19.1\lib\net472\Microsoft.IdentityModel.JsonWebTokens.dll - - ..\packages\Microsoft.IdentityModel.Tokens.8.15.0\lib\net472\Microsoft.IdentityModel.Tokens.dll + + ..\packages\Microsoft.IdentityModel.Logging.8.19.1\lib\net472\Microsoft.IdentityModel.Logging.dll + + + ..\packages\Microsoft.IdentityModel.Tokens.8.19.1\lib\net472\Microsoft.IdentityModel.Tokens.dll - ..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.135\lib\net462\Microsoft.Xaml.Behaviors.dll + ..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.142\lib\net462\Microsoft.Xaml.Behaviors.dll ..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll - - ..\packages\System.Diagnostics.DiagnosticSource.10.0.0\lib\net462\System.Diagnostics.DiagnosticSource.dll + + ..\packages\System.Diagnostics.DiagnosticSource.10.0.9\lib\net462\System.Diagnostics.DiagnosticSource.dll - - ..\packages\System.Formats.Asn1.10.0.0\lib\net462\System.Formats.Asn1.dll + + ..\packages\System.Formats.Asn1.10.0.9\lib\net462\System.Formats.Asn1.dll - - ..\packages\System.IdentityModel.Tokens.Jwt.8.15.0\lib\net472\System.IdentityModel.Tokens.Jwt.dll + + ..\packages\System.IdentityModel.Tokens.Jwt.8.19.1\lib\net472\System.IdentityModel.Tokens.Jwt.dll - - ..\packages\System.IO.Pipelines.10.0.0\lib\net462\System.IO.Pipelines.dll + + ..\packages\System.IO.Pipelines.10.0.9\lib\net462\System.IO.Pipelines.dll ..\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll @@ -116,18 +119,19 @@ - - ..\packages\System.Security.Cryptography.ProtectedData.10.0.0\lib\net462\System.Security.Cryptography.ProtectedData.dll + + ..\packages\System.Security.Cryptography.ProtectedData.10.0.9\lib\net462\System.Security.Cryptography.ProtectedData.dll - - ..\packages\System.Text.Encodings.Web.10.0.0\lib\net462\System.Text.Encodings.Web.dll + + ..\packages\System.Text.Encodings.Web.10.0.9\lib\net462\System.Text.Encodings.Web.dll - - ..\packages\System.Text.Json.10.0.0\lib\net462\System.Text.Json.dll + + ..\packages\System.Text.Json.10.0.9\lib\net462\System.Text.Json.dll ..\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll + @@ -170,6 +174,7 @@ + @@ -188,6 +193,9 @@ EditRetrieverWindow.xaml + + LoginWindow.xaml + ManageChatRoomsWindow.xaml @@ -224,6 +232,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -315,11 +327,11 @@ - + このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。 - + \ No newline at end of file diff --git a/SampleCSharpUI/ViewModels/LoginViewModel.cs b/SampleCSharpUI/ViewModels/LoginViewModel.cs new file mode 100644 index 0000000..581ca87 --- /dev/null +++ b/SampleCSharpUI/ViewModels/LoginViewModel.cs @@ -0,0 +1,75 @@ +using SampleCSharpUI.Commons; +using SampleCSharpUI.Models; +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace SampleCSharpUI.ViewModels +{ + public class LoginViewModel : INotifyPropertyChanged + { + private AboutModel Model = new AboutModel(); + + public string Company { get { return this.Model.Company; } } + public string AppInfo { get { return this.Model.AppInfo; } } + + /// + /// コンストラクター + /// + public LoginViewModel() + { + this.Model.PropertyChanged += (s, e) => { OnPropertyChanged(e.PropertyName); }; + } + + /// + /// バージョン情報取得 + /// + internal void GetVersion() + { + this.Model.GetVersion(); + } + + /// + /// ログイン + /// + RelayCommand _LoginCommand; + public RelayCommand LoginCommand + { + get + { + if (_LoginCommand == null) + { + _LoginCommand = new RelayCommand((target) => + { + OnMessaged("Connect"); + }); + } + return _LoginCommand; + } + set + { + _LoginCommand = value; + } + } + + /// + /// ダイアログ表示用イベント + /// + public event MessagedEventHandler Messaged; + internal virtual void OnMessaged(String message = "") + { + this.Messaged?.Invoke(this, new MessageEventArgs(message)); + } + + // プロパティが変更されたときに通知するイベント + public event PropertyChangedEventHandler PropertyChanged; + + // プロパティ変更通知を発行するメソッド + protected virtual void OnPropertyChanged([CallerMemberName] String propertyName = "") + { + var handler = this.PropertyChanged; + if (handler != null) + handler(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/SampleCSharpUI/ViewModels/MainViewModel.cs b/SampleCSharpUI/ViewModels/MainViewModel.cs index c343320..f4d3619 100644 --- a/SampleCSharpUI/ViewModels/MainViewModel.cs +++ b/SampleCSharpUI/ViewModels/MainViewModel.cs @@ -34,7 +34,11 @@ public bool IsLogin public bool IsSettings { get { return this.Model.IsSettings; } - set { OnPropertyChanged(); } + set + { + OnMessaged("Disconnect"); + OnPropertyChanged(); + } } /// @@ -375,31 +379,16 @@ public RelayCommand PreviewKeyDownCommand // メッセージを追加(ここではローカルに追加するのみ) var content = this.InputText.Trim(); this.InputText = string.Empty; - - if (!string.IsNullOrEmpty(this.SelectedChatRoom?.ID)) - { - await this.Model.SendMessageStreamingAsync(this.SelectedChatRoom.ID, content); - } - else if (string.IsNullOrEmpty(this.AttachedFilePath)) - { - await this.Model.SendMessageAsync(this.Messages.ToList(), (float)0.5, 1024, content); - } - else - { - await this.Model.SendMessageWithFileAsync(this.Messages.ToList(), (float)0.5, 1024, content, this.AttachedFilePath); - this.AttachedFilePath = null; - this.AttachedFileName = null; - } + + await this.Model.SendAsync(content, this.AttachedFilePath); + this.AttachedFilePath = null; + this.AttachedFileName = null; } catch (Exception ex) { // Command内で例外が発生した場合はここでキャッチしてメッセージ表示 OnMessaged(ex.Message); } - if (this.Model.IsStreaming == false) - { - this.EndPreviewKeyDownCommand(); - } } } }); diff --git a/SampleCSharpUI/Views/LoginWindow.xaml b/SampleCSharpUI/Views/LoginWindow.xaml new file mode 100644 index 0000000..5d3f960 --- /dev/null +++ b/SampleCSharpUI/Views/LoginWindow.xaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SampleCSharpUI/Views/LoginWindow.xaml.cs b/SampleCSharpUI/Views/LoginWindow.xaml.cs new file mode 100644 index 0000000..a2cb2f5 --- /dev/null +++ b/SampleCSharpUI/Views/LoginWindow.xaml.cs @@ -0,0 +1,35 @@ +using System.Windows; + +namespace SampleCSharpUI.Views +{ + public partial class LoginWindow : Window + { + public ViewModels.LoginViewModel ViewModel { get; } = new ViewModels.LoginViewModel(); + + public LoginWindow(MainWindow window) + { + this.Owner = window; + InitializeComponent(); + + this.ViewModel.Messaged += (s, e) => + { + if (e.Message == "Connect") + { + App.MainVM.OnMessaged("Connect"); + this.Close(); + } + }; + + App.MainVM.IsBusy = true; + try + { + this.ViewModel.GetVersion(); + } + catch (System.Exception ex) + { + MessageBox.Show(this.Owner, ex.Message, this.Title, MessageBoxButton.OK, MessageBoxImage.Exclamation); + } + App.MainVM.IsBusy = false; + } + } +} diff --git a/SampleCSharpUI/Views/MainWindow.xaml.cs b/SampleCSharpUI/Views/MainWindow.xaml.cs index 9432f3f..b8eeae7 100644 --- a/SampleCSharpUI/Views/MainWindow.xaml.cs +++ b/SampleCSharpUI/Views/MainWindow.xaml.cs @@ -24,8 +24,15 @@ public MainWindow() this.ViewModel.IsBusy = true; try { - // 初期接続 - await App.MainVM.ConnectAsync(); + if (App.MainVM.IsSettings) + { + // 初期接続 + App.MainVM.OnMessaged("Disconnect"); + } + else + { + App.MainVM.OnMessaged("Settings"); + } } catch (Exception ex) { @@ -43,6 +50,11 @@ public MainWindow() { switch (e.Message) { + case "Login": + { + await App.MainVM.ConnectAsync(); + } + break; case "Connect": { await App.MainVM.ConnectAsync(); @@ -52,6 +64,9 @@ public MainWindow() case "Disconnect": { await App.MainVM.DisconnectAsync(); + + // ログイン画面を表示 + this.ShowDialog(new LoginWindow(this) { Owner = this }); } break; diff --git a/SampleCSharpUI/packages.config b/SampleCSharpUI/packages.config index ff962fa..c8e1055 100644 --- a/SampleCSharpUI/packages.config +++ b/SampleCSharpUI/packages.config @@ -1,26 +1,27 @@  - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - - + + + - + \ No newline at end of file From 6039e0f6d759c72c67e05dac5c1e76cd339453c5 Mon Sep 17 00:00:00 2001 From: fukuoka-t Date: Fri, 26 Jun 2026 16:56:00 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20API=20=E8=AA=AC?= =?UTF-8?q?=E6=98=8E=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c1dc15c..0c6a045 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,17 @@ Fujitsu Cloud Service Genearative AI Platform の API を利用するための C 実行ファイルはフォルダごとコピーすることでインストール作業なく Windows OS 環境で実行することができます。 実行時の .NET Framework は、Windows 10 / 11 付属のものを利用します。 +--- # 使い方 ## 起動 1. SampleCSharpUI.exe をクリックして起動 2. 【初回起動時のみ】 -自動的にテナント名とクライアントIDを入力する [ 設定 ] 画面を表示するので、利用している Generative AI Platform 環境のテナント名とクライアント ID を入力して [OK] をクリックして保存してください。 -3. 自動的にサインインが始まりますので、利用している EntraID の ID とパスワードを入力してください。 -4. 「 General Use 」というルームがない場合は、自動的にRAGなしでルームを作成します。 -5. 前回利用時のルームの内容を自動的に表示します。初回起動時のみ「 General Use 」ルームが選択されます。 +自動的にテナント名とクライアントIDを入力する [ 設定 ] 画面を表示します。 + - 利用している Generative AI Platform 環境のテナント名とクライアント ID を入力 + - [OK] をクリックして保存してください。 +4. [ ログイン ] 画面が表示されるので、[ ログイン ] ボタンをクリックして表示されるブラウザ画面にて、利用している EntraID の ID とパスワードを入力してください。 +5. 「 General Use 」というルームがない場合は、自動的にRAGなしでルームを作成します。 +6. 前回利用時のルームの内容を自動的に表示します。初回起動時のみ「 General Use 」ルームが選択されます。 - 「 General Use 」ルームは起動時に会話内容が全クリアされる特別なルームです。 - 他のルームは再起動しても会話内容は維持されます。 @@ -130,14 +133,59 @@ RAG自体を削除したり、RAGに格納されているデータを変更し マルチモーダル対応は、Cohere v2 Chat 互換 API (/v2/chat)、または、Cohere OpenAI Chat Completions 互換 API (/compatibility/v1/chat/completions) を呼び出すことで実現可能です。 サンプルコードでは、Cohere v2 Chat 互換 API を使用しています。 - OpenAI 互換 API、または、Cohere V2 Chat 互換 API を呼び出すことで実現可能です。 +--- +# サンプルコードの利用 API +サンプルコードでは、Fujitsu Cloud Service Genearative AI Platform が提供する次の API を使用しています。 + +## 推論関連 +推論を実現するための API 呼び出しの為のエンドポイントやリクエストボディ、レスポンスボディの解析などは、 MVVM デザインパターンに基づき、 Models\ChatModel.cs に記載しています。 + +| 操作 | エンドポイント | 用途 | +| ---- | ---- | ---- | +| GET | /api/v1/chats | チャットルーム一覧取得 | +| POST | /api/v1/chats | チャットルーム作成 | +| PUT | /api/v1/chats/{id} | チャットルーム初期設定 | +| GET | /api/v1/chats/{id}/messages | 会話一覧取得 | +| PUT | /api/v1/chats/{id}/messages | 会話一覧削除 | +| POST | /api/v1/chats/{id}/messages | 入力(プロンプト送信) | +| POST | /api/v1/chats/{id}/messages/createNextAiMessage | LLM から回答受信 | +| GET | /api/v1/chats/{id} | チャットルーム履歴取得 | +| POST | /api/v1/action/defined/text:simple_chat/call | チャットルームなし推論 | +| POST | /api/v1/pass-through/takane/v2/chat | Cohere v2 Chat 互換 API (画像付き入力推論) | + +## チャットルーム関連 +チャットルームの作成・更新・削除は、 MVVM デザインパターンに基づき、 Models\ChatRoomModel.cs に記載しています。 + +| 操作 | エンドポイント | 用途 | +| ---- | ---- | ---- | +| GET | /api/v1/chats/{id} | チャットルーム設定取得 | +| PUT | /api/v1/chats/{id} | チャットルーム設定更新 | +| DELETE | /api/v1/chats/{id} | チャットルーム削除 | + +## RAG 関連 +RAG 関連については、 MVVM デザインパターンに基づき、 Models\RetrieverModel.cs に記載しています。 + +| 操作 | エンドポイント | 用途 | +| ---- | ---- | ---- | +| GET | /api/v1/retrievers | リトリーバー一覧取得 | +| PUT | /api/v1/retrievers/{id} | リトリーバー取得 | +| POST | /api/v1/retrievers | リトリーバー追加 | +| POST | /api/v1/files/from-url | URL からのファイルアップロード | +| POST | /api/v1/files | ローカルファイルのアップロード | +| POST | /api/v1/retrievers/{id}/process/embeddings | RAGデータ作成 | +| GET | /api/v1/retrievers/{id} | RAGデータ作成完了確認 | +| DELETE | /api/v1/retrievers/{id} | リトリーバー削除 | +| DELETE | /api/v1/retrievers/{id} | リトリーバー削除 | + +--- # サンプルコードの build 方法 サンプルコードは、Visual Studio 2026 または、Visual Studio Code を使用して実行ファイルを build できます。 Visual Studio 2026 であれば、SampleCSharpUI.sln を開いていただければ、あとは UI 上で実行や build が可能です。 Visual Studio Code の場合は、環境設定などが必要です。 +--- # 最後に このサンプルが、Fujitsu Cloud Service Generative AI Platform を活用し、皆様のユーザーエクスペリエンスを飛躍的に進化させる革新的なアプリケーションを生み出すためのインスピレーションとなれば幸いです。 さらに、本サンプルではチャットや RAG の管理においても操作性を追求した実装をアプリ側で行っていますので、皆様が開発されるアプリの管理画面設計のヒントとしてぜひご活用ください。 \ No newline at end of file