Skip to content

Commit

Permalink
Merge pull request #105 from AssemblyAI/niels/user-agent
Browse files Browse the repository at this point in the history
Add AAI UserAgent
  • Loading branch information
Swimburger committed Jun 10, 2024
2 parents 47e4a41 + e3f65d6 commit 61073c9
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 7 deletions.
9 changes: 9 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ src/main/java/com/assemblyai/api/AssemblyAI.java
src/main/java/com/assemblyai/api/PollingTranscriptsClient.java
src/main/java/com/assemblyai/api/Transcriber.java
src/main/java/com/assemblyai/api/RealtimeTranscriber.java
src/main/java/com/assemblyai/api/core/Constants.java

# Ignore SpeechModel to manually mark conformer-2 as deprecated
src/main/java/com/assemblyai/api/resources/transcripts/types/SpeechModel.java
Expand All @@ -19,9 +20,17 @@ src/main/java/com/assemblyai/api/resources/realtime/types/SessionTerminated.java
src/main/java/com/assemblyai/api/AssemblyAIBuilder.java
src/main/java/com/assemblyai/api/core/ClientOptions.java

# Ignore UserAgent
src/main/java/com/assemblyai/api/core/UserAgent.java
src/main/java/com/assemblyai/api/core/UserAgentInterceptor.java
src/main/java/com/assemblyai/api/core/UserAgentItem.java

sample-app/src/main/java/sample/App.java
sample-app/src/main/resources/

# Ignore tests
src/test

LICENSE
README.md

Expand Down
28 changes: 25 additions & 3 deletions src/main/java/com/assemblyai/api/AssemblyAIBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@

import com.assemblyai.api.core.ClientOptions;
import com.assemblyai.api.core.Environment;
import com.assemblyai.api.core.UserAgent;

