Skip to content

Commit

Permalink
修复崩溃的Bug,增加余额查询
Browse files Browse the repository at this point in the history
  • Loading branch information
NGLSG committed Jun 6, 2023
1 parent 504c494 commit 2ef638b
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 9 deletions.
95 changes: 92 additions & 3 deletions include/ChatBot.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ namespace Role {
static std::string Assistant = "assistant";
};

struct Billing {
float total = -1;
float available = -1;
float used = -1;
long long date = -1;
};

class ChatBot {
public:
ChatBot(const OpenAIData &chat_data);
Expand All @@ -31,6 +38,79 @@ class ChatBot {

void Add(std::string name);

Billing GetBilling() {
std::string url;
Billing billing;

if (!chat_data_.useWebProxy) {
url = "https://api.openai.com/";
if (!chat_data_.proxy.empty()) {
session.SetProxies(cpr::Proxies{
{"http", chat_data_.proxy},
{"https", chat_data_.proxy}
});
}
} else {
url = WebProxies[chat_data_.webproxy];
}

auto t1 = std::async(std::launch::async, [&] { // execute the first API request asynchronously
cpr::Session session;
session.SetUrl(cpr::Url{url + "v1/dashboard/billing/subscription"});
session.SetHeader(cpr::Header{
{"Authorization", "Bearer " + chat_data_.api_key},
});
session.SetVerifySsl(cpr::VerifySsl{false});

auto response = session.Get();
if (response.status_code != 200) {
LogError("OpenAI Error: Request failed with status code " + std::to_string(response.status_code));
return;
}

json data = json::parse(response.text);
billing.total = data["system_hard_limit_usd"];
billing.date = data["access_until"];
});

auto t2 = std::async(std::launch::async, [&] { // execute the second API request asynchronously
cpr::Session session;
string start = Stamp2Time(getTimestampBefore(100));
string end = Stamp2Time(getCurrentTimestamp());
url = url + "v1/dashboard/billing/usage?start_date=" + start + "&end_date=" + end;
session.SetUrl(cpr::Url{url});
session.SetHeader(cpr::Header{
{"Authorization", "Bearer " + chat_data_.api_key}
});
session.SetVerifySsl(cpr::VerifySsl{false});

auto response = session.Get();
if (response.status_code != 200) {
LogError("OpenAI Error: Request failed with status code " + std::to_string(response.status_code));
return;
}

json data = json::parse(response.text);
billing.used = float(data["total_usage"]) / 100;
billing.available = billing.total - billing.used;
});

t1.wait(); // wait for both tasks to finish
t2.wait();

return billing;
}

std::string Stamp2Time(long long timestamp) {
time_t tick = (time_t) (timestamp / 1000);//转换时间
struct tm tm;
char s[40];
tm = *localtime(&tick);
strftime(s, sizeof(s), "%Y-%m-%d", &tm);
std::string str(s);
return str;
}

json history;

private:
Expand All @@ -45,18 +125,27 @@ class ChatBot {
const std::string sys = "You are ChatGPT, a large language model trained by OpenAI. Respond conversationally";
const std::string suffix = ".dat";
const std::vector<std::string> WebProxies{"https://nglsg.ml/",
"https://service-n535eyti-1306800451.sg.apigw.tencentcs.com/"};
"https://service-hbv9ql2m-1306800451.sg.apigw.tencentcs.com/"};
json LastHistory;
json defaultJson;

bool IsSaved() {
return LastHistory == history;
}

string sendRequest(std::string data);
long long getCurrentTimestamp() {
auto currentTime = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(currentTime.time_since_epoch()).count();
}

long long getTimestampBefore(const int daysBefore) {
auto currentTime = std::chrono::system_clock::now();
auto days = std::chrono::hours(24 * daysBefore);
auto targetTime = currentTime - days;
return std::chrono::duration_cast<std::chrono::milliseconds>(targetTime.time_since_epoch()).count();
}

string sendRequest(std::string data);
};


#endif
2 changes: 1 addition & 1 deletion include/VoiceToText.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class VoiceToText {

private:
const std::vector<std::string> WebProxies{"https://nglsg.ml/",
"https://service-n535eyti-1306800451.sg.apigw.tencentcs.com/"};
"https://service-hbv9ql2m-1306800451.sg.apigw.tencentcs.com/"};
cpr::Session session;
OpenAIData _voiceData;
};
Expand Down
8 changes: 8 additions & 0 deletions include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class UEncrypt {
static std::string GetMD5(const std::string &str);

static std::string GetMD5(const void *data, std::size_t size);

static std::string md5(const std::string& data);

};

