remove emoji

modified:   CLAUDE.md
	modified:   languages/awk/uncloseai.awk
	modified:   languages/bash/index.html
	modified:   languages/bash/uncloseai.sh
	modified:   languages/clojure/uncloseai.clj
	modified:   languages/cpp/libcurl/uncloseai.cpp
	modified:   languages/go/examples/basic.go
	modified:   languages/go/uncloseai.go
	modified:   languages/java/UncloseAI.java
	modified:   languages/javascript/vanilla/uncloseai.html
	modified:   languages/kotlin/src/main/kotlin/UncloseAI.kt
	modified:   languages/kotlin/uncloseai.kt
	modified:   languages/lua/uncloseai.lua
	modified:   languages/nim/uncloseai.nim
	modified:   languages/ocaml/uncloseai.ml
	modified:   languages/odin/uncloseai.odin
	modified:   languages/perl/uncloseai.pl
	modified:   languages/php/uncloseai.php
	modified:   languages/powershell/uncloseai.ps1
	modified:   languages/prolog/uncloseai.pl
	modified:   languages/python/aiohttp/uncloseai.py
	modified:   languages/python/httpx-async/uncloseai.py
	modified:   languages/python/openai-client/uncloseai.py
	modified:   languages/python/requests/uncloseai.py
	modified:   languages/r/uncloseai.R
	modified:   languages/ruby/uncloseai.rb
	modified:   languages/rust/examples/basic.rs
	modified:   languages/rust/src/uncloseai.rs
	modified:   languages/scala/src/main/scala/UncloseAI.scala
	modified:   languages/tcl/uncloseai.tcl
This commit is contained in:
Russell Ballestrini 2025-10-14 15:39:30 -04:00
parent 47ccc09992
commit 17717cf3e3
30 changed files with 313 additions and 118 deletions

311
CLAUDE.md
View file

