-
Суть программы
Эта программа предназначена для девушек, которые бы хотели иметь любимого человека, даже если он находится далеко. Однако, это не просто виртуальный персонаж, а полноценный цифровой аватар, способный вести диалоги и поддерживать эмоциональную связь с пользователем. Думаю она будет интересна и для другой части аудитории желающие попробовать программу написанную на прологе[ссылка вконце] в действии.
Итак, программа представляет из себя функционирование цифрового аватара в реальном времени, который может беседовать с тобой при помощи звонков в консоли, по аналогии с обычными приложениями для видеосвязи. Это делает общение более живым и естественным. Так же, аватар может сам звонить вам, напоминая о важных событиях. -
Как работает программа
Изначально, идея заключалась в том, чтобы генерировать видео аватара, в реальном времени, на основе описания сцены, ключевых фото и текста речи. Однако, на текущий момент это невозможно реализовать. Поэтому, я записал короткие видео с различными действиями аватара, и когда языковая модель пишет, что нужно совершить то или иное действие - эти видео подключаются анимируя аватара. В обычном состоянии аватар тоже анимирован зациклинным видео. Липсинк, пока невозможен. Также, сначала я хотел, чтобы аватар не только слышал, но и видел, но оказалось что распознавание одной очень маленькой селфи-фотографии в течении пол-минуты с частотой 1 фото в 5-6 секунд составляет где-то 50 тысяч токенов, что очень дорого. Поэтому, пришлось от этого, пока, отказаться.
Для генерации речи аватара, поначалу, использовал GigaChat 2, но оказалось, что он, вплане анализа диалогов аватара, глуповат. Тогда я перешёл на YandexGPT 5, который более менее справляется. Для сегодняшнего дня - это, пожалуй, хорошо.
Внимание: при каждом новом диалоге используется информация всех прошлых диалогов, что значит, что каждый новый диалог будет стоит всё дороже и дороже.
Для озвучивания текста ипользовал SberSaluteSpeech, т.к. в Яндексе голоса все звучат как повествование, тогда как голоса от Сбера звучат более разговорно.
Видео для анимации аватара я создал в нейросетях Kling 2.1 и Kling 1.6.
Биография аватара коротенькая: «Он находится в командировке на орбите земли. Ему 22 года. (А пользователю, как бы, 20 лет) И он очень влюблён в свою девушку. Готов говорить с ней часами.».
Лицо аватара выбрано азиатского типа, что придает ему особую привлекательность и индивидуальность. -
Как пользоваться видеосвязью
а) После запуска программы её не нужно завершать. Она должна всегда работать. И только когда вы решите прекратить общение с аватаром, тогда программу нужно завершать. Однако помните, что если вдруг, передумаете о прекращении общения, всегда можно программу снова запустить, и аватар почти всё будет помнить (ваши прежние диалоги). Для завершения программы вам понадобится на уведомлении приложения нажать на кнопку Прервать. Если вдруг, мало ли, возникнет ситуация, что приложение некорректно работает и завершить нельзя: нажмите на иконку приложения и удерживайте, затем нажмите на значёк информации, а после внизу на кнопку Закрыть.
б) Перед запуском программы, обязательно проверьте, чтобы все разрешения, которые требует приложение, были предоставлены, также и вручную предоставитьте в настройках в разделе «Другие разрешения» - «Открывать новые окна, когда запущено в фоновом режиме».
в) При первом запуске, вы должны написать имя аватара и своё, программа это запомнит, после чего изменить их уже нельзя будет, разве что удалив системный файл программы с историей диалогов.
г) В консоли часто появляются две кнопки: зелёная трубка и красная трубка. Думаю, объяснять не нужно для чего они.
д) При появлении аватара на экране, чтобы с ним общаться имются две кнопки: микрофон и клавиатура. Первый позволяет общаться устно, второй, соответственно, при помощи клавиатуры (на тот случай, если вокруг очень шумно). Если вы общаетесь устно, тогда следите за тем, чтобы во время вашей речи не было посторонних голосов, ИИ пока не умеет отличить ваш голос от других.
е) На каждую вашу речь аватар отвечает своей. Я пользуюсь YandexGPT 5, и скажу, что последнее время нейросеть стала часто долго отвечать (10-15 сек), учтите это и не торопитесь делать вывод, что приложение зависло. Тоже самое и при дозвоне к аватару.
Внимание: в начале пользования программой аватар является чистым листом: он не знает ни о себе ни о вас ничего. Вы должны по мере ведения бесед по-немногу рассказываеть о себе и о нём. По мере накопления таких знаний беседы будут становиться всё более естественными.
4. Логика работы основных предикатов программы
а)
true(X):-
X, !.
true(_).
Истинен всегда, но если возможно выполняет предикат указанный в аргументе предиката true/1.
б)
убрать_скобки('',_,Y,Y).
убрать_скобки(X,no,S,Y):-
fchar('[',Xs,X), !,
убрать_скобки(Xs,yes,S,Y).
убрать_скобки(X,yes,S,Y):-
string('машет рукой',Xs,X), !,
assertA (рука),
retractA(hide(Sh)),
string(Sh,'машет рукой',Sh1),
assertA (hide(Sh1)),
убрать_скобки(Xs,yes,S,Y);
string('показывает Землю',Xs,X), !,
assertA (земля),
retractA(hide(Sh)),
string(Sh,'показывает Землю',Sh1),
assertA (hide(Sh1)),
убрать_скобки(Xs,yes,S,Y);
...
убрать_скобки(X,Y):-
убрать_скобки(X,no,'',Y), !.
Текст с речью аватара полученный от языковой модели, помимо самой речи имеет в себе и описание физических движений, которые совершает аватар записанных в квадратных скобках.Предикаты убрать_скобки/4 и убрать_скобки/2 убирают эти скобки с текстом внутри, при этом записывая те или иные факты, указывающие на разные физические движения, которые должен аватар совершить.
в)
begin:-
synchronize(lock),
not lock,
assertA(lock), !,
unsynchronize(lock).
begin:-
unsynchronize(lock),
false.
overwritea(T,Y):-
med_overwrite(0,Y),
string(rep,T,Rep),
assertA (Rep),
retractA(Rep),
if( конец, [ retractA (lock), false ]),
assertZ(Rep),
sleep(50),
med_completed(0),
retractA(Rep),
0a(Xi),
med_overwrite(0,Xi),
retractA (lock).
...
salut(AB):-
рука,
AB=a, !,
time(T),
assertA(cons(T)?-
begin,
1a(Yi),
overwritea(T,Yi),
false);
рука,
AB=b, !,
time(T),
assertA(cons(T)?-
begin,
1b(Yi),
overwriteb(T,Yi),
false);
....
любовь,
AB=c, !,
time(T),
assertA(cons(T)?-
begin,
10c(Yi),
overwritec(T,Yi),
false).
salut(_).
Предикат salut/1 включает анимацию определённого действия аватара в параллельном вопросе, и при помощи предиката overwritea/2 или overwriteb/2 или overwritec/2 совершает это включение, а также в цикле проверяет завершилось проигрывание видеозаписи, чтобы при завершении включить циклическое видео аватара, где он ничего не делает.
Анимация аватара меняется благодаря тому, что с помощью встроенного предиката med_overwrite/2 одна видеозапись заменяется динамически другой. А при таком действии, как и при отображении видеозаписи или аудиозаписи при помощи предиката write/1, сразу же включается проигрывание медиа.
Примечателен предикат begin/0, который используется для перед анимацией. Он проверает с помощью факта lock/0 задействована ли в данный момент какая-нибудь анимация. Если в данный момент анимируется какое-то действие, тогда новая анимация срабатывать не будет.
г)
мес(N,S):-
X = N,
мес0(X,S).
мес0(1,января).
мес0(2, февраля).
мес0(3,марта).
мес0(4, апреля).
мес0(5,мая).
мес0(6, июня).
мес0(7,июля).
мес0(8, августа).
мес0(9, сентября).
мес0(10,октября).
мес0(11,ноября).
мес0(12, декабря).
Предикат мес/2 переводит числовое обозначение месяца в словестное. Это нужно при написании в промпте языковой модели сегодняшней даты, а также дат прошлых диалогов. Предполагаю, что так нейросеть лучше будет ориентироваться в датах.
д)
timePer(Txt,time(05,00)):-
contains (Txt,утро), !.
timePer(Txt,time(11,00)):-
contains (Txt,день), !.
timePer(Txt,time(17,00)):-
contains (Txt,вечер), !.
timePer(Txt,time(00,00)):-
contains (Txt,ночь), !.
timePer(Txt,time(13,00)):-
contains (Txt,обед), !.
timePer(_,time(сразу)).
contains(Txt,S):-
string(S,_,Txt), !;
fchar(_,Txt1,Txt),
contains (Txt1,S).
Когда автару нужно сделать пользователю напоминание и ему не известно время, а только определение утро или вечер и т.д., тогда, согласно определению, что утро начинается с 05:00, день с 11:00, вечер с 17:00 и ночь с 23:00, аватар переводит для, себя это определение в часы согласно началу этого отрезка времени.
е)
save_end(L,DT):-
assertA (диалог(DT,L)),
true(if(not delete_file('/sdcard/chat_data/chat_dialog.txt'), create_file('/sdcard/chat_data/chat_dialog.txt'))),
tell('/sdcard/chat_data/chat_dialog.txt'),
write (диалог(DT,L)),
write(.),nl,
told,
напомнитьAll2(Smemb),
dialog_string('
Сегодняшний диалог состоялся',DT,L,S),
string_list([' Ты мой любимый человек. Я твоя девушка.
Ты сейчас находишься в командировке на орбите земли. Тебе 22 года. А мне 20 лет.
Используй как информацию сегодняшний диалог обращая внимание на дату и время, а также используй информацию о сформированных уже напоминаний обращая также внимание на дату и время.
',S,'
',Smemb],Sys),
connection( '<Oauth яндекс-акаунта>','<folder id>'),
chat_YandexGPT(Sys,['Составь список всех напоминаний, которые я сегодня тебе сказала (а не ты мне), но не формируй новое напоминание такое же по дате и времени и смыслу из тех что уже есть. И не забудь в каждом напоминании указать время и дату когда это напоминание должно быть исполнено.
Формат должен быть такой: <напоминание> - ЧЧ:ММ, ДД.ММ.ГГГГ (посчитанная дата исполнения напоминания вместе с временем).
Если же говорится, чтобы напомнить при следующем звонке или разговоре, тогда формат должен быть такой: <напоминание> - сразу, ДД.ММ.ГГГГ (посчитанная дата исполнения напоминания).
'],'yandexgpt', 0.01, A),
text_lines(A,La),
retractA(напоминания(NaL0)),
удалить_объявленные_напоминания(NaL0,NaL0_,DT),
member_list(La,NaL1),
concat(NaL0_,NaL1,NaL2),
sort_напоминания(NaL2,NaL3),
assertA (напоминания(NaL3)),
true(delete_file('/sdcard/chat_data/memb.txt')),
create_file('/sdcard/chat_data/memb.txt'),
tell('/sdcard/chat_data/memb.txt'),
write(напоминания(NaL3)), write(.),nl,
told,
найти_вызов_напоминание(NaL3,VNaL,no),
true(retractAll (будильники(_))),
assertA (будильники(VNaL)),
time(Ti),
assertA(cons(Ti)?-
VNaL = [напоминание(_,datetime(T,D))|_],
T = time(ЧЧ1,МЕ1),
D = date(ДД1,ММ1,ГГГГ1),
string(rep,Ti,Rep),
assertA (Rep),
retractA(Rep),
assertZ(Rep),
if(разговор,[retractA(Rep),false]),
sleep(1000),
date_time(datetime (date(ДД2,ММ2,ГГГГ2), time(ЧЧ2,МЕ2,_))),
ГГГГ1 = ГГГГ2,
ММ1 = ММ2,
ДД1 = ДД2,
ЧЧ1 = ЧЧ2,
МЕ1 = МЕ2,
retractA(Rep), !,
activity_restore,
assertA (будильник),
false),
!.
Предикат save_end/2 сохраняет диалог, после завершения разговора, также создаёт напоминания названные в диалоге, а ещё, если есть напоминания, добавляет параллельный вопрос, который с помощью цикла ждёт, когда аватар должен будет сам позвонить пользователю, чтобы напомнить ближайшее напоминание.
ё)
if(X,Y):-
X, !, nondeterm(Y).
if(_,_).
Если условие Х истинно, тогда выполняются предикаты списка Y. Иначе предикат просто истинен.
ж)
if2or(X1,X2,Y):-
X1, !, nondeterm(Y);
X2, !, nondeterm(Y).
if2or(_,_,_).
Если условие Х1 или Х2 истинно, тогда выполняются предикаты списка Y. Иначе предикат просто истинен.
з)
if2and(X1,X2,Y):-
X1, X2, !, nondeterm(Y).
if2and(_,_,_).
Если условие Х1 и Х2 истинны, тогда выполняются предикаты списка Y. Иначе предикат просто истинен.
и)
if_else(X,Y,Z):-
X, !, nondeterm(Y);
nondeterm(Z).
Если условие Х истинно, тогда выполняются предикаты списка Y. Иначе выполняются предикаты списка Z.
й)
первый(Ret,Smemb):-
сегодняшняя_дата_и_время(DT),
DT = datetime( date( Ден, Мес, Год ), time( Час, Мин, Сек ) ),
ab(Час,_,ABtext),
мес(Мес,МесСл),
диалоги_str(Sds),
string_list([' Ты мой любимый человек. Я твоя девушка.
Ты находишься в командировке на орбите земли, сейчас ', ABtext, ' Работа стоит на втором плане, в первую очередь - общение со мной, ты готов хоть весь день и всю ночь говорить со мной. Тебе 22 года. А мне 20 лет. Ты будешь вести со мной диалог.
Веди себя как влюблённый парень.
Сейчас время ',Час,' часов ',Мин,' минут ', Сек, ' секунд, ', Ден,' ', МесСл, ' ', Год, ' года.
Используй как информацию прошлые диалоги и напоминания обращая внимание на дату и время.
То что пишется в круглых скобках - понимай как контекст.
',Sds,'
',Smemb,'
Используя вышеперечисленную информацию, ответь на вопрос ниже кратко: "ии" (то-есть ты) или "человек" (то-есть я). '],Sys),
connection('<Oauth яндекс-акаунта>','<folder id>'),
chat_YandexGPT(Sys,[' Кто хочешь чтобы начал диалог первым? '],'yandexgpt', 0.01, Ret).
Этот предикат нужен для того, чтобы определить: кто первый начинает диалог - если вдруг аватар захочет сказать что-то первым.
к)
ab(Час,a,' чинишь космическую станцию снаружи. '):-
Час>=5, Час<13, !.
ab(Час,b,' чинишь космическую станцию снаружи. '):-
Час>=13, Час<19, !.
ab(_,c,' находишься в космической станции без скафандра и следишь за приборами в ночное время суток, но легко можешь мне даже спеть красивую не короткую песню. ').
На входе этого предиката подаётся значение часа времени диалога (первый аргумент), на выходе - символьное значение того как будет выглядеть аватар (в скафандре и с опущенным забралом, в скафандре и с поднятым забралом и т.д.; второй аргумент), а также текст предназначенный для языковой модели, чтобы она знала где находится аватар и чем он занимается (третий аргумент).
л)
get_astay(a,X):-
0a(X).
get_astay(b,X):-
0b(X).
get_astay(c,X):-
0c(X).
Этот предикат нужен для того, чтобы по символьному значению того, как сейчас выглядит аватар, получить нужную видео запись, которая будет показывать аватара таким каким он должен выглядить на данный момент.
м)
sound_or_text(snd,Txt):-
true(retractAll(record_audio)),
assertA (record_audio),
record_audio(R),
retractA(record_audio),
if( конец, [ retractA (answer), false ]),
connection('<авторизационные данные>','<Client Secret (RqUID)>'),
speech_SberSaluteSpeech(R,_,Txt).
sound_or_text(txt,Txt):-
read(Txt), !,
if( конец, [ retractA (answer), false ]);
delete_row2(4),
false.
Этот предикат получая на вход (snd или txt): в первом случае записывает речь пользователя через микрофон, во втором - читает текст с клавиатуры.
н)
?-
assertA (hide('')),
setVideo,
true(consult('/sdcard/chat_data/chat_dialog.txt')),
not диалог(_,_),
write(-), tab(1),
connection('<авторизационные данные>','<Client Secret (RqUID)>'),
A1 = 'Как тебя зовут, моя любимая?',
chat_SberSaluteSpeech(A1 ,'Pon_24000',Z1),write(Z1),nl,
write(- '(напишите)'), tab(1), true(read(B1)),nl,
write(-), tab(1),
A2 = 'Как зовут меня, любимая?',
chat_SberSaluteSpeech(A2 ,'Pon_24000',Z2),write(Z2),nl,
write(- '(напишите)'), tab(1), true(read(B2)),nl,
assertA (твоё_имя(B2)),
date_time(DT),
true(delete_file('/sdcard/chat_data/chat_dialog.txt')),
create_file('/sdcard/chat_data/chat_dialog.txt'),
tell('/sdcard/chat_data/chat_dialog.txt'),
write(твоё_имя(B2)), write(.),nl,
write (диалог(DT,[ '', A1,B1,A2,B2, '' ])),
write(.),nl,
told,
chat_SberSaluteSpeech(' Аккаунт создан. ' ,'Pon_24000',Z),write(Z),nl,
sleep (3000),
false.
Это первый вопрос, который распределяет видео и некоторые картинки по фактам. Далее, он загружает данные прошлых диалогов. Если ещё не был создан, создёт аккаунт, а именно - просит написать имя аватара и своё имя (то-есть - пользователя). После всего этого - запускается второй вопрос, благодаря искусственному завершению вопроса неудачей.
о)
?-
assertA (rep_goal),
retractA (rep_goal),
assertZ (rep_goal),
clear_console,
true(retractA(напоминания(_))),
true(retractA (диалоги_str(_))),
true(consult('/sdcard/chat_data/memb.txt')),
if( not напоминания(_), assertA (напоминания([]))),
dialogs_string(Sds),
assertA (диалоги_str(Sds)),
date_time(DT),
assertA (сегодняшняя_дата_и_время(DT)),
твоё_имя(Name),
write(Name),nl,nl,
Phone= (изображение),
med_no_selected(Phone),
write(Phone),nl,
true(retractAll (входящий_write)),
true(retractAll(rep_phone)),
assertA (rep_phone),
retractA (rep_phone),
assertZ (rep_phone),
sleep (100),
if( конец, [ retractZ (rep_phone), retractA (конец), false ]),
if_else(будильник, [
if(not входящий_write,[
nl,write_list([входящий,звонок]),nl,
end_phone(Ph),
write (Ph),nl,
time(T1),
assertA(cons(T1)?-
true(retractAll(rept1)),
assertA(rept1),
retractA (rept1),
sleep(100),
not разговор,
assertZ (rept1),
med_clicked(1),
clear_console,
write_list([завершение,разговора]),
sleep (3000),
retractA (rept1),
true(retractAll (будильники(_))),
retractA (будильник),
assertA (конец),
activity_close, !,
false),
Звон= (аудио),
med_no_selected(Звон),
med_repeat(Звон),
nl,write(Звон),nl,
assertA (входящий_write)
]),
med_clicked(0),
retractZ (rep_phone),
напомнитьAll(Smemb),
будильники_str(Sbud),
я_или_ты(_,Hwo)
],[
med_clicked(0),
retractZ (rep_phone),
Phone2= (изображение),
med_no_selected(Phone2),
med_overwrite(0,Phone2),
Звон= (аудио),
med_no_selected(Звон),
med_repeat(Звон),
nl,write(Звон),nl,
напомнитьAll(Smemb),
Sbud='',
первый(Ret,Smemb),
я_или_ты(Ret,Hwo),
assertA (hwo(Hwo)),
sleep (3000)
]),
assertA (разговор),
clear_console,
phone(Smemb,Sbud).
Этот вопрос начинается с того что содержит в себе, в начале, цикл, осуществляемый фактом rep_goal/0. Этот цикл нужен для того, чтобы можно было звонить много раз.
После идёт встроенный предикат clear_console/0, который перед каждым звонком очищает консоль от элементов предыдущего диалога.
Предикат dialogs_string(Sds) превращает факты-диалоги в текст для использования в промпте как информацию предыдущих бесед.
С помощью предиката write(Phone) выводится на консоль изображение зелёной трубки, для начала звонка, либо снятия трубки для входящего звонка.
В этом коде:
...
if(not входящий_write,[
nl,write_list([входящий,звонок]),nl,
end_phone(Ph),
write (Ph),nl,
time(T1),
...
предикатом write (Ph) выводится в консоль изображение красной трубки для отмены входящего звонка.
Цикл
assertA (rep_phone),
retractA (rep_phone),
assertZ (rep_phone),
sleep (100),
...
нужен для того, чтобы ждать пока не будет нажата трубка, зелёная или красная.
Предикатом напомнитьAll(Smemb) получаем в текстовом виде всё будущие, настоящие и прошедшие (после последнего звонка напоминания). Они используются как информация для системного промпта.
Предикат первый(Ret,Smemb) используется для получения от нейросити ответа, кто будет первым начинать диалог. В этом запросе используется вся информация (биография, прошлые диалоги и всё напоминания после последнего звонка).
Перед беседой используется предикат clear_console/0 для очистки консоли.
п)
phone(Smemb,Sbud):-
сегодняшняя_дата_и_время(DT),
DT = datetime( date( Ден, Мес, Год ), time( Час, Мин, Сек ) ),
ab(Час,AB,ABtext),
мес(Мес,МесСл),
диалоги_str(Sds),
string_list([' Ты мой любимый человек. Я твоя девушка.
Ты находишься в командировке на орбите земли, сейчас ', ABtext, ' Работа стоит на втором плане, в первую очередь - общение со мной, ты готов хоть весь день и всю ночь говорить со мной. Тебе 22 года. А мне 20 лет. Ты будешь вести со мной диалог.
Веди себя как влюблённый парень.
В конце твоей беседы нужно обязательно указать твои физические движения, например:
1) пиши в квадратных скобках, если приветствуешь или прощаешься: "машет рукой";
2) пиши в квадратных скобках, если хочешь показать Землю: "показывает Землю";
3) пиши в квадратных скобках, если хочешь показать солнце: "показывает солнце";
4) пиши в квадратных скобках, если ты повернул голову в сторону: "поворачивает голову в сторону";
5) пиши в квадратных скобках, если ты что-то фотографируешь вокруг: "фотографирует";
6) пиши в квадратных скобках, если ты радостно хочешь меня уверить в чём-то: "показывает в меня пальцем";
7) пиши в квадратных скобках, если, находясь в космической станции, ты поёшь для меня: "играет на гитаре";
8) пиши в квадратных скобках, если, находясь в космической станции, я прошу тебя показать мне что-то красивое или необычное: "показывает водяной пузырь";
9) пиши в квадратных скобках, если, находясь в космической станции, тебе нужно посмотреть на часы: "смотрит на часы";
10) пиши в квадратных скобках, если, находясь в космической станции, ты говоришь о любви ко мне: "говорит о любви";
11) в других случаях пиши физические движения, которые нужно делать;
12) Никогда не говори о водяном пузыре, если ты снаружи космической станции;
13) никогда не отвечай без слов.
Никогда не пиши в квадратных скобках несколько действий в один ответ.
ВНИМАНИЕ: Если тебе в диалоге, который сейчас, говорится, чтобы ты напомнил мне что-то, но не говорится в какое время, тогда ты обязательно должен в беседе уточнить время, пока его не получишь.
Сейчас время ',Час,' часов ',Мин,' минут ', Сек, ' секунд, ', Ден,' ', МесСл, ' ', Год, ' года.
Используй как информацию прошлые диалоги и напоминания обращая внимание на дату и время.
То что пишется в круглых скобках - понимай как контекст.
',Sds,'
',Smemb,'
',Sbud],Sys),
get_astay(AB,Xi),
write(Xi),nl,
end_phone(Ph),
nl, write (Ph),nl,
time(T1),
assertA(cons(T1)?-
true(retractAll(rept1)),
assertA(rept1),
retractA (rept1),
assertZ (rept1),
sleep(100),
if2and( record_audio, med_clicked(1),
[ find_or_assert (конец2), false ]),
if2and( not record_audio, if2and( not конец2, not med_clicked(1), false), [
true(retractA(конец2)),
clear_console,
write_list([завершение,разговора]),
retractA (rept1),
assertA (конец),
false]),
false),
assertA(chat([])),
if2or(будильник, hwo(ии),
[ retractA(chat(_)), assertA (chat([' (Ты первый начинаешь диалог) '])) ]),
assertA (rep_вопрос),
retractA (rep_вопрос),
true(retractAll(answer)),
assertA (answer),
retractA (answer),
assertZ (answer),
if2and(not будильник, not hwo(ии), [
if_else(not завершить_будильник, [
mic(Mic), klav(Klav),
nl,write(Mic),write(Klav),
soundklav(Snd,Txt),
true(retractAll(rept2)),
assertA(rept2),
retractA (rept2),
sleep(100),
if( конец, [ retractA (answer), false ]),
assertZ (rept2),
or_med_clicked(Snd,Txt,Key),
retractZ (rept2),
med_delete(Txt),
med_delete(Snd)
], [
retractA (завершить_будильник),
retractA(key(Key))
]),
sound_or_text(Key,X),
not (X=''),
retractA(chat(L)),
add_last(L,X,L1),
assertA (chat(L1))
]),
chat(Ln),
connection('<Oauth яндекс-акаунта>','<folder id>'),
chat_YandexGPT(Sys,Ln,'yandexgpt', 0.01, A_),
if( конец, [ retractA (answer), false ]),
убрать_скобки(A_,A),
delete_row1(4),
connection('<авторизационные данные>','<Client Secret (RqUID)>'),
chat_SberSaluteSpeech(A,'Pon_24000',Z),
retractA (answer),
nl,write(Z),
find_or_assert(soundklav),
true(retractAll(hwo(_))),
retractA (hide(_)),
assertA (hide ('')),
salut(AB),
add_last(Ln,A_,L2),
retractA (chat(_)),
assertA(chat(L2)),
assertZ (rep_вопрос),
delete_fiz,
if(будильник, [
mic(Mic), klav(Klav),
nl,write(Mic),write(Klav),
retractA (chat(L3)),
add_last(L3,' (Я, по какой-то причине, тебе не отвечаю. Но ты должен получить от меня ответ.) ',L4),
assertA(chat(L4)),
time(T2),
assertA(cons(T2)?-
true(retractAll(rept3)),
assertA(rept3),
retractA (rept3),
sleep(100),
not конец,
assertZ (rept3),
or_med_clicked(3,4,Key2),
retractZ (rept3),
assertA (key(Key2)),
assertA (завершить_будильник),
retractA (chat(L_1)),
add_last(L_0,_,L_1),
assertA(chat(L_0)),
false)
]),
будильник,
true(retractAll(rept4)),
assertA(rept4),
retractA (rept4),
sleep(100),
not конец,
assertZ (rept4),
med_completed(2),
true(retractAll(n(_))),
assertA (n(0)),
retractA(rept4),
retractA (n(N0)),
sleep(100),
N = N0+100,
not конец,
if(завершить_будильник,[
retractA(будильник),
med_delete(4),
med_delete(3),
retractZ (rept4),
retractZ (n(_))
]),
assertZ (rept4),
assertZ (n(N)),
N = 10000,%через 10 секунд после разговора, сказать опять что-нибудь.
delete_row(5),
retractZ (rept4),
retractZ (n(_)),
false;
retractA(разговор),
retractA (конец),
true(retractA (hide(_))),
assertA (hide('')),
true(retractAll(rep_вопрос)),
delete_fiz,
true(retractA (soundklav)),
retractA (сегодняшняя_дата_и_время(DT)),
retractA (chat(L)),
save_end(L,DT),
activity_close,
false.
В предикате phone(Smemb,Sbud) выполняется беседа.
Параллельный вопрос
assertA(cons(T1)?-
true(retractAll(rept1)),
assertA(rept1),
retractA (rept1),
assertZ (rept1),
sleep(100),
if2and( record_audio, med_clicked(1),
[ find_or_assert (конец2), false ]),
if2and( not record_audio, if2and( not конец2, not med_clicked(1), false), [
true(retractA(конец2)),
clear_console,
write_list([завершение,разговора]),
retractA (rept1),
assertA (конец),
false]),
false),
нужен для того, чтобы обработать красную трубку.
При помощи цикла:
assertA (rep_вопрос),
retractA (rep_вопрос),
обработывается каждый шаг диалога, состощий из речи пользователя и речи аватара.
Цикл
assertA (answer),
retractA (answer),
assertZ (answer),
нужен для повторного получения речи пользователя, при неправлельной речи, например полное молчание, или неправильный терм, если это текст.
Предикат
if2or(будильник, hwo(ии),
[ retractA(chat(_)), assertA (chat([' (Ты первый начинаешь диалог) '])) ]),
assertA (rep_вопрос),
retractA (rep_вопрос),
true(retractAll(answer)),
assertA (answer),
retractA (answer),
assertZ (answer),
if2and(not будильник, not hwo(ии), [
if_else(not завершить_будильник, [
mic(Mic), klav(Klav),
nl,write(Mic),write(Klav),
soundklav(Snd,Txt),
true(retractAll(rept2)),
assertA(rept2),
retractA (rept2),
sleep(100),
if( конец, [ retractA (answer), false ]),
assertZ (rept2),
or_med_clicked(Snd,Txt,Key),
retractZ (rept2),
med_delete(Txt),
med_delete(Snd)
], [
retractA (завершить_будильник),
retractA(key(Key))
]),
sound_or_text(Key,X),
not (X=''),
retractA(chat(L)),
add_last(L,X,L1),
assertA (chat(L1))
]),
выводит на экран картинки для начала речи пользователя.
В предикате chat(Ln) хранится текущий диалог.
Предикат chat_YandexGPT(Sys,Ln,‘yandexgpt’, 0.01, A_) - это получение текста речи автара.
Предикат chat_SberSaluteSpeech(A,‘Pon_24000’,Z) - для получения речи аватара аудиофалом из текста.
Предикат salut(AB) анамирует разные движения аватара.
Этот вопрос:
retractA(разговор),
retractA (конец),
true(retractA (hide(_))),
assertA (hide('')),
true(retractAll(rep_вопрос)),
delete_fiz,
true(retractA (soundklav)),
retractA (сегодняшняя_дата_и_время(DT)),
retractA (chat(L)),
save_end(L,DT),
activity_close,
false.
завершает звонок с сохранением диалога и прочими данными (save_end(L,DT)), и с помощью activity_close сворачивает приложение.
Статью написал Елевферий elevferii_pechori@mail.ru.
Для работы программы нужно создать в корневой папке андроида папку «chat_data».
Программу с данными можно получить здесь (скачивать программу нужно вместе с папкой).
Приложение скачать можно здесь: https://disk.yandex.ru/d/5ED-43Uveub1ew или в NashStore: https://store.nashstore.ru/store/651cf1c60a39b23f221fc121 (нужна версия приложения не меньше 4.5).
Документацию к приложению можно получить здесь.