ваше сообщение коммита

This commit is contained in:
2025-04-21 10:40:57 +03:00
parent f371521511
commit 16c3534239
22 changed files with 637 additions and 84 deletions

50
.gitignore vendored Normal file
View File

@@ -0,0 +1,50 @@
# Зависимости
node_modules/
/.pnp
.pnp.js
# Логи
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Файлы окружения
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
backend/.env
frontend/.env
# Файлы сборки
/dist
/build
/out
# Кэши и временные файлы
.cache/
.temp/
.DS_Store
.idea/
.vscode/
*.swp
*.swo
# Docker тома
/data
# Приватные ключи и сертификаты
*.pem
*.key
# Локальные настройки
.prettierrc.local
.eslintrc.local
# Файлы базы данных
*.db
*.sqlite
*.sqlite3

93
README.md Normal file
View File

@@ -0,0 +1,93 @@
# DApp-for-Business
Бизнес-платформа для работы с блокчейн и интеграцией ИИ.
## Требования
- Docker и Docker Compose
- Git
## Быстрый запуск
Чтобы запустить проект одной командой, выполните следующие шаги:
1. Клонируйте репозиторий:
```bash
git clone https://github.com/yourusername/DApp-for-Business.git
cd DApp-for-Business
```
2. Настройте переменные окружения:
```bash
# Создайте файлы .env из примеров
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.env
# Отредактируйте файлы .env с вашими настройками
nano backend/.env
nano frontend/.env
```
3. Запустите скрипт установки:
```bash
./setup.sh
```
Скрипт автоматически:
- Проверит наличие Docker и Docker Compose
- Запустит PostgreSQL в контейнере
- Запустит Ollama и загрузит модель qwen2.5:7b
- Запустит backend и frontend сервисы
- Выведет адреса для доступа к сервисам
## Доступные сервисы
После успешного запуска вы получите доступ к следующим сервисам:
- Frontend: http://localhost:5173
- Backend API: http://localhost:8000
- Ollama API: http://localhost:11434
- PostgreSQL: localhost:5432 (по умолчанию dapp_db/dapp_user/dapp_password)
## Ручной запуск
Если вы хотите запустить проект вручную:
```bash
# Запуск в фоновом режиме
docker compose up -d
# Запуск с логами
docker compose up
# Остановка сервисов
docker compose down
# Остановка сервисов и удаление томов
docker compose down -v
```
## Безопасность
По умолчанию проект настроен с базовыми учетными данными для разработки. Перед использованием в продакшене:
1. **Измените все пароли и ключи в .env файлах**
2. **Не публикуйте .env файлы в репозитории** (они добавлены в .gitignore)
3. **Обновите SESSION_SECRET для защиты сессий**
4. **Используйте безопасные пароли для базы данных**
5. **Настройте SSL/TLS для продакшен-окружения**
## Переменные окружения
Основные переменные, которые следует настроить:
- `DB_USER`, `DB_PASSWORD` - учетные данные для базы данных
- `SESSION_SECRET` - секрет для шифрования сессий
- `PRIVATE_KEY` - приватный ключ для подписи транзакций
- `EMAIL_*` - настройки почтового сервера
- `TELEGRAM_BOT_TOKEN` - токен для Telegram бота
## Примечания
- Загрузка модели qwen2.5:7b может занять некоторое время в зависимости от скорости интернета
- Для использования GPU Ollama требуются установленные драйверы NVIDIA и nvidia-container-toolkit

41
backend/.env.example Normal file
View File

@@ -0,0 +1,41 @@
PORT=8000
NODE_ENV=development
SESSION_SECRET=your_session_secret
# RPC URLs
RPC_URL_ETH=https://your-ethereum-rpc-url
RPC_URL_POLYGON=https://your-polygon-rpc-url
RPC_URL_BSC=https://your-bsc-rpc-url
RPC_URL_ARBITRUM=https://your-arbitrum-rpc-url
RPC_URL=https://your-default-rpc-url
ETHEREUM_NETWORK_URL=https://your-ethereum-network-url
PRIVATE_KEY=your_private_key_here
ETHERSCAN_API_KEY=your_etherscan_api_key
# Database
DATABASE_URL=postgresql://dapp_user:dapp_password@postgres:5432/dapp_db
DB_HOST=postgres
DB_PORT=5432
DB_NAME=dapp_db
DB_USER=dapp_user
DB_PASSWORD=dapp_password
# Email Configuration
EMAIL_USER=your_email@example.com
EMAIL_PASSWORD=your_email_password
EMAIL_SMTP_HOST=smtp.example.com
EMAIL_SMTP_PORT=465
EMAIL_IMAP_HOST=imap.example.com
EMAIL_IMAP_PORT=993
# Ollama AI Configuration
OLLAMA_BASE_URL=http://ollama:11434
OLLAMA_EMBEDDINGS_MODEL=qwen2.5:7b
OLLAMA_MODEL=qwen2.5:7b
# Telegram Bot
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
TELEGRAM_BOT_USERNAME=your_bot_username
# Frontend URL
FRONTEND_URL=http://localhost:5173

