Skip to content

Commit d2304ea

Browse files
authored
Embedding Foundations & OpenAI Embeddings (#70)
1 parent 8241fc2 commit d2304ea

File tree

22 files changed

+3789
-8
lines changed

22 files changed

+3789
-8
lines changed

Diff for: docs/.vitepress/config.mts

+4
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ export default defineConfig({
102102
text: "Tool & Function Calling",
103103
link: "/core-concepts/tools-function-calling",
104104
},
105+
{
106+
text: "Embeddings",
107+
link: "/core-concepts/embeddings",
108+
},
105109
{
106110
text: "Prism Server",
107111
link: "/core-concepts/prism-server",

Diff for: docs/core-concepts/embeddings.md

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Embeddings
2+
3+
Transform your text into powerful vector representations! Embeddings let you add semantic search, recommendation systems, and other advanced natural language features to your applications.
4+
5+
## Quick Start
6+
7+
Here's how to generate embeddings with just a few lines of code:
8+
9+
```php
10+
use EchoLabs\Prism\Facades\Prism;
11+
use EchoLabs\Prism\Enums\Provider;
12+
13+
$response = Prism::embeddings()
14+
->using(Provider::OpenAI, 'text-embedding-3-large')
15+
->fromInput('Your text goes here')
16+
->generate();
17+
18+
// Get your embeddings vector
19+
$embeddings = $response->embeddings;
20+
21+
// Check token usage
22+
echo $response->usage->tokens;
23+
```
24+
25+
## Input Methods
26+
27+
You've got two convenient ways to feed text into the embeddings generator:
28+
29+
### Direct Text Input
30+
31+
```php
32+
$response = Prism::embeddings()
33+
->using(Provider::OpenAI, 'text-embedding-3-large')
34+
->fromInput('Analyze this text')
35+
->generate();
36+
```
37+
38+
### From File
39+
40+
Need to analyze a larger document? No problem:
41+
42+
```php
43+
$response = Prism::embeddings()
44+
->using(Provider::OpenAI, 'text-embedding-3-large')
45+
->fromFile('/path/to/your/document.txt')
46+
->generate();
47+
```
48+
49+
> [!NOTE]
50+
> Make sure your file exists and is readable. The generator will throw a helpful `PrismException` if there's any issue accessing the file.
51+
52+
## Common Settings
53+
54+
Just like with text generation, you can fine-tune your embeddings requests:
55+
56+
```php
57+
$response = Prism::embeddings()
58+
->using(Provider::OpenAI, 'text-embedding-3-large')
59+
->fromInput('Your text here')
60+
->withClientOptions(['timeout' => 30]) // Adjust request timeout
61+
->withClientRetry(3, 100) // Add automatic retries
62+
->generate();
63+
```
64+
65+
## Response Handling
66+
67+
The embeddings response gives you everything you need:
68+
69+
```php
70+
// Get the embeddings vector
71+
$vector = $response->embeddings;
72+
73+
// Check token usage
74+
$tokenCount = $response->usage->tokens;
75+
```
76+
77+
## Error Handling
78+
79+
Always handle potential errors gracefully:
80+
81+
```php
82+
use EchoLabs\Prism\Exceptions\PrismException;
83+
84+
try {
85+
$response = Prism::embeddings()
86+
->using(Provider::OpenAI, 'text-embedding-3-large')
87+
->fromInput('Your text here')
88+
->generate();
89+
} catch (PrismException $e) {
90+
Log::error('Embeddings generation failed:', [
91+
'error' => $e->getMessage()
92+
]);
93+
}
94+
```
95+
96+
## Pro Tips 🌟
97+
98+
**Vector Storage**: Consider using a vector database like Milvus, Qdrant, or pgvector to store and query your embeddings efficiently.
99+
100+
**Text Preprocessing**: For best results, clean and normalize your text before generating embeddings. This might include:
101+
- Removing unnecessary whitespace
102+
- Converting to lowercase
103+
- Removing special characters
104+
- Handling Unicode normalization
105+
106+
> [!IMPORTANT]
107+
> Different providers and models produce vectors of different dimensions. Always check your provider's documentation for specific details about the embedding model you're using.

Diff for: src/Contracts/Provider.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace EchoLabs\Prism\Contracts;
66

7+
use EchoLabs\Prism\Embeddings\Request as EmbeddingsRequest;
8+
use EchoLabs\Prism\Embeddings\Response as EmbeddingsResponse;
79
use EchoLabs\Prism\Providers\ProviderResponse;
810
use EchoLabs\Prism\Structured\Request as StructuredRequest;
911
use EchoLabs\Prism\Text\Request as TextRequest;
@@ -13,4 +15,6 @@ interface Provider
1315
public function text(TextRequest $request): ProviderResponse;
1416

1517
public function structured(StructuredRequest $request): ProviderResponse;
18+
19+
public function embeddings(EmbeddingsRequest $request): EmbeddingsResponse;
1620
}

Diff for: src/Embeddings/Generator.php

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EchoLabs\Prism\Embeddings;
6+
7+
use Closure;
8+
use EchoLabs\Prism\Contracts\Provider;
9+
use EchoLabs\Prism\Enums\Provider as ProviderEnum;
10+
use EchoLabs\Prism\Exceptions\PrismException;
11+
use EchoLabs\Prism\PrismManager;
12+
13+
class Generator
14+
{
15+
protected string $input = '';
16+
17+
/** @var array<string, mixed> */
18+
protected array $clientOptions = [];
19+
20+
/** @var array{0: array<int, int>|int, 1?: Closure|int, 2?: ?callable, 3?: bool} */
21+
protected array $clientRetry = [0];
22+
23+
protected Provider $provider;
24+
25+
protected string $model;
26+
27+
public function using(string|ProviderEnum $provider, string $model): self
28+
{
29+
$this->provider = resolve(PrismManager::class)
30+
->resolve($provider);
31+
32+
$this->model = $model;
33+
34+
return $this;
35+
}
36+
37+
public function fromInput(string $input): self
38+
{
39+
$this->input = $input;
40+
41+
return $this;
42+
}
43+
44+
public function fromFile(string $path): self
45+
{
46+
if (! is_file($path)) {
47+
throw new PrismException(sprintf('%s is not a valid file', $path));
48+
}
49+
50+
$contents = file_get_contents($path);
51+
52+
if ($contents === false) {
53+
throw new PrismException(sprintf('%s contents could not be read', $path));
54+
}
55+
56+
$this->input = $contents;
57+
58+
return $this;
59+
}
60+
61+
public function generate(): Response
62+
{
63+
if ($this->input === '' || $this->input === '0') {
64+
throw new PrismException('Embeddings input is required');
65+
}
66+
67+
return $this->provider->embeddings(new Request(
68+
model: $this->model,
69+
input: $this->input,
70+
clientOptions: $this->clientOptions,
71+
clientRetry: $this->clientRetry,
72+
));
73+
}
74+
}

Diff for: src/Embeddings/Request.php

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EchoLabs\Prism\Embeddings;
6+
7+
use Closure;
8+
9+
class Request
10+
{
11+
/**
12+
* @param array<string, mixed> $clientOptions
13+
* @param array{0: array<int, int>|int, 1?: Closure|int, 2?: ?callable, 3?: bool} $clientRetry
14+
*/
15+
public function __construct(
16+
public readonly string $model,
17+
public readonly string $input,
18+
public readonly array $clientOptions,
19+
public readonly array $clientRetry,
20+
) {}
21+
}

Diff for: src/Embeddings/Response.php

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EchoLabs\Prism\Embeddings;
6+
7+
use EchoLabs\Prism\ValueObjects\EmbeddingsUsage;
8+
9+
class Response
10+
{
11+
/**
12+
* @param array<int, int|string> $embeddings
13+
*/
14+
public function __construct(
15+
public readonly array $embeddings,
16+
public readonly EmbeddingsUsage $usage,
17+
) {}
18+
}

Diff for: src/Prism.php

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace EchoLabs\Prism;
66

77
use EchoLabs\Prism\Contracts\Provider;
8+
use EchoLabs\Prism\Embeddings\Generator as EmbeddingsGenerator;
89
use EchoLabs\Prism\Enums\Provider as ProviderEnum;
910
use EchoLabs\Prism\Providers\ProviderResponse;
1011
use EchoLabs\Prism\Structured\Generator as StructuredGenerator;
@@ -44,4 +45,9 @@ public static function structured(): StructuredGenerator
4445
{
4546
return new StructuredGenerator;
4647
}
48+
49+
public static function embeddings(): \EchoLabs\Prism\Embeddings\Generator
50+
{
51+
return new EmbeddingsGenerator;
52+
}
4753
}

Diff for: src/Providers/Anthropic/Anthropic.php

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace EchoLabs\Prism\Providers\Anthropic;
66

77
use EchoLabs\Prism\Contracts\Provider;
8+
use EchoLabs\Prism\Embeddings\Request as EmbeddingRequest;
9+
use EchoLabs\Prism\Embeddings\Response as EmbeddingResponse;
810
use EchoLabs\Prism\Providers\Anthropic\Handlers\Text;
911
use EchoLabs\Prism\Providers\ProviderResponse;
1012
use EchoLabs\Prism\Structured\Request as StructuredRequest;
@@ -33,6 +35,12 @@ public function structured(StructuredRequest $request): ProviderResponse
3335
throw new \Exception(sprintf('%s does not support structured mode', class_basename($this)));
3436
}
3537

