Laravel với weaviate

Laravel với weaviate

Weaviate là một vector database – nó được dùng chủ yếu để lưu trữ, tìm kiếm, và xử lý dữ liệu dưới dạng vector (embedding vectors), thay vì chỉ lưu dữ liệu dạng text hoặc số thông thường như MySQL, MongoDB.

Nói đơn giản:

  • Khi bạn có dữ liệu dạng text, hình ảnh, audio,... bạn sẽ "embed" nó thành vector (ví dụ dùng OpenAI, Huggingface, hay các model embedding khác).

  • Weaviate lưu những vector đó, cùng với metadata.

  • Sau đó, bạn có thể tìm kiếm theo "ý nghĩa" bằng cách so sánh khoảng cách vector (semantic search) thay vì tìm kiếm từ khóa như trong các database truyền thống.

Tóm tắt Weaviate dùng làm gì:

  • Semantic search: Tìm kiếm theo ý nghĩa, không cần phải khớp từ khóa 100%.

  • Recommendation system: Gợi ý sản phẩm, bài viết, video,... dựa trên sự tương đồng vector.

  • Knowledge graph + vector search: Có thể vừa lưu các mối quan hệ kiểu graph, vừa tìm kiếm theo vector.

  • AI applications: Xây chatbot, hệ thống hỏi-đáp (RAG - Retrieval Augmented Generation), hoặc làm các app AI cần tìm kiếm dữ liệu thông minh.

Lý do tại sao mà chúng ta cần dùng weaviate do cần dùng search nội dung tài liệu và audio chứ như mysql hay mongodb thì không thể dùng search được .

Nguyên tắc làm việc của chúng ta sẽ như sau : Dữ liệu cần embebbing  => gọi đến service embebbing => vector dữ liệu => import lên weaviate 

Mình code service embebbing ở bài sau đây : https://dev.truyenvideo.com/p/python-embedding-vector

Ở đây mình tạo 1 service để có thể dễ sử dụng với weaviate :

<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;

class WeaviateService
{
    protected $url;
    protected $apiKey;

    public function __construct()
    {
        $this->url = env('VECTOR_URL');
        $this->apiKey = env('WEAVIATE_API_KEY');
    }

    public function createVector(string $title)
    {
        $response = Http::retry(3, 100)
            ->post(env('EMBEDDING_URL'), [
                'texts' => [$title],
            ]);

        if ($response->successful()) {
            return [
                'status' => 1,
                'vectors' => $response->json('vectors')
            ];
        }

        return ['status' => 0, 'vectors' => null];
    }

    protected function request(string $method, string $endpoint, array $data = [])
    {
        $request = Http::withHeaders([
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . $this->apiKey,
        ])->retry(3, 100);

        $response = $request->$method($this->url . $endpoint, $data);

        if (!$response->successful()) {
            throw new \Exception('Weaviate API error: ' . $response->body());
        }

        return $response->json();
    }

    public function create(string $className, array $properties, array $vector = null)
    {
        $body = [
            'class' => $className,
            'properties' => $properties,
        ];

        if ($vector) {
            $body['vector'] = $vector;
        }

        return $this->request('post', '/v1/objects', $body);
    }


    public function search( string $className,array $vector, $limit = 10, $fields = ['_additional { id }'], $sortField = null, $sortOrder = 'desc',  $distance = null, // thêm distance
        $certainty = null // hoặc certainty
    ) {
        $nearVectorParts = ['vector: [' . implode(',', $vector) . ']'];

        if (!is_null($distance)) {
            $nearVectorParts[] = "distance: $distance";
        }

        if (!is_null($certainty)) {
            $nearVectorParts[] = "certainty: $certainty";
        }

        $fieldString = implode("\n", $fields);

        $body = [
            'query' => "
            {
                Get {
                    $className(
                        nearVector: { " . implode(', ', $nearVectorParts) . " }
                        " . ($sortField ? "sort: [{ path: [\"$sortField\"], order: $sortOrder }]" : "") . "
                        limit: $limit
                    ) {
                        $fieldString
                    }
                }
            }
        "
        ];

        return $this->request('post', '/v1/graphql', $body);
    }


    public function delete(string $uuid)
    {
        return $this->request('delete', "/v1/objects/$uuid");
    }
}

Sau đó chúng ta dùng trong controller :

<?php

namespace App\Http\Controllers\Test;

use App\Http\Controllers\Controller;
use App\Services\WeaviateService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class WeaviateController extends Controller
{

    protected $weaviateService;

    public function __construct(WeaviateService $weaviateService)
    {
        $this->weaviateService = $weaviateService;
    }
    public function deleteweaviate(Request $request){
        $uuid_delete ='c1262dbc-87d6-41d9-8c52-ad3042af3820';
        $status_delete = $this->weaviateService->delete($uuid_delete);
        dd($status_delete);
    }
    public function searchweaviate(Request $request){
        $text_search ='AI Agent - Hướng dẫn dùng N8N tạo chatbot Zalo cá nhân SIÊU CHI TIẾT | Under 29';
        $vector_search = $this->weaviateService->createVector($text_search);
        $data_search = $this->weaviateService->search('Post',$vector_search['vectors'][0],
            limit: 5,
//            fields: ['title', 'created_at','_additional { id distance }'],
            fields : ['title','description', 'created_at', '_additional { id distance certainty score }'],
            distance: 0.5 );
        $posts = data_get($data_search, 'data.Get.Post', []);
        $titles = collect($posts)->pluck('title')->all();
        dd($data_search);
    }
    public function uploadweaviate(Request $request){
        $title = 'AI Agent - Hướng dẫn dùng N8N tạo chatbot Zalo cá nhân SIÊU CHI TIẾT | Under 29';
        $vector = $this->weaviateService->createVector($title);
        $vector_data =  $this->weaviateService->create('Post', [
            'title' => $title,
            'description' =>'Đây là description của ' .$title,
            'created_at' => now()->toIso8601String(),
        ], $vector['vectors'][0]);
        dd($vector_data);
    }
    public function createweaviate(Request $request){
        $response = Http::post(env('EMBEDDING_URL'), [
            'texts' => [
                "[Truyện Audio] Tái Sinh, Tôi Sẽ Không Tài Trợ Cho Tên Vô Ơn Đi Du Học | Phạm Bảo Khánh",
                "P35, Đến Chậm Thâm Tình So Cỏ Tiện, Ta Phản Lại Ngươi Khóc Cái Gì (chương 324324)",
                "P35, Đến Chậm Thâm Tình So Cỏ Tiện, Ta Phản Lại Ngươi Khóc Cái Gì (chương 213)",
            ]
        ]);

        if ($response->successful()) {
            $vectors = $response->json('vectors');
            dd($vectors);
        } else {
            dd($response->status(), $response->body());
        }
    }

}

Ở đây chúng ta thấy 

            'title' => $title,
            'description' =>'Đây là description của ' .$title,
            'created_at' => now()->toIso8601String(),

Mình có thể sử thay thế title ,description bằng các trường của bạn