Skip to content

Commit 730af6c

Browse files
author
Milder Hernandez Cagua
committed
Add Github plugin to learn resources
1 parent c535e61 commit 730af6c

File tree

2 files changed

+363
-0
lines changed

2 files changed

+363
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
package com.microsoft.semantickernel.samples.plugins.github;
3+
4+
import com.fasterxml.jackson.annotation.JsonCreator;
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import com.fasterxml.jackson.core.JsonProcessingException;
7+
import com.fasterxml.jackson.databind.DeserializationFeature;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
10+
public abstract class GitHubModel {
11+
public final static ObjectMapper objectMapper = new ObjectMapper()
12+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
13+
14+
@Override
15+
public String toString() {
16+
try {
17+
return objectMapper.writeValueAsString(this);
18+
} catch (JsonProcessingException e) {
19+
throw new RuntimeException(e);
20+
}
21+
}
22+
23+
public static class User extends GitHubModel {
24+
@JsonProperty("login")
25+
private String login;
26+
@JsonProperty("id")
27+
private long id;
28+
@JsonProperty("name")
29+
private String name;
30+
@JsonProperty("company")
31+
private String company;
32+
@JsonProperty("html_url")
33+
private String url;
34+
35+
@JsonCreator
36+
public User(@JsonProperty("login") String login,
37+
@JsonProperty("id") long id,
38+
@JsonProperty("name") String name,
39+
@JsonProperty("company") String company,
40+
@JsonProperty("html_url") String url) {
41+
this.login = login;
42+
this.id = id;
43+
this.name = name;
44+
this.company = company;
45+
this.url = url;
46+
}
47+
48+
public String getLogin() {
49+
return login;
50+
}
51+
52+
public long getId() {
53+
return id;
54+
}
55+
56+
public String getName() {
57+
return name;
58+
}
59+
60+
public String getCompany() {
61+
return company;
62+
}
63+
64+
public String getUrl() {
65+
return url;
66+
}
67+
}
68+
69+
public static class Repository extends GitHubModel {
70+
@JsonProperty("id")
71+
private long id;
72+
@JsonProperty("full_name")
73+
private String name;
74+
@JsonProperty("description")
75+
private String description;
76+
@JsonProperty("html_url")
77+
private String url;
78+
79+
@JsonCreator
80+
public Repository(@JsonProperty("id") long id,
81+
@JsonProperty("full_name") String name,
82+
@JsonProperty("description") String description,
83+
@JsonProperty("html_url") String url) {
84+
this.id = id;
85+
this.name = name;
86+
this.description = description;
87+
this.url = url;
88+
}
89+
90+
public long getId() {
91+
return id;
92+
}
93+
94+
public String getName() {
95+
return name;
96+
}
97+
98+
public String getDescription() {
99+
return description;
100+
}
101+
102+
public String getUrl() {
103+
return url;
104+
}
105+
106+
@Override
107+
public String toString() {
108+
try {
109+
return objectMapper.writeValueAsString(this);
110+
} catch (JsonProcessingException e) {
111+
throw new RuntimeException(e);
112+
}
113+
}
114+
}
115+
116+
public static class Issue extends GitHubModel {
117+
@JsonProperty("id")
118+
private long id;
119+
@JsonProperty("number")
120+
private long number;
121+
@JsonProperty("title")
122+
private String title;
123+
@JsonProperty("state")
124+
private String state;
125+
@JsonProperty("html_url")
126+
private String url;
127+
@JsonProperty("labels")
128+
private Label[] labels;
129+
@JsonProperty("created_at")
130+
private String createdAt;
131+
@JsonProperty("closed_at")
132+
private String closedAt;
133+
134+
@JsonCreator
135+
public Issue(@JsonProperty("id") long id,
136+
@JsonProperty("number") long number,
137+
@JsonProperty("title") String title,
138+
@JsonProperty("state") String state,
139+
@JsonProperty("html_url") String url,
140+
@JsonProperty("labels") Label[] labels,
141+
@JsonProperty("created_at") String createdAt,
142+
@JsonProperty("closed_at") String closedAt) {
143+
this.id = id;
144+
this.number = number;
145+
this.title = title;
146+
this.state = state;
147+
this.url = url;
148+
this.labels = labels;
149+
this.createdAt = createdAt;
150+
this.closedAt = closedAt;
151+
}
152+
153+
public long getId() {
154+
return id;
155+
}
156+
157+
public long getNumber() {
158+
return number;
159+
}
160+
161+
public String getTitle() {
162+
return title;
163+
}
164+
165+
public String getState() {
166+
return state;
167+
}
168+
169+
public String getUrl() {
170+
return url;
171+
}
172+
173+
public Label[] getLabels() {
174+
return labels;
175+
}
176+
177+
public String getCreatedAt() {
178+
return createdAt;
179+
}
180+
181+
public String getClosedAt() {
182+
return closedAt;
183+
}
184+
}
185+
186+
public static class IssueDetail extends Issue {
187+
@JsonProperty("body")
188+
private String body;
189+
190+
@JsonCreator
191+
public IssueDetail(@JsonProperty("id") long id,
192+
@JsonProperty("number") long number,
193+
@JsonProperty("title") String title,
194+
@JsonProperty("state") String state,
195+
@JsonProperty("html_url") String url,
196+
@JsonProperty("labels") Label[] labels,
197+
@JsonProperty("created_at") String createdAt,
198+
@JsonProperty("closed_at") String closedAt,
199+
@JsonProperty("body") String body) {
200+
super(id, number, title, state, url, labels, createdAt, closedAt);
201+
this.body = body;
202+
}
203+
204+
public String getBody() {
205+
return body;
206+
}
207+
}
208+
209+
public static class Label extends GitHubModel {
210+
@JsonProperty("id")
211+
private long id;
212+
@JsonProperty("name")
213+
private String name;
214+
@JsonProperty("description")
215+
private String description;
216+
217+
@JsonCreator
218+
public Label(@JsonProperty("id") long id,
219+
@JsonProperty("name") String name,
220+
@JsonProperty("description") String description) {
221+
this.id = id;
222+
this.name = name;
223+
this.description = description;
224+
}
225+
226+
public long getId() {
227+
return id;
228+
}
229+
230+
public String getName() {
231+
return name;
232+
}
233+
234+
public String getDescription() {
235+
return description;
236+
}
237+
}
238+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
package com.microsoft.semantickernel.samples.plugins.github;
3+
4+
import reactor.core.publisher.Mono;
5+
import reactor.netty.http.client.HttpClient;
6+
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
7+
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
8+
9+
import java.io.IOException;
10+
import java.util.List;
11+
12+
public class GitHubPlugin {
13+
public static final String baseUrl = "https://api.github.com";
14+
private final String token;
15+
16+
public GitHubPlugin(String token) {
17+
this.token = token;
18+
}
19+
20+
@DefineKernelFunction(name = "get_user_info", description = "Get user information from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$User")
21+
public Mono<GitHubModel.User> getUserProfileAsync() {
22+
HttpClient client = createClient();
23+
24+
return makeRequestAsync(client, "/user")
25+
.map(json -> {
26+
try {
27+
return GitHubModel.objectMapper.readValue(json, GitHubModel.User.class);
28+
} catch (IOException e) {
29+
throw new IllegalStateException("Failed to deserialize GitHubUser", e);
30+
}
31+
});
32+
}
33+
34+
@DefineKernelFunction(name = "get_repo_info", description = "Get repository information from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$Repository")
35+
public Mono<GitHubModel.Repository> getRepositoryAsync(
36+
@KernelFunctionParameter(name = "organization", description = "The name of the repository to retrieve information for") String organization,
37+
@KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve information for") String repoName) {
38+
HttpClient client = createClient();
39+
40+
return makeRequestAsync(client, String.format("/repos/%s/%s", organization, repoName))
41+
.map(json -> {
42+
try {
43+
return GitHubModel.objectMapper.readValue(json, GitHubModel.Repository.class);
44+
} catch (IOException e) {
45+
throw new IllegalStateException("Failed to deserialize GitHubRepository", e);
46+
}
47+
});
48+
}
49+
50+
@DefineKernelFunction(name = "get_issues", description = "Get issues from GitHub", returnType = "java.util.List")
51+
public Mono<List<GitHubModel.Issue>> getIssuesAsync(
52+
@KernelFunctionParameter(name = "organization", description = "The name of the organization to retrieve issues for") String organization,
53+
@KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve issues for") String repoName,
54+
@KernelFunctionParameter(name = "max_results", description = "The maximum number of issues to retrieve", required = false, defaultValue = "10", type = int.class) int maxResults,
55+
@KernelFunctionParameter(name = "state", description = "The state of the issues to retrieve", required = false, defaultValue = "open") String state,
56+
@KernelFunctionParameter(name = "assignee", description = "The assignee of the issues to retrieve", required = false) String assignee) {
57+
HttpClient client = createClient();
58+
59+
String query = String.format("/repos/%s/%s/issues", organization, repoName);
60+
query = buildQueryString(query, "state", state);
61+
query = buildQueryString(query, "assignee", assignee);
62+
query = buildQueryString(query, "per_page", String.valueOf(maxResults));
63+
64+
return makeRequestAsync(client, query)
65+
.flatMap(json -> {
66+
try {
67+
GitHubModel.Issue[] issues = GitHubModel.objectMapper.readValue(json,
68+
GitHubModel.Issue[].class);
69+
return Mono.just(List.of(issues));
70+
} catch (IOException e) {
71+
throw new IllegalStateException("Failed to deserialize GitHubIssues", e);
72+
}
73+
});
74+
}
75+
76+
@DefineKernelFunction(name = "get_issue_detail_info", description = "Get detail information of a single issue from GitHub", returnType = "com.microsoft.semantickernel.samples.plugins.github.GitHubModel$IssueDetail")
77+
public GitHubModel.IssueDetail getIssueDetailAsync(
78+
@KernelFunctionParameter(name = "organization", description = "The name of the repository to retrieve information for") String organization,
79+
@KernelFunctionParameter(name = "repo_name", description = "The name of the repository to retrieve information for") String repoName,
80+
@KernelFunctionParameter(name = "issue_number", description = "The issue number to retrieve information for", type = int.class) int issueNumber) {
81+
HttpClient client = createClient();
82+
83+
return makeRequestAsync(client,
84+
String.format("/repos/%s/%s/issues/%d", organization, repoName, issueNumber))
85+
.map(json -> {
86+
try {
87+
return GitHubModel.objectMapper.readValue(json, GitHubModel.IssueDetail.class);
88+
} catch (IOException e) {
89+
throw new IllegalStateException("Failed to deserialize GitHubIssue", e);
90+
}
91+
}).block();
92+
}
93+
94+
private HttpClient createClient() {
95+
return HttpClient.create()
96+
.baseUrl(baseUrl)
97+
.headers(headers -> {
98+
headers.add("User-Agent", "request");
99+
headers.add("Accept", "application/vnd.github+json");
100+
headers.add("Authorization", "Bearer " + token);
101+
headers.add("X-GitHub-Api-Version", "2022-11-28");
102+
});
103+
}
104+
105+
private static String buildQueryString(String path, String param, String value) {
106+
if (value == null || value.isEmpty()
107+
|| value.equals(KernelFunctionParameter.NO_DEFAULT_VALUE)) {
108+
return path;
109+
}
110+
111+
return path + (path.contains("?") ? "&" : "?") + param + "=" + value;
112+
}
113+
114+
private Mono<String> makeRequestAsync(HttpClient client, String path) {
115+
return client
116+
.get()
117+
.uri(path)
118+
.responseSingle((res, content) -> {
119+
if (res.status().code() != 200) {
120+
return Mono.error(new IllegalStateException("Request failed: " + res.status()));
121+
}
122+
return content.asString();
123+
});
124+
}
125+
}

0 commit comments

Comments
 (0)