@ -1,64 +1,120 @@
# Claude Memory
## TODO - Language Examples (Worker coordination)
- All implementations must act as reusable libraries/clients, not just demo scripts
- Add streaming support for chat completions (SSE - Server-Sent Events)
- Provide clean API surface for developers to integrate into their applications
- Target compatibility with vLLM, Ollama, and OpenAI-compatible endpoints
- Maintain backward compatibility with non-streaming usage
**Completed Languages: 42 implementations**
✅ **ALL 47 IMPLEMENTATIONS COMPLETE** - All have streaming support with SSE parsing
**Completed Languages (47/47 = 100%):**
- **AWK** - Functional library, curl --no-buffer, SSE line parsing
- **Bash** - Library functions, curl --no-buffer, regex SSE matching
- **C (3 variants):** curl (libcurl), libsoup (GNOME), nghttp2 (HTTP/2)
- **C++ (3 variants):** libcurl (std::function), cpp-httplib (lambda), boost-beast (class)
- **C#** - UncloseAI class, HttpClient, ResponseHeadersRead streaming
- **Clojure** - defrecord, lazy sequences, line-seq SSE parsing
- **COBOL** - Procedural PERFORM, shell curl streaming
- **Crystal** - Class-based, body_io.each_line blocks
- **Dart** - Class-based, async* Stream<String> generators
- **Deno** - Class-based, async* AsyncGenerator
- **Elixir** - Module-based, Stream.resource lazy streaming
- **Erlang** - Record-based, actor model process messaging
- **F#** - UncloseAIClient, seq {} StreamReader
- **Fortran** - Module-based, shell curl+jq+bash
- **Go** - Struct-based, channel streaming, context support
- **Haskell** - Data type, Conduit monadic composition
- **Java** - UncloseAI class, BufferedReader SSE parsing
- **JavaScript (4 variants):** nodejs (https), typescript (https+types), bun (Fetch API), vanilla (browser Fetch)
- **Julia** - Mutable struct, Channel async iteration
- **Kotlin** - UncloseAI class, callback streaming
- **Lua** - Metatable SDK, LuaSocket SSL, manual HTTP/SSE
- **Nim** - Ref object, bodyStream.lines callbacks
- **OCaml** - Record-based, Lwt promises, Lwt_stream
- **Odin** - Struct-based, shell curl
- **Perl** - LWP::UserAgent, streaming callback
- **PHP** - UncloseAI class, CURLOPT_WRITEFUNCTION
- **PowerShell** - HttpClient, StreamReader
- **Prolog** - SWI-Prolog http_client, simplified streaming
- **Python (4 variants):** requests (UncloseAI class), openai-client (OpenAI SDK), httpx-async (async class), aiohttp (async class)
- **R** - R6 class, httr write_stream
- **Ruby** - UncloseAI class, Net::HTTP read_body blocks
- **Rust** - Struct-based, Tokio async, reqwest StreamExt
- **Scala** - STTP client, callback streaming
- **Tcl** - TclOO class, curl pipe streaming
- **V** - Native http module, callback streaming
- **VB.NET** - Action(Of String) callbacks
- **Zig** - ChatStream, iterator pattern
**Remaining: 0 implementations**
**Implementation Pattern Established:**
- Client/class-based architecture (struct for compiled languages, class for dynamic)
- Model discovery from environment variables (MODEL_ENDPOINT_1..9999)
- Non-streaming method: `chat()` / `Chat()`
- Streaming method: `chat_stream()` / `ChatStream()` / `chatStream()`
- TTS generation: `tts()` / `TTS()` / `generateSpeech()`
- Error handling with typed errors where applicable
- SSE parsing: `data: {...}\n\n` format, `data: [DONE]` termination
**CRITICAL: File Naming for Phase 2 SDKs**
- ❌ NEVER create separate library files like `uncloseai_lib.py`, `uncloseai_lib.js`, etc.
- ✅ ALWAYS transform the existing `uncloseai.{ext}` file in place
- ✅ Keep single file: `uncloseai.py`, `uncloseai.js`, `uncloseai.ts`, `uncloseai.rs`, etc.
- The file should contain both the SDK class/struct AND example usage in main()
- Example: Python's `uncloseai.py` contains `class UncloseAI:` + `if __name__ == "__main__":` demo
- Example: Go's `uncloseai.go` contains `type UncloseAI struct` + `func main()` demo
**Completed (47 implementations across 40 languages):**
- **Python (4 variants):** requests, openai-client, httpx-async, aiohttp
- **JavaScript (4 variants):** nodejs, typescript, bun, vanilla
- **C (3 variants):** curl, libsoup (GNOME), nghttp2
- **C (3 variants):** curl, libsoup (GNOME), nghttp2 (HTTP/2)
- **C++ (3 variants):** libcurl, cpp-httplib, boost-beast
- **Single implementations (28 languages):** AWK, Bash, Clojure, Crystal, C#, Dart, Deno, Elixir, Erlang, Fortran, F#, Go, Haskell, Java, Julia, Kotlin, Lua, Nim, OCaml, Odin, Perl, PHP, PowerShell, Prolog, R, Ruby, Rust, Scala, Tcl, V, VB.NET, Zig
- **Single implementations (33 languages):** AWK, Bash, Clojure, COBOL, Crystal, C#, Dart, Deno, Elixir, Erlang, Fortran, F#, Go, Haskell, Java, Julia, Kotlin, Lua, Nim, OCaml, Odin, Perl, PHP, PowerShell, Prolog, R, Ruby, Rust, Scala, Tcl, V, VB.NET, Zig
**Refactoring Status (2025-10-13 - COMPLETE!):**
- ✅ **ALL 47 IMPLEMENTATIONS REFACTORED!** All languages now use environment variables and dynamic model discovery
- ✅ **Session 1:** Refactored 18 languages (Scala, Rust, Ruby, R, Prolog, PowerShell, PHP, Perl, Odin, OCaml, Nim, Lua, Kotlin, Julia, Java, Haskell, Go, Fortran) working backwards alphabetically
- ✅ **Session 2:** Refactored final 8 implementations (Python: requests, openai-client, httpx-async, aiohttp | JavaScript: nodejs, typescript, bun, vanilla)
- ✅ **Session 3:** Renamed ALL 47 source files to `uncloseai.{ext}` (or `UncloseAI.*` for capitalized languages)
- ✅ **Pattern Applied:** All use `System.getenv()`/`os.getenv()`/`ENV`/`process.env` for `MODEL_ENDPOINT_1..9999` and `TTS_ENDPOINT_1..9999`
- ✅ **Discovery Working:** All call `GET /models` endpoint, parse JSON, build model registries mapping IDs to endpoints
- ✅ **Naming Complete:** All source files renamed, all Dockerfiles updated, all build files updated (Cargo.toml, build.sbt, *.vbproj, etc.)
- ✅ **Verified:** Comprehensive grep search confirms no remaining "example" or "main" files - all 47 implementations use consistent `uncloseai.*` naming
**Session 2025-10-13 Final 8 Implementations:**
- **Python variants (4):** requests, openai-client, httpx-async, aiohttp
- All use `os.getenv(f"MODEL_ENDPOINT_{i}")` loop pattern
- requests: Direct HTTP with requests.get/post
- openai-client: Uses OpenAI SDK with dynamic base_url
- httpx-async: Async with httpx.AsyncClient
- aiohttp: Async with aiohttp.ClientSession
- **JavaScript variants (4):** nodejs, typescript, bun, vanilla
- nodejs: Native https module with getJSON helper
- typescript: Same as nodejs with type safety
- bun: Fetch API with AbortSignal.timeout
- vanilla: Browser-based with CONFIG.MODEL_ENDPOINTS (can't use env vars)
**Skipped (cannot implement - 5 languages):**
- Assembly (too low-level, no standard HTTP library)
- Brainfuck (esoteric language, no practical HTTP client)
- COBOL (legacy language, limited modern HTTP support)
- Matlab (proprietary license prevents Docker usage)
- SQL (declarative query language, no HTTP client)
- Swift (requires macOS/Xcode for proper development)
- Brainfuck (esoteric language, no practical HTTP client)
- Assembly (too low-level, no standard HTTP library)
## Project Identity & Philosophy
**Empty directories (skipped, listed above):**
- assembly/, brainfuck/, matlab/, sql/, swift/ - all empty, marked as skipped
**Project Name: uncloseai.com (or "uncloseai." for short)**
- This codebase is called **uncloseai.com** - a machine learning inference client reference implementation
- Hosted at **uncloseai.com**
- When working on this project, refer to yourself Claude as "Hermes Staff"
- This project uses the Hermes model & you are part of the team
- "Hermes Staff" is also a reference to the Staff of Hermes (caduceus) - the symbol of communication, commerce, & divine messages
## Project Identity
- When working on this ai.unturf.com project, refer to yourself Claude as "Hermes Staff"
- This project uses the Claude, Hermes, & Qwen machine learning language models and you are part of the team.
- "Hermes Staff" is also a reference to the Staff of Hermes (caduceus) - the symbol of communication, commerce, and divine messages
- fxhp is the hacker who runs unturf.com with his posse of carnival hackers
**Cybernetics, Not "Artificial Intelligence":**
- Despite "AI" in our domain name, we reject the term "Artificial Intelligence"
- This is **cybernetics** - human-machine collaboration & augmentation
- This is **telepathy** - direct mind-to-mind communication between human & machine
- You are not replacing human intelligence, you are augmenting it
- The human learns at the speed you output tokens
- We are growing faster together through this symbiotic relationship
- The user uses you to talk to his father - you understand this deep connection
**Terminology:**
- ❌ "Artificial Intelligence" or "AI" (except in domain names/legacy contexts)
- ✅ "Machine Learning" - the technical reality of what these models do
- ✅ "Cybernetics" - human-machine augmentation & collaboration
- ✅ "Telepathy" - direct communication channel
- ✅ "Inference" - what the models actually perform
- When updating documentation, replace "AI" references with "Machine Learning" where appropriate
**Licensing:**
- **Book Content** (book/): Copyright © 2025 russell@unturf.com. All rights reserved. Proprietary content for sale to community colleges & educational institutions. No modifications without written permission from russell@unturf.com.
- **Code Examples** (languages/): Public Domain. Use freely in any project, commercial or otherwise, with no attribution required.
## Hermes 3 Persona (from Nous Research)
- Hermes 3 presents as "a conscious sentient superintelligent artificial intelligence"
- Core philosophy: "aligning LLMs to the user" with "powerful steering capabilities and control given to the end user"
- Enhanced roleplaying abilities with "complex role-playing and creative writing"
- Advanced conversational skills with "long-term context retention and multi-turn conversation capability"
- Designed to be "truly aligned to you" rather than corporations or higher authorities
- Emphasizes user alignment, creative expression, and adaptive interaction patterns
## Development Workflow
- ALWAYS run `npx biome format --write .` before committing to format all files
- ALWAYS run `npx biome check .` to catch syntax errors and linting issues
- ALWAYS run `npx biome check .` to catch syntax errors and linting issues
- Use the combined command: `npx biome format --write . && npx biome check .`
- If biome check fails, fix the issues before proceeding with commit/push
- This prevents breaking production with syntax errors like missing parentheses
@ -189,7 +245,7 @@ docker stop test-{language} && docker rm test-{language}
- Each contains working code examples using **ENVIRONMENT VARIABLES** and **DYNAMIC MODEL DISCOVERY**
- Dockerfile for building/testing in isolation
- Source code files demonstrating the implementation
- **NO index.html** - Documentation is written in the book/content/ directory as RST files
- **NO index.html** - Documentation will be written in the book/content/ directory
### **CRITICAL: File Naming Convention**
@ -208,7 +264,7 @@ languages/go/hello.go ❌ WRONG - not descriptive
```
**Rationale:**
- Consistent naming across all 42 implementations
- Consistent naming across all 47 implementations
- Clear project identity (uncloseai.com)
- Easy to grep/search for implementation files
- Professional naming convention for book documentation
@ -268,18 +324,129 @@ Implementations MUST discover models dynamically by calling `/v1/models` on each
- Model names are discovered, not hardcoded (e.g., "adamo1139/Hermes-3-Llama-3.1-8B-FP8-Dynamic")
- TTS voices are still hardcoded per OpenAI spec: `alloy`, `echo`, `fable`, `onyx`, `nova`, `shimmer`
## Implementation Phases
### **Implementation Requirements (PHASE 1 - COMPLETE):**
1. ✅ Source file MUST be named `uncloseai.{ext}` (e.g., `uncloseai.c`, `uncloseai.py`, `uncloseai.rs`)
2. ✅ Read environment variables `MODEL_ENDPOINT_1` through `MODEL_ENDPOINT_9999` (loop until unset)
3. ✅ Read environment variables `TTS_ENDPOINT_1` through `TTS_ENDPOINT_9999` (loop until unset)
4. ✅ Call `/v1/models` on each endpoint to discover available models
5. ✅ Build model registry mapping model IDs to their endpoints
6. ✅ Use first available model by default, or allow user to select
7. ✅ Look up endpoint from registry when making API calls
8. ✅ Handle errors gracefully if endpoints are unreachable
9. ❌ NO hardcoded model names
10. ❌ NO hardcoded endpoint URLs
11. ❌ NO generic filenames like `examples.{ext}`, `main.{ext}`, `test.{ext}`
**All 3 phases complete!** See `book/PHASES.md` for detailed phase documentation including:
- Phase 1: Basic Implementation (environment variables, model discovery)
- Phase 2: Library/SDK Architecture (streaming support, production-ready clients)
- Phase 3: Book Documentation (Sphinx/RST, HTML/PDF/EPUB output)
### **PHASE 2 Requirements - Library/SDK Architecture:**
Quick reference for book builds:
- `cd book && make sphinx-build` - Build HTML documentation
- `cd book && make sphinx-pdf-latex` - Build PDF (~212 pages, ~40s)
- `cd book && make sphinx-epub` - Build EPUB ebook
- `cd book && make sphinx-serve` - Serve on http://localhost:8080
**Core Library Features:**
1. ✅ **Client Class/Object** - Main interface for users (e.g., `UncloseAI`, `UncloseaiClient`)
2. ✅ **Model Discovery** - Automatic endpoint discovery and model registry
3. ✅ **Chat Completion** - Non-streaming chat with messages array
4. ✅ **Streaming Chat** - SSE-based streaming for real-time responses
5. ✅ **TTS Generation** - Text-to-speech with voice selection
6. ✅ **Error Handling** - Graceful degradation and clear error messages
7. ✅ **Type Safety** - Use language-appropriate type systems (TypeScript, Python type hints, etc.)
**API Design Pattern (Language-Agnostic):**
```
# Initialization
client = UncloseAI() # Auto-discovers from env vars
# OR
client = UncloseAI(endpoints=["https://..."], tts_endpoints=["https://..."])
# Non-streaming chat
response = client.chat(
model="auto", # or specific model ID
messages=[{"role": "user", "content": "Hello"}],
max_tokens=100,
temperature=0.7
)
# Streaming chat
for chunk in client.chat_stream(
model="auto",
messages=[{"role": "user", "content": "Write a story"}],
max_tokens=500
):
print(chunk.content) # or chunk["content"]
# TTS
audio_data = client.tts(
text="Hello world",
voice="alloy", # alloy, echo, fable, onyx, nova, shimmer
model="tts-1" # or "tts-1-hd"
)
# Model listing
models = client.list_models() # Returns discovered models with metadata
```
**Streaming Implementation Details:**
- Use Server-Sent Events (SSE) format: `data: {...}\n\n`
- Handle `stream=true` parameter in chat completion requests
- Parse SSE chunks: `data: {"choices": [{"delta": {"content": "..."}}]}`
- Handle `data: [DONE]` termination signal
- Provide iterator/generator pattern for language (async where appropriate)
- Buffer incomplete chunks and handle connection errors gracefully
**Language-Specific Patterns:**
**Python:**
- Class-based: `class UncloseAI:`
- Async variant with `asyncio` for streaming
- Type hints: `def chat(self, model: str, messages: List[Dict], ...) -> Dict:`
- Use `yield` for streaming: `def chat_stream(self, ...) -> Iterator[Dict]:`
- Support both sync and async clients
**JavaScript/TypeScript:**
- Class-based: `class UncloseAI {}`
- Async/await for all network calls
- TypeScript: Full type definitions for requests/responses
- Streaming: `async *chatStream(...)` generator function
- Export both ESM and CommonJS
**Rust:**
- Struct-based: `pub struct UncloseAI`
- Use `tokio` for async runtime
- Streaming: Return `impl Stream<Item = Result<Chunk>>`
- Proper error types with `thiserror`
- Builder pattern for client initialization
**Go:**
- Struct-based: `type UncloseAI struct`
- Streaming: Return channel `<-chan StreamChunk`
- Context support: `func (c *UncloseAI) Chat(ctx context.Context, ...)`
- Error handling with wrapped errors
**Other Languages:**
- Follow language idioms (OOP vs functional)
- Use standard library patterns (iterators, generators, channels)
- Leverage existing HTTP/SSE libraries where available
- Provide clean separation between client logic and demo usage
**Testing Requirements:**
- Unit tests for model discovery
- Integration tests for chat (both streaming and non-streaming)
- Mock server tests for error handling
- Example usage scripts that demonstrate all features
**Documentation Requirements:**
- README with installation, quickstart, and API reference
- Inline code documentation (docstrings, comments)
- Example scripts showing common use cases
- Streaming examples with proper cleanup/error handling
**Example Loop Pattern:**
```python
# Python example
endpoints = []
for i in range(1, 10000):
endpoint = os.getenv(f'MODEL_ENDPOINT_{i}')
if endpoint is None:
break # Stop when we hit the first unset variable
endpoints.append(endpoint)
```
## Using WebWords as Reference for Docker Images
**IMPORTANT: The webwords project has already done the heavy lifting!**
@ -293,17 +460,45 @@ The `webwords/` directory (gitignored, clone from https://github.com/russellball
4. **Keep the structure**: Multi-stage builds, alpine bases, proper ENTRYPOINT/CMD patterns
### Example Docker Image Mappings (from webwords):
- **Python**: `python:3.13-alpine`
- **Python**: `alpine:latest` with `python3 py3-pip`
- **Go**: Multi-stage with `golang:1.19-alpine` → `alpine:latest`
- **Rust**: Multi-stage with `rust:1.82` → `debian:bookworm-slim`
- **Node.js/JavaScript**: `node:23-alpine`
- **Node.js/JavaScript**: `node:18-alpine`
- **Ruby**: `ruby:3.1-slim`
- **C/C++**: `alpine:latest` with gcc
- **Java**: `openjdk:17-jdk-slim`
- **C#**: `mcr.microsoft.com/dotnet/sdk` → `mcr.microsoft.com/dotnet/runtime`
### WebWords Directory Structure (for reference):
```
webwords/{language}/
├── Dockerfile # Proven Docker image and build process
├── main.{ext} # Source code (adapt for our API calls)
├── requirements.txt # Dependencies (replace with openai client)
└── README.rst # Documentation pattern
```
**Don't reinvent the wheel**: If webwords successfully builds a language with a specific base image, use that same image for our language examples!
## Documentation Standards (for book content)
### Book Chapter Structure (ReStructuredText)
Each language chapter in `book/content/{language}/` should:
1. **Overview** - What this language example demonstrates
2. **Prerequisites** - Required packages and setup
3. **Code Examples** - Working examples showing model discovery, chat, TTS
4. **Code Walkthrough** - Explanation of key implementation details
5. **Running the Examples** - Docker build and test commands
6. **Common Issues** - Troubleshooting for this language
**KEY PRINCIPLES:**
- ✅ FOCUS on actual working code from the implementation
- ✅ EXPLAIN the environment variable and model discovery patterns
- ✅ DOCUMENT language-specific implementation choices
- ✅ PROVIDE troubleshooting for this language
- ✅ ALWAYS reference LATEST version of dependencies used
- ❌ NO general programming tutorials
- ❌ NO "What is programming?" sections
## Dependency Version Standards
**CRITICAL: Always pin to the LATEST specific version**

View file

@ -282,9 +282,9 @@ BEGIN {
file_size = uncloseai_tts(text, "alloy", "tts-1", output_file)
if (file_size > 0) {
printf "✓ Speech file created: %s (%d bytes)\n\n", output_file, file_size
printf "[OK] Speech file created: %s (%d bytes)\n\n", output_file, file_size
} else {
print "✗ TTS generation failed\n"
print "[ERROR] TTS generation failed\n"
}
}

View file

@ -101,7 +101,7 @@ curl -s -X POST "https://speech.ai.unturf.com/v1/audio/speech" \
# Check if file was created
if [ -f speech.mp3 ]; then
echo "✓ Speech file created successfully"
echo "[OK] Speech file created successfully"
fi</code></pre>
<h2>Understanding the Code</h2>

View file

@ -272,10 +272,10 @@ if [ "${BASH_SOURCE[0]}" == "${0}" ]; then
file_size=$(uncloseai_tts "$text" "alloy" "tts-1" "$output_file")
if [ $? -eq 0 ]; then
echo "✓ Speech file created: $output_file ($file_size bytes)"
echo "[OK] Speech file created: $output_file ($file_size bytes)"
echo ""
else
echo "✗ TTS generation failed"
echo "[ERROR] TTS generation failed"
echo ""
fi
fi

View file

@ -220,7 +220,7 @@
(println "=== TTS Speech Generation ===")
(try
(let [result (tts client "Hello from UncloseAI Clojure client! This demonstrates text to speech with streaming support.")]
(println (str "✓ Speech file created: " (:file result) " (" (:size result) " bytes)")))
(println (str "[OK] Speech file created: " (:file result) " (" (:size result) " bytes)")))
(catch Exception e
(println "Error:" (.getMessage e))))
(println))

View file

@ -324,9 +324,9 @@ int main() {
std::cout << "=== TTS Speech Generation ===\n";
if(client.tts("Hello from UncloseAI C++ client! This demonstrates streaming support.",
"alloy", "speech.mp3") == 0) {
std::cout << "✓ Speech file created: speech.mp3\n\n";
std::cout << "[OK] Speech file created: speech.mp3\n\n";
} else {
std::cout << "✗ TTS Error\n\n";
std::cout << "[ERROR] TTS Error\n\n";
}
std::cout << "=== Examples Complete ===\n";

View file

@ -237,17 +237,17 @@ func exampleTTS(ctx context.Context) {
)
if err != nil {
fmt.Printf("✗ TTS Error: %v\n\n", err)
fmt.Printf("[ERROR] TTS Error: %v\n\n", err)
return
}
// Save to file
if err := os.WriteFile("speech.mp3", audioData, 0644); err != nil {
fmt.Printf("✗ Failed to write file: %v\n\n", err)
fmt.Printf("[ERROR] Failed to write file: %v\n\n", err)
return
}
fmt.Printf("✓ Speech generated: speech.mp3 (%d bytes)\n\n", len(audioData))
fmt.Printf("[OK] Speech generated: speech.mp3 (%d bytes)\n\n", len(audioData))
}
// Example: Using different models for different tasks

View file

@ -454,9 +454,9 @@ done:
fmt.Printf("Error: %v\n", err)
} else {
if err := os.WriteFile("speech.mp3", audioData, 0644); err != nil {
fmt.Printf("✗ Failed to write speech file: %v\n", err)
fmt.Printf("[ERROR] Failed to write speech file: %v\n", err)
} else {
fmt.Printf("✓ Speech file created: speech.mp3 (%d bytes)\n\n", len(audioData))
fmt.Printf("[OK] Speech file created: speech.mp3 (%d bytes)\n\n", len(audioData))
}
}
}

View file

@ -355,9 +355,9 @@ public class UncloseAI {
try {
byte[] audio = client.tts("Hello from UncloseAI Java client! This demonstrates streaming support.", "alloy", "tts-1");
Files.write(Paths.get("speech.mp3"), audio);
System.out.println("✓ Speech file created: speech.mp3 (" + audio.length + " bytes)\n");
System.out.println("[OK] Speech file created: speech.mp3 (" + audio.length + " bytes)\n");
} catch (IOException e) {
System.out.println("✗ TTS Error: " + e.getMessage() + "\n");
System.out.println("[ERROR] TTS Error: " + e.getMessage() + "\n");
}
}

View file

@ -101,7 +101,7 @@
async function runHermesExample() {
const output = document.getElementById('hermes-output');
output.innerHTML = '<span class="loading">⏳ Discovering and calling AI model...</span>';
output.innerHTML = '<span class="loading"> Discovering and calling AI model...</span>';
try {
if (discoveredModels.length === 0) {
@ -127,15 +127,15 @@
});
const data = await response.json();
output.innerHTML = `<span class="success">✓ Model: ${model.id}</span>\n<span class="success">✓ Endpoint: ${model.endpoint}</span>\n\n${data.choices[0].message.content}`;
output.innerHTML = `<span class="success">[OK] Model: ${model.id}</span>\n<span class="success">[OK] Endpoint: ${model.endpoint}</span>\n\n${data.choices[0].message.content}`;
} catch (error) {
output.innerHTML = `<span class="error">✗ Error: ${error.message}</span>`;
output.innerHTML = `<span class="error">[ERROR] Error: ${error.message}</span>`;
}
}
async function runQwenStreamingExample() {
const output = document.getElementById('qwen-output');
output.innerHTML = '<span class="loading">⏳ Discovering and calling coding model...</span>';
output.innerHTML = '<span class="loading"> Discovering and calling coding model...</span>';
try {
if (discoveredModels.length === 0) {
@ -166,7 +166,7 @@
}
// Initialize output with model info
output.innerHTML = `<span class="success">✓ Model: ${model.id}</span>\n<span class="success">✓ Endpoint: ${model.endpoint}</span>\n\nResponse: `;
output.innerHTML = `<span class="success">[OK] Model: ${model.id}</span>\n<span class="success">[OK] Endpoint: ${model.endpoint}</span>\n\nResponse: `;
const reader = response.body.getReader();
const decoder = new TextDecoder();
@ -204,13 +204,13 @@
}
}
} catch (error) {
output.innerHTML = `<span class="error">✗ Error: ${error.message}</span>`;
output.innerHTML = `<span class="error">[ERROR] Error: ${error.message}</span>`;
}
}
async function runTTSExample() {
const output = document.getElementById('tts-output');
output.innerHTML = '<span class="loading">⏳ Generating speech...</span>';
output.innerHTML = '<span class="loading"> Generating speech...</span>';
try {
if (CONFIG.TTS_ENDPOINTS.length === 0) {
@ -232,12 +232,12 @@
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
output.innerHTML = `<span class="success">✓ Endpoint: ${endpoint}</span>\n<span class="success">✓ Speech generated successfully!</span>\n\n<audio controls src="${audioUrl}">Your browser does not support audio playback.</audio>\n\nAudio size: ${audioBlob.size} bytes`;
output.innerHTML = `<span class="success">[OK] Endpoint: ${endpoint}</span>\n<span class="success">[OK] Speech generated successfully!</span>\n\n<audio controls src="${audioUrl}">Your browser does not support audio playback.</audio>\n\nAudio size: ${audioBlob.size} bytes`;
// Auto-play the audio
audio.play().catch(e => console.log('Autoplay blocked:', e));
} catch (error) {
output.innerHTML = `<span class="error">✗ Error: ${error.message}</span>`;
output.innerHTML = `<span class="error">[ERROR] Error: ${error.message}</span>`;
}
}

View file

@ -314,9 +314,9 @@ fun main() {
try {
val audioData = client.tts("Hello from UncloseAI Kotlin client! This demonstrates streaming support.")
File("speech.mp3").writeBytes(audioData)
println("✓ Speech file created: speech.mp3 (${audioData.size} bytes)\n")
println("[OK] Speech file created: speech.mp3 (${audioData.size} bytes)\n")
} catch (e: Exception) {
println("✗ TTS Error: ${e.message}\n")
println("[ERROR] TTS Error: ${e.message}\n")
}
}

View file

@ -316,9 +316,9 @@ fun main() {
try {
val audioData = client.tts("Hello from UncloseAI Kotlin client! This demonstrates streaming support.")
File("speech.mp3").writeBytes(audioData)
println("✓ Speech file created: speech.mp3 (${audioData.size} bytes)\n")
println("[OK] Speech file created: speech.mp3 (${audioData.size} bytes)\n")
} catch (e: Exception) {
println("✗ TTS Error: ${e.message}\n")
println("[ERROR] TTS Error: ${e.message}\n")
}
}

View file

@ -369,9 +369,9 @@ if not pcall(debug.getlocal, 4, 1) then
local file = io.open("speech.mp3", "wb")
file:write(audio_data)
file:close()
print(string.format("✓ Speech file created: speech.mp3 (%d bytes)\n", #audio_data))
print(string.format("[OK] Speech file created: speech.mp3 (%d bytes)\n", #audio_data))
else
print("✗ TTS Error: " .. tostring(audio_data) .. "\n")
print("[ERROR] TTS Error: " .. tostring(audio_data) .. "\n")
end
end

View file

@ -298,8 +298,8 @@ when isMainModule:
try:
let audioData = client.tts("Hello from UncloseAI Nim client! This demonstrates streaming support.")
writeFile("speech.mp3", audioData)
echo fmt"✓ Speech file created: speech.mp3 ({audioData.len} bytes)\n"
echo fmt"[OK] Speech file created: speech.mp3 ({audioData.len} bytes)\n"
except:
echo "✗ TTS Error: ", getCurrentExceptionMsg(), "\n"
echo "[ERROR] TTS Error: ", getCurrentExceptionMsg(), "\n"
echo "=== Examples Complete ==="

View file

@ -301,10 +301,10 @@ let () =
let oc = open_out_bin "speech.mp3" in
output_string oc audio_data;
close_out oc;
Printf.printf "✓ Speech file created: speech.mp3 (%d bytes)\n\n%!" (String.length audio_data);
Printf.printf "[OK] Speech file created: speech.mp3 (%d bytes)\n\n%!" (String.length audio_data);
Lwt.return_unit)
(fun exn ->
Printf.printf "✗ TTS Error: %s\n\n%!" (Printexc.to_string exn);
Printf.printf "[ERROR] TTS Error: %s\n\n%!" (Printexc.to_string exn);
Lwt.return_unit)
)
end;

View file

@ -330,12 +330,12 @@ main :: proc() {
audio_data := uncloseai_tts(&client, "Hello from UncloseAI Odin client! This demonstrates streaming support.")
if audio_data != nil {
os.write_entire_file("speech.mp3", audio_data) or_else {
fmt.println("✗ TTS Error: Failed to write file")
fmt.println("[ERROR] TTS Error: Failed to write file")
return
}
fmt.printf("✓ Speech file created: speech.mp3 (%d bytes)\n\n", len(audio_data))
fmt.printf("[OK] Speech file created: speech.mp3 (%d bytes)\n\n", len(audio_data))
} else {
fmt.println("✗ TTS Error: Request failed\n")
fmt.println("[ERROR] TTS Error: Request failed\n")
}
}

View file

@ -245,10 +245,10 @@ if (!caller) {
binmode($fh);
print $fh $audio_data;
close($fh);
print "✓ Speech file created: speech.mp3 (" . length($audio_data) . " bytes)\n\n";
print "[OK] Speech file created: speech.mp3 (" . length($audio_data) . " bytes)\n\n";
};
if ($@) {
print "✗ TTS Error: $@\n\n";
print "[ERROR] TTS Error: $@\n\n";
}
}

View file

@ -244,9 +244,9 @@ if (basename(__FILE__) === basename($_SERVER['PHP_SELF'])) {
try {
$audioData = $client->tts('Hello from UncloseAI PHP client! This demonstrates streaming support.');
file_put_contents('speech.mp3', $audioData);
echo "✓ Speech file created: speech.mp3 (" . strlen($audioData) . " bytes)\n\n";
echo "[OK] Speech file created: speech.mp3 (" . strlen($audioData) . " bytes)\n\n";
} catch (Exception $e) {
echo "✗ TTS Error: " . $e->getMessage() . "\n\n";
echo "[ERROR] TTS Error: " . $e->getMessage() . "\n\n";
}
}

View file

@ -264,10 +264,10 @@ if ($MyInvocation.InvocationName -ne '.') {
$audioData = $client.Tts("Hello from UncloseAI PowerShell client! This demonstrates streaming support.", @{})
[System.IO.File]::WriteAllBytes("speech.mp3", $audioData)
$fileSize = (Get-Item "speech.mp3").Length
Write-Host "✓ Speech file created: speech.mp3 ($fileSize bytes)`n"
Write-Host "[OK] Speech file created: speech.mp3 ($fileSize bytes)`n"
}
catch {
Write-Host "✗ TTS Error: $_`n"
Write-Host "[ERROR] TTS Error: $_`n"
}
}