69
backend/.gitignore vendored
View File

@@ -1,45 +1,44 @@
# Зависимости
node_modules/
yarn-error.log
# Переменные окружения
.env
.env.local
.env.development
.env.test
.env.production
/.pnp
.pnp.js
# Логи
logs/*
!logs/.gitkeep
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Кэш и временные файлы
# Файлы окружения
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Кэши и временные файлы
.cache/
cache/
dist/
build/
tmp/
temp/
# Артефакты Hardhat
artifacts/
cache/
typechain/
typechain-types/
# Файлы покрытия кода
coverage/
coverage.json
# Файлы IDE
.temp/
.DS_Store
.idea/
.vscode/
*.sublime-project
*.sublime-workspace
*.swp
*.swo
# Системные файлы
.DS_Store
Thumbs.db
# Compiled output
/dist
/build
# Файлы сессий
sessions/
# Приватные ключи и сертификаты
*.pem
*.key
# Локальные настройки
.prettierrc.local
.eslintrc.local
# Файлы базы данных
*.db
*.sqlite
*.sqlite3

21
backend/Dockerfile Normal file
View File

@@ -0,0 +1,21 @@
FROM node:20-alpine
WORKDIR /app
# Устанавливаем зависимости, включая Python для node-gyp
RUN apk add --no-cache python3 make g++
# Копируем package.json и yarn.lock для установки зависимостей
COPY package.json yarn.lock ./
# Устанавливаем зависимости
RUN yarn install --frozen-lockfile
# Копируем остальные файлы проекта
COPY . .
# Экспозим порт
EXPOSE 8000
# Команда запуска по умолчанию
CMD ["yarn", "run", "dev"]

View File

@@ -22,7 +22,7 @@ const tokensRouter = require('./routes/tokens');
const app = express();
// Указываем хост явно
app.set('host', '127.0.0.1');
app.set('host', '0.0.0.0');
app.set('port', process.env.PORT || 8000);
// Настройка CORS

View File

@@ -1,6 +1,14 @@
const { Pool } = require('pg');
require('dotenv').config();
// Выводим настройки подключения (без пароля)
console.log('Настройки подключения к базе данных:');
console.log('DATABASE_URL:', process.env.DATABASE_URL?.replace(/:([^:@]+)@/, ':***@'));
console.log('DB_HOST:', process.env.DB_HOST);
console.log('DB_PORT:', process.env.DB_PORT);
console.log('DB_NAME:', process.env.DB_NAME);
console.log('DB_USER:', process.env.DB_USER);
// Создаем пул соединений с базой данных
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
@@ -11,10 +19,30 @@ const pool = new Pool({
pool.query('SELECT NOW()', (err, res) => {
if (err) {
console.error('Ошибка подключения к базе данных:', err);
console.log('Переключение на временное хранилище данных в памяти...');
// Если не удалось подключиться к базе данных, используем временное хранилище
module.exports = createInMemoryStorage();
// Пробуем альтернативное подключение
console.log('Попытка альтернативного подключения через прямые параметры...');
const altPool = new Pool({
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432'),
database: process.env.DB_NAME || 'dapp_db',
user: process.env.DB_USER || 'dapp_user',
password: process.env.DB_PASSWORD,
});
altPool.query('SELECT NOW()', (altErr, altRes) => {
if (altErr) {
console.error('Альтернативное подключение тоже не удалось:', altErr);
console.log('Переключение на временное хранилище данных в памяти...');
module.exports = createInMemoryStorage();
} else {
console.log('Альтернативное подключение успешно:', altRes.rows[0]);
// Заменяем основной пул на альтернативный
module.exports.pool = altPool;
module.exports.query = (text, params) => altPool.query(text, params);
}
});
} else {
console.log('Успешное подключение к базе данных:', res.rows[0]);
}

View File

@@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS messages (
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
role VARCHAR(20) NOT NULL DEFAULT 'user',
guest_message_id INTEGER,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
tokens_used INTEGER DEFAULT 0,
is_processed BOOLEAN DEFAULT FALSE
);
@@ -18,3 +18,4 @@ CREATE INDEX IF NOT EXISTS idx_messages_sender_type ON messages(sender_type);
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at);
CREATE INDEX IF NOT EXISTS idx_messages_channel ON messages(channel);
CREATE INDEX IF NOT EXISTS idx_messages_metadata ON messages USING gin(metadata);
CREATE INDEX IF NOT EXISTS idx_messages_user_id ON messages(user_id);

View File

@@ -53,7 +53,7 @@ BEGIN
content,
role,
channel,
guest_message_id,
user_id,
created_at
)
SELECT
@@ -63,14 +63,16 @@ BEGIN
content,
CASE WHEN is_ai THEN 'assistant' ELSE 'user' END,
'chat',
id, -- Сохраняем связь с гостевым сообщением
p_user_id,
created_at
FROM guest_messages
WHERE guest_id = p_guest_id
-- Проверка, чтобы избежать дублирования сообщений
-- Проверка, чтобы избежать дублирования сообщений на основе содержимого и времени
AND NOT EXISTS (
SELECT 1 FROM messages m
WHERE m.guest_message_id = guest_messages.id
WHERE m.conversation_id = v_conversation_id
AND m.content = guest_messages.content
AND m.created_at = guest_messages.created_at
)
ORDER BY created_at
RETURNING id

View File

0
backend/logs/error.log Normal file
View File

View File

@@ -18,8 +18,8 @@ async function checkOllamaModels() {
});
console.log('\nДля использования конкретной модели, укажите ее в .env файле:');
console.log('OLLAMA_EMBEDDINGS_MODEL=mistral:7b-instruct-q4_K_M');
console.log('OLLAMA_MODEL=mistral:7b-instruct-q4_K_M');
console.log('OLLAMA_EMBEDDINGS_MODEL=qwen2.5');
console.log('OLLAMA_MODEL=qwen2.5');
} else {
console.log('Не удалось получить список моделей');
}

View File

@@ -0,0 +1,17 @@
#!/bin/bash
set -e
host="$1"
shift
port="$1"
shift
cmd="$@"
until PGPASSWORD=$DB_PASSWORD psql -h "$host" -U "$DB_USER" -p "$port" -d "$DB_NAME" -c '\q'; do
>&2 echo "Ожидание подключения к PostgreSQL..."
sleep 1
done
>&2 echo "PostgreSQL запущен - выполнение команды"
exec $cmd

View File

@@ -7,7 +7,7 @@ const fetch = require('node-fetch');
class AIAssistant {
constructor() {
this.baseUrl = process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
this.defaultModel = process.env.OLLAMA_MODEL || 'mistral:7b-instruct-q4_K_M';
this.defaultModel = process.env.OLLAMA_MODEL || 'qwen2.5';
}
// Создание экземпляра ChatOllama с нужными параметрами

99
docker-compose.yml Normal file
View File

@@ -0,0 +1,99 @@
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: dapp-postgres
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${DB_NAME:-dapp_db}
POSTGRES_USER: ${DB_USER:-dapp_user}
POSTGRES_PASSWORD: ${DB_PASSWORD:-dapp_password}
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-dapp_user} -d ${DB_NAME:-dapp_db}"]
interval: 5s
timeout: 5s
retries: 5
ollama:
image: ollama/ollama:latest
container_name: dapp-ollama
restart: unless-stopped
volumes:
- ollama_data:/root/.ollama
ports:
- "11434:11434"
command: serve
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: dapp-backend
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ollama:
condition: service_started
volumes:
- ./backend:/app
- backend_node_modules:/app/node_modules
environment:
- NODE_ENV=${NODE_ENV:-development}
- PORT=${PORT:-8000}
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=${DB_NAME:-dapp_db}
- DB_USER=${DB_USER:-dapp_user}
- DB_PASSWORD=${DB_PASSWORD:-dapp_password}
- DATABASE_URL=postgresql://${DB_USER:-dapp_user}:${DB_PASSWORD:-dapp_password}@postgres:5432/${DB_NAME:-dapp_db}
- OLLAMA_BASE_URL=http://ollama:11434
- OLLAMA_MODEL=${OLLAMA_MODEL:-qwen2.5:7b}
- OLLAMA_EMBEDDINGS_MODEL=${OLLAMA_EMBEDDINGS_MODEL:-qwen2.5:7b}
- FRONTEND_URL=http://localhost:5173
ports:
- "8000:8000"
command: sh -c "yarn run dev"
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: dapp-frontend
restart: unless-stopped
depends_on:
- backend
volumes:
- ./frontend:/app
- frontend_node_modules:/app/node_modules
ports:
- "5173:5173"
command: yarn run dev -- --host 0.0.0.0
ollama-setup:
image: curlimages/curl:latest
container_name: dapp-ollama-setup
depends_on:
- ollama
restart: on-failure
command: |
sh -c "
echo 'Waiting for Ollama to be ready...'
until curl -s http://ollama:11434/api/tags >/dev/null; do
sleep 5
done
echo 'Ollama is ready, pulling qwen2.5-7b model...'
curl -X POST http://ollama:11434/api/pull -d '{\"name\":\"${OLLAMA_MODEL:-qwen2.5:7b}\"}' -H 'Content-Type: application/json'
echo 'Done!'
"
volumes:
postgres_data:
ollama_data:
backend_node_modules:
frontend_node_modules:

3
frontend/.env.example Normal file
View File

@@ -0,0 +1,3 @@
VITE_APP_ETHEREUM_NETWORK_URL=https://your-ethereum-network-url
VITE_API_URL=http://localhost:8000

61
frontend/.gitignore vendored
View File

@@ -1,23 +1,7 @@
# Зависимости
node_modules/
yarn-error.log
# Переменные окружения
.env
.env.local
.env.development
.env.test
.env.production
# Сборка
dist/
dist-ssr/
build/
# Кэш
.cache/
.temp/
.vite/
/.pnp
.pnp.js
# Логи
logs/
@@ -25,21 +9,36 @@ logs/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Файлы IDE
.idea/
.vscode/*
!.vscode/extensions.json
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Файлы окружения
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Системные файлы
# Кэши и временные файлы
.cache/
.temp/
.DS_Store
Thumbs.db
.idea/
.vscode/
*.swp
*.swo
# Локальные файлы
# Файлы сборки
/dist
/dist-ssr
/build
*.local
# Тесты
/coverage
# Приватные ключи и сертификаты
*.pem
*.key
# Локальные настройки
.prettierrc.local
.eslintrc.local

21
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,21 @@
FROM node:20-alpine
WORKDIR /app
# Устанавливаем дополнительные зависимости
RUN apk add --no-cache python3 make g++
# Копируем package.json и yarn.lock для установки зависимостей
COPY package.json yarn.lock ./
# Устанавливаем зависимости
RUN yarn install --frozen-lockfile
# Копируем остальные файлы проекта
COPY . .
# Экспозим порт
EXPOSE 5173
# Команда запуска по умолчанию
CMD ["yarn", "run", "dev"]

28
frontend/nginx.conf Normal file
View File

@@ -0,0 +1,28 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Поддержка SPA (Single Page Application)
location / {
try_files $uri $uri/ /index.html;
}
# Настройка кеширования для статических файлов
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# Настройка для API запросов на бэкенд
location /api/ {
proxy_pass http://backend:8000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

View File

@@ -1,8 +1,18 @@
import axios from 'axios';
// Определяем baseURL в зависимости от окружения
const getBaseUrl = () => {
// В браузере используем localhost
if (typeof window !== 'undefined' && window.location.hostname === 'localhost') {
return 'http://localhost:8000';
}
// В других случаях используем переменную окружения
return import.meta.env.VITE_API_URL || '';
};
// Создаем экземпляр axios с базовым URL
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || '',
baseURL: getBaseUrl(),
withCredentials: true,
headers: {
'Content-Type': 'application/json'

View File

@@ -7,7 +7,9 @@ import router from './router';
import axios from 'axios';
// Настройка axios
axios.defaults.baseURL = import.meta.env.VITE_API_URL || '';
// В Docker контейнере localhost:8000 не работает, поэтому используем явное значение
const apiUrl = window.location.hostname === 'localhost' ? 'http://localhost:8000' : import.meta.env.VITE_API_URL;
axios.defaults.baseURL = apiUrl;
axios.defaults.withCredentials = true;
// Создаем и монтируем приложение Vue
@@ -25,7 +27,7 @@ app.use(router);
// ]).catch(err => console.error('Failed to load API mocks:', err));
// }
console.log('API URL:', import.meta.env.VITE_API_URL);
console.log('API URL:', apiUrl);
console.log('main.js: Starting application with router');
app.mount('#app');

139
setup.sh Executable file
View File

@@ -0,0 +1,139 @@
#!/bin/bash
# Вывод цветного текста
print_green() {
echo -e "\e[32m$1\e[0m"
}
print_blue() {
echo -e "\e[34m$1\e[0m"
}
print_yellow() {
echo -e "\e[33m$1\e[0m"
}
print_red() {
echo -e "\e[31m$1\e[0m"
}
# Проверка установки Docker и Docker Compose
check_docker() {
print_blue "Проверка наличия Docker..."
if ! command -v docker &> /dev/null; then
print_yellow "Docker не установлен. Установите Docker перед запуском."
print_yellow "Инструкции по установке: https://docs.docker.com/get-docker/"
exit 1
fi
print_green "Docker установлен."
print_blue "Проверка Docker Compose..."
if ! docker compose version &> /dev/null; then
print_yellow "Docker Compose не установлен или требуется обновление."
print_yellow "Инструкции по установке: https://docs.docker.com/compose/install/"
exit 1
fi
print_green "Docker Compose установлен."
}
# Проверка и создание .env файлов
check_env_files() {
print_blue "Проверка наличия файлов конфигурации..."
# Проверяем backend/.env
if [ ! -f backend/.env ]; then
if [ -f backend/.env.example ]; then
print_yellow "Файл backend/.env не найден. Создаю из примера..."
cp backend/.env.example backend/.env
print_green "Файл backend/.env создан. Рекомендуется настроить его вручную."
else
print_red "Файл backend/.env.example не найден. Невозможно создать файл конфигурации."
exit 1
fi
else
print_green "Файл backend/.env уже существует."
fi
# Проверяем frontend/.env
if [ ! -f frontend/.env ]; then
if [ -f frontend/.env.example ]; then
print_yellow "Файл frontend/.env не найден. Создаю из примера..."
cp frontend/.env.example frontend/.env
print_green "Файл frontend/.env создан. Рекомендуется настроить его вручную."
else
print_red "Файл frontend/.env.example не найден. Невозможно создать файл конфигурации."
exit 1
fi
else
print_green "Файл frontend/.env уже существует."
fi
print_blue "Проверка файлов конфигурации завершена."
print_yellow "ВАЖНО: По соображениям безопасности используйте свои значения для паролей и ключей в .env файлах."
}
# Предварительная загрузка образов
pull_images() {
print_blue "Предварительная загрузка образов Docker..."
images=("node:20-alpine" "postgres:16-alpine" "ollama/ollama:latest" "curlimages/curl:latest")
for img in "${images[@]}"; do
print_blue "Загрузка образа: $img"
docker pull $img
if [ $? -ne 0 ]; then
print_yellow "Предупреждение: Не удалось загрузить образ $img, но продолжаем работу..."
else
print_green "Образ $img успешно загружен."
fi
done
}
# Запуск проекта
start_project() {
print_blue "Запуск проекта..."
# Сначала убедимся, что предыдущие контейнеры остановлены
print_blue "Остановка существующих контейнеров..."
docker compose down
# Запуск сервисов в Docker Compose
print_blue "Запуск сервисов (PostgreSQL, Ollama, Backend, Frontend)..."
docker compose up -d
# Проверяем, что сервисы запустились
if [ $? -eq 0 ]; then
print_green "Сервисы успешно запущены!"
print_green "----------------------------------------"
print_green "Проект DApp-for-Business доступен по адресам:"
print_green "Frontend: http://localhost:5173"
print_green "Backend API: http://localhost:8000"
print_green "Ollama API: http://localhost:11434"
print_green "PostgreSQL: localhost:5432"
print_green "----------------------------------------"
print_green "Загрузка модели qwen2.5:7b может занять некоторое время..."
print_green "Вы можете проверить статус загрузки модели командой:"
print_green "docker logs -f dapp-ollama-setup"
print_green "----------------------------------------"
else
print_red "Произошла ошибка при запуске сервисов."
print_yellow "Проверьте логи командой: docker compose logs"
print_yellow "Для просмотра логов конкретного сервиса: docker compose logs [service]"
print_yellow "Например: docker compose logs backend"
fi
}
# Основная функция
main() {
print_blue "==============================================="
print_blue " Установка и запуск DApp-for-Business"
print_blue "==============================================="
check_docker
check_env_files
pull_images
start_project
}
# Запуск основной функции
main