public final class AssemblyAIBuilder {
private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder();
private ClientOptions.Builder lemurClientOptionsBuilder = ClientOptions.builder();

private String apiKey = null;
private UserAgent userAgent = UserAgent.getDefault();

private Environment environment = Environment.DEFAULT;

/**
* Sets apiKey
* Sets API key
*/
public AssemblyAIBuilder apiKey(String apiKey) {
this.apiKey = apiKey;
Expand All @@ -27,6 +29,18 @@ public AssemblyAIBuilder environment(Environment environment) {
return this;
}

/**
* Merges AssemblyAI user agent with the default AssemblyAI user agent.
* If null, sets the AssemblyAI user agent to null.
*
* @param userAgent The AssemblyAI user agent
* @return AssemblyAIBuilder
*/
public AssemblyAIBuilder userAgent(UserAgent userAgent) {
this.userAgent = userAgent;
return this;
}

public AssemblyAIBuilder url(String url) {
this.environment = Environment.custom(url);
return this;
Expand All @@ -36,10 +50,18 @@ public AssemblyAI build() {
if (apiKey == null) {
throw new RuntimeException("Please provide apiKey");
}

this.clientOptionsBuilder.addHeader("Authorization", this.apiKey);
clientOptionsBuilder.environment(this.environment);
clientOptionsBuilder
.environment(this.environment)
.userAgent(userAgent);

this.lemurClientOptionsBuilder.addHeader("Authorization", this.apiKey);
lemurClientOptionsBuilder.environment(this.environment).disableTimeouts();
lemurClientOptionsBuilder
.environment(this.environment)
.userAgent(userAgent)
.disableTimeouts();

return new AssemblyAI(clientOptionsBuilder.build(), lemurClientOptionsBuilder.build());
}
}
40 changes: 36 additions & 4 deletions src/main/java/com/assemblyai/api/core/ClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import okhttp3.OkHttpClient;

import static com.assemblyai.api.core.Constants.SDK_VERSION;

public final class ClientOptions {
private final Environment environment;

Expand All @@ -30,7 +32,7 @@ private ClientOptions(
this.headers.putAll(new HashMap<String, String>() {
{
put("X-Fern-SDK-Name", "com.assemblyai.fern:api-sdk");
put("X-Fern-SDK-Version", "1.1.3");
put("X-Fern-SDK-Version", SDK_VERSION);
put("X-Fern-Language", "JAVA");
}
});
Expand Down Expand Up @@ -77,6 +79,7 @@ public static Builder builder() {

public static final class Builder {
private Environment environment;
private UserAgent userAgent = UserAgent.getDefault();

private final Map<String, String> headers = new HashMap<>();

Expand All @@ -100,7 +103,30 @@ public Builder addHeader(String key, Supplier<String> value) {
}

/**
* This is a temporary measure ot disable timeouts for LeMUR client.
* Merges AssemblyAI user agent with the default AssemblyAI user agent.
* If null, sets the AssemblyAI user agent to null.
*
* @param userAgent The AssemblyAI user agent
* @return ClientOptionsBuilder
*/
public Builder userAgent(UserAgent userAgent) {
if (userAgent == null) {
this.userAgent = null;
return this;
}

// if current and incoming user agent is default user agent, no-op
if(userAgent == UserAgent.getDefault() && this.userAgent == UserAgent.getDefault()) {
return this;
}

// create a new user agent that merges existing and incoming user agent
this.userAgent = new UserAgent(this.userAgent, userAgent);
return this;
}

/**
* This is a temporary measure to disable timeouts for LeMUR client.
* Don't use this method.
*
* @return ClientOptionsBuilder
Expand All @@ -113,15 +139,21 @@ public Builder disableTimeouts() {

public ClientOptions build() {
OkHttpClient.Builder okhttpClientBuilder = new OkHttpClient.Builder()
.addInterceptor(new RetryInterceptor(3));
.addInterceptor(new RetryInterceptor(3))
.addInterceptor(new UserAgentInterceptor(this.userAgent));
if (this.disableTimeouts) {
okhttpClientBuilder
.callTimeout(0, TimeUnit.SECONDS)
.connectTimeout(0, TimeUnit.SECONDS)
.writeTimeout(0, TimeUnit.SECONDS)
.readTimeout(0, TimeUnit.SECONDS);
}
return new ClientOptions(environment, headers, headerSuppliers, okhttpClientBuilder.build());
return new ClientOptions(
environment,
headers,
headerSuppliers,
okhttpClientBuilder.build()
);
}
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/assemblyai/api/core/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.assemblyai.api.core;

public class Constants {
public static final String SDK_VERSION = "1.1.3";
}
1 change: 1 addition & 0 deletions src/main/java/com/assemblyai/api/core/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public String getUrl() {
return this.url;
}


public static Environment custom(String url) {
return new Environment(url);
}
Expand Down
94 changes: 94 additions & 0 deletions src/main/java/com/assemblyai/api/core/UserAgent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.assemblyai.api.core;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static com.assemblyai.api.core.Constants.SDK_VERSION;

public class UserAgent {
private static final UserAgent defaultUserAgent;

static {
defaultUserAgent = createDefaultUserAgent();
}

private final Map<String, UserAgentItem> userAgent;

public UserAgent(Map<String, UserAgentItem> userAgent) {
this.userAgent = userAgent;
}

public UserAgent(UserAgent a, UserAgent b) {
this.userAgent = UserAgent.merge(a.userAgent, b.userAgent);
}

public String toAssemblyAIUserAgentString() {
StringBuilder sb = new StringBuilder();
if (this.userAgent == null) {
return sb.toString();
}

sb.append(" AssemblyAI/1.0 (");
sb.append(
this.userAgent
.entrySet()
.stream()
.map(entry -> String.format(
"%s=%s/%s",
entry.getKey(),
entry.getValue().getName(),
entry.getValue().getVersion()
))
.collect(Collectors.joining(" "))
);
sb.append(")");
return sb.toString();
}

public static UserAgent getDefault(){
return defaultUserAgent;
}

private static UserAgent createDefaultUserAgent() {
HashMap<String, UserAgentItem> defaultUserAgent = new HashMap<>();
defaultUserAgent.put(
"sdk",
new UserAgentItem(
"Java",
SDK_VERSION
)
);
defaultUserAgent.put(
"runtime_env",
new UserAgentItem(
System.getProperty("java.runtime.name"),
System.getProperty("java.runtime.version")
)
);

return new UserAgent(defaultUserAgent);
}

private UserAgent merge(UserAgent other) {
return new UserAgent(UserAgent.merge(this.userAgent, other.userAgent));
}

private static Map<String, UserAgentItem> merge(Map<String, UserAgentItem> a, Map<String, UserAgentItem> b) {
Map<String, UserAgentItem> newUserAgent = new HashMap<>();

// user this user agent
newUserAgent.putAll(a);
// override with incoming user agent
newUserAgent.putAll(b);

// remove all null values
for (Map.Entry<String, UserAgentItem> entry : b.entrySet()) {
if (entry.getValue() == null) {
newUserAgent.remove(entry.getKey());
}
}
return newUserAgent;
}
}

47 changes: 47 additions & 0 deletions src/main/java/com/assemblyai/api/core/UserAgentInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.assemblyai.api.core;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public class UserAgentInterceptor implements Interceptor {
private final UserAgent userAgent;

public UserAgentInterceptor(UserAgent userAgent) {
this.userAgent = userAgent;
}

@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
if (userAgent == null) {
return chain.proceed(chain.request());
}

Request originalRequest = chain.request();
String userAgentString = originalRequest.headers().get("User-Agent");
if (userAgentString != null) {
// if already contains AssemblyAI UA, skip
if (userAgentString.contains("AssemblyAI/")) {
return chain.proceed(chain.request());
}
} else {
userAgentString = "";
}

String assemblyAIUserAgentString = userAgent.toAssemblyAIUserAgentString();
// if AAI UA null or empty, skip
if (assemblyAIUserAgentString == null || assemblyAIUserAgentString.isEmpty()) {
return chain.proceed(chain.request());
}

userAgentString += " " + assemblyAIUserAgentString;
Request requestWithUserAgent = originalRequest.newBuilder()
.header("User-Agent", userAgentString)
.build();
return chain.proceed(requestWithUserAgent);
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/assemblyai/api/core/UserAgentItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.assemblyai.api.core;

public class UserAgentItem{
private final String name;
private final String version;

public UserAgentItem(String name, String version) {
this.name = name;
this.version = version;
}

public String getName() {
return name;
}

public String getVersion() {
return version;
}
}
20 changes: 20 additions & 0 deletions src/test/java/com/assemblyai/api/UserAgentTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.assemblyai.api;

import com.assemblyai.api.core.UserAgent;
import org.junit.jupiter.api.Test;

import static com.assemblyai.api.core.Constants.SDK_VERSION;

public final class UserAgentTest {
@Test
public void ShouldCreateDefaultUserAgent() {
UserAgent agent = UserAgent.getDefault();
assert agent != null;
String userAgentString = agent.toAssemblyAIUserAgentString();
assert userAgentString != null;
assert userAgentString.contains("AssemblyAI/1.0 (");
assert userAgentString.endsWith(")");
assert userAgentString.contains("sdk=Java/" + SDK_VERSION);
assert userAgentString.contains("runtime_env=OpenJDK Runtime Environment/");
}
}

0 comments on commit 61073c9

Please sign in to comment.