mirror of
				https://github.com/ggml-org/llama.cpp.git
				synced 2025-11-03 09:22:01 +00:00 
			
		
		
		
	* wip llava python bindings compatibility * add external llava API * add base64 in-prompt image support * wip refactor image loading * refactor image load out of llava init * cleanup * further cleanup; move llava-cli into its own file and rename * move base64.hpp into common/ * collapse clip and llava libraries * move llava into its own subdir * wip * fix bug where base64 string was not removed from the prompt * get libllava to output in the right place * expose llava methods in libllama.dylib * cleanup memory usage around clip_image_* * cleanup and refactor *again* * update headerdoc * build with cmake, not tested (WIP) * Editorconfig * Editorconfig * Build with make * Build with make * Fix cyclical depts on Windows * attempt to fix build on Windows * attempt to fix build on Windows * Upd TODOs * attempt to fix build on Windows+CUDA * Revert changes in cmake * Fix according to review comments * Support building as a shared library * address review comments --------- Co-authored-by: M. Yusuf Sarıgöz <yusufsarigoz@gmail.com> Co-authored-by: Jared Van Bortel <jared@nomic.ai>
		
			
				
	
	
		
			393 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			393 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
This is free and unencumbered software released into the public domain.
 | 
						|
 | 
						|
Anyone is free to copy, modify, publish, use, compile, sell, or
 | 
						|
distribute this software, either in source code form or as a compiled
 | 
						|
binary, for any purpose, commercial or non-commercial, and by any
 | 
						|
means.
 | 
						|
 | 
						|
In jurisdictions that recognize copyright laws, the author or authors
 | 
						|
of this software dedicate any and all copyright interest in the
 | 
						|
software to the public domain. We make this dedication for the benefit
 | 
						|
of the public at large and to the detriment of our heirs and
 | 
						|
successors. We intend this dedication to be an overt act of
 | 
						|
relinquishment in perpetuity of all present and future rights to this
 | 
						|
software under copyright law.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
						|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
						|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
						|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
						|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
						|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
						|
OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
 | 
						|
For more information, please refer to <http://unlicense.org>
 | 
						|
*/
 | 
						|
 | 
						|
#ifndef PUBLIC_DOMAIN_BASE64_HPP_
 | 
						|
#define PUBLIC_DOMAIN_BASE64_HPP_
 | 
						|
 | 
						|
#include <cstdint>
 | 
						|
#include <iterator>
 | 
						|
#include <stdexcept>
 | 
						|
#include <string>
 | 
						|
 | 
						|
class base64_error : public std::runtime_error
 | 
						|
{
 | 
						|
public:
 | 
						|
    using std::runtime_error::runtime_error;
 | 
						|
};
 | 
						|
 | 
						|
