WIP AI system

This commit is contained in:
vabene1111
2025-09-09 14:58:32 +02:00
parent d0b860e623
commit 397912e87f
49 changed files with 444 additions and 130 deletions

View File

@@ -1,5 +1,6 @@
from django.utils import timezone
from django.db.models import Sum
from litellm import CustomLogger
from cookbook.models import AiLog
@@ -22,4 +23,60 @@ def has_monthly_token(space):
def can_perform_ai_request(space):
return has_monthly_token(space) and space.ai_enabled
return (has_monthly_token(space) or space.ai_credits_balance > 0) and space.ai_enabled
class AiCallbackHandler(CustomLogger):
space = None
user = None
ai_provider = None
def __init__(self, space, user, ai_provider):
super().__init__()
self.space = space
self.user = user
self.ai_provider = ai_provider
def log_pre_api_call(self, model, messages, kwargs):
pass
def log_post_api_call(self, kwargs, response_obj, start_time, end_time):
pass
def log_success_event(self, kwargs, response_obj, start_time, end_time):
self.create_ai_log(kwargs, response_obj, start_time, end_time)
def log_failure_event(self, kwargs, response_obj, start_time, end_time):
self.create_ai_log(kwargs, response_obj, start_time, end_time)
def create_ai_log(self, kwargs, response_obj, start_time, end_time):
credit_cost = 0
credits_from_balance = False
if self.ai_provider.log_credit_cost:
credit_cost = kwargs.get("response_cost", 0) * 100
print(not has_monthly_token(self.space) , self.space.ai_credits_balance > 0, not has_monthly_token(self.space) and self.space.ai_credits_balance > 0)
if (not has_monthly_token(self.space)) and self.space.ai_credits_balance > 0:
print('taking credits from balance')
self.space.ai_credits_balance = max(0, self.space.ai_credits_balance - credit_cost)
print('setting from balance to true')
credits_from_balance = True
print('saving space')
self.space.save()
print('done')
else:
print('not taking credits from balance')
print('creating AI log with credit cost ', credit_cost , ' from balance: ', credits_from_balance)
AiLog.objects.create(
created_by=self.user,
space=self.space,
ai_provider=self.ai_provider,
start_time=start_time,
end_time=end_time,
input_tokens=response_obj['usage']['prompt_tokens'],
output_tokens=response_obj['usage']['completion_tokens'],
function=AiLog.F_FILE_IMPORT,
credit_cost=credit_cost,
credits_from_balance=credits_from_balance,
)

View File

@@ -0,0 +1,24 @@
# Generated by Django 4.2.22 on 2025-09-09 11:40
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0226_aiprovider_log_credit_cost_and_more'),
]
operations = [
migrations.AddField(
model_name='space',
name='ai_default_provider',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_ai_default_provider', to='cookbook.aiprovider'),
),
migrations.AlterField(
model_name='space',
name='ai_credits_balance',
field=models.DecimalField(decimal_places=4, default=0, max_digits=16),
),
]

View File

