sentiments colors, topics in dashboard
parent
f7c0df98b2
commit
40057f7971
|
@ -238,6 +238,10 @@ main {
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ol{
|
||||||
|
padding-left: 1em
|
||||||
|
}
|
||||||
|
|
||||||
#video {
|
#video {
|
||||||
grid-area: video;
|
grid-area: video;
|
||||||
}
|
}
|
||||||
|
@ -343,3 +347,30 @@ ul.segments li{
|
||||||
.track-viz svg{
|
.track-viz svg{
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sentiments-list{
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sentiments-list li{
|
||||||
|
margin-top: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sentiments-list span{
|
||||||
|
display: inline-block;
|
||||||
|
background: #d01c8b;
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
border-radius: 50%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sentiments-list span.pos{
|
||||||
|
background: #4dac26;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sentiments-list span.neut{
|
||||||
|
background: #f7f7f7;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ function setWordCountChart(){
|
||||||
// let max = totalWordCount / count;
|
// let max = totalWordCount / count;
|
||||||
let data = [];
|
let data = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let wordWordsLen = wordWords.length;
|
let wordWordsLen = wordWords.length;
|
||||||
let chunks = Math.floor(wordWordsLen / count);
|
let chunks = Math.floor(wordWordsLen / count);
|
||||||
|
|
||||||
|
@ -69,8 +71,6 @@ function setWordCountChart(){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(max)
|
|
||||||
|
|
||||||
for(let i = 0; i < count; i++){
|
for(let i = 0; i < count; i++){
|
||||||
grid.push({
|
grid.push({
|
||||||
left: `${i * (100 / count)}%`,
|
left: `${i * (100 / count)}%`,
|
||||||
|
@ -170,12 +170,22 @@ const chartSentimentsOptions = {
|
||||||
type: "category",
|
type: "category",
|
||||||
data: ["-1", "0", "1"]
|
data: ["-1", "0", "1"]
|
||||||
},
|
},
|
||||||
color: '#fff',
|
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
symbolSize: sentiWeights,
|
symbolSize: sentiWeights,
|
||||||
data: sentiPol,
|
data: sentiPol,
|
||||||
type: 'scatter'
|
type: 'scatter',
|
||||||
|
itemStyle: {
|
||||||
|
color: (e) => {
|
||||||
|
if(e.data == -1){
|
||||||
|
return '#d01c8b'
|
||||||
|
}else if(e.data == 0){
|
||||||
|
return '#f7f7f7'
|
||||||
|
}else{
|
||||||
|
return '#4dac26'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -288,40 +298,5 @@ document.querySelector('#timeline-bar').addEventListener('click', e => {
|
||||||
player.currentTime(calcCurrenttimeByPosition(x));
|
player.currentTime(calcCurrenttimeByPosition(x));
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
const topics = [
|
|
||||||
["Topic1 Topic2 Topic3"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic6 Topic7 Topic8"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3"],
|
|
||||||
["Topic1 Topic2 Topic3", "Topic3 Topic4 Topic5", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3", "Topic1 Topic2 Topic3"],
|
|
||||||
];
|
|
||||||
|
|
||||||
function setTopicSegments(count){
|
|
||||||
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
topics[count - 1].forEach(t => {
|
|
||||||
html += `<li>${t}</li>`;
|
|
||||||
})
|
|
||||||
|
|
||||||
let list = document.querySelector('#topic-segement-list');
|
|
||||||
list.innerHTML = html;
|
|
||||||
list.style.gridTemplate = `1fr / repeat(${count}, 1fr)`;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let topicSegmentCtrl = document.getElementById('topic-track-segment-ctrl');
|
|
||||||
|
|
||||||
topicSegmentCtrl.addEventListener('change', e => {
|
|
||||||
setTopicSegments(e.target.value);
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
setTopicSegments(topicSegmentCtrl.value);
|
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="visually-hidden" id="tablist_panel_terms" name="tablist" type="radio" /><label
|
<input class="visually-hidden" id="tablist_panel_terms" name="tablist" type="radio" /><label
|
||||||
for="tablist_panel_terms"><span class="visually-hidden">Zeige Tabinhalt
|
for="tablist_panel_terms"><span class="visually-hidden">Zeige Tabinhalt
|
||||||
</span>Dokumentbegriffe</label>
|
</span>Topics</label>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="panel" id="tablist_panel_episode_panel">
|
<div class="panel" id="tablist_panel_episode_panel">
|
||||||
|
@ -69,9 +69,15 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="panel" id="tablist_panel_terms_panel" hidden>
|
<div class="panel" id="tablist_panel_terms_panel" hidden>
|
||||||
<h2 class="visually-hidden">
|
<h2 class="visually-hidden">
|
||||||
Begriffe (Tabinhalt)
|
Topics (Tabinhalt)
|
||||||
</h2>
|
</h2>
|
||||||
<div id="metagrid-widget"></div>
|
<ol>
|
||||||
|
@foreach($topics as $topic)
|
||||||
|
<li>
|
||||||
|
{{ implode(', ', $topic) }}
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
</ol>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -109,27 +115,13 @@
|
||||||
<div class="track">
|
<div class="track">
|
||||||
<div class="track-ctrl">
|
<div class="track-ctrl">
|
||||||
<h2>Sentiment</h2>
|
<h2>Sentiment</h2>
|
||||||
<p>1 = Positiv<br >0 = Neutral<br >-1 = Negativ</p>
|
<ul id="sentiments-list">
|
||||||
|
<li><span class="pos">1</span> = Positiv ({{ round($senti_subdata['verteilung_perc']['positive']) }}%)</li>
|
||||||
|
<li><span class="neut">0</span> = Neutral ({{ round($senti_subdata['verteilung_perc']['neutral']) }}%)</li >
|
||||||
|
<li><span class="neg">-1</span> = Negativ ({{ round($senti_subdata['verteilung_perc']['negative']) }}%)</li></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="track-viz" id="sentiment-track" data-time="{{ implode(',', $senti_subdata['time']) }}" data-sentiments="{{ $senti_subdata['data'] }}" data-weights="{{ $senti_subdata['weights'] }}"></div>
|
<div class="track-viz" id="sentiment-track" data-time="{{ implode(',', $senti_subdata['time']) }}" data-sentiments="{{ $senti_subdata['data'] }}" data-weights="{{ $senti_subdata['weights'] }}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="track">
|
|
||||||
<div class="track-ctrl">
|
|
||||||
<h2>Topics</h2>
|
|
||||||
<label>
|
|
||||||
Segmente:
|
|
||||||
<input type="number" min="1" max="10" value="4" id="topic-track-segment-ctrl">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="track-viz">
|
|
||||||
<ul id="topic-segement-list" class="segments">
|
|
||||||
<li>1</li>
|
|
||||||
<li>2</li>
|
|
||||||
<li>3</li>
|
|
||||||
<li>4</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -23,23 +23,40 @@ Route::get('/detail/{id}', function(int $id) {
|
||||||
$subtitles = $ep->subtitles;
|
$subtitles = $ep->subtitles;
|
||||||
$mediacomposition = json_decode($ep->mediacomposition, 1);
|
$mediacomposition = json_decode($ep->mediacomposition, 1);
|
||||||
$durationSteps = $mediacomposition['chapterList'][0]['duration'] / 1000 / 10;
|
$durationSteps = $mediacomposition['chapterList'][0]['duration'] / 1000 / 10;
|
||||||
|
$topics = json_decode($ep->topics);
|
||||||
|
|
||||||
|
|
||||||
$subdata = json_decode($ep->subtitle_data, 1);
|
$subdata = json_decode($ep->subtitle_data, 1);
|
||||||
$subdata_senti = json_decode($ep->sentiments_from_sub, 1);
|
$subdata_senti = json_decode($ep->sentiments_from_sub, 1);
|
||||||
|
|
||||||
$subdata_senti['data'] = "";
|
$subdata_senti['data'] = "";
|
||||||
$subdata_senti['weights'] = "";
|
$subdata_senti['weights'] = "";
|
||||||
|
$subdata_senti['verteilung'] = ['neutral' => 0, 'negative' => 0, 'positive' => 0];
|
||||||
|
|
||||||
|
|
||||||
foreach ($subdata_senti['sentiments'] as $value) {
|
foreach ($subdata_senti['sentiments'] as $value) {
|
||||||
$subdata_senti['data'] .= $value[0].",";
|
$subdata_senti['data'] .= $value[0].",";
|
||||||
$subdata_senti['weights'] .= (30 * $value[1]).",";
|
$subdata_senti['weights'] .= (50 * $value[1]).",";
|
||||||
|
if($value[0] === 0){
|
||||||
|
$subdata_senti['verteilung']['neutral']++;
|
||||||
|
}else if($value[0] === 1){
|
||||||
|
$subdata_senti['verteilung']['positive']++;
|
||||||
|
}else{
|
||||||
|
$subdata_senti['verteilung']['negative']++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$subdata_senti_all = $subdata_senti['verteilung']['neutral'] + $subdata_senti['verteilung']['negative'] + $subdata_senti['verteilung']['positive'];
|
||||||
|
|
||||||
|
$subdata_senti['verteilung_perc'] = ['negative' => (100 / $subdata_senti_all) * $subdata_senti['verteilung']['negative'], 'neutral' => (100 / $subdata_senti_all) * $subdata_senti['verteilung']['neutral'], 'positive' => (100 / $subdata_senti_all) * $subdata_senti['verteilung']['positive']];
|
||||||
|
|
||||||
|
|
||||||
$wordsPerMinute = array_slice($subdata['word_count'], -1)[0] / (($mediacomposition['chapterList'][0]['duration'] / 1000) / 60);
|
$wordsPerMinute = array_slice($subdata['word_count'], -1)[0] / (($mediacomposition['chapterList'][0]['duration'] / 1000) / 60);
|
||||||
|
|
||||||
$parser = new Podlove\Webvtt\Parser();
|
$parser = new Podlove\Webvtt\Parser();
|
||||||
$subtitles = $parser->parse($subtitles);
|
$subtitles = $parser->parse($subtitles);
|
||||||
|
|
||||||
return view('detail', ['title' => $title, 'subtitles' => $subtitles, 'mediacomposition' => $mediacomposition, 'durationSteps' => $durationSteps, 'dom_color' => $ep->viz_data, 'subdata' => $subdata, 'senti_subdata' => $subdata_senti, 'wpm' => $wordsPerMinute]);
|
|
||||||
|
return view('detail', ['title' => $title, 'subtitles' => $subtitles, 'mediacomposition' => $mediacomposition, 'durationSteps' => $durationSteps, 'dom_color' => $ep->viz_data, 'subdata' => $subdata, 'senti_subdata' => $subdata_senti, 'wpm' => $wordsPerMinute, 'topics' => $topics]);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,8 +14,14 @@ Zählt die Wortanzahl pro Satz.
|
||||||
python src/normalize_subtitles/count_words.py -ep <int>
|
python src/normalize_subtitles/count_words.py -ep <int>
|
||||||
```
|
```
|
||||||
|
|
||||||
## count_words.py
|
## sentence_sentiment.py
|
||||||
Rechnet die Sentimente pro Satz.
|
Rechnet die Sentimente pro Satz.
|
||||||
```bash
|
```bash
|
||||||
python src/normalize_subtitles/sentence_sentiment.py -ep <int>
|
python src/normalize_subtitles/sentence_sentiment.py -ep <int>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## topics.py
|
||||||
|
Generiert Topics mittels LDA.
|
||||||
|
```bash
|
||||||
|
python src/normalize_subtitles/topics.py -ep <int>
|
||||||
|
```
|
||||||
|
|
BIN
database.sqlite
BIN
database.sqlite
Binary file not shown.
Loading…
Reference in New Issue