class base64
 | 
						|
{
 | 
						|
public:
 | 
						|
    enum class alphabet
 | 
						|
    {
 | 
						|
        /** the alphabet is detected automatically */
 | 
						|
        auto_,
 | 
						|
        /** the standard base64 alphabet is used */
 | 
						|
        standard,
 | 
						|
        /** like `standard` except that the characters `+` and `/` are replaced by `-` and `_` respectively*/
 | 
						|
        url_filename_safe
 | 
						|
    };
 | 
						|
 | 
						|
    enum class decoding_behavior
 | 
						|
    {
 | 
						|
        /** if the input is not padded, the remaining bits are ignored */
 | 
						|
        moderate,
 | 
						|
        /** if a padding character is encounter decoding is finished */
 | 
						|
        loose
 | 
						|
    };
 | 
						|
 | 
						|
    /**
 | 
						|
     Encodes all the elements from `in_begin` to `in_end` to `out`.
 | 
						|
 | 
						|
     @warning The source and destination cannot overlap. The destination must be able to hold at least
 | 
						|
     `required_encode_size(std::distance(in_begin, in_end))`, otherwise the behavior depends on the output iterator.
 | 
						|
 | 
						|
     @tparam Input_iterator the source; the returned elements are cast to `std::uint8_t` and should not be greater than
 | 
						|
     8 bits
 | 
						|
     @tparam Output_iterator the destination; the elements written to it are from the type `char`
 | 
						|
     @param in_begin the beginning of the source
 | 
						|
     @param in_end the ending of the source
 | 
						|
     @param out the destination iterator
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @returns the iterator to the next element past the last element copied
 | 
						|
     @throws see `Input_iterator` and `Output_iterator`
 | 
						|
    */
 | 
						|
    template<typename Input_iterator, typename Output_iterator>
 | 
						|
    static Output_iterator encode(Input_iterator in_begin, Input_iterator in_end, Output_iterator out,
 | 
						|
                                  alphabet alphabet = alphabet::standard)
 | 
						|
    {
 | 
						|
        constexpr auto pad = '=';
 | 
						|
        const char* alpha  = alphabet == alphabet::url_filename_safe
 | 
						|
                                ? "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
						|
                                : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
						|
 | 
						|
        while (in_begin != in_end) {
 | 
						|
            std::uint8_t i0 = 0, i1 = 0, i2 = 0;
 | 
						|
 | 
						|
            // first character
 | 
						|
            i0 = static_cast<std::uint8_t>(*in_begin);
 | 
						|
            ++in_begin;
 | 
						|
 | 
						|
            *out = alpha[i0 >> 2 & 0x3f];
 | 
						|
            ++out;
 | 
						|
 | 
						|
            // part of first character and second
 | 
						|
            if (in_begin != in_end) {
 | 
						|
                i1 = static_cast<std::uint8_t>(*in_begin);
 | 
						|
                ++in_begin;
 | 
						|
 | 
						|
                *out = alpha[((i0 & 0x3) << 4) | (i1 >> 4 & 0x0f)];
 | 
						|
                ++out;
 | 
						|
            } else {
 | 
						|
                *out = alpha[(i0 & 0x3) << 4];
 | 
						|
                ++out;
 | 
						|
 | 
						|
                // last padding
 | 
						|
                *out = pad;
 | 
						|
                ++out;
 | 
						|
 | 
						|
                // last padding
 | 
						|
                *out = pad;
 | 
						|
                ++out;
 | 
						|
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            // part of second character and third
 | 
						|
            if (in_begin != in_end) {
 | 
						|
                i2 = static_cast<std::uint8_t>(*in_begin);
 | 
						|
                ++in_begin;
 | 
						|
 | 
						|
                *out = alpha[((i1 & 0xf) << 2) | (i2 >> 6 & 0x03)];
 | 
						|
                ++out;
 | 
						|
            } else {
 | 
						|
                *out = alpha[(i1 & 0xf) << 2];
 | 
						|
                ++out;
 | 
						|
 | 
						|
                // last padding
 | 
						|
                *out = pad;
 | 
						|
                ++out;
 | 
						|
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            // rest of third
 | 
						|
            *out = alpha[i2 & 0x3f];
 | 
						|
            ++out;
 | 
						|
        }
 | 
						|
 | 
						|
        return out;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Encodes a string.
 | 
						|
 | 
						|
     @param str the string that should be encoded
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @returns the encoded base64 string
 | 
						|
     @throws see base64::encode()
 | 
						|
    */
 | 
						|
    static std::string encode(const std::string& str, alphabet alphabet = alphabet::standard)
 | 
						|
    {
 | 
						|
        std::string result;
 | 
						|
 | 
						|
        result.reserve(required_encode_size(str.length()) + 1);
 | 
						|
 | 
						|
        encode(str.begin(), str.end(), std::back_inserter(result), alphabet);
 | 
						|
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Encodes a char array.
 | 
						|
 | 
						|
     @param buffer the char array
 | 
						|
     @param size the size of the array
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @returns the encoded string
 | 
						|
    */
 | 
						|
    static std::string encode(const char* buffer, std::size_t size, alphabet alphabet = alphabet::standard)
 | 
						|
    {
 | 
						|
        std::string result;
 | 
						|
 | 
						|
        result.reserve(required_encode_size(size) + 1);
 | 
						|
 | 
						|
        encode(buffer, buffer + size, std::back_inserter(result), alphabet);
 | 
						|
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Decodes all the elements from `in_begin` to `in_end` to `out`. `in_begin` may point to the same location as `out`,
 | 
						|
     in other words: inplace decoding is possible.
 | 
						|
 | 
						|
     @warning The destination must be able to hold at least `required_decode_size(std::distance(in_begin, in_end))`,
 | 
						|
     otherwise the behavior depends on the output iterator.
 | 
						|
 | 
						|
     @tparam Input_iterator the source; the returned elements are cast to `char`
 | 
						|
     @tparam Output_iterator the destination; the elements written to it are from the type `std::uint8_t`
 | 
						|
     @param in_begin the beginning of the source
 | 
						|
     @param in_end the ending of the source
 | 
						|
     @param out the destination iterator
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @param behavior the behavior when an error was detected
 | 
						|
     @returns the iterator to the next element past the last element copied
 | 
						|
     @throws base64_error depending on the set behavior
 | 
						|
     @throws see `Input_iterator` and `Output_iterator`
 | 
						|
    */
 | 
						|
    template<typename Input_iterator, typename Output_iterator>
 | 
						|
    static Output_iterator decode(Input_iterator in_begin, Input_iterator in_end, Output_iterator out,
 | 
						|
                                  alphabet alphabet          = alphabet::auto_,
 | 
						|
                                  decoding_behavior behavior = decoding_behavior::moderate)
 | 
						|
    {
 | 
						|
        //constexpr auto pad = '=';
 | 
						|
        std::uint8_t last  = 0;
 | 
						|
        auto bits          = 0;
 | 
						|
 | 
						|
        while (in_begin != in_end) {
 | 
						|
            auto c = *in_begin;
 | 
						|
            ++in_begin;
 | 
						|
 | 
						|
            if (c == '=') {
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            auto part = _base64_value(alphabet, c);
 | 
						|
 | 
						|
            // enough bits for one byte
 | 
						|
            if (bits + 6 >= 8) {
 | 
						|
                *out = (last << (8 - bits)) | (part >> (bits - 2));
 | 
						|
                ++out;
 | 
						|
 | 
						|
                bits -= 2;
 | 
						|
            } else {
 | 
						|
                bits += 6;
 | 
						|
            }
 | 
						|
 | 
						|
            last = part;
 | 
						|
        }
 | 
						|
 | 
						|
        // check padding
 | 
						|
        if (behavior != decoding_behavior::loose) {
 | 
						|
            while (in_begin != in_end) {
 | 
						|
                auto c = *in_begin;
 | 
						|
                ++in_begin;
 | 
						|
 | 
						|
                if (c != '=') {
 | 
						|
                    throw base64_error("invalid base64 character.");
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return out;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Decodes a string.
 | 
						|
 | 
						|
     @param str the base64 encoded string
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @param behavior the behavior when an error was detected
 | 
						|
     @returns the decoded string
 | 
						|
     @throws see base64::decode()
 | 
						|
    */
 | 
						|
    static std::string decode(const std::string& str, alphabet alphabet = alphabet::auto_,
 | 
						|
                              decoding_behavior behavior = decoding_behavior::moderate)
 | 
						|
    {
 | 
						|
        std::string result;
 | 
						|
 | 
						|
        result.reserve(max_decode_size(str.length()));
 | 
						|
 | 
						|
        decode(str.begin(), str.end(), std::back_inserter(result), alphabet, behavior);
 | 
						|
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Decodes a string.
 | 
						|
 | 
						|
     @param buffer the base64 encoded buffer
 | 
						|
     @param size the size of the buffer
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @param behavior the behavior when an error was detected
 | 
						|
     @returns the decoded string
 | 
						|
     @throws see base64::decode()
 | 
						|
    */
 | 
						|
    static std::string decode(const char* buffer, std::size_t size, alphabet alphabet = alphabet::auto_,
 | 
						|
                              decoding_behavior behavior = decoding_behavior::moderate)
 | 
						|
    {
 | 
						|
        std::string result;
 | 
						|
 | 
						|
        result.reserve(max_decode_size(size));
 | 
						|
 | 
						|
        decode(buffer, buffer + size, std::back_inserter(result), alphabet, behavior);
 | 
						|
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Decodes a string inplace.
 | 
						|
 | 
						|
     @param[in,out] str the base64 encoded string
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @param behavior the behavior when an error was detected
 | 
						|
     @throws base64::decode_inplace()
 | 
						|
    */
 | 
						|
    static void decode_inplace(std::string& str, alphabet alphabet = alphabet::auto_,
 | 
						|
                               decoding_behavior behavior = decoding_behavior::moderate)
 | 
						|
    {
 | 
						|
        str.resize(decode(str.begin(), str.end(), str.begin(), alphabet, behavior) - str.begin());
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Decodes a char array inplace.
 | 
						|
 | 
						|
     @param[in,out] str the string array
 | 
						|
     @param size the length of the array
 | 
						|
     @param alphabet which alphabet should be used
 | 
						|
     @param behavior the behavior when an error was detected
 | 
						|
     @returns the pointer to the next element past the last element decoded
 | 
						|
     @throws base64::decode_inplace()
 | 
						|
    */
 | 
						|
    static char* decode_inplace(char* str, std::size_t size, alphabet alphabet = alphabet::auto_,
 | 
						|
                                decoding_behavior behavior = decoding_behavior::moderate)
 | 
						|
    {
 | 
						|
        return decode(str, str + size, str, alphabet, behavior);
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Returns the required decoding size for a given size. The value is calculated with the following formula:
 | 
						|
 | 
						|
     $$
 | 
						|
     \lceil \frac{size}{4} \rceil \cdot 3
 | 
						|
     $$
 | 
						|
 | 
						|
     @param size the size of the encoded input
 | 
						|
     @returns the size of the resulting decoded buffer; this the absolute maximum
 | 
						|
    */
 | 
						|
    static std::size_t max_decode_size(std::size_t size) noexcept
 | 
						|
    {
 | 
						|
        return (size / 4 + (size % 4 ? 1 : 0)) * 3;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Returns the required encoding size for a given size. The value is calculated with the following formula:
 | 
						|
 | 
						|
     $$
 | 
						|
     \lceil \frac{size}{3} \rceil \cdot 4
 | 
						|
     $$
 | 
						|
 | 
						|
     @param size the size of the decoded input
 | 
						|
     @returns the size of the resulting encoded buffer
 | 
						|
    */
 | 
						|
    static std::size_t required_encode_size(std::size_t size) noexcept
 | 
						|
    {
 | 
						|
        return (size / 3 + (size % 3 ? 1 : 0)) * 4;
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    static std::uint8_t _base64_value(alphabet& alphabet, char c)
 | 
						|
    {
 | 
						|
        if (c >= 'A' && c <= 'Z') {
 | 
						|
            return c - 'A';
 | 
						|
        } else if (c >= 'a' && c <= 'z') {
 | 
						|
            return c - 'a' + 26;
 | 
						|
        } else if (c >= '0' && c <= '9') {
 | 
						|
            return c - '0' + 52;
 | 
						|
        }
 | 
						|
 | 
						|
        // comes down to alphabet
 | 
						|
        if (alphabet == alphabet::standard) {
 | 
						|
            if (c == '+') {
 | 
						|
                return 62;
 | 
						|
            } else if (c == '/') {
 | 
						|
                return 63;
 | 
						|
            }
 | 
						|
        } else if (alphabet == alphabet::url_filename_safe) {
 | 
						|
            if (c == '-') {
 | 
						|
                return 62;
 | 
						|
            } else if (c == '_') {
 | 
						|
                return 63;
 | 
						|
            }
 | 
						|
        } // auto detect
 | 
						|
        else {
 | 
						|
            if (c == '+') {
 | 
						|
                alphabet = alphabet::standard;
 | 
						|
 | 
						|
                return 62;
 | 
						|
            } else if (c == '/') {
 | 
						|
                alphabet = alphabet::standard;
 | 
						|
 | 
						|
                return 63;
 | 
						|
            } else if (c == '-') {
 | 
						|
                alphabet = alphabet::url_filename_safe;
 | 
						|
 | 
						|
                return 62;
 | 
						|
            } else if (c == '_') {
 | 
						|
                alphabet = alphabet::url_filename_safe;
 | 
						|
 | 
						|
                return 63;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        throw base64_error("invalid base64 character.");
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
#endif // !PUBLIC_DOMAIN_BASE64_HPP_
 |