Added initial ability to transcribe video messages.

This commit is contained in:
23rd 2022-10-23 22:02:19 +03:00 committed by John Preston
parent b4a9705564
commit 579b20fff7
13 changed files with 134 additions and 21 deletions

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "history/history.h"
#include "main/main_session.h"
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_peer.h"
#include "apiwrap.h"
@ -30,6 +31,9 @@ void Transcribes::toggle(not_null<HistoryItem*> item) {
_session->data().requestItemResize(item);
} else if (!i->second.requestId) {
i->second.shown = !i->second.shown;
if (i->second.roundview) {
_session->data().requestItemViewRefresh(item);
}
_session->data().requestItemResize(item);
}
}
@ -55,6 +59,9 @@ void Transcribes::apply(const MTPDupdateTranscribedAudio &update) {
j->second.result = text;
j->second.pending = update.is_pending();
if (const auto item = _session->data().message(i->second)) {
if (j->second.roundview) {
_session->data().requestItemViewRefresh(item);
}
_session->data().requestItemResize(item);
}
}
@ -63,29 +70,41 @@ void Transcribes::load(not_null<HistoryItem*> item) {
if (!item->isHistoryEntry() || item->isLocal()) {
return;
}
const auto toggleRound = [](not_null<HistoryItem*> item, Entry &entry) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
if (document->isVideoMessage()) {
entry.roundview = true;
document->owner().requestItemViewRefresh(item);
}
}
}
};
const auto id = item->fullId();
const auto requestId = _api.request(MTPmessages_TranscribeAudio(
item->history()->peer->input,
MTP_int(item->id)
)).done([=](const MTPmessages_TranscribedAudio &result) {
result.match([&](const MTPDmessages_transcribedAudio &data) {
auto &entry = _map[id];
entry.requestId = 0;
entry.pending = data.is_pending();
entry.result = qs(data.vtext());
_ids.emplace(data.vtranscription_id().v, id);
if (const auto item = _session->data().message(id)) {
_session->data().requestItemResize(item);
}
});
const auto &data = result.data();
auto &entry = _map[id];
entry.requestId = 0;
entry.pending = data.is_pending();
entry.result = qs(data.vtext());
_ids.emplace(data.vtranscription_id().v, id);
if (const auto item = _session->data().message(id)) {
toggleRound(item, entry);
_session->data().requestItemResize(item);
}
}).fail([=](const MTP::Error &error) {
auto &entry = _map[id];
entry.requestId = 0;
entry.pending = false;
entry.failed = true;
if (error.type() == qstr("MSG_VOICE_TOO_LONG")) {
if (error.type() == u"MSG_VOICE_TOO_LONG"_q) {
entry.toolong = true;
} else if (const auto item = _session->data().message(id)) {
}
if (const auto item = _session->data().message(id)) {
toggleRound(item, entry);
_session->data().requestItemResize(item);
}
}).send();

View File

@ -27,6 +27,7 @@ public:
bool failed = false;
bool toolong = false;
bool pending = false;
bool roundview = false;
mtpRequestId requestId = 0;
};

View File

@ -381,6 +381,10 @@ void DocumentData::setattributes(
type = data.is_round_message()
? RoundVideoDocument
: VideoDocument;
if (data.is_round_message()) {
_additional = std::make_unique<RoundData>();
round()->duration = data.vduration().v;
}
} else if (const auto info = sticker()) {
info->type = StickerType::Webm;
}
@ -397,7 +401,7 @@ void DocumentData::setattributes(
_additional = std::make_unique<SongData>();
}
}
if (const auto voiceData = voice()) {
if (const auto voiceData = voice() ? voice() : round()) {
voiceData->duration = data.vduration().v;
voiceData->waveform = documentWaveformDecode(
data.vwaveform().value_or_empty());
@ -1252,6 +1256,16 @@ const VoiceData *DocumentData::voice() const {
return const_cast<DocumentData*>(this)->voice();
}
RoundData *DocumentData::round() {
return isVideoMessage()
? static_cast<RoundData*>(_additional.get())
: nullptr;
}
const RoundData *DocumentData::round() const {
return const_cast<DocumentData*>(this)->round();
}
bool DocumentData::hasRemoteLocation() const {
return (_dc != 0 && _access != 0);
}

View File

@ -90,6 +90,8 @@ struct VoiceData : public DocumentAdditionalData {
char wavemax = 0;
};
using RoundData = VoiceData;
namespace Serialize {
class Document;
} // namespace Serialize;
@ -152,6 +154,8 @@ public:
[[nodiscard]] const SongData *song() const;
[[nodiscard]] VoiceData *voice();
[[nodiscard]] const VoiceData *voice() const;
[[nodiscard]] RoundData *round();
[[nodiscard]] const RoundData *round() const;
void forceIsStreamedAnimation();
[[nodiscard]] bool isVoiceMessage() const;

View File

@ -1048,6 +1048,23 @@ std::unique_ptr<HistoryView::Media> MediaFile::createView(
_document,
_skipPremiumEffect,
replacing));
} else if (_document->isVideoMessage()) {
const auto &entry = _document->session().api().transcribes().entry(
parent());
if (!entry.requestId
&& entry.shown
&& entry.roundview
&& !entry.pending) {
return std::make_unique<HistoryView::Document>(
message,
realParent,
_document);
} else {
return std::make_unique<HistoryView::Gif>(
message,
realParent,
_document);
}
} else if (_document->isAnimation() || _document->isVideoFile()) {
return std::make_unique<HistoryView::Gif>(
message,

View File

@ -839,7 +839,7 @@ std::optional<int> RepliesList::computeUnreadCountLocally(
end(_list),
wasReadTillId,
std::greater<>());
return std::max(*wasUnreadCountAfter - (till - from), 0);
return std::max(int(*wasUnreadCountAfter - (till - from)), 0);
}
return std::nullopt;
}

