cactus-react-native 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +573 -13
- package/android/CMakeLists.txt +4 -3
- package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusFileSystem.kt +21 -4
- package/android/src/main/jniLibs/arm64-v8a/libcactus.a +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libcactus_util.a +0 -0
- package/cpp/HybridCactus.cpp +112 -19
- package/cpp/HybridCactus.hpp +12 -3
- package/cpp/HybridCactusIndex.cpp +325 -0
- package/cpp/HybridCactusIndex.hpp +43 -0
- package/cpp/HybridCactusUtil.cpp +3 -3
- package/cpp/HybridCactusUtil.hpp +2 -1
- package/cpp/cactus_ffi.h +83 -2
- package/cpp/cactus_util.h +1 -1
- package/ios/HybridCactusFileSystem.swift +23 -2
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus.h +2 -0
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +83 -2
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_telemetry.h +656 -0
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/{ffi_utils.h → cactus_utils.h} +104 -17
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/engine.h +117 -7
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/graph.h +91 -5
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel.h +15 -6
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/Info.plist +0 -0
- package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus.h +2 -0
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_ffi.h +83 -2
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_telemetry.h +656 -0
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/{ffi_utils.h → cactus_utils.h} +104 -17
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/engine.h +117 -7
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/graph.h +91 -5
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel.h +15 -6
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Info.plist +0 -0
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/_CodeSignature/CodeResources +1 -1
- package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/cactus +0 -0
- package/ios/cactus_util.xcframework/Info.plist +4 -4
- package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/cactus_util.h +1 -1
- package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/database.h +27 -0
- package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Info.plist +0 -0
- package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/cactus_util +0 -0
- package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/cactus_util.h +1 -1
- package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/database.h +27 -0
- package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Info.plist +0 -0
- package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/_CodeSignature/CodeResources +3 -3
- package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/cactus_util +0 -0
- package/lib/module/api/Database.js +57 -3
- package/lib/module/api/Database.js.map +1 -1
- package/lib/module/classes/CactusIndex.js +45 -0
- package/lib/module/classes/CactusIndex.js.map +1 -0
- package/lib/module/classes/CactusLM.js +35 -10
- package/lib/module/classes/CactusLM.js.map +1 -1
- package/lib/module/classes/CactusSTT.js +20 -12
- package/lib/module/classes/CactusSTT.js.map +1 -1
- package/lib/module/config/CactusConfig.js +2 -0
- package/lib/module/config/CactusConfig.js.map +1 -1
- package/lib/module/constants/packageVersion.js +1 -1
- package/lib/module/hooks/useCactusIndex.js +175 -0
- package/lib/module/hooks/useCactusIndex.js.map +1 -0
- package/lib/module/hooks/useCactusLM.js +54 -2
- package/lib/module/hooks/useCactusLM.js.map +1 -1
- package/lib/module/hooks/useCactusSTT.js +2 -2
- package/lib/module/hooks/useCactusSTT.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/native/Cactus.js +21 -5
- package/lib/module/native/Cactus.js.map +1 -1
- package/lib/module/native/CactusFileSystem.js +3 -0
- package/lib/module/native/CactusFileSystem.js.map +1 -1
- package/lib/module/native/CactusIndex.js +32 -0
- package/lib/module/native/CactusIndex.js.map +1 -0
- package/lib/module/native/CactusUtil.js +16 -3
- package/lib/module/native/CactusUtil.js.map +1 -1
- package/lib/module/native/index.js +1 -0
- package/lib/module/native/index.js.map +1 -1
- package/lib/module/specs/CactusIndex.nitro.js +4 -0
- package/lib/module/specs/CactusIndex.nitro.js.map +1 -0
- package/lib/module/telemetry/Telemetry.js +3 -1
- package/lib/module/telemetry/Telemetry.js.map +1 -1
- package/lib/module/types/CactusIndex.js +2 -0
- package/lib/module/types/CactusIndex.js.map +1 -0
- package/lib/module/types/CactusSTTModel.js +2 -0
- package/lib/module/types/CactusSTTModel.js.map +1 -0
- package/lib/typescript/src/api/Database.d.ts +7 -1
- package/lib/typescript/src/api/Database.d.ts.map +1 -1
- package/lib/typescript/src/classes/CactusIndex.d.ts +15 -0
- package/lib/typescript/src/classes/CactusIndex.d.ts.map +1 -0
- package/lib/typescript/src/classes/CactusLM.d.ts +5 -3
- package/lib/typescript/src/classes/CactusLM.d.ts.map +1 -1
- package/lib/typescript/src/classes/CactusSTT.d.ts +4 -4
- package/lib/typescript/src/classes/CactusSTT.d.ts.map +1 -1
- package/lib/typescript/src/config/CactusConfig.d.ts +1 -0
- package/lib/typescript/src/config/CactusConfig.d.ts.map +1 -1
- package/lib/typescript/src/constants/packageVersion.d.ts +1 -1
- package/lib/typescript/src/hooks/useCactusIndex.d.ts +14 -0
- package/lib/typescript/src/hooks/useCactusIndex.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useCactusLM.d.ts +4 -2
- package/lib/typescript/src/hooks/useCactusLM.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useCactusSTT.d.ts +3 -3
- package/lib/typescript/src/hooks/useCactusSTT.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +5 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native/Cactus.d.ts +4 -2
- package/lib/typescript/src/native/Cactus.d.ts.map +1 -1
- package/lib/typescript/src/native/CactusFileSystem.d.ts +1 -0
- package/lib/typescript/src/native/CactusFileSystem.d.ts.map +1 -1
- package/lib/typescript/src/native/CactusIndex.d.ts +12 -0
- package/lib/typescript/src/native/CactusIndex.d.ts.map +1 -0
- package/lib/typescript/src/native/CactusUtil.d.ts.map +1 -1
- package/lib/typescript/src/native/index.d.ts +1 -0
- package/lib/typescript/src/native/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/Cactus.nitro.d.ts +4 -2
- package/lib/typescript/src/specs/Cactus.nitro.d.ts.map +1 -1
- package/lib/typescript/src/specs/CactusFileSystem.nitro.d.ts +1 -0
- package/lib/typescript/src/specs/CactusFileSystem.nitro.d.ts.map +1 -1
- package/lib/typescript/src/specs/CactusIndex.nitro.d.ts +24 -0
- package/lib/typescript/src/specs/CactusIndex.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/CactusUtil.nitro.d.ts +1 -1
- package/lib/typescript/src/specs/CactusUtil.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types/CactusIndex.d.ts +34 -0
- package/lib/typescript/src/types/CactusIndex.d.ts.map +1 -0
- package/lib/typescript/src/types/CactusLM.d.ts +17 -0
- package/lib/typescript/src/types/CactusLM.d.ts.map +1 -1
- package/lib/typescript/src/types/CactusModel.d.ts +1 -0
- package/lib/typescript/src/types/CactusModel.d.ts.map +1 -1
- package/lib/typescript/src/types/CactusSTT.d.ts +1 -1
- package/lib/typescript/src/types/CactusSTT.d.ts.map +1 -1
- package/lib/typescript/src/types/CactusSTTModel.d.ts +8 -0
- package/lib/typescript/src/types/CactusSTTModel.d.ts.map +1 -0
- package/nitro.json +3 -0
- package/nitrogen/generated/android/c++/JDeviceInfo.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_double.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.cpp +1 -1
- package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.cpp +1 -1
- package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridCactusFileSystemSpec.cpp +17 -1
- package/nitrogen/generated/android/c++/JHybridCactusFileSystemSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridCactusImageSpec.cpp +1 -1
- package/nitrogen/generated/android/c++/JHybridCactusImageSpec.hpp +1 -1
- package/nitrogen/generated/android/cactus+autolinking.cmake +2 -1
- package/nitrogen/generated/android/cactus+autolinking.gradle +1 -1
- package/nitrogen/generated/android/cactusOnLoad.cpp +11 -1
- package/nitrogen/generated/android/cactusOnLoad.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/DeviceInfo.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/Func_void_double.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusCryptoSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusDeviceInfoSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusFileSystemSpec.kt +5 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusImageSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/cactusOnLoad.kt +1 -1
- package/nitrogen/generated/ios/Cactus+autolinking.rb +1 -1
- package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.cpp +1 -1
- package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.hpp +1 -1
- package/nitrogen/generated/ios/Cactus-Swift-Cxx-Umbrella.hpp +1 -1
- package/nitrogen/generated/ios/CactusAutolinking.mm +11 -1
- package/nitrogen/generated/ios/CactusAutolinking.swift +1 -1
- package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/c++/HybridCactusFileSystemSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridCactusFileSystemSpecSwift.hpp +9 -1
- package/nitrogen/generated/ios/c++/HybridCactusImageSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridCactusImageSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/swift/DeviceInfo.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_DeviceInfo.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_double.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec_cxx.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec_cxx.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCactusFileSystemSpec.swift +2 -1
- package/nitrogen/generated/ios/swift/HybridCactusFileSystemSpec_cxx.swift +20 -1
- package/nitrogen/generated/ios/swift/HybridCactusImageSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCactusImageSpec_cxx.swift +1 -1
- package/nitrogen/generated/shared/c++/CactusIndexGetResult.hpp +84 -0
- package/nitrogen/generated/shared/c++/CactusIndexQueryResult.hpp +79 -0
- package/nitrogen/generated/shared/c++/DeviceInfo.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusFileSystemSpec.cpp +2 -1
- package/nitrogen/generated/shared/c++/HybridCactusFileSystemSpec.hpp +2 -1
- package/nitrogen/generated/shared/c++/HybridCactusImageSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusImageSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusIndexSpec.cpp +27 -0
- package/nitrogen/generated/shared/c++/HybridCactusIndexSpec.hpp +76 -0
- package/nitrogen/generated/shared/c++/HybridCactusSpec.cpp +3 -1
- package/nitrogen/generated/shared/c++/HybridCactusSpec.hpp +6 -3
- package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.hpp +2 -2
- package/package.json +2 -2
- package/src/api/Database.ts +80 -2
- package/src/classes/CactusIndex.ts +58 -0
- package/src/classes/CactusLM.ts +41 -11
- package/src/classes/CactusSTT.ts +24 -16
- package/src/config/CactusConfig.ts +3 -0
- package/src/constants/packageVersion.ts +1 -1
- package/src/hooks/useCactusIndex.ts +195 -0
- package/src/hooks/useCactusLM.ts +63 -3
- package/src/hooks/useCactusSTT.ts +4 -4
- package/src/index.tsx +17 -0
- package/src/native/Cactus.ts +39 -4
- package/src/native/CactusFileSystem.ts +4 -0
- package/src/native/CactusIndex.ts +54 -0
- package/src/native/CactusUtil.ts +19 -3
- package/src/native/index.ts +1 -0
- package/src/specs/Cactus.nitro.ts +13 -2
- package/src/specs/CactusFileSystem.nitro.ts +2 -0
- package/src/specs/CactusIndex.nitro.ts +31 -0
- package/src/specs/CactusUtil.nitro.ts +1 -1
- package/src/telemetry/Telemetry.ts +1 -1
- package/src/types/CactusIndex.ts +40 -0
- package/src/types/CactusLM.ts +21 -0
- package/src/types/CactusModel.ts +1 -0
- package/src/types/CactusSTT.ts +1 -1
- package/src/types/CactusSTTModel.ts +10 -0
- package/android/src/main/jniLibs/arm64-v8a/libcactus_util.so +0 -0
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
#ifndef CACTUS_TELEMETRY_H
|
|
2
|
+
#define CACTUS_TELEMETRY_H
|
|
3
|
+
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <thread>
|
|
6
|
+
#include <sstream>
|
|
7
|
+
#include <iostream>
|
|
8
|
+
#include <chrono>
|
|
9
|
+
#include <mutex>
|
|
10
|
+
#include <map>
|
|
11
|
+
#include <iomanip>
|
|
12
|
+
#include <ctime>
|
|
13
|
+
#include <fstream>
|
|
14
|
+
#include <sys/stat.h>
|
|
15
|
+
#include "cactus_utils.h"
|
|
16
|
+
|
|
17
|
+
#if defined(__APPLE__)
|
|
18
|
+
#include <TargetConditionals.h>
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
#if defined(__APPLE__) && (!TARGET_OS_IPHONE) && !defined(__ANDROID__)
|
|
22
|
+
#define CACTUS_TELEMETRY_ENABLED
|
|
23
|
+
#include <curl/curl.h>
|
|
24
|
+
#include <sys/utsname.h>
|
|
25
|
+
#include <unistd.h>
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
namespace cactus {
|
|
29
|
+
namespace ffi {
|
|
30
|
+
|
|
31
|
+
enum class TelemetryEventType {
|
|
32
|
+
Init,
|
|
33
|
+
Completion,
|
|
34
|
+
Embedding,
|
|
35
|
+
Transcription
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
struct TelemetryMetrics {
|
|
39
|
+
TelemetryEventType event_type;
|
|
40
|
+
std::string model;
|
|
41
|
+
|
|
42
|
+
double ttft_ms = 0.0;
|
|
43
|
+
double tps = 0.0;
|
|
44
|
+
double response_time_ms = 0.0;
|
|
45
|
+
int tokens = 0;
|
|
46
|
+
|
|
47
|
+
bool success = false;
|
|
48
|
+
std::string message;
|
|
49
|
+
|
|
50
|
+
std::chrono::system_clock::time_point timestamp;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class HttpClient {
|
|
55
|
+
public:
|
|
56
|
+
struct Response {
|
|
57
|
+
bool success;
|
|
58
|
+
int status_code;
|
|
59
|
+
std::string body;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
static Response postJson(
|
|
63
|
+
const std::string& url,
|
|
64
|
+
const std::map<std::string, std::string>& headers,
|
|
65
|
+
const std::string& json_body
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
private:
|
|
69
|
+
static size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
inline size_t HttpClient::writeCallback(void* contents, size_t size, size_t nmemb, void* userp) {
|
|
73
|
+
size_t totalSize = size * nmemb;
|
|
74
|
+
std::string* response = static_cast<std::string*>(userp);
|
|
75
|
+
response->append(static_cast<char*>(contents), totalSize);
|
|
76
|
+
return totalSize;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
inline HttpClient::Response HttpClient::postJson(
|
|
80
|
+
[[maybe_unused]] const std::string& url,
|
|
81
|
+
[[maybe_unused]] const std::map<std::string, std::string>& headers,
|
|
82
|
+
[[maybe_unused]] const std::string& json_body
|
|
83
|
+
) {
|
|
84
|
+
#ifdef CACTUS_TELEMETRY_ENABLED
|
|
85
|
+
Response response;
|
|
86
|
+
response.success = false;
|
|
87
|
+
response.status_code = 0;
|
|
88
|
+
|
|
89
|
+
CURL* curl = curl_easy_init();
|
|
90
|
+
if (!curl) {
|
|
91
|
+
return response;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
|
95
|
+
|
|
96
|
+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
|
97
|
+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
|
98
|
+
|
|
99
|
+
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
|
100
|
+
|
|
101
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
|
|
102
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json_body.length());
|
|
103
|
+
|
|
104
|
+
struct curl_slist* header_list = nullptr;
|
|
105
|
+
for (const auto& header : headers) {
|
|
106
|
+
std::string header_str = header.first + ": " + header.second;
|
|
107
|
+
header_list = curl_slist_append(header_list, header_str.c_str());
|
|
108
|
+
}
|
|
109
|
+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
|
|
110
|
+
|
|
111
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
|
|
112
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response.body);
|
|
113
|
+
|
|
114
|
+
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
|
|
115
|
+
|
|
116
|
+
CURLcode res = curl_easy_perform(curl);
|
|
117
|
+
|
|
118
|
+
if (res == CURLE_OK) {
|
|
119
|
+
long response_code = 0;
|
|
120
|
+
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
|
121
|
+
response.status_code = static_cast<int>(response_code);
|
|
122
|
+
response.success = (response_code >= 200 && response_code < 300);
|
|
123
|
+
|
|
124
|
+
if (!response.success && !response.body.empty()) {
|
|
125
|
+
std::cerr << "[Telemetry] Response body: " << response.body << std::endl;
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
std::cerr << "[Telemetry] HTTP POST failed: " << curl_easy_strerror(res) << std::endl;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (header_list) {
|
|
132
|
+
curl_slist_free_all(header_list);
|
|
133
|
+
}
|
|
134
|
+
curl_easy_cleanup(curl);
|
|
135
|
+
|
|
136
|
+
return response;
|
|
137
|
+
#else
|
|
138
|
+
(void)url;
|
|
139
|
+
(void)headers;
|
|
140
|
+
(void)json_body;
|
|
141
|
+
Response response;
|
|
142
|
+
response.success = false;
|
|
143
|
+
response.status_code = 0;
|
|
144
|
+
return response;
|
|
145
|
+
#endif
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
class DeviceManager {
|
|
149
|
+
public:
|
|
150
|
+
static std::string getDeviceId();
|
|
151
|
+
static std::string getProjectId();
|
|
152
|
+
static std::map<std::string, std::string> getDeviceMetadata();
|
|
153
|
+
static std::string registerDevice(const std::string& device_id = "", const std::string& pro_key = "");
|
|
154
|
+
|
|
155
|
+
static void setProKey(const std::string& key);
|
|
156
|
+
static std::string getProKey();
|
|
157
|
+
|
|
158
|
+
private:
|
|
159
|
+
static std::string getConfigPath();
|
|
160
|
+
static std::map<std::string, std::string> readConfig();
|
|
161
|
+
static void writeConfig(const std::map<std::string, std::string>& config);
|
|
162
|
+
|
|
163
|
+
static std::string pro_key_;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
inline std::string DeviceManager::pro_key_ = "";
|
|
167
|
+
|
|
168
|
+
inline void DeviceManager::setProKey(const std::string& key) {
|
|
169
|
+
pro_key_ = key;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
inline std::string DeviceManager::getProKey() {
|
|
173
|
+
return pro_key_;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
inline std::string DeviceManager::getConfigPath() {
|
|
177
|
+
const char* home = getenv("HOME");
|
|
178
|
+
if (!home) {
|
|
179
|
+
home = "/tmp";
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
std::string cactus_dir = std::string(home) + "/.cactus";
|
|
183
|
+
|
|
184
|
+
mkdir(cactus_dir.c_str(), 0755);
|
|
185
|
+
|
|
186
|
+
return cactus_dir + "/telemetry_config.json";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
inline std::map<std::string, std::string> DeviceManager::readConfig() {
|
|
190
|
+
std::map<std::string, std::string> config;
|
|
191
|
+
std::string path = getConfigPath();
|
|
192
|
+
std::ifstream file(path);
|
|
193
|
+
|
|
194
|
+
if (file.is_open()) {
|
|
195
|
+
std::stringstream buffer;
|
|
196
|
+
buffer << file.rdbuf();
|
|
197
|
+
file.close();
|
|
198
|
+
|
|
199
|
+
std::string content = buffer.str();
|
|
200
|
+
|
|
201
|
+
const std::string project_id_key = "\"project_id\":\"";
|
|
202
|
+
size_t project_pos = content.find(project_id_key);
|
|
203
|
+
if (project_pos != std::string::npos) {
|
|
204
|
+
size_t start = project_pos + project_id_key.length();
|
|
205
|
+
size_t end = content.find("\"", start);
|
|
206
|
+
if (end != std::string::npos) {
|
|
207
|
+
config["project_id"] = content.substr(start, end - start);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return config;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
inline void DeviceManager::writeConfig(const std::map<std::string, std::string>& config) {
|
|
216
|
+
std::string path = getConfigPath();
|
|
217
|
+
std::ofstream file(path);
|
|
218
|
+
|
|
219
|
+
if (file.is_open()) {
|
|
220
|
+
file << "{\n";
|
|
221
|
+
|
|
222
|
+
auto device_it = config.find("device_id");
|
|
223
|
+
if (device_it != config.end()) {
|
|
224
|
+
file << " \"device_id\":\"" << device_it->second << "\"";
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
auto project_it = config.find("project_id");
|
|
228
|
+
if (project_it != config.end()) {
|
|
229
|
+
if (device_it != config.end()) {
|
|
230
|
+
file << ",\n";
|
|
231
|
+
}
|
|
232
|
+
file << " \"project_id\":\"" << project_it->second << "\"";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
file << "\n}\n";
|
|
236
|
+
file.close();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
inline std::string DeviceManager::getDeviceId() {
|
|
241
|
+
auto config = readConfig();
|
|
242
|
+
std::string pro_key = getProKey();
|
|
243
|
+
|
|
244
|
+
std::string project_id = config["project_id"];
|
|
245
|
+
if (project_id.empty()) {
|
|
246
|
+
project_id = generateUUID();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
config["project_id"] = project_id;
|
|
250
|
+
writeConfig(config);
|
|
251
|
+
|
|
252
|
+
const char* device_id_cstr = get_device_id(pro_key.c_str());
|
|
253
|
+
if (device_id_cstr != nullptr) {
|
|
254
|
+
std::string device_id = std::string(device_id_cstr);
|
|
255
|
+
size_t pipe_pos = device_id.find('|');
|
|
256
|
+
if (pipe_pos != std::string::npos) {
|
|
257
|
+
std::string device_part = device_id.substr(0, pipe_pos);
|
|
258
|
+
std::string pro_key_part = device_id.substr(pipe_pos + 1);
|
|
259
|
+
setProKey(pro_key_part);
|
|
260
|
+
return registerDevice(device_part, pro_key_part);
|
|
261
|
+
}
|
|
262
|
+
return device_id;
|
|
263
|
+
}
|
|
264
|
+
return registerDevice("", pro_key);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
inline std::string DeviceManager::getProjectId() {
|
|
268
|
+
auto config = readConfig();
|
|
269
|
+
std::string project_id = config["project_id"];
|
|
270
|
+
|
|
271
|
+
if (!project_id.empty()) {
|
|
272
|
+
return project_id;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
project_id = generateUUID();
|
|
276
|
+
std::cerr << "[Device Manager] Generated new project ID: " << project_id << std::endl;
|
|
277
|
+
|
|
278
|
+
config["project_id"] = project_id;
|
|
279
|
+
writeConfig(config);
|
|
280
|
+
|
|
281
|
+
return project_id;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
inline std::string DeviceManager::registerDevice(const std::string& device_id, const std::string& pro_key) {
|
|
285
|
+
#ifdef CACTUS_TELEMETRY_ENABLED
|
|
286
|
+
static const std::string SUPABASE_URL = "https://vlqqczxwyaodtcdmdmlw.supabase.co";
|
|
287
|
+
static const std::string SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZscXFjenh3eWFvZHRjZG1kbWx3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTE1MTg2MzIsImV4cCI6MjA2NzA5NDYzMn0.nBzqGuK9j6RZ6mOPWU2boAC_5H9XDs-fPpo5P3WZYbI";
|
|
288
|
+
|
|
289
|
+
auto metadata = getDeviceMetadata();
|
|
290
|
+
|
|
291
|
+
std::ostringstream json;
|
|
292
|
+
json << "{";
|
|
293
|
+
|
|
294
|
+
if (!device_id.empty()) {
|
|
295
|
+
json << "\"device_id\":\"" << generateUUID() << "\"";
|
|
296
|
+
} else {
|
|
297
|
+
json << "\"device_data\":{"
|
|
298
|
+
<< "\"model\":\"" << metadata["model"] << "\",";
|
|
299
|
+
json << "\"os\":\"" << metadata["os"] << "\",";
|
|
300
|
+
json << "\"os_version\":\"" << metadata["os_version"] << "\",";
|
|
301
|
+
json << "\"brand\":\"" << metadata["brand"] << "\"";
|
|
302
|
+
json << "}";
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
json << ",\"cactus_pro_key\":\"" << pro_key << "\"";
|
|
306
|
+
json << "}";
|
|
307
|
+
|
|
308
|
+
std::string payload = json.str();
|
|
309
|
+
|
|
310
|
+
std::map<std::string, std::string> headers;
|
|
311
|
+
headers["Content-Type"] = "application/json";
|
|
312
|
+
|
|
313
|
+
std::string url = SUPABASE_URL + "/functions/v1/device-registration";
|
|
314
|
+
|
|
315
|
+
auto response = HttpClient::postJson(url, headers, payload);
|
|
316
|
+
|
|
317
|
+
if (response.success && !response.body.empty()) {
|
|
318
|
+
const char* registered_id_cstr = register_app(response.body.c_str());
|
|
319
|
+
std::string registered_id = (registered_id_cstr && registered_id_cstr[0] != '\0')
|
|
320
|
+
? std::string(registered_id_cstr)
|
|
321
|
+
: std::string();
|
|
322
|
+
|
|
323
|
+
if (!registered_id.empty()) {
|
|
324
|
+
std::cerr << "[Device Registration] SUCCESS - Device registered!" << std::endl;
|
|
325
|
+
return registered_id;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
std::cerr << "[Device Registration] FAILED - Could not parse ID from response" << std::endl;
|
|
329
|
+
return "";
|
|
330
|
+
} else {
|
|
331
|
+
std::cerr << "[Device Registration] FAILED - Direct table insertion unsuccessful" << std::endl;
|
|
332
|
+
return "";
|
|
333
|
+
}
|
|
334
|
+
#else
|
|
335
|
+
return "";
|
|
336
|
+
#endif
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
inline std::map<std::string, std::string> DeviceManager::getDeviceMetadata() {
|
|
340
|
+
std::map<std::string, std::string> metadata;
|
|
341
|
+
|
|
342
|
+
#ifdef CACTUS_TELEMETRY_ENABLED
|
|
343
|
+
struct utsname system_info;
|
|
344
|
+
if (uname(&system_info) == 0) {
|
|
345
|
+
metadata["os"] = "macOS";
|
|
346
|
+
metadata["os_version"] = system_info.release;
|
|
347
|
+
metadata["architecture"] = system_info.machine;
|
|
348
|
+
metadata["model"] = system_info.machine;
|
|
349
|
+
metadata["brand"] = "apple";
|
|
350
|
+
}
|
|
351
|
+
#else
|
|
352
|
+
metadata["os"] = "unknown";
|
|
353
|
+
metadata["os_version"] = "unknown";
|
|
354
|
+
metadata["architecture"] = "unknown";
|
|
355
|
+
metadata["model"] = "unknown";
|
|
356
|
+
metadata["brand"] = "unknown";
|
|
357
|
+
#endif
|
|
358
|
+
|
|
359
|
+
return metadata;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
class LogRecord {
|
|
363
|
+
public:
|
|
364
|
+
static std::string buildJson(
|
|
365
|
+
const TelemetryMetrics& metrics,
|
|
366
|
+
const std::string& project_id,
|
|
367
|
+
const std::string& device_id,
|
|
368
|
+
const std::string& telemetry_token
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
private:
|
|
372
|
+
static std::string escapeJson(const std::string& input);
|
|
373
|
+
static std::string formatTimestamp(const std::chrono::system_clock::time_point& timestamp);
|
|
374
|
+
static std::string eventTypeToString(TelemetryEventType type);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
inline std::string LogRecord::escapeJson(const std::string& input) {
|
|
378
|
+
std::ostringstream output;
|
|
379
|
+
for (char c : input) {
|
|
380
|
+
switch (c) {
|
|
381
|
+
case '"': output << "\\\""; break;
|
|
382
|
+
case '\\': output << "\\\\"; break;
|
|
383
|
+
case '\b': output << "\\b"; break;
|
|
384
|
+
case '\f': output << "\\f"; break;
|
|
385
|
+
case '\n': output << "\\n"; break;
|
|
386
|
+
case '\r': output << "\\r"; break;
|
|
387
|
+
case '\t': output << "\\t"; break;
|
|
388
|
+
default:
|
|
389
|
+
if (static_cast<unsigned char>(c) < 0x20) {
|
|
390
|
+
output << "\\u" << std::hex << std::setw(4) << std::setfill('0')
|
|
391
|
+
<< static_cast<int>(c);
|
|
392
|
+
} else {
|
|
393
|
+
output << c;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return output.str();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
inline std::string LogRecord::formatTimestamp(const std::chrono::system_clock::time_point& timestamp) {
|
|
401
|
+
auto time_t = std::chrono::system_clock::to_time_t(timestamp);
|
|
402
|
+
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
403
|
+
timestamp.time_since_epoch()) % 1000;
|
|
404
|
+
|
|
405
|
+
std::tm tm;
|
|
406
|
+
#ifdef _WIN32
|
|
407
|
+
gmtime_s(&tm, &time_t);
|
|
408
|
+
#else
|
|
409
|
+
gmtime_r(&time_t, &tm);
|
|
410
|
+
#endif
|
|
411
|
+
|
|
412
|
+
std::ostringstream oss;
|
|
413
|
+
oss << std::put_time(&tm, "%Y-%m-%dT%H:%M:%S")
|
|
414
|
+
<< '.' << std::setfill('0') << std::setw(3) << ms.count() << 'Z';
|
|
415
|
+
return oss.str();
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
inline std::string LogRecord::eventTypeToString(TelemetryEventType type) {
|
|
419
|
+
switch (type) {
|
|
420
|
+
case TelemetryEventType::Init:
|
|
421
|
+
return "init";
|
|
422
|
+
case TelemetryEventType::Completion:
|
|
423
|
+
return "completion";
|
|
424
|
+
case TelemetryEventType::Embedding:
|
|
425
|
+
return "embedding";
|
|
426
|
+
case TelemetryEventType::Transcription:
|
|
427
|
+
return "transcription";
|
|
428
|
+
default:
|
|
429
|
+
return "unknown";
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
inline std::string LogRecord::buildJson(
|
|
434
|
+
const TelemetryMetrics& metrics,
|
|
435
|
+
const std::string& project_id,
|
|
436
|
+
const std::string& device_id,
|
|
437
|
+
const std::string& telemetry_token
|
|
438
|
+
) {
|
|
439
|
+
std::ostringstream json;
|
|
440
|
+
json << std::fixed << std::setprecision(2);
|
|
441
|
+
|
|
442
|
+
json << "{";
|
|
443
|
+
json << "\"event_type\":\"" << eventTypeToString(metrics.event_type) << "\",";
|
|
444
|
+
json << "\"model\":\"" << escapeJson(metrics.model) << "\",";
|
|
445
|
+
json << "\"success\":" << (metrics.success ? "true" : "false") << ",";
|
|
446
|
+
json << "\"project_id\":\"" << project_id << "\",";
|
|
447
|
+
json << "\"device_id\":\"" << device_id << "\",";
|
|
448
|
+
json << "\"telemetry_token\":\"" << telemetry_token << "\",";
|
|
449
|
+
json << "\"framework\":\"cpp\",";
|
|
450
|
+
json << "\"framework_version\":\"" << getVersion() << "\"";
|
|
451
|
+
|
|
452
|
+
json << ",\"ttft\":" << metrics.ttft_ms;
|
|
453
|
+
json << ",\"tps\":" << metrics.tps;
|
|
454
|
+
json << ",\"response_time\":" << metrics.response_time_ms;
|
|
455
|
+
json << ",\"tokens\":" << metrics.tokens;
|
|
456
|
+
|
|
457
|
+
if (!metrics.message.empty()) {
|
|
458
|
+
json << ",\"message\":\"" << escapeJson(metrics.message) << "\"";
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
json << "}";
|
|
462
|
+
return json.str();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
class CactusTelemetry {
|
|
466
|
+
public:
|
|
467
|
+
static CactusTelemetry& getInstance();
|
|
468
|
+
|
|
469
|
+
void setEnabled(bool enabled);
|
|
470
|
+
void setTelemetryToken(const std::string& token);
|
|
471
|
+
void setProjectId(const std::string& project_id);
|
|
472
|
+
void ensureInitialized();
|
|
473
|
+
|
|
474
|
+
void recordEvent(const TelemetryMetrics& metrics);
|
|
475
|
+
|
|
476
|
+
void recordInit(const std::string& model, bool success, const std::string& message = "");
|
|
477
|
+
|
|
478
|
+
void recordCompletion(const std::string& model, bool success,
|
|
479
|
+
double ttft_ms, double tps, double response_time_ms,
|
|
480
|
+
int tokens, const std::string& message = "");
|
|
481
|
+
|
|
482
|
+
void recordEmbedding(const std::string& model, bool success,
|
|
483
|
+
const std::string& message = "");
|
|
484
|
+
|
|
485
|
+
void recordTranscription(const std::string& model, bool success,
|
|
486
|
+
double ttft_ms, double tps, double response_time_ms,
|
|
487
|
+
int tokens, const std::string& message = "");
|
|
488
|
+
|
|
489
|
+
bool isEnabled() const;
|
|
490
|
+
|
|
491
|
+
private:
|
|
492
|
+
CactusTelemetry();
|
|
493
|
+
~CactusTelemetry() = default;
|
|
494
|
+
|
|
495
|
+
CactusTelemetry(const CactusTelemetry&) = delete;
|
|
496
|
+
CactusTelemetry& operator=(const CactusTelemetry&) = delete;
|
|
497
|
+
|
|
498
|
+
void sendToSupabase(const TelemetryMetrics& metrics);
|
|
499
|
+
|
|
500
|
+
bool enabled_ = false;
|
|
501
|
+
bool initialized_ = false;
|
|
502
|
+
std::string telemetry_token_;
|
|
503
|
+
std::string project_id_;
|
|
504
|
+
std::string device_id_;
|
|
505
|
+
|
|
506
|
+
mutable std::mutex mutex_;
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
static const std::string SUPABASE_URL = "https://vlqqczxwyaodtcdmdmlw.supabase.co";
|
|
510
|
+
static const std::string SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZscXFjenh3eWFvZHRjZG1kbWx3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTE1MTg2MzIsImV4cCI6MjA2NzA5NDYzMn0.nBzqGuK9j6RZ6mOPWU2boAC_5H9XDs-fPpo5P3WZYbI";
|
|
511
|
+
|
|
512
|
+
inline CactusTelemetry& CactusTelemetry::getInstance() {
|
|
513
|
+
static CactusTelemetry instance;
|
|
514
|
+
return instance;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
inline CactusTelemetry::CactusTelemetry() {
|
|
518
|
+
// Device ID and project ID are now initialized lazily
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
inline void CactusTelemetry::setEnabled(bool enabled) {
|
|
522
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
523
|
+
enabled_ = enabled;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
inline void CactusTelemetry::setTelemetryToken(const std::string& token) {
|
|
527
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
528
|
+
telemetry_token_ = token;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
inline void CactusTelemetry::setProjectId(const std::string& project_id) {
|
|
532
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
533
|
+
project_id_ = project_id;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
inline void CactusTelemetry::ensureInitialized() {
|
|
537
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
538
|
+
if (!initialized_) {
|
|
539
|
+
std::string pro_key = DeviceManager::getProKey();
|
|
540
|
+
if (!pro_key.empty()) {
|
|
541
|
+
get_device_id(pro_key.c_str());
|
|
542
|
+
}
|
|
543
|
+
#ifdef CACTUS_TELEMETRY_ENABLED
|
|
544
|
+
device_id_ = DeviceManager::getDeviceId();
|
|
545
|
+
project_id_ = DeviceManager::getProjectId();
|
|
546
|
+
#endif
|
|
547
|
+
initialized_ = true;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
inline bool CactusTelemetry::isEnabled() const {
|
|
552
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
553
|
+
return enabled_ && !telemetry_token_.empty();
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
inline void CactusTelemetry::sendToSupabase([[maybe_unused]] const TelemetryMetrics& metrics) {
|
|
557
|
+
#ifdef CACTUS_TELEMETRY_ENABLED
|
|
558
|
+
std::string telemetry_token;
|
|
559
|
+
std::string project_id;
|
|
560
|
+
std::string device_id;
|
|
561
|
+
{
|
|
562
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
563
|
+
telemetry_token = telemetry_token_;
|
|
564
|
+
project_id = project_id_;
|
|
565
|
+
device_id = device_id_;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
std::string log_json = LogRecord::buildJson(metrics, project_id, device_id, telemetry_token);
|
|
569
|
+
|
|
570
|
+
std::string payload = "[" + log_json + "]";
|
|
571
|
+
|
|
572
|
+
std::map<std::string, std::string> headers;
|
|
573
|
+
headers["apikey"] = SUPABASE_KEY;
|
|
574
|
+
headers["Authorization"] = "Bearer " + SUPABASE_KEY;
|
|
575
|
+
headers["Content-Type"] = "application/json";
|
|
576
|
+
headers["Prefer"] = "return=minimal";
|
|
577
|
+
headers["Content-Profile"] = "cactus";
|
|
578
|
+
|
|
579
|
+
std::string url = SUPABASE_URL + "/rest/v1/logs";
|
|
580
|
+
HttpClient::postJson(url, headers, payload);
|
|
581
|
+
#else
|
|
582
|
+
(void)metrics;
|
|
583
|
+
#endif
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
inline void CactusTelemetry::recordEvent(const TelemetryMetrics& metrics) {
|
|
587
|
+
if (!isEnabled()) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
std::thread([this, metrics]() {
|
|
591
|
+
sendToSupabase(metrics);
|
|
592
|
+
}).detach();
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
inline void CactusTelemetry::recordInit(const std::string& model, bool success,
|
|
596
|
+
const std::string& message) {
|
|
597
|
+
TelemetryMetrics metrics;
|
|
598
|
+
metrics.event_type = TelemetryEventType::Init;
|
|
599
|
+
metrics.model = model;
|
|
600
|
+
metrics.success = success;
|
|
601
|
+
metrics.message = message;
|
|
602
|
+
metrics.timestamp = std::chrono::system_clock::now();
|
|
603
|
+
|
|
604
|
+
recordEvent(metrics);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
inline void CactusTelemetry::recordCompletion(const std::string& model, bool success,
|
|
608
|
+
double ttft_ms, double tps, double response_time_ms,
|
|
609
|
+
int tokens, const std::string& message) {
|
|
610
|
+
TelemetryMetrics metrics;
|
|
611
|
+
metrics.event_type = TelemetryEventType::Completion;
|
|
612
|
+
metrics.model = model;
|
|
613
|
+
metrics.success = success;
|
|
614
|
+
metrics.ttft_ms = ttft_ms;
|
|
615
|
+
metrics.tps = tps;
|
|
616
|
+
metrics.response_time_ms = response_time_ms;
|
|
617
|
+
metrics.tokens = tokens;
|
|
618
|
+
metrics.message = message;
|
|
619
|
+
metrics.timestamp = std::chrono::system_clock::now();
|
|
620
|
+
|
|
621
|
+
recordEvent(metrics);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
inline void CactusTelemetry::recordEmbedding(const std::string& model, bool success,
|
|
625
|
+
const std::string& message) {
|
|
626
|
+
TelemetryMetrics metrics;
|
|
627
|
+
metrics.event_type = TelemetryEventType::Embedding;
|
|
628
|
+
metrics.model = model;
|
|
629
|
+
metrics.success = success;
|
|
630
|
+
metrics.message = message;
|
|
631
|
+
metrics.timestamp = std::chrono::system_clock::now();
|
|
632
|
+
|
|
633
|
+
recordEvent(metrics);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
inline void CactusTelemetry::recordTranscription(const std::string& model, bool success,
|
|
637
|
+
double ttft_ms, double tps, double response_time_ms,
|
|
638
|
+
int tokens, const std::string& message) {
|
|
639
|
+
TelemetryMetrics metrics;
|
|
640
|
+
metrics.event_type = TelemetryEventType::Transcription;
|
|
641
|
+
metrics.model = model;
|
|
642
|
+
metrics.success = success;
|
|
643
|
+
metrics.response_time_ms = response_time_ms;
|
|
644
|
+
metrics.ttft_ms = ttft_ms;
|
|
645
|
+
metrics.tps = tps;
|
|
646
|
+
metrics.tokens = tokens;
|
|
647
|
+
metrics.message = message;
|
|
648
|
+
metrics.timestamp = std::chrono::system_clock::now();
|
|
649
|
+
|
|
650
|
+
recordEvent(metrics);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
} // namespace ffi
|
|
654
|
+
} // namespace cactus
|
|
655
|
+
|
|
656
|
+
#endif // CACTUS_TELEMETRY_H
|