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:
2026-04-19 22:18:25 +05:00
parent 52aea9ac87
commit f1e0f6b5ef
56 changed files with 8892 additions and 397 deletions
+349
View File
@@ -0,0 +1,349 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
// Простой тест DeepSeek API без Flutter зависимостей
void main() async {
const apiKey = 'sk-6600b6bee68745aa88b076b0c3393638';
const baseUrl = 'https://api.deepseek.com';
print('🧪 Тестирование DeepSeek API...\n');
print('=' * 60);
// Тест 1: Проверка API ключа (простой запрос)
print('\n📝 Тест 1: Проверка API ключа');
print('-' * 60);
await testApiKey(apiKey, baseUrl);
// Тест 2: Генерация подзадач
print('\n📋 Тест 2: Генерация подзадач');
print('-' * 60);
await testGenerateSubtasks(apiKey, baseUrl);
// Тест 3: Приоритизация задачи
print('\n🎯 Тест 3: Приоритизация задачи');
print('-' * 60);
await testPrioritizeTask(apiKey, baseUrl);
// Тест 4: Генерация описания
print('\n✍️ Тест 4: Генерация описания задачи');
print('-' * 60);
await testGenerateDescription(apiKey, baseUrl);
// Тест 5: Генерация mind-карты
print('️ Тест 5: Генерация mind-карты');
print('-' * 60);
await testGenerateMindMap(apiKey, baseUrl);
// Тест 6: Умное планирование
print('\n📅 Тест 6: Умное планирование');
print('-' * 60);
await testSmartSchedule(apiKey, baseUrl);
print('\n${'=' * 60}');
print('✅ Тестирование завершено!');
print('=' * 60);
}
// Тест 1: Проверка API ключа
Future<void> testApiKey(String apiKey, String baseUrl) async {
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': 'user',
'content': 'Привет! Скажи "API работает отлично!"',
},
],
'max_tokens': 50,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final message = data['choices'][0]['message']['content'];
print('✅ API ключ валиден!');
print('💬 Ответ: $message');
print('📊 Использовано токенов: ${data['usage']['total_tokens']}');
} else {
print('❌ Ошибка: ${response.statusCode}');
print('📄 Ответ: ${response.body}');
}
} catch (e) {
print('❌ Исключение: $e');
}
}
// Тест 2: Генерация подзадач
Future<void> testGenerateSubtasks(String apiKey, String baseUrl) async {
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: Создать CRM систему\nDescription: Разработка CRM для управления задачами команды с AI планированием\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'];
print('✅ Подзадачи сгенерированы!');
print('📊 Использовано токенов: ${data['usage']['total_tokens']}');
print('\n📝 Результат:');
// Пытаемся распарсить JSON
final jsonMatch = RegExp(r'\[.*\]', dotAll: true).firstMatch(content);
if (jsonMatch != null) {
final List<dynamic> subtasks = jsonDecode(jsonMatch.group(0)!);
for (int i = 0; i < subtasks.length; i++) {
final task = subtasks[i];
print('\n${i + 1}. ${task['title']}');
print(' ⏱️ Часы: ${task['estimatedHours']}');
print(' 📄 ${task['description']}');
}
} else {
print(content);
}
} else {
print('❌ Ошибка: ${response.statusCode}');
print('📄 Ответ: ${response.body}');
}
} catch (e) {
print('❌ Исключение: $e');
}
}
// Тест 3: Приоритизация задачи
Future<void> testPrioritizeTask(String apiKey, String baseUrl) async {
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: Срочный баг - пользователи не могут войти\nDescription: Критическая ошибка авторизации, все пользователи заблокированы\nDue: 2026-04-09T12:00:00\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 priority = data['choices'][0]['message']['content'].trim().toLowerCase();
print('✅ Приоритизация выполнена!');
print('📊 Использовано токенов: ${data['usage']['total_tokens']}');
print('🎯 Приоритет: ${priority.toUpperCase()}');
} else {
print('❌ Ошибка: ${response.statusCode}');
print('📄 Ответ: ${response.body}');
}
} catch (e) {
print('❌ Исключение: $e');
}
}
// Тест 4: Генерация описания
Future<void> testGenerateDescription(String apiKey, String baseUrl) async {
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: Интеграция с Google Calendar\nContext: Синхронизация событий между CRM и Google Calendar\n\nWrite in Russian.',
},
],
'temperature': 0.5,
'max_tokens': 500,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final description = data['choices'][0]['message']['content'];
print('✅ Описание сгенерировано!');
print('📊 Использовано токенов: ${data['usage']['total_tokens']}');
print('\n📝 Описание:\n$description');
} else {
print('❌ Ошибка: ${response.statusCode}');
print('📄 Ответ: ${response.body}');
}
} catch (e) {
print('❌ Исключение: $e');
}
}
// Тест 5: Генерация mind-карты
Future<void> testGenerateMindMap(String apiKey, String baseUrl) async {
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: CRM App
Description: Мобильное CRM приложение с AI планированием, mind-картами и интеграцией с календарем
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'];
print('✅ Mind-карта сгенерирована!');
print('📊 Использовано токенов: ${data['usage']['total_tokens']}');
// Пытаемся распарсить JSON
final jsonMatch = RegExp(r'\[.*\]', dotAll: true).firstMatch(content);
if (jsonMatch != null) {
final List<dynamic> nodes = jsonDecode(jsonMatch.group(0)!);
print('\n🗺️ Структура mind-карты:');
for (final node in nodes) {
final indent = ' ' * (node['level'] as int);
print('$indent${node['level'] == 0 ? '📌' : '└'} ${node['title']}');
}
} else {
print('\n📝 Результат:\n$content');
}
} else {
print('❌ Ошибка: ${response.statusCode}');
print('📄 Ответ: ${response.body}');
}
} catch (e) {
print('❌ Исключение: $e');
}
}
// Тест 6: Умное планирование
Future<void> testSmartSchedule(String apiKey, String baseUrl) async {
try {
final tasks = [
{'title': 'Анализ требований', 'estimatedHours': 4, 'priority': 'high'},
{'title': 'Проектирование', 'estimatedHours': 6, 'priority': 'high'},
{'title': 'Frontend разработка', 'estimatedHours': 12, 'priority': 'medium'},
{'title': 'Backend разработка', 'estimatedHours': 10, 'priority': 'medium'},
{'title': 'Тестирование', 'estimatedHours': 5, 'priority': 'high'},
];
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(tasks)}
Available hours per day: 6
Start date: 2026-04-09
End date: 2026-04-16
Return JSON array: [{"taskId": index, "taskName": "name", "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'];
print('✅ Планирование выполнено!');
print('📊 Использовано токенов: ${data['usage']['total_tokens']}');
// Пытаемся распарсить JSON
final jsonMatch = RegExp(r'\[.*\]', dotAll: true).firstMatch(content);
if (jsonMatch != null) {
final List<dynamic> schedule = jsonDecode(jsonMatch.group(0)!);
print('\n📅 Расписание:');
for (final item in schedule) {
print(' 📆 ${item['date']}: ${item['taskName'] ?? item['taskId']} (${item['hours']}ч)');
}
} else {
print('\n📝 Результат:\n$content');
}
} else {
print('❌ Ошибка: ${response.statusCode}');
print('📄 Ответ: ${response.body}');
}
} catch (e) {
print('❌ Исключение: $e');
}
}