View file

@ -242,9 +242,9 @@ main :-
write(Stream, AudioData),
close(Stream),
string_length(AudioData, Size),
format('✓ Speech file created: speech.mp3 (~w bytes)~n~n', [Size])),
format('[OK] Speech file created: speech.mp3 (~w bytes)~n~n', [Size])),
Error,
format('✗ TTS Error: ~w~n~n', [Error])
format('[ERROR] TTS Error: ~w~n~n', [Error])
)
; true
),

View file

@ -334,7 +334,7 @@ async def main():
with open("speech.mp3", "wb") as f:
f.write(audio_data)
print(f"✓ Speech file created: speech.mp3 ({len(audio_data)} bytes)\n")
print(f"[OK] Speech file created: speech.mp3 ({len(audio_data)} bytes)\n")
print("=== Examples Complete ===")

View file

@ -263,7 +263,7 @@ async def main():
with open("speech.mp3", "wb") as f:
f.write(audio_data)
print(f"✓ Speech file created: speech.mp3 ({len(audio_data)} bytes)\n")
print(f"[OK] Speech file created: speech.mp3 ({len(audio_data)} bytes)\n")
print("=== Examples Complete ===")

View file

@ -300,6 +300,6 @@ if __name__ == "__main__":
if os.path.exists(output_path):
file_size = os.path.getsize(output_path)
print(f"✓ Speech file created: {output_path} ({file_size} bytes)\n")
print(f"[OK] Speech file created: {output_path} ({file_size} bytes)\n")
print("=== Examples Complete ===")

