Safetensors
GGUF
Turkish
llama
Llama-3
instruct
finetune
chatml
gpt4
synthetic data
distillation
function calling
json mode
axolotl
roleplaying
chat
Instructions to use tda45/TdAI with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- llama-cpp-python
How to use tda45/TdAI with llama-cpp-python:
# !pip install llama-cpp-python from llama_cpp import Llama llm = Llama.from_pretrained( repo_id="tda45/TdAI", filename="llama.cpp/models/ggml-vocab-aquila.gguf", )
output = llm( "Once upon a time,", max_tokens=512, echo=True ) print(output)
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use tda45/TdAI with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf tda45/TdAI # Run inference directly in the terminal: llama cli -hf tda45/TdAI
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf tda45/TdAI # Run inference directly in the terminal: llama cli -hf tda45/TdAI
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf tda45/TdAI # Run inference directly in the terminal: ./llama-cli -hf tda45/TdAI
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf tda45/TdAI # Run inference directly in the terminal: ./build/bin/llama-cli -hf tda45/TdAI
Use Docker
docker model run hf.co/tda45/TdAI
- LM Studio
- Jan
- Ollama
How to use tda45/TdAI with Ollama:
ollama run hf.co/tda45/TdAI
- Unsloth Studio
How to use tda45/TdAI with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for tda45/TdAI to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for tda45/TdAI to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for tda45/TdAI to start chatting
- Atomic Chat new
- Docker Model Runner
How to use tda45/TdAI with Docker Model Runner:
docker model run hf.co/tda45/TdAI
- Lemonade
How to use tda45/TdAI with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull tda45/TdAI
Run and chat with the model
lemonade run user.TdAI-{{QUANT_TAG}}List all available models
lemonade list
| json server_chat_convert_responses_to_chatcmpl(const json & response_body) { | |
| if (!response_body.contains("input")) { | |
| throw std::invalid_argument("'input' is required"); | |
| } | |
| if (!json_value(response_body, "previous_response_id", std::string{}).empty()) { | |
| throw std::invalid_argument("llama.cpp does not support 'previous_response_id'."); | |
| } | |
| const json input_value = response_body.at("input"); | |
| json chatcmpl_body = response_body; | |
| chatcmpl_body.erase("input"); | |
| std::vector<json> chatcmpl_messages; | |
| if (response_body.contains("instructions")) { | |
| chatcmpl_messages.push_back({ | |
| {"role", "system"}, | |
| {"content", json_value(response_body, "instructions", std::string())}, | |
| }); | |
| chatcmpl_body.erase("instructions"); | |
| } | |
| if (input_value.is_string()) { | |
| // #responses_create-input-text_input | |
| chatcmpl_messages.push_back({ | |
| {"role", "user"}, | |
| {"content", input_value}, | |
| }); | |
| } else if (input_value.is_array()) { | |
| // #responses_create-input-input_item_list | |
| static auto exists_and_is_array = [](const json & j, const char * key) -> bool { | |
| return j.contains(key) && j.at(key).is_array(); | |
| }; | |
| static auto exists_and_is_string = [](const json & j, const char * key) -> bool { | |
| return j.contains(key) && j.at(key).is_string(); | |
| }; | |
| for (json item : input_value) { | |
| bool merge_prev = !chatcmpl_messages.empty() && chatcmpl_messages.back().value("role", "") == "assistant"; | |
| if (exists_and_is_string(item, "content")) { | |
| // #responses_create-input-input_item_list-input_message-content-text_input | |
| // Only "Input message" contains item["content"]::string | |
| // After converting item["content"]::string to item["content"]::array, | |
| // we can treat "Input message" as sum of "Item-Input message" and "Item-Output message" | |
| item["content"] = json::array({ | |
| json { | |
| {"text", item.at("content")}, | |
| {"type", "input_text"} | |
| } | |
| }); | |
| } | |
| if (exists_and_is_array(item, "content") && | |
| exists_and_is_string(item, "role") && | |
| (item.at("role") == "user" || | |
| item.at("role") == "system" || | |
| item.at("role") == "developer") | |
| ) { | |
| // #responses_create-input-input_item_list-item-input_message | |
| std::vector<json> chatcmpl_content; | |
| for (const json & input_item : item.at("content")) { | |
| const std::string type = json_value(input_item, "type", std::string()); | |
| if (type == "input_text") { | |
| if (!input_item.contains("text")) { | |
| throw std::invalid_argument("'Input text' requires 'text'"); | |
| } | |
| chatcmpl_content.push_back({ | |
| {"text", input_item.at("text")}, | |
| {"type", "text"}, | |
| }); | |
| } else if (type == "input_image") { | |
| // While `detail` is marked as required, | |
| // it has default value("auto") and can be omitted. | |
| if (!input_item.contains("image_url")) { | |
| throw std::invalid_argument("'image_url' is required"); | |
| } | |
| chatcmpl_content.push_back({ | |
| {"image_url", json { | |
| {"url", input_item.at("image_url")} | |
| }}, | |
| {"type", "image_url"}, | |
| }); | |
| } else if (type == "input_file") { | |
| throw std::invalid_argument("'input_file' is not supported by llamacpp at this moment"); | |
| } else { | |
| throw std::invalid_argument("'type' must be one of 'input_text', 'input_image', or 'input_file'"); | |
| } | |
| } | |
| if (item.contains("type")) { | |
| item.erase("type"); | |
| } | |
| if (item.contains("status")) { | |
| item.erase("status"); | |
| } | |
| item["content"] = chatcmpl_content; | |
| chatcmpl_messages.push_back(item); | |
| } else if (exists_and_is_string(item, "role") && | |
| item.at("role") == "assistant" && | |
| exists_and_is_string(item, "type") && | |
| item.at("type") == "message" | |
| ) { | |
| // #responses_create-input-input_item_list-item-output_message | |
| auto chatcmpl_content = json::array(); | |
| // Handle both string content and array content | |
| if (item.contains("content") && item.at("content").is_string()) { | |
| // String content - convert to text content part | |
| chatcmpl_content.push_back({ | |
| {"text", item.at("content")}, | |
| {"type", "text"}, | |
| }); | |
| } else if (exists_and_is_array(item, "content")) { | |
| // Array content - process each item | |
| for (const auto & output_text : item.at("content")) { | |
| const std::string type = json_value(output_text, "type", std::string()); | |
| if (type == "output_text" || type == "input_text") { | |
| // Accept both output_text and input_text (string content gets converted to input_text) | |
| if (!exists_and_is_string(output_text, "text")) { | |
| throw std::invalid_argument("'Output text' requires 'text'"); | |
| } | |
| chatcmpl_content.push_back({ | |
| {"text", output_text.at("text")}, | |
| {"type", "text"}, | |
| }); | |
| } else if (type == "refusal") { | |
| if (!exists_and_is_string(output_text, "refusal")) { | |
| throw std::invalid_argument("'Refusal' requires 'refusal'"); | |
| } | |
| chatcmpl_content.push_back({ | |
| {"refusal", output_text.at("refusal")}, | |
| {"type", "refusal"}, | |
| }); | |
| } else { | |
| throw std::invalid_argument("'type' must be one of 'output_text' or 'refusal'"); | |
| } | |
| } | |
| } | |
| if (merge_prev) { | |
| auto & prev_msg = chatcmpl_messages.back(); | |
| if (!exists_and_is_array(prev_msg, "content")) { | |
| prev_msg["content"] = json::array(); | |
| } | |
| auto & prev_content = prev_msg["content"]; | |
| prev_content.insert(prev_content.end(), chatcmpl_content.begin(), chatcmpl_content.end()); | |
| } else { | |
| item.erase("status"); | |
| item.erase("type"); | |
| item["content"] = chatcmpl_content; | |
| chatcmpl_messages.push_back(item); | |
| } | |
| } else if (exists_and_is_string(item, "arguments") && | |
| exists_and_is_string(item, "call_id") && | |
| exists_and_is_string(item, "name") && | |
| exists_and_is_string(item, "type") && | |
| item.at("type") == "function_call" | |
| ) { | |
| // #responses_create-input-input_item_list-item-function_tool_call | |
| json tool_call = { | |
| {"function", json { | |
| {"arguments", item.at("arguments")}, | |
| {"name", item.at("name")}, | |
| }}, | |
| {"id", item.at("call_id")}, | |
| {"type", "function"}, | |
| }; | |
| if (merge_prev) { | |
| auto & prev_msg = chatcmpl_messages.back(); | |
| if (!exists_and_is_array(prev_msg, "tool_calls")) { | |
| prev_msg["tool_calls"] = json::array(); | |
| } | |
| prev_msg["tool_calls"].push_back(tool_call); | |
| } else { | |
| chatcmpl_messages.push_back(json { | |
| {"role", "assistant"}, | |
| {"tool_calls", json::array({tool_call})} | |
| }); | |
| } | |
| } else if (exists_and_is_string(item, "call_id") && | |
| (exists_and_is_string(item, "output") || exists_and_is_array(item, "output")) && | |
| exists_and_is_string(item, "type") && | |
| item.at("type") == "function_call_output" | |
| ) { | |
| // #responses_create-input-input_item_list-item-function_tool_call_output | |
| if (item.at("output").is_string()) { | |
| chatcmpl_messages.push_back(json { | |
| {"content", item.at("output")}, | |
| {"role", "tool"}, | |
| {"tool_call_id", item.at("call_id")}, | |
| }); | |
| } else { | |
| json chatcmpl_outputs = item.at("output"); | |
| for (json & chatcmpl_output : chatcmpl_outputs) { | |
| if (!chatcmpl_output.contains("type") || chatcmpl_output.at("type") != "input_text") { | |
| throw std::invalid_argument("Output of tool call should be 'Input text'"); | |
| } | |
| chatcmpl_output["type"] = "text"; | |
| } | |
| chatcmpl_messages.push_back(json { | |
| {"content", chatcmpl_outputs}, | |
| {"role", "tool"}, | |
| {"tool_call_id", item.at("call_id")}, | |
| }); | |
| } | |
| } else if (exists_and_is_array(item, "summary") && | |
| exists_and_is_string(item, "type") && | |
| item.at("type") == "reasoning") { | |
| // #responses_create-input-input_item_list-item-reasoning | |
| if (!exists_and_is_array(item, "content")) { | |
| throw std::invalid_argument("item['content'] is not an array"); | |
| } | |
| if (item.at("content").empty()) { | |
| throw std::invalid_argument("item['content'] is empty"); | |
| } | |
| if (!exists_and_is_string(item.at("content")[0], "text")) { | |
| throw std::invalid_argument("item['content']['text'] is not a string"); | |
| } | |
| if (merge_prev) { | |
| auto & prev_msg = chatcmpl_messages.back(); | |
| prev_msg["reasoning_content"] = item.at("content")[0].at("text"); | |
| } else { | |
| chatcmpl_messages.push_back(json { | |
| {"role", "assistant"}, | |
| {"content", json::array()}, | |
| {"reasoning_content", item.at("content")[0].at("text")}, | |
| }); | |
| } | |
| } else { | |
| throw std::invalid_argument("Cannot determine type of 'item'"); | |
| } | |
| } | |
| } else { | |
| throw std::invalid_argument("'input' must be a string or array of objects"); | |
| } | |
| chatcmpl_body["messages"] = chatcmpl_messages; | |
| if (response_body.contains("tools")) { | |
| if (!response_body.at("tools").is_array()) { | |
| throw std::invalid_argument("'tools' must be an array of objects"); | |
| } | |
| std::vector<json> chatcmpl_tools; | |
| for (json resp_tool : response_body.at("tools")) { | |
| json chatcmpl_tool; | |
| const std::string type = json_value(resp_tool, "type", std::string()); | |
| if (type != "function") { | |
| // Non-function Responses tools have no Chat Completions equivalent. | |
| SRV_WRN("unsupported Responses tool type '%s' skipped\n", type.c_str()); | |
| continue; | |
| } | |
| resp_tool.erase("type"); | |
| chatcmpl_tool["type"] = "function"; | |
| if (!resp_tool.contains("strict")) { | |
| resp_tool["strict"] = true; | |
| } | |
| chatcmpl_tool["function"] = resp_tool; | |
| chatcmpl_tools.push_back(chatcmpl_tool); | |
| } | |
| chatcmpl_body.erase("tools"); | |
| if (!chatcmpl_tools.empty()) { | |
| chatcmpl_body["tools"] = chatcmpl_tools; | |
| } | |
| } | |
| if (response_body.contains("max_output_tokens")) { | |
| chatcmpl_body.erase("max_output_tokens"); | |
| chatcmpl_body["max_tokens"] = response_body["max_output_tokens"]; | |
| } | |
| return chatcmpl_body; | |
| } | |
| // Edits the cch section of an "x-anthropic-billing-header" system prompt. | |
| // Does nothing to any other prompt. | |
| // | |
| // This is a claude message with a "cch=ef01a" attribute that breaks prefix caching. | |
| // The cch stamp is a whitebox end-to-end integrity hint. It's not meaningful as a | |
| // system prompt data, particularly to llama.cpp, but its presence means the prefix | |
| // cache will not get past it: It changes on each request. | |
| // | |
| // Reference: https://github.com/ggml-org/llama.cpp/pull/21793 | |
| // Example header: | |
| // ``` | |
| // x-anthropic-billing-header: cc_version=2.1.101.e51; cc_entrypoint=cli; cch=a5145;You are Claude Code, Anthropic's official CLI for Claude. | |
| // ^^^^^ | |
| // ``` | |
| static void normalize_anthropic_billing_header(std::string & system_text) { | |
| if (system_text.rfind("x-anthropic-billing-header:", 0) != 0) { | |
| return; | |
| } | |
| const size_t header_prefix_length = strlen("x-anthropic-billing-header:"); | |
| const size_t cch_length = 5; | |
| const size_t index_cch = system_text.find("cch=", header_prefix_length); | |
| if (index_cch == std::string::npos) { | |
| return; | |
| } | |
| const size_t index_replace = index_cch + 4; | |
| if (index_replace + cch_length < system_text.length() && system_text[index_replace + cch_length] == ';') { | |
| for (size_t i = 0; i < cch_length; ++i) { | |
| system_text[index_replace + i] = 'f'; | |
| } | |
| } else { | |
| LOG_ERR("anthropic string not as expected: %s", system_text.c_str()); | |
| } | |
| } | |
| json server_chat_convert_anthropic_to_oai(const json & body) { | |
| json oai_body; | |
| // Convert system prompt | |
| json oai_messages = json::array(); | |
| auto system_param = json_value(body, "system", json()); | |
| if (!system_param.is_null()) { | |
| std::string system_content; | |
| if (system_param.is_string()) { | |
| system_content = system_param.get<std::string>(); | |
| normalize_anthropic_billing_header(system_content); | |
| } else if (system_param.is_array()) { | |
| for (const auto & block : system_param) { | |
| if (json_value(block, "type", std::string()) == "text") { | |
| auto system_text = json_value(block, "text", std::string()); | |
| normalize_anthropic_billing_header(system_text); | |
| system_content += system_text; | |
| } | |
| } | |
| } | |
| oai_messages.push_back({ | |
| {"role", "system"}, | |
| {"content", system_content} | |
| }); | |
| } | |
| // Convert messages | |
| if (!body.contains("messages")) { | |
| throw std::runtime_error("'messages' is required"); | |
| } | |
| const json & messages = body.at("messages"); | |
| if (messages.is_array()) { | |
| for (const auto & msg : messages) { | |
| std::string role = json_value(msg, "role", std::string()); | |
| if (!msg.contains("content")) { | |
| if (role == "assistant") { | |
| continue; | |
| } | |
| oai_messages.push_back(msg); | |
| continue; | |
| } | |
| const json & content = msg.at("content"); | |
| if (content.is_string()) { | |
| oai_messages.push_back(msg); | |
| continue; | |
| } | |
| if (!content.is_array()) { | |
| oai_messages.push_back(msg); | |
| continue; | |
| } | |
| json tool_calls = json::array(); | |
| json converted_content = json::array(); | |
| json tool_results = json::array(); | |
| std::string reasoning_content; | |
| bool has_tool_calls = false; | |
| for (const auto & block : content) { | |
| std::string type = json_value(block, "type", std::string()); | |
| if (type == "text") { | |
| converted_content.push_back(block); | |
| } else if (type == "thinking") { | |
| reasoning_content += json_value(block, "thinking", std::string()); | |
| } else if (type == "image") { | |
| json source = json_value(block, "source", json::object()); | |
| std::string source_type = json_value(source, "type", std::string()); | |
| if (source_type == "base64") { | |
| std::string media_type = json_value(source, "media_type", std::string("image/jpeg")); | |
| std::string data = json_value(source, "data", std::string()); | |
| std::ostringstream ss; | |
| ss << "data:" << media_type << ";base64," << data; | |
| converted_content.push_back({ | |
| {"type", "image_url"}, | |
| {"image_url", { | |
| {"url", ss.str()} | |
| }} | |
| }); | |
| } else if (source_type == "url") { | |
| std::string url = json_value(source, "url", std::string()); | |
| converted_content.push_back({ | |
| {"type", "image_url"}, | |
| {"image_url", { | |
| {"url", url} | |
| }} | |
| }); | |
| } | |
| } else if (type == "tool_use") { | |
| tool_calls.push_back({ | |
| {"id", json_value(block, "id", std::string())}, | |
| {"type", "function"}, | |
| {"function", { | |
| {"name", json_value(block, "name", std::string())}, | |
| {"arguments", json_value(block, "input", json::object()).dump()} | |
| }} | |
| }); | |
| has_tool_calls = true; | |
| } else if (type == "tool_result") { | |
| std::string tool_use_id = json_value(block, "tool_use_id", std::string()); | |
| auto result_content = json_value(block, "content", json()); | |
| std::string result_text; | |
| if (result_content.is_string()) { | |
| result_text = result_content.get<std::string>(); | |
| } else if (result_content.is_array()) { | |
| for (const auto & c : result_content) { | |
| if (json_value(c, "type", std::string()) == "text") { | |
| result_text += json_value(c, "text", std::string()); | |
| } | |
| } | |
| } | |
| tool_results.push_back({ | |
| {"role", "tool"}, | |
| {"tool_call_id", tool_use_id}, | |
| {"content", result_text} | |
| }); | |
| } | |
| } | |
| if (!converted_content.empty() || has_tool_calls || !reasoning_content.empty()) { | |
| json new_msg = {{"role", role}}; | |
| if (!converted_content.empty()) { | |
| new_msg["content"] = converted_content; | |
| } else if (has_tool_calls || !reasoning_content.empty()) { | |
| new_msg["content"] = ""; | |
| } | |
| if (!tool_calls.empty()) { | |
| new_msg["tool_calls"] = tool_calls; | |
| } | |
| if (!reasoning_content.empty()) { | |
| new_msg["reasoning_content"] = reasoning_content; | |
| } | |
| oai_messages.push_back(new_msg); | |
| } | |
| for (const auto & tool_msg : tool_results) { | |
| oai_messages.push_back(tool_msg); | |
| } | |
| } | |
| } | |
| oai_body["messages"] = oai_messages; | |
| // Convert tools | |
| if (body.contains("tools")) { | |
| const json & tools = body.at("tools"); | |
| if (tools.is_array()) { | |
| json oai_tools = json::array(); | |
| for (const auto & tool : tools) { | |
| oai_tools.push_back({ | |
| {"type", "function"}, | |
| {"function", { | |
| {"name", json_value(tool, "name", std::string())}, | |
| {"description", json_value(tool, "description", std::string())}, | |
| {"parameters", tool.contains("input_schema") ? tool.at("input_schema") : json::object()} | |
| }} | |
| }); | |
| } | |
| oai_body["tools"] = oai_tools; | |
| } | |
| } | |
| // Convert tool_choice | |
| if (body.contains("tool_choice")) { | |
| const json & tc = body.at("tool_choice"); | |
| if (tc.is_object()) { | |
| std::string type = json_value(tc, "type", std::string()); | |
| if (type == "auto") { | |
| oai_body["tool_choice"] = "auto"; | |
| } else if (type == "any" || type == "tool") { | |
| oai_body["tool_choice"] = "required"; | |
| } | |
| } | |
| } | |
| // Convert stop_sequences to stop | |
| if (body.contains("stop_sequences")) { | |
| oai_body["stop"] = body.at("stop_sequences"); | |
| } | |
| // Handle max_tokens (required in Anthropic, but we're permissive) | |
| if (body.contains("max_tokens")) { | |
| oai_body["max_tokens"] = body.at("max_tokens"); | |
| } else { | |
| oai_body["max_tokens"] = 4096; | |
| } | |
| // Pass through common params | |
| for (const auto & key : {"temperature", "top_p", "top_k", "stream", "chat_template_kwargs"}) { | |
| if (body.contains(key)) { | |
| oai_body[key] = body.at(key); | |
| } | |
| } | |
| // Handle Anthropic-specific thinking param | |
| if (body.contains("thinking")) { | |
| json thinking = json_value(body, "thinking", json::object()); | |
| std::string thinking_type = json_value(thinking, "type", std::string()); | |
| if (thinking_type == "enabled") { | |
| int budget_tokens = json_value(thinking, "budget_tokens", 10000); | |
| oai_body["thinking_budget_tokens"] = budget_tokens; | |
| } | |
| } | |
| // Handle Anthropic-specific metadata param | |
| if (body.contains("metadata")) { | |
| json metadata = json_value(body, "metadata", json::object()); | |
| std::string user_id = json_value(metadata, "user_id", std::string()); | |
| if (!user_id.empty()) { | |
| oai_body["__metadata_user_id"] = user_id; | |
| } | |
| } | |
| return oai_body; | |
| } | |
| json server_chat_msg_diff_to_json_oaicompat(const common_chat_msg_diff & diff) { | |
| json delta = json::object(); | |
| if (!diff.reasoning_content_delta.empty()) { | |
| delta["reasoning_content"] = diff.reasoning_content_delta; | |
| } | |
| if (!diff.content_delta.empty()) { | |
| delta["content"] = diff.content_delta; | |
| } | |
| if (diff.tool_call_index != std::string::npos) { | |
| json tool_call; | |
| tool_call["index"] = diff.tool_call_index; | |
| if (!diff.tool_call_delta.id.empty()) { | |
| tool_call["id"] = diff.tool_call_delta.id; | |
| tool_call["type"] = "function"; | |
| } | |
| if (!diff.tool_call_delta.name.empty() || !diff.tool_call_delta.arguments.empty()) { | |
| json function = json::object(); | |
| if (!diff.tool_call_delta.name.empty()) { | |
| function["name"] = diff.tool_call_delta.name; | |
| } | |
| if (!diff.tool_call_delta.arguments.empty()) { | |
| function["arguments"] = diff.tool_call_delta.arguments; | |
| } | |
| tool_call["function"] = function; | |
| } | |
| delta["tool_calls"] = json::array({ tool_call }); | |
| } | |
| return delta; | |
| } | |
| json convert_transcriptions_to_chatcmpl( | |
| const json & inp_body, | |
| const common_chat_templates * tmpls, | |
| const std::map<std::string, uploaded_file> & in_files, | |
| std::vector<raw_buffer> & out_files) { | |
| // TODO @ngxson : this function may need to be improved in the future | |
| // handle input files | |
| out_files.clear(); | |
| auto it = in_files.find("file"); | |
| if (it != in_files.end()) { | |
| out_files.push_back(it->second.data); | |
| } else { | |
| throw std::invalid_argument("No input file found for transcription"); | |
| } | |
| // handle input data | |
| std::string prompt = json_value(inp_body, "prompt", std::string()); | |
| std::string language = json_value(inp_body, "language", std::string()); | |
| std::string response_format = json_value(inp_body, "response_format", std::string("json")); | |
| if (response_format != "json") { | |
| throw std::invalid_argument("Only 'json' response_format is supported for transcription"); | |
| } | |
| const common_chat_prompt_preset preset = common_chat_get_asr_prompt(tmpls); | |
| if (prompt.empty()) { | |
| prompt = preset.user; | |
| } | |
| if (!language.empty()) { | |
| prompt += string_format(" (language: %s)", language.c_str()); | |
| } | |
| prompt += get_media_marker(); | |
| json messages = json::array(); | |
| if (!preset.system.empty()) { | |
| messages.push_back({{"role", "system"}, {"content", preset.system}}); | |
| } | |
| messages.push_back({{"role", "user"}, {"content", prompt}}); | |
| json chatcmpl_body = inp_body; // copy all fields | |
| chatcmpl_body["messages"] = messages; | |
| // because input from form-data, everything is string, we need to correct the types here | |
| std::string stream = json_value(inp_body, "stream", std::string("false")); | |
| chatcmpl_body["stream"] = stream == "true"; | |
| if (inp_body.contains("max_tokens")) { | |
| std::string inp = inp_body["max_tokens"].get<std::string>(); | |
| chatcmpl_body["max_tokens"] = std::stoul(inp); | |
| } | |
| if (inp_body.contains("temperature")) { | |
| std::string inp = inp_body["temperature"].get<std::string>(); | |
| chatcmpl_body["temperature"] = std::stof(inp); | |
| } | |
| return chatcmpl_body; | |
| } | |