View File

@ -155,7 +155,7 @@ void PaintWaveform(
if (const auto song = document->song()) {
add(FormatPlayedText(duration, duration));
add(FormatDurationAndSizeText(duration, document->size));
} else if (const auto voice = document->voice()) {
} else if (const auto voice = document->voice() ? document->voice() : document->round()) {
add(FormatPlayedText(duration, duration));
add(FormatDurationAndSizeText(duration, document->size));
} else if (document->isVideoFile()) {
@ -174,6 +174,12 @@ Document::Document(
not_null<DocumentData*> document)
: File(parent, realParent)
, _data(document) {
if (_data->isVideoMessage()) {
const auto &entry = _data->session().api().transcribes().entry(
realParent);
_transcribedRound = entry.shown;
}
auto caption = createCaption();
createComponents(!caption.isEmpty());
@ -215,7 +221,7 @@ bool Document::dataLoaded() const {
void Document::createComponents(bool caption) {
uint64 mask = 0;
if (_data->isVoiceMessage()) {
if (_data->isVoiceMessage() || _transcribedRound) {
mask |= HistoryDocumentVoice::Bit();
} else {
mask |= HistoryDocumentNamed::Bit();
@ -344,7 +350,9 @@ QSize Document::countOptimalSize() {
if (thumbed) {
accumulate_max(maxWidth, tleft + MaxStatusWidth(_data) + tright);
} else {
auto unread = _data->isVoiceMessage() ? (st::mediaUnreadSkip + st::mediaUnreadSize) : 0;
auto unread = (_data->isVoiceMessage() || _transcribedRound)
? (st::mediaUnreadSkip + st::mediaUnreadSize)
: 0;
accumulate_max(maxWidth, tleft + MaxStatusWidth(_data) + unread + _parent->skipBlockWidth() + st::msgPadding.right());
}
@ -604,8 +612,11 @@ void Document::draw(
if (voice) {
ensureDataMediaCreated();
if (const auto voiceData = _data->voice()) {
if (voiceData->waveform.isEmpty()) {
{
const auto voiceData = _data->isVideoMessage()
? _data->round()
: _data->voice();
if (voiceData && voiceData->waveform.isEmpty()) {
if (loaded) {
Local::countVoiceWaveform(_dataMedia.get());
}
@ -642,7 +653,7 @@ void Document::draw(
PaintWaveform(p,
context,
_data->voice(),
_transcribedRound ? _data->round() : _data->voice(),
namewidth + st::msgWaveformSkip,
progress);
p.restore();
@ -1156,6 +1167,8 @@ void Document::setStatusSize(int64 newSize, TimeId realDuration) const {
? _data->song()->duration
: (_data->isVoiceMessage()
? _data->voice()->duration
: _transcribedRound
? _data->round()->duration
: -1);
File::setStatusSize(newSize, _data->size, duration, realDuration);
if (auto thumbed = Get<HistoryDocumentThumbed>()) {
@ -1190,7 +1203,7 @@ bool Document::updateStatusText() const {
statusSize = Ui::FileStatusSizeReady;
}
if (_data->isVoiceMessage()) {
if (_data->isVoiceMessage() || _transcribedRound) {
const auto state = ::Media::Player::instance()->getState(AudioMsgId::Type::Voice);
if (state.id == AudioMsgId(_data, _realParent->fullId(), state.id.externalPlayId())
&& !::Media::Player::IsStoppedOrStopping(state.state)) {

View File

@ -174,6 +174,8 @@ private:
mutable TooltipFilename _tooltipFilename;
bool _transcribedRound = false;
};
bool DrawThumbnailAsSongCover(

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/media/history_view_gif.h"
#include "apiwrap.h"
#include "api/api_transcribes.h"
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "main/main_session.h"
@ -93,6 +95,13 @@ Gif::Gif(
_data->loadVideoThumbnail(realParent->fullId());
}
}
_transcribe = std::make_shared<LambdaClickHandler>([=,
id = realParent->fullId()] {
if (const auto item = _data->session().data().message(id)) {
_data->session().api().transcribes().toggle(item);
}
});
}
Gif::~Gif() {
@ -673,6 +682,21 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
fastShareTop -= (st::msgDateImgDelta + st::msgDateImgPadding.y() + st::msgDateFont->height + st::msgDateImgPadding.y());
}
_parent->drawRightAction(p, context, fastShareLeft, fastShareTop, 2 * paintx + paintw);
if (_data->session().premium()) {
const auto stm = context.messageStyle();
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
p.setBrush(context.st->msgServiceBg());
const auto s = st::historyFastShareSize;
const auto r = QRect(
fastShareLeft,
fastShareTop - s - st::msgDateImgDelta,
s,
s);
p.drawEllipse(r);
context.st->historyFastTranscribeIcon().paintInCenter(p, r);
}
}
}
}
@ -976,6 +1000,17 @@ TextState Gif::textState(QPoint point, StateRequest request) const {
if (QRect(fastShareLeft, fastShareTop, size->width(), size->height()).contains(point)) {
result.link = _parent->rightActionLink();
}
if (_data->session().premium()) {
const auto s = st::historyFastShareSize;
const auto r = QRect(
fastShareLeft,
fastShareTop - s - st::msgDateImgDelta,
s,
s);
if (r.contains(point)) {
result.link = _transcribe;
}
}
}
}
return result;

View File

@ -201,6 +201,8 @@ private:
mutable bool _thumbCacheBlurred = false;
mutable bool _thumbIsEllipse = false;
ClickHandlerPtr _transcribe;
};
} // namespace HistoryView

View File

@ -876,6 +876,7 @@ historyFastShareBottom: 5px;
historyFastShareIcon: icon {{ "fast_share", msgServiceFg }};
historyGoToOriginalIcon: icon {{ "fast_to_original", msgServiceFg }};
historyFastCommentsIcon: icon {{ "fast_comments", msgServiceFg }};
historyFastTranscribeIcon: icon {{ "chat/voice_to_text", msgServiceFg }};
historySavedFont: font(semibold 14px);

View File

@ -85,6 +85,7 @@ ChatStyle::ChatStyle() {
make(_msgBotKbWebviewIcon, st::msgBotKbWebviewIcon);
make(_historyFastCommentsIcon, st::historyFastCommentsIcon);
make(_historyFastShareIcon, st::historyFastShareIcon);
make(_historyFastTranscribeIcon, st::historyFastTranscribeIcon);
make(_historyGoToOriginalIcon, st::historyGoToOriginalIcon);
make(_historyMapPoint, st::historyMapPoint);
make(_historyMapPointInner, st::historyMapPointInner);

View File

@ -252,6 +252,9 @@ public:
[[nodiscard]] const style::icon &historyFastShareIcon() const {
return _historyFastShareIcon;
}
[[nodiscard]] const style::icon &historyFastTranscribeIcon() const {
return _historyFastTranscribeIcon;
}
[[nodiscard]] const style::icon &historyGoToOriginalIcon() const {
return _historyGoToOriginalIcon;
}
@ -344,6 +347,7 @@ private:
style::icon _msgBotKbWebviewIcon = { Qt::Uninitialized };
style::icon _historyFastCommentsIcon = { Qt::Uninitialized };
style::icon _historyFastShareIcon = { Qt::Uninitialized };
style::icon _historyFastTranscribeIcon = { Qt::Uninitialized };
style::icon _historyGoToOriginalIcon = { Qt::Uninitialized };
style::icon _historyMapPoint = { Qt::Uninitialized };
style::icon _historyMapPointInner = { Qt::Uninitialized };