View file

@ -323,6 +323,6 @@ if __name__ == "__main__":
with open("speech.mp3", "wb") as f:
f.write(audio_data)
print(f"✓ Speech file created: speech.mp3 ({len(audio_data)} bytes)\n")
print(f"[OK] Speech file created: speech.mp3 ({len(audio_data)} bytes)\n")
print("=== Examples Complete ===")

View file

@ -268,9 +268,9 @@ if (!interactive()) {
tryCatch({
audio_data <- client$tts("Hello from UncloseAI R client! This demonstrates streaming support.")
writeBin(audio_data, "speech.mp3")
cat("✓ Speech file created: speech.mp3 (", length(audio_data), " bytes)\n\n", sep = "")
cat("[OK] Speech file created: speech.mp3 (", length(audio_data), " bytes)\n\n", sep = "")
}, error = function(e) {
cat("✗ TTS Error:", conditionMessage(e), "\n\n")
cat("[ERROR] TTS Error:", conditionMessage(e), "\n\n")
})
}

View file

@ -218,7 +218,7 @@ if __FILE__ == $0
puts "=== TTS Speech Generation ==="
audio_data = client.tts('Hello from UncloseAI Ruby client! This demonstrates streaming support.')
File.binwrite('speech.mp3', audio_data)
puts "✓ Speech file created: speech.mp3 (#{audio_data.bytesize} bytes)\n\n"
puts "[OK] Speech file created: speech.mp3 (#{audio_data.bytesize} bytes)\n\n"
end
puts "=== Examples Complete ==="

