├── openai_chat ├── i18n │ └── fr.po ├── security │ ├── security.xml │ └── ir.model.access.csv ├── static │ ├── img │ │ ├── chat.png │ │ ├── logo.png │ │ ├── discuss.png │ │ ├── open_chat.png │ │ ├── clear_chat.png │ │ ├── longer_answer.png │ │ ├── truncated_answer.png │ │ └── openai_logo.svg │ ├── description │ │ ├── icon.png │ │ ├── logo.png │ │ └── index.html │ └── src │ │ └── models │ │ └── messaging_initializer.js ├── data │ ├── openai-odoo-avatar.png │ ├── openai_completion_data.xml │ └── openai_chat_data.xml ├── __init__.py ├── models │ ├── __init__.py │ ├── mail_thread.py │ ├── res_partner.py │ ├── res_users.py │ ├── mail_channel.py │ └── mail_ai_bot.py ├── __manifest__.py └── README.md ├── openai_connector ├── i18n │ └── fr.po ├── security │ ├── security.xml │ └── ir.model.access.csv ├── static │ ├── img │ │ ├── prompt.png │ │ ├── tests.png │ │ ├── settings.png │ │ ├── openai_params.png │ │ ├── completion_params.png │ │ └── openai_logo.svg │ ├── description │ │ ├── icon.png │ │ ├── logo.png │ │ └── index.html │ └── src │ │ └── scss │ │ └── style.scss ├── __init__.py ├── models │ ├── __init__.py │ ├── res_config_settings.py │ ├── openai_tool_property.py │ ├── openai_image_result.py │ ├── openai_result_mixin.py │ ├── openai_question_answer.py │ ├── openai_mixin.py │ ├── openai_fine_tuning.py │ ├── openai_tool.py │ ├── openai_completion_result.py │ ├── openai_completion.py │ └── openai_image.py ├── views │ ├── res_config_settings_views.xml │ ├── openai_question_answer_views.xml │ ├── openai_image_result_views.xml │ ├── openai_completion_result_views.xml │ ├── openai_fine_tuning_views.xml │ ├── openai_completion_views.xml │ └── openai_image_views.xml ├── __manifest__.py └── README.md ├── openai_product_tags ├── i18n │ └── fr.po ├── security │ ├── security.xml │ └── ir.model.access.csv ├── static │ ├── description │ │ ├── icon.png │ │ ├── logo.png │ │ └── index.html │ └── img │ │ ├── product_tags.png │ │ ├── create_tags_action.png │ │ └── openai_logo.svg ├── __init__.py ├── models │ ├── __init__.py │ └── product.py ├── data │ ├── prompt_templates.xml │ └── openai_completion_data.xml ├── __manifest__.py ├── README.md └── views │ └── openai_product_result_views.xml ├── openai_edit_product_image ├── i18n │ └── fr.po ├── security │ ├── security.xml │ └── ir.model.access.csv ├── static │ ├── img │ │ ├── product.png │ │ ├── apply_image.png │ │ ├── create_image.png │ │ ├── config_product.png │ │ ├── product_results.png │ │ ├── create_image_prompt.png │ │ └── openai_logo.svg │ └── description │ │ ├── icon.png │ │ ├── logo.png │ │ └── index.html ├── __init__.py ├── models │ ├── __init__.py │ └── product.py ├── data │ ├── prompt_templates.xml │ └── openai_edit_data.xml ├── views │ ├── product_views.xml │ └── openai_product_result_views.xml ├── __manifest__.py └── README.md ├── openai_product_description ├── i18n │ └── fr.po ├── security │ ├── security.xml │ └── ir.model.access.csv ├── static │ ├── img │ │ ├── results.png │ │ ├── create_description_action.png │ │ └── openai_logo.svg │ └── description │ │ ├── icon.png │ │ ├── logo.png │ │ └── index.html ├── __init__.py ├── models │ ├── __init__.py │ └── product.py ├── data │ ├── prompt_templates.xml │ └── openai_completion_data.xml ├── __manifest__.py ├── README.md └── views │ └── openai_product_result_views.xml ├── requirements.txt ├── .gitignore ├── README.md └── LICENSE /openai_chat/i18n/fr.po: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_connector/i18n/fr.po: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_product_tags/i18n/fr.po: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_edit_product_image/i18n/fr.po: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_product_description/i18n/fr.po: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | openai>=1.7.2 2 | -------------------------------------------------------------------------------- /openai_chat/security/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /openai_chat/static/img/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/img/chat.png -------------------------------------------------------------------------------- /openai_chat/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/img/logo.png -------------------------------------------------------------------------------- /openai_connector/security/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /openai_product_tags/security/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /openai_chat/static/img/discuss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/img/discuss.png -------------------------------------------------------------------------------- /openai_edit_product_image/security/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /openai_chat/static/img/open_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/img/open_chat.png -------------------------------------------------------------------------------- /openai_product_description/security/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /openai_chat/data/openai-odoo-avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/data/openai-odoo-avatar.png -------------------------------------------------------------------------------- /openai_chat/static/description/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/description/icon.png -------------------------------------------------------------------------------- /openai_chat/static/description/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/description/logo.png -------------------------------------------------------------------------------- /openai_chat/static/img/clear_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/img/clear_chat.png -------------------------------------------------------------------------------- /openai_connector/static/img/prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_connector/static/img/prompt.png -------------------------------------------------------------------------------- /openai_connector/static/img/tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_connector/static/img/tests.png -------------------------------------------------------------------------------- /openai_chat/security/ir.model.access.csv: -------------------------------------------------------------------------------- 1 | "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" 2 | -------------------------------------------------------------------------------- /openai_chat/static/img/longer_answer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/img/longer_answer.png -------------------------------------------------------------------------------- /openai_connector/static/img/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_connector/static/img/settings.png -------------------------------------------------------------------------------- /openai_chat/static/img/truncated_answer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_chat/static/img/truncated_answer.png -------------------------------------------------------------------------------- /openai_connector/static/description/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_connector/static/description/icon.png -------------------------------------------------------------------------------- /openai_connector/static/description/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_connector/static/description/logo.png -------------------------------------------------------------------------------- /openai_connector/static/img/openai_params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_connector/static/img/openai_params.png -------------------------------------------------------------------------------- /openai_product_tags/security/ir.model.access.csv: -------------------------------------------------------------------------------- 1 | "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" 2 | -------------------------------------------------------------------------------- /openai_connector/static/img/completion_params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_connector/static/img/completion_params.png -------------------------------------------------------------------------------- /openai_edit_product_image/security/ir.model.access.csv: -------------------------------------------------------------------------------- 1 | "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" 2 | -------------------------------------------------------------------------------- /openai_edit_product_image/static/img/product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/img/product.png -------------------------------------------------------------------------------- /openai_product_description/security/ir.model.access.csv: -------------------------------------------------------------------------------- 1 | "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" 2 | -------------------------------------------------------------------------------- /openai_product_description/static/img/results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_description/static/img/results.png -------------------------------------------------------------------------------- /openai_product_tags/static/description/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_tags/static/description/icon.png -------------------------------------------------------------------------------- /openai_product_tags/static/description/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_tags/static/description/logo.png -------------------------------------------------------------------------------- /openai_product_tags/static/img/product_tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_tags/static/img/product_tags.png -------------------------------------------------------------------------------- /openai_edit_product_image/static/description/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/description/icon.png -------------------------------------------------------------------------------- /openai_edit_product_image/static/description/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/description/logo.png -------------------------------------------------------------------------------- /openai_edit_product_image/static/img/apply_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/img/apply_image.png -------------------------------------------------------------------------------- /openai_edit_product_image/static/img/create_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/img/create_image.png -------------------------------------------------------------------------------- /openai_product_description/static/description/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_description/static/description/icon.png -------------------------------------------------------------------------------- /openai_product_description/static/description/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_description/static/description/logo.png -------------------------------------------------------------------------------- /openai_product_tags/static/img/create_tags_action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_tags/static/img/create_tags_action.png -------------------------------------------------------------------------------- /openai_edit_product_image/static/img/config_product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/img/config_product.png -------------------------------------------------------------------------------- /openai_edit_product_image/static/img/product_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/img/product_results.png -------------------------------------------------------------------------------- /openai_edit_product_image/static/img/create_image_prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_edit_product_image/static/img/create_image_prompt.png -------------------------------------------------------------------------------- /openai_product_description/static/img/create_description_action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrrkel/odoo-openai/HEAD/openai_product_description/static/img/create_description_action.png -------------------------------------------------------------------------------- /openai_chat/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import models 6 | -------------------------------------------------------------------------------- /openai_connector/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2022 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from . import models 6 | -------------------------------------------------------------------------------- /openai_product_tags/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import models 6 | -------------------------------------------------------------------------------- /openai_edit_product_image/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import models 6 | -------------------------------------------------------------------------------- /openai_product_description/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import models 6 | -------------------------------------------------------------------------------- /openai_product_tags/models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import product 6 | -------------------------------------------------------------------------------- /openai_edit_product_image/models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import product 6 | -------------------------------------------------------------------------------- /openai_product_description/models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import product 6 | -------------------------------------------------------------------------------- /openai_chat/models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | 5 | from . import res_users 6 | from . import res_partner 7 | from . import mail_thread 8 | from . import mail_ai_bot 9 | from . import mail_channel 10 | -------------------------------------------------------------------------------- /openai_edit_product_image/data/prompt_templates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /openai_connector/static/src/scss/style.scss: -------------------------------------------------------------------------------- 1 | .btn-center { 2 | width: 30%; 3 | display: block; 4 | margin-left: auto; 5 | margin-right: auto; 6 | } 7 | 8 | .alert-info-center { 9 | width: max-content; 10 | margin-left: auto; 11 | margin-right: auto; 12 | } 13 | .image-transparent-background img { 14 | background: 15 | repeating-conic-gradient(#b8b8b8 0% 25%, transparent 0% 50%) 16 | 50% / 15px 15px 17 | } -------------------------------------------------------------------------------- /openai_product_tags/data/prompt_templates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /openai_chat/models/mail_thread.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models 6 | 7 | 8 | class MailThread(models.AbstractModel): 9 | _inherit = 'mail.thread' 10 | 11 | def _message_post_after_hook(self, message, msg_vals): 12 | res = super(MailThread, self)._message_post_after_hook(message, msg_vals) 13 | self.env['mail.ai.bot']._answer_to_message(self, msg_vals) 14 | return res 15 | -------------------------------------------------------------------------------- /openai_product_description/data/prompt_templates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /openai_connector/models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2022 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from . import res_config_settings 6 | from . import openai_mixin 7 | from . import openai_result_mixin 8 | from . import openai_completion 9 | from . import openai_completion_result 10 | from . import openai_image 11 | from . import openai_image_result 12 | from . import openai_question_answer 13 | from . import openai_fine_tuning 14 | from . import openai_tool 15 | from . import openai_tool_property 16 | -------------------------------------------------------------------------------- /openai_connector/models/res_config_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2022 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import api, fields, models, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class ResConfigSettings(models.TransientModel): 12 | _inherit = 'res.config.settings' 13 | 14 | openai_api_key = fields.Char(string="OpenAI API Key", config_parameter='openai_api_key') 15 | openai_organization_id = fields.Char(string="OpenAI Organisation ID", config_parameter='openai_organization_id') 16 | -------------------------------------------------------------------------------- /openai_chat/models/res_partner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class ResPartner(models.Model): 12 | _inherit = 'res.partner' 13 | 14 | def _compute_im_status(self): 15 | super(ResPartner, self)._compute_im_status() 16 | ai_bot_user_id = self.env['ir.model.data']._xmlid_to_res_id('openai_chat.partner_ai') 17 | for user in self.filtered(lambda u: u.id == ai_bot_user_id): 18 | user.im_status = 'online' 19 | -------------------------------------------------------------------------------- /openai_chat/static/src/models/messaging_initializer.js: -------------------------------------------------------------------------------- 1 | /** @odoo-module **/ 2 | 3 | import { registerPatch } from '@mail/model/model_core'; 4 | import { insert } from '@mail/model/model_field_command'; 5 | 6 | registerPatch({ 7 | name: 'MessagingInitializer', 8 | recordMethods: { 9 | /** 10 | * @override 11 | */ 12 | _initCommands() { 13 | this._super(); 14 | this.messaging.update({ 15 | commands: insert({ 16 | help: this.env._t("Clear chat with AI Bot"), 17 | methodName: 'execute_command_clear_ai_chat', 18 | name: "clear", 19 | }), 20 | }); 21 | }, 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /openai_chat/data/openai_completion_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AI Chat 6 | 7 | [] 8 | gpt-3.5-turbo 9 | 3200 10 | 1 11 | 1 12 | 0.5 13 | 0 14 | 1 15 | The following is a conversation with an AI assistant. 16 | 17 | 18 | -------------------------------------------------------------------------------- /openai_chat/models/res_users.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class ResUsers(models.Model): 12 | _inherit = 'res.users' 13 | 14 | def _init_messaging(self): 15 | if self._is_internal(): 16 | self._init_ai_bot() 17 | return super()._init_messaging() 18 | 19 | def _init_ai_bot(self): 20 | self.ensure_one() 21 | ai_bot_partner_id = self.env['ir.model.data']._xmlid_to_res_id('openai_chat.partner_ai') 22 | channel_info = self.env['mail.channel'].channel_get([ai_bot_partner_id, self.partner_id.id]) 23 | channel = self.env['mail.channel'].browse(channel_info['id']) 24 | return channel 25 | -------------------------------------------------------------------------------- /openai_connector/static/description/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

OpenAI Connector

4 |

openai_connector

5 |
6 |

7 | This module adds a connector for OpenAI API 8 |

9 |
10 |
11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 | Contact me 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /openai_product_description/models/product.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class ProductTemplate(models.Model): 12 | _inherit = 'product.template' 13 | 14 | def action_openai_create_product_sales_description(self): 15 | completion_id = self.env.ref('openai_product_description.completion_product_description') 16 | for rec in self: 17 | completion_id.apply(rec.id) 18 | action_name = 'openai_product_description.openai_product_description_result_action' 19 | action = self.env['ir.actions.act_window']._for_xml_id(action_name) 20 | action['domain'] = [('res_id', 'in', self.ids)] 21 | return action 22 | -------------------------------------------------------------------------------- /openai_chat/static/description/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

OpenAI Chat

4 |

openai_chat

5 |
6 |

7 | This module adds an AI Bot user to chat with like in ChatGPT. 8 |

9 |
10 |
11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 | Contact me 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /openai_product_tags/models/product.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class ProductTemplate(models.Model): 12 | _inherit = 'product.template' 13 | 14 | def action_openai_create_product_tags(self): 15 | completion_id = self.env.ref('openai_product_tags.completion_product_tags') 16 | for rec in self: 17 | completion_id.apply(rec.id) 18 | if not completion_id.save_on_target_field: 19 | action_name = 'openai_product_tags.openai_product_tags_result_action' 20 | action = self.env['ir.actions.act_window']._for_xml_id(action_name) 21 | action['domain'] = [('res_id', 'in', self.ids)] 22 | return action 23 | -------------------------------------------------------------------------------- /openai_chat/models/mail_channel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, _ 6 | 7 | 8 | class MailChannel(models.Model): 9 | _inherit = 'mail.channel' 10 | 11 | def execute_command_clear_ai_chat(self, **kwargs): 12 | partner = self.env.user.partner_id 13 | key = kwargs['body'] 14 | if key.lower().strip() == '/clear': 15 | ai_bot_id = self.env['ir.model.data']._xmlid_to_res_id('openai_chat.partner_ai') 16 | ai_chat_member_ids = {ai_bot_id, partner.id} 17 | if ai_chat_member_ids == set(self.channel_member_ids.mapped('partner_id.id')): 18 | self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.message/delete', 19 | {'message_ids': self.message_ids.ids}) 20 | self.message_ids.unlink() 21 | -------------------------------------------------------------------------------- /openai_product_tags/static/description/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

OpenAI Product Tags

4 |

openai_product_tags

5 |
6 |

7 | This module allows to generate tags for a product with OpenAI's GTP3 model from product's description. 8 |

9 |
10 |
11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 | Contact me 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /openai_connector/models/openai_tool_property.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 - Michel Perrocheau (https://github.com/myrrkel). 2 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 3 | 4 | import json 5 | from tempfile import NamedTemporaryFile 6 | from odoo import models, fields, api, _ 7 | from odoo.tools.safe_eval import safe_eval 8 | from odoo.addons.base.models.ir_model import SAFE_EVAL_BASE 9 | 10 | import logging 11 | 12 | _logger = logging.getLogger(__name__) 13 | 14 | 15 | class OpenAiToolProperty(models.Model): 16 | _name = 'openai.tool.property' 17 | _description = 'OpenAI Tool Property' 18 | 19 | def _get_tool_property_type_list(self): 20 | return [('string', _('String')), 21 | ('integer', _('Integer'))] 22 | 23 | name = fields.Char() 24 | tool_id = fields.Many2one('openai.tool', invisible=True) 25 | type = fields.Selection(selection=_get_tool_property_type_list) 26 | description = fields.Text() 27 | required = fields.Boolean() 28 | -------------------------------------------------------------------------------- /openai_edit_product_image/static/description/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

OpenAI Edit Product Image

4 |

openai_edit_product_image

5 |
6 |

7 | This module allows to generate tags for a product with OpenAI's GTP3 model from product's description. 8 |

9 |
10 |
11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 | Contact me 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /openai_product_description/data/openai_completion_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Product Sales Description 6 | 7 | 8 | [] 9 | gpt-3.5-turbo 10 | 300 11 | 4 12 | 0.5 13 | 0.5 14 | 0 15 | 1 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /openai_product_description/static/description/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

OpenAI Product Description

4 |

openai_product_description

5 |
6 |

7 | This module allows to generate a product sales description with OpenAI's GTP3 model from product tags, attributes or any other product information. 8 |

9 |
10 |
11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 | Contact me 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /openai_chat/data/openai_chat_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AI Bot 6 | 7 | ai@example.com 8 | 9 | 10 | 11 | 12 | 13 | ai 14 | 15 | 16 | 17 | --
18 | AI]]>
19 | 20 |
21 |
22 |
-------------------------------------------------------------------------------- /openai_edit_product_image/views/product_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | product.template.form.view.inherit.openai.edit.image 6 | product.template 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /openai_product_tags/__manifest__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | { 5 | 'name': 'OpenAI Product Tags', 6 | 'version': '16.1.0.0', 7 | 'author': 'Michel Perrocheau', 8 | 'website': 'https://github.com/myrrkel', 9 | 'summary': "Generate product tags with OpenAI", 10 | 'sequence': 0, 11 | 'certificate': '', 12 | 'license': 'AGPL-3', 13 | 'depends': [ 14 | 'openai_connector', 15 | 'product', 16 | 'sale', 17 | ], 18 | 'category': 'Community', 19 | 'complexity': 'easy', 20 | 'qweb': [ 21 | ], 22 | 'demo': [ 23 | ], 24 | 'images': [ 25 | ], 26 | 'data': [ 27 | 'security/ir.model.access.csv', 28 | 'security/security.xml', 29 | 'data/prompt_templates.xml', 30 | 'data/openai_completion_data.xml', 31 | 'views/openai_product_result_views.xml', 32 | ], 33 | 'auto_install': False, 34 | 'installable': True, 35 | 'application': False, 36 | } 37 | -------------------------------------------------------------------------------- /openai_product_tags/data/openai_completion_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Product Tags 6 | 7 | 8 | list_to_many2many 9 | True 10 | [] 11 | gpt-3.5-turbo 12 | 500 13 | 1 14 | 0.5 15 | 0.5 16 | 0 17 | 1 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /openai_product_description/__manifest__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | { 5 | 'name': 'OpenAI Product Description', 6 | 'version': '16.0.0.0', 7 | 'author': 'Michel Perrocheau', 8 | 'website': 'https://github.com/myrrkel', 9 | 'summary': "Generate a product sales description with OpenAI", 10 | 'sequence': 0, 11 | 'certificate': '', 12 | 'license': 'AGPL-3', 13 | 'depends': [ 14 | 'openai_connector', 15 | 'product', 16 | 'sale', 17 | ], 18 | 'category': 'Community', 19 | 'complexity': 'easy', 20 | 'qweb': [ 21 | ], 22 | 'demo': [ 23 | ], 24 | 'images': [ 25 | ], 26 | 'data': [ 27 | 'security/ir.model.access.csv', 28 | 'security/security.xml', 29 | 'data/prompt_templates.xml', 30 | 'data/openai_completion_data.xml', 31 | 'views/openai_product_result_views.xml', 32 | ], 33 | 'auto_install': False, 34 | 'installable': True, 35 | 'application': False, 36 | } 37 | -------------------------------------------------------------------------------- /openai_edit_product_image/__manifest__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | { 5 | 'name': 'OpenAI Edit Product Image', 6 | 'version': '16.1.0.0', 7 | 'author': 'Michel Perrocheau', 8 | 'website': 'https://github.com/myrrkel', 9 | 'summary': "Generate a new product image from a cropped product image with DALL-E", 10 | 'sequence': 0, 11 | 'certificate': '', 12 | 'license': 'AGPL-3', 13 | 'depends': [ 14 | 'openai_connector', 15 | 'product', 16 | 'sale', 17 | ], 18 | 'category': 'Community', 19 | 'complexity': 'easy', 20 | 'qweb': [ 21 | ], 22 | 'demo': [ 23 | ], 24 | 'images': [ 25 | ], 26 | 'data': [ 27 | 'security/ir.model.access.csv', 28 | 'security/security.xml', 29 | 'data/prompt_templates.xml', 30 | 'data/openai_edit_data.xml', 31 | 'views/openai_product_result_views.xml', 32 | 'views/product_views.xml', 33 | ], 34 | 'auto_install': False, 35 | 'installable': True, 36 | 'application': False, 37 | } 38 | -------------------------------------------------------------------------------- /openai_chat/__manifest__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/algpl.html). 4 | { 5 | 'name': 'OpenAI Chat', 6 | 'version': '16.1.0.0', 7 | 'author': 'Michel Perrocheau', 8 | 'website': 'https://github.com/myrrkel', 9 | 'summary': "Add a AI Bot user to chat with like in ChatGPT", 10 | 'sequence': 0, 11 | 'certificate': '', 12 | 'license': 'AGPL-3', 13 | 'depends': [ 14 | 'openai_connector', 15 | 'mail', 16 | 'bus', 17 | ], 18 | 'category': 'Community', 19 | 'complexity': 'easy', 20 | 'qweb': [ 21 | ], 22 | 'demo': [ 23 | ], 24 | 'images': [ 25 | ], 26 | 'data': [ 27 | 'security/ir.model.access.csv', 28 | 'security/security.xml', 29 | 'data/openai_chat_data.xml', 30 | 'data/openai_completion_data.xml', 31 | ], 32 | 'assets': { 33 | 'mail.assets_messaging': [ 34 | 'openai_chat/static/src/models/messaging_initializer.js', 35 | ], 36 | }, 37 | 'auto_install': False, 38 | 'installable': True, 39 | 'application': False, 40 | } 41 | -------------------------------------------------------------------------------- /openai_edit_product_image/data/openai_edit_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Edit Product Image 6 | 7 | 8 | 10 | 12 | 14 | False 15 | [] 16 | create_edit 17 | 4 18 | 1024x1024 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /openai_product_tags/README.md: -------------------------------------------------------------------------------- 1 | [![License: AGPL-3](https://img.shields.io/badge/licence-AGPL--3-blue.png)](http://www.gnu.org/licenses/agpl-3.0-standalone.html) 2 | 3 | OpenAI Product Tags 4 | =================== 5 | 6 | [OpenAI Logo](https://openai.com/) 7 | 8 | This module allows to generate tags from product's description with OpenAI's GTP3 model. 9 | 10 | ## Usage 11 | 12 | On a product, select **Create Product Tags** action : 13 | 14 | 15 | 16 | ![image](./static/img/create_tags_action.png) 17 | 18 | Tags are generated from **Internal Notes**: 19 | 20 | ![image](./static/img/product_tags.png) 21 | 22 | This action is also available from the product list view. 23 | 24 | ## Requirements 25 | 26 | [openai_connector](../openai_connector/README.md) is required. 27 | 28 | This module requires the Python client library for OpenAI API 29 | 30 | pip install openai 31 | 32 | ## Maintainer 33 | 34 | * This module is maintained by [Michel Perrocheau](https://github.com/myrrkel). 35 | * Contact me on [LinkedIn](https://www.linkedin.com/in/michel-perrocheau-ba17a4122). 36 | 37 | [](https://github.com/myrrkel) 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /openai_connector/views/res_config_settings_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | res.config.settings.inherit 5 | res.config.settings 6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | OpenAI settings 14 |
15 | Configure OpenAI API 16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /openai_product_description/README.md: -------------------------------------------------------------------------------- 1 | [![License: AGPL-3](https://img.shields.io/badge/licence-AGPL--3-blue.png)](http://www.gnu.org/licenses/agpl-3.0-standalone.html) 2 | 3 | OpenAI Product Description 4 | ========================== 5 | 6 | [OpenAI Logo](https://openai.com/) 7 | 8 | This module allows to generate a product sales description with OpenAI's GTP3 model from product tags, attributes or any other product information. 9 | 10 | ## Usage 11 | 12 | On a product, select **Create Sales Description** action : 13 | 14 | ![image](./static/img/create_description_action.png) 15 | 16 | OpenAI will create 4 description proposals. Choose the one you prefer (you can correct it), then, click on **Apply** to save the value as the product sales description. 17 | 18 | ![image](./static/img/results.png) 19 | 20 | This action is also available from the product list view. 21 | 22 | 23 | 24 | ## Requirements 25 | 26 | [openai_connector](../openai_connector/README.md) is required. 27 | 28 | This module requires the Python client library for OpenAI API 29 | 30 | pip install openai 31 | 32 | ## Maintainer 33 | 34 | * This module is maintained by [Michel Perrocheau](https://github.com/myrrkel). 35 | * Contact me on [LinkedIn](https://www.linkedin.com/in/michel-perrocheau-ba17a4122). 36 | 37 | [](https://github.com/myrrkel) 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /openai_connector/__manifest__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2022 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | { 5 | 'name': 'OpenAI Connector', 6 | 'version': '16.2.0.0', 7 | 'author': 'Michel Perrocheau', 8 | 'website': 'https://github.com/myrrkel', 9 | 'summary': "Connector for OpenAI API", 10 | 'sequence': 0, 11 | 'certificate': '', 12 | 'license': 'AGPL-3', 13 | 'depends': [ 14 | 'base', 15 | 'mail', 16 | ], 17 | 'external_dependencies': { 18 | 'python': ['openai'], 19 | }, 20 | 'category': 'OpenAI', 21 | 'complexity': 'easy', 22 | 'qweb': [ 23 | ], 24 | 'demo': [ 25 | ], 26 | 'images': [ 27 | ], 28 | 'data': [ 29 | 'security/ir.model.access.csv', 30 | 'security/security.xml', 31 | 'views/res_config_settings_views.xml', 32 | 'views/openai_completion_views.xml', 33 | 'views/openai_completion_result_views.xml', 34 | 'views/openai_image_views.xml', 35 | 'views/openai_image_result_views.xml', 36 | 'views/openai_question_answer_views.xml', 37 | 'views/openai_fine_tuning_views.xml', 38 | ], 39 | 'assets': { 40 | 'web.assets_backend': [ 41 | 'openai_connector/static/src/scss/style.scss', 42 | ], 43 | }, 44 | 45 | 'auto_install': False, 46 | 'installable': True, 47 | 'application': False, 48 | } 49 | -------------------------------------------------------------------------------- /openai_chat/README.md: -------------------------------------------------------------------------------- 1 | [![License: AGPL-3](https://img.shields.io/badge/licence-AGPL--3-blue.png)](http://www.gnu.org/licenses/agpl-3.0-standalone.html) 2 | 3 | OpenAI Chat 4 | =================== 5 | 6 | [OpenAI Logo](https://openai.com/) 7 | 8 | This module adds an AI Bot user to chat with like in ChatGPT. 9 | 10 | ## Usage 11 | 12 | Open a chat and start talking to AI Bot: 13 | 14 | ![image](./static/img/open_chat.png) 15 | 16 | ![image](./static/img/chat.png) 17 | 18 | Or go is **Discuss**: 19 | 20 | ![image](./static/img/discuss.png) 21 | 22 | 23 | ### Clear the chat 24 | 25 | use the command **/clear** to clear the chat: 26 | 27 | ![image](./static/img/clear_chat.png) 28 | 29 | ### Boost AI Bot answer 30 | 31 | By default, AI Bot answer length is limited. To get longer answer, start your prompt with an exclamation mark, so AI Bor will use a maximum of tokens to answer. 32 | 33 | 34 | 35 | ![image](./static/img/truncated_answer.png) 36 | ![image](./static/img/longer_answer.png) 37 | 38 | 39 | 40 | ## Requirements 41 | 42 | **openai_connector** is required. 43 | 44 | This module requires the Python client library for OpenAI API 45 | 46 | pip install openai 47 | 48 | ## Maintainer 49 | 50 | * This module is maintained by [Michel Perrocheau](https://github.com/myrrkel). 51 | * Contact me on [LinkedIn](https://www.linkedin.com/in/michel-perrocheau-ba17a4122). 52 | 53 | [](https://github.com/myrrkel) 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /openai_connector/security/ir.model.access.csv: -------------------------------------------------------------------------------- 1 | "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" 2 | access_openai_completion_user,access_openai_completion user,openai_connector.model_openai_completion,base.group_user,1,0,0,0 3 | access_openai_completion_admin,access_openai_completion admin,openai_connector.model_openai_completion,base.group_erp_manager,1,1,1,1 4 | access_openai_completion_result_user,access_openai_completion_result user,openai_connector.model_openai_completion_result,base.group_user,1,1,1,1 5 | access_openai_image_user,access_openai_image user,openai_connector.model_openai_image,base.group_user,1,0,0,0 6 | access_openai_image_admin,access_openai_image admin,openai_connector.model_openai_image,base.group_erp_manager,1,1,1,1 7 | access_openai_image_result_user,access_openai_image_result user,openai_connector.model_openai_image_result,base.group_user,1,1,1,1 8 | access_openai_question_answer_user,access_openai_question_answer user,openai_connector.model_openai_question_answer,base.group_user,1,1,1,1 9 | access_openai_fine_tuning_user,access_openai_fine_tuning user,openai_connector.model_openai_fine_tuning,base.group_user,1,0,0,0 10 | access_openai_fine_tuning_admin,access_openai_fine_tuning admin,openai_connector.model_openai_fine_tuning,base.group_erp_manager,1,1,1,1 11 | access_openai_tool_user,access_openai_tool user,openai_connector.model_openai_tool,base.group_user,1,0,0,0 12 | access_openai_tool_admin,access_openai_tool admin,openai_connector.model_openai_tool,base.group_erp_manager,1,1,1,1 13 | access_openai_tool_property_user,access_openai_tool_property user,openai_connector.model_openai_tool_property,base.group_user,1,0,0,0 14 | access_openai_tool_property_admin,access_openai_tool_property admin,openai_connector.model_openai_tool_property,base.group_erp_manager,1,1,1,1 -------------------------------------------------------------------------------- /openai_connector/models/openai_image_result.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2022 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class OpenAiImageResult(models.Model): 12 | _name = 'openai.image.result' 13 | _description = 'OpenAI Image Result' 14 | _inherit = ['openai.result.mixin'] 15 | 16 | image_id = fields.Many2one('openai.image', string='OpenAI Action', readonly=True, ondelete='cascade') 17 | original_image = fields.Image(compute='_compute_original_image') 18 | method = fields.Char() 19 | answer = fields.Image(readonly=False) 20 | 21 | def _compute_name(self): 22 | for rec in self: 23 | if hasattr(rec.resource_ref, 'name'): 24 | name = f'{rec.image_id.name} - {rec.resource_ref.name}' 25 | elif hasattr(rec.resource_ref, 'display_name'): 26 | name = f'{rec.image_id.name} - {rec.resource_ref.display_name}' 27 | else: 28 | name = f'{rec.image_id.name} - {rec.model_id.name} ({self.res_id})' 29 | if rec.test_result: 30 | name = '%s (%s)' % (name, _('TEST')) 31 | rec.name = name 32 | 33 | def _compute_original_image(self): 34 | for rec in self: 35 | try: 36 | record_id = self.env[rec.model_id.model].browse(rec.res_id) 37 | if rec.image_id.source_image_field_id: 38 | res = record_id[rec.image_id.source_image_field_id.name] 39 | if res: 40 | rec.original_image = res 41 | continue 42 | rec.original_image = None 43 | except Exception as err: 44 | _logger.error(err) 45 | pass 46 | -------------------------------------------------------------------------------- /openai_edit_product_image/models/product.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2023 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class ProductTemplate(models.Model): 12 | _inherit = 'product.template' 13 | 14 | openai_source_image = fields.Image("OpenAI Source Image", max_width=2000, max_height=2000) 15 | openai_mask_image = fields.Image("OpenAI Mask Image", max_width=2000, max_height=2000) 16 | image_ratio = fields.Float() 17 | image_description = fields.Char() 18 | 19 | def action_openai_create_product_edit_image(self): 20 | for rec in self: 21 | image_edit_id = self.env.ref('openai_edit_product_image.edit_product_image') 22 | if rec.openai_source_image: 23 | method = 'create_edit' 24 | elif rec.image_description: 25 | method = 'create' 26 | elif rec.image_1920: 27 | method = 'create_variation' 28 | else: 29 | continue 30 | image_edit_id.apply(rec.id, method=method) 31 | if image_edit_id.save_on_target_field: 32 | return { 33 | 'type': 'ir.actions.client', 34 | 'tag': 'display_notification', 35 | 'params': { 36 | 'message': _("Product image created."), 37 | 'type': 'success', 38 | 'sticky': False, 39 | 'next': {'type': 'ir.actions.client', 'tag': 'reload'}, 40 | } 41 | } 42 | else: 43 | action_name = 'openai_edit_product_image.openai_product_edit_image_action' 44 | action = self.env['ir.actions.act_window']._for_xml_id(action_name) 45 | action['domain'] = [('res_id', 'in', self.ids)] 46 | return action 47 | -------------------------------------------------------------------------------- /openai_edit_product_image/README.md: -------------------------------------------------------------------------------- 1 | [![License: AGPL-3](https://img.shields.io/badge/licence-AGPL--3-blue.png)](http://www.gnu.org/licenses/agpl-3.0-standalone.html) 2 | 3 | OpenAI Edit Product Image 4 | ========================= 5 | 6 | [OpenAI Logo](https://openai.com/) 7 | 8 | This module allows to generate a new product image from a cropped product image with DALL-E. 9 | 10 | ## Usage 11 | 12 | On a product, select **DALL-E** tab, add a PNG image with transparency or add a mask image, and write a description of the result you want: 13 | 14 | You can also set an image ratio. 15 | 16 | ![image](./static/img/config_product.png) 17 | 18 | Go in menu **Action** and select **Edit Product Image with DALL-E**: 19 | 20 | ![image](./static/img/product_results.png) 21 | 22 | Select the image you prefer and click on **Apply Image** to set is as product image : 23 | 24 | ![image](./static/img/apply_image.png) 25 | 26 | ![image](./static/img/product.png) 27 | 28 | 29 | 30 | Action **Edit Product Image with DALL-E** is also available from the product list view. 31 | 32 | ## Create a product image from scratch 33 | 34 | Leave the **Source Image** field empty, select **Edit Product Image with DALL-E** action. 35 | 36 | This option will turn any product into a DALL-E playground... 37 | 38 | *You can also update the template "edit_product_image_template" to create your own prompt from your product properties.* 39 | 40 | 41 | 42 | ![image](./static/img/create_image_prompt.png) 43 | ![image](./static/img/create_image.png) 44 | 45 | 46 | 47 | 48 | ## Requirements 49 | 50 | [openai_connector](../openai_connector/README.md) is required. 51 | 52 | This module requires the Python client library for OpenAI API 53 | 54 | pip install openai 55 | 56 | ## Maintainer 57 | 58 | * This module is maintained by [Michel Perrocheau](https://github.com/myrrkel). 59 | * Contact me on [LinkedIn](https://www.linkedin.com/in/michel-perrocheau-ba17a4122). 60 | 61 | [](https://github.com/myrrkel) 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /openai_product_tags/views/openai_product_result_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | openai.product.tags.search 6 | openai.completion.result 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | Create Product Tags 17 | 18 | 19 | list,form 20 | code 21 | action = records.action_openai_create_product_tags() 22 | 23 | 24 | 25 | OpenAI Product Tags Results 26 | ir.actions.act_window 27 | openai.completion.result 28 | tree,form 29 | 30 | 31 | {'search_default_openai_product_tags': 1} 32 | 33 |

34 | No OpenAI Product Tags Result 35 |

36 |
37 |
38 | 39 | 43 |
44 | -------------------------------------------------------------------------------- /openai_edit_product_image/views/openai_product_result_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | openai.product.tags.search 6 | openai.image.result 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | Edit Product Image with DALL-E 17 | 18 | 19 | list,form 20 | code 21 | action = records.action_openai_create_product_edit_image() 22 | 23 | 24 | 25 | DALL-E Product Image Results 26 | ir.actions.act_window 27 | openai.image.result 28 | tree,form 29 | 30 | 31 | {'search_default_openai_product_edit_image': 1} 32 | 33 |

34 | No DALL-E Product Image Result 35 |

36 |
37 |
38 | 39 | 43 |
44 | -------------------------------------------------------------------------------- /openai_product_description/views/openai_product_result_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | openai.product.description.search 6 | openai.completion.result 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | Create Sales Description 17 | 18 | 19 | list,form 20 | code 21 | action = records.action_openai_create_product_sales_description() 22 | 23 | 24 | 25 | OpenAI Product Sales Description Results 26 | ir.actions.act_window 27 | openai.completion.result 28 | tree,form 29 | 30 | 31 | {'search_default_openai_product_description': 1} 32 | 33 |

34 | No OpenAI Product Sales Description Result 35 |

36 |
37 |
38 | 39 | 43 |
44 | -------------------------------------------------------------------------------- /openai_connector/models/openai_result_mixin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2022 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | import logging 7 | 8 | _logger = logging.getLogger(__name__) 9 | 10 | 11 | class OpenAiResultMixin(models.AbstractModel): 12 | _name = 'openai.result.mixin' 13 | _description = 'OpenAI result Mixin' 14 | 15 | name = fields.Char(compute='_compute_name') 16 | model_id = fields.Many2one('ir.model', string='Model', readonly=True, ondelete='cascade') 17 | model = fields.Char(related='model_id.model', string='Model Name', readonly=True, store=True) 18 | target_field_id = fields.Many2one('ir.model.fields', string='Target Field', readonly=True) 19 | res_id = fields.Integer('Resource ID', readonly=True) 20 | resource_ref = fields.Reference(string='Record', selection='_selection_target_model', 21 | compute='_compute_resource_ref', inverse='_set_resource_ref', readonly=True) 22 | prompt = fields.Text(readonly=True) 23 | test_result = fields.Boolean() 24 | 25 | @api.model 26 | def _selection_target_model(self): 27 | model_ids = self.env['ir.model'].search([]) 28 | return [(model.model, model.name) for model in model_ids] 29 | 30 | @api.depends('model_id', 'res_id') 31 | def _compute_resource_ref(self): 32 | for rec in self: 33 | if rec.model_id and rec.res_id: 34 | record = self.env[rec.model_id.model].browse(rec.res_id) 35 | res_id = record[0] if record else 0 36 | rec.resource_ref = '%s,%s' % (rec.model_id.model, res_id.id) 37 | else: 38 | rec.resource_ref = False 39 | 40 | @api.onchange('resource_ref') 41 | def _set_resource_ref(self): 42 | for rec in self: 43 | if rec.resource_ref: 44 | rec.res_id = rec.resource_ref.id 45 | 46 | def get_answer_value(self): 47 | return self.answer 48 | 49 | def save_result_on_target_field(self): 50 | record = self.env[self.model_id.model].browse(self.res_id) 51 | answer_value = self.get_answer_value() 52 | if answer_value and self.target_field_id: 53 | record.write({self.target_field_id.name: answer_value}) 54 | 55 | def action_apply(self): 56 | self.save_result_on_target_field() 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | #Pycharm 132 | .idea 133 | -------------------------------------------------------------------------------- /openai_connector/models/openai_question_answer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2024 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | 7 | import logging 8 | 9 | _logger = logging.getLogger(__name__) 10 | 11 | 12 | class OpenAiQuestionAnswer(models.Model): 13 | _name = 'openai.question.answer' 14 | _description = 'OpenAI Question Answer' 15 | 16 | name = fields.Text('Question') 17 | answer = fields.Text('Answer') 18 | model_id = fields.Many2one('ir.model', string='Model', ondelete='cascade') 19 | model = fields.Char(related='model_id.model', string='Model Name', readonly=True, store=True) 20 | res_id = fields.Integer('Resource ID', readonly=True) 21 | resource_ref = fields.Reference(string='Record', selection='_selection_target_model', 22 | compute='_compute_resource_ref', inverse='_set_resource_ref') 23 | answer_completion_id = fields.Many2one('openai.completion', string='Answer Completion') 24 | content_length = fields.Integer(compute='_compute_content_length') 25 | 26 | @api.model 27 | def _selection_target_model(self): 28 | model_ids = self.env['ir.model'].search([]) 29 | return [(model.model, model.name) for model in model_ids] 30 | 31 | def _compute_content_length(self): 32 | for res in self: 33 | res.content_length = len(res.name) + len(res.answer) 34 | 35 | @api.depends('res_id') 36 | def _compute_resource_ref(self): 37 | for rec in self: 38 | if rec.model_id and rec.res_id: 39 | record = self.env[rec.model_id.model].browse(rec.res_id) 40 | res_id = record[0] if record else 0 41 | rec.resource_ref = '%s,%s' % (rec.model_id.model, res_id.id) 42 | else: 43 | rec.resource_ref = False 44 | 45 | @api.onchange('resource_ref') 46 | def _set_resource_ref(self): 47 | for rec in self: 48 | if rec.resource_ref: 49 | rec.model_id = self.env['ir.model']._get(rec.resource_ref._name) 50 | rec.res_id = rec.resource_ref.id 51 | 52 | def action_answer_question(self): 53 | for rec in self: 54 | res = rec.answer_completion_id.create_completion(rec.id) 55 | rec.answer = res[0].answer 56 | 57 | def get_score(self, keyword_list): 58 | score = 0 59 | for keyword in keyword_list: 60 | keyword = keyword.lower() 61 | if keyword in self.name.lower(): 62 | score += 2 63 | if keyword in self.answer.lower(): 64 | score += 1 65 | return score 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # odoo-openai 2 | OpenAI tools integration in Odoo (ChatGPT, GPT3, DALL-E...) 3 | 4 | | | Addons | Description | Versions | 5 | |---------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|---------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------| 6 | | [](./openai_connector/README.md) | [openai_connector](./openai_connector/README.md) | Connector for OpenAI API | ![16.0](https://img.shields.io/badge/-16.0-blueviolet)![17.0](https://img.shields.io/badge/-17.0-blue) | 7 | | [](./openai_chat/README.md) | [openai_chat](./openai_chat/README.md) | Add an AI Bot user to chat with like in ChatGPT | ![16.0](https://img.shields.io/badge/-16.0-blueviolet)![17.0](https://img.shields.io/badge/-17.0-blue) | 8 | | [](./openai_edit_product_image/README.md) | [openai_edit_product_image](./openai_edit_product_image/README.md) | Create a new product image from a cropped product image with DALL-E | ![16.0](https://img.shields.io/badge/-16.0-blueviolet)![17.0](https://img.shields.io/badge/-17.0-blue) | 9 | | [](./openai_product_description/README.md) | [openai_product_description](./openai_product_description/README.md) | Generate a product sales description with OpenAI | ![16.0](https://img.shields.io/badge/-16.0-blueviolet)![17.0](https://img.shields.io/badge/-17.0-blue) | 10 | | [](./openai_product_tags/README.md) | [openai_product_tags](./openai_product_tags/README.md) | Generate product tags with OpenAI | ![16.0](https://img.shields.io/badge/-16.0-blueviolet)![17.0](https://img.shields.io/badge/-17.0-blue) | 11 | -------------------------------------------------------------------------------- /openai_connector/views/openai_question_answer_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | openai.question.answer.view.form 5 | openai.question.answer 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 |
24 | 25 | 26 | openai.question.answer.view.tree 27 | openai.question.answer 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | OpenAI Question Answers 41 | ir.actions.act_window 42 | openai.question.answer 43 | tree,form 44 | 45 |

46 | No OpenAI Question Answers 47 |

48 |
49 |
50 | 51 | 52 | Answer Question 53 | 54 | 55 | list,form 56 | code 57 | action = records.action_answer_question() 58 | 59 | 60 | 64 |
65 | -------------------------------------------------------------------------------- /openai_connector/views/openai_image_result_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | openai.image.result.view.form 5 | openai.image.result 6 | 7 |
8 | 9 |
10 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 |
34 | 35 | 36 | openai.image.result.view.tree 37 | openai.image.result 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | OpenAI Image Results 54 | ir.actions.act_window 55 | openai.image.result 56 | tree,form 57 | 58 |

59 | No OpenAI Image Result 60 |

61 |
62 |
63 | 64 | 68 |
69 | -------------------------------------------------------------------------------- /openai_chat/static/img/openai_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_connector/static/img/openai_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_product_tags/static/img/openai_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_edit_product_image/static/img/openai_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_product_description/static/img/openai_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openai_connector/models/openai_mixin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (C) 2022 - Michel Perrocheau (https://github.com/myrrkel). 3 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 4 | 5 | from odoo import models, fields, api, _ 6 | from odoo.exceptions import UserError 7 | from odoo.tools.safe_eval import safe_eval 8 | from odoo.addons.base.models.ir_model import SAFE_EVAL_BASE 9 | from odoo.tools import html2plaintext 10 | import logging 11 | from openai import OpenAI 12 | 13 | _logger = logging.getLogger(__name__) 14 | 15 | 16 | class OpenAiMixin(models.AbstractModel): 17 | _name = 'openai.mixin' 18 | _description = 'OpenAI Mixin' 19 | _inherit = ['mail.render.mixin'] 20 | 21 | name = fields.Char() 22 | active = fields.Boolean(default=True) 23 | model_id = fields.Many2one('ir.model', string='Model', required=True, ondelete='cascade') 24 | domain = fields.Char() 25 | save_on_target_field = fields.Boolean() 26 | target_field_id = fields.Many2one('ir.model.fields', string='Target Field') 27 | prompt_template = fields.Text() 28 | prompt_template_id = fields.Many2one('ir.ui.view', string='Prompt Template View') 29 | n = fields.Integer(default=1) 30 | answer_lang_id = fields.Many2one('res.lang', string='Answer Language', context={'active_test': False}) 31 | test_prompt = fields.Text(readonly=True) 32 | 33 | @api.model 34 | def get_openai(self): 35 | api_key = self.env['ir.config_parameter'].sudo().get_param('openai_api_key') 36 | if not api_key: 37 | raise UserError(_('OpenAI API key is required.')) 38 | client = OpenAI(api_key=api_key) 39 | return client 40 | 41 | def get_prompt(self, rec_id=0): 42 | context = {'html2plaintext': html2plaintext} 43 | lang = self.env.lang 44 | answer_lang_id = self.answer_lang_id or self.env['res.lang']._lang_get(lang) 45 | if answer_lang_id: 46 | context['answer_lang'] = answer_lang_id.name 47 | if self.prompt_template_id: 48 | prompt = self._render_template_qweb_view(self.prompt_template_id.xml_id, self.model_id.model, [rec_id], 49 | add_context=context) 50 | elif self.prompt_template: 51 | prompt = self._render_template_qweb(self.prompt_template, self.model_id.model, [rec_id], 52 | add_context=context) 53 | else: 54 | raise UserError(_('A prompt template is required')) 55 | 56 | return prompt[rec_id].strip() 57 | 58 | def get_records(self, limit=0): 59 | domain = safe_eval(self.domain, SAFE_EVAL_BASE, {'self': self}) if self.domain else [] 60 | rec_ids = self.env[self.model_id.model].search(domain, limit=limit) 61 | return rec_ids 62 | 63 | def get_record(self, rec_id): 64 | record_id = self.env[self.model_id.model].browse(rec_id) 65 | return record_id 66 | 67 | def run(self): 68 | for rec_id in self.get_records(): 69 | self.apply(rec_id.id) 70 | 71 | def apply(self, rec_id, method=False): 72 | result_ids = self.openai_create(rec_id, method) 73 | for result_id in result_ids: 74 | if self.save_on_target_field: 75 | result_id.save_result_on_target_field() 76 | 77 | def openai_create(self, rec_id, method=False): 78 | return False 79 | 80 | def run_test_prompt(self): 81 | rec_id = self.get_records(limit=1).id 82 | if not rec_id: 83 | return 84 | self.test_prompt = self.get_prompt(rec_id) 85 | -------------------------------------------------------------------------------- /openai_connector/README.md: -------------------------------------------------------------------------------- 1 | [![License: AGPL-3](https://img.shields.io/badge/licence-AGPL--3-blue.png)](http://www.gnu.org/licenses/agpl-3.0-standalone.html) 2 | 3 | OpenAI Connector 4 | ================= 5 | 6 | [OpenAI Logo](https://openai.com/) 7 | 8 | 9 | This technical module provides a connector for the OpenAI API and allows integration of ChatGPT and DALL-E capabilities within Odoo. 10 | ChatGPT4 and DALL·E 3 are available. 11 | 12 | It can be used as a playground to test OpenAI tools in Odoo but does not have standalone functionality. 13 | The module is intended to be inherited by other modules for specific use cases, such as: 14 | - [openai_chat](../openai_chat/README.md): Adding an AI bot user for interactive chat using ChatGPT 15 | - [openai_edit_product_image](../openai_edit_product_image/README.md): Generating a new product image from a cropped image using DALL-E 16 | - [openai_product_description](../openai_product_description/README.md): Generating sales descriptions for products using ChatGPT 17 | - [openai_product_tags](../openai_product_tags/README.md): Generating product tags using ChatGPT 18 | 19 | To create custom OpenAI completions, edits, or images, refer to the API documentation for proper configuration of API parameters. 20 | 21 | [OpenAI API Documentation](https://beta.openai.com/docs/api-reference/introduction) 22 | 23 | ## Configuration 24 | 25 | Create an account on [https://beta.openai.com/](https://beta.openai.com/) 26 | 27 | Generate your API key: [API keys](https://beta.openai.com/account/api-keys) 28 | 29 | In **Settings**, fill the **API Key** field with your generated key. 30 | 31 | ![image](./static/img/settings.png) 32 | 33 | ## Usage 34 | 35 | ### OpenAI Completion 36 | 37 | To create a new **OpenAI Completion**, go to **Settings**, **Technical**, **OpenAI Completion** and create a new record. 38 | 39 | ![image](./static/img/completion_params.png) 40 | 41 | **Model**: The model on witch the completion will be applied. 42 | 43 | **Target Field**: The field where the generated value will be saved. 44 | 45 | **Domain**: The domain to select the records on witch the completion will be run. 46 | 47 | 48 | ![image](./static/img/openai_params.png) 49 | 50 | Check the [API Documentation](https://beta.openai.com/docs/api-reference/introduction) to set **OpenAI Parameters** values. 51 | 52 | For Completion results go to **Settings**, **Technical**, **OpenAI Completion Results** 53 | 54 | ### OpenAI Image 55 | 56 | To create a new **OpenAI Image**, go to **Settings**, **Technical**, **OpenAI Image** and create a new record. 57 | 58 | For results go to **Settings**, **Technical**, **OpenAI Image Results** 59 | 60 | ### Prompt template 61 | 62 | Write a prompt template in Qweb. 63 | 64 | Available functions in prompt template: 65 | - object : Current record 66 | - answer_lang : Function returning the language name 67 | - html2plaintext : Function to convert html to text 68 | 69 | ![image](./static/img/prompt.png) 70 | 71 | ### Tests 72 | 73 | Test actions use the first record of the model selected by the domain. 74 | 75 | Test first your prompt to adjust your template, then test the result of the Completion, Edit or Image to adjust OpenAI parameters. 76 | 77 | ![image](./static/img/tests.png) 78 | 79 | ## Requirements 80 | 81 | This module requires the Python client library for OpenAI API 82 | 83 | pip install openai>=1.6.1 84 | 85 | ## Maintainer 86 | 87 | * This module is maintained by [Michel Perrocheau](https://github.com/myrrkel). 88 | * Contact me on [LinkedIn](https://www.linkedin.com/in/michel-perrocheau-ba17a4122). 89 | 90 | [](https://github.com/myrrkel) 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /openai_connector/models/openai_fine_tuning.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 - Michel Perrocheau (https://github.com/myrrkel). 2 | # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). 3 | 4 | import json 5 | from tempfile import NamedTemporaryFile 6 | from odoo import models, fields, api, _ 7 | from odoo.tools.safe_eval import safe_eval 8 | from odoo.addons.base.models.ir_model import SAFE_EVAL_BASE 9 | 10 | import logging 11 | 12 | _logger = logging.getLogger(__name__) 13 | 14 | 15 | class OpenAiFineTuning(models.Model): 16 | _name = 'openai.fine.tuning' 17 | _description = 'OpenAI Fine-Tuning' 18 | 19 | def _get_training_model_list(self): 20 | return [('gpt-3.5-turbo', 'gpt-3.5-turbo'), 21 | ('gpt-3.5-turbo-1106', 'gpt-3.5-turbo-1106'), 22 | ('gpt-3.5-turbo-0613', 'gpt-3.5-turbo-0613'), 23 | ('gpt-4-0613', 'gpt-4-0613'), 24 | ('babbage-002', 'babbage-002'), 25 | ('davinci-002', 'davinci-002')] 26 | 27 | name = fields.Char() 28 | training_model = fields.Selection(selection=_get_training_model_list, default='gpt-3.5-turbo') 29 | training_file_id = fields.Char('Training File ID') 30 | fine_tuning_job_id = fields.Char('Fine-Tuning Job ID') 31 | fine_tuned_model = fields.Char('Fine-Tuned Model') 32 | question_answer_domain = fields.Char() 33 | question_answer_ids = fields.Many2many('openai.question.answer', string='Questions /Answers', 34 | compute='_compute_question_answers', 35 | store=False) 36 | system_role_content = fields.Char() 37 | 38 | def _compute_question_answers(self): 39 | for rec in self: 40 | domain = safe_eval(rec.question_answer_domain, 41 | SAFE_EVAL_BASE, 42 | {'self': rec}) if rec.question_answer_domain else [] 43 | rec.question_answer_ids = self.env['openai.question.answer'].search(domain) 44 | 45 | def get_training_content(self): 46 | content = '' 47 | for question_answer_id in self.question_answer_ids: 48 | messages = { 49 | 'messages': [ 50 | {'role': 'system', 'content': self.system_role_content}, 51 | {'role': 'user', 'content': question_answer_id.name}, 52 | {'role': 'assistant', 'content': question_answer_id.answer} 53 | ] 54 | } 55 | content += json.dumps(messages) + '\n' 56 | return bytes(content, 'utf-8') 57 | 58 | def create_training_file(self): 59 | client = self.env['openai.mixin'].get_openai() 60 | file = ('training_%s' % self.id, self.get_training_content()) 61 | res = client.files.create(file=file, purpose='fine-tune') 62 | self.training_file_id = res.id 63 | 64 | def create_fine_tuning(self): 65 | client = self.env['openai.mixin'].get_openai() 66 | res = client.fine_tuning.jobs.create(training_file=self.training_file_id, model=self.training_model) 67 | self.fine_tuning_job_id = res.id 68 | _logger.info(res) 69 | 70 | def update_fine_tuned_model(self): 71 | client = self.env['openai.mixin'].get_openai() 72 | res = client.fine_tuning.jobs.retrieve(self.fine_tuning_job_id) 73 | self.fine_tuned_model = res.fine_tuned_model 74 | _logger.info(res) 75 | 76 | def action_create_training_file(self): 77 | for rec in self: 78 | rec.create_training_file() 79 | 80 | def action_create_fine_tuning(self): 81 | for rec in self: 82 | rec.create_fine_tuning() 83 | 84 | def action_update_fine_tuned_model(self): 85 | for rec in self: 86 | rec.update_fine_tuned_model() 87 | -------------------------------------------------------------------------------- /openai_connector/views/openai_completion_result_views.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | openai.completion.result.view.form 5 | openai.completion.result 6 | 7 |
8 | 9 |
10 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 | 39 | 40 | openai.completion.result.view.tree 41 | openai.completion.result 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | openai.completion.result.simple.view.tree 54 | openai.completion.result 55 | 56 | 57 | 58 | 59 |