class UCompression {
Expand Down Expand Up @@ -145,6 +148,11 @@ class Utils {

static std::string Stamp2Time(long long timestamp) { return Logger::Stamp2Time(timestamp); }

static int Stamp2Day(long long timestamp) {
return timestamp / 86400000;
}


};

#endif
52 changes: 48 additions & 4 deletions sample/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Application::Application(const OpenAIData &chat_data, const TranslateData &data,
}
translator = CreateRef<Translate>(data);
bot = CreateRef<ChatBot>(chat_data);
billing = bot->GetBilling();
voiceToText = CreateRef<VoiceToText>(chat_data);
listener = CreateRef<Listener>(sampleRate, framesPerBuffer);
vitsData = VitsData;
Expand All @@ -36,6 +37,7 @@ Application::Application(const Configure &configure, bool setting) {
}
translator = CreateRef<Translate>(configure.baiDuTranslator);
bot = CreateRef<ChatBot>(configure.openAi);
billing = bot->GetBilling();
voiceToText = CreateRef<VoiceToText>(configure.openAi);
listener = CreateRef<Listener>(sampleRate, framesPerBuffer);
vitsData = configure.vits;
Expand Down Expand Up @@ -117,11 +119,14 @@ void Application::render_code_box() {

static bool show_codes = false;
for (auto &it: codes) {

show_codes = ImGui::CollapsingHeader(it.first.c_str());
if (show_codes) {
for (const auto &code: it.second) {
if (ImGui::Button(code.c_str(), ImVec2(-1, 0))) {
glfwSetClipboardString(nullptr, code.c_str());
if (!is_valid_text(code)) {
if (ImGui::Button(code.c_str(), ImVec2(-1, 0))) {
glfwSetClipboardString(nullptr, code.c_str());
}
}
}
}
Expand Down Expand Up @@ -458,13 +463,50 @@ void Application::render_input_box() {
ImGui::Begin("Input filed", NULL,
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_NoTitleBar);
ImGui::BeginGroup();
// 设置子窗口的背景颜色为浅灰色
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
// 设置子窗口的圆角半径为10像素
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
// 创建一个子窗口,注意要设置大小和标志
// 大小要和你的控件一致,标志要去掉边框和滚动条
ImGui::BeginChild("background", ImVec2(500, 20), false,
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse |
ImGuiWindowFlags_NoDecoration);
// 恢复默认的样式
ImGui::PopStyleColor();
ImGui::PopStyleVar();
// 显示你的控件
ImGui::SameLine();
ImGui::Text(reinterpret_cast<const char *>(u8"总额: %.2f"), billing.total);
ImGui::SameLine();
ImGui::Text(reinterpret_cast<const char *>(u8"可用: %.2f"), billing.available);
ImGui::SameLine();
ImGui::Text(reinterpret_cast<const char *>(u8"剩余: %d 天"),
Utils::Stamp2Day(billing.date * 1000 - Utils::getCurrentTimestamp()));
ImGui::SameLine();
// 设置进度条的背景颜色为透明
ImGui::PushStyleColor(ImGuiCol_PlotHistogramHovered, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
// 设置进度条的前景颜色为白色
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(1.00f, 1.0f, 1.0f, 1.0f));
// 设置进度条的圆角半径为10像素
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f);
// 显示进度条,注意要设置frame_padding为-1,否则会有边框
ImGui::ProgressBar(billing.used / billing.total, ImVec2(100, 20), NULL);
// 恢复默认的样式
ImGui::PopStyleVar();
ImGui::PopStyleColor(2);
// 结束子窗口
ImGui::EndChild();
ImGui::EndGroup();

ImVec2 size(50, 0);
ImGui::SameLine(ImGui::GetWindowWidth() - size.x - 10);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.85f, 0.85f, 0.85f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.9f, 0.9f, 0.9f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 5.0f);
ImGui::Text("%d", strlen(last_input.c_str()));
token = countTokens(input_buffer);
ImGui::Text(reinterpret_cast<const char *>(u8"字符数: %d"), token);
ImGui::PopStyleVar();
ImGui::PopStyleColor(3);
}
Expand Down Expand Up @@ -514,6 +556,8 @@ void Application::render_input_box() {
codetype = i.substr(0, pos);
i = i.substr(pos + 1); // 删除第一行
}
if (is_valid_text(codetype))
codetype = "Unknown";
if (codes.contains(codetype)) {
codes[codetype].emplace_back(i);
} else {
Expand Down
109 changes: 108 additions & 1 deletion sample/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include "utils.h"

#define TEXT_BUFFER 1024
const std::string VERSION = reinterpret_cast<const char *>(u8"Listener v1.1");
const std::string VERSION = reinterpret_cast<const char *>(u8"Listener v1.2");

enum State {
OK = 0,
Expand Down Expand Up @@ -78,6 +78,7 @@ class Application {
int role_id = 0;
int Rnum = 0;
int selected_dir = 0;
int token;

char input_buffer[4096 * 32];
char api_buffer[4096];
Expand Down Expand Up @@ -153,6 +154,112 @@ class Application {
return text.empty() || text == "";
}

int countTokens(const std::string& str)
{
// 单一字符的token数量,包括回车
const int singleCharTokenCount = 1;

// 按照中文、英文、数字、特殊字符、emojis将字符串分割
std::vector<std::string> tokens;
std::string token;

for (char c : str)
{
if ((c >= 0 && c <= 127) || (c >= -64 && c <= -33))
{
// 遇到ASCII码或者中文字符的第一个部分,加入前一个token
if (!token.empty())
{
tokens.push_back(token);
token.clear();
}

// 加入当前字符所对应的token数量,根据字节数判断是否是中文字符
if ((c >= 0 && c <= 127) || c == '\n')
{
tokens.push_back(std::string(singleCharTokenCount, c));
}
else
{
tokens.push_back(std::string(2, c));
}
}
else if (c >= -128 && c <= -65)
{
// 中文字符第二个部分,加入前一个token
if (!token.empty())
{
tokens.push_back(token);
token.clear();
}

// 加入当前字符所对应的token数量
token = std::string(2, c);
tokens.push_back(token);
token.clear();
}
else if ((c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z'))
{
// 数字或者字母的一段,加入前一个token
if (token.empty())
{
token += c;
}
else if (isdigit(c) == isdigit(token[0]))
{
token += c;
}
else
{
tokens.push_back(token);
token = c;
}
}
else
{
// 特殊字符或者emoji等,加入前一个token
if (!token.empty())
{
tokens.push_back(token);
token.clear();
}

// 根据不同类型的字符加入当前字符所对应的token数量
if (c == '\n')
{
tokens.push_back(std::string(singleCharTokenCount, c));
}
else if (c == 0xF0)
{
tokens.push_back(std::string(6, ' '));
}
else if (c == '[' || c == ']')
{
tokens.push_back(std::string(singleCharTokenCount, c));
}
else if (c == ' ' || c == '\t' || c == '.' || c == ',' || c == ';' || c == ':' || c == '!' || c == '?' || c == '(' || c == ')' || c == '{' || c == '}' || c == '/' || c == '\\' || c == '+' || c == '-' || c == '*' || c == '=' || c == '<' || c == '>' || c == '|' || c == '&' || c == '^' || c == '%' || c == '$' || c == '#' || c == '@')
{
tokens.push_back(std::string(singleCharTokenCount, c));
}
else
{
tokens.push_back(std::string(singleCharTokenCount, c));
}
}
}

// 加入最后一个token
if (!token.empty())
{
tokens.push_back(token);
}

return tokens.size();
}

Billing billing;
public:
std::string WhisperConvertor(const std::string &file);

Expand Down
Loading

0 comments on commit 2ef638b

Please sign in to comment.