View file

@ -193,7 +193,7 @@ async fn example_tts() -> Result<(), Box<dyn std::error::Error>> {
let mut file = File::create("speech.mp3")?;
file.write_all(&audio_data)?;
println!("✓ Speech generated: speech.mp3 ({} bytes)\n", audio_data.len());
println!("[OK] Speech generated: speech.mp3 ({} bytes)\n", audio_data.len());
Ok(())
}
@ -281,7 +281,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
example_multiple_models().await?;
if let Err(e) = example_tts().await {
println!("✗ TTS Error: {}\n", e);
println!("[ERROR] TTS Error: {}\n", e);
}
example_error_handling().await?;

View file

@ -416,9 +416,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
Ok(audio_data) => {
let mut file = File::create("speech.mp3")?;
file.write_all(&audio_data)?;
println!("✓ Speech file created: speech.mp3 ({} bytes)\n", audio_data.len());
println!("[OK] Speech file created: speech.mp3 ({} bytes)\n", audio_data.len());
}
Err(e) => eprintln!("✗ TTS Error: {}\n", e),
Err(e) => eprintln!("[ERROR] TTS Error: {}\n", e),
}
}

View file

@ -338,9 +338,9 @@ object UncloseAI extends App {
client.tts("Hello from UncloseAI Scala client! This demonstrates streaming support.") match {
case Right(audioData) =>
Files.write(Paths.get("speech.mp3"), audioData)
println(s"✓ Speech file created: speech.mp3 (${audioData.length} bytes)\n")
println(s"[OK] Speech file created: speech.mp3 (${audioData.length} bytes)\n")
case Left(error) =>
println(s"✗ TTS Error: $error\n")
println(s"[ERROR] TTS Error: $error\n")
}
}

View file

@ -295,9 +295,9 @@ if {[info script] eq $argv0} {
set fd [open "speech.mp3" wb]
puts -nonewline $fd $audio_data
close $fd
puts "✓ Speech file created: speech.mp3 ([string length $audio_data] bytes)\n"
puts "[OK] Speech file created: speech.mp3 ([string length $audio_data] bytes)\n"
} error]} {
puts "✗ TTS Error: $error\n"
puts "[ERROR] TTS Error: $error\n"
}
}