|
|
#include <iostream> |
|
|
#include <string> |
|
|
#include <vector> |
|
|
#include <map> |
|
|
#include <set> |
|
|
#include <fstream> |
|
|
#include <regex> |
|
|
#include <memory> |
|
|
#include "json.hpp" |
|
|
#include <sstream> |
|
|
#include <cctype> |
|
|
#include <cmath> |
|
|
|
|
|
|
|
|
using json = nlohmann::json; |
|
|
|
|
|
|
|
|
class Postprocessor { |
|
|
private: |
|
|
|
|
|
std::map<std::string, std::string> cls_map; |
|
|
std::map<std::string, std::vector<std::string>> area2NL; |
|
|
std::map<std::string, std::string> NL2area; |
|
|
std::map<std::string, std::map<std::string, std::string>> maxmin_val_map; |
|
|
std::set<std::string> uncommon_area_NL; |
|
|
std::set<std::string> st_open; |
|
|
std::set<std::string> st_close; |
|
|
std::map<std::string, std::string> default_value; |
|
|
std::vector<std::string> switch_keywords; |
|
|
std::vector<std::string> level_keywords; |
|
|
std::vector<std::string> str2remove; |
|
|
std::vector<std::string> max_level_keys; |
|
|
std::vector<std::string> min_level_keys; |
|
|
std::string exclude_pattern_str; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> split_utf8_string(const std::string& text) { |
|
|
std::vector<std::string> utf8_chars; |
|
|
size_t i = 0; |
|
|
while (i < text.length()) { |
|
|
size_t len = 1; |
|
|
unsigned char c = (unsigned char)text[i]; |
|
|
if (c >= 0xE0) len = 3; |
|
|
else if (c >= 0xC0) len = 2; |
|
|
|
|
|
|
|
|
if (i + len > text.length()) { |
|
|
len = 1; |
|
|
} |
|
|
|
|
|
utf8_chars.push_back(text.substr(i, len)); |
|
|
i += len; |
|
|
} |
|
|
return utf8_chars; |
|
|
} |
|
|
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) { |
|
|
size_t start_pos = 0; |
|
|
while((start_pos = str.find(from, start_pos)) != std::string::npos) { |
|
|
str.replace(start_pos, from.length(), to); |
|
|
start_pos += to.length(); |
|
|
} |
|
|
return str; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::pair<long long, size_t> parse_english_numbers(const std::vector<std::string>& words, size_t start_index) { |
|
|
|
|
|
static const std::map<std::string, long long> ONES = { |
|
|
{"zero", 0}, {"one", 1}, {"two", 2}, {"three", 3}, {"four", 4}, |
|
|
{"five", 5}, {"six", 6}, {"seven", 7}, {"eight", 8}, {"nine", 9} |
|
|
}; |
|
|
static const std::map<std::string, long long> TEENS = { |
|
|
{"ten", 10}, {"eleven", 11}, {"twelve", 12}, {"thirteen", 13}, |
|
|
{"fourteen", 14}, {"fifteen", 15}, {"sixteen", 16}, |
|
|
{"seventeen", 17}, {"eighteen", 18}, {"nineteen", 19} |
|
|
}; |
|
|
static const std::map<std::string, long long> TENS = { |
|
|
{"twenty", 20}, {"thirty", 30}, {"forty", 40}, {"fifty", 50}, |
|
|
{"sixty", 60}, {"seventy", 70}, {"eighty", 80}, {"ninety", 90} |
|
|
}; |
|
|
static const std::map<std::string, long long> MAGNITUDES = { |
|
|
{"hundred", 100}, {"thousand", 1000}, {"million", 1000000}, {"billion", 1000000000} |
|
|
}; |
|
|
|
|
|
long long result = 0; |
|
|
long long current_magnitude_val = 0; |
|
|
long long current_hundred_val = 0; |
|
|
|
|
|
size_t i = start_index; |
|
|
while (i < words.size()) { |
|
|
std::string word = words[i]; |
|
|
|
|
|
|
|
|
std::transform(word.begin(), word.end(), word.begin(), |
|
|
[](unsigned char c){ return std::tolower(c); }); |
|
|
|
|
|
|
|
|
if (word.find('-') != std::string::npos) { |
|
|
std::string part1 = word.substr(0, word.find('-')); |
|
|
std::string part2 = word.substr(word.find('-') + 1); |
|
|
|
|
|
if (TENS.count(part1) && ONES.count(part2)) { |
|
|
current_hundred_val += TENS.at(part1) + ONES.at(part2); |
|
|
i++; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
if (ONES.count(word)) { |
|
|
current_hundred_val += ONES.at(word); |
|
|
} else if (TEENS.count(word)) { |
|
|
current_hundred_val += TEENS.at(word); |
|
|
} else if (TENS.count(word)) { |
|
|
current_hundred_val += TENS.at(word); |
|
|
} else if (MAGNITUDES.count(word)) { |
|
|
long long mag = MAGNITUDES.at(word); |
|
|
|
|
|
if (mag == 100) { |
|
|
|
|
|
if (current_hundred_val == 0) current_hundred_val = 1; |
|
|
current_hundred_val *= mag; |
|
|
} else { |
|
|
|
|
|
current_magnitude_val += current_hundred_val; |
|
|
if (current_magnitude_val == 0) current_magnitude_val = 1; |
|
|
|
|
|
result += current_magnitude_val * mag; |
|
|
current_magnitude_val = 0; |
|
|
current_hundred_val = 0; |
|
|
} |
|
|
} else if (word == "and" && i + 1 < words.size()) { |
|
|
|
|
|
i++; |
|
|
continue; |
|
|
} else { |
|
|
|
|
|
break; |
|
|
} |
|
|
i++; |
|
|
} |
|
|
|
|
|
|
|
|
result += current_magnitude_val; |
|
|
result += current_hundred_val; |
|
|
|
|
|
|
|
|
if (start_index < words.size() && i == start_index + 1 && words[start_index] == "zero") { |
|
|
return {0, start_index + 1}; |
|
|
} |
|
|
|
|
|
|
|
|
if (i == start_index) { |
|
|
return {0, start_index}; |
|
|
} |
|
|
|
|
|
return {result, i}; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string cn2an_transform(const std::string& text) { |
|
|
|
|
|
|
|
|
std::map<std::string, int> digit_map = { |
|
|
{"零", 0}, {"一", 1}, {"二", 2}, {"三", 3}, {"四", 4}, {"五", 5}, {"六", 6}, {"七", 7}, {"八", 8}, {"九", 9}, |
|
|
{"〇", 0}, {"壹", 1}, {"貳", 2}, {"參", 3}, {"肆", 4}, {"伍", 5}, {"陸", 6}, {"柒", 7}, {"捌", 8}, {"玖", 9}, |
|
|
{"兩", 2} |
|
|
}; |
|
|
|
|
|
std::map<std::string, int> unit_map = { |
|
|
{"十", 10}, {"百", 100}, {"千", 1000}, {"萬", 10000}, {"億", 100000000} |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> utf8_chars = split_utf8_string(text); |
|
|
std::string result_string = ""; |
|
|
|
|
|
|
|
|
long long total_val = 0; |
|
|
long long section_val = 0; |
|
|
long long current_val = 0; |
|
|
|
|
|
|
|
|
bool in_english_sequence = false; |
|
|
std::vector<std::string> english_words; |
|
|
|
|
|
|
|
|
auto flush_chinese = [&](std::string& res_str) { |
|
|
if (total_val > 0 || current_val > 0 || section_val > 0) { |
|
|
res_str += std::to_string(total_val + current_val + section_val); |
|
|
total_val = current_val = section_val = 0; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
auto flush_english = [&](std::string& res_str) { |
|
|
if (in_english_sequence && !english_words.empty()) { |
|
|
auto [num, end_idx] = parse_english_numbers(english_words, 0); |
|
|
if (end_idx > 0) { |
|
|
|
|
|
res_str += std::to_string(num); |
|
|
|
|
|
for (size_t k = end_idx; k < english_words.size(); ++k) { |
|
|
res_str += english_words[k]; |
|
|
} |
|
|
} else { |
|
|
|
|
|
for (const auto& word : english_words) { |
|
|
res_str += word; |
|
|
} |
|
|
} |
|
|
english_words.clear(); |
|
|
in_english_sequence = false; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
for (size_t j = 0; j < utf8_chars.size(); ++j) { |
|
|
std::string c = utf8_chars[j]; |
|
|
|
|
|
|
|
|
if (digit_map.count(c) || unit_map.count(c)) { |
|
|
flush_english(result_string); |
|
|
|
|
|
|
|
|
if (digit_map.count(c)) { |
|
|
|
|
|
section_val = digit_map.at(c); |
|
|
|
|
|
if (j == utf8_chars.size() - 1 || !unit_map.count(utf8_chars[j+1])) { |
|
|
current_val += section_val; |
|
|
section_val = 0; |
|
|
} |
|
|
} else if (unit_map.count(c)) { |
|
|
|
|
|
int unit_val = unit_map.at(c); |
|
|
|
|
|
|
|
|
if (unit_val < 10000 && (j == 0 || !digit_map.count(utf8_chars[j-1])) && section_val == 0 && current_val == 0) { |
|
|
section_val = 1; |
|
|
} |
|
|
|
|
|
if (unit_val < 10000) { |
|
|
|
|
|
current_val += section_val * unit_val; |
|
|
} else { |
|
|
|
|
|
total_val += (current_val + section_val) * unit_val; |
|
|
current_val = 0; |
|
|
} |
|
|
section_val = 0; |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else if (c.length() == 1) { |
|
|
char ch = c[0]; |
|
|
|
|
|
|
|
|
if (std::isdigit(ch)) { |
|
|
flush_chinese(result_string); |
|
|
flush_english(result_string); |
|
|
|
|
|
|
|
|
std::string num_str = ""; |
|
|
while (j < utf8_chars.size() && utf8_chars[j].length() == 1 && std::isdigit(utf8_chars[j][0])) { |
|
|
num_str += utf8_chars[j]; |
|
|
j++; |
|
|
} |
|
|
result_string += num_str; |
|
|
j--; |
|
|
continue; |
|
|
} |
|
|
|
|
|
|
|
|
if (std::isalpha(ch) || ch == '-') { |
|
|
flush_chinese(result_string); |
|
|
|
|
|
|
|
|
std::string token = ""; |
|
|
while (j < utf8_chars.size() && utf8_chars[j].length() == 1 && (std::isalpha(utf8_chars[j][0]) || utf8_chars[j][0] == '-')) { |
|
|
token += utf8_chars[j]; |
|
|
j++; |
|
|
} |
|
|
j--; |
|
|
|
|
|
|
|
|
english_words.push_back(token); |
|
|
in_english_sequence = true; |
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
flush_chinese(result_string); |
|
|
flush_english(result_string); |
|
|
|
|
|
|
|
|
result_string += c; |
|
|
} |
|
|
} |
|
|
|
|
|
else { |
|
|
flush_chinese(result_string); |
|
|
flush_english(result_string); |
|
|
|
|
|
|
|
|
result_string += c; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
flush_chinese(result_string); |
|
|
flush_english(result_string); |
|
|
|
|
|
return result_string; |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<std::string> extract_numbers_from_string(const std::string& text) { |
|
|
|
|
|
std::regex exclude_pattern(this->exclude_pattern_str); |
|
|
std::string cleaned_text = std::regex_replace(text, exclude_pattern, ""); |
|
|
|
|
|
std::regex num_pattern(R"(\d+)"); |
|
|
std::sregex_iterator next(cleaned_text.begin(), cleaned_text.end(), num_pattern); |
|
|
std::sregex_iterator end; |
|
|
std::vector<std::string> numbers; |
|
|
while (next != end) { |
|
|
numbers.push_back(next->str()); |
|
|
++next; |
|
|
} |
|
|
return numbers; |
|
|
} |
|
|
|
|
|
|
|
|
json get_keywords(const std::string& text) { |
|
|
json keywords; |
|
|
keywords["switch"] = json::array(); |
|
|
keywords["level"] = json::array(); |
|
|
keywords["num"] = json::array(); |
|
|
keywords["area_id"] = json::array(); |
|
|
|
|
|
for (const auto& pair : area2NL) { |
|
|
for (const auto& nl_phrase : pair.second) { |
|
|
if (text.find(nl_phrase) != std::string::npos) { |
|
|
keywords["area_id"].push_back(nl_phrase); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
auto find_keywords = [&](const std::vector<std::string>& kw_list, const std::string& key) { |
|
|
for (const auto& keyword : kw_list) { |
|
|
if (text.find(keyword) != std::string::npos) { |
|
|
keywords[key].push_back(keyword); |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
find_keywords(switch_keywords, "switch"); |
|
|
find_keywords(level_keywords, "level"); |
|
|
|
|
|
keywords["num"] = extract_numbers_from_string(text); |
|
|
return keywords; |
|
|
} |
|
|
|
|
|
|
|
|
std::string find_longest_string(const json& arr) { |
|
|
if (arr.empty()) { |
|
|
return ""; |
|
|
} |
|
|
std::string longest_str = arr[0].get<std::string>(); |
|
|
for (const auto& val : arr) { |
|
|
std::string current_str = val.get<std::string>(); |
|
|
if (current_str.length() > longest_str.length()) { |
|
|
longest_str = current_str; |
|
|
} |
|
|
} |
|
|
return longest_str; |
|
|
} |
|
|
|
|
|
public: |
|
|
|
|
|
void load_data() { |
|
|
|
|
|
std::ifstream cls_file("response_template.json"); |
|
|
if (!cls_file.is_open()) { |
|
|
std::cerr << "[ERROR] response_template.json file not found. Please ensure it's in the same directory." << std::endl; |
|
|
return; |
|
|
} |
|
|
|
|
|
json temp_json; |
|
|
try { |
|
|
cls_file >> temp_json; |
|
|
for (json::iterator it = temp_json.begin(); it != temp_json.end(); ++it) { |
|
|
cls_map[it.key()] = it.value().get<std::string>(); |
|
|
} |
|
|
} catch (const json::parse_error& e) { |
|
|
std::cerr << "[ERROR] JSON parse error in response_template.json: " << e.what() << std::endl; |
|
|
} |
|
|
|
|
|
|
|
|
std::ifstream data_file("keywords_data.json"); |
|
|
if (!data_file.is_open()) { |
|
|
std::cerr << "[ERROR] keywords_data.json file not found. Please ensure it's in the same directory." << std::endl; |
|
|
return; |
|
|
} |
|
|
|
|
|
json data_json; |
|
|
try { |
|
|
data_file >> data_json; |
|
|
|
|
|
|
|
|
for (const auto& [key, value] : data_json["area2NL"].items()) { |
|
|
area2NL[key] = value.get<std::vector<std::string>>(); |
|
|
} |
|
|
|
|
|
for (const auto& [key, value] : data_json["maxmin_val_map"].items()) { |
|
|
maxmin_val_map[key] = value.get<std::map<std::string, std::string>>(); |
|
|
} |
|
|
|
|
|
for (const auto& val : data_json["uncommon_area_NL"]) { |
|
|
uncommon_area_NL.insert(val.get<std::string>()); |
|
|
} |
|
|
|
|
|
for (const auto& val : data_json["st_open"]) { |
|
|
st_open.insert(val.get<std::string>()); |
|
|
} |
|
|
|
|
|
for (const auto& val : data_json["st_close"]) { |
|
|
st_close.insert(val.get<std::string>()); |
|
|
} |
|
|
|
|
|
for (const auto& [key, value] : data_json["default_value"].items()) { |
|
|
default_value[key] = value.get<std::string>(); |
|
|
} |
|
|
|
|
|
switch_keywords = data_json["switch_keywords"].get<std::vector<std::string>>(); |
|
|
|
|
|
level_keywords = data_json["level_keywords"].get<std::vector<std::string>>(); |
|
|
|
|
|
exclude_pattern_str = data_json["exclude_pattern_str"].get<std::string>(); |
|
|
str2remove = data_json["str2remove"].get<std::vector<std::string>>(); |
|
|
max_level_keys = data_json["max_level"].get<std::vector<std::string>>(); |
|
|
min_level_keys = data_json["min_level"].get<std::vector<std::string>>(); |
|
|
|
|
|
|
|
|
for (const auto& [area_id, nl_phrases] : area2NL) { |
|
|
for (const auto& nl_phrase : nl_phrases) { |
|
|
NL2area[nl_phrase] = area_id; |
|
|
} |
|
|
} |
|
|
|
|
|
} catch (const json::parse_error& e) { |
|
|
std::cerr << "[ERROR] JSON parse error in keywords_data.json: " << e.what() << std::endl; |
|
|
} |
|
|
} |
|
|
|
|
|
bool verbose = false; |
|
|
|
|
|
|
|
|
std::string postprocess(const std::string& query, const std::string& pred_class) { |
|
|
if (verbose) { |
|
|
std::cerr << "[DEBUG] input query: " << query << ", pred_class: " << pred_class << std::endl; |
|
|
} |
|
|
|
|
|
std::string ori_func_name = pred_class.substr(0, pred_class.find('%')); |
|
|
|
|
|
if (cls_map.find(pred_class) == cls_map.end()) { |
|
|
|
|
|
json empty_json; |
|
|
return empty_json.dump(); |
|
|
} |
|
|
|
|
|
std::string func_tmp_str = cls_map[pred_class]; |
|
|
std::string ori_query = query; |
|
|
std::string new_query = cn2an_transform(query); |
|
|
|
|
|
|
|
|
std::transform(new_query.begin(), new_query.end(), new_query.begin(), |
|
|
[](unsigned char c){ return std::tolower(c); }); |
|
|
|
|
|
for (auto s:str2remove){ |
|
|
size_t pos = new_query.find(s); |
|
|
if (pos != std::string::npos) { |
|
|
new_query.erase(pos, s.length()); |
|
|
} |
|
|
} |
|
|
std::replace(new_query.begin(), new_query.end(), '-', ' '); |
|
|
new_query = ReplaceAll(new_query, std::string("first level"), std::string("1")); |
|
|
new_query = ReplaceAll(new_query, std::string("second level"), std::string("2")); |
|
|
new_query = ReplaceAll(new_query, std::string("third level"), std::string("3")); |
|
|
new_query = ReplaceAll(new_query, std::string("fourth level"), std::string("4")); |
|
|
new_query = ReplaceAll(new_query, std::string("fifth level"), std::string("5")); |
|
|
new_query = ReplaceAll(new_query, std::string("sixth level"), std::string("6")); |
|
|
new_query = ReplaceAll(new_query, std::string("seventh level"), std::string("7")); |
|
|
new_query = ReplaceAll(new_query, std::string("eighth level"), std::string("8")); |
|
|
|
|
|
|
|
|
if (verbose) { |
|
|
std::cerr << "[DEBUG] new_query: " << new_query << std::endl; |
|
|
} |
|
|
|
|
|
json keywords = get_keywords(new_query); |
|
|
if (verbose) { |
|
|
std::cerr << "[DEBUG] keywords: " << keywords.dump() << std::endl; |
|
|
} |
|
|
|
|
|
json func_tmp = json::parse(func_tmp_str); |
|
|
|
|
|
std::set<std::string> set_keywords; |
|
|
for (const auto& kw : keywords["area_id"]) { |
|
|
set_keywords.insert(kw.get<std::string>()); |
|
|
} |
|
|
|
|
|
if (!keywords["area_id"].empty()) { |
|
|
std::string area_kw = find_longest_string(keywords["area_id"]); |
|
|
if (verbose) { |
|
|
std::cerr << "[DEBUG] area_kw: " << area_kw << std::endl; |
|
|
} |
|
|
if (pred_class.find("SLIDING_DOOR") != std::string::npos) { |
|
|
if (set_keywords.count("左邊") || set_keywords.count("左側") || set_keywords.count("左") || set_keywords.count("left")) { |
|
|
func_tmp["areaId"] = NL2area["左邊"]; |
|
|
} else if (set_keywords.count("右邊") || set_keywords.count("右側") || set_keywords.count("右") || set_keywords.count("right")) { |
|
|
func_tmp["areaId"] = NL2area["右邊"]; |
|
|
} |
|
|
} else if (pred_class.find("HVAC_DEFROSTER") != std::string::npos) { |
|
|
if (set_keywords.count("前除霜") || set_keywords.count("front defroster")) { |
|
|
func_tmp["areaId"] = NL2area["前除霜"]; |
|
|
} else if (set_keywords.count("後除霜") || set_keywords.count("rear defroster")) { |
|
|
func_tmp["areaId"] = NL2area["後除霜"]; |
|
|
} |
|
|
} else if (pred_class.find("POWER_SUNSHADE") != std::string::npos) { |
|
|
if (set_keywords.count("頂棚") || set_keywords.count("roof")) { |
|
|
func_tmp["areaId"] = NL2area["頂棚"]; |
|
|
} else if (set_keywords.count("右邊") || set_keywords.count("右側") || set_keywords.count("右") || set_keywords.count("right")) { |
|
|
func_tmp["areaId"] = "SEAT_ROW_2_RIGHT"; |
|
|
} else if (set_keywords.count("左邊") || set_keywords.count("左側") || set_keywords.count("左") || set_keywords.count("left")) { |
|
|
func_tmp["areaId"] = "SEAT_ROW_2_LEFT"; |
|
|
} |
|
|
} |
|
|
bool is_uncommon = false; |
|
|
for (const auto& uc_kw : uncommon_area_NL) { |
|
|
if (area_kw == uc_kw) { |
|
|
is_uncommon = true; |
|
|
break; |
|
|
} |
|
|
} |
|
|
if (!is_uncommon) { |
|
|
if (NL2area.count(area_kw) && func_tmp["areaId"]=="") { |
|
|
func_tmp["areaId"] = NL2area[area_kw]; |
|
|
} |
|
|
} |
|
|
if (func_tmp["areaId"]=="SEAT_ROW_1" || func_tmp["areaId"]=="SEAT_ROW_2" || func_tmp["areaId"]=="SEAT_ROW_3"){ |
|
|
if (new_query.find("left") != std::string::npos){ |
|
|
func_tmp["areaId"] = std::string(func_tmp["areaId"])+"_LEFT"; |
|
|
} |
|
|
else if (new_query.find("right") != std::string::npos){ |
|
|
func_tmp["areaId"] = std::string(func_tmp["areaId"])+"_RIGHT"; |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (!keywords["num"].empty() && func_tmp.count("value") && func_tmp["value"].is_string() && func_tmp["value"].get<std::string>() == "") { |
|
|
func_tmp["value"] = keywords["num"][0].get<std::string>(); |
|
|
} else if (!keywords["level"].empty() && func_tmp.count("value") && func_tmp["value"].is_string() && func_tmp["value"].get<std::string>() == "" && maxmin_val_map.count(ori_func_name)) { |
|
|
for (auto &m:max_level_keys){ |
|
|
if(std::find(keywords["level"].begin(), keywords["level"].end(), m) != keywords["level"].end()) |
|
|
func_tmp["value"] = maxmin_val_map[ori_func_name]["max"]; |
|
|
} |
|
|
for (auto &m:min_level_keys) { |
|
|
if(std::find(keywords["level"].begin(), keywords["level"].end(), m) != keywords["level"].end()) |
|
|
func_tmp["value"] = maxmin_val_map[ori_func_name]["min"]; |
|
|
} |
|
|
} else if (!keywords["switch"].empty() && ori_func_name == "POWER_SUNSHADE" && func_tmp.count("value") && func_tmp["value"].is_string() && func_tmp["value"].get<std::string>() == "") { |
|
|
bool open_found = false; |
|
|
bool close_found = false; |
|
|
for (const auto& op : keywords["switch"]) { |
|
|
if (st_open.count(op)) open_found = true; |
|
|
if (st_close.count(op)) close_found = true; |
|
|
} |
|
|
if (open_found && new_query.find("開大") == std::string::npos) { |
|
|
func_tmp["value"] = "100"; |
|
|
} else if (close_found && new_query.find("關小") == std::string::npos) { |
|
|
func_tmp["value"] = "0"; |
|
|
} |
|
|
} |
|
|
|
|
|
if (func_tmp.count("value") && func_tmp["value"].is_string() && func_tmp["value"].get<std::string>() == "") { |
|
|
if (pred_class.find("increas") != std::string::npos || pred_class.find("decreas") != std::string::npos || pred_class.find("reduc") != std::string::npos || pred_class.find("reduc") != std::string::npos) { |
|
|
func_tmp["value"] = "1"; |
|
|
} else if (ori_func_name == "HVAC_TEMPERATURE_SET") { |
|
|
if (new_query.find("熱") != std::string::npos || new_query.find("hot") != std::string::npos) { |
|
|
func_tmp["value"] = maxmin_val_map[ori_func_name]["min"]; |
|
|
} else if (new_query.find("冷") != std::string::npos || new_query.find("凍") != std::string::npos || new_query.find("cold") != std::string::npos) { |
|
|
func_tmp["value"] = maxmin_val_map[ori_func_name]["max"]; |
|
|
} |
|
|
} else if (default_value.count(ori_func_name)) { |
|
|
func_tmp["value"] = default_value[ori_func_name]; |
|
|
} |
|
|
} |
|
|
|
|
|
json final_json; |
|
|
if (ori_func_name == "set_seat_mode") { |
|
|
final_json.push_back({{"name", ori_func_name}, {"arguments", func_tmp}}); |
|
|
} else if (ori_func_name == "get_hhtd_info" || ori_func_name == "get_vehicle_info") { |
|
|
func_tmp["query"] = ori_query; |
|
|
final_json.push_back({{"name", ori_func_name}, {"arguments", func_tmp}}); |
|
|
} else { |
|
|
final_json.push_back({{"name", "control_car_properties"}, {"arguments", func_tmp}}); |
|
|
} |
|
|
|
|
|
std::string result = final_json.dump(4); |
|
|
if (verbose) { |
|
|
std::cerr << "[DEBUG] Final output: " << result << std::endl; |
|
|
} |
|
|
|
|
|
return result; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
extern "C" { |
|
|
const char* postprocess_c(const char* query_c, const char* pred_class_c) { |
|
|
static Postprocessor processor; |
|
|
static bool data_loaded = false; |
|
|
|
|
|
|
|
|
if (!data_loaded) { |
|
|
processor.load_data(); |
|
|
data_loaded = true; |
|
|
} |
|
|
|
|
|
std::string query(query_c); |
|
|
std::string pred_class(pred_class_c); |
|
|
std::string result = processor.postprocess(query, pred_class); |
|
|
|
|
|
char* c_str = new char[result.length() + 1]; |
|
|
if (c_str == nullptr) { |
|
|
std::cerr << "ERROR: Memory allocation failed in postprocess_c." << std::endl; |
|
|
return nullptr; |
|
|
} |
|
|
std::copy(result.begin(), result.end(), c_str); |
|
|
c_str[result.length()] = '\0'; |
|
|
|
|
|
return c_str; |
|
|
} |
|
|
} |
|
|
|