ruby_todo 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +60 -75
- data/ai_assistant_implementation.md +1 -1
- data/lib/ruby_todo/ai_assistant/command_processor.rb +127 -0
- data/lib/ruby_todo/ai_assistant/openai_integration.rb +178 -183
- data/lib/ruby_todo/ai_assistant/param_extractor.rb +64 -0
- data/lib/ruby_todo/ai_assistant/prompt_builder.rb +95 -0
- data/lib/ruby_todo/ai_assistant/task_creator.rb +161 -0
- data/lib/ruby_todo/cli.rb +128 -469
- data/lib/ruby_todo/commands/ai_assistant.rb +752 -287
- data/lib/ruby_todo/commands/ai_commands.rb +20 -0
- data/lib/ruby_todo/commands/notebook_commands.rb +39 -0
- data/lib/ruby_todo/commands/template_commands.rb +139 -0
- data/lib/ruby_todo/concerns/import_export.rb +138 -0
- data/lib/ruby_todo/concerns/statistics.rb +166 -0
- data/lib/ruby_todo/concerns/task_filters.rb +39 -0
- data/lib/ruby_todo/formatters/display_formatter.rb +80 -0
- data/lib/ruby_todo/models/task.rb +0 -7
- data/lib/ruby_todo/version.rb +1 -1
- data/lib/ruby_todo.rb +9 -0
- metadata +13 -8
- data/.env.template +0 -2
- data/lib/ruby_todo/ai_assistant/common_query_handler.rb +0 -378
- data/lib/ruby_todo/ai_assistant/task_management.rb +0 -331
- data/lib/ruby_todo/ai_assistant/task_search.rb +0 -365
- data/test_ai_assistant.rb +0 -55
- data/test_migration.rb +0 -55
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyTodo
|
4
|
+
module AIAssistant
|
5
|
+
# Module for natural language task creation
|
6
|
+
module TaskCreator
|
7
|
+
# Handle natural language task creation
|
8
|
+
def handle_natural_language_task_creation(prompt, api_key)
|
9
|
+
# Get the default notebook
|
10
|
+
notebook_name = default_notebook_name
|
11
|
+
|
12
|
+
# Extract task description from prompt
|
13
|
+
task_description = extract_task_description(prompt)
|
14
|
+
|
15
|
+
# Generate task details using AI
|
16
|
+
task_details = generate_task_details(task_description, api_key)
|
17
|
+
|
18
|
+
# Create the task
|
19
|
+
create_task_from_details(notebook_name, task_details)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the default notebook name or fallback to "default"
|
23
|
+
def default_notebook_name
|
24
|
+
default_notebook = RubyTodo::Notebook.default_notebook
|
25
|
+
default_notebook ? default_notebook.name : "default"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Extract task description from the prompt
|
29
|
+
def extract_task_description(prompt)
|
30
|
+
if prompt =~ /create(?:\s+a)?\s+(?:new\s+)?task\s+(?:to|for|about)\s+(.+)/i
|
31
|
+
Regexp.last_match(1).strip
|
32
|
+
else
|
33
|
+
""
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Generate task details using AI
|
38
|
+
def generate_task_details(task_description, api_key)
|
39
|
+
# Build the query for AI
|
40
|
+
task_query = build_task_query(task_description)
|
41
|
+
|
42
|
+
# Query OpenAI for task details
|
43
|
+
content = query_openai_for_task_details(task_query, api_key)
|
44
|
+
|
45
|
+
# Parse the response
|
46
|
+
parse_task_details_response(content, task_description)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Build the query to send to OpenAI
|
50
|
+
def build_task_query(task_description)
|
51
|
+
"Generate a professional task with the following information:\n" \
|
52
|
+
"Task description: #{task_description}\n" \
|
53
|
+
"Please generate a JSON response with these fields:\n" \
|
54
|
+
"- title: A concise, professional title for the task\n" \
|
55
|
+
"- description: A detailed description of what the task involves\n" \
|
56
|
+
"- priority: Suggested priority (high, medium, or low)\n" \
|
57
|
+
"- tags: Relevant tags as a comma-separated string"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Module for OpenAI query related to task creation
|
62
|
+
module TaskOpenAIQuery
|
63
|
+
# Query OpenAI for task details
|
64
|
+
def query_openai_for_task_details(task_query, api_key)
|
65
|
+
client = OpenAI::Client.new(access_token: api_key)
|
66
|
+
messages = [
|
67
|
+
{ role: "system", content: "You are a task management assistant that generates professional task details." },
|
68
|
+
{ role: "user", content: task_query }
|
69
|
+
]
|
70
|
+
|
71
|
+
say "Generating professional task details..." if @options[:verbose]
|
72
|
+
|
73
|
+
response = client.chat(parameters: {
|
74
|
+
model: "gpt-4o-mini",
|
75
|
+
messages: messages,
|
76
|
+
temperature: 0.7,
|
77
|
+
max_tokens: 500
|
78
|
+
})
|
79
|
+
|
80
|
+
response["choices"][0]["message"]["content"]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Module for parsing and processing AI responses
|
85
|
+
module TaskResponseProcessor
|
86
|
+
# Parse the OpenAI response for task details
|
87
|
+
def parse_task_details_response(content, task_description)
|
88
|
+
# Try to extract JSON from the response
|
89
|
+
json_match = content.match(/```json\n(.+?)\n```/m) || content.match(/\{.+\}/m)
|
90
|
+
if json_match
|
91
|
+
json_str = json_match[0].gsub(/```json\n|```/, "")
|
92
|
+
JSON.parse(json_str)
|
93
|
+
else
|
94
|
+
extract_task_details_with_regex(content, task_description)
|
95
|
+
end
|
96
|
+
rescue JSON::ParserError
|
97
|
+
extract_task_details_with_regex(content, task_description)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Extract task details using regex as a fallback
|
101
|
+
def extract_task_details_with_regex(content, task_description)
|
102
|
+
title_match = content.match(/title["\s:]+([^"]+)["]/i)
|
103
|
+
desc_match = content.match(/description["\s:]+([^"]+)["]/i)
|
104
|
+
priority_match = content.match(/priority["\s:]+([^"]+)["]/i)
|
105
|
+
tags_match = content.match(/tags["\s:]+([^"]+)["]/i)
|
106
|
+
|
107
|
+
{
|
108
|
+
"title" => title_match ? title_match[1] : "Task from #{task_description}",
|
109
|
+
"description" => desc_match ? desc_match[1] : task_description,
|
110
|
+
"priority" => priority_match ? priority_match[1] : "medium",
|
111
|
+
"tags" => tags_match ? tags_match[1] : ""
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
# Create a task from the generated details
|
116
|
+
def create_task_from_details(notebook_name, task_details)
|
117
|
+
# Ensure we have a valid notebook
|
118
|
+
notebook = RubyTodo::Notebook.find_by(name: notebook_name)
|
119
|
+
unless notebook
|
120
|
+
# Try to create the notebook if it doesn't exist
|
121
|
+
RubyTodo::CLI.start(["notebook:create", notebook_name])
|
122
|
+
notebook = RubyTodo::Notebook.find_by(name: notebook_name)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Use default notebook as fallback if we couldn't create or find the specified one
|
126
|
+
unless notebook
|
127
|
+
default_notebook = RubyTodo::Notebook.default_notebook
|
128
|
+
notebook_name = default_notebook ? default_notebook.name : "default"
|
129
|
+
# Create default notebook if it doesn't exist
|
130
|
+
unless RubyTodo::Notebook.find_by(name: notebook_name)
|
131
|
+
RubyTodo::CLI.start(["notebook:create", notebook_name])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
args = ["task:add", notebook_name, task_details["title"]]
|
136
|
+
args << "--description" << task_details["description"] if task_details["description"]
|
137
|
+
args << "--priority" << task_details["priority"] if task_details["priority"]
|
138
|
+
args << "--tags" << task_details["tags"] if task_details["tags"]
|
139
|
+
|
140
|
+
RubyTodo::CLI.start(args)
|
141
|
+
rescue StandardError => e
|
142
|
+
say "Error creating task: #{e.message}".red
|
143
|
+
say "Attempting simplified task creation...".yellow
|
144
|
+
|
145
|
+
# Fallback to simplified command
|
146
|
+
begin
|
147
|
+
RubyTodo::CLI.start(["task:add", notebook_name, task_details["title"]])
|
148
|
+
rescue StandardError => e2
|
149
|
+
say "Failed to create task: #{e2.message}".red
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Include all task creation modules
|
155
|
+
module TaskCreatorCombined
|
156
|
+
include TaskCreator
|
157
|
+
include TaskOpenAIQuery
|
158
|
+
include TaskResponseProcessor
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|