@@ -331,7 +331,8 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
ai_enabled = models.BooleanField(default=True)
ai_credits_monthly = models.IntegerField(default=100)
ai_credits_balance = models.IntegerField(default=0)
ai_credits_balance = models.DecimalField(default=0, max_digits=16, decimal_places=4)
ai_default_provider = models.ForeignKey("AiProvider", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_ai_default_provider')
internal_note = models.TextField(blank=True, null=True)

View File

@@ -326,83 +326,6 @@ class UserFileViewSerializer(serializers.ModelSerializer):
read_only_fields = ('id', 'file', 'file_download', 'file_size_kb', 'preview', 'created_by', 'created_at')
class SpaceSerializer(WritableNestedModelSerializer):
created_by = UserSerializer(read_only=True)
user_count = serializers.SerializerMethodField('get_user_count')
recipe_count = serializers.SerializerMethodField('get_recipe_count')
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
ai_monthly_credits_used = serializers.SerializerMethodField('get_ai_monthly_credits_used')
food_inherit = FoodInheritFieldSerializer(many=True)
image = UserFileViewSerializer(required=False, many=False, allow_null=True)
nav_logo = UserFileViewSerializer(required=False, many=False, allow_null=True)
custom_space_theme = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_32 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_128 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_144 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_180 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_192 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_512 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_svg = UserFileViewSerializer(required=False, many=False, allow_null=True)
@extend_schema_field(int)
def get_user_count(self, obj):
return UserSpace.objects.filter(space=obj).count()
@extend_schema_field(int)
def get_recipe_count(self, obj):
return Recipe.objects.filter(space=obj).count()
@extend_schema_field(int)
def get_ai_monthly_credits_used(self, obj):
return get_monthly_token_usage(obj)
@extend_schema_field(float)
def get_file_size_mb(self, obj):
try:
return UserFile.objects.filter(space=obj).aggregate(Sum('file_size_kb'))['file_size_kb__sum'] / 1000
except TypeError:
return 0
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = Space
fields = (
'id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
'allow_sharing', 'demo', 'food_inherit', 'user_count', 'recipe_count', 'file_size_mb',
'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color',
'logo_color_32', 'logo_color_128', 'logo_color_144', 'logo_color_180', 'logo_color_192', 'logo_color_512', 'logo_color_svg', 'ai_credits_monthly',
'ai_credits_balance', 'ai_monthly_credits_used', 'ai_enabled')
read_only_fields = (
'id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing',
'demo', 'ai_credits_monthly', 'ai_credits_balance', 'ai_monthly_credits_used')
class UserSpaceSerializer(WritableNestedModelSerializer):
user = UserSerializer(read_only=True)
groups = GroupSerializer(many=True)
def validate(self, data):
if self.instance.user == self.context['request'].space.created_by: # can't change space owner permission
raise serializers.ValidationError(_('Cannot modify Space owner permission.'))
return super().validate(data)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserSpace
fields = ('id', 'user', 'space', 'groups', 'active', 'internal_note', 'invite_link', 'created_at', 'updated_at',)
read_only_fields = ('id', 'invite_link', 'created_at', 'updated_at', 'space')
class SpacedModelSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
class AiProviderSerializer(serializers.ModelSerializer):
api_key = serializers.CharField(required=False, write_only=True)
@@ -442,6 +365,96 @@ class AiLogSerializer(serializers.ModelSerializer):
read_only_fields = ('__all__',)
class SpaceSerializer(WritableNestedModelSerializer):
created_by = UserSerializer(read_only=True)
user_count = serializers.SerializerMethodField('get_user_count')
recipe_count = serializers.SerializerMethodField('get_recipe_count')
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
ai_monthly_credits_used = serializers.SerializerMethodField('get_ai_monthly_credits_used')
ai_default_provider = AiProviderSerializer(required=False, allow_null=True)
food_inherit = FoodInheritFieldSerializer(many=True)
image = UserFileViewSerializer(required=False, many=False, allow_null=True)
nav_logo = UserFileViewSerializer(required=False, many=False, allow_null=True)
custom_space_theme = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_32 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_128 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_144 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_180 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_192 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_512 = UserFileViewSerializer(required=False, many=False, allow_null=True)
logo_color_svg = UserFileViewSerializer(required=False, many=False, allow_null=True)
@extend_schema_field(int)
def get_user_count(self, obj):
return UserSpace.objects.filter(space=obj).count()
@extend_schema_field(int)
def get_recipe_count(self, obj):
return Recipe.objects.filter(space=obj).count()
@extend_schema_field(int)
def get_ai_monthly_credits_used(self, obj):
return get_monthly_token_usage(obj)
@extend_schema_field(float)
def get_file_size_mb(self, obj):
try:
return UserFile.objects.filter(space=obj).aggregate(Sum('file_size_kb'))['file_size_kb__sum'] / 1000
except TypeError:
return 0
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
def update(self, instance, validated_data):
if 'ai_enabled' in validated_data and not self.context['request'].user.is_superuser:
del validated_data['ai_enabled']
if 'ai_credits_monthly' in validated_data and not self.context['request'].user.is_superuser:
del validated_data['ai_credits_monthly']
if 'ai_credits_balance' in validated_data and not self.context['request'].user.is_superuser:
del validated_data['ai_credits_balance']
return super().update(instance, validated_data)
class Meta:
model = Space
fields = (
'id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
'allow_sharing', 'demo', 'food_inherit', 'user_count', 'recipe_count', 'file_size_mb',
'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color',
'logo_color_32', 'logo_color_128', 'logo_color_144', 'logo_color_180', 'logo_color_192', 'logo_color_512', 'logo_color_svg', 'ai_credits_monthly',
'ai_credits_balance', 'ai_monthly_credits_used', 'ai_enabled', 'ai_default_provider')
read_only_fields = (
'id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing',
'demo', 'ai_monthly_credits_used')
class UserSpaceSerializer(WritableNestedModelSerializer):
user = UserSerializer(read_only=True)
groups = GroupSerializer(many=True)
def validate(self, data):
if self.instance.user == self.context['request'].space.created_by: # can't change space owner permission
raise serializers.ValidationError(_('Cannot modify Space owner permission.'))
return super().validate(data)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserSpace
fields = ('id', 'user', 'space', 'groups', 'active', 'internal_note', 'invite_link', 'created_at', 'updated_at',)
read_only_fields = ('id', 'invite_link', 'created_at', 'updated_at', 'space')
class SpacedModelSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
def create(self, validated_data):
@@ -1610,7 +1623,6 @@ class ServerSettingsSerializer(serializers.Serializer):
# TODO add all other relevant settings including path/url related ones?
shopping_min_autosync_interval = serializers.CharField()
enable_pdf_export = serializers.BooleanField()
enable_ai_import = serializers.BooleanField()
disable_external_connectors = serializers.BooleanField()
terms_url = serializers.CharField()
privacy_url = serializers.CharField()

View File

@@ -65,7 +65,7 @@ from cookbook.connectors.connector_manager import ConnectorManager, ActionType
from cookbook.forms import ImportForm, ImportExportBase
from cookbook.helper import recipe_url_import as helper
from cookbook.helper.HelperFunctions import str2bool, validate_import_url
from cookbook.helper.ai_helper import has_monthly_token, can_perform_ai_request
from cookbook.helper.ai_helper import has_monthly_token, can_perform_ai_request, AiCallbackHandler
from cookbook.helper.image_processing import handle_image
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.open_data_importer import OpenDataImporter
@@ -117,7 +117,7 @@ from cookbook.serializer import (AccessTokenSerializer, AutomationSerializer, Au
from cookbook.version_info import TANDOOR_VERSION
from cookbook.views.import_export import get_integration
from recipes import settings
from recipes.settings import DRF_THROTTLE_RECIPE_URL_IMPORT, FDC_API_KEY, AI_RATELIMIT, AI_API_KEY, AI_MODEL_NAME
from recipes.settings import DRF_THROTTLE_RECIPE_URL_IMPORT, FDC_API_KEY, AI_RATELIMIT
DateExample = OpenApiExample('Date Format', value='1972-12-05', request_only=True)
BeforeDateExample = OpenApiExample('Before Date Format', value='-1972-12-05', request_only=True)
@@ -2041,25 +2041,7 @@ class AiImportView(APIView):
ai_provider = AiProvider.objects.filter(pk=serializer.validated_data['ai_provider_id']).filter(Q(space=request.space) | Q(space__isnull=True)).first()
def log_ai_request(kwargs, completion_response, start_time, end_time):
credit_cost = 0
if ai_provider.log_credit_cost:
credit_cost = kwargs.get("response_cost", 0) * 100
AiLog.objects.create(
created_by=request.user,
space=request.space,
ai_provider=ai_provider,
start_time=start_time,
end_time=end_time,
input_tokens=completion_response['usage']['prompt_tokens'],
output_tokens=completion_response['usage']['completion_tokens'],
function=AiLog.F_FILE_IMPORT,
credit_cost=credit_cost,
credits_from_balance=False, # TODO implement
)
litellm.success_callback = [log_ai_request]
litellm.callbacks = [AiCallbackHandler(request.space, request.user, ai_provider)]
messages = []
uploaded_file = serializer.validated_data['file']
@@ -2442,7 +2424,6 @@ class ServerSettingsViewSet(viewsets.GenericViewSet):
# Attention: No login required, do not return sensitive data
s['shopping_min_autosync_interval'] = settings.SHOPPING_MIN_AUTOSYNC_INTERVAL
s['enable_pdf_export'] = settings.ENABLE_PDF_EXPORT
s['enable_ai_import'] = settings.AI_API_KEY != ''
s['disable_external_connectors'] = settings.DISABLE_EXTERNAL_CONNECTORS
s['terms_url'] = settings.TERMS_URL
s['privacy_url'] = settings.PRIVACY_URL

View File

@@ -484,6 +484,11 @@ Sets the monthly default credit limit for AI usage
SPACE_AI_CREDITS_MONTHLY=100
```
Ratelimit for AI API
```
AI_RATELIMIT=60/hour
```
#### FDC Api
The FDC Api is used to automatically load nutrition information from

View File

@@ -139,8 +139,6 @@ HCAPTCHA_SECRET = os.getenv('HCAPTCHA_SECRET', '')
FDC_API_KEY = os.getenv('FDC_API_KEY', 'DEMO_KEY')
AI_API_KEY = os.getenv('AI_API_KEY', '')
AI_MODEL_NAME = os.getenv('AI_MODEL_NAME', 'gemini/gemini-2.0-flash')
AI_RATELIMIT = os.getenv('AI_RATELIMIT', '60/hour')
SHARING_ABUSE = extract_bool('SHARING_ABUSE', False)

View File

@@ -14,6 +14,7 @@
<v-list-item link title="Space" @click="window = 'space'" prepend-icon="fa-solid fa-database"></v-list-item>
<v-list-item link :title="$t('Recipes')" @click="window = 'recipes'" prepend-icon="$recipes"></v-list-item>
<v-list-item link :title="$t('Import')" @click="window = 'import'" prepend-icon="$import"></v-list-item>
<v-list-item link :title="$t('AI')" @click="window = 'ai'" prepend-icon="$ai"></v-list-item>
<v-list-item link :title="$t('Unit')" @click="window = 'unit'" prepend-icon="fa-solid fa-scale-balanced"></v-list-item>
<v-list-item link :title="$t('Food')" @click="window = 'food'" prepend-icon="fa-solid fa-carrot"></v-list-item>
<v-list-item link :title="$t('Keyword')" @click="window = 'keyword'" prepend-icon="fa-solid fa-tags"></v-list-item>
@@ -105,6 +106,35 @@
<v-btn color="primary" variant="tonal" prepend-icon="$import" class="me-2" :to="{name: 'RecipeImportPage'}">{{ $t('Import') }}</v-btn>
</v-window-item>
<v-window-item value="ai">
<p class="mt-3">Tandoor has several functions that allow you to use AI to automatically perform certain tasks like importing recipes from a PDFs or images.
</p>
<p class="mt-3" v-if="useUserPreferenceStore().serverSettings.hosted">
To use AI you must first configure an AI Provider. This can also be done globally for all spaces by the person operating your Tandoor Server.
</p>
<p class="mt-3" v-if="!useUserPreferenceStore().serverSettings.hosted">
Some AI Providers are available globally for every space to use. You can also configure additional AI Providers for your space only.
</p>
<p class="mt-3" v-if="useUserPreferenceStore().serverSettings.hosted">
To prevent accidental AI cost you can review your AI usage using the AI Log. The Server Administrator can also set AI usage limits for your space (either monthly or using a balance).
</p>
<p class="mt-3" v-if="!useUserPreferenceStore().serverSettings.hosted">
Depending on your subscription you will have different AI Credits available for your space every month. Additionally you might have a Credit balance
that will be used once your monthly limit is reached.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="$ai" class="me-2" :to="{name: 'ModelListPage', params: {model: 'AiProvider'}}">
{{ $t('AiProvider') }}
</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="$ai" class="me-2" :to="{name: 'ModelListPage', params: {model: 'AiLog'}}">
{{ $t('AiLog') }}
</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="$ai" class="me-2" :to="{name: 'SpaceSettings'}">{{ $t('SpaceSettings') }}</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="$import" class="me-2" :to="{name: 'RecipeImportPage'}">{{ $t('Import') }}</v-btn>
</v-window-item>
<v-window-item value="unit">
<p class="mt-3">Units allow you to measure how much of something you need in a recipe or on a shopping list.

View File

@@ -223,7 +223,7 @@ const recipe = defineModel<Recipe>({required: true})
const servings = ref(1)
const showFullRecipeName = ref(false)
const selectedAiProvider = ref<undefined | AiProvider>(undefined)
const selectedAiProvider = ref<undefined | AiProvider>(useUserPreferenceStore().activeSpace.aiDefaultProvider)
/**
* factor for multiplying ingredient amounts based on recipe base servings and user selected servings

View File

@@ -78,19 +78,38 @@
<v-textarea v-model="space.message" :label="$t('Message')"></v-textarea>
<v-btn color="success" @click="updateSpace()" prepend-icon="$save">{{ $t('Save') }}</v-btn>
<!-- <model-select v-model="space.foodInherit" model="FoodInheritField" mode="tags"></model-select>-->
<p class="text-h6 mt-2">{{ $t('AI') }}</p>
<v-divider class="mb-2"></v-divider>
<p class="text-disabled font-italic text-body-2">
<span v-if="useUserPreferenceStore().serverSettings.hosted">
{{ $t('AISettingsHostedHelp') }}
</span>
<span v-else>
{{ $t('SettingsOnlySuperuser') }}
</span>
</p>
<v-checkbox v-model="space.aiEnabled" :label="$t('Enabled')" :disabled="!useUserPreferenceStore().userSettings.user.isSuperuser" hide-details></v-checkbox>
<template v-if="space.aiEnabled">
<model-select model="AiProvider" :label="$t('Default')" v-model="space.aiDefaultProvider"></model-select>
<v-number-input v-model="space.aiCreditsMonthly" :label="$t('MonthlyCredits')" :disabled="!useUserPreferenceStore().userSettings.user.isSuperuser"></v-number-input>
<v-number-input v-model="space.aiCreditsBalance" :label="$t('AiCreditsBalance')" :disabled="!useUserPreferenceStore().userSettings.user.isSuperuser"></v-number-input>
</template>
<v-btn color="success" @click="updateSpace()" prepend-icon="$save">{{ $t('Save') }}</v-btn>
<v-divider class="mt-4 mb-2"></v-divider>
<h2>{{$t('Cosmetic')}}</h2>
<span>{{$t('Space_Cosmetic_Settings')}}</span>
<h2>{{ $t('Cosmetic') }}</h2>
<span>{{ $t('Space_Cosmetic_Settings') }}</span>
<v-label class="mt-4">{{ $t('Nav_Color') }}</v-label>
<v-color-picker v-model="space.navBgColor" class="mb-4" mode="hex" :modes="['hex']" show-swatches
:swatches="[['#ddbf86'],['#b98766'],['#b55e4f'],['#82aa8b'],['#385f84']]"></v-color-picker>
<v-btn class="mb-4" @click="space.navBgColor = ''">{{$t('Reset')}}</v-btn>
<v-btn class="mb-4" @click="space.navBgColor = ''">{{ $t('Reset') }}</v-btn>
<user-file-field v-model="space.navLogo" :label="$t('Logo')" :hint="$t('CustomNavLogoHelp')" persistent-hint></user-file-field>

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API_Browser": "",
"API_Documentation": "",
"Add": "",
@@ -14,6 +15,7 @@
"Added_by": "",
"Added_on": "",
"Advanced": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -109,6 +111,7 @@
"FoodOnHand": "",
"Food_Alias": "",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -176,6 +179,7 @@
"Message": "",
"MissingProperties": "",
"Month": "",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "",
"MoveCategory": "",
@@ -268,6 +272,7 @@
"Selected": "",
"Servings": "",
"Settings": "",
"SettingsOnlySuperuser": "",
"Share": "",
"Shopping_Categories": "",
"Shopping_Category": "",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API_Browser": "",
"API_Documentation": "",
"Add": "Добави",
@@ -14,6 +15,7 @@
"Added_by": "Добавено от",
"Added_on": "Добавено",
"Advanced": "Разширено",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -106,6 +108,7 @@
"FoodOnHand": "Имате {храна} под ръка.",
"Food_Alias": "Псевдоним на храната",
"Foods": "Храни",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -170,6 +173,7 @@
"Merge_Keyword": "Обединяване на ключова дума",
"MissingProperties": "",
"Month": "Месец",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Премести",
"MoveCategory": "Премести към: ",
@@ -261,6 +265,7 @@
"Selected": "Избрано",
"Servings": "Порции",
"Settings": "Настройки",
"SettingsOnlySuperuser": "",
"Share": "Споделяне",
"Shopping_Categories": "Категории за пазаруване",
"Shopping_Category": "Категория за пазаруване",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Afegit per",
"Added_on": "Afegit el",
"Advanced": "Avançat",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "Àlies per l'aliment",
"Food_Replace": "Aliment equivalent",
"Foods": "Aliments",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "Missatge",
"MissingProperties": "",
"Month": "Mes",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Moure",
"MoveCategory": "Moure a: ",
@@ -340,6 +344,7 @@
"Selected": "Seleccionat",
"Servings": "Racions",
"Settings": "Opcions",
"SettingsOnlySuperuser": "",
"Share": "Compartir",
"ShoppingBackgroundSyncWarning": "Error de la connexió, esperant per sincronitzar ...",
"Shopping_Categories": "Categoria de compres",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Přidáno uživatelem",
"Added_on": "Přidáno v",
"Advanced": "Rozšířené",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -149,6 +151,7 @@
"Food_Alias": "Přezdívka potraviny",
"Food_Replace": "Nahrazení v potravině",
"Foods": "Potraviny",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -225,6 +228,7 @@
"Message": "Zpráva",
"MissingProperties": "",
"Month": "Měsíc",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Přesunout",
"MoveCategory": "Přesunout do: ",
@@ -337,6 +341,7 @@
"Selected": "Vybrané",
"Servings": "Porce",
"Settings": "Nastavení",
"SettingsOnlySuperuser": "",
"Share": "Sdílet",
"Shopping_Categories": "Kategorie nákupního seznamu",
"Shopping_Category": "Kategorie nákupního seznamu",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Tilføjet af",
"Added_on": "Tilføjet den",
"Advanced": "Avanceret",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "Alternativt navn til mad",
"Food_Replace": "Erstat ingrediens",
"Foods": "Mad",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "Besked",
"MissingProperties": "",
"Month": "Måned",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Flyt",
"MoveCategory": "Flyt til: ",
@@ -340,6 +344,7 @@
"Selected": "Valgt",
"Servings": "Serveringer",
"Settings": "Indstillinger",
"SettingsOnlySuperuser": "",
"Share": "Del",
"ShoppingBackgroundSyncWarning": "Dårligt netværk, afventer synkronisering ...",
"Shopping_Categories": "Indkøbskategorier",

View File

@@ -1,6 +1,7 @@
{
"AI": "AI",
"AIImportSubtitle": "Verwende AI um Fotos von Rezepten zu importieren.",
"AISettingsHostedHelp": "AI Verfügbarkeit und Credit Limits können über die Tarifverwaltung geändert werden. ",
"API": "API",
"APIKey": "API Schlüssel",
"API_Browser": "API Browser",
@@ -29,6 +30,7 @@
"Admin": "Admin",
"Advanced": "Erweitert",
"Advanced Search Settings": "Erweiterte Sucheinstellungen",
"AiCreditsBalance": "Credit Guthaben",
"AiLog": "AI Protokoll",
"AiLogHelp": "Eine Übersicht der AI Anfragen.",
"AiModelHelp": "Die Liste enthält Modelle die offiziell Unterstützt und getestet wurden. Weitere modelle können manuell eingetragen werden.",
@@ -212,6 +214,7 @@
"Food_Replace": "Essen Ersetzen",
"Foods": "Lebensmittel",
"Friday": "Freitag",
"FromBalance": "Guthaben verwendet",
"Fulltext": "Volltext",
"FulltextHelp": "Felder welche im Volltext durchsucht werden sollen. Tipp: Die Suchtypen 'web', 'raw' und 'phrase' funktionieren nur mit Volltext-Feldern.",
"Fuzzy": "Unscharf",
@@ -317,6 +320,7 @@
"ModelSelectResultsHelp": "Für mehr Ergebnisse suchen",
"Monday": "Montag",
"Month": "Monat",
"MonthlyCredits": "Monatliche Credits",
"MonthlyCreditsUsed": "Monatliche Credits verwendet",
"More": "Mehr",
"Move": "Verschieben",
@@ -471,6 +475,7 @@
"Servings": "Portionen",
"ServingsText": "Portionstext",
"Settings": "Einstellungen",
"SettingsOnlySuperuser": "Einige Einstellungen können nur vom Server Administrator verändert werden.",
"Share": "Teilen",
"ShopLater": "Später kaufen",
"ShopNow": "Jetzt kaufen",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Προστέθηκε από",
"Added_on": "Προστέθηκε στις",
"Advanced": "Για προχωρημένους",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "Ψευδώνυμο φαγητού",
"Food_Replace": "Αντικατάσταση Φαγητού",
"Foods": "Φαγητά",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "Μήνυμα",
"MissingProperties": "",
"Month": "Μήνας",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Μετακίνηση",
"MoveCategory": "Μετακίνηση σε: ",
@@ -340,6 +344,7 @@
"Selected": "Επιλεγμένο",
"Servings": "Μερίδες",
"Settings": "Ρυθμίσεις",
"SettingsOnlySuperuser": "",
"Share": "Κοινοποίηση",
"ShoppingBackgroundSyncWarning": "Κακό δίκτυο, αναμονή συγχρονισμού...",
"Shopping_Categories": "Κατηγορίες αγορών",

View File

@@ -1,6 +1,7 @@
{
"AI": "AI",
"AIImportSubtitle": "Use AI to import images of recipes.",
"AISettingsHostedHelp": "You can enable AI features or change available credits by managing your subscription.",
"API": "API",
"APIKey": "API key",
"API_Browser": "API Browser",
@@ -27,6 +28,7 @@
"Added_on": "Added On",
"Admin": "Admin",
"Advanced": "Advanced",
"AiCreditsBalance": "Credit Balance",
"AiLog": "AI Log",
"AiLogHelp": "Overview of your spaces AI requests. ",
"AiModelHelp": "The list contains model that are offically tested and supported. You can add additional models if you want.",
@@ -210,6 +212,7 @@
"Food_Replace": "Food Replace",
"Foods": "Foods",
"Friday": "Friday",
"FromBalance": "From Balance",
"Fulltext": "Fulltext",
"FulltextHelp": "Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods only function with fulltext fields.",
"Fuzzy": "Fuzzy",
@@ -315,6 +318,7 @@
"ModelSelectResultsHelp": "Search for more results",
"Monday": "Monday",
"Month": "Month",
"MonthlyCredits": "Monthly Credits",
"MonthlyCreditsUsed": "Monthly credits used",
"More": "More",
"Move": "Move",
@@ -469,6 +473,7 @@
"Servings": "Servings",
"ServingsText": "Servings Text",
"Settings": "Settings",
"SettingsOnlySuperuser": "Some Settings can only be changed by the Server Administrator.",
"Share": "Share",
"ShopLater": "Shop later",
"ShopNow": "Shop now",

View File

@@ -1,6 +1,7 @@
{
"AI": "IA",
"AIImportSubtitle": "Usar IA para importar imágenes de recetas.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -26,6 +27,7 @@
"Added_on": "Añadido el",
"Admin": "Administrador",
"Advanced": "Avanzado",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -207,6 +209,7 @@
"Food_Replace": "Sustituir Alimento",
"Foods": "Alimentos",
"Friday": "Viernes",
"FromBalance": "",
"GettingStarted": "Primeros pasos",
"Global": "",
"GlobalHelp": "",
@@ -305,6 +308,7 @@
"ModelSelectResultsHelp": "Buscar más resultados",
"Monday": "Lunes",
"Month": "Mes",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"More": "Más",
"Move": "Mover",
@@ -453,6 +457,7 @@
"Servings": "Raciones",
"ServingsText": "Texto de la porción",
"Settings": "Opciones",
"SettingsOnlySuperuser": "",
"Share": "Compartir",
"ShopLater": "Comprar después",
"ShopNow": "Comprar ahora",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -17,6 +18,7 @@
"Added_on": "Lisätty",
"Advanced": "Edistynyt",
"Advanced Search Settings": "Tarkennetun Haun Asetukset",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -147,6 +149,7 @@
"Food_Alias": "Ruoan nimimerkki",
"Food_Replace": "Korvaa Ruoka",
"Foods": "Ruuat",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -221,6 +224,7 @@
"Message": "Viesti",
"MissingProperties": "",
"Month": "Kuukausi",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Siirry",
"MoveCategory": "Siirrä paikkaan: ",
@@ -329,6 +333,7 @@
"Selected": "Valittu",
"Servings": "Annokset",
"Settings": "Asetukset",
"SettingsOnlySuperuser": "",
"Share": "Jaa",
"ShoppingBackgroundSyncWarning": "Huono verkkoyhteys, odotetaan synkronointia ...",
"Shopping_Categories": "Ostoskategoriat",

View File

@@ -1,6 +1,7 @@
{
"AI": "IA",
"AIImportSubtitle": "Utiliser l'IA pour importer des images de recettes.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -27,6 +28,7 @@
"Admin": "Admin",
"Advanced": "Avancé",
"Advanced Search Settings": "Paramètres de recherche avancée",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -210,6 +212,7 @@
"Food_Replace": "Remplacer l'aliment",
"Foods": "Aliments",
"Friday": "Vendredi",
"FromBalance": "",
"Fulltext": "Texte intégral",
"FulltextHelp": "Champs de recherche en texte intégral. Remarque : les méthodes de recherche \"web\", \"phrase\" et \"raw\" ne fonctionnent qu'avec des champs en texte intégral.",
"Fuzzy": "Approximatif",
@@ -312,6 +315,7 @@
"ModelSelectResultsHelp": "Chercher plus de résultats",
"Monday": "Lundi",
"Month": "Mois",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"More": "Plus",
"Move": "Déplacer",
@@ -466,6 +470,7 @@
"Servings": "Portions",
"ServingsText": "Texte des portions",
"Settings": "Paramètres",
"SettingsOnlySuperuser": "",
"Share": "Partager",
"ShopLater": "Acheter plus tard",
"ShopNow": "Acheter maintenant",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "נוסף ע\"י",
"Added_on": "נוסף ב",
"Advanced": "מתקדם",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "שם כינוי לאוכל",
"Food_Replace": "החלף אוכל",
"Foods": "מאכלים",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "הודעה",
"MissingProperties": "",
"Month": "חודש",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "העברה",
"MoveCategory": "העבר אל: ",
@@ -340,6 +344,7 @@
"Selected": "נבחר",
"Servings": "מנות",
"Settings": "הגדרות",
"SettingsOnlySuperuser": "",
"Share": "שיתוף",
"ShoppingBackgroundSyncWarning": "בעיית תקשורת, מחכה לסנכון...",
"Shopping_Categories": "קטגוריות קניות",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Dodao",
"Added_on": "Dodano",
"Advanced": "Napredno",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "Nadimci namirnice",
"Food_Replace": "Zamjena namirnica",
"Foods": "Namirnice",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "Poruka",
"MissingProperties": "",
"Month": "Mjesec",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Premjesti",
"MoveCategory": "Premjesti u: ",
@@ -340,6 +344,7 @@
"Selected": "Odabrano",
"Servings": "Porcije",
"Settings": "Postavke",
"SettingsOnlySuperuser": "",
"Share": "Podijeli",
"ShoppingBackgroundSyncWarning": "Loša mreža, čeka se sinkronizacija...",
"Shopping_Categories": "Kategorije Kupovine",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Hozzádta",
"Added_on": "Hozzáadva",
"Advanced": "Haladó",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -133,6 +135,7 @@
"Food_Alias": "",
"Food_Replace": "Étel cseréje",
"Foods": "Alapanyagok",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -208,6 +211,7 @@
"Message": "Üzenet",
"MissingProperties": "",
"Month": "Hónap",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Mozgatás",
"MoveCategory": "Áthelyezés ide: ",
@@ -313,6 +317,7 @@
"Selected": "Kiválasztott",
"Servings": "Adag",
"Settings": "Beállítások",
"SettingsOnlySuperuser": "",
"Share": "Megosztás",
"Shopping_Categories": "Vásárlási kategóriák",
"Shopping_Category": "Vásárlási kategória",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API_Browser": "",
"API_Documentation": "",
"Add": "",
@@ -8,6 +9,7 @@
"Add_to_Plan": "Ավելացնել պլանին",
"Add_to_Shopping": "Ավելացնել գնումներին",
"Advanced Search Settings": "Ընդլայնված փնտրման կարգավորումներ",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -58,6 +60,7 @@
"File": "",
"Files": "",
"Food": "Սննդամթերք",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -89,6 +92,7 @@
"MergeAutomateHelp": "",
"Merge_Keyword": "Միացնել բանալի բառը",
"MissingProperties": "",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Տեղափոխել",
"Move_Food": "Տեղափոխել սննդամթերքը",
@@ -136,6 +140,7 @@
"Selected": "",
"Servings": "",
"Settings": "Կարգավորումներ",
"SettingsOnlySuperuser": "",
"Share": "",
"Shopping_Category": "Գնումների կատեգորիա",
"Shopping_list": "Գնումների ցուցակ",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "",
"Added_on": "",
"Advanced": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -121,6 +123,7 @@
"FoodOnHand": "",
"Food_Alias": "",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -193,6 +196,7 @@
"Message": "",
"MissingProperties": "",
"Month": "",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Bergerak",
"MoveCategory": "",
@@ -289,6 +293,7 @@
"Selected": "Terpilih",
"Servings": "Porsi",
"Settings": "Pengaturan",
"SettingsOnlySuperuser": "",
"Share": "Bagikan",
"Shopping_Categories": "Kategori Belanja",
"Shopping_Category": "Kategori Belanja",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "",
"Added_on": "",
"Advanced": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -149,6 +151,7 @@
"Food_Alias": "",
"Food_Replace": "",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -226,6 +229,7 @@
"Message": "",
"MissingProperties": "",
"Month": "",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "",
"MoveCategory": "",
@@ -339,6 +343,7 @@
"Selected": "",
"Servings": "",
"Settings": "",
"SettingsOnlySuperuser": "",
"Share": "",
"ShoppingBackgroundSyncWarning": "",
"Shopping_Categories": "",

View File

@@ -1,6 +1,7 @@
{
"AI": "IA",
"AIImportSubtitle": "Utilizza IA per importare le immagini delle ricette.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -27,6 +28,7 @@
"Admin": "Amministratore",
"Advanced": "Avanzate",
"Advanced Search Settings": "Impostazioni avanzate di ricerca",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -210,6 +212,7 @@
"Food_Replace": "Sostituisci alimento",
"Foods": "Alimenti",
"Friday": "Venerdì",
"FromBalance": "",
"Fulltext": "Fulltext",
"FulltextHelp": "Campi per la ricerca full text. Nota: i metodi di ricerca 'web', 'phrase', e 'raw' funzionano solo con i campi fulltext.",
"Fuzzy": "Fuzzy",
@@ -314,6 +317,7 @@
"ModelSelectResultsHelp": "Cerca altri risultati",
"Monday": "Lunedì",
"Month": "Mese",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"More": "Altro",
"Move": "Sposta",
@@ -468,6 +472,7 @@
"Servings": "Porzioni",
"ServingsText": "Testo porzioni",
"Settings": "Impostazioni",
"SettingsOnlySuperuser": "",
"Share": "Condividi",
"ShopLater": "Compra dopo",
"ShopNow": "Compra subito",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "",
"Added_on": "",
"Advanced": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -135,6 +137,7 @@
"Food_Alias": "",
"Food_Replace": "",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -210,6 +213,7 @@
"Message": "",
"MissingProperties": "",
"Month": "",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "",
"MoveCategory": "",
@@ -317,6 +321,7 @@
"Selected": "",
"Servings": "",
"Settings": "",
"SettingsOnlySuperuser": "",
"Share": "",
"Shopping_Categories": "",
"Shopping_Category": "",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "",
"Added_on": "",
"Advanced": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "",
"Food_Replace": "",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "",
"MissingProperties": "",
"Month": "",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "",
"MoveCategory": "",
@@ -340,6 +344,7 @@
"Selected": "",
"Servings": "",
"Settings": "",
"SettingsOnlySuperuser": "",
"Share": "",
"ShoppingBackgroundSyncWarning": "",
"Shopping_Categories": "",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Lagt til av",
"Added_on": "Lagt til",
"Advanced": "Avansert",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -141,6 +143,7 @@
"FoodOnHand": "Du har {food} på lager.",
"Food_Alias": "Matrett Alias",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -217,6 +220,7 @@
"Message": "Melding",
"MissingProperties": "",
"Month": "Måned",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Flytt",
"MoveCategory": "Flytt til: ",
@@ -324,6 +328,7 @@
"Selected": "Valgte",
"Servings": "Porsjoner",
"Settings": "Innstillinger",
"SettingsOnlySuperuser": "",
"Share": "Del",
"ShoppingBackgroundSyncWarning": "Dårlig nettverkstilkobling, venter på synkronisering...",
"Shopping_Categories": "Butikk Kategorier",

View File

@@ -1,6 +1,7 @@
{
"AI": "AI",
"AIImportSubtitle": "Gebruik Al om afbeeldingen van recepten te importeren.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -28,6 +29,7 @@
"Admin": "Beheer",
"Advanced": "Geavanceerd",
"Advanced Search Settings": "Geavanceerde zoekinstellingen",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -211,6 +213,7 @@
"Food_Replace": "Voedingsmiddelen vervangen",
"Foods": "Voedingsmiddelen",
"Friday": "Vrijdag",
"FromBalance": "",
"Fulltext": "Volledige tekst",
"FulltextHelp": "Velden voor volledige tekstzoekopdrachten. Opmerking: de zoekmethoden web, zin en ruw werken alleen met volledige tekstvelden.",
"Fuzzy": "Fuzzy",
@@ -315,6 +318,7 @@
"ModelSelectResultsHelp": "Zoek naar meer resultaten",
"Monday": "Maandag",
"Month": "Maand",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"More": "Meer",
"Move": "Verplaats",
@@ -469,6 +473,7 @@
"Servings": "Porties",
"ServingsText": "Portie tekst",
"Settings": "Instellingen",
"SettingsOnlySuperuser": "",
"Share": "Deel",
"ShopLater": "Later boodschappen doen",
"ShopNow": "Nu boodschappen doen",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -25,6 +26,7 @@
"Admin": "Administator",
"Advanced": "Zaawansowany",
"Advanced Search Settings": "Ustawienia zaawansowanego wyszukiwania",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -176,6 +178,7 @@
"Food_Alias": "Alias żywności",
"Food_Replace": "Zastąp produkt",
"Foods": "Żywność",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -253,6 +256,7 @@
"Message": "Wiadomość",
"MissingProperties": "",
"Month": "Miesiąc",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Przenieś",
"MoveCategory": "Przenieś do: ",
@@ -366,6 +370,7 @@
"Selected": "Wybrane",
"Servings": "Porcje",
"Settings": "Ustawienia",
"SettingsOnlySuperuser": "",
"Share": "Udostępnij",
"ShoppingBackgroundSyncWarning": "Słaba sieć, oczekiwanie na synchronizację...",
"Shopping_Categories": "Kategorie zakupów",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API_Browser": "",
"API_Documentation": "",
"Add": "Adicionar",
@@ -14,6 +15,7 @@
"Added_by": "Adicionado por",
"Added_on": "Adicionado a",
"Advanced": "Avançado",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -121,6 +123,7 @@
"FoodOnHand": "Tem {food} disponível.",
"Food_Alias": "Alcunha da comida",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -182,6 +185,7 @@
"Merge_Keyword": "Unir palavra-chave",
"MissingProperties": "",
"Month": "Mês",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Mover",
"MoveCategory": "Mover para: ",
@@ -279,6 +283,7 @@
"Selected": "Selecionado",
"Servings": "Doses",
"Settings": "Definições",
"SettingsOnlySuperuser": "",
"Share": "Partilhar",
"Shopping_Categories": "Categorias de Compras",
"Shopping_Category": "Categoria de Compras",

View File

@@ -1,6 +1,7 @@
{
"AI": "IA",
"AIImportSubtitle": "Use IA para importar imagens das receitas.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -26,6 +27,7 @@
"Added_on": "Incluído Em",
"Admin": "Administrador",
"Advanced": "Avançado",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -209,6 +211,7 @@
"Food_Replace": "Substituir Alimento",
"Foods": "Alimentos",
"Friday": "Sexta-feira",
"FromBalance": "",
"Fulltext": "Texto completo",
"FulltextHelp": "Campos para pesquisa textual completa. Observação: os métodos de pesquisa 'web', 'phrase' e 'raw' só funcionam com campos de pesquisa textual completa.",
"Fuzzy": "Fuzzy",
@@ -307,6 +310,7 @@
"Message": "Mensagem",
"MissingProperties": "",
"Month": "Mês",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Mover",
"MoveCategory": "Mover Para: ",
@@ -414,6 +418,7 @@
"Selected": "Selecionado",
"Servings": "Porções",
"Settings": "Configurações",
"SettingsOnlySuperuser": "",
"Share": "Compartilhar",
"ShoppingBackgroundSyncWarning": "Rede ruim, aguardando sincronização...",
"Shopping_Categories": "Categorias de Mercado",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -17,6 +18,7 @@
"Added_on": "Adăugat la",
"Advanced": "Avansat",
"Advanced Search Settings": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -128,6 +130,7 @@
"FoodOnHand": "Aveți {food} la îndemână.",
"Food_Alias": "Pseudonim mâncare",
"Foods": "Alimente",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -202,6 +205,7 @@
"Message": "Mesaj",
"MissingProperties": "",
"Month": "Lună",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Mută",
"MoveCategory": "Mută la: ",
@@ -301,6 +305,7 @@
"Selected": "Selectat",
"Servings": "Porții",
"Settings": "Setări",
"SettingsOnlySuperuser": "",
"Share": "Împărtășire",
"Shopping_Categories": "Categorii de cumpărături",
"Shopping_Category": "Categorie de cumpărături",

View File

@@ -1,6 +1,7 @@
{
"AI": "AI",
"AIImportSubtitle": "Используй AI для импорта изображений рецептов.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -27,6 +28,7 @@
"Admin": "Админ",
"Advanced": "Расширенный",
"Advanced Search Settings": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -210,6 +212,7 @@
"Food_Replace": "Замена продукта",
"Foods": "Продукты",
"Friday": "Пятница",
"FromBalance": "",
"Fulltext": "Полнотекстовый",
"FulltextHelp": "Поля, используемые в полнотекстовом поиске. Важно: методы поиска web, phrase и raw применимы только к полнотекстовым полям.",
"Fuzzy": "Нечёткий",
@@ -313,6 +316,7 @@
"ModelSelectResultsHelp": "Показать больше результатов",
"Monday": "Понедельник",
"Month": "Месяц",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"More": "Ещё",
"Move": "Переместить",
@@ -466,6 +470,7 @@
"Servings": "Порции",
"ServingsText": "Описание порций",
"Settings": "Настройки",
"SettingsOnlySuperuser": "",
"Share": "Поделиться",
"ShopLater": "Купить позже",
"ShopNow": "Купить сейчас",

View File

@@ -1,6 +1,7 @@
{
"AI": "Umetna inteligenca",
"AIImportSubtitle": "Uporabite umetno inteligenco za uvoz slik receptov.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -27,6 +28,7 @@
"Admin": "Skrbnik",
"Advanced": "Napredno",
"Advanced Search Settings": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -210,6 +212,7 @@
"Food_Replace": "Zamenjava živila",
"Foods": "Živila",
"Friday": "Petek",
"FromBalance": "",
"Fulltext": "Celotno besedilo",
"FulltextHelp": "Polja za iskanje po celotnem besedilu. Opomba: metode iskanja »splet«, »fraza« in »surovo« delujejo samo s polji po celotnem besedilu.",
"Fuzzy": "Nejasno",
@@ -314,6 +317,7 @@
"ModelSelectResultsHelp": "Išči več rezultatov",
"Monday": "Ponedeljek",
"Month": "Mesec",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"More": "Več",
"Move": "Premakni",
@@ -468,6 +472,7 @@
"Servings": "Porcije",
"ServingsText": "Besedilo o porcijah",
"Settings": "Nastavitve",
"SettingsOnlySuperuser": "",
"Share": "Deli",
"ShopLater": "Nakupujte pozneje",
"ShopNow": "Nakupujte zdaj",

View File

@@ -1,5 +1,6 @@
{
"AIImportSubtitle": "Använd AI för att importera bilder av recept.",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -26,6 +27,7 @@
"Added_on": "Tillagd på",
"Admin": "Administratör",
"Advanced": "Avancerat",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -187,6 +189,7 @@
"Food_Alias": "Alias för livsmedel",
"Food_Replace": "Ersätt ingrediens",
"Foods": "Livsmedel",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -264,6 +267,7 @@
"Message": "Meddelande",
"MissingProperties": "",
"Month": "Månad",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Flytta",
"MoveCategory": "Flytta till: ",
@@ -377,6 +381,7 @@
"Selected": "Vald",
"Servings": "Portioner",
"Settings": "Inställningar",
"SettingsOnlySuperuser": "",
"Share": "Dela",
"ShoppingBackgroundSyncWarning": "Dålig uppkoppling, inväntar synkronisering...",
"Shopping_Categories": "Shopping kategorier",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "Ekleyen",
"Added_on": "Eklenme Zamanı",
"Advanced": "Gelişmiş",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "Yiyecek Takma Adı",
"Food_Replace": "Yiyecek Değiştir",
"Foods": "Yiyecekler",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "Mesaj",
"MissingProperties": "",
"Month": "Ay",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Taşı",
"MoveCategory": "Taşı: ",
@@ -340,6 +344,7 @@
"Selected": "Seçilen",
"Servings": "Servis Sayısı",
"Settings": "Ayarlar",
"SettingsOnlySuperuser": "",
"Share": "Paylaş",
"ShoppingBackgroundSyncWarning": "Kötü bağlantı, senkronizasyon bekleniyor...",
"Shopping_Categories": "Alışveriş Kategorileri",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API_Browser": "",
"API_Documentation": "",
"Add": "Додати",
@@ -14,6 +15,7 @@
"Added_by": "Додано",
"Added_on": "Додано На",
"Advanced": "",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -131,6 +133,7 @@
"FoodOnHand": "Ви маєте {food} на руках.",
"Food_Alias": "Найменування Їжі",
"Foods": "",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -199,6 +202,7 @@
"Merge_Keyword": "Об'єднати Ключове слово",
"MissingProperties": "",
"Month": "Місяць",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "Перемістити",
"MoveCategory": "Перемістити До: ",
@@ -302,6 +306,7 @@
"Selected": "Вибрано",
"Servings": "Порції",
"Settings": "Налаштування",
"SettingsOnlySuperuser": "",
"Share": "Поділитися",
"Shopping_Categories": "Категорії Покупок",
"Shopping_Category": "Категорія Покупок",

View File

@@ -1,4 +1,5 @@
{
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -16,6 +17,7 @@
"Added_by": "添加者",
"Added_on": "添加到",
"Advanced": "高级",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -150,6 +152,7 @@
"Food_Alias": "食物别名",
"Food_Replace": "食物替换",
"Foods": "食物",
"FromBalance": "",
"Fulltext": "",
"FulltextHelp": "",
"Fuzzy": "",
@@ -227,6 +230,7 @@
"Message": "信息",
"MissingProperties": "",
"Month": "月份",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"Move": "移动",
"MoveCategory": "移动到: ",
@@ -340,6 +344,7 @@
"Selected": "选定",
"Servings": "份量",
"Settings": "设置",
"SettingsOnlySuperuser": "",
"Share": "分享",
"ShoppingBackgroundSyncWarning": "网络状况不佳,正在等待进行同步……",
"Shopping_Categories": "购物类别",

View File

@@ -1,6 +1,7 @@
{
"AI": "人工智慧",
"AIImportSubtitle": "以人工智慧匯入食譜圖片。",
"AISettingsHostedHelp": "",
"API": "API",
"API_Browser": "",
"API_Documentation": "",
@@ -26,6 +27,7 @@
"Added_on": "添加於",
"Admin": "管理者",
"Advanced": "高級",
"AiCreditsBalance": "",
"AiLog": "",
"AiLogHelp": "",
"AiModelHelp": "",
@@ -209,6 +211,7 @@
"Food_Replace": "食物替換",
"Foods": "食物",
"Friday": "星期五",
"FromBalance": "",
"Fulltext": "全文",
"FulltextHelp": "全文搜索的字段。注意:'web'、'phrase' 和 'raw' 搜索方法僅對全文欄位有效。",
"Fuzzy": "模糊",
@@ -313,6 +316,7 @@
"ModelSelectResultsHelp": "搜尋更多結果",
"Monday": "星期一",
"Month": "月",
"MonthlyCredits": "",
"MonthlyCreditsUsed": "",
"More": "更多",
"Move": "移動",
@@ -467,6 +471,7 @@
"Servings": "份量",
"ServingsText": "份量文字",
"Settings": "設定",
"SettingsOnlySuperuser": "",
"Share": "分享",
"ShopLater": "稍後購物",
"ShopNow": "立即購物",

View File

@@ -1785,7 +1785,7 @@ export interface ApiSpaceListRequest {
export interface ApiSpacePartialUpdateRequest {
id: number;
patchedSpace?: Omit<PatchedSpace, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiCreditsMonthly'|'aiCreditsBalance'|'aiMonthlyCreditsUsed'>;
patchedSpace?: Omit<PatchedSpace, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiMonthlyCreditsUsed'>;
}
export interface ApiSpaceRetrieveRequest {

View File

@@ -31,6 +31,12 @@ import {
SpaceNavTextColorEnumFromJSONTyped,
SpaceNavTextColorEnumToJSON,
} from './SpaceNavTextColorEnum';
import type { AiProvider } from './AiProvider';
import {
AiProviderFromJSON,
AiProviderFromJSONTyped,
AiProviderToJSON,
} from './AiProvider';
import type { FoodInheritField } from './FoodInheritField';
import {
FoodInheritFieldFromJSON,
@@ -217,13 +223,13 @@ export interface PatchedSpace {
* @type {number}
* @memberof PatchedSpace
*/
readonly aiCreditsMonthly?: number;
aiCreditsMonthly?: number;
/**
*
* @type {number}
* @memberof PatchedSpace
*/
readonly aiCreditsBalance?: number;
aiCreditsBalance?: number;
/**
*
* @type {number}
@@ -236,6 +242,12 @@ export interface PatchedSpace {
* @memberof PatchedSpace
*/
aiEnabled?: boolean;
/**
*
* @type {AiProvider}
* @memberof PatchedSpace
*/
aiDefaultProvider?: AiProvider;
}
/**
@@ -286,10 +298,11 @@ export function PatchedSpaceFromJSONTyped(json: any, ignoreDiscriminator: boolea
'aiCreditsBalance': json['ai_credits_balance'] == null ? undefined : json['ai_credits_balance'],
'aiMonthlyCreditsUsed': json['ai_monthly_credits_used'] == null ? undefined : json['ai_monthly_credits_used'],
'aiEnabled': json['ai_enabled'] == null ? undefined : json['ai_enabled'],
'aiDefaultProvider': json['ai_default_provider'] == null ? undefined : AiProviderFromJSON(json['ai_default_provider']),
};
}
export function PatchedSpaceToJSON(value?: Omit<PatchedSpace, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiCreditsMonthly'|'aiCreditsBalance'|'aiMonthlyCreditsUsed'> | null): any {
export function PatchedSpaceToJSON(value?: Omit<PatchedSpace, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiMonthlyCreditsUsed'> | null): any {
if (value == null) {
return value;
}
@@ -312,7 +325,10 @@ export function PatchedSpaceToJSON(value?: Omit<PatchedSpace, 'createdBy'|'creat
'logo_color_192': UserFileViewToJSON(value['logoColor192']),
'logo_color_512': UserFileViewToJSON(value['logoColor512']),
'logo_color_svg': UserFileViewToJSON(value['logoColorSvg']),
'ai_credits_monthly': value['aiCreditsMonthly'],
'ai_credits_balance': value['aiCreditsBalance'],
'ai_enabled': value['aiEnabled'],
'ai_default_provider': AiProviderToJSON(value['aiDefaultProvider']),
};
}

View File

@@ -31,12 +31,6 @@ export interface ServerSettings {
* @memberof ServerSettings
*/
enablePdfExport: boolean;
/**
*
* @type {boolean}
* @memberof ServerSettings
*/
enableAiImport: boolean;
/**
*
* @type {boolean}
@@ -159,7 +153,6 @@ export interface ServerSettings {
export function instanceOfServerSettings(value: object): value is ServerSettings {
if (!('shoppingMinAutosyncInterval' in value) || value['shoppingMinAutosyncInterval'] === undefined) return false;
if (!('enablePdfExport' in value) || value['enablePdfExport'] === undefined) return false;
if (!('enableAiImport' in value) || value['enableAiImport'] === undefined) return false;
if (!('disableExternalConnectors' in value) || value['disableExternalConnectors'] === undefined) return false;
if (!('termsUrl' in value) || value['termsUrl'] === undefined) return false;
if (!('privacyUrl' in value) || value['privacyUrl'] === undefined) return false;
@@ -184,7 +177,6 @@ export function ServerSettingsFromJSONTyped(json: any, ignoreDiscriminator: bool
'shoppingMinAutosyncInterval': json['shopping_min_autosync_interval'],
'enablePdfExport': json['enable_pdf_export'],
'enableAiImport': json['enable_ai_import'],
'disableExternalConnectors': json['disable_external_connectors'],
'termsUrl': json['terms_url'],
'privacyUrl': json['privacy_url'],
@@ -215,7 +207,6 @@ export function ServerSettingsToJSON(value?: ServerSettings | null): any {
'shopping_min_autosync_interval': value['shoppingMinAutosyncInterval'],
'enable_pdf_export': value['enablePdfExport'],
'enable_ai_import': value['enableAiImport'],
'disable_external_connectors': value['disableExternalConnectors'],
'terms_url': value['termsUrl'],
'privacy_url': value['privacyUrl'],

View File

@@ -31,6 +31,12 @@ import {
SpaceNavTextColorEnumFromJSONTyped,
SpaceNavTextColorEnumToJSON,
} from './SpaceNavTextColorEnum';
import type { AiProvider } from './AiProvider';
import {
AiProviderFromJSON,
AiProviderFromJSONTyped,
AiProviderToJSON,
} from './AiProvider';
import type { FoodInheritField } from './FoodInheritField';
import {
FoodInheritFieldFromJSON,
@@ -217,13 +223,13 @@ export interface Space {
* @type {number}
* @memberof Space
*/
readonly aiCreditsMonthly: number;
aiCreditsMonthly?: number;
/**
*
* @type {number}
* @memberof Space
*/
readonly aiCreditsBalance: number;
aiCreditsBalance?: number;
/**
*
* @type {number}
@@ -236,6 +242,12 @@ export interface Space {
* @memberof Space
*/
aiEnabled?: boolean;
/**
*
* @type {AiProvider}
* @memberof Space
*/
aiDefaultProvider?: AiProvider;
}
/**
@@ -253,8 +265,6 @@ export function instanceOfSpace(value: object): value is Space {
if (!('userCount' in value) || value['userCount'] === undefined) return false;
if (!('recipeCount' in value) || value['recipeCount'] === undefined) return false;
if (!('fileSizeMb' in value) || value['fileSizeMb'] === undefined) return false;
if (!('aiCreditsMonthly' in value) || value['aiCreditsMonthly'] === undefined) return false;
if (!('aiCreditsBalance' in value) || value['aiCreditsBalance'] === undefined) return false;
if (!('aiMonthlyCreditsUsed' in value) || value['aiMonthlyCreditsUsed'] === undefined) return false;
return true;
}
@@ -296,14 +306,15 @@ export function SpaceFromJSONTyped(json: any, ignoreDiscriminator: boolean): Spa
'logoColor192': json['logo_color_192'] == null ? undefined : UserFileViewFromJSON(json['logo_color_192']),
'logoColor512': json['logo_color_512'] == null ? undefined : UserFileViewFromJSON(json['logo_color_512']),
'logoColorSvg': json['logo_color_svg'] == null ? undefined : UserFileViewFromJSON(json['logo_color_svg']),
'aiCreditsMonthly': json['ai_credits_monthly'],
'aiCreditsBalance': json['ai_credits_balance'],
'aiCreditsMonthly': json['ai_credits_monthly'] == null ? undefined : json['ai_credits_monthly'],
'aiCreditsBalance': json['ai_credits_balance'] == null ? undefined : json['ai_credits_balance'],
'aiMonthlyCreditsUsed': json['ai_monthly_credits_used'],
'aiEnabled': json['ai_enabled'] == null ? undefined : json['ai_enabled'],
'aiDefaultProvider': json['ai_default_provider'] == null ? undefined : AiProviderFromJSON(json['ai_default_provider']),
};
}
export function SpaceToJSON(value?: Omit<Space, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiCreditsMonthly'|'aiCreditsBalance'|'aiMonthlyCreditsUsed'> | null): any {
export function SpaceToJSON(value?: Omit<Space, 'createdBy'|'createdAt'|'maxRecipes'|'maxFileStorageMb'|'maxUsers'|'allowSharing'|'demo'|'userCount'|'recipeCount'|'fileSizeMb'|'aiMonthlyCreditsUsed'> | null): any {
if (value == null) {
return value;
}
@@ -326,7 +337,10 @@ export function SpaceToJSON(value?: Omit<Space, 'createdBy'|'createdAt'|'maxReci
'logo_color_192': UserFileViewToJSON(value['logoColor192']),
'logo_color_512': UserFileViewToJSON(value['logoColor512']),
'logo_color_svg': UserFileViewToJSON(value['logoColorSvg']),
'ai_credits_monthly': value['aiCreditsMonthly'],
'ai_credits_balance': value['aiCreditsBalance'],
'ai_enabled': value['aiEnabled'],
'ai_default_provider': AiProviderToJSON(value['aiDefaultProvider']),
};
}

View File

@@ -661,7 +661,7 @@ const appImportDuplicates = ref(false)
const appImportLog = ref<null | ImportLog>(null)
const image = ref<null | File>(null)
const aiMode = ref<'file' | 'text'>('file')
const selectedAiProvider = ref<undefined | AiProvider>(undefined)
const selectedAiProvider = ref<undefined | AiProvider>(useUserPreferenceStore().activeSpace.aiDefaultProvider)
const editAfterImport = ref(false)
const bookmarkletToken = ref("")

View File

@@ -834,6 +834,7 @@ export const TAiLog = {
{title: 'Type', key: '_function'},
{title: 'AiProvider', key: 'aiProvider.name',},
{title: 'Credits', key: 'creditCost',},
{title: 'FromBalance', key: 'creditsFromBalance',},
{title: 'CreatedAt', key: 'createdAt'},
{title: 'Actions', key: 'action', align: 'end'},
]