Spaces:
Runtime error
Runtime error
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdbool.h> | |
| #include <ctype.h> | |
| #define MAX_COMMAND_LEN 4096 | |
| #define MAX_DIRECTIVES 16 | |
| #define MAX_VALUE_LEN 1024 | |
| typedef enum { | |
| UI_NONE, | |
| UI_STREAMLIT, | |
| UI_GRADIO, | |
| UI_HTML | |
| } UiShell; | |
| typedef enum { | |
| MEDIA_NONE, | |
| MEDIA_TEXT_TO_IMAGE, | |
| MEDIA_IMAGE_TO_IMAGE, | |
| MEDIA_IMAGE_TO_VIDEO, | |
| MEDIA_TEXT_TO_VIDEO | |
| } MediaType; | |
| typedef struct { | |
| char main_prompt[MAX_COMMAND_LEN]; | |
| UiShell ui_shell; | |
| bool web_search_enabled; | |
| char model_id[MAX_VALUE_LEN]; | |
| struct { | |
| MediaType type; | |
| char prompt[MAX_COMMAND_LEN]; | |
| } media_ops[MAX_DIRECTIVES]; | |
| int media_count; | |
| char url_redesign[MAX_VALUE_LEN]; | |
| char source_image[MAX_VALUE_LEN]; | |
| char reference_doc[MAX_VALUE_LEN]; | |
| char others[MAX_DIRECTIVES][MAX_VALUE_LEN]; | |
| int other_count; | |
| } CommandSpec; | |
| typedef struct { | |
| char message[MAX_VALUE_LEN]; | |
| char type[32]; // "missing-url", "missing-image", "unknown-directive", "empty-value" | |
| } Validation; | |
| // Helper: trim whitespace from start and end of string | |
| void trim(char *str) { | |
| char *end; | |
| while (isspace(*str)) str++; | |
| if (*str == '\0') return; | |
| end = str + strlen(str) - 1; | |
| while (end > str && isspace(*end)) end--; | |
| *(end + 1) = '\0'; | |
| } | |
| // Helper: check if string starts with prefix (case-insensitive) | |
| bool starts_with(const char *str, const char *prefix) { | |
| size_t len = strlen(prefix); | |
| if (strlen(str) < len) return false; | |
| for (size_t i = 0; i < len; i++) { | |
| if (tolower(str[i]) != tolower(prefix[i])) return false; | |
| } | |
| return true; | |
| } | |
| // Helper: extract value after colon (trim whitespace) | |
| char* extract_value(const char *directive) { | |
| char *colon = strchr(directive, ':'); | |
| if (!colon) return NULL; | |
| char *value = colon + 1; | |
| while (*value && isspace(*value)) value++; | |
| return value; | |
| } | |
| // Split command by top-level commas (ignore commas inside URLs) | |
| int split_command(const char *input, char *parts[], int max_parts) { | |
| int count = 0; | |
| char *buf = strdup(input); | |
| char *ptr = buf; | |
| bool in_url = false; | |
| char quote = '\0'; | |
| for (int i = 0; ptr[i] != '\0'; i++) { | |
| if (ptr[i] == '"' || ptr[i] == '\'') { | |
| if (quote == '\0') quote = ptr[i]; | |
| else if (quote == ptr[i]) quote = '\0'; | |
| } | |
| if (quote == '\0' && ptr[i] == ':' && i > 0 && ptr[i-1] == 'h') { | |
| // Look ahead for http(s):// | |
| if (i >= 4 && strncmp(&ptr[i-4], "http", 4) == 0) in_url = true; | |
| } | |
| if (quote == '\0' && !in_url && ptr[i] == ',' && i > 0 && ptr[i-1] != '\\') { | |
| ptr[i] = '\0'; | |
| if (count < max_parts) { | |
| parts[count] = ptr; | |
| trim(parts[count]); | |
| count++; | |
| } | |
| ptr = &ptr[i+1]; | |
| i = -1; // reset to re-check from start of new segment | |
| } | |
| if (in_url && ptr[i] == ' ') in_url = false; // URL ends at space | |
| } | |
| if (count < max_parts && strlen(ptr) > 0) { | |
| parts[count] = ptr; | |
| trim(parts[count]); | |
| count++; | |
| } | |
| free(buf); | |
| return count; | |
| } | |
| // Parse a single directive | |
| bool parse_directive(const char *directive, CommandSpec *spec) { | |
| char lower_dir[1024]; | |
| strcpy(lower_dir, directive); | |
| for (int i = 0; lower_dir[i]; i++) lower_dir[i] = tolower(lower_dir[i]); | |
| if (starts_with(lower_dir, "use streamlit")) { | |
| spec->ui_shell = UI_STREAMLIT; | |
| return true; | |
| } | |
| if (starts_with(lower_dir, "use gradio")) { | |
| spec->ui_shell = UI_GRADIO; | |
| return true; | |
| } | |
| if (starts_with(lower_dir, "use html")) { | |
| spec->ui_shell = UI_HTML; | |
| return true; | |
| } | |
| if (starts_with(lower_dir, "enable web search")) { | |
| spec->web_search_enabled = true; | |
| return true; | |
| } | |
| if (starts_with(lower_dir, "disable web search")) { | |
| spec->web_search_enabled = false; | |
| return true; | |
| } | |
| if (starts_with(lower_dir, "model:")) { | |
| char *val = extract_value(directive); | |
| if (val && strlen(val) > 0) { | |
| strncpy(spec->model_id, val, MAX_VALUE_LEN - 1); | |
| spec->model_id[MAX_VALUE_LEN - 1] = '\0'; | |
| return true; | |
| } else { | |
| return false; // empty value | |
| } | |
| } | |
| if (starts_with(lower_dir, "redesign ")) { | |
| char *url = extract_value(directive); | |
| if (url && strlen(url) > 0) { | |
| strncpy(spec->url_redesign, url, MAX_VALUE_LEN - 1); | |
| spec->url_redesign[MAX_VALUE_LEN - 1] = '\0'; | |
| return true; | |
| } else { | |
| return false; // missing URL | |
| } | |
| } | |
| if (starts_with(lower_dir, "generate images:")) { | |
| if (spec->media_count < MAX_DIRECTIVES) { | |
| char *prompt = extract_value(directive); | |
| if (prompt && strlen(prompt) > 0) { | |
| spec->media_ops[spec->media_count].type = MEDIA_TEXT_TO_IMAGE; | |
| strncpy(spec->media_ops[spec->media_count].prompt, prompt, MAX_COMMAND_LEN - 1); | |
| spec->media_ops[spec->media_count].prompt[MAX_COMMAND_LEN - 1] = '\0'; | |
| spec->media_count++; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| if (starts_with(lower_dir, "image to image:")) { | |
| if (spec->media_count < MAX_DIRECTIVES) { | |
| char *prompt = extract_value(directive); | |
| if (prompt && strlen(prompt) > 0) { | |
| spec->media_ops[spec->media_count].type = MEDIA_IMAGE_TO_IMAGE; | |
| strncpy(spec->media_ops[spec->media_count].prompt, prompt, MAX_COMMAND_LEN - 1); | |
| spec->media_ops[spec->media_count].prompt[MAX_COMMAND_LEN - 1] = '\0'; | |
| spec->media_count++; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| if (starts_with(lower_dir, "image to video:")) { | |
| if (spec->media_count < MAX_DIRECTIVES) { | |
| char *prompt = extract_value(directive); | |
| if (prompt && strlen(prompt) > 0) { | |
| spec->media_ops[spec->media_count].type = MEDIA_IMAGE_TO_VIDEO; | |
| strncpy(spec->media_ops[spec->media_count].prompt, prompt, MAX_COMMAND_LEN - 1); | |
| spec->media_ops[spec->media_count].prompt[MAX_COMMAND_LEN - 1] = '\0'; | |
| spec->media_count++; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| if (starts_with(lower_dir, "text to video:")) { | |
| if (spec->media_count < MAX_DIRECTIVES) { | |
| char *prompt = extract_value(directive); | |
| if (prompt && strlen(prompt) > 0) { | |
| spec->media_ops[spec->media_count].type = MEDIA_TEXT_TO_VIDEO; | |
| strncpy(spec->media_ops[spec->media_count].prompt, prompt, MAX_COMMAND_LEN - 1); | |
| spec->media_ops[spec->media_count].prompt[MAX_COMMAND_LEN - 1] = '\0'; | |
| spec->media_count++; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // Unknown directive - treat as part of main prompt (non-fatal) | |
| return false; | |
| } | |
| // Parse entire command string into CommandSpec | |
| CommandSpec parse_command(const char *input) { | |
| CommandSpec spec = {0}; | |
| strcpy(spec.main_prompt, input); | |
| char *parts[MAX_DIRECTIVES + 1]; | |
| int n = split_command(input, parts, MAX_DIRECTIVES + 1); | |
| if (n == 0) return spec; | |
| // First part is main prompt (unless it's a redesign) | |
| bool found_redesign = false; | |
| for (int i = 0; i < n; i++) { | |
| if (starts_with(parts[i], "redesign ")) { | |
| parse_directive(parts[i], &spec); | |
| found_redesign = true; | |
| } | |
| } | |
| if (!found_redesign) { | |
| // Extract main prompt as everything before first directive | |
| char *first = parts[0]; | |
| if (strlen(first) > 0) { | |
| strncpy(spec.main_prompt, first, MAX_COMMAND_LEN - 1); | |
| spec.main_prompt[MAX_COMMAND_LEN - 1] = '\0'; | |
| } | |
| } | |
| // Parse modifiers | |
| for (int i = 0; i < n; i++) { | |
| if (starts_with(parts[i], "redesign ")) continue; // Already handled | |
| if (!parse_directive(parts[i], &spec)) { | |
| // Unknown directive — do nothing (per spec: non-fatal, kept in main prompt) | |
| } | |
| } | |
| // Default model if not set | |
| if (strlen(spec.model_id) == 0) { | |
| strcpy(spec.model_id, "default-model"); | |
| } | |
| return spec; | |
| } | |
| // Validate command against attachments (simplified mock) | |
| Validation validate_command(CommandSpec *spec, bool has_source_image) { | |
| Validation v = {0}; | |
| if (strlen(spec->url_redesign) > 0 && !strstr(spec->url_redesign, "http")) { | |
| strcpy(v.message, "URL required for redesign"); | |
| strcpy(v.type, "missing-url"); | |
| return v; | |
| } | |
| for (int i = 0; i < spec->media_count; i++) { | |
| if ((spec->media_ops[i].type == MEDIA_IMAGE_TO_IMAGE || spec->media_ops[i].type == MEDIA_IMAGE_TO_VIDEO) && !has_source_image) { | |
| strcpy(v.message, "No source image attached"); | |
| strcpy(v.type, "missing-image"); | |
| return v; | |
| } | |
| } | |
| // No errors | |
| v.type[0] = '\0'; | |
| return v; | |
| } | |
| // Apply command to system state (mock implementation) | |
| void apply_command(CommandSpec *spec) { | |
| printf("[APPLYING COMMAND]\n"); | |
| printf("Main Prompt: %s\n", spec->main_prompt); | |
| printf("UI Shell: "); | |
| switch (spec->ui_shell) { | |
| case UI_STREAMLIT: printf("Streamlit\n"); break; | |
| case UI_GRADIO: printf("Gradio\n"); break; | |
| case UI_HTML: printf("HTML\n"); break; | |
| default: printf("None\n"); break; | |
| } | |
| printf("Web Search: %s\n", spec->web_search_enabled ? "Enabled" : "Disabled"); | |
| printf("Model: %s\n", spec->model_id); | |
| if (strlen(spec->url_redesign) > 0) { | |
| printf("Redesign URL: %s\n", spec->url_redesign); | |
| } | |
| for (int i = 0; i < spec->media_count; i++) { | |
| char *type_str = "unknown"; | |
| switch (spec->media_ops[i].type) { | |
| case MEDIA_TEXT_TO_IMAGE: type_str = "Text→Image"; break; | |
| case MEDIA_IMAGE_TO_IMAGE: type_str = "Image→Image"; break; | |
| case MEDIA_IMAGE_TO_VIDEO: type_str = "Image→Video"; break; | |
| case MEDIA_TEXT_TO_VIDEO: type_str = "Text→Video"; break; | |
| } | |
| printf("Media: %s → \"%s\"\n", type_str, spec->media_ops[i].prompt); | |
| } | |
| } | |
| // Main CLI entry point | |
| int main() { | |
| char command[MAX_COMMAND_LEN]; | |
| printf("Command Palette DSL (Type 'quit' to exit)\n"); | |
| while (true) { | |
| printf("> "); | |
| if (!fgets(command, sizeof(command), stdin)) break; | |
| command[strcspn(command, "\n")] = 0; // remove newline | |
| if (strcmp(command, "quit") == 0) break; | |
| CommandSpec spec = parse_command(command); | |
| Validation validation = validate_command(&spec, false); // Mock: no image attached | |
| if (validation.type[0] != '\0') { | |
| printf("❌ Validation Error: [%s] %s\n", validation.type, validation.message); | |
| } | |
| apply_command(&spec); | |
| printf("\n"); | |
| } | |
| return 0; | |
| } |