fix build failures: haskell streaming with withResponse, java-openai 4.3.0 with proper API, go-openai fixes, mojo real container
This commit is contained in:
parent
d5c443fbdb
commit
60b61b5a7e
11 changed files with 91 additions and 159 deletions
|
|
@ -4,8 +4,8 @@ FROM golang:1.22-alpine AS builder
|
|||
WORKDIR /app
|
||||
|
||||
# Copy go mod files
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY go.mod ./
|
||||
RUN go get github.com/openai/openai-go/v3@v3.3.0
|
||||
|
||||
# Copy source code
|
||||
COPY main.go ./
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ module uncloseai-go-openai
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/openai/openai-go v0.1.0-alpha.39
|
||||
require github.com/openai/openai-go/v3 v3.3.0
|
||||
|
||||
require (
|
||||
github.com/tidwall/gjson v1.14.4 // indirect
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
github.com/openai/openai-go v0.1.0-alpha.39 h1:FvoNWy7BPhA0TjGOK5huRGU5sAUEx2jeubLXz34K9LE=
|
||||
github.com/openai/openai-go v0.1.0-alpha.39/go.mod h1:3SdE6BffOX9HPEQv8IL/fi3LYZ5TUpRYaqGQZbyk11A=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/option"
|
||||
"github.com/openai/openai-go/v3"
|
||||
"github.com/openai/openai-go/v3/option"
|
||||
)
|
||||
|
||||
type ModelsResponse struct {
|
||||
|
|
@ -68,16 +68,17 @@ func main() {
|
|||
|
||||
// Non-streaming chat with Model 1
|
||||
fmt.Println("=== Non-Streaming Chat (Model 1) ===")
|
||||
// Use full endpoint including /v1 - v3 SDK doesn't add it
|
||||
client1 := openai.NewClient(
|
||||
option.WithBaseURL(modelEndpoint1),
|
||||
option.WithAPIKey("dummy-key"),
|
||||
)
|
||||
|
||||
chatResponse1, err := client1.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
|
||||
Model: openai.F(model1ID),
|
||||
Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
|
||||
Model: openai.ChatModel(model1ID),
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.UserMessage("Give a Python Fizzbuzz solution in one line of code?"),
|
||||
}),
|
||||
},
|
||||
Temperature: openai.Float(0.5),
|
||||
MaxTokens: openai.Int(150),
|
||||
})
|
||||
|
|
@ -91,10 +92,10 @@ func main() {
|
|||
// Streaming chat with Model 1
|
||||
fmt.Println("=== Streaming Chat (Model 1) ===")
|
||||
stream1 := client1.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
|
||||
Model: openai.F(model1ID),
|
||||
Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
|
||||
Model: openai.ChatModel(model1ID),
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.UserMessage("Explain quantum entanglement in one sentence."),
|
||||
}),
|
||||
},
|
||||
Temperature: openai.Float(0.5),
|
||||
MaxTokens: openai.Int(150),
|
||||
})
|
||||
|
|
@ -114,16 +115,17 @@ func main() {
|
|||
|
||||
// Non-streaming chat with Model 2
|
||||
fmt.Println("=== Non-Streaming Chat (Model 2) ===")
|
||||
// Use full endpoint including /v1 - v3 SDK doesn't add it
|
||||
client2 := openai.NewClient(
|
||||
option.WithBaseURL(modelEndpoint2),
|
||||
option.WithAPIKey("dummy-key"),
|
||||
)
|
||||
|
||||
chatResponse2, err := client2.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
|
||||
Model: openai.F(model2ID),
|
||||
Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
|
||||
Model: openai.ChatModel(model2ID),
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.UserMessage("Write a JavaScript function to check if a number is prime"),
|
||||
}),
|
||||
},
|
||||
Temperature: openai.Float(0.5),
|
||||
MaxTokens: openai.Int(150),
|
||||
})
|
||||
|
|
@ -137,10 +139,10 @@ func main() {
|
|||
// Streaming chat with Model 2
|
||||
fmt.Println("=== Streaming Chat (Model 2) ===")
|
||||
stream2 := client2.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
|
||||
Model: openai.F(model2ID),
|
||||
Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
|
||||
Model: openai.ChatModel(model2ID),
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.UserMessage("Give a Python Fizzbuzz solution in one line of code?"),
|
||||
}),
|
||||
},
|
||||
Temperature: openai.Float(0.5),
|
||||
MaxTokens: openai.Int(150),
|
||||
})
|
||||
|
|
@ -160,15 +162,16 @@ func main() {
|
|||
|
||||
// TTS example
|
||||
fmt.Println("=== TTS Speech Generation ===")
|
||||
// Use full endpoint including /v1 - v3 SDK doesn't add it
|
||||
ttsClient := openai.NewClient(
|
||||
option.WithBaseURL(ttsEndpoint1),
|
||||
option.WithAPIKey("dummy-key"),
|
||||
)
|
||||
|
||||
response, err := ttsClient.Audio.Speech.New(context.Background(), openai.AudioSpeechNewParams{
|
||||
Model: openai.F(openai.SpeechModelTTS1),
|
||||
Voice: openai.F(openai.AudioSpeechNewParamsVoiceAlloy),
|
||||
Input: openai.F("I think so therefore, Today is a wonderful day to grow something people love!"),
|
||||
Model: openai.SpeechModelTTS1,
|
||||
Voice: openai.AudioSpeechNewParamsVoiceAlloy,
|
||||
Input: "I think so therefore, Today is a wonderful day to grow something people love!",
|
||||
Speed: openai.Float(0.9),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -259,8 +259,8 @@ chatStream client msgs maybeModelIdx maybeMaxToks maybeTemp = do
|
|||
result <- try $ do
|
||||
request <- parseRequest $ "POST " ++ modelEndpoint modelInfo ++ "/chat/completions"
|
||||
let request' = setRequestBodyJSON req request
|
||||
httpSink request' $ \response -> do
|
||||
responseBody response
|
||||
withResponse request' $ \response ->
|
||||
runConduit $ getResponseBody response
|
||||
.| CC.linesUnboundedAscii
|
||||
.| CL.mapM_ processSSELine
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,13 @@ FROM eclipse-temurin:17-jre-alpine
|
|||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy jar with dependencies from builder
|
||||
# Copy jar and dependencies from builder
|
||||
COPY --from=builder /app/target/*.jar ./uncloseai.jar
|
||||
COPY --from=builder /app/target/lib ./lib
|
||||
|
||||
CMD ["java", "-jar", "uncloseai.jar"]
|
||||
# Set environment variables for testing
|
||||
ENV MODEL_ENDPOINT_1=https://hermes.ai.unturf.com/v1
|
||||
ENV MODEL_ENDPOINT_2=https://qwen.ai.unturf.com/v1
|
||||
ENV TTS_ENDPOINT_1=https://speech.ai.unturf.com/v1
|
||||
|
||||
CMD ["java", "-cp", "uncloseai.jar:lib/*", "uncloseai"]
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<dependency>
|
||||
<groupId>com.openai</groupId>
|
||||
<artifactId>openai-java</artifactId>
|
||||
<version>0.8.1</version>
|
||||
<version>4.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
|
|
@ -59,6 +59,18 @@
|
|||
<mainClass>uncloseai</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>uncloseai</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import com.openai.client.OpenAIClient;
|
||||
import com.openai.client.okhttp.OpenAIOkHttpClient;
|
||||
import com.openai.models.*;
|
||||
import com.openai.models.chat.completions.ChatCompletion;
|
||||
import com.openai.models.chat.completions.ChatCompletionCreateParams;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
|
@ -8,8 +9,6 @@ import java.net.URI;
|
|||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
|
@ -65,14 +64,7 @@ public class uncloseai {
|
|||
|
||||
ChatCompletionCreateParams params1 = ChatCompletionCreateParams.builder()
|
||||
.model(model1Id)
|
||||
.addMessage(ChatCompletionMessageParam.ofChatCompletionUserMessageParam(
|
||||
ChatCompletionUserMessageParam.builder()
|
||||
.role(ChatCompletionUserMessageParam.Role.USER)
|
||||
.content(ChatCompletionUserMessageParam.Content.ofTextContent(
|
||||
"Give a Python Fizzbuzz solution in one line of code?"
|
||||
))
|
||||
.build()
|
||||
))
|
||||
.addUserMessage("Give a Python Fizzbuzz solution in one line of code?")
|
||||
.temperature(0.5)
|
||||
.maxTokens(150L)
|
||||
.build();
|
||||
|
|
@ -84,14 +76,7 @@ public class uncloseai {
|
|||
System.out.println("=== Streaming Chat (Model 1) ===");
|
||||
ChatCompletionCreateParams streamParams1 = ChatCompletionCreateParams.builder()
|
||||
.model(model1Id)
|
||||
.addMessage(ChatCompletionMessageParam.ofChatCompletionUserMessageParam(
|
||||
ChatCompletionUserMessageParam.builder()
|
||||
.role(ChatCompletionUserMessageParam.Role.USER)
|
||||
.content(ChatCompletionUserMessageParam.Content.ofTextContent(
|
||||
"Explain quantum entanglement in one sentence."
|
||||
))
|
||||
.build()
|
||||
))
|
||||
.addUserMessage("Explain quantum entanglement in one sentence.")
|
||||
.temperature(0.5)
|
||||
.maxTokens(150L)
|
||||
.build();
|
||||
|
|
@ -113,14 +98,7 @@ public class uncloseai {
|
|||
|
||||
ChatCompletionCreateParams params2 = ChatCompletionCreateParams.builder()
|
||||
.model(model2Id)
|
||||
.addMessage(ChatCompletionMessageParam.ofChatCompletionUserMessageParam(
|
||||
ChatCompletionUserMessageParam.builder()
|
||||
.role(ChatCompletionUserMessageParam.Role.USER)
|
||||
.content(ChatCompletionUserMessageParam.Content.ofTextContent(
|
||||
"Write a JavaScript function to check if a number is prime"
|
||||
))
|
||||
.build()
|
||||
))
|
||||
.addUserMessage("Write a JavaScript function to check if a number is prime")
|
||||
.temperature(0.5)
|
||||
.maxTokens(150L)
|
||||
.build();
|
||||
|
|
@ -132,14 +110,7 @@ public class uncloseai {
|
|||
System.out.println("=== Streaming Chat (Model 2) ===");
|
||||
ChatCompletionCreateParams streamParams2 = ChatCompletionCreateParams.builder()
|
||||
.model(model2Id)
|
||||
.addMessage(ChatCompletionMessageParam.ofChatCompletionUserMessageParam(
|
||||
ChatCompletionUserMessageParam.builder()
|
||||
.role(ChatCompletionUserMessageParam.Role.USER)
|
||||
.content(ChatCompletionUserMessageParam.Content.ofTextContent(
|
||||
"Give a Python Fizzbuzz solution in one line of code?"
|
||||
))
|
||||
.build()
|
||||
))
|
||||
.addUserMessage("Give a Python Fizzbuzz solution in one line of code?")
|
||||
.temperature(0.5)
|
||||
.maxTokens(150L)
|
||||
.build();
|
||||
|
|
@ -152,9 +123,9 @@ public class uncloseai {
|
|||
});
|
||||
System.out.println("\n");
|
||||
|
||||
// TTS example - not supported in openai-java 0.8.1
|
||||
// TTS example
|
||||
System.out.println("=== TTS Speech Generation ===");
|
||||
System.out.println("[SKIPPED] TTS not available in openai-java SDK 0.8.1\n");
|
||||
System.out.println("[SKIPPED] TTS implementation needs audio API research\n");
|
||||
|
||||
System.out.println("=== Examples Complete ===");
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,6 @@
|
|||
"node": ">=18.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"openai": "^4.77.0"
|
||||
"openai": "6.3.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,44 @@
|
|||
# Mojo examples (source code reference)
|
||||
# Note: Mojo SDK requires Modular license which isn't freely available in Docker
|
||||
# We provide Python equivalents that demonstrate the same patterns
|
||||
FROM python:3.13-alpine
|
||||
# Mojo language container built from Ubuntu (Modular supports Ubuntu/Debian)
|
||||
FROM ubuntu:24.04
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install HTTP client
|
||||
RUN pip install --no-cache-dir httpx==0.28.1
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy source files
|
||||
# Create virtual environment for pip packages
|
||||
RUN python3 -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Install Modular CLI
|
||||
RUN curl -s https://get.modular.com | sh -
|
||||
|
||||
# Add modular to PATH
|
||||
ENV PATH="/root/.modular/bin:$PATH"
|
||||
|
||||
# Copy Mojo source files
|
||||
COPY hermes_nonstreaming.mojo .
|
||||
COPY qwen_nonstreaming.mojo .
|
||||
COPY uncloseai.py .
|
||||
COPY README.md .
|
||||
|
||||
# Default command shows README and runs Python equivalent
|
||||
CMD ["sh", "-c", "echo '=== Mojo Examples (Reference) ===\n' && cat README.md && echo '\n\n=== Running Python Equivalent ===\n' && python uncloseai.py"]
|
||||
# Create entrypoint script
|
||||
RUN echo '#!/bin/bash\n\
|
||||
if [ -z "$MODULAR_AUTH" ]; then\n\
|
||||
echo "ERROR: MODULAR_AUTH environment variable not set"\n\
|
||||
echo "Get your auth key from: https://developer.modular.com/"\n\
|
||||
echo "Then run: docker run -e MODULAR_AUTH=your-key ai-unturf-mojo"\n\
|
||||
exit 1\n\
|
||||
fi\n\
|
||||
modular auth $MODULAR_AUTH\n\
|
||||
modular install mojo\n\
|
||||
magic run mojo hermes_nonstreaming.mojo\n\
|
||||
' > /app/run.sh && chmod +x /app/run.sh
|
||||
|
||||
# Default: run Mojo example
|
||||
CMD ["/app/run.sh"]
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# uncloseai. - Python equivalent demonstrating patterns shown in Mojo examples
|
||||
# This runs in place of Mojo since Mojo SDK requires Modular license
|
||||
|
||||
import os
|
||||
import httpx
|
||||
import json
|
||||
|
||||
print("=== uncloseai. Mojo Examples (Python Equivalent) ===\n")
|
||||
|
||||
# Discover endpoints from environment variables
|
||||
model_endpoint_1 = os.getenv("MODEL_ENDPOINT_1")
|
||||
model_endpoint_2 = os.getenv("MODEL_ENDPOINT_2")
|
||||
tts_endpoint_1 = os.getenv("TTS_ENDPOINT_1")
|
||||
|
||||
if not model_endpoint_1 or not model_endpoint_2 or not tts_endpoint_1:
|
||||
print("ERROR: No models discovered. Set environment variables:")
|
||||
print(" MODEL_ENDPOINT_1, MODEL_ENDPOINT_2, TTS_ENDPOINT_1")
|
||||
exit(1)
|
||||
|
||||
# Discover models from endpoint 1
|
||||
print(f"Discovering models from {model_endpoint_1}...")
|
||||
response1 = httpx.get(f"{model_endpoint_1}/models")
|
||||
models1 = response1.json()["data"]
|
||||
model_1_id = models1[0]["id"]
|
||||
print(f"Model 1: {model_1_id}\n")
|
||||
|
||||
# Discover models from endpoint 2
|
||||
print(f"Discovering models from {model_endpoint_2}...")
|
||||
response2 = httpx.get(f"{model_endpoint_2}/models")
|
||||
models2 = response2.json()["data"]
|
||||
model_2_id = models2[0]["id"]
|
||||
print(f"Model 2: {model_2_id}\n")
|
||||
|
||||
# Non-streaming chat with Model 1
|
||||
print("=== Non-Streaming Chat (Model 1) ===")
|
||||
payload1 = {
|
||||
"model": model_1_id,
|
||||
"messages": [{"role": "user", "content": "Give a Python Fizzbuzz solution in one line of code?"}],
|
||||
"temperature": 0.5,
|
||||
"max_tokens": 150
|
||||
}
|
||||
chat_response1 = httpx.post(f"{model_endpoint_1}/chat/completions", json=payload1)
|
||||
content1 = chat_response1.json()["choices"][0]["message"]["content"]
|
||||
print(f"Response: {content1}\n")
|
||||
|
||||
# Non-streaming chat with Model 2
|
||||
print("=== Non-Streaming Chat (Model 2) ===")
|
||||
payload2 = {
|
||||
"model": model_2_id,
|
||||
"messages": [{"role": "user", "content": "Give a Python Fizzbuzz solution in one line of code?"}],
|
||||
"temperature": 0.5,
|
||||
"max_tokens": 150
|
||||
}
|
||||
chat_response2 = httpx.post(f"{model_endpoint_2}/chat/completions", json=payload2)
|
||||
content2 = chat_response2.json()["choices"][0]["message"]["content"]
|
||||
print(f"Response: {content2}\n")
|
||||
|
||||
# TTS example
|
||||
print("=== TTS Speech Generation ===")
|
||||
tts_payload = {
|
||||
"model": "tts-1",
|
||||
"voice": "alloy",
|
||||
"input": "I think so therefore, Today is a wonderful day to grow something people love!",
|
||||
"speed": 0.9
|
||||
}
|
||||
tts_response = httpx.post(f"{tts_endpoint_1}/audio/speech", json=tts_payload)
|
||||
with open("speech.mp3", "wb") as f:
|
||||
f.write(tts_response.content)
|
||||
print(f"[OK] Speech file created: speech.mp3 ({len(tts_response.content)} bytes)\n")
|
||||
|
||||
print("=== Examples Complete ===")
|
||||
print("\nNote: The .mojo files in this directory show what this would look like")
|
||||
print("in Mojo. We run Python equivalents since Mojo SDK requires Modular license.")
|
||||
Loading…
Add table
Add a link
Reference in a new issue