Skip to content

Commit

Permalink
Merge branch 'release/4.2.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
abidibo committed Dec 11, 2024
2 parents 1f1dbb6 + ea029ee commit d644332
Show file tree
Hide file tree
Showing 32 changed files with 1,200 additions and 105 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Ready to contribute? Here's how to set up `django-baton` for local development.
<script src="http://localhost:8080/dist/baton.min.js"></script>
```
Start the js app in watch mode::
Start both the django testapp and the js app (the last one in watch mode)::
```
$ cd baton/static/baton/app
Expand Down
95 changes: 68 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,23 @@ Login with user `demo` and password `demo`
---
**Last changes**

Baton 4.2.1 integrates the computer vision in the `BatonAiImageField`, fixes some minor styling issues and includes some PR.

Baton 4.2.0 introduces the use of computer vision to generate alt attributes for images.

Baton 4.0.* introduces a bunch of new AI functionalities!

- automatic translations with django-modeltranslation
- text summarization
- text corrections
- image vision
- image generation

It also introduces themes, and makes it easier to customize the application, there is no need to recompile the js app unless you wanto to change primary and secondary colors or you need heavy customization.

> New!
> Take a look at the new `django-baton-themes` repo: [django-baton-themes](https://github.com/otto-torino/django-baton-themes)
---

![Screenshot](docs/images/baton-ai.gif)
Expand Down Expand Up @@ -84,7 +90,7 @@ Everything is styled through CSS and when required, JS is used.
- Optional display of changelist filters in a modal
- Optional use of changelist filters as a form (combine some filters at once and perform the search action)
- Customization available by editing css vars and/or recompiling the js app provided
- IT translations provided
- IT ad FA translations provided

Baton is based on the following frontend technologies:

Expand Down Expand Up @@ -178,6 +184,7 @@ BATON = {
},
'BATON_CLIENT_ID': 'xxxxxxxxxxxxxxxxxxxx',
'BATON_CLIENT_SECRET': 'xxxxxxxxxxxxxxxxxx',
'IMAGE_PREVIEW_WIDTH': 200,
'AI': {
"MODELS": "myapp.foo.bar", # alternative to the below for lines, a function which returns the models dictionary
"IMAGES_MODEL": AIModels.BATON_DALL_E_3,
Expand Down Expand Up @@ -239,12 +246,13 @@ Default value is `True`.
- `FORCE_THEME`: You can force the light or dark theme, and the theme toggle disappears from the user area. Defaults to `None`
- `BATON_CLIENT_ID`: The client ID of your baton subscription (unleashes AI functionalities). Defaults to `None`
- `BATON_CLIENT_SECRET`: The client secret of your baton subscription (unleashes AI functionalities). Defaults to `None`
- `IMAGE_PREVIEW_WIDTH`: The default image width in pixels of the preview shown to set the subject location of the `BatonAiImageField`. Defaults to `200`

`AI`, `MENU` and `SEARCH_FIELD` configurations in detail:

### <a name="configuration-ai"></a>AI

Django Baton can provide you AI assistance in the admin interface: translations, summarizations, corrections and image generation. You can choose which model to use for each functionality, please note that different models have different prices, see [Baton site](https://www.baton.sqrt64.it).
Django Baton can provide you AI assistance in the admin interface: translations, summarizations, corrections, image generation and image vision. You can choose which model to use for each functionality, please note that different models have different prices, see [Baton site](https://www.baton.sqrt64.it).

Django Baton supports native fields (input, textarea) and ckeditor (django-ckeditor package) by default, but provides hooks you can use to add support to any other wysiwyg editor, read more in the [AI](#baton-ai) section.

Expand Down Expand Up @@ -521,29 +529,6 @@ In this modal you can edit the `words` and `useBulletedList` parameters and perf

All default fields and CKEDITOR fields are supported, see AI Hooks section below if you need to support other wysiwyg editors.

### <a name="ai-vision"></a>Image vision

In your `ModelAdmin` classes you can define which images can be described in order to generate an alt text, look at the following example:

``` python
class MyModelAdmin(admin.ModelAdmin):
# ...
baton_vision_fields = {
"image": [{
"target": "image_alt",
"chars": 80,
"language": "en",
}],
}
```

You have to specify the target field name. You can also optionally specify the follwing parameters:

- `chars`: max number of characters used in the alt description (approximate, it will not be followed strictly, default is 100)
- `language`: the language of the summary, default is your default language

With this configuration, one (the number of targets) button will appear near the `image` field, clicking it the calculated image alt text will be inserted in the `image_alt` field.

### <a name="ai-image-generation"></a>Image Generation

Baton provides a new model field and a new image widget which can be used to generate images from text. The image field can be used as a normal image field, but also a new button will appear near it.
Expand All @@ -565,6 +550,57 @@ There is also another way to add the AI image generation functionality to a norm
</script>
```

Baton also integrates the functionality of [django-subject-imagefield](https://github.com/otto-torino/django-subject-imagefield/), so you can specify a `subject_location` field that will store the percentage coordinated of the subject of the image, and in editing mode a point will appear on the image preview in order to let you change this position:

``` python
from baton.fields import BatonAiImageField

class MyModel(models.Model):
image = BatonAiImageField(verbose_name=_("immagine"), upload_to="news/", subject_location_field='subject_location')
subject_location = models.CharField(max_length=7, default="50,50")
```

You can configure the width of the preview image through the settings `IMAGE_PREVIEW_WIDTH` which by default equals `200`.

Check the `django-subject-imagefield` documentation for more details and properties.

### <a name="ai-vision"></a>Image vision
There are two ways to activate image vision functionality in Baton, both allow to generate an alt text for the image through the AI.

The first way is to just use the `BatonAiImageField` and define the `alt_field` attribute (an optionally `alt_chars`, `alt_language`)

``` python
from baton.fields import BatonAiImageField

class MyModel(models.Model):
image = BatonAiImageField(verbose_name=_("immagine"), upload_to="news/", alt_field="image_alt", alt_chars=20, alt_language="en")
image_alt = models.CharField(max_length=40, blank=True)
```

This method will work only when images are inside inlines.

The second method consists in defining in the `ModelAdmin` classes which images can be described in order to generate an alt text, look at the following example:

``` python
class MyModelAdmin(admin.ModelAdmin):
# ...
baton_vision_fields = {
"#id_image": [{ # key must be a selector (useful for inlines)
"target": "image_alt", # target should be the name of a field of the same model
"chars": 80,
"language": "en",
}],
}
```

You have to specify the target field name. You can also optionally specify the follwing parameters:

- `chars`: max number of characters used in the alt description (approximate, it will not be followed strictly, default is 100)
- `language`: the language of the summary, default is your default language

With this configuration, one (the number of targets) button will appear near the `image` field, clicking it the calculated image alt text will be inserted in the `image_alt` field.
Even this methos should work for inline images.

### <a name="ai-stats"></a>Stats widget

Baton provides a new widget which can be used to display stats about AI usage. Just include it in your admin index template:
Expand Down Expand Up @@ -1122,6 +1158,9 @@ You can override all the css variables, just create a `baton/css/root.css` file

You can also create themes directly from the admin site, just surf to `/admin/baton/batontheme/`. There can be only one active theme, if present, the saved content is used instead of the `root.css` file. So just copy the content of that file in the field and change the colors you want. Be aware that the theme content is considered safe and injected into the page as is, so be carefull.

> New!
> You may find ready to use themes and ideas [here](https://github.com/otto-torino/django-baton-themes).
If you need heavy customization or you need to customize the `primary` and `secondary` colors, you can edit and recompile the JS app which resides in `baton/static/baton/app`.

![Customization](docs/images/customization.png)
Expand All @@ -1141,7 +1180,7 @@ So:
If you want to test your live changes, just start the webpack dev server:

$ cd django-baton/baton/static/baton/app/
$ npm run dev
$ npm run dev:baton

And inside the `base_site.html` template, make these changes:

Expand Down Expand Up @@ -1169,7 +1208,7 @@ Switch the baton js path in `base_site.html`
<!-- <script src="{% static 'baton/app/dist/baton.min.js' %}"></script> comment the compiled src and uncomment the webpack served src -->
<script src="http://localhost:8080/static/baton/app/dist/baton.min.js"></script>

Start the js app in watch mode
Start both the django testapp and the js app (the last one in watch mode):

$ cd baton/static/baton/app
$ npm install
Expand Down Expand Up @@ -1197,6 +1236,8 @@ Read [CONTRIBUTING.md](CONTRIBUTING.md)

## <a name="screenshots"></a>Screenshots

Actually the following screenshots are not always up to date, better to visit the [demo site](https://django-baton.sqrt64.it/)

![Screenshot](docs/screenshots/mobile_mix.jpg)

![Screenshot](docs/screenshots/mobile_mix2.png)
Expand Down
1 change: 1 addition & 0 deletions baton/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'SUPPORT_HREF': 'https://github.com/otto-torino/django-baton/issues',
'COPYRIGHT': 'copyright © 2022 <a href="https://www.otto.to.it">Otto srl</a>', # noqa
'POWERED_BY': '<a href="https://www.otto.to.it">Otto srl</a>',
'IMAGE_PREVIEW_WIDTH': 200,
'CONFIRM_UNSAVED_CHANGES': True,
'SHOW_MULTIPART_UPLOADING': True,
'ENABLE_IMAGES_PREVIEW': True,
Expand Down
79 changes: 78 additions & 1 deletion baton/fields.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,88 @@
from django.db import models

from django.db.models.fields.files import ImageFieldFile
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.utils.translation import get_language

from .forms import BatonAiImageFormField
from .widgets import BatonAiImageInput

class BatonAiImageFieldFile(ImageFieldFile):
@property
def subject_perc_position(self):
if self.field.subject_location_field and getattr(
self.instance, self.field.subject_location_field):
(cX, cY) = getattr(self.instance,
self.field.subject_location_field).split(',')

return {
'x': int(cX),
'y': int(cY)
}
return None

@property
def subject_position(self):
perc = self.subject_perc_position
if perc:
return {
'x': (self.width or 0) * perc.get('x', 0) // 100,
'y': (self.height or 0) * perc.get('y', 0) // 100
}
return None

@property
def sorl(self):
""" shortcut property to use with sorl-thumbnmail crop featur e"""
position = self.subject_perc_position
if position:
x = position.get('x')
y = position.get('y')
# also need -0
return '%s%% %s%%' % (x, y)
return '50% 50%'

class BatonAiImageField(models.ImageField):
attr_class = BatonAiImageFieldFile

def __init__(self,
verbose_name=None,
name=None,
width_field=None,
height_field=None,
subject_location_field=None,
alt_field=None,
alt_chars=20,
alt_language=get_language(),
**kwargs):
self.width_field, self.height_field = width_field, height_field
self.subject_location_field = subject_location_field
self.alt_field = alt_field
self.alt_chars = alt_chars
self.alt_language = alt_language
super().__init__(verbose_name, name, **kwargs)

def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.alt_field:
kwargs['alt_field'] = self.alt_field
kwargs['alt_chars'] = self.alt_chars
kwargs['alt_language'] = self.alt_language
if self.subject_location_field:
kwargs['subject_location_field'] = self.subject_location_field
return name, path, args, kwargs

def formfield(self, **kwargs):
d = kwargs
# override widget
d.update({
'widget': BatonAiImageInput,
'form_class': BatonAiImageFormField,
'alt_field': self.alt_field,
'alt_chars': self.alt_chars,
'alt_language': self.alt_language,
'subject_location_field': self.subject_location_field,
'help_text':_('Drag the circle or click on the image to set the image subject') if self.subject_location_field else d.get('help_text', ''),
})
return super(BatonAiImageField, self).formfield(**d)
return super().formfield(**d)
23 changes: 23 additions & 0 deletions baton/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.forms.fields import ImageField
from .widgets import BatonAiImageInput
from .config import get_config


class BatonAiImageFormField(ImageField):
widget = BatonAiImageInput

def __init__(self, subject_location_field=None, alt_field=None, alt_chars=20, alt_language='en', *args, **kwargs):
self.subject_location_field = subject_location_field
self.alt_field = alt_field
self.alt_chars = alt_chars
self.alt_language = alt_language
return super().__init__(*args, **kwargs)

def widget_attrs(self, widget):
attrs = super().widget_attrs(widget)
attrs['subject_location_field'] = self.subject_location_field
attrs['alt_field'] = self.alt_field
attrs['alt_chars'] = self.alt_chars
attrs['alt_language'] = self.alt_language
attrs['preview_width'] = get_config('IMAGE_PREVIEW_WIDTH')
return attrs
Binary file added baton/locale/fa/LC_MESSAGES/django.mo
Binary file not shown.
Loading

0 comments on commit d644332

Please sign in to comment.