diff --git a/Dockerfile b/Dockerfile
index d548409661b4e637f7414828e1c17e86b4478900..b3da5f370c20f0bb468e71786e2c2d93a499fa49 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,5 @@
# pull official base image
-FROM python:3.10-bullseye
-
+FROM python:3.12-bullseye
RUN useradd -m -u 1000 user
USER user
@@ -26,7 +25,6 @@ RUN pip install --no-cache-dir --upgrade -r requirements.txt
COPY --chown=user . /app
RUN python manage.py migrate
-
CMD ["python", "manage.py", "runserver", "0.0.0.0:7860"]
#CMD ["uvicorn", "spaces.asgi:application", "--host", "0.0.0.0", "--port", "7860"]
\ No newline at end of file
diff --git a/dashboard/__init__.py b/dashboard/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dashboard/admin.py b/dashboard/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..47aaf9a81cb67e6edc560f2fd03779557798c26a
--- /dev/null
+++ b/dashboard/admin.py
@@ -0,0 +1,7 @@
+from django.contrib import admin
+
+# Register your models here.
+from django.contrib import admin
+from .models import Country
+
+admin.site.register(Country)
\ No newline at end of file
diff --git a/dashboard/apps.py b/dashboard/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b1cc053ac6a6ab71e1104a691564c4bb933e6b7
--- /dev/null
+++ b/dashboard/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class DashboardConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'dashboard'
diff --git a/dashboard/commands/generate_companies.py b/dashboard/commands/generate_companies.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f3d9cf90c6b3185c2fb7c690702bca00636455c
--- /dev/null
+++ b/dashboard/commands/generate_companies.py
@@ -0,0 +1,32 @@
+import random
+from django.core.management.base import BaseCommand
+from dashboard.models import Country, Company
+
+
+class Command(BaseCommand):
+ help = "Generate random companies for all countries"
+
+ def handle(self, *args, **kwargs):
+ company_names = [
+ "Global Tech Inc.", "Alpha Industries", "Beta Solutions", "Delta Corp.",
+ "Zeta Enterprises", "Omega Systems", "Apollo Holdings", "Titan Innovations"
+ ]
+
+ for country in Country.objects.all():
+ self.stdout.write(f"Generating companies for {country.name}...")
+ for _ in range(random.randint(3, 6)): # Generate 3-6 companies per country
+ Company.objects.create(
+ name=random.choice(company_names),
+ country=country,
+ balance_sheet={
+ "Aktiva": {
+ "Anlagevermögen": random.randint(100000, 500000),
+ "Umlaufvermögen": random.randint(50000, 200000)
+ },
+ "Passiva": {
+ "Eigenkapital": random.randint(70000, 300000),
+ "Fremdkapital": random.randint(20000, 150000)
+ }
+ }
+ )
+ self.stdout.write(self.style.SUCCESS("Companies successfully generated!"))
diff --git a/dashboard/commands/load_coordinates.py b/dashboard/commands/load_coordinates.py
new file mode 100644
index 0000000000000000000000000000000000000000..f19573c86d9f93dcf02bdb572e2973340f466e75
--- /dev/null
+++ b/dashboard/commands/load_coordinates.py
@@ -0,0 +1,26 @@
+import json
+from django.core.management.base import BaseCommand
+from dashboard.models import Country
+
+class Command(BaseCommand):
+ help = "Load country data into the database"
+
+ def handle(self, *args, **kwargs):
+ data = [
+ {"name": "Germany", "iso_code": "DE", "latitude": 51.1657, "longitude": 10.4515, "pillar2_implemented": True, "local_top_up_tax": True},
+ {"name": "France", "iso_code": "FR", "latitude": 46.6034, "longitude": 1.8883, "pillar2_implemented": True, "local_top_up_tax": False},
+ {"name": "United States", "iso_code": "US", "latitude": 37.0902, "longitude": -95.7129, "pillar2_implemented": False, "local_top_up_tax": False},
+ {"name": "Japan", "iso_code": "JP", "latitude": 36.2048, "longitude": 138.2529, "pillar2_implemented": True, "local_top_up_tax": True},
+ {"name": "India", "iso_code": "IN", "latitude": 20.5937, "longitude": 78.9629, "pillar2_implemented": False, "local_top_up_tax": False}
+ ]
+
+ for country_data in data:
+ country, created = Country.objects.get_or_create(
+ name=country_data["name"],
+ iso_code=country_data["iso_code"],
+ latitude=country_data["latitude"],
+ longitude=country_data["longitude"],
+ pillar2_implemented=country_data["pillar2_implemented"],
+ local_top_up_tax=country_data["local_top_up_tax"]
+ )
+ self.stdout.write(f"{'Created' if created else 'Updated'}: {country.name}")
\ No newline at end of file
diff --git a/dashboard/commands/populate_country_data.py b/dashboard/commands/populate_country_data.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d0134345e5c14920b03eea71c4de19283ab99d9
--- /dev/null
+++ b/dashboard/commands/populate_country_data.py
@@ -0,0 +1,47 @@
+from django.core.management.base import BaseCommand
+from dashboard.models import Country, CountryData
+import random
+
+class Command(BaseCommand):
+ help = 'Populate CountryData with random balance sheet values'
+
+ def handle(self, *args, **kwargs):
+ countries = Country.objects.all()
+ for country in countries:
+ for year in range(2020, 2025): # Add data for multiple years
+ balance_sheet = {
+ "Aktiva": {
+ "Anlagevermögen": {
+ "Sachanlagen": random.randint(10000, 50000),
+ "immaterielle Vermögensgegenstände": random.randint(5000, 20000),
+ "Finanzanlagen": random.randint(20000, 70000),
+ },
+ "Umlaufvermögen": {
+ "Vorräte": random.randint(3000, 15000),
+ "Forderungen": random.randint(5000, 25000),
+ "Kassenbestand": random.randint(1000, 5000),
+ "Wertpapiere": random.randint(10000, 20000),
+ }
+ },
+ "Passiva": {
+ "Eigenkapital": {
+ "Gezeichnetes Kapital": random.randint(50000, 100000),
+ "Kapitalrücklagen": random.randint(10000, 50000),
+ "Gewinnrücklagen": random.randint(20000, 60000),
+ },
+ "Fremdkapital": {
+ "Kurzfristige Verbindlichkeiten": random.randint(10000, 40000),
+ "langfristige Verbindlichkeiten": random.randint(30000, 80000),
+ }
+ }
+ }
+
+ CountryData.objects.create(
+ country=country,
+ year=year,
+ balance_sheet=balance_sheet,
+ company_name=f"Example Company {year}",
+ is_plausible=random.choice([True, False])
+ )
+
+ self.stdout.write(self.style.SUCCESS("Successfully populated CountryData"))
\ No newline at end of file
diff --git a/dashboard/management/commands/generate_companies.py b/dashboard/management/commands/generate_companies.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f3d9cf90c6b3185c2fb7c690702bca00636455c
--- /dev/null
+++ b/dashboard/management/commands/generate_companies.py
@@ -0,0 +1,32 @@
+import random
+from django.core.management.base import BaseCommand
+from dashboard.models import Country, Company
+
+
+class Command(BaseCommand):
+ help = "Generate random companies for all countries"
+
+ def handle(self, *args, **kwargs):
+ company_names = [
+ "Global Tech Inc.", "Alpha Industries", "Beta Solutions", "Delta Corp.",
+ "Zeta Enterprises", "Omega Systems", "Apollo Holdings", "Titan Innovations"
+ ]
+
+ for country in Country.objects.all():
+ self.stdout.write(f"Generating companies for {country.name}...")
+ for _ in range(random.randint(3, 6)): # Generate 3-6 companies per country
+ Company.objects.create(
+ name=random.choice(company_names),
+ country=country,
+ balance_sheet={
+ "Aktiva": {
+ "Anlagevermögen": random.randint(100000, 500000),
+ "Umlaufvermögen": random.randint(50000, 200000)
+ },
+ "Passiva": {
+ "Eigenkapital": random.randint(70000, 300000),
+ "Fremdkapital": random.randint(20000, 150000)
+ }
+ }
+ )
+ self.stdout.write(self.style.SUCCESS("Companies successfully generated!"))
diff --git a/dashboard/management/commands/load_coordinates.py b/dashboard/management/commands/load_coordinates.py
new file mode 100644
index 0000000000000000000000000000000000000000..f19573c86d9f93dcf02bdb572e2973340f466e75
--- /dev/null
+++ b/dashboard/management/commands/load_coordinates.py
@@ -0,0 +1,26 @@
+import json
+from django.core.management.base import BaseCommand
+from dashboard.models import Country
+
+class Command(BaseCommand):
+ help = "Load country data into the database"
+
+ def handle(self, *args, **kwargs):
+ data = [
+ {"name": "Germany", "iso_code": "DE", "latitude": 51.1657, "longitude": 10.4515, "pillar2_implemented": True, "local_top_up_tax": True},
+ {"name": "France", "iso_code": "FR", "latitude": 46.6034, "longitude": 1.8883, "pillar2_implemented": True, "local_top_up_tax": False},
+ {"name": "United States", "iso_code": "US", "latitude": 37.0902, "longitude": -95.7129, "pillar2_implemented": False, "local_top_up_tax": False},
+ {"name": "Japan", "iso_code": "JP", "latitude": 36.2048, "longitude": 138.2529, "pillar2_implemented": True, "local_top_up_tax": True},
+ {"name": "India", "iso_code": "IN", "latitude": 20.5937, "longitude": 78.9629, "pillar2_implemented": False, "local_top_up_tax": False}
+ ]
+
+ for country_data in data:
+ country, created = Country.objects.get_or_create(
+ name=country_data["name"],
+ iso_code=country_data["iso_code"],
+ latitude=country_data["latitude"],
+ longitude=country_data["longitude"],
+ pillar2_implemented=country_data["pillar2_implemented"],
+ local_top_up_tax=country_data["local_top_up_tax"]
+ )
+ self.stdout.write(f"{'Created' if created else 'Updated'}: {country.name}")
\ No newline at end of file
diff --git a/dashboard/management/commands/populate_country_data.py b/dashboard/management/commands/populate_country_data.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d0134345e5c14920b03eea71c4de19283ab99d9
--- /dev/null
+++ b/dashboard/management/commands/populate_country_data.py
@@ -0,0 +1,47 @@
+from django.core.management.base import BaseCommand
+from dashboard.models import Country, CountryData
+import random
+
+class Command(BaseCommand):
+ help = 'Populate CountryData with random balance sheet values'
+
+ def handle(self, *args, **kwargs):
+ countries = Country.objects.all()
+ for country in countries:
+ for year in range(2020, 2025): # Add data for multiple years
+ balance_sheet = {
+ "Aktiva": {
+ "Anlagevermögen": {
+ "Sachanlagen": random.randint(10000, 50000),
+ "immaterielle Vermögensgegenstände": random.randint(5000, 20000),
+ "Finanzanlagen": random.randint(20000, 70000),
+ },
+ "Umlaufvermögen": {
+ "Vorräte": random.randint(3000, 15000),
+ "Forderungen": random.randint(5000, 25000),
+ "Kassenbestand": random.randint(1000, 5000),
+ "Wertpapiere": random.randint(10000, 20000),
+ }
+ },
+ "Passiva": {
+ "Eigenkapital": {
+ "Gezeichnetes Kapital": random.randint(50000, 100000),
+ "Kapitalrücklagen": random.randint(10000, 50000),
+ "Gewinnrücklagen": random.randint(20000, 60000),
+ },
+ "Fremdkapital": {
+ "Kurzfristige Verbindlichkeiten": random.randint(10000, 40000),
+ "langfristige Verbindlichkeiten": random.randint(30000, 80000),
+ }
+ }
+ }
+
+ CountryData.objects.create(
+ country=country,
+ year=year,
+ balance_sheet=balance_sheet,
+ company_name=f"Example Company {year}",
+ is_plausible=random.choice([True, False])
+ )
+
+ self.stdout.write(self.style.SUCCESS("Successfully populated CountryData"))
\ No newline at end of file
diff --git a/dashboard/migrations/0001_initial.py b/dashboard/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef54fab4057eaf43110465d3dcab49b68a9f5646
--- /dev/null
+++ b/dashboard/migrations/0001_initial.py
@@ -0,0 +1,27 @@
+# Generated by Django 5.1.3 on 2024-11-24 10:34
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Country',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100)),
+ ('iso_code', models.CharField(max_length=3, unique=True)),
+ ('gdp', models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True)),
+ ('effective_tax_rate', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)),
+ ('part_of_pillar2', models.BooleanField(default=False)),
+ ('latitude', models.FloatField(blank=True, null=True)),
+ ('longitude', models.FloatField(blank=True, null=True)),
+ ],
+ ),
+ ]
diff --git a/dashboard/migrations/0002_remove_country_effective_tax_rate_remove_country_gdp_and_more.py b/dashboard/migrations/0002_remove_country_effective_tax_rate_remove_country_gdp_and_more.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c2da570ab7b034a5bccdd5fd980c449dbb70b36
--- /dev/null
+++ b/dashboard/migrations/0002_remove_country_effective_tax_rate_remove_country_gdp_and_more.py
@@ -0,0 +1,46 @@
+# Generated by Django 5.1.3 on 2024-11-24 11:04
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dashboard', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='country',
+ name='effective_tax_rate',
+ ),
+ migrations.RemoveField(
+ model_name='country',
+ name='gdp',
+ ),
+ migrations.AddField(
+ model_name='country',
+ name='local_top_up_tax',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AddField(
+ model_name='country',
+ name='pillar2_implemented',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AlterField(
+ model_name='country',
+ name='iso_code',
+ field=models.CharField(max_length=10),
+ ),
+ migrations.AlterField(
+ model_name='country',
+ name='latitude',
+ field=models.FloatField(),
+ ),
+ migrations.AlterField(
+ model_name='country',
+ name='longitude',
+ field=models.FloatField(),
+ ),
+ ]
diff --git a/dashboard/migrations/0003_countrydata_questionnaire.py b/dashboard/migrations/0003_countrydata_questionnaire.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf8051cd4bcca6e00130232cecd5511bb25ca611
--- /dev/null
+++ b/dashboard/migrations/0003_countrydata_questionnaire.py
@@ -0,0 +1,39 @@
+# Generated by Django 5.1.3 on 2024-11-24 14:29
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dashboard', '0002_remove_country_effective_tax_rate_remove_country_gdp_and_more'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='CountryData',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('year', models.IntegerField()),
+ ('balance_sheet', models.TextField()),
+ ('company_name', models.CharField(max_length=200)),
+ ('is_plausible', models.BooleanField(default=True)),
+ ('country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='data', to='dashboard.country')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Questionnaire',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('question', models.TextField()),
+ ('response', models.TextField(blank=True, null=True)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('is_resolved', models.BooleanField(default=False)),
+ ('country_data', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='questionnaires', to='dashboard.countrydata')),
+ ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/dashboard/migrations/0004_alter_countrydata_balance_sheet_and_more.py b/dashboard/migrations/0004_alter_countrydata_balance_sheet_and_more.py
new file mode 100644
index 0000000000000000000000000000000000000000..e19b8b8e5db994cb997f9844891050fe0ed27e19
--- /dev/null
+++ b/dashboard/migrations/0004_alter_countrydata_balance_sheet_and_more.py
@@ -0,0 +1,38 @@
+# Generated by Django 5.1.3 on 2024-11-24 15:07
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dashboard', '0003_countrydata_questionnaire'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='countrydata',
+ name='balance_sheet',
+ field=models.JSONField(default=dict),
+ ),
+ migrations.AlterField(
+ model_name='countrydata',
+ name='company_name',
+ field=models.CharField(max_length=255),
+ ),
+ migrations.AlterField(
+ model_name='countrydata',
+ name='country',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dashboard.country'),
+ ),
+ migrations.CreateModel(
+ name='Company',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=200)),
+ ('balance_sheet', models.JSONField()),
+ ('country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='companies', to='dashboard.country')),
+ ],
+ ),
+ ]
diff --git a/dashboard/migrations/__init__.py b/dashboard/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dashboard/models.py b/dashboard/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..f63301277739b4ea312ee95890ddd94db9f43068
--- /dev/null
+++ b/dashboard/models.py
@@ -0,0 +1,43 @@
+from django.contrib.auth.models import User
+from django.db import models
+
+class Country(models.Model):
+ name = models.CharField(max_length=100)
+ iso_code = models.CharField(max_length=10)
+ latitude = models.FloatField()
+ longitude = models.FloatField()
+ part_of_pillar2 = models.BooleanField(default=False)
+ pillar2_implemented = models.BooleanField(default=False) # Neu
+ local_top_up_tax = models.BooleanField(default=False) # Neu
+
+ def __str__(self):
+ return self.name
+
+class CountryData(models.Model):
+ country = models.ForeignKey(Country, on_delete=models.CASCADE)
+ year = models.IntegerField()
+ balance_sheet = models.JSONField(default=dict) # JSONField for structured data
+ company_name = models.CharField(max_length=255)
+ is_plausible = models.BooleanField(default=True)
+
+ def __str__(self):
+ return f"{self.country.name} - {self.year}"
+
+class Questionnaire(models.Model):
+ country_data = models.ForeignKey(CountryData, on_delete=models.CASCADE, related_name='questionnaires')
+ question = models.TextField()
+ response = models.TextField(blank=True, null=True)
+ created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+ is_resolved = models.BooleanField(default=False)
+
+ def __str__(self):
+ return f"Questionnaire for {self.country_data.country.name} ({self.country_data.year})"
+
+class Company(models.Model):
+ name = models.CharField(max_length=200)
+ country = models.ForeignKey(Country, on_delete=models.CASCADE, related_name='companies')
+ balance_sheet = models.JSONField() # JSONField to store Aktiva/Passiva data
+
+ def __str__(self):
+ return self.name
\ No newline at end of file
diff --git a/dashboard/static/css/style.css b/dashboard/static/css/style.css
new file mode 100644
index 0000000000000000000000000000000000000000..9b3900c747f785fda99cb8f1523718fd1262fa75
--- /dev/null
+++ b/dashboard/static/css/style.css
@@ -0,0 +1,137 @@
+/* style.css */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Roboto', sans-serif;
+ background-color: #f4f8ff; /* Helles Blau als Hintergrund */
+ color: #333;
+}
+
+.hero {
+ background-color: #007bb5; /* Blau-Ton für den Hero-Bereich */
+ color: white;
+ text-align: center;
+ padding: 100px 0;
+ border-bottom: 5px solid #006699; /* Dunklerer Blau-Ton als Trennung */
+}
+
+.hero h1 {
+ font-size: 3em;
+ margin-bottom: 20px;
+}
+
+.hero p {
+ font-size: 1.2em;
+ margin-bottom: 30px;
+}
+
+.cta-button {
+ background-color: #00aaff; /* Hellerer Blau-Ton für Button */
+ color: white;
+ padding: 10px 20px;
+ text-decoration: none;
+ font-size: 1.1em;
+ border-radius: 5px;
+ margin-top: 20px;
+}
+
+.cta-button:hover {
+ background-color: #0099cc; /* Dunklerer Blau-Ton für Hover */
+}
+
+.links {
+ margin-top: 30px;
+}
+
+.link-item {
+ color: #00aaff;
+ font-size: 1.1em;
+ text-decoration: none;
+ margin-right: 20px;
+}
+
+.link-item:hover {
+ text-decoration: underline;
+}
+
+.features {
+ padding: 50px 20px;
+ text-align: center;
+ background-color: #e1efff; /* Leichterer Blauton für Features-Sektion */
+}
+
+.features h2 {
+ font-size: 2.5em;
+ margin-bottom: 40px;
+}
+
+.feature {
+ background-color: white;
+ padding: 20px;
+ margin: 20px 0;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ border-radius: 8px;
+}
+
+.feature h3 {
+ font-size: 1.5em;
+ margin-bottom: 10px;
+}
+
+.feature p {
+ font-size: 1em;
+ color: #555;
+}
+/* Configuration Section Styling */
+.configuration {
+ background-color: #f4f8ff; /* Blau-Ton für den Hintergrund */
+ color: #333;
+ text-align: center; /* Den Text zentrieren, wenn es ein zentrierter Header sein soll */
+ padding: 80px 0; /* Etwas weniger Padding, damit mehr Platz für den Text bleibt */
+ border-bottom: 5px solid #006699; /* Dunklerer Blau-Ton als Trennung */
+}
+
+/* Container innerhalb der Section */
+.configuration .container {
+ max-width: 1200px; /* Maximale Breite für die Container */
+ margin: 0 auto; /* Zentriert den Container */
+ padding: 0 15px; /* Leichter Abstand zu den Rändern */
+}
+
+/* Stil für die Überschrift */
+.configuration h1 {
+ font-size: 3em; /* Größere Schriftgröße für den Titel */
+ margin-bottom: 20px; /* Abstand unter der Überschrift */
+ line-height: 1.2; /* Zeilenhöhe für bessere Lesbarkeit */
+}
+
+/* Stil für die CTA-Schaltfläche */
+.cta-button {
+ background-color: #00aaff; /* Hellerer Blau-Ton für den Button */
+ color: white;
+ padding: 15px 30px; /* Mehr Padding für die Schaltfläche */
+ text-decoration: none;
+ font-size: 1.2em; /* Etwas größere Schriftgröße für bessere Sichtbarkeit */
+ border-radius: 5px;
+ margin-top: 20px;
+ display: inline-block; /* Der Button wird als Inline-Block angezeigt, damit er nicht die gesamte Zeile ausfüllt */
+}
+
+.cta-button:hover {
+ background-color: #0099cc; /* Dunklerer Blau-Ton für Hover-Effekt */
+}
+
+footer {
+ background-color: #007bb5; /* Gleicher Blau-Ton wie im Hero-Bereich */
+ color: white;
+ text-align: center;
+ padding: 20px;
+}
+
+footer p {
+ font-size: 1em;
+}
\ No newline at end of file
diff --git a/dashboard/static/js/map.js b/dashboard/static/js/map.js
new file mode 100644
index 0000000000000000000000000000000000000000..8414163ca8fa3a95580cddabfce57f13c2bad36e
--- /dev/null
+++ b/dashboard/static/js/map.js
@@ -0,0 +1,71 @@
+/*const countries = [
+ {
+ name: "Germany",
+ iso_code: "DE",
+ latitude: 51.1657,
+ longitude: 10.4515,
+ pillar2_implemented: true,
+ local_top_up_tax: true
+ },
+ {
+ name: "France",
+ iso_code: "FR",
+ latitude: 46.6034,
+ longitude: 1.8883,
+ pillar2_implemented: true,
+ local_top_up_tax: false
+ },
+ {
+ name: "United States",
+ iso_code: "US",
+ latitude: 37.0902,
+ longitude: -95.7129,
+ pillar2_implemented: false,
+ local_top_up_tax: false
+ },
+ {
+ name: "Japan",
+ iso_code: "JP",
+ latitude: 36.2048,
+ longitude: 138.2529,
+ pillar2_implemented: true,
+ local_top_up_tax: true
+ },
+ {
+ name: "India",
+ iso_code: "IN",
+ latitude: 20.5937,
+ longitude: 78.9629,
+ pillar2_implemented: false,
+ local_top_up_tax: false
+ }
+];
+*/
+// Initialize map
+const map = L.map('map').setView([20, 0], 2);
+
+// Add OpenStreetMap tiles
+L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ maxZoom: 19
+}).addTo(map);
+
+// Add countries to map
+countries.forEach(country => {
+ const color = country.pillar2_implemented ? 'green' : 'gray';
+
+ // Add circle marker for each country
+ L.circleMarker([country.latitude, country.longitude], {
+ color: color,
+ radius: 10
+ }).addTo(map).bindPopup(`${country.name}`);
+
+ // Add symbol for Local Top-Up Tax
+ if (country.local_top_up_tax) {
+ L.marker([country.latitude, country.longitude], {
+ icon: L.divIcon({
+ className: 'custom-icon',
+ html: '+'
+ })
+ }).addTo(map);
+ }
+});
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/aiAgent.html b/dashboard/templates/dashboard/aiAgent.html
new file mode 100644
index 0000000000000000000000000000000000000000..932572119fffee02a5944a3766d7358e2c508791
--- /dev/null
+++ b/dashboard/templates/dashboard/aiAgent.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Title
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/company_detail.html b/dashboard/templates/dashboard/company_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..ea4844d5d2172d16d48c1c22028764110e3bfd7c
--- /dev/null
+++ b/dashboard/templates/dashboard/company_detail.html
@@ -0,0 +1,34 @@
+
+{% load static %}
+
+
+
+
+
+ {{ company.name }} - Details
+
+
+
+
{{ company.name }}
+
Details for {{ company.name }} in {{ company.country.name }}
+
+
+
Financial Data
+
+
Aktiva
+
+ - Anlagevermögen: {{ company.balance_sheet.Aktiva.Anlagevermögen }}
+ - Umlaufvermögen: {{ company.balance_sheet.Aktiva.Umlaufvermögen }}
+
+
Passiva
+
+ - Eigenkapital: {{ company.balance_sheet.Passiva.Eigenkapital }}
+ - Fremdkapital: {{ company.balance_sheet.Passiva.Fremdkapital }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/connectors.html b/dashboard/templates/dashboard/connectors.html
new file mode 100644
index 0000000000000000000000000000000000000000..932572119fffee02a5944a3766d7358e2c508791
--- /dev/null
+++ b/dashboard/templates/dashboard/connectors.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Title
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/country_detail.html b/dashboard/templates/dashboard/country_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..2bb009363038babaa8567268c6a14ae4dd19e67a
--- /dev/null
+++ b/dashboard/templates/dashboard/country_detail.html
@@ -0,0 +1,105 @@
+
+{% load static %}
+
+
+
+
+
+ {{ country.name }} - {{ data.year }}
+
+
+
+
{{ country.name }} - {{ data.year }}
+
Details for {{ data.company_name }}
+
+
+
Financial Data
+
+
Balance Sheet: {{ data.balance_sheet }}
+
Plausibility: {% if data.is_plausible %}✔️ Plausible{% else %}❌ Implausible{% endif %}
+
+
+
Actions
+
+
Send Questionnaire
+
+
+ Balance Sheet
+
+
Aktiva
+
+ - Anlagevermögen:
+
+ - Sachanlagen: {{ data.balance_sheet.Aktiva.Anlagevermögen.Sachanlagen }}
+ - immaterielle Vermögensgegenstände: {{ data.balance_sheet.Aktiva.Anlagevermögen.immaterielle_Vermögensgegenstände }}
+ - Finanzanlagen: {{ data.balance_sheet.Aktiva.Anlagevermögen.Finanzanlagen }}
+
+
+ - Umlaufvermögen:
+
+ - Vorräte: {{ data.balance_sheet.Aktiva.Umlaufvermögen.Vorräte }}
+ - Forderungen: {{ data.balance_sheet.Aktiva.Umlaufvermögen.Forderungen }}
+ - Kassenbestand: {{ data.balance_sheet.Aktiva.Umlaufvermögen.Kassenbestand }}
+ - Wertpapiere: {{ data.balance_sheet.Aktiva.Umlaufvermögen.Wertpapiere }}
+
+
+
+
Passiva
+
+ - Eigenkapital:
+
+ - Gezeichnetes Kapital: {{ data.balance_sheet.Passiva.Eigenkapital.Gezeichnetes_Kapital }}
+ - Kapitalrücklagen: {{ data.balance_sheet.Passiva.Eigenkapital.Kapitalrücklagen }}
+ - Gewinnrücklagen: {{ data.balance_sheet.Passiva.Eigenkapital.Gewinnrücklagen }}
+
+
+ - Fremdkapital:
+
+ - Kurzfristige Verbindlichkeiten: {{ data.balance_sheet.Passiva.Fremdkapital.Kurzfristige_Verbindlichkeiten }}
+ - langfristige Verbindlichkeiten: {{ data.balance_sheet.Passiva.Fremdkapital.langfristige_Verbindlichkeiten }}
+
+
+
+
+
+
+
+
diff --git a/dashboard/templates/dashboard/country_list.html b/dashboard/templates/dashboard/country_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..204ed5ead324bebb1e2fe54ceba85eeff68e033e
--- /dev/null
+++ b/dashboard/templates/dashboard/country_list.html
@@ -0,0 +1,41 @@
+
+{% load static %}
+
+
+
+
+
+ Country Overview
+
+
+
+
Country Overview
+
Explore financial data for each company by country
+
+
+
Available Countries and Companies
+
+
+ {% for country in countries %}
+ -
+
+
{{ country.name }}
+
Companies:
+
+
+
+ {% endfor %}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/dashboard.html b/dashboard/templates/dashboard/dashboard.html
new file mode 100644
index 0000000000000000000000000000000000000000..8f11975e580dbda656e1e8b7ad3fc7d0d62c61ba
--- /dev/null
+++ b/dashboard/templates/dashboard/dashboard.html
@@ -0,0 +1,267 @@
+
+
+
+
+
+
Pillar 2 Dashboard
+
+
+
+
+
Pillar 2 Dashboard
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/masterData.html b/dashboard/templates/dashboard/masterData.html
new file mode 100644
index 0000000000000000000000000000000000000000..932572119fffee02a5944a3766d7358e2c508791
--- /dev/null
+++ b/dashboard/templates/dashboard/masterData.html
@@ -0,0 +1,10 @@
+
+
+
+
+
Title
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/start_page.html b/dashboard/templates/dashboard/start_page.html
new file mode 100644
index 0000000000000000000000000000000000000000..4af0758a97dbb4af27625e023663bbb9780b05c2
--- /dev/null
+++ b/dashboard/templates/dashboard/start_page.html
@@ -0,0 +1,61 @@
+
+{% load static %}
+
+
+
+
+
Your Tax-Cockpit
+
+
+
+
+
+
+
+
+
+
+
What We Offer
+
+
Connect your Systems
+ Keep your Data in one place
+ Modular dashboard, different use-cases can be added
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/userManagement.html b/dashboard/templates/dashboard/userManagement.html
new file mode 100644
index 0000000000000000000000000000000000000000..932572119fffee02a5944a3766d7358e2c508791
--- /dev/null
+++ b/dashboard/templates/dashboard/userManagement.html
@@ -0,0 +1,10 @@
+
+
+
+
+
Title
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/tests.py b/dashboard/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/dashboard/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/dashboard/urls.py b/dashboard/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..d89c6002e350f27ddfd0ef21d48f875af910e0dd
--- /dev/null
+++ b/dashboard/urls.py
@@ -0,0 +1,24 @@
+from django.urls import path
+from . import views
+from .views import (
+ StartPageView,
+ masterData,
+ connectors,
+ userManagement,
+ aiAgent,)
+
+
+urlpatterns = [
+ path('', StartPageView.as_view(), name='start_page'), # Startseite
+ path('overview', views.dashboard, name='dashboard'), # Dashboard
+ path('masterData', masterData, name='masterData'), # Master Data
+ path('connectors', connectors, name='connectors'), # Connectors
+ path('userManagement', userManagement, name='userManagement'), # User Management
+ path('aiAgent', aiAgent, name='aiAgent'), # AI Agent
+ path('countries/', views.country_list, name='country_list'),
+ path('countries/
//', views.country_detail, name='country_detail'),
+ path('mark_implausible//', views.mark_implausible, name='mark_implausible'),
+ path('send_questionnaire//', views.send_questionnaire, name='send_questionnaire'),
+ path('companies//', views.company_detail, name='company_detail'),
+
+]
\ No newline at end of file
diff --git a/dashboard/views.py b/dashboard/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..8757e2708864c058dd41b5aec3edd35bd0bace18
--- /dev/null
+++ b/dashboard/views.py
@@ -0,0 +1,82 @@
+from django.http import JsonResponse
+from django.shortcuts import render, get_object_or_404
+from django.views.decorators.csrf import csrf_exempt
+from django.shortcuts import render, get_object_or_404, redirect
+from .models import Country, CountryData, Questionnaire
+from django.http import JsonResponse
+from django.views.decorators.csrf import csrf_exempt
+from .models import Country
+from django.views.generic import ListView, DetailView, CreateView, UpdateView, TemplateView
+
+class StartPageView(TemplateView):
+ template_name = "dashboard/start_page.html"
+
+def dashboard(request):
+ countries = Country.objects.all()
+ country_data = [
+ {
+ "name": country.name,
+ "iso_code": country.iso_code,
+ "latitude": country.latitude,
+ "longitude": country.longitude,
+ "pillar2_implemented": country.pillar2_implemented,
+ "local_top_up_tax": country.local_top_up_tax,
+ }
+ for country in countries
+ ]
+ return render(request, 'dashboard/dashboard.html', {"countries": country_data})
+
+
+def country_list(request):
+ countries = Country.objects.all()
+ return render(request, 'dashboard/country_list.html', {'countries': countries})
+
+def country_detail(request, country_id, year):
+ country = get_object_or_404(Country, id=country_id)
+ data = get_object_or_404(CountryData, country=country, year=year)
+ questionnaires = data.questionnaires.all()
+ return render(request, 'dashboard/country_detail.html', {
+ 'country': country,
+ 'data': data,
+ 'questionnaires': questionnaires,
+ })
+
+@csrf_exempt
+def mark_implausible(request, country_data_id):
+ if request.method == 'POST':
+ data = get_object_or_404(CountryData, id=country_data_id)
+ data.is_plausible = False
+ data.save()
+ return JsonResponse({'status': 'success'})
+
+@csrf_exempt
+def send_questionnaire(request, country_data_id):
+ if request.method == 'POST':
+ question = request.POST.get('question')
+ country_data = get_object_or_404(CountryData, id=country_data_id)
+ Questionnaire.objects.create(
+ country_data=country_data,
+ question=question,
+ created_by=request.user
+ )
+ return JsonResponse({'status': 'questionnaire_created'})
+
+
+from django.shortcuts import render, get_object_or_404
+from .models import Company
+
+def company_detail(request, company_id):
+ company = get_object_or_404(Company, id=company_id)
+ return render(request, 'dashboard/company_detail.html', {"company": company})
+
+def masterData(request):
+ return render(request, 'dashboard/masterData.html')
+
+def connectors(request):
+ return render(request, 'dashboard/connectors.html')
+
+def userManagement(request):
+ return render(request, 'dashboard/userManagement.html')
+
+def aiAgent(request):
+ return render(request, 'dashboard/aiAgent.html')
diff --git a/docs/setup.md b/docs/setup.md
deleted file mode 100644
index df4272bd3e5684b57a124e8c942194a71dcaeada..0000000000000000000000000000000000000000
--- a/docs/setup.md
+++ /dev/null
@@ -1,47 +0,0 @@
-Backend
-
-Setup
-
-
-
-git clone https://huggingface.co/spaces/gaganyatri/django_spaces
-
-cd django_spaces
-
-docker build -t slabstech/gaganyatri -f Dockerfile .
-
-docker run slabstech/gaganyatri
-
-
-- Steps to build this project
- - python3.10 -m venv venv
- - source venv/bin/activate
- - pip install Django==5.1.1
- - django-admin startproject spaces .
- - python manage.py migrate
- - python manage.py runserver
-
- - python manage.py startapp space_walks
- - python manage.py makemigrations
- - python manage.py migrate
-
-
- - pip install uvicorn
- - python -m uvicorn spaces.asgi:application
-
-
-- Merge for Huggingface
- - git fetch --all
- - git checkout main
- - git merge --squash django-setup
- - git commit -m "merge"
- - git push origin main
-
-
-
- - Referenc
- - https://www.djangoproject.com/download/
- - https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/
- - https://github.com/testdrivenio/django-on-docker
-
-
\ No newline at end of file
diff --git a/games/__init__.py b/games/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/games/admin.py b/games/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a45832ac104b79d66156766864e4b8d98190953
--- /dev/null
+++ b/games/admin.py
@@ -0,0 +1,4 @@
+from django.contrib import admin
+from .models import Game
+
+admin.site.register(Game)
diff --git a/games/apps.py b/games/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a3efecd74780eea04b23c15fb0f682ae555fd52
--- /dev/null
+++ b/games/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class GamesConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'games'
diff --git a/games/migrations/0001_initial.py b/games/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6612ffbc44fa42fb5118eaffbbab4f7964554fb
--- /dev/null
+++ b/games/migrations/0001_initial.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.1.1 on 2024-10-31 09:32
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Game',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=200)),
+ ('description', models.TextField()),
+ ('release_date', models.DateField()),
+ ],
+ ),
+ ]
diff --git a/games/migrations/__init__.py b/games/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/games/models.py b/games/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..33fc04a10ce3c54177c29f418c7d258a6bcf6ed6
--- /dev/null
+++ b/games/models.py
@@ -0,0 +1,6 @@
+from django.db import models
+
+class Game(models.Model):
+ name = models.CharField(max_length=200)
+ description = models.TextField()
+ release_date = models.DateField()
diff --git a/games/templates/game_list.html b/games/templates/game_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..dfbde615285df5d6912f3715a42859b47987f3d0
--- /dev/null
+++ b/games/templates/game_list.html
@@ -0,0 +1,16 @@
+
+
+
+ Game List
+
+
+ Games
+ {% for game in games %}
+
+ {{ game.name }}
+ {{ game.description }}
+ Released on: {{ game.release_date }}
+
+ {% endfor %}
+
+
diff --git a/games/tests.py b/games/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/games/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/games/urls.py b/games/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..0605c8a194b4b6db94c2fd5dbe0d69c99404e7b0
--- /dev/null
+++ b/games/urls.py
@@ -0,0 +1,6 @@
+from django.urls import path
+from . import views
+
+urlpatterns = [
+ path('', views.game_list, name='game_list'),
+]
\ No newline at end of file
diff --git a/games/views.py b/games/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..90cfd8de613408ae414b7ab94b959e14acd677ce
--- /dev/null
+++ b/games/views.py
@@ -0,0 +1,6 @@
+from django.shortcuts import render
+from .models import Game
+
+def game_list(request):
+ games = Game.objects.all()
+ return render(request, 'games/game_list.html', {'games': games})
diff --git a/inference/__init__.py b/inference/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/inference/admin.py b/inference/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/inference/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/inference/apps.py b/inference/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..8828545787b4be35ce31a85ea4d5be446dadcf91
--- /dev/null
+++ b/inference/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class InferenceConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'inference'
diff --git a/inference/migrations/__init__.py b/inference/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/inference/models.py b/inference/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..71a836239075aa6e6e4ecb700e9c42c95c022d91
--- /dev/null
+++ b/inference/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/inference/tests.py b/inference/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/inference/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/inference/urls.py b/inference/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..b3f0a7186c618a19c3c06d2e2b3f509a65a71b59
--- /dev/null
+++ b/inference/urls.py
@@ -0,0 +1,15 @@
+from django.urls import path
+from .views import VisionLLMView, NIMVisionLLMView, TextLLMView, TranslateLLMView, SpeechLLMView, LlamaVisionView, IndicLLMView, TTSView, SpeechASRView, SpeechToSpeechView
+
+urlpatterns = [
+ path('vision_llm_url/', VisionLLMView.as_view()),
+ path('nim_vision_llm_url/', NIMVisionLLMView.as_view()),
+ path('text_llm_url/', TextLLMView.as_view()),
+ path('translate_llm_url/', TranslateLLMView.as_view()),
+ path('speech_llm_url/', SpeechLLMView.as_view()),
+ path('speech_asr_url/', SpeechASRView.as_view()),
+ path('llama_vision_url/', LlamaVisionView.as_view()),
+ path('indic_llm_url/', IndicLLMView.as_view()),
+ path('tts_url/', TTSView.as_view()),
+ path('speech_to_speech_url/', SpeechToSpeechView.as_view()),
+]
diff --git a/inference/views.py b/inference/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..be934c2ad38012a478b3888f75655d03f93b9393
--- /dev/null
+++ b/inference/views.py
@@ -0,0 +1,430 @@
+from django.http import JsonResponse
+from rest_framework.response import Response
+from rest_framework.views import APIView
+from mistralai import Mistral
+import os
+import requests
+from openai import OpenAI
+from ollama import Client
+from django.http import FileResponse
+import io
+
+class TTSView(APIView):
+ def post(self, request, format=None):
+ # Define the API endpoint
+ # Define the URL for the TTS API
+ url = 'http://localhost:5002/api/tts'
+
+ # Define the multiline text
+ text = "This is the first line"
+
+ # Prepare the parameters for the GET request
+ params = {
+ 'text': text
+ }
+
+ # Make the GET request
+ response = requests.get(url, params=params)
+
+ # Check if the request was successful
+ if response.status_code == 200:
+ # Save the audio response as a WAV file
+ # Create a file-like object with the audio data
+ audio_data = io.BytesIO(response.content)
+
+ # Return the audio file as a response
+ return FileResponse(audio_data, as_attachment=True, filename='audio_output.wav')
+ else:
+ return Response({"error": "Failed to synthesize speech"}, status=response.status_code)
+
+class SpeechASRView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+ ##prompt = data['prompt']
+ audio = data['audio']
+ print('hre1')
+ client = OpenAI(api_key="cant-be-empty", base_url="http://0.0.0.0:11800/v1/")
+ print('her2')
+ #filename= '/home/gaganyatri/Music/test1.flac'
+ audio_bytes = audio.read()
+
+ #audio_file = open(filename, "rb")
+
+ transcript = client.audio.transcriptions.create(
+ model="Systran/faster-distil-whisper-small.en", file=audio_bytes
+ )
+
+ #print(transcript.text)
+ voice_content = transcript.text
+ return Response({"response": voice_content})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+
+class SpeechToSpeechView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+ ##prompt = data['prompt']
+ audio = data['audio']
+
+ client = OpenAI(api_key="cant-be-empty", base_url="http://0.0.0.0:11800/v1/")
+
+ #filename= '/home/gaganyatri/Music/test1.flac'
+ audio_bytes = audio.read()
+
+ #audio_file = open(filename, "rb")
+
+ transcript = client.audio.transcriptions.create(
+ model="Systran/faster-distil-whisper-small.en", file=audio_bytes
+ )
+
+ #print(transcript.text)
+ voice_content = transcript.text
+ #content = 'audio recieved'
+ system_prompt = "Please summarize the following prompt into a concise and clear statement:"
+
+
+ model = "mistral-nemo:latest"
+ client = Client(host='http://localhost:11434')
+ response = client.chat(
+ model=model,
+ messages=[
+ {
+ "role": "system",
+ "content": system_prompt
+ },
+ {
+ "role": "user",
+ "content": voice_content,
+ }
+ ],
+ )
+
+ # Extract the model's response about the image
+ response_text = response['message']['content'].strip()
+
+ url = 'http://localhost:5002/api/tts'
+
+ # Define the multiline text
+ #text = "This is the first line"
+
+ # Prepare the parameters for the GET request
+ params = {
+ 'text': response_text
+ }
+
+ # Make the GET request
+ response = requests.get(url, params=params)
+
+ # Check if the request was successful
+ if response.status_code == 200:
+ # Save the audio response as a WAV file
+ # Create a file-like object with the audio data
+ audio_data = io.BytesIO(response.content)
+
+ # Return the audio file as a response
+ return FileResponse(audio_data, as_attachment=True, filename='audio_output.wav')
+ else:
+ return Response({"error": "Failed to synthesize speech"}, status=response.status_code)
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+class SpeechLLMView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+ ##prompt = data['prompt']
+ audio = data['audio']
+
+ client = OpenAI(api_key="cant-be-empty", base_url="http://localhost:11800/v1/")
+
+ #filename= '/home/gaganyatri/Music/test1.flac'
+ audio_bytes = audio.read()
+
+ #audio_file = open(filename, "rb")
+
+ transcript = client.audio.transcriptions.create(
+ model="Systran/faster-distil-whisper-small.en", file=audio_bytes
+ )
+
+ #print(transcript.text)
+ voice_content = transcript.text
+ #content = 'audio recieved'
+
+ model = "mistral-nemo:latest"
+ client = Client(host='http://localhost:11434')
+ response = client.chat(
+ model=model,
+ messages=[{
+ "role": "user",
+ "content": voice_content,
+ }],
+ )
+
+ # Extract the model's response about the image
+ response_text = response['message']['content'].strip()
+
+ return Response({"response": response_text})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+class TranslateLLMView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+ prompt = data['messages'][0]['prompt']
+ # Specify model
+ source_language = data['sourceLanguage']
+ target_language = data['targetLanguage']
+ #model = data['model']
+ # Define the messages for the chat
+ api_key=os.getenv("SARVAM_API_KEY", "")
+ url = "https://api.sarvam.ai/translate"
+
+ payload = {
+ "input": prompt,
+ "source_language_code": source_language,
+ "target_language_code": target_language,
+ "speaker_gender": "Male",
+ "mode": "formal",
+ "model": "mayura:v1",
+ "enable_preprocessing": True
+ }
+ headers = {"Content-Type": "application/json",
+ 'API-Subscription-Key': f"{api_key}"
+ }
+
+ response = requests.request("POST", url, json=payload, headers=headers)
+ content = response.text
+ #print(chat_response.choices[0].message.content)
+ # Return the content of the response
+ return Response({"response": content})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+class TextLLMView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+
+ isOnline = data['isOnline']
+
+ prompt = data['messages'][0]['prompt']
+ # Specify model
+ #model = "pixtral-12b-2409"
+ model = data['model']
+ # Define the messages for the chat
+ messages = [
+ {
+ "role": "user",
+ "content": [
+ {
+ "type": "text",
+ "text": prompt
+ }
+ ]
+ }
+ ]
+
+ if(isOnline):
+ api_key = os.environ["MISTRAL_API_KEY"]
+
+ # Initialize the Mistral client
+ client = Mistral(api_key=api_key)
+
+
+ # Get the chat response
+ chat_response = client.chat.complete(
+ model=model,
+ messages=messages
+ )
+
+ content = chat_response.choices[0].message.content
+ else:
+ content = "helloWorld"
+
+ #print(chat_response.choices[0].message.content)
+ # Return the content of the response
+ return Response({"response": content})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+class IndicLLMView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+
+ isOnline = data['isOnline']
+
+ print(isOnline)
+ prompt = data['messages'][0]['prompt']
+ # Specify model
+ #model = "pixtral-12b-2409"
+ model = data['model']
+ # Define the messages for the chat
+
+ client = Client(host='http://localhost:11434')
+ response = client.chat(
+ model=model,
+ messages=[{
+ "role": "user",
+ "content": prompt,
+ }],
+ )
+
+ # Extract the model's response about the image
+ response_text = response['message']['content'].strip()
+
+ #print(chat_response.choices[0].message.content)
+ # Return the content of the response
+ return Response({"response": response_text})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+class LlamaVisionView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+
+ print("gere")
+
+ image_data = (data['messages'][0]['image'][0])
+ prompt = data['messages'][0]['prompt']
+ # Specify model
+ #model = "pixtral-12b-2409"
+ model = data['model']
+ # Define the messages for the chat
+
+ # Define the messages for the chat
+
+ print("gere")
+ client = Client(host='http://localhost:21434')
+ response = client.chat(
+ model="x/llama3.2-vision:latest",
+ messages=[{
+ "role": "user",
+ "content": prompt,
+ "images": [image_data]
+ }],
+ )
+
+ print("gere")
+ # Extract the model's response about the image
+ response_text = response['message']['content'].strip()
+
+ print(response_text)
+ content = response_text
+ print("gere")
+
+
+ #print(chat_response.choices[0].message.content)
+ # Return the content of the response
+ return Response({"response": content})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+
+class VisionLLMView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+ api_key = os.environ["MISTRAL_API_KEY"]
+
+ # Initialize the Mistral client
+ client = Mistral(api_key=api_key)
+
+ image_data = (data['messages'][0]['image'][0])
+ prompt = data['messages'][0]['prompt']
+ # Specify model
+ #model = "pixtral-12b-2409"
+ model = data['model']
+ # Define the messages for the chat
+ messages = [
+ {
+ "role": "user",
+ "content": [
+ {
+ "type": "text",
+ "text": prompt
+ },
+ {
+ "type": "image_url",
+ "image_url": f"data:image/jpeg;base64,{image_data}"
+ }
+ ]
+ }
+ ]
+
+ # Get the chat response
+ chat_response = client.chat.complete(
+ model=model,
+ messages=messages
+ )
+
+ content = chat_response.choices[0].message.content
+ #print(chat_response.choices[0].message.content)
+ # Return the content of the response
+ return Response({"response": content})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+
+
+class NIMVisionLLMView(APIView):
+ def post(self, request, format=None):
+ try:
+ invoke_url = "https://ai.api.nvidia.com/v1/gr/meta/llama-3.2-11b-vision-instruct/chat/completions"
+ stream = False
+ api_key = os.environ["NIM_API_KEY"]
+ data = request.data
+ model = data['model']
+ print(model)
+ image_data = (data['messages'][0]['image'][0])
+ prompt = data['messages'][0]['prompt']
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Accept": "text/event-stream" if stream else "application/json"
+ }
+ payload = {
+ "model": model,
+ "messages": [
+ {
+ "role": "user",
+ "content": f'{prompt} '
+ }
+ ],
+ "max_tokens": 512,
+ "temperature": 1.00,
+ "top_p": 1.00,
+ "stream": stream
+ }
+ response = requests.post(invoke_url, headers=headers, json=payload)
+
+ if stream:
+ for line in response.iter_lines():
+ if line:
+ #print(line.decode("utf-8"))
+ data = line.decode("utf-8")
+ #content = json.loads(data)['choices'][0]['delta'].get('content', '')
+ else:
+ #print(response.json())
+ data = response.json()
+ content = data['choices'][0]['message']['content']
+
+ #print(content)
+ return Response({"response": content})
+
+
+ except Exception as e: # Added general exception handling
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
diff --git a/recipes/urls.py b/recipes/urls.py
index 7fa417e14f6640082d022f48d77a1851237e33c6..a05cc2f2f9079d54f04bfd64e8092d985a37528a 100644
--- a/recipes/urls.py
+++ b/recipes/urls.py
@@ -1,17 +1,6 @@
from django.urls import path
from .views import recipe_generate_route
-from .views import VisionLLMView, NIMVisionLLMView, TextLLMView, TranslateLLMView, SpeechLLMView, LlamaVisionView, IndicLLMView, TTSView, SpeechASRView, SpeechToSpeechView
urlpatterns = [
path('recipe_generate/', recipe_generate_route, name='recipe_generate'),
- path('vision_llm_url/', VisionLLMView.as_view()),
- path('nim_vision_llm_url/', NIMVisionLLMView.as_view()),
- path('text_llm_url/', TextLLMView.as_view()),
- path('translate_llm_url/', TranslateLLMView.as_view()),
- path('speech_llm_url/', SpeechLLMView.as_view()),
- path('speech_asr_url/', SpeechASRView.as_view()),
- path('llama_vision_url/', LlamaVisionView.as_view()),
- path('indic_llm_url/', IndicLLMView.as_view()),
- path('tts_url/', TTSView.as_view()),
- path('speech_to_speech_url/', SpeechToSpeechView.as_view()),
]
diff --git a/recipes/views.py b/recipes/views.py
index ec8d4cc389dfa89421a477e9d422a755b32e4fb8..6c6344f06335b9cec59d2d2e602a24e3b03ec095 100644
--- a/recipes/views.py
+++ b/recipes/views.py
@@ -1,302 +1,7 @@
-from django.http import JsonResponse
from rest_framework.decorators import api_view
from rest_framework.response import Response
-from rest_framework import serializers
from .engine import execute_prompt, bundle_function, propose_recipes, compute_reduced_prices
-from rest_framework.views import APIView
-from mistralai import Mistral
-import os
-import base64
import json
-import requests
-from openai import OpenAI
-from ollama import Client
-from django.http import FileResponse
-import io
-
-class TTSView(APIView):
- def post(self, request, format=None):
- # Define the API endpoint
- # Define the URL for the TTS API
- url = 'http://localhost:5002/api/tts'
-
- # Define the multiline text
- text = "This is the first line"
-
- # Prepare the parameters for the GET request
- params = {
- 'text': text
- }
-
- # Make the GET request
- response = requests.get(url, params=params)
-
- # Check if the request was successful
- if response.status_code == 200:
- # Save the audio response as a WAV file
- # Create a file-like object with the audio data
- audio_data = io.BytesIO(response.content)
-
- # Return the audio file as a response
- return FileResponse(audio_data, as_attachment=True, filename='audio_output.wav')
- else:
- return Response({"error": "Failed to synthesize speech"}, status=response.status_code)
-
-class SpeechASRView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
- ##prompt = data['prompt']
- audio = data['audio']
-
- client = OpenAI(api_key="cant-be-empty", base_url="http://localhost:11800/v1/")
-
- #filename= '/home/gaganyatri/Music/test1.flac'
- audio_bytes = audio.read()
-
- #audio_file = open(filename, "rb")
-
- transcript = client.audio.transcriptions.create(
- model="Systran/faster-distil-whisper-small.en", file=audio_bytes
- )
-
- #print(transcript.text)
- voice_content = transcript.text
- return Response({"response": voice_content})
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-
-class SpeechToSpeechView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
- ##prompt = data['prompt']
- audio = data['audio']
-
- client = OpenAI(api_key="cant-be-empty", base_url="http://localhost:11800/v1/")
-
- #filename= '/home/gaganyatri/Music/test1.flac'
- audio_bytes = audio.read()
-
- #audio_file = open(filename, "rb")
-
- transcript = client.audio.transcriptions.create(
- model="Systran/faster-distil-whisper-small.en", file=audio_bytes
- )
-
- #print(transcript.text)
- voice_content = transcript.text
- #content = 'audio recieved'
- system_prompt = "Please summarize the following prompt into a concise and clear statement:"
-
-
- model = "mistral-nemo:latest"
- client = Client(host='http://localhost:11434')
- response = client.chat(
- model=model,
- messages=[
- {
- "role": "system",
- "content": system_prompt
- },
- {
- "role": "user",
- "content": voice_content,
- }
- ],
- )
-
- # Extract the model's response about the image
- response_text = response['message']['content'].strip()
-
- url = 'http://localhost:5002/api/tts'
-
- # Define the multiline text
- #text = "This is the first line"
-
- # Prepare the parameters for the GET request
- params = {
- 'text': response_text
- }
-
- # Make the GET request
- response = requests.get(url, params=params)
-
- # Check if the request was successful
- if response.status_code == 200:
- # Save the audio response as a WAV file
- # Create a file-like object with the audio data
- audio_data = io.BytesIO(response.content)
-
- # Return the audio file as a response
- return FileResponse(audio_data, as_attachment=True, filename='audio_output.wav')
- else:
- return Response({"error": "Failed to synthesize speech"}, status=response.status_code)
-
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-class SpeechLLMView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
- ##prompt = data['prompt']
- audio = data['audio']
-
- client = OpenAI(api_key="cant-be-empty", base_url="http://localhost:11800/v1/")
-
- #filename= '/home/gaganyatri/Music/test1.flac'
- audio_bytes = audio.read()
-
- #audio_file = open(filename, "rb")
-
- transcript = client.audio.transcriptions.create(
- model="Systran/faster-distil-whisper-small.en", file=audio_bytes
- )
-
- #print(transcript.text)
- voice_content = transcript.text
- #content = 'audio recieved'
-
- model = "mistral-nemo:latest"
- client = Client(host='http://localhost:11434')
- response = client.chat(
- model=model,
- messages=[{
- "role": "user",
- "content": voice_content,
- }],
- )
-
- # Extract the model's response about the image
- response_text = response['message']['content'].strip()
-
- return Response({"response": response_text})
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-class TranslateLLMView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
- prompt = data['messages'][0]['prompt']
- # Specify model
- source_language = data['sourceLanguage']
- target_language = data['targetLanguage']
- #model = data['model']
- # Define the messages for the chat
- api_key=os.getenv("SARVAM_API_KEY", "")
- url = "https://api.sarvam.ai/translate"
-
- payload = {
- "input": prompt,
- "source_language_code": source_language,
- "target_language_code": target_language,
- "speaker_gender": "Male",
- "mode": "formal",
- "model": "mayura:v1",
- "enable_preprocessing": True
- }
- headers = {"Content-Type": "application/json",
- 'API-Subscription-Key': f"{api_key}"
- }
-
- response = requests.request("POST", url, json=payload, headers=headers)
- content = response.text
- #print(chat_response.choices[0].message.content)
- # Return the content of the response
- return Response({"response": content})
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-class TextLLMView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
-
- isOnline = data['isOnline']
-
- print(isOnline)
- prompt = data['messages'][0]['prompt']
- # Specify model
- #model = "pixtral-12b-2409"
- model = data['model']
- # Define the messages for the chat
- messages = [
- {
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": prompt
- }
- ]
- }
- ]
-
- if(isOnline):
- api_key = os.environ["MISTRAL_API_KEY"]
-
- # Initialize the Mistral client
- client = Mistral(api_key=api_key)
-
-
- # Get the chat response
- chat_response = client.chat.complete(
- model=model,
- messages=messages
- )
-
- content = chat_response.choices[0].message.content
- else:
- content = "helloWorld"
-
- #print(chat_response.choices[0].message.content)
- # Return the content of the response
- return Response({"response": content})
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-class IndicLLMView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
-
- isOnline = data['isOnline']
-
- print(isOnline)
- prompt = data['messages'][0]['prompt']
- # Specify model
- #model = "pixtral-12b-2409"
- model = data['model']
- # Define the messages for the chat
-
- client = Client(host='http://localhost:11434')
- response = client.chat(
- model=model,
- messages=[{
- "role": "user",
- "content": prompt,
- }],
- )
-
- # Extract the model's response about the image
- response_text = response['message']['content'].strip()
-
- #print(chat_response.choices[0].message.content)
- # Return the content of the response
- return Response({"response": response_text})
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-
@api_view(['GET'])
def recipe_generate_route(request):
@@ -313,138 +18,3 @@ def recipe_generate_route(request):
print(f"An error occurred: {e}")
return Response({'error': 'Something went wrong'}, status=500)
return Response(result)
-
-
-class LlamaVisionView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
-
- image_data = (data['messages'][0]['image'][0])
- prompt = data['messages'][0]['prompt']
- # Specify model
- #model = "pixtral-12b-2409"
- model = data['model']
- # Define the messages for the chat
-
- # Define the messages for the chat
-
- client = Client(host='http://localhost:21434')
- response = client.chat(
- model="x/llama3.2-vision:latest",
- messages=[{
- "role": "user",
- "content": prompt,
- "images": [image_data]
- }],
- )
-
- # Extract the model's response about the image
- response_text = response['message']['content'].strip()
-
- print(response_text)
- content = response_text
-
-
- #print(chat_response.choices[0].message.content)
- # Return the content of the response
- return Response({"response": content})
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-
-class VisionLLMView(APIView):
- def post(self, request, format=None):
- try:
- data = request.data
- api_key = os.environ["MISTRAL_API_KEY"]
-
- # Initialize the Mistral client
- client = Mistral(api_key=api_key)
-
- image_data = (data['messages'][0]['image'][0])
- prompt = data['messages'][0]['prompt']
- # Specify model
- #model = "pixtral-12b-2409"
- model = data['model']
- # Define the messages for the chat
- messages = [
- {
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": prompt
- },
- {
- "type": "image_url",
- "image_url": f"data:image/jpeg;base64,{image_data}"
- }
- ]
- }
- ]
-
- # Get the chat response
- chat_response = client.chat.complete(
- model=model,
- messages=messages
- )
-
- content = chat_response.choices[0].message.content
- #print(chat_response.choices[0].message.content)
- # Return the content of the response
- return Response({"response": content})
- except Exception as e:
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
-
-
-class NIMVisionLLMView(APIView):
- def post(self, request, format=None):
- try:
- invoke_url = "https://ai.api.nvidia.com/v1/gr/meta/llama-3.2-11b-vision-instruct/chat/completions"
- stream = False
- api_key = os.environ["NIM_API_KEY"]
- data = request.data
- model = data['model']
- print(model)
- image_data = (data['messages'][0]['image'][0])
- prompt = data['messages'][0]['prompt']
- headers = {
- "Authorization": f"Bearer {api_key}",
- "Accept": "text/event-stream" if stream else "application/json"
- }
- payload = {
- "model": model,
- "messages": [
- {
- "role": "user",
- "content": f'{prompt} '
- }
- ],
- "max_tokens": 512,
- "temperature": 1.00,
- "top_p": 1.00,
- "stream": stream
- }
- response = requests.post(invoke_url, headers=headers, json=payload)
-
- if stream:
- for line in response.iter_lines():
- if line:
- #print(line.decode("utf-8"))
- data = line.decode("utf-8")
- #content = json.loads(data)['choices'][0]['delta'].get('content', '')
- else:
- #print(response.json())
- data = response.json()
- content = data['choices'][0]['message']['content']
-
- #print(content)
- return Response({"response": content})
-
-
- except Exception as e: # Added general exception handling
- print(f"An error occurred: {e}")
- return Response({'error': 'Something went wrong'}, status=500)
diff --git a/requirements.txt b/requirements.txt
index b3ebc65b9c4efed61da632f3207ca88870e64210..830aa11f3e7405a7d473c61ae0dc195dddbaeb90 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -46,6 +46,7 @@ pytz==2024.2
PyYAML==6.0.2
requests==2.32.3
requests-oauthlib==2.0.0
+setuptools==75.6.0
six==1.16.0
sniffio==1.3.1
social-auth-app-django==5.4.2
diff --git a/spaces/settings.py b/spaces/settings.py
index a8e21f7d265a5fac3feabeca9c8068a2c9f96084..f37ad306e64d82fb0efcca580dc8a0820db1497a 100644
--- a/spaces/settings.py
+++ b/spaces/settings.py
@@ -9,12 +9,13 @@ https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
-
+import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
+#BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
@@ -46,7 +47,10 @@ INSTALLED_APPS = [
'rest_framework',
'rest_framework.authtoken',
'djoser',
- 'accounts'
+ 'accounts',
+ 'games',
+ 'taxtech',
+ 'dashboard',
]
MIDDLEWARE = [
@@ -148,7 +152,7 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
-STATIC_URL = 'static/'
+#STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
@@ -173,3 +177,11 @@ REST_FRAMEWORK = {
DJOSER = {
"USER_ID_FIELD": "username"
}
+
+STATIC_ROOT = os.path.join(BASE_DIR, 'static')
+
+
+
+# Static Files
+STATIC_URL = '/static/'
+STATICFILES_DIRS = [os.path.join(BASE_DIR, 'dashboard/static'),]
\ No newline at end of file
diff --git a/spaces/urls.py b/spaces/urls.py
index 4d764f79a744b688e1c1dc4f37250ab6c3c6b02f..7a80abe38b23f2653132b7297fdf2c40bfc7e811 100644
--- a/spaces/urls.py
+++ b/spaces/urls.py
@@ -40,5 +40,9 @@ urlpatterns = [
path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
path('api/v1/space_walks/', include('space_walks.urls')),
path('api/v1/recipes/', include('recipes.urls')),
+ path('api/v1/inference/', include('inference.urls')),
path('api/v1/accounts/', include('accounts.urls')),
+ path('games/', include('games.urls')),
+ path('taxtech/', include('taxtech.urls')),
+ path('dashboard/', include('dashboard.urls')), # Include dashboard app URLs
]
diff --git a/taxtech/__init__.py b/taxtech/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/taxtech/admin.py b/taxtech/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..1cecf145084ff74d5dfa3d4caf4645bf79817c6c
--- /dev/null
+++ b/taxtech/admin.py
@@ -0,0 +1,8 @@
+from django.contrib import admin
+from .models import TaxTechApp, Company, TaxData
+
+admin.site.register(TaxTechApp)
+
+admin.site.register(Company)
+
+admin.site.register(TaxData)
\ No newline at end of file
diff --git a/taxtech/apps.py b/taxtech/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..69bcc4116e9c2878383e4751b48cefa7d6e56147
--- /dev/null
+++ b/taxtech/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class TaxtechConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'taxtech'
diff --git a/taxtech/engine.py b/taxtech/engine.py
new file mode 100644
index 0000000000000000000000000000000000000000..6dd163641baea23a74eb6dc3dbbf7cbf344431cc
--- /dev/null
+++ b/taxtech/engine.py
@@ -0,0 +1,213 @@
+import pandas as pd
+import numpy as np
+import requests
+import json
+from inference.mistral_inference import text_llm
+from django.core.files.storage import default_storage
+
+def execute_prompt(prompt, local=True):
+
+ if local:
+ #url = "http://10.211.137.191:11434/api/generate"
+ url = "http://localhost:11434/api/generate"
+ headers = {"Content-Type": "application/json"}
+ data = {
+ "model": "mistral",
+ #"model": "mistral-nemo",
+ "prompt": prompt,
+ "stream": False
+ }
+
+ response = requests.post(url, headers=headers, data=json.dumps(data))
+ output = ""
+ if response.status_code == 200:
+ responses = response.text.strip().split('\n')
+ for resp in responses:
+ try:
+ result = json.loads(resp)
+ print(result.get('response', ''))
+ output += result.get('response', '') + '\n'
+ except json.JSONDecodeError:
+ print(f"Error decoding JSON: {resp}")
+
+ else:
+ print(f"Error: {response.status_code}")
+ return output.strip()
+ else:
+ response = text_llm(prompt)
+ #print(response)
+ return response
+
+from datetime import datetime
+
+def bundle_function(articles):
+ current_date = datetime.now()
+ bundle_articles = []
+
+ for article in articles:
+ demand = article.get('demand')*100-100
+ stock = article.get('stock')*100+15
+ expires_at_str = article.get('expiresAt')
+
+ try:
+ expires_at = datetime.strptime(expires_at_str, '%Y-%m-%d')
+ days_to_expire = (expires_at - current_date).days
+
+ #TODO change days to expire to e.g. 3 / 10
+ if days_to_expire<3 or (stock > 15 and demand < 10 and days_to_expire<300):
+ bundle_articles.append(article)
+
+ except (ValueError, TypeError):
+ print(f"Fehler beim Verarbeiten des Ablaufdatums für Artikel: {article.get('name', 'Unbekannt')} in bundle_function")
+
+ return bundle_articles
+
+
+
+
+
+def propose_recipes(bundle_articles):
+ if bundle_articles:
+ bundle_article_names = ', '.join([article.get('name') for article in bundle_articles])
+
+ prompt = (
+ f"Give me some recipes where the Bundle articles could be used. My goal is that all items in Bundle articles "
+ f"are used in a recipe. Seperate the response in three parts. 1. Name of the recipe, 2. Ingredients for the recipe, 3. Steps in the recipe. Answer in a JSON Format"
+ f"Bundle articles: {bundle_article_names}"
+ )
+
+ return prompt
+
+ else:
+ return "Tell me a joke."
+
+
+
+def price_reduction(time_to_expiration, product_type, demand, stock):
+ """ Calculate the price reduction percentage based on normalized values
+ (between 0 and 1) for time to expiration, product type, demand, and stock.
+
+ Args:
+ time_to_expiration (float):
+ Normalized time to expiration, 0 means expiring today, 1 means maximum time.
+ product_type (float):
+ Normalized product type (0 = non-perishable, 0.5 = semi-perishable, 1 = highly perishable).
+ demand (float):
+ Normalized demand (0 to 1), where 1 is high demand and 0 is no demand.
+ stock (float):
+ Normalized stock level (0 to 1), where 0 is low stock and 1 is high stock.
+
+ Returns:
+ reduction_percentage (float): Percentage of price reduction.
+ """
+
+ # Maximum discouts
+ MAX_EXPIRATION = 0.05
+ MAX_STOCK_DEMAND = 0.05
+
+ if time_to_expiration > 0.5:
+ return 0
+
+ # Time to expiration: Closer to expiration means higher discount (inverted)
+ # Maximum factor when time_to_expiration is 0
+ expiration_factor = (1 - time_to_expiration) * MAX_EXPIRATION
+
+ # Stock: Higher stock means higher discount
+ # Demand: Lower demand should increase discount
+ # Maximum factor when stock is 1 (high stock) and demand is 0 (low demand)
+ stock_demand_factor = (stock - demand) * MAX_STOCK_DEMAND
+
+ # Product type: Non-perishable (0), semi-perishable (0.5), perishable (1) impact
+ # Factor ranges from 1.0 (non-perishable) to 1.4 (highly perishable)
+ product_factor = 1 + (product_type * 6.0)
+
+ # Combine all factors to calculate total reduction
+ reduction_percentage = ((expiration_factor + stock_demand_factor) * product_factor)
+ # Cap the discount between 0% and 80%
+ return min(max(reduction_percentage * 100, 0), 80)
+
+
+def compute_reduced_prices(as_json=True):
+ #df = pd.read_json('articles.json')
+ file = default_storage.open('data/articles.json', 'r')
+ data = json.load(file)
+ file.close()
+ df = pd.DataFrame(data)
+ df["product_type"] = 1
+ df["time_to_expiration"] = np.random.rand(len(df.index))
+ df["demand"] = np.random.rand(len(df.index))
+ df["stock"] = np.random.rand(len(df.index))
+ df["discount"] = df.apply(lambda row: price_reduction(row['time_to_expiration'], row['product_type'], row['demand'], row['stock']), axis=1)
+ df["discounted_price"] = df["price"] * (1 - df["discount"] / 100)
+ df = df.drop(columns=['weight', 'packagingUnit', 'available'])
+
+ return df.to_json(orient="records") if as_json is True else df
+
+
+def json_parser(api_json):
+
+ explicit_prompt = """
+ 1. State the name of the food item.
+ 2. Mention the expiration date to raise awareness about freshness.
+ 3. Describe the best storage practices to prolong shelf life.
+ 4. List creative ways to use the food item to encourage consumption before it spoils.
+ 5. Provide actionable tips for minimizing waste, such as recipes or preservation methods.
+ JSON DATA = {}
+ """.format(api_json)
+
+
+ implicit_prompt = """
+ Analyse the data about food items, Lets think step by step
+ JSON DATA = {}
+ """.format(api_json)
+
+ few_shot_cots = """
+ JSON DATA = {}
+ """.format(api_json)
+
+ categorize_articles= """
+ Put the food into 3 categories. Long living food with the criteria: time to expiration greater than 3 months, middle living food with the criteria: time to expiration greater than 2 weeks and less than 3 months, short living food with the criteria: time to expiration less than 2 weeks.
+ JSON DATA = {}
+ """.format(api_json)
+
+ return categorize_articles
+
+def get_json_objects():
+ try:
+ with open('../data/articles.json', 'r') as openfile:
+ # Reading from json file
+ json_object = json.load(openfile)
+
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
+
+ # debug -
+ first_ten_objects = json_object[:10]
+ return first_ten_objects
+ #return json_object
+
+def main():
+
+ try:
+ json_objs = compute_reduced_prices()
+ obj= json.loads(json_objs)
+ print(obj)
+ #chunk_size = 100
+ #for i in range(0,len(obj), chunk_size):
+ #chunk = obj[i: i+chunk_size]
+ #level_1_prompt = json_parser(obj[:10])
+ #execute_prompt(level_1_prompt)
+ bundle_articles = bundle_function(obj[:10])
+ execute_prompt(propose_recipes(bundle_articles))
+ except FileNotFoundError:
+ print("The file 'articles.json' was not found.")
+ except json.JSONDecodeError:
+ print("The file 'articles.json' is not a valid JSON file.")
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/taxtech/migrations/0001_initial.py b/taxtech/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..2cf95a803bcee1d96d7dc2b048bd410d3a137fd9
--- /dev/null
+++ b/taxtech/migrations/0001_initial.py
@@ -0,0 +1,24 @@
+# Generated by Django 5.1.1 on 2024-11-24 11:39
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='TaxTechApp',
+ fields=[
+ ('id', models.BigAutoField(primary_key=True, serialize=False)),
+ ('appointment_day', models.DateField()),
+ ('company_name', models.CharField(max_length=255)),
+ ('status', models.CharField(max_length=255)),
+ ('observations', models.TextField()),
+ ],
+ ),
+ ]
diff --git a/taxtech/migrations/0002_auto_20241124_1235.py b/taxtech/migrations/0002_auto_20241124_1235.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bd69c2a14caf43f35646c63e5d5d85f33a6f461
--- /dev/null
+++ b/taxtech/migrations/0002_auto_20241124_1235.py
@@ -0,0 +1,19 @@
+# Generated by Django 5.1.1 on 2024-11-19 09:22
+
+from django.db import migrations
+
+def add_default_entries(apps, schema_editor):
+ TaxTechApp = apps.get_model('taxtech', 'TaxTechApp')
+ TaxTechApp.objects.create(appointment_day='2024-11-19', company_name='User 001', status='Pending', observations='Unverified')
+ TaxTechApp.objects.create(appointment_day='2024-11-21', company_name='User 002', status='Confirmed', observations='Unverified')
+ TaxTechApp.objects.create(appointment_day='2024-12-04', company_name='User 003', status='Cancelled', observations='Unverified')
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('taxtech', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RunPython(add_default_entries),
+ ]
\ No newline at end of file
diff --git a/taxtech/migrations/0003_company_taxdata.py b/taxtech/migrations/0003_company_taxdata.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa07b1855dd9607c35bffd1e1248cf5eb2a5f0e2
--- /dev/null
+++ b/taxtech/migrations/0003_company_taxdata.py
@@ -0,0 +1,45 @@
+# Generated by Django 5.1.1 on 2024-11-25 09:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('taxtech', '0002_auto_20241124_1235'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Company',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255)),
+ ('country', models.CharField(max_length=255)),
+ ('currency', models.CharField(max_length=10)),
+ ('ebt', models.IntegerField()),
+ ('taxes', models.IntegerField()),
+ ('revenues', models.IntegerField()),
+ ('wages', models.IntegerField()),
+ ('fixed_assets', models.IntegerField()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='TaxData',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('country', models.CharField(max_length=255)),
+ ('currency', models.CharField(max_length=10)),
+ ('ebt', models.IntegerField()),
+ ('taxes', models.IntegerField()),
+ ('quote', models.FloatField()),
+ ('check_data', models.CharField(max_length=255)),
+ ('pot_mehrsteuer', models.IntegerField()),
+ ('de_minimis', models.CharField(max_length=10)),
+ ('five_percent_check', models.IntegerField()),
+ ('revenues', models.IntegerField(blank=True, null=True)),
+ ('salaries', models.IntegerField()),
+ ('net_loss', models.IntegerField()),
+ ],
+ ),
+ ]
diff --git a/taxtech/migrations/0004_auto_20241125_1038.py b/taxtech/migrations/0004_auto_20241125_1038.py
new file mode 100644
index 0000000000000000000000000000000000000000..83d296d9c5d2422d9736cf97e2b3a362edef8c91
--- /dev/null
+++ b/taxtech/migrations/0004_auto_20241125_1038.py
@@ -0,0 +1,333 @@
+# Generated by Django 5.1.1 on 2024-11-25 10:38
+
+from django.db import migrations
+from django.core.serializers.json import DjangoJSONEncoder
+import json
+
+
+def add_default_entries(apps, schema_editor):
+ Company = apps.get_model('taxtech', 'Company')
+ json_data = [
+ {
+ "Name": "SOLAR STAR Australia Pty Ltd.",
+ "Country": "Australia",
+ "Currency": "$",
+ "EBT": 3110804,
+ "Taxes": 933287,
+ "Revenues": 15019053,
+ "Wages": 4462929,
+ "Fixed Assets": 490842
+ },
+ {
+ "Name": "Münchener Bau Peking Trading Co. Ltd.",
+ "Country": "China",
+ "Currency": "¥",
+ "EBT": 2879422,
+ "Taxes": 122634,
+ "Revenues": 18531124,
+ "Wages": 1287482,
+ "Fixed Assets": 49983
+ },
+ {
+ "Name": "SOLAR STAR Peking Co. Ltd.",
+ "Country": "China",
+ "Currency": "¥",
+ "EBT": 3398064,
+ "Taxes": 858188,
+ "Revenues": 48629095,
+ "Wages": 1791086,
+ "Fixed Assets": 16620
+ },
+ {
+ "Name": "SOLAR STAR Shenzhen Precision Tools Co. Ltd.",
+ "Country": "China",
+ "Currency": "¥",
+ "EBT": 4890481,
+ "Taxes": 1425081,
+ "Revenues": 210938122,
+ "Wages": 52355302,
+ "Fixed Assets": 23675449
+ },
+ {
+ "Name": "Helvetia STAR Nanjing Co. Ltd.",
+ "Country": "China",
+ "Currency": "¥",
+ "EBT": 12736577,
+ "Taxes": 3318591,
+ "Revenues": 107841917,
+ "Wages": 19877312,
+ "Fixed Assets": 9181474
+ },
+ {
+ "Name": "LASER FOCUS Solutions Ltd.",
+ "Country": "China",
+ "Currency": "¥",
+ "EBT": 22933642,
+ "Taxes": 8532294,
+ "Revenues": 107007592,
+ "Wages": 28371569,
+ "Fixed Assets": 7684218
+ },
+ {
+ "Name": "SOLAR STAR AG",
+ "Country": "Germany",
+ "Currency": "€",
+ "EBT": -6257808,
+ "Taxes": 25241000,
+ "Revenues": 78373525,
+ "Wages": 24276114,
+ "Fixed Assets": 72113495
+ },
+ {
+ "Name": "SOLAR STAR Techologien GmbH",
+ "Country": "Germany",
+ "Currency": "€",
+ "EBT": -13750861,
+ "Taxes": 1011699,
+ "Revenues": 29458635,
+ "Wages": 12183108,
+ "Fixed Assets": 1563488
+ },
+ {
+ "Name": "SOLAR STAR Industrial Solar Panel Germany GmbH",
+ "Country": "Germany",
+ "Currency": "€",
+ "EBT": 2613482,
+ "Taxes": -541593,
+ "Revenues": 49003962,
+ "Wages": 21250856,
+ "Fixed Assets": 16304595
+ },
+ {
+ "Name": "SOLAR STAR Technology GmbH",
+ "Country": "Germany",
+ "Currency": "€",
+ "EBT": 86892900,
+ "Taxes": 2203025,
+ "Revenues": 406030404,
+ "Wages": 101856077,
+ "Fixed Assets": 71899050
+ },
+ {
+ "Name": "SOLAR STAR Panel Industries GmbH",
+ "Country": "Germany",
+ "Currency": "€",
+ "EBT": 6503237,
+ "Taxes": 1011920,
+ "Revenues": 69569294,
+ "Wages": 24093966,
+ "Fixed Assets": 7266301
+ },
+ {
+ "Name": "LASER GmbH",
+ "Country": "Germany",
+ "Currency": "€",
+ "EBT": 14553790,
+ "Taxes": 1296192,
+ "Revenues": 92341726,
+ "Wages": 28630956,
+ "Fixed Assets": 21589109
+ },
+ {
+ "Name": "LASER Scandinavia Oy",
+ "Country": "Finland",
+ "Currency": "€",
+ "EBT": -425655,
+ "Taxes": 600,
+ "Revenues": 294901,
+ "Wages": 365941,
+ "Fixed Assets": 71284
+ },
+ {
+ "Name": "SOLAR STAR Industrial Solar Panel France SAS",
+ "Country": "France",
+ "Currency": "€",
+ "EBT": 30126,
+ "Taxes": 1267,
+ "Revenues": 6691332,
+ "Wages": 3044949,
+ "Fixed Assets": 2837295
+ },
+ {
+ "Name": "SOLAR STAR Flight Solutions UK Ltd.",
+ "Country": "United Kingdom",
+ "Currency": "£",
+ "EBT": -1163011,
+ "Taxes": -496500,
+ "Revenues": 17802862,
+ "Wages": 7638225,
+ "Fixed Assets": 4926736
+ },
+ {
+ "Name": "LASER Hong Kong Ltd.",
+ "Country": "Hong Kong",
+ "Currency": "HK$",
+ "EBT": 9105693,
+ "Taxes": 1354462,
+ "Revenues": 142579492,
+ "Wages": 0,
+ "Fixed Assets": 0
+ },
+ {
+ "Name": "SOLAR STAR Industrial Solar Panel India Private Ltd.",
+ "Country": "India",
+ "Currency": "₹",
+ "EBT": 21728631,
+ "Taxes": 4111624,
+ "Revenues": 127793212,
+ "Wages": 20120981,
+ "Fixed Assets": 6955992
+ },
+ {
+ "Name": "SOLAR STAR Tokio Co. Ltd.",
+ "Country": "Japan",
+ "Currency": "¥",
+ "EBT": -15680825,
+ "Taxes": -4315440,
+ "Revenues": 630186879,
+ "Wages": 106616937,
+ "Fixed Assets": 23725837
+ },
+ {
+ "Name": "LASER Kyoto Co. Ltd.",
+ "Country": "Japan",
+ "Currency": "¥",
+ "EBT": 241224668,
+ "Taxes": 83370716,
+ "Revenues": 1207927931,
+ "Wages": 151146587,
+ "Fixed Assets": 125623816
+ },
+ {
+ "Name": "SOLARTWO Consumer Ltd.",
+ "Country": "Canada",
+ "Currency": "$",
+ "EBT": 11767002,
+ "Taxes": 2666776,
+ "Revenues": 74227540,
+ "Wages": 20360137,
+ "Fixed Assets": 6030437
+ },
+ {
+ "Name": "SOLAR STAR Benelux B.V.",
+ "Country": "Netherlands",
+ "Currency": "€",
+ "EBT": 804169,
+ "Taxes": 163865,
+ "Revenues": 3600132,
+ "Wages": 792861,
+ "Fixed Assets": 429649
+ },
+ {
+ "Name": "SOLAR STAR Flight Solutions Switzerland AG",
+ "Country": "Switzerland",
+ "Currency": "CHF",
+ "EBT": 371618,
+ "Taxes": 62905,
+ "Revenues": 5064940,
+ "Wages": 964089,
+ "Fixed Assets": 326595
+ },
+ {
+ "Name": "Helvetia STAR AG",
+ "Country": "Switzerland",
+ "Currency": "CHF",
+ "EBT": 14518851,
+ "Taxes": 1934433,
+ "Revenues": 113261403,
+ "Wages": 44705919,
+ "Fixed Assets": 29984629
+ },
+ {
+ "Name": "SOLAR STAR Middle East-Asia-Pacific Pte. Ltd.",
+ "Country": "Singapore",
+ "Currency": "$",
+ "EBT": -585661,
+ "Taxes": 0,
+ "Revenues": 2004397,
+ "Wages": 415867,
+ "Fixed Assets": 46753
+ },
+ {
+ "Name": "LASER Singapore Pte. Ltd.",
+ "Country": "Singapore",
+ "Currency": "$",
+ "EBT": 376199,
+ "Taxes": 47124,
+ "Revenues": 2334164,
+ "Wages": 520424,
+ "Fixed Assets": 49001
+ },
+ {
+ "Name": "SOLAR STAR International S.L.",
+ "Country": "Spain",
+ "Currency": "€",
+ "EBT": -9681319,
+ "Taxes": 823250,
+ "Revenues": 1071584,
+ "Wages": 2543733,
+ "Fixed Assets": 2516270
+ },
+ {
+ "Name": "SOLAR STAR Seoul Corp. Ltd.",
+ "Country": "South Korea",
+ "Currency": "₩",
+ "EBT": 544369794,
+ "Taxes": 16250558,
+ "Revenues": 6899230193,
+ "Wages": 1110176335,
+ "Fixed Assets": 28179496
+ },
+ {
+ "Name": "LASER Seoul Co. Ltd.",
+ "Country": "South Korea",
+ "Currency": "₩",
+ "EBT": 324790107,
+ "Taxes": 43581880,
+ "Revenues": 3468920376,
+ "Wages": 1114736450,
+ "Fixed Assets": 338538646
+ },
+ {
+ "Name": "LASER Taipeh Ltd.",
+ "Country": "Taiwan",
+ "Currency": "$",
+ "EBT": 27964294,
+ "Taxes": 5647274,
+ "Revenues": 173775171,
+ "Wages": 21404306,
+ "Fixed Assets": 13571150
+ },
+ {
+ "Name": "SOLAR STAR North America Inc.",
+ "Country": "USA",
+ "Currency": "$",
+ "EBT": -1528575,
+ "Taxes": 1301266,
+ "Revenues": 767515,
+ "Wages": 0,
+ "Fixed Assets": 0
+ }
+ ]
+
+ for entry in json_data:
+ Company.objects.create(
+ name=entry['Name'],
+ country=entry['Country'],
+ currency=entry['Currency'],
+ ebt=entry['EBT'],
+ taxes=entry['Taxes'],
+ revenues=entry['Revenues'],
+ wages=entry['Wages'],
+ fixed_assets=entry['Fixed Assets'],
+ )
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('taxtech', '0003_company_taxdata'),
+ ]
+ operations = [
+ migrations.RunPython(add_default_entries),
+ ]
\ No newline at end of file
diff --git a/taxtech/migrations/0005_auto_20241125_1043.py b/taxtech/migrations/0005_auto_20241125_1043.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb98ca5905060163ed9f736afcee4b17fe093105
--- /dev/null
+++ b/taxtech/migrations/0005_auto_20241125_1043.py
@@ -0,0 +1,276 @@
+# Generated by Django 5.1.1 on 2024-11-25 10:43
+
+from django.db import migrations
+from django.core.serializers.json import DjangoJSONEncoder
+import json
+
+
+def add_default_entries(apps, schema_editor):
+ TaxData = apps.get_model('taxtech', 'TaxData')
+ data = [
+ {
+ "Country": "Land Australien",
+ "Currency": "€",
+ "EBT": 2050144,
+ "Taxes": 615074,
+ "Quote": 30.00,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 9898156,
+ "De Minimis?": "N/A",
+ "5% Check": 24397,
+ "Revenues": None,
+ "Salaries": 348962,
+ "Net Loss": -40501
+ },
+ {
+ "Country": "Land China",
+ "Currency": "€",
+ "EBT": 6615474,
+ "Taxes": 2013643,
+ "Quote": 30.44,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 69624464,
+ "De Minimis?": "N/A",
+ "5% Check": 430459,
+ "Revenues": None,
+ "Salaries": -17508,
+ "Net Loss": -117654
+ },
+ {
+ "Country": "Land Deutschland",
+ "Currency": "€",
+ "EBT": 90554740,
+ "Taxes": 30222242,
+ "Quote": 33.37,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 724777547,
+ "De Minimis?": "N/A",
+ "5% Check": 14877411,
+ "Revenues": None,
+ "Salaries": 22201920,
+ "Net Loss": -235523
+ },
+ {
+ "Country": "Land Finnland",
+ "Currency": "€",
+ "EBT": -425655,
+ "Taxes": 600,
+ "Quote": -0.14,
+ "Check_Data": "Nein, Verlust im Land",
+ "Pot. Mehrsteuer": 294901,
+ "De Minimis?": "N/A",
+ "5% Check": 5560,
+ "Revenues": None,
+ "Salaries": 600,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Frankreich",
+ "Currency": "€",
+ "EBT": 30126,
+ "Taxes": 1267,
+ "Quote": 4.20,
+ "Check_Data": "Ja, Gewinn und Quote unter 15%",
+ "Pot. Mehrsteuer": 4519,
+ "De Minimis?": "De Minimus' Test greift",
+ "5% Check": 6691332,
+ "Revenues": None,
+ "Salaries": 298405,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Großbritannien",
+ "Currency": "€",
+ "EBT": -1364065,
+ "Taxes": -582332,
+ "Quote": 42.69,
+ "Check_Data": "Nein, Verlust im Land",
+ "Pot. Mehrsteuer": 20880504,
+ "De Minimis?": "N/A",
+ "5% Check": 433276,
+ "Revenues": None,
+ "Salaries": 0,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Hongkong",
+ "Currency": "€",
+ "EBT": 1103555,
+ "Taxes": 164153,
+ "Quote": 14.87,
+ "Check_Data": "Ja, Gewinn und Quote unter 15%",
+ "Pot. Mehrsteuer": 165533,
+ "De Minimis?": "Kein 'De Minimus' Fall; EBT zu hoch; Umsatz zu hoch",
+ "5% Check": 17279773,
+ "Revenues": 1103555,
+ "Salaries": 0,
+ "Net Loss": 1381
+ },
+ {
+ "Country": "Land Indien",
+ "Currency": "€",
+ "EBT": 262694,
+ "Taxes": 49709,
+ "Quote": 18.92,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 1544992,
+ "De Minimis?": "N/A",
+ "5% Check": 6154,
+ "Revenues": None,
+ "Salaries": -28863,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Japan",
+ "Currency": "€",
+ "EBT": 1634316,
+ "Taxes": 572843,
+ "Quote": 35.05,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 13319184,
+ "De Minimis?": "N/A",
+ "5% Check": 82819,
+ "Revenues": None,
+ "Salaries": 38108,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Kanada",
+ "Currency": "€",
+ "EBT": 8586955,
+ "Taxes": 1946076,
+ "Quote": 22.66,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 54167451,
+ "De Minimis?": "N/A",
+ "5% Check": 325744,
+ "Revenues": None,
+ "Salaries": 169119,
+ "Net Loss": -186086
+ },
+ {
+ "Country": "Land Niederlande",
+ "Currency": "€",
+ "EBT": 804169,
+ "Taxes": 163865,
+ "Quote": 20.38,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 3600132,
+ "De Minimis?": "N/A",
+ "5% Check": 33513,
+ "Revenues": None,
+ "Salaries": 5548,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Schweiz",
+ "Currency": "€",
+ "EBT": 14813848,
+ "Taxes": 1987060,
+ "Quote": 13.41,
+ "Check_Data": "Ja, Gewinn und Quote unter 15%",
+ "Pot. Mehrsteuer": 2222077,
+ "De Minimis?": "Kein 'De Minimus' Fall; EBT zu hoch; Umsatz zu hoch",
+ "5% Check": 117717474,
+ "Revenues": 7960207,
+ "Salaries": 4452630,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Singapur",
+ "Currency": "€",
+ "EBT": -144261,
+ "Taxes": 32455,
+ "Quote": -22.50,
+ "Check_Data": "Nein, Verlust im Land",
+ "Pot. Mehrsteuer": 2988059,
+ "De Minimis?": "N/A",
+ "5% Check": 5223,
+ "Revenues": None,
+ "Salaries": 0,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Spanien",
+ "Currency": "€",
+ "EBT": -9681319,
+ "Taxes": 823250,
+ "Quote": -8.50,
+ "Check_Data": "Nein, Verlust im Land",
+ "Pot. Mehrsteuer": 1071584,
+ "De Minimis?": "N/A",
+ "5% Check": 196269,
+ "Revenues": None,
+ "Salaries": 812250,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Südkorea",
+ "Currency": "€",
+ "EBT": 639996,
+ "Taxes": 44057,
+ "Quote": 6.88,
+ "Check_Data": "Ja, Gewinn und Quote unter 15%",
+ "Pot. Mehrsteuer": 95999,
+ "De Minimis?": "De Minimus' Test greift",
+ "5% Check": 7634468,
+ "Revenues": None,
+ "Salaries": 160552,
+ "Net Loss": 0
+ },
+ {
+ "Country": "Land Taiwan",
+ "Currency": "€",
+ "EBT": 892780,
+ "Taxes": 180293,
+ "Quote": 20.19,
+ "Check_Data": "Nein, Gewinn und Quote>= 15%",
+ "Pot. Mehrsteuer": 5547897,
+ "De Minimis?": "N/A",
+ "5% Check": 32348,
+ "Revenues": None,
+ "Salaries": -20675,
+ "Net Loss": 1277
+ },
+ {
+ "Country": "Land USA",
+ "Currency": "€",
+ "EBT": -1450430,
+ "Taxes": 1234741,
+ "Quote": -85.13,
+ "Check_Data": "Nein, Verlust im Land",
+ "Pot. Mehrsteuer": 728277,
+ "De Minimis?": "N/A",
+ "5% Check": 0,
+ "Revenues": None,
+ "Salaries": 3205307,
+ "Net Loss": -41751
+ }
+ ]
+
+ for item in data:
+ TaxData.objects.create(
+ country=item['Country'],
+ currency=item['Currency'],
+ ebt=item['EBT'],
+ taxes=item['Taxes'],
+ quote=item['Quote'],
+ check_data=item['Check_Data'],
+ pot_mehrsteuer=item['Pot. Mehrsteuer'],
+ de_minimis=item['De Minimis?'],
+ five_percent_check=item['5% Check'],
+ revenues=item['Revenues'],
+ salaries=item['Salaries'],
+ net_loss=item['Net Loss']
+ )
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('taxtech', '0004_auto_20241125_1038'),
+ ]
+
+ operations = [
+ migrations.RunPython(add_default_entries),
+ ]
\ No newline at end of file
diff --git a/taxtech/migrations/__init__.py b/taxtech/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/taxtech/models.py b/taxtech/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..858cc8e9aebb13090f0cfa59d1bb02295ba110ef
--- /dev/null
+++ b/taxtech/models.py
@@ -0,0 +1,37 @@
+from django.db import models
+
+class TaxTechApp(models.Model):
+ id = models.BigAutoField(primary_key=True)
+ appointment_day = models.DateField()
+ company_name = models.CharField(max_length=255)
+ status = models.CharField(max_length=255)
+ observations = models.TextField()
+
+class TaxData(models.Model):
+ country = models.CharField(max_length=255)
+ currency = models.CharField(max_length=10)
+ ebt = models.IntegerField()
+ taxes = models.IntegerField()
+ quote = models.FloatField()
+ check_data = models.CharField(max_length=255)
+ pot_mehrsteuer = models.IntegerField()
+ de_minimis = models.CharField(max_length=10)
+ five_percent_check = models.IntegerField()
+ revenues = models.IntegerField(null=True, blank=True)
+ salaries = models.IntegerField()
+ net_loss = models.IntegerField()
+
+# backend/taxtech/models.py
+
+class Company(models.Model):
+ name = models.CharField(max_length=255)
+ country = models.CharField(max_length=255)
+ currency = models.CharField(max_length=10)
+ ebt = models.IntegerField()
+ taxes = models.IntegerField()
+ revenues = models.IntegerField()
+ wages = models.IntegerField()
+ fixed_assets = models.IntegerField()
+
+ def __str__(self):
+ return self.name
\ No newline at end of file
diff --git a/taxtech/serializers.py b/taxtech/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..8ba9644ab672f830156435f58156dcd06768d145
--- /dev/null
+++ b/taxtech/serializers.py
@@ -0,0 +1,19 @@
+from rest_framework import serializers
+from .models import TaxTechApp, TaxData, Company
+
+class TaxTechAppSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = TaxTechApp
+ fields = '__all__'
+
+
+class TaxDataSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = TaxData
+ fields = '__all__'
+
+
+class CompanySerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Company
+ fields = '__all__'
\ No newline at end of file
diff --git a/taxtech/tests.py b/taxtech/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/taxtech/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/taxtech/urls.py b/taxtech/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..45d6e7574876b418336749ba13d71a9c02d5f39a
--- /dev/null
+++ b/taxtech/urls.py
@@ -0,0 +1,16 @@
+from django.urls import path, include
+from rest_framework.routers import DefaultRouter
+from .views import TaxTechAppViewSet, TaxLLMView, TaxDataViewSet, CompanyViewSet
+
+router = DefaultRouter()
+router.register(r'taxtechapp', TaxTechAppViewSet)
+router.register(r'taxdata', TaxDataViewSet)
+router.register(r'company', CompanyViewSet)
+
+
+
+urlpatterns = [
+ # ... other URL patterns
+ path('taxdata/', include(router.urls)),
+ path('tax_llm_url/', TaxLLMView.as_view(), name='tax_llm_url'),
+]
\ No newline at end of file
diff --git a/taxtech/views.py b/taxtech/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..0920e0066a67577daec42683530bca696eb1a70f
--- /dev/null
+++ b/taxtech/views.py
@@ -0,0 +1,136 @@
+from django.shortcuts import render
+from django.core.files.storage import FileSystemStorage
+import django_filters
+from rest_framework import viewsets
+from rest_framework.decorators import action
+from rest_framework.response import Response
+from rest_framework.pagination import LimitOffsetPagination
+from django.utils import timezone
+from datetime import datetime, timedelta
+import requests
+
+from .models import TaxTechApp, TaxData, Company
+from .serializers import TaxTechAppSerializer, CompanySerializer, TaxDataSerializer
+
+from django.http import JsonResponse
+from rest_framework.response import Response
+from rest_framework.views import APIView
+from mistralai import Mistral
+import os
+import requests
+from openai import OpenAI
+from ollama import Client
+from django.http import FileResponse
+import io
+from rest_framework.pagination import PageNumberPagination
+
+
+
+class TaxTechAppPagination(PageNumberPagination):
+ page_size = 10
+ page_size_query_param = 'page_size'
+ max_page_size = 100
+
+class TaxTechAppViewSet(viewsets.ModelViewSet):
+ queryset = TaxTechApp.objects.all().order_by('id')
+ serializer_class = TaxTechAppSerializer
+ pagination_class = TaxTechAppPagination
+
+
+
+class TaxDataPagination(PageNumberPagination):
+ page_size = 10
+ page_size_query_param = 'page_size'
+ max_page_size = 100
+
+class TaxDataViewSet(viewsets.ModelViewSet):
+ queryset = TaxData.objects.all().order_by('id')
+ serializer_class = TaxDataSerializer
+ pagination_class = TaxDataPagination
+
+
+class CompanyPagination(PageNumberPagination):
+ page_size = 10
+ page_size_query_param = 'page_size'
+ max_page_size = 100
+
+class CompanyViewSet(viewsets.ModelViewSet):
+ queryset = Company.objects.all().order_by('id')
+ serializer_class = CompanySerializer
+ pagination_class = CompanyPagination
+
+
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from .engine import execute_prompt, bundle_function, propose_recipes, compute_reduced_prices
+import json
+
+@api_view(['GET'])
+def recipe_generate_route(request):
+ isLocal = False
+ try:
+ json_objs = compute_reduced_prices()
+ obj= json.loads(json_objs)
+ bundle_articles = bundle_function(obj[:10])
+
+ result = execute_prompt(propose_recipes(bundle_articles), False)
+ except (FileNotFoundError, json.JSONDecodeError) as e:
+ return Response({'error': str(e)}, status=500)
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)
+ return Response(result)
+
+
+class TaxLLMView(APIView):
+ def post(self, request, format=None):
+ try:
+ data = request.data
+
+ #isOnline = data['isOnline']
+ isOnline = True
+
+ prompt = data['messages'][0]['prompt']
+ # Specify model
+ #model = "pixtral-12b-2409"
+ model = data['model']
+ # Define the messages for the chat
+ messages = [
+ {
+ "role": "system",
+ "content": "Please provide a concise response, limiting your answer to three lines or less."
+ },
+ {
+ "role": "user",
+ "content": [
+ {
+ "type": "text",
+ "text": prompt
+ }
+ ]
+ }
+ ]
+
+ if(isOnline):
+ api_key = os.environ["MISTRAL_API_KEY"]
+
+ # Initialize the Mistral client
+ client = Mistral(api_key=api_key)
+
+
+ # Get the chat response
+ chat_response = client.chat.complete(
+ model=model,
+ messages=messages
+ )
+
+ content = chat_response.choices[0].message.content
+ else:
+ content = "helloWorld"
+
+ #print(chat_response.choices[0].message.content)
+ # Return the content of the response
+ return Response({"response": content})
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ return Response({'error': 'Something went wrong'}, status=500)