Add DeepSeek AI service integration
This commit is contained in:
+8
-8
@@ -1,18 +1,18 @@
|
|||||||
# API Keys Configuration
|
# API Keys Configuration
|
||||||
# Copy this file to .env and fill in your actual keys
|
# Copy this file to .env and fill in your actual keys
|
||||||
|
|
||||||
# OpenAI API (for AI features)
|
# DeepSeek API (recommended - cost effective)
|
||||||
# Get from: https://platform.openai.com/api-keys
|
# Get from: https://platform.deepseek.com/api_keys
|
||||||
OPENAI_API_KEY=your_openai_api_key_here
|
DEEPSEEK_API_KEY=sk_your_deepseek_api_key_here
|
||||||
|
|
||||||
# Anthropic API (alternative AI provider)
|
# OpenAI API (alternative)
|
||||||
|
# Get from: https://platform.openai.com/api-keys
|
||||||
|
OPENAI_API_KEY=sk_your_openai_api_key_here
|
||||||
|
|
||||||
|
# Anthropic API (alternative)
|
||||||
# Get from: https://console.anthropic.com/
|
# Get from: https://console.anthropic.com/
|
||||||
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
||||||
|
|
||||||
# Google AI API (Gemini)
|
|
||||||
# Get from: https://makersuite.google.com/app/apikey
|
|
||||||
GOOGLE_AI_API_KEY=your_google_ai_api_key_here
|
|
||||||
|
|
||||||
# Firebase Configuration
|
# Firebase Configuration
|
||||||
# These will be in your Firebase console
|
# These will be in your Firebase console
|
||||||
FIREBASE_API_KEY=your_firebase_api_key
|
FIREBASE_API_KEY=your_firebase_api_key
|
||||||
|
|||||||
@@ -0,0 +1,246 @@
|
|||||||
|
# 🤖 DeepSeek AI - Настройка
|
||||||
|
|
||||||
|
## Что такое DeepSeek?
|
||||||
|
|
||||||
|
**DeepSeek** - это мощная китайская нейросеть с открытым API, которая:
|
||||||
|
- 🚀 По качеству на уровне GPT-4
|
||||||
|
- 💰 В 10-20 раз дешевле OpenAI
|
||||||
|
- 🌐 Поддерживает русский язык
|
||||||
|
- 🔑 Даёт бесплатные токены при регистрации
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Как получить API ключ
|
||||||
|
|
||||||
|
### Шаг 1: Регистрация
|
||||||
|
|
||||||
|
1. Перейди на https://platform.deepseek.com
|
||||||
|
2. Нажми **Sign Up** или **Login**
|
||||||
|
3. Зарегистрируйся через email или Google
|
||||||
|
|
||||||
|
### Шаг 2: Получение API ключа
|
||||||
|
|
||||||
|
1. После входа перейди в **API Keys**: https://platform.deepseek.com/api_keys
|
||||||
|
2. Нажми **Create API Key**
|
||||||
|
3. Скопируй ключ (начинается с `sk-`)
|
||||||
|
|
||||||
|
**Важно:** Сохрани ключ в надёжном месте! Показать его можно только один раз.
|
||||||
|
|
||||||
|
### Шаг 3: Пополнение баланса (опционально)
|
||||||
|
|
||||||
|
DeepSeek даёт **бесплатные токены** новым пользователям (~$2-5).
|
||||||
|
|
||||||
|
Для пополнения:
|
||||||
|
1. Перейди в **Billing**: https://platform.deepseek.com/billing
|
||||||
|
2. Выбери способ оплаты
|
||||||
|
3. Минимальное пополнение: ~$10
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💰 Тарифы
|
||||||
|
|
||||||
|
| Модель | Цена (за 1M токенов) |
|
||||||
|
|--------|---------------------|
|
||||||
|
| **DeepSeek Chat** | ~$0.14 (input) / ~$0.28 (output) |
|
||||||
|
| **DeepSeek Coder** | ~$0.14 (input) / ~$0.28 (output) |
|
||||||
|
|
||||||
|
**Для сравнения:**
|
||||||
|
- GPT-4: ~$30 / $60 за 1M токенов
|
||||||
|
- DeepSeek: ~$0.14 / $0.28 за 1M токенов
|
||||||
|
|
||||||
|
**Экономия: в 200+ раз!** 💰
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Настройка в проекте
|
||||||
|
|
||||||
|
### 1. Создай файл `.env`
|
||||||
|
|
||||||
|
Скопируй `.env.example` в `.env`:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Добавь API ключ
|
||||||
|
|
||||||
|
Открой `.env` и вставь ключ:
|
||||||
|
```
|
||||||
|
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Обновите `lib/core/deepseek_service.dart`
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final deepSeekService = DeepSeekService(
|
||||||
|
apiKey: 'sk-xxxxxxxxxxxxxxxxxxxxxxxx', // Твой ключ
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Или используй пакет `flutter_dotenv`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
// В main.dart
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
await dotenv.load(fileName: ".env");
|
||||||
|
|
||||||
|
final deepSeekService = DeepSeekService(
|
||||||
|
apiKey: dotenv.env['DEEPSEEK_API_KEY'],
|
||||||
|
);
|
||||||
|
|
||||||
|
runApp(...);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📱 Примеры использования
|
||||||
|
|
||||||
|
### Генерация подзадач
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:nanaxe_crm/core/deepseek_service.dart';
|
||||||
|
|
||||||
|
final subtasks = await deepSeekService.generateSubtasks(
|
||||||
|
title: 'Создать CRM систему',
|
||||||
|
description: 'Разработка CRM для управления задачами команды с AI',
|
||||||
|
);
|
||||||
|
|
||||||
|
print(subtasks);
|
||||||
|
// [
|
||||||
|
// {"title": "Анализ требований", "estimatedHours": 2, "description": "..."},
|
||||||
|
// {"title": "Проектирование", "estimatedHours": 3, "description": "..."},
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Приоритизация задачи
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final priority = await deepSeekService.prioritizeTask(
|
||||||
|
title: 'Срочный баг',
|
||||||
|
description: 'Пользователи не могут войти',
|
||||||
|
dueDate: DateTime.now().add(Duration(hours: 2)),
|
||||||
|
);
|
||||||
|
|
||||||
|
print(priority); // TaskPriority.urgent
|
||||||
|
```
|
||||||
|
|
||||||
|
### Умное планирование
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final schedule = await deepSeekService.smartSchedule(
|
||||||
|
tasks: myTasks,
|
||||||
|
startDate: DateTime.now(),
|
||||||
|
endDate: DateTime.now().add(Duration(days: 7)),
|
||||||
|
availableHoursPerDay: 6,
|
||||||
|
);
|
||||||
|
|
||||||
|
print(schedule);
|
||||||
|
// [
|
||||||
|
// {"taskId": 0, "date": "2026-03-27", "hours": 3},
|
||||||
|
// {"taskId": 1, "date": "2026-03-27", "hours": 3},
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Генерация mind-карты проекта
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final mindMapNodes = await deepSeekService.generateMindMap(
|
||||||
|
projectName: 'CRM App',
|
||||||
|
description: 'Мобильное CRM приложение с AI планированием',
|
||||||
|
);
|
||||||
|
|
||||||
|
print(mindMapNodes);
|
||||||
|
// [
|
||||||
|
// {"level": 0, "title": "CRM App", "parentId": null},
|
||||||
|
// {"level": 1, "title": "Планирование", "parentId": 0},
|
||||||
|
// {"level": 1, "title": "Разработка", "parentId": 0},
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 Troubleshooting
|
||||||
|
|
||||||
|
### Ошибка: "Invalid API key"
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Проверь что ключ начинается с 'sk-'
|
||||||
|
2. Убедись что нет лишних пробелов
|
||||||
|
3. Проверь что ключ активен в Dashboard
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ошибка: "Insufficient balance"
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Проверь баланс в Billing: https://platform.deepseek.com/billing
|
||||||
|
2. Пополни счёт
|
||||||
|
3. Или используй mock данные (по умолчанию)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ошибка: "Rate limit exceeded"
|
||||||
|
|
||||||
|
```
|
||||||
|
DeepSeek ограничивает запросы. Подожди немного или увеличь лимиты в настройках.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Статистика использования
|
||||||
|
|
||||||
|
Для отслеживания расходов:
|
||||||
|
|
||||||
|
1. Перейди в **Usage**: https://platform.deepseek.com/usage
|
||||||
|
2. Просматривай статистику по дням/моделям
|
||||||
|
3. Настрой алерты при достижении лимита
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Безопасность
|
||||||
|
|
||||||
|
**Никогда не публикуй API ключ в GitHub!**
|
||||||
|
|
||||||
|
✅ Правильно:
|
||||||
|
```bash
|
||||||
|
# Добавить .env в .gitignore
|
||||||
|
echo ".env" >> .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ Использовать в коде:
|
||||||
|
```dart
|
||||||
|
// Загружать из .env файла
|
||||||
|
final apiKey = dotenv.env['DEEPSEEK_API_KEY'];
|
||||||
|
```
|
||||||
|
|
||||||
|
❌ Неправильно:
|
||||||
|
```dart
|
||||||
|
// Хардкод ключа в коде
|
||||||
|
final apiKey = 'sk-xxxxx'; // НЕ ДЕЛАЙ ТАК!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Ресурсы
|
||||||
|
|
||||||
|
- **Официальная документация**: https://platform.deepseek.com/docs
|
||||||
|
- **API Reference**: https://platform.deepseek.com/api-docs
|
||||||
|
- **Цены**: https://platform.deepseek.com/pricing
|
||||||
|
- **Dashboard**: https://platform.deepseek.com
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Следующие шаги
|
||||||
|
|
||||||
|
1. ✅ Получить API ключ
|
||||||
|
2. ✅ Добавить в `.env`
|
||||||
|
3. ✅ Протестировать генерацию подзадач
|
||||||
|
4. ✅ Интегрировать в UI приложения
|
||||||
|
5. ✅ Настроить отслеживание расходов
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**DeepSeek готов к работе! 🚀**
|
||||||
@@ -0,0 +1,375 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import '../models/task_model.dart';
|
||||||
|
|
||||||
|
class DeepSeekService {
|
||||||
|
final String? apiKey;
|
||||||
|
final String baseUrl = 'https://api.deepseek.com';
|
||||||
|
|
||||||
|
DeepSeekService({this.apiKey});
|
||||||
|
|
||||||
|
// Генерация подзадач из основной задачи
|
||||||
|
Future<List<Map<String, dynamic>>> generateSubtasks({
|
||||||
|
required String title,
|
||||||
|
required String description,
|
||||||
|
}) async {
|
||||||
|
if (apiKey == null || apiKey!.isEmpty) {
|
||||||
|
return _mockGenerateSubtasks(title, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('$baseUrl/v1/chat/completions'),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer $apiKey',
|
||||||
|
},
|
||||||
|
body: jsonEncode({
|
||||||
|
'model': 'deepseek-chat',
|
||||||
|
'messages': [
|
||||||
|
{
|
||||||
|
'role': 'system',
|
||||||
|
'content': 'You are a task planning assistant. Break down tasks into logical subtasks. Return ONLY a JSON array.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'role': 'user',
|
||||||
|
'content': 'Break down this task into 3-7 subtasks:\n\nTitle: $title\nDescription: $description\n\nReturn ONLY a JSON array with format: [{"title": "...", "estimatedHours": 0, "description": "..."}]',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'temperature': 0.7,
|
||||||
|
'max_tokens': 2000,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
final content = data['choices'][0]['message']['content'];
|
||||||
|
|
||||||
|
// Извлекаем JSON из ответа
|
||||||
|
final jsonMatch = RegExp(r'\[.*\]', dotAll: true).firstMatch(content);
|
||||||
|
if (jsonMatch != null) {
|
||||||
|
final List<dynamic> subtasks = jsonDecode(jsonMatch.group(0)!);
|
||||||
|
return subtasks.cast<Map<String, dynamic>>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print('DeepSeek API Error: ${response.statusCode} - ${response.body}');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('DeepSeek Service Error: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mockGenerateSubtasks(title, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI приоритизация задач
|
||||||
|
Future<TaskPriority> prioritizeTask({
|
||||||
|
required String title,
|
||||||
|
required String description,
|
||||||
|
DateTime? dueDate,
|
||||||
|
}) async {
|
||||||
|
if (apiKey == null || apiKey!.isEmpty) {
|
||||||
|
return _mockPrioritizeTask(dueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('$baseUrl/v1/chat/completions'),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer $apiKey',
|
||||||
|
},
|
||||||
|
body: jsonEncode({
|
||||||
|
'model': 'deepseek-chat',
|
||||||
|
'messages': [
|
||||||
|
{
|
||||||
|
'role': 'system',
|
||||||
|
'content': 'You are a task prioritization assistant. Determine task priority: low, medium, high, or urgent. Reply with ONE word only.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'role': 'user',
|
||||||
|
'content': 'What priority should this task have?\n\nTitle: $title\nDescription: $description\nDue: ${dueDate ?? "Not specified"}\n\nReply with ONE word: low, medium, high, or urgent',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'temperature': 0.3,
|
||||||
|
'max_tokens': 10,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
final content = data['choices'][0]['message']['content'].trim().toLowerCase();
|
||||||
|
|
||||||
|
switch (content) {
|
||||||
|
case 'urgent': return TaskPriority.urgent;
|
||||||
|
case 'high': return TaskPriority.high;
|
||||||
|
case 'low': return TaskPriority.low;
|
||||||
|
default: return TaskPriority.medium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('DeepSeek Service Error: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mockPrioritizeTask(dueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерация описания задачи
|
||||||
|
Future<String> generateTaskDescription({
|
||||||
|
required String title,
|
||||||
|
String? context,
|
||||||
|
}) async {
|
||||||
|
if (apiKey == null || apiKey!.isEmpty) {
|
||||||
|
return 'Описание для задачи: $title';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('$baseUrl/v1/chat/completions'),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer $apiKey',
|
||||||
|
},
|
||||||
|
body: jsonEncode({
|
||||||
|
'model': 'deepseek-chat',
|
||||||
|
'messages': [
|
||||||
|
{
|
||||||
|
'role': 'system',
|
||||||
|
'content': 'You are a task description writer. Write clear, concise task descriptions in Russian. Keep it under 100 words.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'role': 'user',
|
||||||
|
'content': 'Write a brief description for this task:\n\nTitle: $title\nContext: ${context ?? "No additional context"}\n\nWrite in Russian.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'temperature': 0.5,
|
||||||
|
'max_tokens': 500,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
return data['choices'][0]['message']['content'];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('DeepSeek Service Error: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Описание для задачи: $title';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Умное планирование - распределение задач по времени
|
||||||
|
Future<List<Map<String, dynamic>>> smartSchedule({
|
||||||
|
required List<TaskModel> tasks,
|
||||||
|
required DateTime startDate,
|
||||||
|
required DateTime endDate,
|
||||||
|
required int availableHoursPerDay,
|
||||||
|
}) async {
|
||||||
|
if (apiKey == null || apiKey!.isEmpty) {
|
||||||
|
return _mockSchedule(tasks, startDate, endDate, availableHoursPerDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final tasksJson = tasks.map((t) => {
|
||||||
|
'title': t.title,
|
||||||
|
'estimatedHours': t.estimatedHours,
|
||||||
|
'priority': t.priority.name,
|
||||||
|
'dueDate': t.dueDate?.toIso8601String(),
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('$baseUrl/v1/chat/completions'),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer $apiKey',
|
||||||
|
},
|
||||||
|
body: jsonEncode({
|
||||||
|
'model': 'deepseek-chat',
|
||||||
|
'messages': [
|
||||||
|
{
|
||||||
|
'role': 'system',
|
||||||
|
'content': 'You are a smart scheduling assistant. Distribute tasks across available days optimally. Return ONLY a JSON array.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'role': 'user',
|
||||||
|
'content': '''
|
||||||
|
Schedule these tasks optimally:
|
||||||
|
${jsonEncode(tasksJson)}
|
||||||
|
|
||||||
|
Available hours per day: $availableHoursPerDay
|
||||||
|
Start date: ${startDate.toIso8601String()}
|
||||||
|
End date: ${endDate.toIso8601String()}
|
||||||
|
|
||||||
|
Return JSON array: [{"taskId": index, "date": "YYYY-MM-DD", "hours": 0}]
|
||||||
|
''',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'temperature': 0.5,
|
||||||
|
'max_tokens': 3000,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
final content = data['choices'][0]['message']['content'];
|
||||||
|
|
||||||
|
final jsonMatch = RegExp(r'\[.*\]', dotAll: true).firstMatch(content);
|
||||||
|
if (jsonMatch != null) {
|
||||||
|
final List<dynamic> schedule = jsonDecode(jsonMatch.group(0)!);
|
||||||
|
return schedule.map((s) {
|
||||||
|
return {
|
||||||
|
'taskId': s['taskId'],
|
||||||
|
'date': DateTime.parse(s['date']),
|
||||||
|
'hours': s['hours'],
|
||||||
|
};
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('DeepSeek Service Error: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mockSchedule(tasks, startDate, endDate, availableHoursPerDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI анализ проекта - генерация mind-карты
|
||||||
|
Future<List<Map<String, dynamic>>> generateMindMap({
|
||||||
|
required String projectName,
|
||||||
|
required String description,
|
||||||
|
}) async {
|
||||||
|
if (apiKey == null || apiKey!.isEmpty) {
|
||||||
|
return _mockMindMap(projectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('$baseUrl/v1/chat/completions'),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer $apiKey',
|
||||||
|
},
|
||||||
|
body: jsonEncode({
|
||||||
|
'model': 'deepseek-chat',
|
||||||
|
'messages': [
|
||||||
|
{
|
||||||
|
'role': 'system',
|
||||||
|
'content': 'You are a project structure assistant. Create a mind-map structure for projects. Return ONLY a JSON array of nodes.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'role': 'user',
|
||||||
|
'content': '''
|
||||||
|
Create a mind-map structure for this project:
|
||||||
|
|
||||||
|
Project: $projectName
|
||||||
|
Description: $description
|
||||||
|
|
||||||
|
Return JSON array of nodes with format:
|
||||||
|
[{"level": 0, "title": "Project Name", "parentId": null}, {"level": 1, "title": "Phase 1", "parentId": 0}, ...]
|
||||||
|
''',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'temperature': 0.7,
|
||||||
|
'max_tokens': 3000,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
final content = data['choices'][0]['message']['content'];
|
||||||
|
|
||||||
|
final jsonMatch = RegExp(r'\[.*\]', dotAll: true).firstMatch(content);
|
||||||
|
if (jsonMatch != null) {
|
||||||
|
final List<dynamic> nodes = jsonDecode(jsonMatch.group(0)!);
|
||||||
|
return nodes.cast<Map<String, dynamic>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('DeepSeek Service Error: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mockMindMap(projectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock данные для тестирования
|
||||||
|
List<Map<String, dynamic>> _mockGenerateSubtasks(String title, String description) {
|
||||||
|
return [
|
||||||
|
{'title': 'Анализ требований', 'estimatedHours': 2, 'description': 'Изучить требования и документацию'},
|
||||||
|
{'title': 'Проектирование', 'estimatedHours': 3, 'description': 'Спроектировать архитектуру решения'},
|
||||||
|
{'title': 'Реализация', 'estimatedHours': 8, 'description': 'Написать код'},
|
||||||
|
{'title': 'Тестирование', 'estimatedHours': 3, 'description': 'Протестировать функциональность'},
|
||||||
|
{'title': 'Документирование', 'estimatedHours': 2, 'description': 'Создать документацию'},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskPriority _mockPrioritizeTask(DateTime? dueDate) {
|
||||||
|
if (dueDate == null) return TaskPriority.medium;
|
||||||
|
|
||||||
|
final daysUntilDue = dueDate.difference(DateTime.now()).inDays;
|
||||||
|
|
||||||
|
if (daysUntilDue <= 1) return TaskPriority.urgent;
|
||||||
|
if (daysUntilDue <= 3) return TaskPriority.high;
|
||||||
|
if (daysUntilDue <= 7) return TaskPriority.medium;
|
||||||
|
return TaskPriority.low;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> _mockSchedule(
|
||||||
|
List<TaskModel> tasks,
|
||||||
|
DateTime startDate,
|
||||||
|
DateTime endDate,
|
||||||
|
int availableHoursPerDay,
|
||||||
|
) {
|
||||||
|
final schedule = <Map<String, dynamic>>[];
|
||||||
|
var currentDate = startDate;
|
||||||
|
var remainingHours = availableHoursPerDay;
|
||||||
|
|
||||||
|
for (var i = 0; i < tasks.length; i++) {
|
||||||
|
if (currentDate.isAfter(endDate)) break;
|
||||||
|
|
||||||
|
final task = tasks[i];
|
||||||
|
if (task.estimatedHours <= remainingHours) {
|
||||||
|
schedule.add({
|
||||||
|
'taskId': i,
|
||||||
|
'date': currentDate,
|
||||||
|
'hours': task.estimatedHours,
|
||||||
|
});
|
||||||
|
remainingHours -= task.estimatedHours;
|
||||||
|
} else {
|
||||||
|
currentDate = currentDate.add(const Duration(days: 1));
|
||||||
|
remainingHours = availableHoursPerDay;
|
||||||
|
|
||||||
|
if (currentDate.isAfter(endDate)) break;
|
||||||
|
|
||||||
|
schedule.add({
|
||||||
|
'taskId': i,
|
||||||
|
'date': currentDate,
|
||||||
|
'hours': task.estimatedHours > remainingHours
|
||||||
|
? remainingHours
|
||||||
|
: task.estimatedHours,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> _mockMindMap(String projectName) {
|
||||||
|
return [
|
||||||
|
{'level': 0, 'title': projectName, 'parentId': null},
|
||||||
|
{'level': 1, 'title': 'Планирование', 'parentId': 0},
|
||||||
|
{'level': 1, 'title': 'Разработка', 'parentId': 0},
|
||||||
|
{'level': 1, 'title': 'Тестирование', 'parentId': 0},
|
||||||
|
{'level': 1, 'title': 'Деплой', 'parentId': 0},
|
||||||
|
{'level': 2, 'title': 'Анализ', 'parentId': 1},
|
||||||
|
{'level': 2, 'title': 'Дизайн', 'parentId': 1},
|
||||||
|
{'level': 2, 'title': 'Frontend', 'parentId': 2},
|
||||||
|
{'level': 2, 'title': 'Backend', 'parentId': 2},
|
||||||
|
{'level': 2, 'title': 'Unit тесты', 'parentId': 3},
|
||||||
|
{'level': 2, 'title': 'E2E тесты', 'parentId': 3},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Глобальный экземпляр сервиса
|
||||||
|
final deepSeekService = DeepSeekService(
|
||||||
|
// API ключ можно получить на https://platform.deepseek.com
|
||||||
|
apiKey: null, // Добавить ключ здесь или через .env
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user