From a2158d0821c2a4801639e901768eb7e2841d464c Mon Sep 17 00:00:00 2001 From: Milkey Tan Date: Wed, 20 Mar 2024 22:15:50 +0800 Subject: [PATCH] FormImport --- Onllama.Tiny/Form1.cs | 4 +- Onllama.Tiny/FormImport.Designer.cs | 195 ++++++++++++++++++ Onllama.Tiny/FormImport.cs | 69 +++++++ Onllama.Tiny/FormImport.resx | 120 +++++++++++ Onllama.Tiny/FormSettings.cs | 12 +- Onllama.Tiny/Properties/Resources.Designer.cs | 56 ++++- Onllama.Tiny/Properties/Resources.resx | 36 +++- Onllama.Tiny/Resources/setting.png | Bin 6349 -> 0 bytes 8 files changed, 479 insertions(+), 13 deletions(-) create mode 100644 Onllama.Tiny/FormImport.Designer.cs create mode 100644 Onllama.Tiny/FormImport.cs create mode 100644 Onllama.Tiny/FormImport.resx delete mode 100644 Onllama.Tiny/Resources/setting.png diff --git a/Onllama.Tiny/Form1.cs b/Onllama.Tiny/Form1.cs index c35d92b..74ad73b 100644 --- a/Onllama.Tiny/Form1.cs +++ b/Onllama.Tiny/Form1.cs @@ -280,12 +280,12 @@ private void dropdown1_SelectedValueChanged(object sender, object value) { if (value.ToString() == "导入模型") { - MessageBox.Show("imp"); + new FormImport().ShowDialog(); + ListModels(); } else if (value.ToString() == "Ollama 设置") { new FormSettings().ShowDialog(); - Notification.info(this, "设置已更改", "请手动重启 Ollama 核心以使配置生效。"); } else if (value.ToString() == "刷新模型列表") { diff --git a/Onllama.Tiny/FormImport.Designer.cs b/Onllama.Tiny/FormImport.Designer.cs new file mode 100644 index 0000000..28a255c --- /dev/null +++ b/Onllama.Tiny/FormImport.Designer.cs @@ -0,0 +1,195 @@ +namespace Onllama.Tiny +{ + partial class FormImport + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + panel1 = new AntdUI.Panel(); + inputMf = new AntdUI.Input(); + select1 = new AntdUI.Select(); + buttonSave = new AntdUI.Button(); + panel2 = new AntdUI.Panel(); + input1 = new AntdUI.Input(); + buttonOpen = new AntdUI.Button(); + divider2 = new AntdUI.Divider(); + divider1 = new AntdUI.Divider(); + inputName = new AntdUI.Input(); + panel1.SuspendLayout(); + panel2.SuspendLayout(); + SuspendLayout(); + // + // panel1 + // + panel1.Controls.Add(inputName); + panel1.Controls.Add(inputMf); + panel1.Controls.Add(select1); + panel1.Controls.Add(buttonSave); + panel1.Controls.Add(panel2); + panel1.Controls.Add(divider2); + panel1.Controls.Add(divider1); + panel1.Location = new Point(12, 12); + panel1.Name = "panel1"; + panel1.Shadow = 5; + panel1.Size = new Size(560, 387); + panel1.TabIndex = 1; + panel1.Text = "panel1"; + // + // inputMf + // + inputMf.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + inputMf.BackColor = Color.Transparent; + inputMf.Location = new Point(11, 176); + inputMf.Multiline = true; + inputMf.Name = "inputMf"; + inputMf.Size = new Size(538, 167); + inputMf.TabIndex = 8; + // + // select1 + // + select1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + select1.BackColor = Color.Transparent; + select1.Items.AddRange(new object[] { "qwen", "yi", "gemma", "mistral" }); + select1.Location = new Point(11, 140); + select1.Name = "select1"; + select1.Size = new Size(538, 30); + select1.TabIndex = 7; + select1.SelectedValueChanged += select1_SelectedValueChanged; + // + // buttonSave + // + buttonSave.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + buttonSave.BackColor = Color.Transparent; + buttonSave.BorderWidth = 1F; + buttonSave.Location = new Point(11, 349); + buttonSave.Name = "buttonSave"; + buttonSave.Size = new Size(538, 30); + buttonSave.TabIndex = 6; + buttonSave.Text = "导入"; + buttonSave.Click += buttonSave_Click; + // + // panel2 + // + panel2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + panel2.BackColor = Color.Transparent; + panel2.Controls.Add(input1); + panel2.Controls.Add(buttonOpen); + panel2.Location = new Point(11, 32); + panel2.Name = "panel2"; + panel2.Size = new Size(538, 35); + panel2.TabIndex = 2; + // + // input1 + // + input1.Dock = DockStyle.Fill; + input1.JoinRight = true; + input1.Location = new Point(0, 0); + input1.Margin = new Padding(5); + input1.Margins = 6; + input1.Name = "input1"; + input1.PlaceholderText = "qwen1_5-14b-chat-q4_0.gguf"; + input1.Size = new Size(489, 35); + input1.TabIndex = 0; + // + // buttonOpen + // + buttonOpen.AutoSizeMode = AntdUI.TAutoSize.Width; + buttonOpen.BorderWidth = 1F; + buttonOpen.Dock = DockStyle.Right; + buttonOpen.Ghost = true; + buttonOpen.JoinLeft = true; + buttonOpen.Location = new Point(489, 0); + buttonOpen.Margins = 6; + buttonOpen.Name = "buttonOpen"; + buttonOpen.Size = new Size(49, 35); + buttonOpen.TabIndex = 1; + buttonOpen.Text = "选择"; + buttonOpen.Click += buttonOpen_Click; + // + // divider2 + // + divider2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + divider2.BackColor = Color.Transparent; + divider2.Location = new Point(8, 111); + divider2.Name = "divider2"; + divider2.Orientation = AntdUI.TOrientation.Left; + divider2.Size = new Size(544, 23); + divider2.TabIndex = 3; + divider2.Text = "Modelfile"; + // + // divider1 + // + divider1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + divider1.BackColor = Color.Transparent; + divider1.Location = new Point(8, 8); + divider1.Name = "divider1"; + divider1.Orientation = AntdUI.TOrientation.Left; + divider1.Size = new Size(544, 23); + divider1.TabIndex = 0; + divider1.Text = "模型位置"; + // + // inputName + // + inputName.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + inputName.BackColor = Color.Transparent; + inputName.Location = new Point(11, 75); + inputName.Name = "inputName"; + inputName.PlaceholderText = "qwen"; + inputName.Size = new Size(538, 30); + inputName.TabIndex = 9; + // + // FormImport + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(584, 411); + Controls.Add(panel1); + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + Name = "FormImport"; + Text = "导入"; + Load += FormImport_Load; + panel1.ResumeLayout(false); + panel2.ResumeLayout(false); + panel2.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private AntdUI.Panel panel1; + private AntdUI.Select select1; + private AntdUI.Button buttonSave; + private AntdUI.Panel panel2; + private AntdUI.Input input1; + private AntdUI.Button buttonOpen; + private AntdUI.Divider divider2; + private AntdUI.Divider divider1; + private AntdUI.Input inputMf; + private AntdUI.Input inputName; + } +} \ No newline at end of file diff --git a/Onllama.Tiny/FormImport.cs b/Onllama.Tiny/FormImport.cs new file mode 100644 index 0000000..44a77f9 --- /dev/null +++ b/Onllama.Tiny/FormImport.cs @@ -0,0 +1,69 @@ +using AntdUI; +using OllamaSharp.Models; +using OllamaSharp.Streamer; +using Onllama.Tiny.Properties; + +namespace Onllama.Tiny +{ + public partial class FormImport : Form + { + public FormImport() + { + InitializeComponent(); + } + + private void buttonOpen_Click(object sender, EventArgs e) + { + var f = new OpenFileDialog(); + if (f.ShowDialog() == DialogResult.OK) input1.Text = f.FileName; + inputName.Text = f.SafeFileNames.Last().Split('.', '-').First(); + foreach (var item in select1.Items) + if (input1.Text.Contains(item.ToString())) + select1.SelectedValue = item.ToString(); + } + + private void buttonSave_Click(object sender, EventArgs e) + { + AntdUI.Modal.open(new AntdUI.Modal.Config(this, "您确定要导入模型吗?", + new[] + { + new Modal.TextLine(inputName.Text, Style.Db.Primary) + }, TType.Success) + { + OkType = TTypeMini.Success, + OkText = "导入", + OnOk = _ => + { + try + { + Task.Run(() => Form1.OllamaApi.CreateModel( + new CreateModelRequest + {ModelFileContent = inputMf.Text, Name = inputName.Text, Stream = true}, + new ActionResponseStreamer(x => Invoke(() => Text = x.Status)))).Wait(); + } + catch (Exception exception) + { + Console.WriteLine(exception); + } + + Invoke(Close); + return true; + } + }); + } + + private void select1_SelectedValueChanged(object sender, object value) + { + inputMf.Text = "FROM " + input1.Text + Environment.NewLine; + if (value.ToString() == "qwen") inputMf.Text += Resources.qwenTmp; + if (value.ToString() == "yi") inputMf.Text += Resources.yiTmp; + if (value.ToString() == "gemma") inputMf.Text += Resources.gemmaTmp; + if (value.ToString() == "mistral") inputMf.Text += Resources.mistralTmp; + } + + private void FormImport_Load(object sender, EventArgs e) + { + + } + } +} diff --git a/Onllama.Tiny/FormImport.resx b/Onllama.Tiny/FormImport.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/Onllama.Tiny/FormImport.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Onllama.Tiny/FormSettings.cs b/Onllama.Tiny/FormSettings.cs index 3d86d72..74e069d 100644 --- a/Onllama.Tiny/FormSettings.cs +++ b/Onllama.Tiny/FormSettings.cs @@ -48,10 +48,14 @@ private void buttonSave_Click(object sender, EventArgs e) //() => Kill("ollama app"), //() => Kill("ollama") ); - //Process.Start(Application.ExecutablePath); - //MessageBox.Show("设置完成,程序将会重启…"); - //Environment.Exit(0); - Close(); + AntdUI.Modal.open(new AntdUI.Modal.Config(this, "设置已更改", "请手动重启 Ollama 核心以使配置生效。", TType.Info) + { + OnOk = _ => + { + Invoke(Close); + return true; + } + }); } private void Kill(string name) diff --git a/Onllama.Tiny/Properties/Resources.Designer.cs b/Onllama.Tiny/Properties/Resources.Designer.cs index 804d6e9..a4006fd 100644 --- a/Onllama.Tiny/Properties/Resources.Designer.cs +++ b/Onllama.Tiny/Properties/Resources.Designer.cs @@ -61,12 +61,44 @@ internal Resources() { } /// - /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// 查找类似 TEMPLATE """<start_of_turn>user + ///{{ if .System }}{{ .System }} {{ end }}{{ .Prompt }}<end_of_turn> + ///<start_of_turn>model + ///{{ .Response }}<end_of_turn> + ///""" + ///PARAMETER stop "<start_of_turn>" + ///PARAMETER stop "<end_of_turn>" + ///PARAMETER repeat_penalty 1 的本地化字符串。 /// - internal static System.Drawing.Bitmap setting { + internal static string gemmaTmp { get { - object obj = ResourceManager.GetObject("setting", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); + return ResourceManager.GetString("gemmaTmp", resourceCulture); + } + } + + /// + /// 查找类似 TEMPLATE """[INST] {{ .System }} {{ .Prompt }} [/INST]""" + ///PARAMETER stop "[INST]" + ///PARAMETER stop "[/INST]" 的本地化字符串。 + /// + internal static string mistralTmp { + get { + return ResourceManager.GetString("mistralTmp", resourceCulture); + } + } + + /// + /// 查找类似 TEMPLATE """{{ if .System }}<|im_start|>system + ///{{ .System }}<|im_end|>{{ end }}<|im_start|>user + ///{{ .Prompt }}<|im_end|> + ///<|im_start|>assistant + ///""" + ///PARAMETER stop "<|im_start|>" + ///PARAMETER stop "<|im_end|>" 的本地化字符串。 + /// + internal static string qwenTmp { + get { + return ResourceManager.GetString("qwenTmp", resourceCulture); } } @@ -78,5 +110,21 @@ internal static string settingSvg { return ResourceManager.GetString("settingSvg", resourceCulture); } } + + /// + /// 查找类似 TEMPLATE """<|im_start|>system + ///{{ .System }}<|im_end|> + ///<|im_start|>user + ///{{ .Prompt }}<|im_end|> + ///<|im_start|>assistant + ///""" + ///PARAMETER stop "<|im_start|>" + ///PARAMETER stop "<|im_end|>" 的本地化字符串。 + /// + internal static string yiTmp { + get { + return ResourceManager.GetString("yiTmp", resourceCulture); + } + } } } diff --git a/Onllama.Tiny/Properties/Resources.resx b/Onllama.Tiny/Properties/Resources.resx index 6cfd3e1..c681dcd 100644 --- a/Onllama.Tiny/Properties/Resources.resx +++ b/Onllama.Tiny/Properties/Resources.resx @@ -117,11 +117,41 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\setting.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + TEMPLATE """<start_of_turn>user +{{ if .System }}{{ .System }} {{ end }}{{ .Prompt }}<end_of_turn> +<start_of_turn>model +{{ .Response }}<end_of_turn> +""" +PARAMETER stop "<start_of_turn>" +PARAMETER stop "<end_of_turn>" +PARAMETER repeat_penalty 1 + + + TEMPLATE """[INST] {{ .System }} {{ .Prompt }} [/INST]""" +PARAMETER stop "[INST]" +PARAMETER stop "[/INST]" + + + TEMPLATE """{{ if .System }}<|im_start|>system +{{ .System }}<|im_end|>{{ end }}<|im_start|>user +{{ .Prompt }}<|im_end|> +<|im_start|>assistant +""" +PARAMETER stop "<|im_start|>" +PARAMETER stop "<|im_end|>" <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1710874848376" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8348" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56c10.1-8.6 13.8-22.6 9.3-35.2l-0.9-2.6c-18.1-50.5-44.9-96.9-79.7-137.9l-1.8-2.1c-8.6-10.1-22.5-13.9-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85c-2.4-13.1-12.7-23.3-25.8-25.7l-2.7-0.5c-52.1-9.4-106.9-9.4-159 0l-2.7 0.5c-13.1 2.4-23.4 12.6-25.8 25.7l-15.8 85.4c-35.9 13.6-69.2 32.9-99 57.4l-81.9-29.1c-12.5-4.4-26.5-0.7-35.1 9.5l-1.8 2.1c-34.8 41.1-61.6 87.5-79.7 137.9l-0.9 2.6c-4.5 12.5-0.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5c-10.1 8.6-13.8 22.6-9.3 35.2l0.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1c8.6 10.1 22.5 13.9 35.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4c2.4 13.1 12.7 23.3 25.8 25.7l2.7 0.5c26.1 4.7 52.8 7.1 79.5 7.1 26.7 0 53.5-2.4 79.5-7.1l2.7-0.5c13.1-2.4 23.4-12.6 25.8-25.7l15.7-85c36.2-13.6 69.7-32.9 99.7-57.6l81.3 28.9c12.5 4.4 26.5 0.7 35.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l0.9-2.6c4.5-12.3 0.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9c-11.3 26.1-25.6 50.7-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97c-28.1 3.2-56.8 3.2-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9z" p-id="8349"></path><path d="M512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176z m79.2 255.2C570 602.3 541.9 614 512 614c-29.9 0-58-11.7-79.2-32.8C411.7 560 400 531.9 400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8C612.3 444 624 472.1 624 502c0 29.9-11.7 58-32.8 79.2z" p-id="8350"></path></svg> + + TEMPLATE """<|im_start|>system +{{ .System }}<|im_end|> +<|im_start|>user +{{ .Prompt }}<|im_end|> +<|im_start|>assistant +""" +PARAMETER stop "<|im_start|>" +PARAMETER stop "<|im_end|>" + \ No newline at end of file diff --git a/Onllama.Tiny/Resources/setting.png b/Onllama.Tiny/Resources/setting.png deleted file mode 100644 index d0ca063a256dbbe195c6def3266ba254c14d4726..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6349 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

pnTPpiNvsHUlIV(&{Zr`s%>5TuJncsDug+| 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