feat: Add Focus Tools (ADHD-friendly productivity features)
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
- Add Focus Tools dashboard with collapsible help section - Implement Quick Wins page for tasks under 15 minutes - Add Single Task Focus mode to reduce overwhelm - Create Body Doubling page for virtual co-working - Add visual timer, break reminders, and energy tracking - Implement hyperfocus protection alerts - Add ADHD settings panel with customizable options - Include full English and German translations - Fix larger touch targets CSS to not break button layouts - Add Playwright tests for Focus Tools features
This commit is contained in:
@@ -738,6 +738,88 @@ Format:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Break down a large task into smaller, manageable subtasks for ADHD users.
|
||||
*/
|
||||
async breakdownTask(task: { title: string; description?: string; estimatedDuration?: number }): Promise<{
|
||||
subtasks: { title: string; estimatedMinutes: number; order: number }[];
|
||||
totalEstimatedMinutes: number;
|
||||
encouragement: string;
|
||||
}> {
|
||||
const provider = await this.storage.getSystemSettings("ai_provider") || "openai";
|
||||
const apiKey = await this.storage.getSystemSettings("ai_api_key");
|
||||
const model = await this.storage.getSystemSettings("ai_model") || "gpt-4o";
|
||||
const baseUrl = await this.storage.getSystemSettings("ai_base_url");
|
||||
|
||||
// Default fallback if AI is not configured
|
||||
if (!apiKey && provider !== "ollama") {
|
||||
return {
|
||||
subtasks: [
|
||||
{ title: `Start: ${task.title}`, estimatedMinutes: 5, order: 1 },
|
||||
{ title: `Continue: ${task.title}`, estimatedMinutes: 10, order: 2 },
|
||||
{ title: `Finish: ${task.title}`, estimatedMinutes: 5, order: 3 },
|
||||
],
|
||||
totalEstimatedMinutes: 20,
|
||||
encouragement: "Du schaffst das! Nimm dir einen Schritt nach dem anderen vor.",
|
||||
};
|
||||
}
|
||||
|
||||
const prompt = `Du bist ein ADHS-Coach. Der Nutzer hat eine überwältigende Aufgabe, die in kleinere Schritte zerlegt werden muss.
|
||||
|
||||
Aufgabe: "${task.title}"
|
||||
${task.description ? `Beschreibung: "${task.description}"` : ''}
|
||||
${task.estimatedDuration ? `Geschätzte Dauer: ${task.estimatedDuration} Minuten` : ''}
|
||||
|
||||
Zerlege diese Aufgabe in 3-7 kleine, konkrete Schritte.
|
||||
Jeder Schritt sollte:
|
||||
- In 5-15 Minuten erledigt werden können
|
||||
- Eine klare, aktionsorientierte Beschreibung haben (auf Deutsch)
|
||||
- Einen konkreten Endpunkt haben
|
||||
|
||||
Antworte NUR mit einem JSON-Objekt. Keine Markdown-Formatierung.
|
||||
Format:
|
||||
{
|
||||
"subtasks": [
|
||||
{ "title": "Schritt beschreibung", "estimatedMinutes": 5, "order": 1 },
|
||||
...
|
||||
],
|
||||
"totalEstimatedMinutes": number,
|
||||
"encouragement": "Eine ermutigende Nachricht auf Deutsch"
|
||||
}`;
|
||||
|
||||
const messages: ChatMessage[] = [
|
||||
{ role: "system", content: "Du bist ein hilfreicher ADHS-Coach. Antworte nur mit validem JSON." },
|
||||
{ role: "user", content: prompt }
|
||||
];
|
||||
|
||||
try {
|
||||
let responseText = "";
|
||||
if (provider === "openai" || provider === "ollama") {
|
||||
responseText = await this.chatOpenAI(provider, apiKey || "", model, baseUrl, messages, undefined, []);
|
||||
} else if (provider === "anthropic") {
|
||||
responseText = await this.chatAnthropic(apiKey || "", model, messages);
|
||||
} else if (provider === "google") {
|
||||
responseText = await this.chatGemini(apiKey || "", model, messages);
|
||||
}
|
||||
|
||||
// Clean response
|
||||
const cleanJson = responseText.replace(/```json/g, '').replace(/```/g, '').trim();
|
||||
return JSON.parse(cleanJson);
|
||||
} catch (error) {
|
||||
console.error("AI Breakdown Error:", error);
|
||||
// Fallback
|
||||
return {
|
||||
subtasks: [
|
||||
{ title: `Schritt 1: ${task.title} vorbereiten`, estimatedMinutes: 5, order: 1 },
|
||||
{ title: `Schritt 2: ${task.title} durchführen`, estimatedMinutes: 10, order: 2 },
|
||||
{ title: `Schritt 3: ${task.title} abschließen`, estimatedMinutes: 5, order: 3 },
|
||||
],
|
||||
totalEstimatedMinutes: 20,
|
||||
encouragement: "Jeder kleine Schritt zählt! Du machst das großartig.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async chatAnthropic(apiKey: string, model: string, messages: any[]): Promise<string> {
|
||||
const systemMessage = messages.find(m => m.role === "system")?.content || "";
|
||||
const userAssistantMessages = messages.filter(m => m.role !== "system");
|
||||
|
||||
Reference in New Issue
Block a user