diff --git a/paint/sources/nodes_neural/neural_node_models.c b/paint/sources/nodes_neural/neural_node_models.c index 3f251cb1..00056adc 100644 --- a/paint/sources/nodes_neural/neural_node_models.c +++ b/paint/sources/nodes_neural/neural_node_models.c @@ -57,16 +57,15 @@ void neural_node_models_init() { .license = "hunyuan3d"}), GC_ALLOC_INIT(neural_node_model_t, {.name = "Qwen", - .memory = "16GB", - .size = "15.7GB", + .memory = "20GB", + .size = "15.3GB", .nodes = "Text to Text, Console", .urls = any_array_create_from_raw( (void *[]){ - "https://huggingface.co/unsloth/Qwen3.6-27B-GGUF/resolve/main/Qwen3.6-27B-Q4_K_M.gguf", - // "https://huggingface.co/unsloth/Qwen3.6-27B-GGUF/resolve/main/mmproj-F16.gguf", + "https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/main/Qwen3.8-27B-UD-Q4_K_M.gguf", }, 1), - .web = "https://huggingface.co/unsloth/Qwen3.6-27B-GGUF", + .web = "https://huggingface.co/unsloth/Qwen3.8-27B-GGUF", .license = "apache-2.0"}), }, 5); diff --git a/paint/sources/nodes_neural/text_to_text_node.c b/paint/sources/nodes_neural/text_to_text_node.c index 513f69eb..107cf227 100644 --- a/paint/sources/nodes_neural/text_to_text_node.c +++ b/paint/sources/nodes_neural/text_to_text_node.c @@ -4,7 +4,8 @@ static i32 text_to_text_node_backend = CONSOLE_MODEL_QWEN; static char *text_to_text_node_guide = "Reply with C code only wrapped in a ```c markdown fence. Place the code inside 'void main()' function. " - "Do not chain statements - declare intermediary variables. Do not use preprocessor."; + "Do not chain statements - declare intermediary variables. Do not use preprocessor. " + "Do not use casts - casting is implicit. Do not use comma operator. Do not use multi-dimensional arrays.\n"; static char *text_to_text_node_grok_dir(void) { #ifndef NDEBUG @@ -94,25 +95,91 @@ static char *text_to_text_node_project_contents(void) { return string("/* Current project state:\n%s\n%s%s*/\n", json, text_to_text_node_scene_bounds(), text_to_text_node_shapes()); } +static void text_to_text_node_write_sockets(buffer_t *sb, char *label, ui_node_socket_t_array_t *sockets) { + if (sockets == NULL || sockets->length == 0) { + return; + } + string_buffer_append(sb, string(" | %s:", label)); + for (i32 i = 0; i < sockets->length; ++i) { + string_buffer_append(sb, string("%s %d %s", i > 0 ? "," : "", i, sockets->buffer[i]->name)); + } +} + +static void text_to_text_node_write_node(buffer_t *sb, ui_node_t *n) { + string_buffer_append(sb, string("// %s", n->type)); + text_to_text_node_write_sockets(sb, "in", n->inputs); + text_to_text_node_write_sockets(sb, "out", n->outputs); + string_buffer_append(sb, "\n"); + + for (i32 i = 0; i < n->buttons->length; ++i) { + ui_node_button_t *b = n->buttons->buffer[i]; + string_buffer_append(sb, string("// button %d %s %s", i, b->name, b->type)); + if (string_equals(b->type, "ENUM") && b->data != NULL) { + any_array_t *options = string_split(u8_array_to_string(b->data), "\n"); + for (i32 j = 0; j < options->length; ++j) { + string_buffer_append(sb, string("%s %d %s", j > 0 ? "," : ":", j, (char *)options->buffer[j])); + } + } + string_buffer_append(sb, "\n"); + } +} + +static char *text_to_text_node_nodes_reference(void) { + buffer_t sb; + string_buffer_init(&sb); + + nodes_material_init(); + + string_buffer_append(&sb, "// Material nodes reference:\n"); + + for (i32 i = 0; i < nodes_material_list->length; ++i) { + ui_node_t_array_t *c = (ui_node_t_array_t *)nodes_material_list->buffer[i]; + for (i32 j = 0; j < c->length; ++j) { + text_to_text_node_write_node(&sb, c->buffer[j]); + } + } + + ui_node_canvas_t *canvas = g_context != NULL && g_context->material != NULL ? g_context->material->canvas : NULL; + if (canvas != NULL) { + for (i32 i = 0; i < canvas->nodes->length; ++i) { + if (string_equals(canvas->nodes->buffer[i]->type, "OUTPUT_MATERIAL_PBR")) { + string_buffer_append(&sb, "//\n// Pre-created material output node:\n"); + text_to_text_node_write_node(&sb, canvas->nodes->buffer[i]); + break; + } + } + } + + char *result = string_copy(string_buffer_get(&sb)); + string_buffer_free(&sb); + return result; +} + string_array_t *text_to_text_node_qwen_args(char *dir) { char *prompt_file = string("%s%sprompt.txt", dir, PATH_SEP); string_array_t *argv = any_array_create_from_raw( (void *[]){ string("%s/%s", dir, neural_node_llama_bin()), "-m", - string("%s/Qwen3.6-27B-Q4_K_M.gguf", dir), + string("%s/Qwen3.8-27B-UD-Q4_K_M.gguf", dir), "-ngl", "99", "-c", - "20000", + "65536", + "--temp", + "1.0", + "--top-p", + "0.95", + "--top-k", + "20", + "--min-p", + "0.0", "--single-turn", - "--prompt-cache", - string("%s/context.bin", dir), "--file", prompt_file, NULL, }, - 13); + 19); return argv; } @@ -180,7 +247,6 @@ void text_to_text_node_check_result(void (*done)(char *)) { void text_to_text_node_clear(void) { char *dir = neural_node_dir(); iron_delete_file(string("%s%sprompt.txt", dir, PATH_SEP)); - iron_delete_file(string("%s%scontext.bin", dir, PATH_SEP)); iron_delete_file(string("%s%soutput.txt", dir, PATH_SEP)); iron_delete_file(string("%s%sapi.h", dir, PATH_SEP)); char *gdir = text_to_text_node_grok_dir(); @@ -196,8 +262,9 @@ void text_to_text_node_run(char *prompt, void (*done)(char *)) { text_to_text_node_backend = g_config->console_model; char *api = minic_api_header_generate(); + char *nodes = text_to_text_node_nodes_reference(); char *contents = text_to_text_node_project_contents(); - char *reference = string("%s\n%s\n%s\n", api, contents, text_to_text_node_guide); + char *reference = string("%s\n%s\n%s\n%s\n", api, nodes, contents, text_to_text_node_guide); string_array_t *argv; if (text_to_text_node_backend == CONSOLE_MODEL_CLAUDE) {