This commit is contained in:
2026-05-16 01:43:15 +07:00
parent ea467f8298
commit 91b05aae5d
8 changed files with 210 additions and 95 deletions
BIN
View File
Binary file not shown.
+28 -20
View File
@@ -1,24 +1,32 @@
# ninja log v5 # ninja log v5
4 104 1778781069727168295 CMakeFiles/BIPY_App.dir/glad/glad.c.o fefc672e5ba266d4
1 10013 1778784423530677763 CMakeFiles/Xenith_Studio.dir/Xenith/core.cpp.o 75fc1accc9ccbfb7
3 252 1778784413776238204 CMakeFiles/Xenith_Studio.dir/imgui/backends/imgui_impl_opengl3.cpp.o c304bba33816b766
4 3195 1778356067684895625 CMakeFiles/BIPY_App.dir/imgui/imgui_draw.cpp.o aadac94ced07c385
3 525 1778784414048712486 CMakeFiles/Xenith_Studio.dir/imgui/backends/imgui_impl_glfw.cpp.o 365209c92a3adff5
4 3849 1778356068338800863 CMakeFiles/BIPY_App.dir/imgui/imgui_widgets.cpp.o a4289b0d8e815019
5 2848 1778356067338391370 CMakeFiles/BIPY_App.dir/imgui/imgui_demo.cpp.o 1cce55d13d233628
4 2983 1778356067474176706 CMakeFiles/BIPY_App.dir/imgui/imgui_tables.cpp.o e443056602aa9f6e
4 10037 1778783521781801022 CMakeFiles/BIPY_App.dir/main.cpp.o c17c6f3b932c08b1
2 3330 1778784416851815172 CMakeFiles/Xenith_Studio.dir/imgui/imgui_draw.cpp.o 1800e14a851f25f
2 2750 1778784416272029553 CMakeFiles/Xenith_Studio.dir/imgui/imgui_demo.cpp.o 7f9519f75639670
4 4153 1778356068641915985 CMakeFiles/BIPY_App.dir/imgui/imgui.cpp.o e920e8e567c1a611 4 4153 1778356068641915985 CMakeFiles/BIPY_App.dir/imgui/imgui.cpp.o e920e8e567c1a611
10347 10665 1778784916629791881 Xenith_Studio 3b63d1325bf76a8b 10347 10665 1778784916629791881 Xenith_Studio 3b63d1325bf76a8b
5 8912 1778780147519966740 CMakeFiles/BIPY_App.dir/Xenith/core.cpp.o 6cb7eb29ca382303 2 2750 1778784416272029553 CMakeFiles/Xenith_Studio.dir/imgui/imgui_demo.cpp.o 7f9519f75639670
2 2219 1778784415742112339 CMakeFiles/Xenith_Studio.dir/imgui/imgui_tables.cpp.o 7af2c6b743b00546 2 3330 1778784416851815172 CMakeFiles/Xenith_Studio.dir/imgui/imgui_draw.cpp.o 1800e14a851f25f
4 333 1778356183513052019 CMakeFiles/BIPY_App.dir/imgui/backends/imgui_impl_glfw.cpp.o 98ffae70adc86661 4 2983 1778356067474176706 CMakeFiles/BIPY_App.dir/imgui/imgui_tables.cpp.o e443056602aa9f6e
2 137 1778845540743304132 build.ninja e62af03e6510d470 5 2848 1778356067338391370 CMakeFiles/BIPY_App.dir/imgui/imgui_demo.cpp.o 1cce55d13d233628
1 2096 1778784415617799929 CMakeFiles/Xenith_Studio.dir/Xenith/token/token.cpp.o a2b96f15ecedfdd7 4 3849 1778356068338800863 CMakeFiles/BIPY_App.dir/imgui/imgui_widgets.cpp.o a4289b0d8e815019
5 262 1778356064753829258 CMakeFiles/BIPY_App.dir/imgui/backends/imgui_impl_opengl3.cpp.o 676a63c53e4312bd 3 525 1778784414048712486 CMakeFiles/Xenith_Studio.dir/imgui/backends/imgui_impl_glfw.cpp.o 365209c92a3adff5
2 3544 1778784417065823495 CMakeFiles/Xenith_Studio.dir/imgui/imgui_widgets.cpp.o 3971787f04936e8 4 10037 1778783521781801022 CMakeFiles/BIPY_App.dir/main.cpp.o c17c6f3b932c08b1
4 1654 1778780308577521598 CMakeFiles/BIPY_App.dir/Xenith/token/token.cpp.o bb661ce05133983a
2 4369 1778784417888358381 CMakeFiles/Xenith_Studio.dir/imgui/imgui.cpp.o 65b5accda161432f
4 10347 1778784916307341110 CMakeFiles/Xenith_Studio.dir/main.cpp.o 1d76afb3a7c80307 4 10347 1778784916307341110 CMakeFiles/Xenith_Studio.dir/main.cpp.o 1d76afb3a7c80307
2 4369 1778784417888358381 CMakeFiles/Xenith_Studio.dir/imgui/imgui.cpp.o 65b5accda161432f
4 1654 1778780308577521598 CMakeFiles/BIPY_App.dir/Xenith/token/token.cpp.o bb661ce05133983a
4 104 1778781069727168295 CMakeFiles/BIPY_App.dir/glad/glad.c.o fefc672e5ba266d4
2 3544 1778784417065823495 CMakeFiles/Xenith_Studio.dir/imgui/imgui_widgets.cpp.o 3971787f04936e8
5 262 1778356064753829258 CMakeFiles/BIPY_App.dir/imgui/backends/imgui_impl_opengl3.cpp.o 676a63c53e4312bd
1 2096 1778784415617799929 CMakeFiles/Xenith_Studio.dir/Xenith/token/token.cpp.o a2b96f15ecedfdd7
2 137 1778865662389891016 build.ninja e62af03e6510d470
4 333 1778356183513052019 CMakeFiles/BIPY_App.dir/imgui/backends/imgui_impl_glfw.cpp.o 98ffae70adc86661
2 2219 1778784415742112339 CMakeFiles/Xenith_Studio.dir/imgui/imgui_tables.cpp.o 7af2c6b743b00546
5 8912 1778780147519966740 CMakeFiles/BIPY_App.dir/Xenith/core.cpp.o 6cb7eb29ca382303
4 3195 1778356067684895625 CMakeFiles/BIPY_App.dir/imgui/imgui_draw.cpp.o aadac94ced07c385
1 10013 1778784423530677763 CMakeFiles/Xenith_Studio.dir/Xenith/core.cpp.o 75fc1accc9ccbfb7
3 252 1778784413776238204 CMakeFiles/Xenith_Studio.dir/imgui/backends/imgui_impl_opengl3.cpp.o c304bba33816b766
5 10938 1778865724645927242 CMakeFiles/Xenith_Studio.dir/main.cpp.o 1d76afb3a7c80307
10939 11279 1778865724988598575 Xenith_Studio 3b63d1325bf76a8b
3 10019 1778866395827010833 CMakeFiles/Xenith_Studio.dir/main.cpp.o 1d76afb3a7c80307
10019 10298 1778866396109399696 Xenith_Studio 3b63d1325bf76a8b
3 10320 1778866459031278247 CMakeFiles/Xenith_Studio.dir/main.cpp.o 1d76afb3a7c80307
10320 10631 1778866459343783291 Xenith_Studio 3b63d1325bf76a8b
4 10229 1778867165712694964 CMakeFiles/Xenith_Studio.dir/main.cpp.o 1d76afb3a7c80307
10229 10510 1778867165996696192 Xenith_Studio 3b63d1325bf76a8b
Binary file not shown.
Binary file not shown.
+7 -13
View File
@@ -1,26 +1,20 @@
[ARCHITECTURE] [ARCHITECTURE]
layers=4 layers=3
[LAYER 0] [LAYER 0]
size=2048 size=65536
branch=-1 branch=-1
sources= sources=
branches= branches=
[LAYER 1] [LAYER 1]
size=128 size=2048
branch=-1 branch=-1
sources= sources=0
branches= branches=-1
[LAYER 2] [LAYER 2]
size=128
branch=-1
sources=
branches=
[LAYER 3]
size=300 size=300
branch=-1 branch=-1
sources= sources=1
branches= branches=-1
+2 -2
View File
@@ -12,7 +12,7 @@ Size=1280,720
[Window][Main] [Window][Main]
Pos=0,0 Pos=0,0
Size=2560,1371 Size=1600,1000
[Window][Studio] [Window][Studio]
Pos=0,0 Pos=0,0
@@ -28,5 +28,5 @@ Size=1600,1000
[Window][##Props] [Window][##Props]
Pos=26,120 Pos=26,120
Size=240,220 Size=240,240
+173 -60
View File
@@ -1,5 +1,5 @@
// ============================================================================ // ============================================================================
// Xenith Studio - Node Editor v3.1 (Исправлено обучение + Загрузка из файла + Фикс портов) // Xenith AI Studio v3.2
// ============================================================================ // ============================================================================
#define IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS
@@ -21,12 +21,23 @@
#include <cmath> #include <cmath>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <chrono>
#include <cstring>
#include "Xenith/core.hpp" #include "Xenith/core.hpp"
#include "Xenith/token/token.hpp" #include "Xenith/token/token.hpp"
// ============================================================================ // ============================================================================
// NODE EDITOR ENGINE // ⚠️ ГЛОБАЛЬНЫЕ НАСТРОЙКИ - ДОЛЖНЫ БЫТЬ ПЕРЕД ВСЕМИ ФУНКЦИЯМИ КОТОРЫЕ ИХ ИСПОЛЬЗУЮТ
// ============================================================================
int UI_CONTEXT = 512;
int UI_EMBED = 128;
int UI_VOCAB = 300;
int MAX_RESPONSE_TOKENS = 128;
// ============================================================================
// NODE EDITOR ENGINE (теперь видит UI_CONTEXT, UI_EMBED, UI_VOCAB)
// ============================================================================ // ============================================================================
namespace NodeEditor { namespace NodeEditor {
@@ -54,12 +65,14 @@ struct Node {
int layerSize; int layerSize;
int branchCount; int branchCount;
int activeBranch; int activeBranch;
bool isSizeFixed; // NEW: для Input/Output
std::vector<Port> inputs; std::vector<Port> inputs;
std::vector<Port> outputs; std::vector<Port> outputs;
Node(int id_, const std::string& t_, NodeType type_) Node(int id_, const std::string& t_, NodeType type_)
: id(id_), title(t_), type(type_), pos(0,0), size(180,100), : id(id_), title(t_), type(type_), pos(0,0), size(180,100),
selected(false), dragging(false), layerSize(128), branchCount(2), activeBranch(-1) { selected(false), dragging(false), layerSize(128), branchCount(2),
activeBranch(-1), isSizeFixed(false) {
UpdatePorts(); UpdatePorts();
} }
@@ -67,25 +80,32 @@ struct Node {
inputs.clear(); outputs.clear(); inputs.clear(); outputs.clear();
switch(type) { switch(type) {
case NodeType::Input: case NodeType::Input:
// ИСПРАВЛЕНО: 0 входов, 1 выход
outputs.push_back(Port("Out", PortType::Output)); outputs.push_back(Port("Out", PortType::Output));
isSizeFixed = true;
// Размер вычисляется из глобальных настроек
layerSize = UI_CONTEXT * UI_EMBED;
break; break;
case NodeType::Hidden: case NodeType::Hidden:
// ИСПРАВЛЕНО: 1 вход, 1 выход
inputs.push_back(Port("In", PortType::Input)); inputs.push_back(Port("In", PortType::Input));
outputs.push_back(Port("Out", PortType::Output)); outputs.push_back(Port("Out", PortType::Output));
isSizeFixed = false;
break; break;
case NodeType::Output: case NodeType::Output:
// ИСПРАВЛЕНО: 1 вход, 0 выходов
inputs.push_back(Port("In", PortType::Input)); inputs.push_back(Port("In", PortType::Input));
isSizeFixed = true;
layerSize = UI_VOCAB;
break; break;
case NodeType::Splitter: case NodeType::Splitter:
inputs.push_back(Port("In", PortType::Input)); inputs.push_back(Port("In", PortType::Input));
for(int i=0;i<branchCount;i++) outputs.push_back(Port("Br "+std::to_string(i), PortType::Output)); for(int i=0;i<branchCount;i++)
outputs.push_back(Port("Br "+std::to_string(i), PortType::Output));
isSizeFixed = false;
break; break;
case NodeType::Merger: case NodeType::Merger:
for(int i=0;i<branchCount;i++) inputs.push_back(Port("Br "+std::to_string(i), PortType::Input)); for(int i=0;i<branchCount;i++)
inputs.push_back(Port("Br "+std::to_string(i), PortType::Input));
outputs.push_back(Port("Out", PortType::Output)); outputs.push_back(Port("Out", PortType::Output));
isSizeFixed = false;
break; break;
} }
} }
@@ -138,12 +158,25 @@ void DrawNode(ImDrawList* dl, const Node& n, const GraphState& g, const ImVec2&
dl->AddRect(scr, scr + n.size, GetNodeColor(n.type, n.selected), 6, 0, 2.0f); dl->AddRect(scr, scr + n.size, GetNodeColor(n.type, n.selected), 6, 0, 2.0f);
dl->AddText(scr + ImVec2(10,4), IM_COL32(255,255,255,255), n.title.c_str()); dl->AddText(scr + ImVec2(10,4), IM_COL32(255,255,255,255), n.title.c_str());
dl->AddText(scr + ImVec2(10,20), IM_COL32(160,160,160,200), std::to_string(n.layerSize).c_str());
// Отображение размера
if(n.isSizeFixed) {
std::string sizeInfo = std::to_string(n.layerSize) + " (auto)";
dl->AddText(scr + ImVec2(10,20), IM_COL32(160,160,160,200), sizeInfo.c_str());
if(n.type == NodeType::Input) {
dl->AddText(scr + ImVec2(10,36), IM_COL32(100,100,100,150), "CTX×EMB");
} else if(n.type == NodeType::Output) {
dl->AddText(scr + ImVec2(10,36), IM_COL32(100,100,100,150), "VOCAB");
}
} else {
dl->AddText(scr + ImVec2(10,20), IM_COL32(160,160,160,200), std::to_string(n.layerSize).c_str());
}
if(n.type == NodeType::Splitter || n.type == NodeType::Merger) { if(n.type == NodeType::Splitter || n.type == NodeType::Merger) {
dl->AddText(scr + ImVec2(10, n.size.y-18), IM_COL32(255,220,100,255), (" x"+std::to_string(n.branchCount)).c_str()); dl->AddText(scr + ImVec2(10, n.size.y-18), IM_COL32(255,220,100,255), (" x"+std::to_string(n.branchCount)).c_str());
} }
// Порты ввода
for(size_t i=0; i<n.inputs.size(); i++) { for(size_t i=0; i<n.inputs.size(); i++) {
ImVec2 p = n.GetPortScreenPos((int)i, true, canvasPos, pan); ImVec2 p = n.GetPortScreenPos((int)i, true, canvasPos, pan);
bool hov = (g.hoveredPortNode == n.id && g.hoveredPortIdx == (int)i && g.hoveredPortType == PortType::Input); bool hov = (g.hoveredPortNode == n.id && g.hoveredPortIdx == (int)i && g.hoveredPortType == PortType::Input);
@@ -151,6 +184,7 @@ void DrawNode(ImDrawList* dl, const Node& n, const GraphState& g, const ImVec2&
dl->AddCircle(p, 5, IM_COL32(50,50,50,255), 12, 1.5f); dl->AddCircle(p, 5, IM_COL32(50,50,50,255), 12, 1.5f);
dl->AddText(p + ImVec2(10,-5), IM_COL32(200,200,200,255), n.inputs[i].name.c_str()); dl->AddText(p + ImVec2(10,-5), IM_COL32(200,200,200,255), n.inputs[i].name.c_str());
} }
// Порты вывода
for(size_t i=0; i<n.outputs.size(); i++) { for(size_t i=0; i<n.outputs.size(); i++) {
ImVec2 p = n.GetPortScreenPos((int)i, false, canvasPos, pan); ImVec2 p = n.GetPortScreenPos((int)i, false, canvasPos, pan);
bool hov = (g.hoveredPortNode == n.id && g.hoveredPortIdx == (int)i && g.hoveredPortType == PortType::Output); bool hov = (g.hoveredPortNode == n.id && g.hoveredPortIdx == (int)i && g.hoveredPortType == PortType::Output);
@@ -206,23 +240,32 @@ void HandleInput(GraphState& g, const ImVec2& canvasPos, const ImVec2& canvasSiz
for(const auto& n : g.nodes) { for(const auto& n : g.nodes) {
for(size_t i=0;i<n.inputs.size();i++) { for(size_t i=0;i<n.inputs.size();i++) {
ImVec2 p = n.GetPortScreenPos((int)i, true, canvasPos, g.pan); ImVec2 p = n.GetPortScreenPos((int)i, true, canvasPos, g.pan);
if(ImLengthSqr(mouseScreen-p) < 64) { g.hoveredPortNode=n.id; g.hoveredPortIdx=(int)i; g.hoveredPortType=PortType::Input; } if(ImLengthSqr(mouseScreen-p) < 64) {
g.hoveredPortNode=n.id; g.hoveredPortIdx=(int)i; g.hoveredPortType=PortType::Input;
}
} }
for(size_t i=0;i<n.outputs.size();i++) { for(size_t i=0;i<n.outputs.size();i++) {
ImVec2 p = n.GetPortScreenPos((int)i, false, canvasPos, g.pan); ImVec2 p = n.GetPortScreenPos((int)i, false, canvasPos, g.pan);
if(ImLengthSqr(mouseScreen-p) < 64) { g.hoveredPortNode=n.id; g.hoveredPortIdx=(int)i; g.hoveredPortType=PortType::Output; } if(ImLengthSqr(mouseScreen-p) < 64) {
g.hoveredPortNode=n.id; g.hoveredPortIdx=(int)i; g.hoveredPortType=PortType::Output;
}
} }
} }
if(ImGui::IsMouseClicked(ImGuiMouseButton_Left) && g.hoveredPortNode!=-1 && !g.panning) { if(ImGui::IsMouseClicked(ImGuiMouseButton_Left) && g.hoveredPortNode!=-1 && !g.panning) {
g.creatingConn=true; g.connStartNode=g.hoveredPortNode; g.connStartPort=g.hoveredPortIdx; g.connStartType=g.hoveredPortType; g.creatingConn=true;
g.connStartNode=g.hoveredPortNode;
g.connStartPort=g.hoveredPortIdx;
g.connStartType=g.hoveredPortType;
} }
if(g.creatingConn) { if(g.creatingConn) {
g.connMousePos = mouseScreen; g.connMousePos = mouseScreen;
if(ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { if(ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
if(g.hoveredPortNode!=-1 && g.hoveredPortNode!=g.connStartNode && g.hoveredPortType!=g.connStartType) { if(g.hoveredPortNode!=-1 && g.hoveredPortNode!=g.connStartNode && g.hoveredPortType!=g.connStartType) {
if(g.connStartType==PortType::Output) g.connections.emplace_back(g.connStartNode, g.connStartPort, g.hoveredPortNode, g.hoveredPortIdx); if(g.connStartType==PortType::Output)
else g.connections.emplace_back(g.hoveredPortNode, g.hoveredPortIdx, g.connStartNode, g.connStartPort); g.connections.emplace_back(g.connStartNode, g.connStartPort, g.hoveredPortNode, g.hoveredPortIdx);
else
g.connections.emplace_back(g.hoveredPortNode, g.hoveredPortIdx, g.connStartNode, g.connStartPort);
} }
g.creatingConn=false; g.creatingConn=false;
} }
@@ -243,7 +286,8 @@ void HandleInput(GraphState& g, const ImVec2& canvasPos, const ImVec2& canvasSiz
if(ImGui::IsMouseClicked(ImGuiMouseButton_Left) && g.hoveredPortNode==-1 && !g.creatingConn && !g.panning) { if(ImGui::IsMouseClicked(ImGuiMouseButton_Left) && g.hoveredPortNode==-1 && !g.creatingConn && !g.panning) {
bool onNode = false; bool onNode = false;
for(const auto& n : g.nodes) if(ImRect(canvasPos+n.pos+g.pan, canvasPos+n.pos+g.pan+n.size).Contains(mouseScreen)) onNode=true; for(const auto& n : g.nodes)
if(ImRect(canvasPos+n.pos+g.pan, canvasPos+n.pos+g.pan+n.size).Contains(mouseScreen)) onNode=true;
if(!onNode) { g.selectedNode=-1; for(auto& n:g.nodes) n.selected=false; } if(!onNode) { g.selectedNode=-1; for(auto& n:g.nodes) n.selected=false; }
} }
} }
@@ -256,8 +300,10 @@ void DrawGraph(GraphState& g, const ImVec2& canvasSize) {
float gs = 40.0f; float gs = 40.0f;
ImVec2 off = ImVec2(fmodf(g.pan.x, gs), fmodf(g.pan.y, gs)); ImVec2 off = ImVec2(fmodf(g.pan.x, gs), fmodf(g.pan.y, gs));
for(float x=off.x; x<canvasSize.x; x+=gs) dl->AddLine(canvasPos+ImVec2(x,0), canvasPos+ImVec2(x,canvasSize.y), IM_COL32(40,44,55,120)); for(float x=off.x; x<canvasSize.x; x+=gs)
for(float y=off.y; y<canvasSize.y; y+=gs) dl->AddLine(canvasPos+ImVec2(0,y), canvasPos+ImVec2(canvasSize.x,y), IM_COL32(40,44,55,120)); dl->AddLine(canvasPos+ImVec2(x,0), canvasPos+ImVec2(x,canvasSize.y), IM_COL32(40,44,55,120));
for(float y=off.y; y<canvasSize.y; y+=gs)
dl->AddLine(canvasPos+ImVec2(0,y), canvasPos+ImVec2(canvasSize.x,y), IM_COL32(40,44,55,120));
DrawConnections(dl, g, canvasPos, g.pan); DrawConnections(dl, g, canvasPos, g.pan);
for(auto& n : g.nodes) DrawNode(dl, n, g, canvasPos, g.pan); for(auto& n : g.nodes) DrawNode(dl, n, g, canvasPos, g.pan);
@@ -267,13 +313,29 @@ void DrawGraph(GraphState& g, const ImVec2& canvasSize) {
if(ImGui::BeginPopupContextItem("##Ctx")) { if(ImGui::BeginPopupContextItem("##Ctx")) {
ImVec2 wPos = ImGui::GetMousePos() - canvasPos - g.pan; ImVec2 wPos = ImGui::GetMousePos() - canvasPos - g.pan;
if(ImGui::MenuItem("🟢 Input")) { g.nodes.emplace_back(g.nextId++, "Input", NodeType::Input); g.nodes.back().pos=wPos; } if(ImGui::MenuItem("🟢 Input")) {
if(ImGui::MenuItem(" Hidden")) { g.nodes.emplace_back(g.nextId++, "Hidden", NodeType::Hidden); g.nodes.back().pos=wPos; } auto& n = g.nodes.emplace_back(g.nextId++, "Input", NodeType::Input);
if(ImGui::MenuItem(" Output")) { g.nodes.emplace_back(g.nextId++, "Output", NodeType::Output); g.nodes.back().pos=wPos; } n.pos=wPos;
}
if(ImGui::MenuItem(" Hidden")) {
auto& n = g.nodes.emplace_back(g.nextId++, "Hidden", NodeType::Hidden);
n.pos=wPos;
}
if(ImGui::MenuItem(" Output")) {
auto& n = g.nodes.emplace_back(g.nextId++, "Output", NodeType::Output);
n.pos=wPos;
}
ImGui::Separator(); ImGui::Separator();
if(ImGui::MenuItem(" Splitter (x2)")) { auto& n=g.nodes.emplace_back(g.nextId++, "Splitter", NodeType::Splitter); n.pos=wPos; n.branchCount=2; n.UpdatePorts(); } if(ImGui::MenuItem(" Splitter")) {
if(ImGui::MenuItem(" Merger (x2)")) { auto& n=g.nodes.emplace_back(g.nextId++, "Merger", NodeType::Merger); n.pos=wPos; n.branchCount=2; n.UpdatePorts(); } auto& n = g.nodes.emplace_back(g.nextId++, "Splitter", NodeType::Splitter);
ImGui::Separator(); ImGui::Text("LMB: Drag/Connect | RMB: Cancel | MMB: Pan"); n.pos=wPos; n.branchCount=2; n.UpdatePorts();
}
if(ImGui::MenuItem(" Merger")) {
auto& n = g.nodes.emplace_back(g.nextId++, "Merger", NodeType::Merger);
n.pos=wPos; n.branchCount=2; n.UpdatePorts();
}
ImGui::Separator();
ImGui::Text("LMB: Drag/Connect | RMB: Cancel | MMB: Pan");
ImGui::EndPopup(); ImGui::EndPopup();
} }
@@ -282,16 +344,32 @@ void DrawGraph(GraphState& g, const ImVec2& canvasSize) {
if(it != g.nodes.end()) { if(it != g.nodes.end()) {
Node& sel = *it; Node& sel = *it;
ImGui::SetNextWindowPos(canvasPos + ImVec2(10,10)); ImGui::SetNextWindowPos(canvasPos + ImVec2(10,10));
ImGui::SetNextWindowSize(ImVec2(240,220)); ImGui::SetNextWindowSize(ImVec2(240,240));
if(ImGui::Begin("##Props", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove)) { if(ImGui::Begin("##Props", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove)) {
ImGui::TextColored(ImVec4(1,1,0.5f,1), "%s # %d", sel.title.c_str(), sel.id); ImGui::Separator(); ImGui::TextColored(ImVec4(1,1,0.5f,1), "%s # %d", sel.title.c_str(), sel.id);
ImGui::Separator();
if(sel.type != NodeType::Output) { ImGui::InputInt("Neurons", &sel.layerSize); if(sel.layerSize<1) sel.layerSize=1; } // Редактирование размера ТОЛЬКО для не-фиксированных слоёв
if(!sel.isSizeFixed) {
ImGui::InputInt("Neurons", &sel.layerSize);
if(sel.layerSize < 1) sel.layerSize = 1;
} else {
ImGui::Text("Size: %d (auto)", sel.layerSize);
if(sel.type == NodeType::Input) {
ImGui::TextColored(ImVec4(0.5,0.5,0.5,1), "= CONTEXT × EMBED");
ImGui::TextColored(ImVec4(0.5,0.5,0.5,1), "= %d × %d", UI_CONTEXT, UI_EMBED);
} else if(sel.type == NodeType::Output) {
ImGui::TextColored(ImVec4(0.5,0.5,0.5,1), "= VOCAB_SIZE");
ImGui::TextColored(ImVec4(0.5,0.5,0.5,1), "= %d", UI_VOCAB);
}
}
if(sel.type == NodeType::Splitter || sel.type == NodeType::Merger) { if(sel.type == NodeType::Splitter || sel.type == NodeType::Merger) {
ImGui::Separator();
ImGui::SliderInt("Branches", &sel.branchCount, 2, 8); ImGui::SliderInt("Branches", &sel.branchCount, 2, 8);
if(ImGui::IsItemDeactivatedAfterEdit()) sel.UpdatePorts(); if(ImGui::IsItemDeactivatedAfterEdit()) sel.UpdatePorts();
} else if(sel.type == NodeType::Input) { } else if(sel.type == NodeType::Input) {
ImGui::Separator();
ImGui::Text("Branch:"); ImGui::Text("Branch:");
ImGui::RadioButton("Combined", &sel.activeBranch, -1); ImGui::RadioButton("Combined", &sel.activeBranch, -1);
ImGui::RadioButton("A (0)", &sel.activeBranch, 0); ImGui::RadioButton("A (0)", &sel.activeBranch, 0);
@@ -300,7 +378,8 @@ void DrawGraph(GraphState& g, const ImVec2& canvasSize) {
ImGui::Spacing(); ImGui::Spacing();
if(ImGui::Button("🗑 Delete", ImVec2(-1,28))) { if(ImGui::Button("🗑 Delete", ImVec2(-1,28))) {
g.connections.erase(std::remove_if(g.connections.begin(), g.connections.end(), [id=sel.id](const Connection& c){return c.fromNode==id||c.toNode==id;}), g.connections.end()); g.connections.erase(std::remove_if(g.connections.begin(), g.connections.end(),
[id=sel.id](const Connection& c){return c.fromNode==id||c.toNode==id;}), g.connections.end());
g.nodes.erase(it); g.selectedNode=-1; g.nodes.erase(it); g.selectedNode=-1;
} }
ImGui::End(); ImGui::End();
@@ -316,8 +395,20 @@ void SyncFromConfigs(GraphState& g, const std::vector<LayerStructure_t>& cfgs) {
NodeType t = c.sources.empty() ? NodeType::Input : (i==cfgs.size()-1 ? NodeType::Output : NodeType::Hidden); NodeType t = c.sources.empty() ? NodeType::Input : (i==cfgs.size()-1 ? NodeType::Output : NodeType::Hidden);
Node n(g.nextId++, t==NodeType::Input?"Input":t==NodeType::Output?"Output":"Hidden", t); Node n(g.nextId++, t==NodeType::Input?"Input":t==NodeType::Output?"Output":"Hidden", t);
n.pos = ImVec2(120 + i*260, 150 + (i%3)*120); n.pos = ImVec2(120 + i*260, 150 + (i%3)*120);
n.layerSize = c.size; n.activeBranch = c.branch;
// UpdatePorts вызывается в конструкторе, но для гарантии: // Фиксированные размеры для Input/Output
if(t == NodeType::Input) {
n.layerSize = UI_CONTEXT * UI_EMBED;
n.isSizeFixed = true;
} else if(t == NodeType::Output) {
n.layerSize = UI_VOCAB;
n.isSizeFixed = true;
} else {
n.layerSize = c.size;
n.isSizeFixed = false;
}
n.activeBranch = c.branch;
n.UpdatePorts(); n.UpdatePorts();
g.nodes.push_back(n); g.nodes.push_back(n);
} }
@@ -337,7 +428,9 @@ void SyncToConfigs(GraphState& g, std::vector<LayerStructure_t>& cfgs) {
for(size_t i=0;i<sorted.size();i++) idToIdx[sorted[i]->id] = (int)i; for(size_t i=0;i<sorted.size();i++) idToIdx[sorted[i]->id] = (int)i;
for(const Node* n : sorted) { for(const Node* n : sorted) {
LayerStructure_t l; l.size=n->layerSize; l.branch=n->activeBranch; LayerStructure_t l;
l.size = n->layerSize;
l.branch = n->activeBranch;
for(const auto& c : g.connections) { for(const auto& c : g.connections) {
if(c.toNode==n->id && idToIdx.count(c.fromNode)) { if(c.toNode==n->id && idToIdx.count(c.fromNode)) {
l.sources.push_back(idToIdx[c.fromNode]); l.sources.push_back(idToIdx[c.fromNode]);
@@ -362,13 +455,21 @@ std::string GenerateArchitectureText(const GraphState& g, const std::vector<Laye
} }
ss << "Total Parameters: " << totalParams << " (" << std::fixed << std::setprecision(2) << (totalParams/1000000.0) << "M)\n\n"; ss << "Total Parameters: " << totalParams << " (" << std::fixed << std::setprecision(2) << (totalParams/1000000.0) << "M)\n\n";
ss << "Layer Structure:\n"; ss << "Layer Structure:\n----------------\n";
ss << "----------------\n";
for(size_t i=0;i<configs.size();i++) { for(size_t i=0;i<configs.size();i++) {
auto& l = configs[i]; auto& l = configs[i];
std::string type = l.sources.empty() ? "INPUT" : (i==configs.size()-1 ? "OUTPUT" : "HIDDEN"); std::string type = l.sources.empty() ? "INPUT" : (i==configs.size()-1 ? "OUTPUT" : "HIDDEN");
ss << "Layer " << i << " [" << type << "]: " << l.size << " neurons";
if(type == "INPUT") {
ss << "Layer " << i << " [INPUT]: " << l.size << " neurons";
ss << " (CONTEXT=" << UI_CONTEXT << " × EMBED=" << UI_EMBED << ")";
} else if(type == "OUTPUT") {
ss << "Layer " << i << " [OUTPUT]: " << l.size << " neurons";
ss << " (VOCAB=" << UI_VOCAB << ")";
} else {
ss << "Layer " << i << " [HIDDEN]: " << l.size << " neurons";
}
if(l.branch != -1) ss << " (Branch " << (char)('A'+l.branch) << ")"; if(l.branch != -1) ss << " (Branch " << (char)('A'+l.branch) << ")";
ss << "\n"; ss << "\n";
@@ -389,8 +490,9 @@ std::string GenerateArchitectureText(const GraphState& g, const std::vector<Laye
for(const auto& n : g.nodes) { for(const auto& n : g.nodes) {
ss << "Node #" << n.id << " [" << n.title << "] @ (" ss << "Node #" << n.id << " [" << n.title << "] @ ("
<< (int)n.pos.x << "," << (int)n.pos.y << ")\n"; << (int)n.pos.x << "," << (int)n.pos.y << ")\n";
ss << " Size: " << n.layerSize << " neurons\n"; ss << " Size: " << n.layerSize << " neurons";
ss << " Inputs: " << n.inputs.size() << " | Outputs: " << n.outputs.size() << "\n"; if(n.isSizeFixed) ss << " (auto)";
ss << "\n Inputs: " << n.inputs.size() << " | Outputs: " << n.outputs.size() << "\n";
if(n.type == NodeType::Splitter || n.type == NodeType::Merger) if(n.type == NodeType::Splitter || n.type == NodeType::Merger)
ss << " Branches: " << n.branchCount << "\n"; ss << " Branches: " << n.branchCount << "\n";
} }
@@ -398,7 +500,6 @@ std::string GenerateArchitectureText(const GraphState& g, const std::vector<Laye
return ss.str(); return ss.str();
} }
// === SAVE/LOAD ARCHITECTURE AS TEXT STRUCTURE ===
bool SaveArchitectureToFile(const std::vector<LayerStructure_t>& configs, const std::string& filename) { bool SaveArchitectureToFile(const std::vector<LayerStructure_t>& configs, const std::string& filename) {
std::ofstream file(filename); std::ofstream file(filename);
if(!file.is_open()) return false; if(!file.is_open()) return false;
@@ -538,9 +639,6 @@ bool LoadDatasetFromFile(std::string& buffer, const std::string& filename) {
// GLOBAL STATE // GLOBAL STATE
// ============================================================================ // ============================================================================
int UI_CONTEXT = 256, UI_EMBED = 8, UI_VOCAB = 300;
int MAX_RESPONSE_TOKENS = 50;
struct UIState { struct UIState {
std::vector<ChatSession> chats; std::vector<ChatSession> chats;
int activeChat = 0; int activeChat = 0;
@@ -553,11 +651,11 @@ struct UIState {
int epochs = 10; int epochs = 10;
int doneEpochs = 0; int doneEpochs = 0;
// Performance metrics
double tokensPerSecond = 0.0; double tokensPerSecond = 0.0;
double generationTokensPerSecond = 0.0; double generationTokensPerSecond = 0.0;
int totalTokensTrained = 0; int totalTokensTrained = 0;
std::chrono::steady_clock::time_point trainingStartTime; std::chrono::steady_clock::time_point trainingStartTime;
std::chrono::steady_clock::time_point lastTokenTime;
char dsBuf[524288] = ""; char dsBuf[524288] = "";
std::vector<TrainingSample> parsedSamples; std::vector<TrainingSample> parsedSamples;
@@ -568,7 +666,6 @@ struct UIState {
NodeEditor::GraphState graph; NodeEditor::GraphState graph;
std::string architectureText; std::string architectureText;
bool showArchitecture = true;
char archFilePath[256] = "architecture.txt"; char archFilePath[256] = "architecture.txt";
char datasetFilePath[256] = "dataset.txt"; char datasetFilePath[256] = "dataset.txt";
@@ -609,7 +706,6 @@ void TrainTask(NeuralNetwork* nn, Tokenizer* tk, Embedder* eb) {
int os = ui.layers.back().size; int os = ui.layers.back().size;
double totalLoss = 0; double totalLoss = 0;
int sampleCount = 0; int sampleCount = 0;
int totalTokens = 0;
ui.trainingStartTime = std::chrono::steady_clock::now(); ui.trainingStartTime = std::chrono::steady_clock::now();
ui.totalTokensTrained = 0; ui.totalTokensTrained = 0;
@@ -633,7 +729,6 @@ void TrainTask(NeuralNetwork* nn, Tokenizer* tk, Embedder* eb) {
double loss = nn->train(PrepInput(context, *eb), target, ui.lr); double loss = nn->train(PrepInput(context, *eb), target, ui.lr);
totalLoss += loss; totalLoss += loss;
sampleCount++; sampleCount++;
totalTokens++;
ui.totalTokensTrained++; ui.totalTokensTrained++;
context.push_back(aiToks[i]); context.push_back(aiToks[i]);
@@ -663,19 +758,16 @@ void TrainTask(NeuralNetwork* nn, Tokenizer* tk, Embedder* eb) {
ui.doneEpochs++; ui.doneEpochs++;
// Логируем каждую эпоху
std::cout << "Epoch " << (e+1) << "/" << ui.epochs std::cout << "Epoch " << (e+1) << "/" << ui.epochs
<< " | Loss: " << (totalLoss/sampleCount) << " | Loss: " << (totalLoss/(sampleCount>0?sampleCount:1))
<< " | Time: " << epochTime << "s" << " | Time: " << epochTime << "s"
<< " | Tokens/sec: " << ui.tokensPerSecond << " | Tokens/sec: " << ui.tokensPerSecond << "\n";
<< "\n";
} }
if(sampleCount > 0) { if(sampleCount > 0) {
std::lock_guard<std::mutex> lk(ui.mtx); std::lock_guard<std::mutex> lk(ui.mtx);
ui.lastStatus.totalLoss = totalLoss / sampleCount; ui.lastStatus.totalLoss = totalLoss / sampleCount;
// Общая статистика
auto totalTime = std::chrono::duration<double>( auto totalTime = std::chrono::duration<double>(
std::chrono::steady_clock::now() - ui.trainingStartTime).count(); std::chrono::steady_clock::now() - ui.trainingStartTime).count();
if(totalTime > 0) { if(totalTime > 0) {
@@ -686,6 +778,7 @@ void TrainTask(NeuralNetwork* nn, Tokenizer* tk, Embedder* eb) {
ui.training=false; ui.training=false;
ui.stop=false; ui.stop=false;
} }
// ============================================================================ // ============================================================================
// MAIN // MAIN
// ============================================================================ // ============================================================================
@@ -700,6 +793,7 @@ int main() {
io.Fonts->AddFontFromFileTTF("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 16.0f, nullptr, io.Fonts->GetGlyphRangesCyrillic()); io.Fonts->AddFontFromFileTTF("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 16.0f, nullptr, io.Fonts->GetGlyphRangesCyrillic());
ImGui_ImplGlfw_InitForOpenGL(win, true); ImGui_ImplOpenGL3_Init("#version 130"); ImGui_ImplGlfw_InitForOpenGL(win, true); ImGui_ImplOpenGL3_Init("#version 130");
// Init default architecture
ui.layers = { ui.layers = {
LayerStructure_t(UI_CONTEXT*UI_EMBED,{}), LayerStructure_t(UI_CONTEXT*UI_EMBED,{}),
LayerStructure_t(512,{0}), LayerStructure_t(512,{0}),
@@ -721,6 +815,9 @@ int main() {
std::cout << "Loaded architecture from " << ui.archFilePath << "\n"; std::cout << "Loaded architecture from " << ui.archFilePath << "\n";
} }
// Track last values for auto-update
int lastContext = UI_CONTEXT, lastEmbed = UI_EMBED, lastVocab = UI_VOCAB;
while(!glfwWindowShouldClose(win)) { while(!glfwWindowShouldClose(win)) {
glfwPollEvents(); glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame();
@@ -750,6 +847,7 @@ int main() {
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
// Status bar
{ {
std::lock_guard<std::mutex> lk(ui.mtx); std::lock_guard<std::mutex> lk(ui.mtx);
ImGui::Text("Epoch: %d/%d | Loss: %.5f | %.1f%%", ImGui::Text("Epoch: %d/%d | Loss: %.5f | %.1f%%",
@@ -761,6 +859,7 @@ int main() {
} }
ImGui::Separator(); ImGui::Separator();
// Three columns
ImGui::Columns(3, "MainCols", true); ImGui::Columns(3, "MainCols", true);
ImGui::SetColumnWidth(0, io.DisplaySize.x*0.35f); ImGui::SetColumnWidth(0, io.DisplaySize.x*0.35f);
ImGui::SetColumnWidth(1, io.DisplaySize.x*0.35f); ImGui::SetColumnWidth(1, io.DisplaySize.x*0.35f);
@@ -792,18 +891,18 @@ int main() {
} }
if(ImGui::BeginTabItem("Training")) { if(ImGui::BeginTabItem("Training")) {
// Performance metrics
ImGui::TextColored(ImVec4(0,1,1,1), "Performance Metrics:"); ImGui::TextColored(ImVec4(0,1,1,1), "Performance Metrics:");
ImGui::Separator(); ImGui::Separator();
{ {
std::lock_guard<std::mutex> lk(ui.mtx); std::lock_guard<std::mutex> lk(ui.mtx);
ImGui::Text("Training Speed: %.2f tokens/sec", ui.tokensPerSecond); ImGui::Text("Training Speed: %.2f tokens/sec", ui.tokensPerSecond);
ImGui::Text("Generation Speed: %.2f tokens/sec", ui.generationTokensPerSecond); ImGui::Text("Generation Speed: %.2f tokens/sec", ui.generationTokensPerSecond);
ImGui::Text("Total Tokens Trained: %d", ui.totalTokensTrained); ImGui::Text("Total Tokens Trained: %d", ui.totalTokensTrained);
} }
ImGui::Separator(); ImGui::Separator();
// Settings
ImGui::SliderFloat("Learning Rate", &ui.lr, 0.0001f, 0.1f, "%.5f"); ImGui::SliderFloat("Learning Rate", &ui.lr, 0.0001f, 0.1f, "%.5f");
ImGui::InputInt("Epochs", &ui.epochs); if(ui.epochs<1) ui.epochs=1; ImGui::InputInt("Epochs", &ui.epochs); if(ui.epochs<1) ui.epochs=1;
ImGui::InputInt("Max Response Tokens", &MAX_RESPONSE_TOKENS); if(MAX_RESPONSE_TOKENS<1) MAX_RESPONSE_TOKENS=1; ImGui::InputInt("Max Response Tokens", &MAX_RESPONSE_TOKENS); if(MAX_RESPONSE_TOKENS<1) MAX_RESPONSE_TOKENS=1;
@@ -811,6 +910,21 @@ int main() {
ImGui::InputInt("Embedding Dim", &UI_EMBED); if(UI_EMBED<1) UI_EMBED=1; ImGui::InputInt("Embedding Dim", &UI_EMBED); if(UI_EMBED<1) UI_EMBED=1;
ImGui::InputInt("Vocab Size", &UI_VOCAB); if(UI_VOCAB<1) UI_VOCAB=1; ImGui::InputInt("Vocab Size", &UI_VOCAB); if(UI_VOCAB<1) UI_VOCAB=1;
// Auto-update fixed layer sizes when globals change
if(UI_CONTEXT != lastContext || UI_EMBED != lastEmbed || UI_VOCAB != lastVocab) {
lastContext = UI_CONTEXT; lastEmbed = UI_EMBED; lastVocab = UI_VOCAB;
for(auto& node : ui.graph.nodes) {
if(node.type == NodeEditor::NodeType::Input) {
node.layerSize = UI_CONTEXT * UI_EMBED;
node.UpdatePorts();
} else if(node.type == NodeEditor::NodeType::Output) {
node.layerSize = UI_VOCAB;
node.UpdatePorts();
}
}
ui.architectureText = NodeEditor::GenerateArchitectureText(ui.graph, ui.layers);
}
ImGui::Separator(); ImGui::Separator();
ImGui::TextColored(ImVec4(1,0.5f,0,1), "⚠️ Recommendations:"); ImGui::TextColored(ImVec4(1,0.5f,0,1), "⚠️ Recommendations:");
if(ui.parsedSamples.size() < 10) { if(ui.parsedSamples.size() < 10) {
@@ -822,15 +936,17 @@ int main() {
if(ui.lr > 0.01f) { if(ui.lr > 0.01f) {
ImGui::TextColored(ImVec4(1,0.8f,0,1), "• High learning rate! Try 0.001-0.01"); ImGui::TextColored(ImVec4(1,0.8f,0,1), "• High learning rate! Try 0.001-0.01");
} }
// Dataset loading
ImGui::Separator();
ImGui::Text("Dataset File:");
ImGui::InputText("##DSFile", ui.datasetFilePath, 256);
if(ImGui::Button("Load Dataset from File")) { if(ImGui::Button("Load Dataset from File")) {
std::string tempBuffer; // 1. Создаем переменную для загрузки std::string tempBuffer;
if(LoadDatasetFromFile(tempBuffer, ui.datasetFilePath)) { if(LoadDatasetFromFile(tempBuffer, ui.datasetFilePath)) {
// 2. Копируем данные из переменной в буфер ImGui
// Используем strncpy, чтобы не переполнить массив ui.dsBuf
strncpy(ui.dsBuf, tempBuffer.c_str(), sizeof(ui.dsBuf) - 1); strncpy(ui.dsBuf, tempBuffer.c_str(), sizeof(ui.dsBuf) - 1);
ui.dsBuf[sizeof(ui.dsBuf) - 1] = '\0'; // Гарантируем завершение строки нулем ui.dsBuf[sizeof(ui.dsBuf) - 1] = '\0';
// 3. Парсим обновленный буфер
ui.parsedSamples = ParseDataset(ui.dsBuf, tok); ui.parsedSamples = ParseDataset(ui.dsBuf, tok);
ui.datasetLoaded = true; ui.datasetLoaded = true;
std::cout << "Loaded " << ui.parsedSamples.size() << " samples\n"; std::cout << "Loaded " << ui.parsedSamples.size() << " samples\n";
@@ -954,16 +1070,13 @@ int main() {
auto genEndTime = std::chrono::steady_clock::now(); auto genEndTime = std::chrono::steady_clock::now();
double genTime = std::chrono::duration<double>(genEndTime - genStartTime).count(); double genTime = std::chrono::duration<double>(genEndTime - genStartTime).count();
// Добавляем информацию о скорости в лог (опционально)
std::cout << "Generated " << generatedTokens << " tokens in " std::cout << "Generated " << generatedTokens << " tokens in "
<< genTime << "s (" << genTime << "s (" << (generatedTokens/genTime) << " tok/s)\n";
<< (generatedTokens/genTime) << " tok/s)\n";
chat.messages.push_back({"AI", ans}); chat.messages.push_back({"AI", ans});
ui.inputBuf[0]=0; ui.inputBuf[0]=0;
ui.scrollChat=true; ui.scrollChat=true;
} }
} }
ImGui::EndChild(); ImGui::EndChild();