Skip to content

Instantly share code, notes, and snippets.

@kishida
Created February 25, 2023 10:34
Show Gist options
  • Save kishida/1f6a61679dc3c9b4ecf2514aef81c02c to your computer and use it in GitHub Desktop.
Save kishida/1f6a61679dc3c9b4ecf2514aef81c02c to your computer and use it in GitHub Desktop.
Clever chat bot than ChatGPT(overblown)
package naoki.openai;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Map;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
public class ArticleFinder {
private record Score(int vol, double score, Element elm){
double rate() {
if (vol == 0) return 0;
return score * score / vol;
}
}
private static final double RATE = 0.7;
private static final Map<String, Double> customRate = Map.of("p", 1., "li", 0.3);
private Score longest;
private ArticleFinder() {
}
/**
* @see https://chiral.hatenablog.com/entry/20111114/1321293238
*/
private Element findLongest(Element elm) {
longest = null;
calc(elm);
return longest == null ? null : longest.elm();
}
private Score calc(Element elm) {
int textlen = elm.ownText().length();
double score = textlen;
for (Element child : elm.children()) {
var chScore = calc(child);
textlen += chScore.vol();
score += chScore.score() * customRate.getOrDefault(child.tagName().toLowerCase(), RATE);
}
var result = new Score(textlen, score, elm);
if (longest == null || longest.rate() < result.rate()) {
longest = result;
}
return result;
}
public static String findArticle(String url) {
try {
var doc = Jsoup.connect(url).get();
var body = doc.body();
var elm = findArticleElement(body);
return elm == null ? "" : elm.text();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
public static Element findArticleElement(Element elm) {
var fa = new ArticleFinder();
return fa.findLongest(elm);
}
}
package naoki.openai;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
public class GoogleSearch {
static String getApiKey() {
String key = System.getenv("GOOGLE_API_KEY");
if (key == null) {
throw new IllegalArgumentException("GOOGLE_API_KEY not found");
}
return key.trim();
}
static String getCx() {
String cx = System.getenv("GOOGLE_SEARCH_CX");
if (cx == null) {
throw new IllegalArgumentException("GOOGLE_SEARCH_CX not found");
}
return cx.trim();
}
record SearchItem(String kind, String title, String htmlTitle, String link) {}
record SearchUrl(String type, String template){}
record SearchResult(String kind, SearchUrl url, List<SearchItem> items){}
static SearchItem search(String keyword) {
try {
var om = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
var url = "https://www.googleapis.com/customsearch/v1?key=%s&cx=%s&q=%s".formatted(
getApiKey(), getCx(), URLEncoder.encode(keyword, "utf-8"));
SearchResult result = om.readValue(new URL(url), SearchResult.class);
return result.items().get(0);
} catch(IOException ex) {
throw new UncheckedIOException(ex);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>naoki</groupId>
<artifactId>aisearch</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>service</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<exec.mainClass>naoki.mavenproject1openai.Mavenproject1openai</exec.mainClass>
</properties>
</project>
package naoki.openai;
import com.theokanning.openai.service.OpenAiService;
import com.theokanning.openai.completion.CompletionRequest;
import com.theokanning.openai.completion.CompletionResult;
import com.theokanning.openai.edit.EditRequest;
import com.theokanning.openai.edit.EditResult;
import java.awt.BorderLayout;
import java.time.Duration;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import static naoki.openai.Mavenproject1openai.getToken;
public class SearchAI {
static String getToken() {
var token = System.getenv("OPENAI_TOKEN");
if (token == null) {
throw new IllegalArgumentException("no token env for OPENAI_TOKEN");
}
return token;
}
static void out(JTextArea ta, String format, Object... params) {
var t = format.formatted(params);
System.out.print(t);
ta.append(t);
}
static void search(OpenAiService service, String text, JTextArea ta) {
// 検索キーワードを得る
var editReq = EditRequest.builder().input(text)
.instruction("質問に答えるためのWeb検索キーワードに変換")
.temperature(0.4)
.model("text-davinci-edit-001").build();
EditResult keyResult = service.createEdit(editReq);
var keyword = keyResult.getChoices().get(0).getText().trim();
out(ta, "[%s]%n", keyword);
// 検索を行う
var item = GoogleSearch.search(keyword);
out(ta, "%s%n%s%n", item.title(), item.link());
// 検索トップのサイトのテキストを得る
var article = ArticleFinder.findArticle(item.link());
out(ta, "%d characters in the article%n", article.length());
// 要約する
var cArticle = article.substring(0, Math.min(article.length(), 1800));
CompletionRequest completionRequest = CompletionRequest.builder()
.model("text-davinci-003") // davinci-003, curry, babbage, ada
.prompt("「%s」という質問に答えるよう要約してください\n\n%s\n".formatted(text, cArticle))
.echo(false)
.temperature(0.5)
.user("testing")
.maxTokens(500)
.build();
CompletionResult result = service.createCompletion(completionRequest);
out(ta, "%s%n", result.getChoices().get(0).getText());
}
public static void main(String[] args) {
var f = new JFrame("AI検索");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
var p = new JPanel(new BorderLayout());
f.add(p, BorderLayout.NORTH);
var t = new JTextField(30);
p.add(t);
var b = new JButton("検索");
p.add(b, BorderLayout.EAST);
var out = new JTextArea();
out.setLineWrap(true);
f.add(new JScrollPane(out));
f.setVisible(true);
OpenAiService service = new OpenAiService(getToken(), Duration.ZERO);
b.addActionListener(al -> {
b.setEnabled(false);
new Thread(() -> {try {
search(service, t.getText(), out);
} finally {
b.setEnabled(true);
}}).start();
});
}
}
@kishida
Copy link
Author

kishida commented Feb 25, 2023

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment