return tmpls->has_explicit_template;
}
+// LFM2 format detection: template uses <|tool_list_start|>[...]<|tool_list_end|> around the tool list
+// and <|tool_call_start|>[...]<|tool_call_end|> around each tool call
+static bool is_lfm2_template(const std::string & src) {
+ return src.find("<|tool_list_start|>") != std::string::npos &&
+ src.find("<|tool_list_end|>") != std::string::npos;
+}
+
+common_chat_prompt_preset common_chat_get_asr_prompt(const common_chat_templates * chat_templates) {
+ common_chat_prompt_preset asr_preset;
+ asr_preset.system = "";
+ asr_preset.user = "Transcribe audio to text";
+
+ if (chat_templates && chat_templates->template_default && is_lfm2_template(chat_templates->template_default->source())) {
+ asr_preset.system = "Perform ASR.";
+ asr_preset.user = "";
+ }
+
+ return asr_preset;
+}
+
std::string common_chat_templates_source(const struct common_chat_templates * tmpls, const std::string & variant) {
if (!variant.empty()) {
if (variant == "tool_use") {
return common_chat_params_init_kimi_k2(tmpl, params);
}
- // LFM2 format detection: template uses <|tool_list_start|>[...]<|tool_list_end|> around the tool list
- // and <|tool_call_start|>[...]<|tool_call_end|> around each tool call
- if (src.find("<|tool_list_start|>") != std::string::npos &&
- src.find("<|tool_list_end|>") != std::string::npos) {
+ if (is_lfm2_template(src)) {
LOG_DBG("Using specialized template: LFM2\n");
return common_chat_params_init_lfm2(tmpl, params);
}
GGML_ASSERT(chat_templates->template_default != nullptr);
return chat_templates->template_default->caps.to_map();
}
-
const common_chat_template & tmpl,
const std::string & src,
autoparser::generation_params & params);
+
+// specialized per-task preset
+struct common_chat_prompt_preset {
+ std::string system;
+ std::string user;
+};
+
+common_chat_prompt_preset common_chat_get_asr_prompt(const common_chat_templates * chat_templates);
json convert_transcriptions_to_chatcmpl(
const json & inp_body,
+ const common_chat_templates * tmpls,
const std::map<std::string, raw_buffer> & in_files,
std::vector<raw_buffer> & out_files) {
// TODO @ngxson : this function may need to be improved in the future
}
// 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 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 = "Transcribe audio to text";
+ 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"] = json::array({
- {
- {"role", "user"},
- {"content", prompt},
- },
- });
+ 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"));
// convert OpenAI transcriptions API format to OpenAI Chat Completions API format
json convert_transcriptions_to_chatcmpl(
const json & body,
+ const common_chat_templates * tmpls,
const std::map<std::string, raw_buffer> & in_files,
std::vector<raw_buffer> & out_files);
std::vector<raw_buffer> files;
json body = convert_transcriptions_to_chatcmpl(
json::parse(req.body),
+ meta->chat_params.tmpls.get(),
req.files,
files);
SRV_DBG("%s\n", "Request converted: OpenAI Transcriptions -> OpenAI Chat Completions");