feat: Add Nanaxe server with Docker, GitHub Actions CI/CD, and auto-deployment
- Add complete server infrastructure with Gitea, API, PostgreSQL - Implement Obsidian-compatible markdown mindmap converter - Add Flutter service for server synchronization - Configure GitHub Actions for automated build and deploy - Add production docker-compose with health checks - Include VPS setup and deployment scripts - Add comprehensive deployment documentation
This commit is contained in:
@@ -7,14 +7,95 @@ class DeepSeekService {
|
||||
final String? apiKey;
|
||||
final String baseUrl = 'https://api.deepseek.com';
|
||||
|
||||
// 🎯 РЕЖИМ MOCK - установите true для работы без API запросов
|
||||
// Когда пополните баланс DeepSeek, установите false
|
||||
final bool useMockMode = true;
|
||||
|
||||
DeepSeekService({this.apiKey});
|
||||
|
||||
// AI чат для mind maps
|
||||
Future<Map<String, dynamic>> chatCompletion({
|
||||
required List<Map<String, dynamic>> messages,
|
||||
}) async {
|
||||
if (useMockMode || apiKey == null || apiKey!.isEmpty) {
|
||||
return _mockChatResponse(messages);
|
||||
}
|
||||
|
||||
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': messages,
|
||||
'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) {
|
||||
return jsonDecode(jsonMatch.group(0)!) as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
return {'text': content};
|
||||
} else {
|
||||
print('DeepSeek API Error: ${response.statusCode} - ${response.body}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('DeepSeek Service Error: $e');
|
||||
}
|
||||
|
||||
return _mockChatResponse(messages);
|
||||
}
|
||||
|
||||
// Mock ответ для чата
|
||||
Map<String, dynamic> _mockChatResponse(List<Map<String, dynamic>> messages) {
|
||||
final lastMessage = messages.lastWhere(
|
||||
(m) => m['role'] == 'user',
|
||||
orElse: () => {'content': ''},
|
||||
);
|
||||
final content = lastMessage['content'] as String;
|
||||
|
||||
// Простая логика для демонстрации
|
||||
if (content.toLowerCase().contains('добавь') ||
|
||||
content.toLowerCase().contains('add')) {
|
||||
return {
|
||||
'ACTION': 'add',
|
||||
'TARGET': null,
|
||||
'CHANGES': [
|
||||
{
|
||||
'action': 'add',
|
||||
'title': 'AI Предложение: $content',
|
||||
'level': 0,
|
||||
'parentId': null
|
||||
},
|
||||
],
|
||||
'EXPLANATION': 'Я добавил новый узел на основе вашего запроса',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
'text':
|
||||
'Понял ваш запрос: "$content". В реальном режиме я предложу изменения для mind map.',
|
||||
};
|
||||
}
|
||||
|
||||
// Генерация подзадач из основной задачи
|
||||
Future<List<Map<String, dynamic>>> generateSubtasks({
|
||||
required String title,
|
||||
required String description,
|
||||
}) async {
|
||||
if (apiKey == null || apiKey!.isEmpty) {
|
||||
// Возвращаем mock данные пока нет баланса на DeepSeek
|
||||
if (useMockMode || apiKey == null || apiKey!.isEmpty) {
|
||||
return _mockGenerateSubtasks(title, description);
|
||||
}
|
||||
|
||||
@@ -56,9 +137,11 @@ class DeepSeekService {
|
||||
}
|
||||
} else {
|
||||
print('DeepSeek API Error: ${response.statusCode} - ${response.body}');
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
} catch (e) {
|
||||
print('DeepSeek Service Error: $e');
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
|
||||
return _mockGenerateSubtasks(title, description);
|
||||
@@ -70,7 +153,8 @@ class DeepSeekService {
|
||||
required String description,
|
||||
DateTime? dueDate,
|
||||
}) async {
|
||||
if (apiKey == null || apiKey!.isEmpty) {
|
||||
// Возвращаем mock данные пока нет баланса на DeepSeek
|
||||
if (useMockMode || apiKey == null || apiKey!.isEmpty) {
|
||||
return _mockPrioritizeTask(dueDate);
|
||||
}
|
||||
|
||||
@@ -115,9 +199,12 @@ class DeepSeekService {
|
||||
default:
|
||||
return TaskPriority.medium;
|
||||
}
|
||||
} else {
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
} catch (e) {
|
||||
print('DeepSeek Service Error: $e');
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
|
||||
return _mockPrioritizeTask(dueDate);
|
||||
@@ -128,8 +215,9 @@ class DeepSeekService {
|
||||
required String title,
|
||||
String? context,
|
||||
}) async {
|
||||
if (apiKey == null || apiKey!.isEmpty) {
|
||||
return 'Описание для задачи: $title';
|
||||
// Возвращаем mock данные пока нет баланса на DeepSeek
|
||||
if (useMockMode || apiKey == null || apiKey!.isEmpty) {
|
||||
return _mockGenerateDescription(title, context);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -161,12 +249,15 @@ class DeepSeekService {
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
return data['choices'][0]['message']['content'];
|
||||
} else {
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
} catch (e) {
|
||||
print('DeepSeek Service Error: $e');
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
|
||||
return 'Описание для задачи: $title';
|
||||
return _mockGenerateDescription(title, context);
|
||||
}
|
||||
|
||||
// Умное планирование - распределение задач по времени
|
||||
@@ -176,7 +267,8 @@ class DeepSeekService {
|
||||
required DateTime endDate,
|
||||
required int availableHoursPerDay,
|
||||
}) async {
|
||||
if (apiKey == null || apiKey!.isEmpty) {
|
||||
// Возвращаем mock данные пока нет баланса на DeepSeek
|
||||
if (useMockMode || apiKey == null || apiKey!.isEmpty) {
|
||||
return _mockSchedule(tasks, startDate, endDate, availableHoursPerDay);
|
||||
}
|
||||
|
||||
@@ -238,9 +330,12 @@ Return JSON array: [{"taskId": index, "date": "YYYY-MM-DD", "hours": 0}]
|
||||
};
|
||||
}).toList();
|
||||
}
|
||||
} else {
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
} catch (e) {
|
||||
print('DeepSeek Service Error: $e');
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
|
||||
return _mockSchedule(tasks, startDate, endDate, availableHoursPerDay);
|
||||
@@ -251,7 +346,8 @@ Return JSON array: [{"taskId": index, "date": "YYYY-MM-DD", "hours": 0}]
|
||||
required String projectName,
|
||||
required String description,
|
||||
}) async {
|
||||
if (apiKey == null || apiKey!.isEmpty) {
|
||||
// Возвращаем mock данные пока нет баланса на DeepSeek
|
||||
if (useMockMode || apiKey == null || apiKey!.isEmpty) {
|
||||
return _mockMindMap(projectName);
|
||||
}
|
||||
|
||||
@@ -297,9 +393,12 @@ Return JSON array of nodes with format:
|
||||
final List<dynamic> nodes = jsonDecode(jsonMatch.group(0)!);
|
||||
return nodes.cast<Map<String, dynamic>>();
|
||||
}
|
||||
} else {
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
} catch (e) {
|
||||
print('DeepSeek Service Error: $e');
|
||||
print('⚠️ Используется mock режим как fallback');
|
||||
}
|
||||
|
||||
return _mockMindMap(projectName);
|
||||
@@ -348,6 +447,24 @@ Return JSON array of nodes with format:
|
||||
return TaskPriority.low;
|
||||
}
|
||||
|
||||
String _mockGenerateDescription(String title, String? context) {
|
||||
final descriptions = {
|
||||
'Анализ требований':
|
||||
'Изучить и проанализировать все требования проекта. Подготовить документацию с детальным описанием функционала и ожиданий пользователей.',
|
||||
'Проектирование':
|
||||
'Разработать архитектуру решения, создать схемы базы данных и определить основные компоненты системы.',
|
||||
'Реализация':
|
||||
'Написать чистый, поддерживаемый код согласно лучшим практикам. Реализовать весь запланированный функционал.',
|
||||
'Тестирование':
|
||||
'Провести комплексное тестирование: модульные, интеграционные и end-to-end тесты для обеспечения качества.',
|
||||
'Деплой':
|
||||
'Подготовить инфраструктуру, настроить CI/CD пайплайн и развернуть приложение на production сервере.',
|
||||
};
|
||||
|
||||
return descriptions[title] ??
|
||||
'Задача: $title. ${context ?? "Выполнить в срок с надлежащим качеством."}';
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _mockSchedule(
|
||||
List<TaskModel> tasks,
|
||||
DateTime startDate,
|
||||
|
||||
Reference in New Issue
Block a user