38+
#[\Override]
39+
public function embeddings(EmbeddingRequest $request): EmbeddingResponse
40+
{
41+
throw new \Exception(sprintf('%s does not support embeddings', class_basename($this)));
42+
}
43+
3644
/**
3745
* @param array<string, mixed> $options
3846
* @param array<mixed> $retry

Diff for: src/Providers/Groq/Groq.php

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace EchoLabs\Prism\Providers\Groq;
66

77
use EchoLabs\Prism\Contracts\Provider;
8+
use EchoLabs\Prism\Embeddings\Request as EmbeddingRequest;
9+
use EchoLabs\Prism\Embeddings\Response as EmbeddingResponse;
810
use EchoLabs\Prism\Providers\Groq\Handlers\Text;
911
use EchoLabs\Prism\Providers\ProviderResponse;
1012
use EchoLabs\Prism\Structured\Request as StructuredRequest;
@@ -33,6 +35,12 @@ public function structured(StructuredRequest $request): ProviderResponse
3335
throw new \Exception(sprintf('%s does not support structured mode', class_basename($this)));
3436
}
3537

38+
#[\Override]
39+
public function embeddings(EmbeddingRequest $request): EmbeddingResponse
40+
{
41+
throw new \Exception(sprintf('%s does not support embeddings', class_basename($this)));
42+
}
43+
3644
/**
3745
* @param array<string, mixed> $options
3846
* @param array<mixed> $retry

Diff for: src/Providers/Mistral/Mistral.php

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace EchoLabs\Prism\Providers\Mistral;
66

77
use EchoLabs\Prism\Contracts\Provider;
8+
use EchoLabs\Prism\Embeddings\Request as EmbeddingRequest;
9+
use EchoLabs\Prism\Embeddings\Response as EmbeddingResponse;
810
use EchoLabs\Prism\Providers\Mistral\Handlers\Text;
911
use EchoLabs\Prism\Providers\ProviderResponse;
1012
use EchoLabs\Prism\Structured\Request as StructuredRequest;
@@ -33,6 +35,12 @@ public function structured(StructuredRequest $request): ProviderResponse
3335
throw new \Exception(sprintf('%s does not support structured mode', class_basename($this)));
3436
}
3537

38+
#[\Override]
39+
public function embeddings(EmbeddingRequest $request): EmbeddingResponse
40+
{
41+
throw new \Exception(sprintf('%s does not support embeddings', class_basename($this)));
42+
}
43+
3644
/**
3745
* @param array<string, mixed> $options
3846
* @param array<mixed> $retry

Diff for: src/Providers/Ollama/Ollama.php

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace EchoLabs\Prism\Providers\Ollama;
66

77
use EchoLabs\Prism\Contracts\Provider;
8+
use EchoLabs\Prism\Embeddings\Request as EmbeddingRequest;
9+
use EchoLabs\Prism\Embeddings\Response as EmbeddingResponse;
810
use EchoLabs\Prism\Providers\Ollama\Handlers\Text;
911
use EchoLabs\Prism\Providers\ProviderResponse;
1012
use EchoLabs\Prism\Structured\Request as StructuredRequest;
@@ -33,6 +35,12 @@ public function structured(StructuredRequest $request): ProviderResponse
3335
throw new \Exception(sprintf('%s does not support structured mode', class_basename($this)));
3436
}
3537

38+
#[\Override]
39+
public function embeddings(EmbeddingRequest $request): EmbeddingResponse
40+
{
41+
throw new \Exception(sprintf('%s does not support embeddings', class_basename($this)));
42+
}
43+
3644
/**
3745
* @param array<string, mixed> $options
3846
* @param array<mixed> $retry

0 commit comments

Comments
 (0)