|
1 | 1 | using System; |
2 | 2 | using System.ClientModel; |
3 | | -using System.Collections.Generic; |
4 | | -using System.Text; |
5 | | -using System.Threading; |
6 | | -using System.Threading.Tasks; |
7 | | -using Azure.AI.OpenAI; |
8 | | -using OpenAI; |
9 | | -using OpenAI.Chat; |
10 | 3 |
|
11 | 4 | namespace SourceGit.AI |
12 | 5 | { |
13 | 6 | public class Service |
14 | 7 | { |
15 | | - public Service(Models.AIProvider ai) |
16 | | - { |
17 | | - _ai = ai; |
18 | | - } |
19 | | - |
20 | | - public async Task GenerateCommitMessage(string repo, string changeList, Action<string> onUpdate, CancellationToken cancellation) |
21 | | - { |
22 | | - var key = _ai.ReadApiKeyFromEnv ? Environment.GetEnvironmentVariable(_ai.ApiKey) : _ai.ApiKey; |
23 | | - var endPoint = new Uri(_ai.Server); |
24 | | - var credential = new ApiKeyCredential(key); |
25 | | - var client = _ai.Server.Contains("openai.azure.com/", StringComparison.Ordinal) |
26 | | - ? new AzureOpenAIClient(endPoint, credential) |
27 | | - : new OpenAIClient(credential, new() { Endpoint = endPoint }); |
28 | | - |
29 | | - var chatClient = client.GetChatClient(_ai.Model); |
30 | | - var options = new ChatCompletionOptions() { Tools = { ChatTools.Tool_GetDetailChangesInFile } }; |
31 | | - |
32 | | - var userMessageBuilder = new StringBuilder(); |
33 | | - userMessageBuilder |
34 | | - .AppendLine("Generate a commit message (follow the rule of conventional commit message) for given git repository.") |
35 | | - .AppendLine("- Read all given changed files before generating. Do not skip any one file.") |
36 | | - .AppendLine("- Output the conventional commit message (with detail changes in list) directly. Do not explain your output nor introduce your answer.") |
37 | | - .AppendLine(string.IsNullOrEmpty(_ai.AdditionalPrompt) ? string.Empty : _ai.AdditionalPrompt) |
38 | | - .Append("Reposiory path: ").AppendLine(repo.Quoted()) |
39 | | - .AppendLine("Changed files: ") |
40 | | - .Append(changeList); |
41 | | - |
42 | | - var messages = new List<ChatMessage>() { new UserChatMessage(userMessageBuilder.ToString()) }; |
43 | | - |
44 | | - do |
45 | | - { |
46 | | - ChatCompletion completion = await chatClient.CompleteChatAsync(messages, options, cancellation); |
47 | | - var inProgress = false; |
48 | | - |
49 | | - switch (completion.FinishReason) |
50 | | - { |
51 | | - case ChatFinishReason.Stop: |
52 | | - onUpdate?.Invoke(string.Empty); |
53 | | - onUpdate?.Invoke("[Assistant]:"); |
54 | | - if (completion.Content.Count > 0) |
55 | | - onUpdate?.Invoke(completion.Content[0].Text); |
56 | | - else |
57 | | - onUpdate?.Invoke("[No content was generated.]"); |
58 | | - break; |
59 | | - case ChatFinishReason.Length: |
60 | | - throw new Exception("The response was cut off because it reached the maximum length. Consider increasing the max tokens limit."); |
61 | | - case ChatFinishReason.ToolCalls: |
62 | | - { |
63 | | - messages.Add(new AssistantChatMessage(completion)); |
64 | | - |
65 | | - foreach (var call in completion.ToolCalls) |
66 | | - { |
67 | | - var result = await ChatTools.Process(call, onUpdate); |
68 | | - messages.Add(result); |
69 | | - } |
70 | | - |
71 | | - inProgress = true; |
72 | | - break; |
73 | | - } |
74 | | - case ChatFinishReason.ContentFilter: |
75 | | - throw new Exception("Ommitted content due to a content filter flag"); |
76 | | - default: |
77 | | - break; |
78 | | - } |
79 | | - |
80 | | - if (!inProgress) |
81 | | - break; |
82 | | - } while (true); |
83 | | - } |
84 | | - |
85 | | - private readonly Models.AIProvider _ai; |
| 8 | + public string Name { get; set; } |
| 9 | + public string Server { get; set; } |
| 10 | + public string Model { get; set; } |
| 11 | + public string ApiKey { get; set; } |
| 12 | + public bool ReadApiKeyFromEnv { get; set; } |
| 13 | + public string AdditionalPrompt { get; set; } |
| 14 | + public ApiKeyCredential Credential => new ApiKeyCredential(ReadApiKeyFromEnv ? Environment.GetEnvironmentVariable(ApiKey) : ApiKey); |
86 | 15 | } |
87 | 16 | } |
0 commit comments