redmine
Найдено: 2 записи
Звуки музыки →
Создание задач Redmine голосом
Как-то недавно с коллегами обсуждали возможность быстрого добавления задач в redmine. Среди немногих, а точнее единственным предложенным вариантом стало определение текста задачи по голосу. А мне стало интересно – смогу я склеить эту ‘балалайку’ за выходные?
Далее опишу основные моменты и что в итоге получилось.
Записываем во Flac
И так, мне потребовалось: Dot NET, Google Speech-Api, кодек Flac, Redmine API .NET.
Использование speech-api освещается в интернетах в т.ч. и на хабре, для этого необходимо просто отправить POST запрос со звуковым файлом, в ответ получите JSON объект:
Строка запроса:
http://www.google.com/speech-api/v1/recognize?lang=ru&client=chromium
Ответ:
{status:int, id:string, hypotheses : [{utterance : string, confidence : double}]}
Сложность заключается в записи файла такого формата, а именно – Flac, 16kHz, 16bit, mono. Получением pcm данных c wave-in интерфейса занимается (WaveLib господина Ianier Munoz) — полученные данные с буферов очереди отправляются в указанный callback, где записываются в кольцевой буфер (ring buffer), перед созданием обработчика записи создаётся тред для извлечения данных из кольцевого буфера и их отправки в кодек. Кодек я обернул в C++/CLI библиотеке, в чём помог пример, прилагающийся к libflac:
// Обратите внимание что сэмплы для flac имеют размер в 32bit
// Создаётся Енкодер
static
bool InitialiseEncoder(char* filepath, FILE** _file, FLAC__StreamEncoder** _encoder, FLAC__StreamMetadata** _metadata1, FLAC__StreamMetadata** _metadata2)
{
FLAC__bool ok = true;
FLAC__StreamEncoder *encoder = 0;
FLAC__StreamEncoderInitStatus init_status;
FLAC__StreamMetadata *metadata[2];
unsigned sample_rate = 16000;
unsigned channels = 1;
unsigned bps = 16;
/* allocate the encoder */
if((encoder = FLAC__stream_encoder_new()) == NULL) {
return false;
}
ok &= FLAC__stream_encoder_set_verify(encoder, true);
ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
ok &= FLAC__stream_encoder_set_channels(encoder, channels);
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);
ok &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);
ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, 0);
// В этот файл будет записан выход Енкодера
FILE* flacfile = _wfopen((wchar_t*)filepath, L"wb");
// Создаём Енкодер
if(ok) {
init_status = FLAC__stream_encoder_init_FILE(encoder, flacfile, progress_callback, /*client_data=*/NULL);
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
ok = false;
}
}
*_encoder = encoder;
*_file = flacfile;
return ok;
}
// Отправка pcm данных кодеку
static
bool ProcessEncoder(FLAC__StreamEncoder *encoder, FLAC__byte* _pcm, size_t need)
{
// С wave-in данные приходят в 16bit на семпл
FLAC__bool ok = true;
// На вход екодеру послупают 32bit сэмплы, здесь они просто копируются соблюдая последовательности
for(unsigned int i = 0; i < need*1; i++) {
pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)_pcm[2*i+1] << 8) | (FLAC__int16)_pcm[2*i]);
}
ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need);
return ok;
}
Далее был создан класс Recorder. Помимо создания экземпляра WaveInRecorder(менеджер wave-in устройства) создаётся тред для отправки pcm данных в Flac кодек из колцевого буфера:
private unsafe void DataArrived(IntPtr data, int size)
{
// Записываем pcm в кольцевой буфер
cb.Upload(data.ToPointer(), size);
}
WaveLib.WaveInRecorder m_Recorder;
VorbisEnc.FlacEncoder ve;
VorbisEnc.CircleBuffer cb;
IntPtr filepath;
public unsafe Recorder(string tempfilepath)
{
cb = new VorbisEnc.CircleBuffer();
ve = new VorbisEnc.FlacEncoder();
ve.Initialise((sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalUni(tempfilepath).ToPointer());
// Тред для кодировщика
System.Threading.Thread th = new System.Threading.Thread(EncodeData);
WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(16000, 16, 1);
m_Recorder = new WaveLib.WaveInRecorder(-1, fmt, 4096, 4, new WaveLib.BufferDoneEventHandler(DataArrived));
th.Start();
}
bool StopThread;
public bool AllDone = false;
public void Stop()
{
m_Recorder.Dispose();
StopThread = true;
cb.Dispose();
}
unsafe void EncodeData()
{
IntPtr datax = System.Runtime.InteropServices.Marshal.AllocHGlobal(4096);
sbyte* data = (sbyte*)datax.ToPointer();
while (!StopThread)
{
System.Threading.Thread.Sleep(10);
// Извлекаем из кольца данные, если курсор записи приблизился к курсору
// чтения на 4 итерации
while (cb.getNeedForUpdate() < 4096 * 4)
{
cb.Download(data, 4096);
ve.Encode(data, 4096);
}
}
System.Runtime.InteropServices.Marshal.FreeHGlobal(datax);
ve.Close();
// Данные кодированы и записаны, файл закрыт
AllDone = true;
}
Важность кольцевого буфера сложно переоценить, ведь он компенсирует задержки кодека и запись в файл, без него в данном случае при недостаточной производительности происходили потери данных: задержки на кодирование и запись в файл, не давали вовремя передать следующий буфер в очередь записи.
Аудиофайл записывается одной функцией:
string file = Path.GetTempFileName();
Recorder rec = new Recorder(file);
// Просто ждём пока записывается аудиофайл
System.Threading.Thread.Sleep(seconds * 1000);
// Останавливаем запись, закрываем файл
rec.Stop();
Далее передаётся на отправку в google:
string result = WebUpload.UploadFileEx(flacpath, "http://www.google.com/speech-api/v1/recognize?lang=ru&client=chromium",
"file", "audio/x-flac; rate=16000", parameters, null);
Функция отправки файла:
Uri uri = new Uri(url);
FileStream fileStream = new FileStream(uploadfile,
FileMode.Open, FileAccess.Read);
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
if (cookies != null)
webrequest.CookieContainer = cookies;
// Лишние заголовки необходимо убрать
webrequest.Headers.Clear();
webrequest.ContentLength = fileStream.Length;
webrequest.ContentType = contenttype;
webrequest.Method = "POST";
Stream requestStream = webrequest.GetRequestStream();
byte[] buffer = new Byte[checked((uint)Math.Min(4096,
(int)fileStream.Length))];
// Записываем файл в поток Http запроса
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);
fileStream.Close();
WebResponse response = webrequest.GetResponse();
Stream s = response.GetResponseStream();
StreamReader sr = new StreamReader(s);
string resps = sr.ReadToEnd();
response.Close();
return resps;
Redmine API
В redmine есть Rest api через который без сложностей, используя логин – пароль добавляется задача
RedmineManager manager = new RedmineManager(Configuration.RedmineHost,
Configuration.RedmineUser, Configuration.RedminePassword);
// Задача
var newIssue = new Issue
{
Subject = Title,
Description = Description,
Project = new IdentifiableName() { Id = ProjectId },
Tracker = new IdentifiableName() { Id = TrackerId }
};
// Находим id текущего пользователя
User thisuser = (from u in manager.GetObjectList<User>(new System.Collections.Specialized.NameValueCollection())
where u.Login == Configuration.RedmineUser
select u).FirstOrDefault();
if (thisuser != null)
newIssue.AssignedTo = new IdentifiableName() { Id = thisuser.Id };
manager.CreateObject(newIssue);
Получение списка проектов и трекеров:
public static Dictionary<string, int> GetProjects()
{
RedmineManager manager = new RedmineManager(Configuration.RedmineHost,
Configuration.RedmineUser, Configuration.RedminePassword);
Dictionary<string, int> Projects = new Dictionary<string, int>();
foreach (Project proj in manager.GetObjectList<Project>(new NameValueCollection()))
{
Projects.Add(proj.Name, proj.Id);
}
return Projects;
}
public static Dictionary<string, int> GetTrackers()
{
RedmineManager manager = new RedmineManager(Configuration.RedmineHost,
Configuration.RedmineUser, Configuration.RedminePassword);
Dictionary<string, int> Trackers = new Dictionary<string, int>();
foreach (Tracker track in manager.GetObjectList<Tracker>(new NameValueCollection()))
{
Trackers.Add(track.Name, track.Id);
}
return Trackers;
}
Кстати, всё то актуально для версий моложе 1.3 (появился список трекеров в REST API)
Итог или заключение
В итоге получилась форма с двумя полями для определения по голосу: название задачи, описание задачи. На время записи и распознавания все поля закрываются панелью. Запись производится с устройства, выставленного в системе для записи по умолчанию в течение 4 секунд.
Конечно, за выходные я управился и это плюс, однако получил не совсем то, что ожидал. Да, можно доработать и добавить выделение фраз для повышения точности распознавания, сделать интерфейс удобнее (много удобнее), но вряд ли это поможет избавить от рутины добавления задач.
Источники
Flac
Redmine API
WaveLib
Ссылки
Бинарники
Исходники
01.03.2012 23:21+0400
Песочница →
Переносим Redmine c VPS на Heroku или как получить бесплатный project-management tool
Эта статья дает пошаговую инструкцию как опубликовать Redmine приложение на веб хостинге Heroku.
Сперва давайте определимся почему и зачем нам/вам это нужно. Кто еще не знает что такое Redmine то это веб-приложение для управления проектами и отслеживания ошибок (баг трекер). Это довольно популярное приложение с открытым кодом и множеством плагинов.
Heroku это платформа для хостинга веб приложений. Отличительными чертами которой являются простота использования, минимальная конфигурация и возможность быстро менять требуемые ресурсы сервера (например если ожидается хабраэффект можно быстро увеличить требуемые мощности). То что нас интересует для этой статьи это возможность хостить приложение бесплатно.
Зачем нужна эта статья? Heroku платформа хоть и предоставляет ряд преимуществ перед VPS хостингом, у нее так же в добавок есть ограничения. Эта статья раскрывает сложности при установки и рассчитана на среднего-опытного пользователя.
Мы будем устанавливать текущую trunk версию Redmine. Она требует rails 2.3.14 и одну из версий ruby 1.8.7, 1.9.2, 1.9.3.
На данный момент мы имеем.
В примере мы будем использовать 1.9.2-p180 версию ruby. Сначала создадим новый gemset.
Теперь нам нужно получить последнюю версию Redmine, брать мы ее будем из git репозитория.
Теперь нам нужно изменить настройки подключения к дата-базе. Хоть мы и не будем запускать приложение локально, нам нужно будет загрузить информацию с существующего Redmine, который уже использует MySql, поэтому мы ее и будем использовать. Пример "/config/database.yml":
На данный момент trunk версия Redmine использует rails gem версии 2.3.14, поэтому устанавливаем его. Так же установим gem для подключения к дата-базе и создадим пустую базу.
Т.к. у нас уже есть существующая база, нам ее нужно импортировать. Для этого установим mysql клиент и произведем импорт дампа базы который взят из последнего бэкапа.
Хочу обратить ваше внимание что если используется короткий флаг (-u, -p и -h) для mysql то следующий параметр нужно писать без пробела.
Дальше создаем session_key командой, которая создаст новый файл "/config/initializers/session_store.rb"
Т.к. у нас уже есть session_key с предыдущей установки, заменим им новосозданный ключ в файле "/config/initializers/session_store.rb". Если это новая установка то ничего не трогаем.
Если вы использовали плагины к Redmine, то сейчас самое время также установить и произвести для них обновление датабазы. У нас их нет, поэтому этот шаг пропускаем.
Теперь произведем обновление датабазы.
Если это новая установка то загрузим стандартную информацию командой
Создадим папки если они еще не существуют и удалим "/config/initializers/session_store.rb" из .gitignore
Основной шаг подошел к концу. Добавим все изменения в git.
Просто так Redmine не будет полностью работать на Heroku, для этого нам нужно установить плагины. Будем использовать giternal для их установки.
Создадим новый файл «config/giternal.yml»
Произведем установку плагинов.
Теперь нам нужно настроить redmine_s3 плагин. Этот плагин позволяет сохранять файлы закачки Redmine в Amazon S3. Так что если у вас еще нету аккаунта S3 на амазоне, то самое время его завести.
Создадим файл «config/s3.yml»
Удалим "/public/plugin_assets" из .gitignore и произведем кофигурацию изменений.
Теперь нужно поменять session_key в файле "/config/initializers/session_store.rb" еще раз т.к. он был заменен при генерации на переменую. В идеальном мире мы не должны сохранять никакие пароли в репозиторий, но для простоты этой статьи сделаем именно так.
Теперь можно сделать еще одну остановку и сохранить изменения.
Т.к. мы переносим существующую установку нам так же нужно перенести все файлы закачки. Для этого скопируем все текущие файлы из VPS через SSH и произведем их загрузку в Amazon S3. Мы не можем просто скопировать в S3, т.к. файловая структура изменится.
Установим gem heroku, он нужен для создания и настройки нашего приложения на серверах heroku.
Создадим новое приложение на heroku с названием «redmine». Название должно быть уникально, поэтому его нужно заменить на еще не существующее.
И последний шаг это загрузить локальную базу на серверы heroku. Gem taps нужен для этой команды, поэтому предварительно установим его.
Приложение должно быть доступно по адресу redmine.heroku.com.
Для примера будем использовать Google Mail почтовый ящик. Создадим "/config/configuration.yml" с email конфигурацией.
Удалим этот фаил из gitignore и сохраним изменения
Ну и напоследок обновим версию на сервере
Как уже было упомянуто выше, это не лучшая идея сохранять пароли в репозиторий. Как выход все секретные данные можно вынести в глобальные переменные которые можно добавить на heroku командой
Единственный минус в том что нужно в некоторых случаях менять код. Больше можно прочитать тут
На бесплатном тарифном плане наше приложение имеет меньший приоритет, плюс если оно не получает запросы то полностью останавливается и запустится при первом следующем запросе (что будет довольно заметно, т.к. это займет около 10 сек). Чтобы проверить производительность при нескольких пользователях мы использовали бесплатную версию одного сервиса. Если честно то результаты довольно оптимистичны и я не совсем верю в их точность. Если верить графику то при 50 пользователях одновременно, задержка будет не более 3 секунд если пользователи близко находятся к серверу. Сервер с нашим приложением расположен в городе Сиэттл (Seattle). Но должен заметить что приложение работает довольно быстро и значительно быстрее чем на дешевом VPS.
В итоге переезда приложения Redmine с VPS на Heroku значительно уменьшились расходы и увеличилась производительность. Бесплатным решением это теоретически нельзя назвать ведь нам прийдется платить за Amazon S3, но эти расходы можно назвать копейками.
При написании этой статьи использовалась статья blog.firsthand.ca/2010/10/installing-redmine-on-heroku-with-s3.html
Сперва давайте определимся почему и зачем нам/вам это нужно. Кто еще не знает что такое Redmine то это веб-приложение для управления проектами и отслеживания ошибок (баг трекер). Это довольно популярное приложение с открытым кодом и множеством плагинов.
Heroku это платформа для хостинга веб приложений. Отличительными чертами которой являются простота использования, минимальная конфигурация и возможность быстро менять требуемые ресурсы сервера (например если ожидается хабраэффект можно быстро увеличить требуемые мощности). То что нас интересует для этой статьи это возможность хостить приложение бесплатно.
Зачем нужна эта статья? Heroku платформа хоть и предоставляет ряд преимуществ перед VPS хостингом, у нее так же в добавок есть ограничения. Эта статья раскрывает сложности при установки и рассчитана на среднего-опытного пользователя.
Мы будем устанавливать текущую trunk версию Redmine. Она требует rails 2.3.14 и одну из версий ruby 1.8.7, 1.9.2, 1.9.3.
На данный момент мы имеем.
- Установленный git
- RVM c нужной версией Ruby
- VPS с уже рабочим Redmine и доступом по SSH
- Аккаунт на Heroku
- Аккаунт на Amazon S3
В примере мы будем использовать 1.9.2-p180 версию ruby. Сначала создадим новый gemset.
rvm use ruby-1.9.2-p180
rvm gemset create 'redmineheroku'
rvm use ruby-1.9.2-p180@redmineheroku
Теперь нам нужно получить последнюю версию Redmine, брать мы ее будем из git репозитория.
mkdir redmine_heroku
cd redmine_heroku
git init
git remote add redmine git://github.com/edavis10/redmine.git
git fetch redmine
git merge redmine/master
Теперь нам нужно изменить настройки подключения к дата-базе. Хоть мы и не будем запускать приложение локально, нам нужно будет загрузить информацию с существующего Redmine, который уже использует MySql, поэтому мы ее и будем использовать. Пример "/config/database.yml":
production:
adapter: mysql
database: redmineheroku
host: localhost
username: db_user
password: db_password
encoding: utf8
development:
adapter: mysql
database: redmineheroku
host: localhost
username: db_user
password: db_password
encoding: utf8
На данный момент trunk версия Redmine использует rails gem версии 2.3.14, поэтому устанавливаем его. Так же установим gem для подключения к дата-базе и создадим пустую базу.
gem install rails --version 2.3.14
gem install mysql
rake db:create RAILS_ENV=production
Т.к. у нас уже есть существующая база, нам ее нужно импортировать. Для этого установим mysql клиент и произведем импорт дампа базы который взят из последнего бэкапа.
sudo apt-get install mysql-client-core-5.1
mysql -udb_user -pdb_password -h127.0.0.1 redmineheroku < ~/mysqldump-file-path.sql
Хочу обратить ваше внимание что если используется короткий флаг (-u, -p и -h) для mysql то следующий параметр нужно писать без пробела.
Дальше создаем session_key командой, которая создаст новый файл "/config/initializers/session_store.rb"
rake generate_session_store
Т.к. у нас уже есть session_key с предыдущей установки, заменим им новосозданный ключ в файле "/config/initializers/session_store.rb". Если это новая установка то ничего не трогаем.
Если вы использовали плагины к Redmine, то сейчас самое время также установить и произвести для них обновление датабазы. У нас их нет, поэтому этот шаг пропускаем.
RAILS_ENV=production rake db:migrate:upgrade_plugin_migrations
Теперь произведем обновление датабазы.
RAILS_ENV=production rake db:migrate
Если это новая установка то загрузим стандартную информацию командой
RAILS_ENV=production rake redmine:load_default_data
Создадим папки если они еще не существуют и удалим "/config/initializers/session_store.rb" из .gitignore
mkdir tmp public/plugin_assets
sed -i '/\/config\/initializers\/session_store.rb/d' .gitignore
Основной шаг подошел к концу. Добавим все изменения в git.
git add .
git commit -m "Initial configuration"
Устанавливаем плагины
Просто так Redmine не будет полностью работать на Heroku, для этого нам нужно установить плагины. Будем использовать giternal для их установки.
gem install giternal
Создадим новый файл «config/giternal.yml»
redmine_heroku:
path: vendor/plugins
repo: http://github.com/edavis10/redmine_heroku.git
redmine_s3:
path: vendor/plugins
repo: http://github.com/tigrish/redmine_s3.git
Произведем установку плагинов.
giternal update
giternal freeze
Теперь нам нужно настроить redmine_s3 плагин. Этот плагин позволяет сохранять файлы закачки Redmine в Amazon S3. Так что если у вас еще нету аккаунта S3 на амазоне, то самое время его завести.
Создадим файл «config/s3.yml»
production:
access_key_id: YOUR_S3_ACCESS_KEY_ID
secret_access_key: YOUR_S3_SECRET_ACCESS_KEY
bucket: YOUR_S3_REDMINE_PRODUCTION_BUCKET
cname_bucket: false
development:
access_key_id: YOUR_S3_ACCESS_KEY_ID
secret_access_key: YOUR_S3_SECRET_ACCESS_KEY
bucket: YOUR_S3_REDMINE_DEVELOPMENT_BUCKET
cname_bucket: false
Удалим "/public/plugin_assets" из .gitignore и произведем кофигурацию изменений.
sed -i '/\/public\/plugin_assets/d' .gitignore
rake heroku:setup
Теперь нужно поменять session_key в файле "/config/initializers/session_store.rb" еще раз т.к. он был заменен при генерации на переменую. В идеальном мире мы не должны сохранять никакие пароли в репозиторий, но для простоты этой статьи сделаем именно так.
Теперь можно сделать еще одну остановку и сохранить изменения.
git add .
git commit -m "Configure plugins"
Переносим файлы
Т.к. мы переносим существующую установку нам так же нужно перенести все файлы закачки. Для этого скопируем все текущие файлы из VPS через SSH и произведем их загрузку в Amazon S3. Мы не можем просто скопировать в S3, т.к. файловая структура изменится.
scp user@123.456.789.000:~/vps_redmine/files/* ~/redmine_heroku/files/
RAILS_ENV=production rake redmine_s3:files_to_s3
Запускаем сервер
Установим gem heroku, он нужен для создания и настройки нашего приложения на серверах heroku.
gem install heroku
Создадим новое приложение на heroku с названием «redmine». Название должно быть уникально, поэтому его нужно заменить на еще не существующее.
heroku create redmine
git push heroku master
И последний шаг это загрузить локальную базу на серверы heroku. Gem taps нужен для этой команды, поэтому предварительно установим его.
gem install taps
heroku db:push
Приложение должно быть доступно по адресу redmine.heroku.com.
Дополнительная информация
Настраиваем email уведомления
Для примера будем использовать Google Mail почтовый ящик. Создадим "/config/configuration.yml" с email конфигурацией.
production:
email_delivery:
delivery_method: :smtp
smtp_settings:
tls: true
enable_starttls_auto: true
address: "smtp.gmail.com"
port: '587'
domain: "smtp.gmail.com"
authentication: :plain
user_name: "email_address@gmail.com"
password: "email_password"
Удалим этот фаил из gitignore и сохраним изменения
sed -i '/\/config\/configuration.yml/d' .gitignore
git add .
git commit -m "email config"
Ну и напоследок обновим версию на сервере
git push heroku master
Настройка безопасности
Как уже было упомянуто выше, это не лучшая идея сохранять пароли в репозиторий. Как выход все секретные данные можно вынести в глобальные переменные которые можно добавить на heroku командой
config:add key=val [...] # add one or more config vars
Единственный минус в том что нужно в некоторых случаях менять код. Больше можно прочитать тут
Производительность
На бесплатном тарифном плане наше приложение имеет меньший приоритет, плюс если оно не получает запросы то полностью останавливается и запустится при первом следующем запросе (что будет довольно заметно, т.к. это займет около 10 сек). Чтобы проверить производительность при нескольких пользователях мы использовали бесплатную версию одного сервиса. Если честно то результаты довольно оптимистичны и я не совсем верю в их точность. Если верить графику то при 50 пользователях одновременно, задержка будет не более 3 секунд если пользователи близко находятся к серверу. Сервер с нашим приложением расположен в городе Сиэттл (Seattle). Но должен заметить что приложение работает довольно быстро и значительно быстрее чем на дешевом VPS.
В заключение
В итоге переезда приложения Redmine с VPS на Heroku значительно уменьшились расходы и увеличилась производительность. Бесплатным решением это теоретически нельзя назвать ведь нам прийдется платить за Amazon S3, но эти расходы можно назвать копейками.
При написании этой статьи использовалась статья blog.firsthand.ca/2010/10/installing-redmine-on-heroku-with-s3.html
27.12.2011 16:41+0400