Commit f23e7ea1 authored by Yorrd's avatar Yorrd
Browse files

fix: adjustments to the landing page and some bot things

parent f6bf810e
Pipeline #1438 passed with stages
in 11 minutes and 38 seconds
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/webcomponentsjs/webcomponents-loader.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="/webcomponentsjs/webcomponents-loader.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Barlow" rel="stylesheet">
<style>
body {
padding: 0px;
margin: 0px;
font-family: "Barlow", sans-serif;
}
</style>
</head>
\ No newline at end of file
<link href="https://fonts.googleapis.com/css?family=Barlow" rel="stylesheet" />
<style>
body {
padding: 0px;
margin: 0px;
font-family: 'Barlow', sans-serif;
}
</style>
<!-- <script>
window.intergramId = '-430832444';
window.intergramCustomizations = {
titleClosed: 'Closed chat title',
titleOpen: 'Opened chat title',
introMessage: '/start',
autoResponse: 'A message that is sent immediately after the user sends its first message',
autoNoResponse:
'A message that is sent one minute after the user sends its first message ' + 'and no response was received',
mainColor: '#E91E63', // Can be any css supported color 'red', 'rgb(255,87,34)', etc
alwaysUseFloatingButton: false, // Use the mobile floating button also on large screens
};
</script>
<script id="intergram" type="text/javascript" src="https://www.intergram.xyz/js/widget.js"></script> -->
</head>
......@@ -15,10 +15,9 @@ import { BreakPoint, listenDevice } from 'imports/git_modules/base/window-size';
import { ifDefined } from 'lit-html/directives/if-defined';
import { repeat } from 'lit-html/directives/repeat';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { distinctUntilChanged, map, switchMap, takeUntil } from 'rxjs/operators';
import { distinctUntilChanged, map, switchMap, takeUntil, take } from 'rxjs/operators';
const moment = require('moment');
@element('ccb-contents-admin')
export class CCBContentsAdmin extends AdornisDBView<Content> {
@rerender public filterForOwnEntities = new BehaviorSubject(false);
......@@ -95,7 +94,7 @@ export class CCBContentsAdmin extends AdornisDBView<Content> {
<mwc-button raised icon="add" @click=${() => this.createNewBasicInstanceAndSave(this.fields.getValue())}>
Frage hinzufügen
</mwc-button>
${this.csvUploadButton()}
${this.csvUploadButton()} ${this.syncWithDialogflowButton()}
</a-inline>
<a-inline size="md">
${rxRepeat(
......@@ -410,48 +409,55 @@ export class CCBContentsAdmin extends AdornisDBView<Content> {
const contents = await this.askForFile('*.csv');
const array2d = contents.split('\n').map(line => line.split(';'));
console.log('Client Log');
Content.csvImport(contents).subscribe();
/*
if (array2d[0][0] === 'A.1') {
console.log('Richtige Versionsnummer');
if (array2d[24][0].startsWith('#')) {
console.log('Formatierung scheint nicht geändert worden zu sein. Gut so!');
const importResult = await Content.csvImport(contents)
.pipe(take(1))
.toPromise();
for (var i = 0; i <= 14; i++) {
console.log(array2d[24][i]);
if (array2d[24][i] !== ('' || undefined)) {
console.log('Fortschritt');
}
}
}
}*/
console.log('Antwort: ' + importResult);
if (importResult === false) {
AdornisDialog.showPopup(
resolve =>
html`
<a-stack padding="md" size="sm">
<ccb-h3>Error</ccb-h3>
// await Promise.all(
// contents
// .split('\n')
// .slice(1)
// .map(async line => {
// const [type, question, answer, deepnessLevel, date, source, contactName, contactMail] = line.split(';');
// // Check if content is new
// console.log('Hier loggt Markus jetzt:');
// let contentCheck = await Content.findOne({ Rechtsgebiet: type, Frage: question }).result;
// if (!contentCheck) {
// contentCheck = new Content({
// Rechtsgebiet: type,
// Frage: question,
// Antwort: answer,
// Quelle: source,
// Ansprechpartner: contactName + ', ' + contactMail,
// });
// // contentCheck.save().subscribe(console.log);
// console.log(contentCheck);
// } else console.log('[UPLOAD] Mult. content skipped - ID:', contentCheck._id, 'Q:', contentCheck.Frage);
// }),
// );
<ccb-text
>Mindestens einer der Usernamen aus der .csv stimmt nicht mit den Usernamen auf dem Server
überein.</ccb-text
>
<a-box horizontal centerjustified style="padding: ${spacing.md} 0 0 0"
><mwc-icon
class="${this.css({ cursor: 'pointer', userselect: 'none' })}"
@click=${() => resolve()}
>highlight_off</mwc-icon
></a-box
>
</a-stack>
`,
);
} else {
AdornisDialog.showPopup(
resolve =>
html`
<a-stack padding="md" size="sm">
<ccb-h3>Success</ccb-h3>
<ccb-text>Upload der .csv war erfolgreich</ccb-text>
<a-box horizontal centerjustified style="padding: ${spacing.md} 0 0 0"
><mwc-icon
class="${this.css({ cursor: 'pointer', userselect: 'none' })}"
@click=${() => resolve()}
>highlight_off</mwc-icon
></a-box
>
</a-stack>
`,
);
}
}}"
>
CSV hochladen!
CSV hochladen
</mwc-button>
`;
}
......@@ -479,4 +485,12 @@ export class CCBContentsAdmin extends AdornisDBView<Content> {
</mwc-button>
`;
}
protected syncWithDialogflowButton() {
return html`
<mwc-button icon="refresh" @click=${() => Content.syncWithDialogflow().subscribe(res => alert(res))}>
sync with dialogflow
</mwc-button>
`;
}
}
......@@ -18,49 +18,66 @@ export class CCBLandingPage extends EmotionMixin(ScopingElement) {
return html`
<a-stack size="xl">
<a-inline horizontal size="lg" padding="xl" style=${{ width: `calc(100vw - ${spacing.xl} * 2)` }}>
<a-stack size="md" class="${this.css({ flex: '1' })}">
<ccb-text>Hi!</ccb-text>
<a-stack size="md" class="${this.css({ flex: '1', paddingTop: spacing.xxl })}">
<ccb-text style=${{ fontWeight: 'bold' }}> Unsere Mission </ccb-text>
<ccb-text>
Der Corona Legal Chatbot soll alle rechtlichen Fragen beantworten, die im Zusammenhang mit der
Corona-Krise entstanden sind.
Wir sind ein Team aus Tech und Legal Begeisterten und haben im Rahmen des #wirvsvirus Hackathon
der Bundesregierung einen Corona Legal Chatbot entwickelt. Er soll jede Frage im Zusammenhang
mit den rechtlichen Auswirkungen um Covid-19 beantworten können und damit Behörden entlasten.
Egal ob sich einem Arbeitnehmer Fragen zur Entschädigung für Kinderbetreuung stellen oder ein
Arbeitgeber Kurzarbeitergeld beantragen möchte.
</ccb-text>
<ccb-text
>Als Experte, Behörde oder Institution könnt ihr eure FAQs hier bereitstellen und diese
regelmäßig updaten.</ccb-text
>
<ccb-text>
Viele dieser Fragen sind repetitiv. Der Corona Legal Chatbot kann helfen, das große
Informationsbedürfnis in der Bevölkerung zu befriedigen und die Funktionsfähigkeit von Behörden
aufrechtzuerhalten.
</ccb-text>
<ccb-text>
Der Corona Legal Chatbot ist bereits in der Messenger-App Telegram #coronalegalchatbot
erreichbar. Er kann aber auch auf jeder Website integriert und beispielsweise einem Callcenter
vorgeschaltet werden.
</ccb-text>
<ccb-text>
Wir sind keine Mediziner oder Virologen. Doch mit dem Corona Legal Chatbot möchten wir vor dem
Hintergrund unserer Expertise u.a. als Juristen, Software-Entwickler und Medienpädagogen einen
Beitrag zur Bewältigung der aktuellen Krise leisten.
</ccb-text>
<a-stack class="${this.css({ alignItems: 'center' })}" size="md">
<a-link href="mailto:dialog@coronalegalchatbot.de">
<ccb-button secondary> Jetzt kontaktieren </ccb-button>
</a-link>
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/0l38cOidQGo"
frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
</a-stack>
</a-stack>
<a-stack size="md" class="${this.css({ flex: '1', justifyContent: 'center', minWidth: '300px' })}">
<a-link
href="https://t.me/CoronaLegalChatBot"
target="_blank"
class="${this.css({ marginBottom: spacing.xl })}"
>
<ccb-button class="${this.css({ width: '100%' })}"
>Zum Legal Chatbot für&nbsp;<b>Fragende</b></ccb-button
>
</a-link>
<a-link href="/contentadmin">
<ccb-button secondary class="${this.css({ width: '100%' })}">
Als&nbsp;<b>Institution</b>&nbsp;FAQs hinterlassen (bspw. LandesReg.)
<a-stack size="md" class="${this.css({ alignItems: 'center' })}">
<ccb-text style=${{ fontStyle: 'italic', textAlign: 'center' }}>
Diese Demo speist sich aus etwa 100 Beispiel-Antworten und kann den Inhalten Deiner Behörde
passgenau zugeschnitten werden. Es soll lediglich die grundsätzliche Funktionsweise
demonstriert werden.
</ccb-text>
</a-stack>
<a-link href="https://t.me/CoronaLegalChatBot" target="_blank">
<ccb-button class="${this.css({ width: '100%' })}">
Zum Legal Chatbot für&nbsp;<b>Fragende</b> auf Telegram
</ccb-button>
</a-link>
<a-link href="/contentadmin">
<ccb-button secondary class="${this.css({ width: '100%' })}">
Als&nbsp;<b>Experte</b>&nbsp;FAQs hinterlassen (bspw. Kanzlei)
Zum Autorentool
</ccb-button>
</a-link>
</a-stack>
</a-inline>
<a-stack class="${this.css({ alignItems: 'center' })}">
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/0l38cOidQGo"
frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
</a-stack>
<a-stack size="xl" class="${this.css({ alignItems: 'center' })}">
<ccb-h4>Unsere Partner:</ccb-h4>
<a-box padding="xl">
......
import { Entity, Field } from '@adornis/baseql/decorators';
import { Entity, Field, RPC } from '@adornis/baseql/decorators';
import { MongoEntity, nothingSelector } from '@adornis/baseql/entities/mongo.type';
import { dateNow } from '@adornis/baseql/validators';
import { AdornisUser } from '@adornis/users/db';
......@@ -6,6 +6,9 @@ import { ID } from '@adornis/baseql/baseqlTypes';
import { AdornisEntity } from '@adornis/baseql/entities/adornis.type';
import { isClient, isServer } from '@adornis/baseql/isServer-isClient';
import { AdornisFile, files } from '@adornis/file-utils/db';
import csv from 'csv-parser';
import { IntentsClient, SessionsClient } from 'dialogflow';
import { CCBUser } from './ccbuser';
/**
* Database index for fallback answer querying
......@@ -39,6 +42,8 @@ export class Content extends AdornisFile {
public Rechtsgebiet?: string;
@Field(String)
public Frage?: string;
@Field([String], { default: [] })
public AlternativFragen!: string[];
@Field(String)
public Antwort?: string;
@Field(Date, { preSaveHook: dateNow() })
......@@ -84,6 +89,63 @@ export class Content extends AdornisFile {
}
}
@RPC(Boolean)
public static csvImport(_, content: string) {
const { Readable } = require('stream');
const readable = Readable.from(content);
const results: {
Frage: string;
Quelle: string;
Rechtsgebiet: string;
Antwort: string;
createdby: string;
createdat: string;
[key: string]: string;
}[] = [];
return new Promise(resolve => {
readable.pipe(
csv({ skipLines: 20, separator: ';' })
.on('data', data => results.push(data))
.on('end', async () => {
console.log(results);
var i;
for (i = 0; i <= results.length - 1; i++) {
let contentCheck = (await Content.findOne({ _id: results[i]['# (wird automatisch erstellt)'] })
.result) as Content;
if (!contentCheck) {
contentCheck = new Content({
Frage: results[i]['Frage'],
Quelle: results[i]['Quelle'],
Rechtsgebiet: results[i]['Rechtsgebiet'],
Antwort: results[i]['Antwort'],
createdby: (await CCBUser.findOne({ username: results[i]['createdby'] }).result)?._id,
});
} else {
contentCheck.Quelle = results[i]['Quelle'];
contentCheck.createdBy = (await CCBUser.findOne({ username: results[i]['createdby'] }).result)?._id;
contentCheck.Rechtsgebiet = results[i]['Rechtsgebiet'];
contentCheck.Frage = results[i]['Frage'];
contentCheck.Antwort = results[i]['Antwort'];
if ((await CCBUser.findOne({ username: results[i]['createdby'] }).result)?._id === undefined) {
console.log('Username in .csv ist nicht korrekt');
resolve(false);
break;
}
}
contentCheck.save().subscribe(console.log);
// [
// { NAME: 'Daffy Duck', AGE: '24' },
// { NAME: 'Bugs Bunny', AGE: '22' }
// ]}
}
resolve(true);
}),
);
});
}
public crawlSource() {
if (!this.Quelle || !this.Quelle.length) return;
const request = require('request-promise-native');
......@@ -97,4 +159,80 @@ export class Content extends AdornisFile {
return '';
});
}
@RPC(Boolean)
public static async syncWithDialogflow() {
console.log('lel, working on it');
// You can find your project ID in your Dialogflow agent settings
const projectId = '<project-id-here>';
const sessionId = '<put-chat-session-id-here>';
// const sessionid = 'fa2d5904-a751-40e0-a878-d622fa8d65d9'
const query = 'hi';
const languageCode = 'en-US';
const credentials = {
client_email: '<client-email-here>',
private_key:
'<private-key-here>',
};
// Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new SessionsClient({
projectId,
credentials,
});
// Instantiates the Intent Client
const intentsClient = new IntentsClient();
// The path to identify the agent that owns the created intent.
const agentPath = intentsClient.projectAgentPath('coronalegalchatbot-tuelpk');
const trainingPhrasesParts = [];
const trainingPhrases = [];
const messageTexts = ['antwort?'];
const displayName = '[test] intent?';
trainingPhrasesParts.forEach(trainingPhrasesPart => {
const part = {
text: trainingPhrasesPart,
};
// Here we create a new training phrase for each provided part.
const trainingPhrase = {
type: 'EXAMPLE',
parts: [part],
};
trainingPhrases.push(trainingPhrase);
});
const messageText = {
text: messageTexts,
};
const message = {
text: messageText,
};
const intent = {
displayName: displayName,
trainingPhrases: trainingPhrases,
messages: [message],
};
const createIntentRequest = {
parent: agentPath,
intent: intent,
};
// Create the intent
const responses = await intentsClient.createIntent(createIntentRequest);
console.log(`Intent ${responses[0].name} created`);
// [END dialogflow_create_intent]
return true;
}
}
Subproject commit 660d7196c3402323df862d79b2cdc267a7870400
Subproject commit fdb4bd9bdcd819ce8f4ae03303574ca615de4985
Subproject commit 2aa992292f34db72fec830d265c4e28e3daccdd5
Subproject commit 162ac64f5e009c09e96f0dc772e1483b0b894247
Subproject commit dad8137411d3b2a9b3511b0fa8afd8366866b701
Subproject commit 67b52f73a329101e4a26c3d277472b9399e39ef5
Subproject commit 153388095f8befaf4b5b07f282ffaebc015a3eba
Subproject commit 9a98ea5e4d06adb115d5ff06f986e7aa97566199
......@@ -1139,6 +1139,14 @@
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-0.0.30.tgz",
"integrity": "sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ=="
},
"@types/dialogflow": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/dialogflow/-/dialogflow-4.0.4.tgz",
"integrity": "sha512-W0sSi/Zrn+HJ/Rijhteoh9bcI4dEBx5qAhcfRk614/ovV/E+/WmQTJlKHh/pbHcks17vDxdc0RrJ9IJ7MH6u5w==",
"requires": {
"dialogflow": "*"
}
},
"@types/dialogflow-fulfillment": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@types/dialogflow-fulfillment/-/dialogflow-fulfillment-0.6.0.tgz",
......
......@@ -10,202 +10,180 @@ import { Content } from 'imports/db';
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
const expressApp = express();
expressApp.post('/api/dialogflow-webhook', (request, response, next) => {
let data = '';
request.on('data', e => {
data += e.toString();
});
request.on('end', () => {
request.body = JSON.parse(data);
const agent = new WebhookClient({ request, response });
async function yourFunctionHandler(agent: WebhookClient) {
console.log(JSON.stringify(agent.originalRequest, null, 2));
if (agent.query.includes('/land')) {
agent.add(
'Land zu Deutschland gewechselt. Wir arbeiten an der Datengrundlage für weitere Länder. Die Schweiz und Niederlande sollen demnächst folgen',
async function yourFunctionHandler(agent: WebhookClient) {
console.log(agent);
console.log(JSON.stringify(agent.originalRequest, null, 2));
if (agent.query.includes('/land')) {
agent.add(
'Land zu Deutschland gewechselt. Wir arbeiten an der Datengrundlage für weitere Länder. Die Schweiz und Niederlande sollen demnächst folgen',
);
agent.add('Wie kann ich dir helfen?');
return;
}
//This is 4fun and should be removed as soon as intents are working properly, or it might cause complications
if (
agent.query.length <= 4 &&
!agent.query.includes('/start') &&
!agent.query.includes('/land') &&
!agent.query.includes('Ja') &&
!agent.query.includes('Nein')
) {
if (agent.query.match('test')) {
agent.add('Starte Testsequenz...');
agent.add('Biep Boop. Biep Boop.');
agent.add('... Test erfolgreich abgeschlossen. Was genau sollte ich nochmal testen?');
return;
}
agent.add('Tut mir Leid, ich kann leider noch keinen Small Talk');
agent.add('Aber stell mir doch eine rechtliche Frage :)');
return;
}
if (agent.query.includes('Kontakt aufnehmen')) {
// TODO intent detection
agent.add(
'Du interessierst dich für Steuerrecht, ich habe einen passenden Partner aus unserem Netzwerk für dich gefunden.',
);
agent.add(
new Card({
title: 'Rechtsanwältin Mirella Endt-Eckhardt',
text: 'Tel. +4916094430671 \nMail: mail@steuernundrecht.berlin',
buttonText: 'Website',
buttonUrl: 'https://www.steuernundrecht.berlin',
}),
);
return;
}
// answer to disclaimer
if (agent.contexts.find(el => el.name === 'asked-for-disclaimer')) {
if (agent.query === 'Ja') {
agent.add('Du scheinst dich in Deutschland aufzuhalten. Wenn das nicht stimmt, wechsle das Land mit /land');
agent.add('Wie kann ich dir helfen?');
} else {
agent.add(
'Disclaimer: \nDer Legal Chatbot richtet sich an Unternehmer und Unternehmen sowie juristische Laien und Interessierte, die allgemeine rechtliche Informationen suchen. Um für diese Zielgruppe rechtliche Sachverhalte verständlich darstellen zu können, werden unsere Informationen oftmals vereinfacht und verkürzt dargestellt. Die Legal Chatbot Antworten dienen insofern lediglich der Information und geben die Auffassung und Meinung der jeweiligen Autor*innen/ Institutionen wieder. Die Legal Chatbot Antworten können daher nicht als Rechtsberatung angesehen werden, da konkrete Fälle zu unterschiedlich sind, um sie anhand einer Legal Chatbot Antwort zu lösen zu können. Die Legal Chatbot Beiträge spiegeln lediglich die Rechtslage zum jeweiligen Veröffentlichungsdatum wieder.',
);
agent.add('Du scheinst dich in Deutschland aufzuhalten. Wenn das nicht stimmt, wechsle das Land mit /land');
agent.add('Wie kann ich dir helfen?');
}
return;
}
if (agent.query.includes('weiter suchen') || agent.query.includes('noch einmal suchen')) {
return;
}
if (agent.query.includes('danke')) {
agent.add('gerne! :) Wie kann ich dir noch helfen?');
return;
}
switch (agent.intent) {
case 'welcome disclaimer': {
agent.add('Hallo ' + agent.originalRequest.payload.data.from.first_name);
agent.add(
'Ich bin erst wenige Stunden alt, also noch eine Beta-Version. Es kann sein, dass mich die ein oder andere Frage noch verwirrt. Wenn Du mir Feedback gibst lerne ich und werde jeden Tag besser! \nKennst du schon den Disclaimer zur Haftung und zum Datenschutz schon?',
);
agent.add(new Suggestion('Ja'));
agent.add(new Suggestion('Nein'));
agent.setContext({ name: 'asked-for-disclaimer', lifespan: 1 });
break;
}
default: {
let content: Content | null = null;
if (agent.intent && (await Content.findOne({ intent: agent.intent }).result)) {
const foundContent = (await Content.findOne({ intent: agent.intent }).result) as Content | null;
content = foundContent;
} else {
const foundContents = await (files.rawCollection() as Collection)
.find({ $text: { $search: agent.query } })
.project({ score: { $meta: 'textScore' } })
// .filter({ score: { $gte: 0.7 } })
.sort({ score: { $meta: 'textScore' } })
.toArray();
console.log(
'scores',
foundContents.map(x => x.score),
);
agent.add('Wie kann ich dir helfen?');
return;
}
//This is 4fun and should be removed as soon as intents are working properly, or it might cause complications