iatoolkit 0.3.9__py3-none-any.whl → 0.107.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iatoolkit might be problematic. Click here for more details.
- iatoolkit/__init__.py +27 -35
- iatoolkit/base_company.py +3 -35
- iatoolkit/cli_commands.py +18 -47
- iatoolkit/common/__init__.py +0 -0
- iatoolkit/common/exceptions.py +48 -0
- iatoolkit/common/interfaces/__init__.py +0 -0
- iatoolkit/common/interfaces/asset_storage.py +34 -0
- iatoolkit/common/interfaces/database_provider.py +39 -0
- iatoolkit/common/model_registry.py +159 -0
- iatoolkit/common/routes.py +138 -0
- iatoolkit/common/session_manager.py +26 -0
- iatoolkit/common/util.py +353 -0
- iatoolkit/company_registry.py +66 -29
- iatoolkit/core.py +514 -0
- iatoolkit/infra/__init__.py +5 -0
- iatoolkit/infra/brevo_mail_app.py +123 -0
- iatoolkit/infra/call_service.py +140 -0
- iatoolkit/infra/connectors/__init__.py +5 -0
- iatoolkit/infra/connectors/file_connector.py +17 -0
- iatoolkit/infra/connectors/file_connector_factory.py +57 -0
- iatoolkit/infra/connectors/google_cloud_storage_connector.py +53 -0
- iatoolkit/infra/connectors/google_drive_connector.py +68 -0
- iatoolkit/infra/connectors/local_file_connector.py +46 -0
- iatoolkit/infra/connectors/s3_connector.py +33 -0
- iatoolkit/infra/google_chat_app.py +57 -0
- iatoolkit/infra/llm_providers/__init__.py +0 -0
- iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
- iatoolkit/infra/llm_providers/gemini_adapter.py +350 -0
- iatoolkit/infra/llm_providers/openai_adapter.py +124 -0
- iatoolkit/infra/llm_proxy.py +268 -0
- iatoolkit/infra/llm_response.py +45 -0
- iatoolkit/infra/redis_session_manager.py +122 -0
- iatoolkit/locales/en.yaml +222 -0
- iatoolkit/locales/es.yaml +225 -0
- iatoolkit/repositories/__init__.py +5 -0
- iatoolkit/repositories/database_manager.py +187 -0
- iatoolkit/repositories/document_repo.py +33 -0
- iatoolkit/repositories/filesystem_asset_repository.py +36 -0
- iatoolkit/repositories/llm_query_repo.py +105 -0
- iatoolkit/repositories/models.py +279 -0
- iatoolkit/repositories/profile_repo.py +171 -0
- iatoolkit/repositories/vs_repo.py +150 -0
- iatoolkit/services/__init__.py +5 -0
- iatoolkit/services/auth_service.py +193 -0
- {services → iatoolkit/services}/benchmark_service.py +7 -7
- iatoolkit/services/branding_service.py +153 -0
- iatoolkit/services/company_context_service.py +214 -0
- iatoolkit/services/configuration_service.py +375 -0
- iatoolkit/services/dispatcher_service.py +134 -0
- {services → iatoolkit/services}/document_service.py +20 -8
- iatoolkit/services/embedding_service.py +148 -0
- iatoolkit/services/excel_service.py +156 -0
- {services → iatoolkit/services}/file_processor_service.py +36 -21
- iatoolkit/services/history_manager_service.py +208 -0
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +80 -0
- iatoolkit/services/language_service.py +89 -0
- iatoolkit/services/license_service.py +82 -0
- iatoolkit/services/llm_client_service.py +438 -0
- iatoolkit/services/load_documents_service.py +174 -0
- iatoolkit/services/mail_service.py +213 -0
- {services → iatoolkit/services}/profile_service.py +200 -101
- iatoolkit/services/prompt_service.py +303 -0
- iatoolkit/services/query_service.py +467 -0
- iatoolkit/services/search_service.py +55 -0
- iatoolkit/services/sql_service.py +169 -0
- iatoolkit/services/tool_service.py +246 -0
- iatoolkit/services/user_feedback_service.py +117 -0
- iatoolkit/services/user_session_context_service.py +213 -0
- iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit/static/images/iatoolkit_core.png +0 -0
- iatoolkit/static/images/iatoolkit_logo.png +0 -0
- iatoolkit/static/js/chat_feedback_button.js +80 -0
- iatoolkit/static/js/chat_filepond.js +85 -0
- iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit/static/js/chat_history_button.js +110 -0
- iatoolkit/static/js/chat_logout_button.js +36 -0
- iatoolkit/static/js/chat_main.js +401 -0
- iatoolkit/static/js/chat_model_selector.js +227 -0
- iatoolkit/static/js/chat_onboarding_button.js +103 -0
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +38 -0
- iatoolkit/static/styles/chat_iatoolkit.css +559 -0
- iatoolkit/static/styles/chat_modal.css +133 -0
- iatoolkit/static/styles/chat_public.css +135 -0
- iatoolkit/static/styles/documents.css +598 -0
- iatoolkit/static/styles/landing_page.css +398 -0
- iatoolkit/static/styles/llm_output.css +148 -0
- iatoolkit/static/styles/onboarding.css +176 -0
- iatoolkit/system_prompts/__init__.py +0 -0
- iatoolkit/system_prompts/query_main.prompt +30 -23
- iatoolkit/system_prompts/sql_rules.prompt +47 -12
- iatoolkit/templates/_company_header.html +45 -0
- iatoolkit/templates/_login_widget.html +42 -0
- iatoolkit/templates/base.html +78 -0
- iatoolkit/templates/change_password.html +66 -0
- iatoolkit/templates/chat.html +337 -0
- iatoolkit/templates/chat_modals.html +185 -0
- iatoolkit/templates/error.html +51 -0
- iatoolkit/templates/forgot_password.html +51 -0
- iatoolkit/templates/onboarding_shell.html +106 -0
- iatoolkit/templates/signup.html +79 -0
- iatoolkit/views/__init__.py +5 -0
- iatoolkit/views/base_login_view.py +96 -0
- iatoolkit/views/change_password_view.py +116 -0
- iatoolkit/views/chat_view.py +76 -0
- iatoolkit/views/embedding_api_view.py +65 -0
- iatoolkit/views/forgot_password_view.py +75 -0
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +56 -0
- iatoolkit/views/home_view.py +63 -0
- iatoolkit/views/init_context_api_view.py +74 -0
- iatoolkit/views/llmquery_api_view.py +59 -0
- iatoolkit/views/load_company_configuration_api_view.py +49 -0
- iatoolkit/views/load_document_api_view.py +65 -0
- iatoolkit/views/login_view.py +170 -0
- iatoolkit/views/logout_api_view.py +57 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +37 -0
- iatoolkit/views/root_redirect_view.py +22 -0
- iatoolkit/views/signup_view.py +100 -0
- iatoolkit/views/static_page_view.py +27 -0
- iatoolkit/views/user_feedback_api_view.py +60 -0
- iatoolkit/views/users_api_view.py +33 -0
- iatoolkit/views/verify_user_view.py +60 -0
- iatoolkit-0.107.4.dist-info/METADATA +268 -0
- iatoolkit-0.107.4.dist-info/RECORD +132 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE +21 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/top_level.txt +0 -1
- iatoolkit/iatoolkit.py +0 -413
- iatoolkit/system_prompts/arquitectura.prompt +0 -32
- iatoolkit-0.3.9.dist-info/METADATA +0 -252
- iatoolkit-0.3.9.dist-info/RECORD +0 -32
- services/__init__.py +0 -5
- services/api_service.py +0 -75
- services/dispatcher_service.py +0 -351
- services/excel_service.py +0 -98
- services/history_service.py +0 -45
- services/jwt_service.py +0 -91
- services/load_documents_service.py +0 -212
- services/mail_service.py +0 -62
- services/prompt_manager_service.py +0 -172
- services/query_service.py +0 -334
- services/search_service.py +0 -32
- services/sql_service.py +0 -42
- services/tasks_service.py +0 -188
- services/user_feedback_service.py +0 -67
- services/user_session_context_service.py +0 -85
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from injector import inject
|
|
7
|
+
from iatoolkit.common.interfaces.asset_storage import AssetRepository, AssetType
|
|
8
|
+
from iatoolkit.repositories.llm_query_repo import LLMQueryRepo
|
|
9
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
10
|
+
from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
11
|
+
from collections import defaultdict
|
|
12
|
+
from iatoolkit.repositories.models import Prompt, PromptCategory, Company
|
|
13
|
+
from iatoolkit.common.exceptions import IAToolkitException
|
|
14
|
+
import importlib.resources
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
# iatoolkit system prompts definitions
|
|
19
|
+
_SYSTEM_PROMPTS = [
|
|
20
|
+
{'name': 'query_main', 'description': 'iatoolkit main prompt'},
|
|
21
|
+
{'name': 'format_styles', 'description': 'output format styles'},
|
|
22
|
+
{'name': 'sql_rules', 'description': 'instructions for SQL queries'}
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
class PromptService:
|
|
26
|
+
@inject
|
|
27
|
+
def __init__(self,
|
|
28
|
+
asset_repo: AssetRepository,
|
|
29
|
+
llm_query_repo: LLMQueryRepo,
|
|
30
|
+
profile_repo: ProfileRepo,
|
|
31
|
+
i18n_service: I18nService):
|
|
32
|
+
self.asset_repo = asset_repo
|
|
33
|
+
self.llm_query_repo = llm_query_repo
|
|
34
|
+
self.profile_repo = profile_repo
|
|
35
|
+
self.i18n_service = i18n_service
|
|
36
|
+
|
|
37
|
+
def sync_company_prompts(self, company_short_name: str, prompts_config: list, categories_config: list):
|
|
38
|
+
"""
|
|
39
|
+
Synchronizes prompt categories and prompts from YAML config to Database.
|
|
40
|
+
Strategies:
|
|
41
|
+
- Categories: Create or Update existing based on name.
|
|
42
|
+
- Prompts: Create or Update existing based on name. Soft-delete or Delete unused.
|
|
43
|
+
"""
|
|
44
|
+
if not prompts_config:
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
48
|
+
if not company:
|
|
49
|
+
raise IAToolkitException(IAToolkitException.ErrorType.INVALID_NAME,
|
|
50
|
+
f'Company {company_short_name} not found')
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
# 1. Sync Categories
|
|
54
|
+
category_map = {}
|
|
55
|
+
|
|
56
|
+
for i, category_name in enumerate(categories_config):
|
|
57
|
+
category_obj = PromptCategory(
|
|
58
|
+
company_id=company.id,
|
|
59
|
+
name=category_name,
|
|
60
|
+
order=i + 1
|
|
61
|
+
)
|
|
62
|
+
# Persist and get back the object with ID
|
|
63
|
+
persisted_cat = self.llm_query_repo.create_or_update_prompt_category(category_obj)
|
|
64
|
+
category_map[category_name] = persisted_cat
|
|
65
|
+
|
|
66
|
+
# 2. Sync Prompts
|
|
67
|
+
defined_prompt_names = set()
|
|
68
|
+
|
|
69
|
+
for prompt_data in prompts_config:
|
|
70
|
+
category_name = prompt_data.get('category')
|
|
71
|
+
if not category_name or category_name not in category_map:
|
|
72
|
+
logging.warning(
|
|
73
|
+
f"⚠️ Warning: Prompt '{prompt_data['name']}' has an invalid or missing category. Skipping.")
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
prompt_name = prompt_data['name']
|
|
77
|
+
defined_prompt_names.add(prompt_name)
|
|
78
|
+
|
|
79
|
+
category_obj = category_map[category_name]
|
|
80
|
+
filename = f"{prompt_name}.prompt"
|
|
81
|
+
|
|
82
|
+
new_prompt = Prompt(
|
|
83
|
+
company_id=company.id,
|
|
84
|
+
name=prompt_name,
|
|
85
|
+
description=prompt_data.get('description'),
|
|
86
|
+
order=prompt_data.get('order'),
|
|
87
|
+
category_id=category_obj.id,
|
|
88
|
+
active=prompt_data.get('active', True),
|
|
89
|
+
is_system_prompt=False,
|
|
90
|
+
filename=filename,
|
|
91
|
+
custom_fields=prompt_data.get('custom_fields', [])
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
self.llm_query_repo.create_or_update_prompt(new_prompt)
|
|
95
|
+
|
|
96
|
+
# 3. Cleanup: Delete prompts present in DB but not in Config
|
|
97
|
+
existing_prompts = self.llm_query_repo.get_prompts(company)
|
|
98
|
+
for p in existing_prompts:
|
|
99
|
+
if p.name not in defined_prompt_names:
|
|
100
|
+
# Using hard delete to keep consistent with previous "refresh" behavior
|
|
101
|
+
self.llm_query_repo.session.delete(p)
|
|
102
|
+
|
|
103
|
+
self.llm_query_repo.commit()
|
|
104
|
+
|
|
105
|
+
except Exception as e:
|
|
106
|
+
self.llm_query_repo.rollback()
|
|
107
|
+
raise IAToolkitException(IAToolkitException.ErrorType.DATABASE_ERROR, str(e))
|
|
108
|
+
|
|
109
|
+
def register_system_prompts(self):
|
|
110
|
+
"""
|
|
111
|
+
Synchronizes system prompts defined in Dispatcher/Code to Database.
|
|
112
|
+
"""
|
|
113
|
+
try:
|
|
114
|
+
defined_names = set()
|
|
115
|
+
|
|
116
|
+
for i, prompt_data in enumerate(_SYSTEM_PROMPTS):
|
|
117
|
+
prompt_name = prompt_data['name']
|
|
118
|
+
defined_names.add(prompt_name)
|
|
119
|
+
|
|
120
|
+
new_prompt = Prompt(
|
|
121
|
+
company_id=None, # System prompts have no company
|
|
122
|
+
name=prompt_name,
|
|
123
|
+
description=prompt_data['description'],
|
|
124
|
+
order=i + 1,
|
|
125
|
+
category_id=None,
|
|
126
|
+
active=True,
|
|
127
|
+
is_system_prompt=True,
|
|
128
|
+
filename=f"{prompt_name}.prompt",
|
|
129
|
+
custom_fields=[]
|
|
130
|
+
)
|
|
131
|
+
self.llm_query_repo.create_or_update_prompt(new_prompt)
|
|
132
|
+
|
|
133
|
+
# Cleanup old system prompts
|
|
134
|
+
existing_sys_prompts = self.llm_query_repo.get_system_prompts()
|
|
135
|
+
for p in existing_sys_prompts:
|
|
136
|
+
if p.name not in defined_names:
|
|
137
|
+
self.llm_query_repo.session.delete(p)
|
|
138
|
+
|
|
139
|
+
self.llm_query_repo.commit()
|
|
140
|
+
|
|
141
|
+
except Exception as e:
|
|
142
|
+
self.llm_query_repo.rollback()
|
|
143
|
+
raise IAToolkitException(IAToolkitException.ErrorType.DATABASE_ERROR, str(e))
|
|
144
|
+
|
|
145
|
+
def create_prompt(self,
|
|
146
|
+
prompt_name: str,
|
|
147
|
+
description: str,
|
|
148
|
+
order: int,
|
|
149
|
+
company: Company = None,
|
|
150
|
+
category: PromptCategory = None,
|
|
151
|
+
active: bool = True,
|
|
152
|
+
is_system_prompt: bool = False,
|
|
153
|
+
custom_fields: list = []
|
|
154
|
+
):
|
|
155
|
+
"""
|
|
156
|
+
Direct creation method (used by sync or direct calls).
|
|
157
|
+
Validates file existence before creating DB entry.
|
|
158
|
+
"""
|
|
159
|
+
prompt_filename = prompt_name.lower() + '.prompt'
|
|
160
|
+
if is_system_prompt:
|
|
161
|
+
if not importlib.resources.files('iatoolkit.system_prompts').joinpath(prompt_filename).is_file():
|
|
162
|
+
raise IAToolkitException(IAToolkitException.ErrorType.INVALID_NAME,
|
|
163
|
+
f'missing system prompt file: {prompt_filename}')
|
|
164
|
+
else:
|
|
165
|
+
if not self.asset_repo.exists(company.short_name, AssetType.PROMPT, prompt_filename):
|
|
166
|
+
raise IAToolkitException(IAToolkitException.ErrorType.INVALID_NAME,
|
|
167
|
+
f'missing prompt file: {prompt_filename} in prompts/')
|
|
168
|
+
|
|
169
|
+
if custom_fields:
|
|
170
|
+
for f in custom_fields:
|
|
171
|
+
if ('data_key' not in f) or ('label' not in f):
|
|
172
|
+
raise IAToolkitException(IAToolkitException.ErrorType.INVALID_PARAMETER,
|
|
173
|
+
f'The field "custom_fields" must contain the following keys: data_key y label')
|
|
174
|
+
|
|
175
|
+
# add default value for data_type
|
|
176
|
+
if 'type' not in f:
|
|
177
|
+
f['type'] = 'text'
|
|
178
|
+
|
|
179
|
+
prompt = Prompt(
|
|
180
|
+
company_id=company.id if company else None,
|
|
181
|
+
name=prompt_name,
|
|
182
|
+
description=description,
|
|
183
|
+
order=order,
|
|
184
|
+
category_id=category.id if category and not is_system_prompt else None,
|
|
185
|
+
active=active,
|
|
186
|
+
filename=prompt_filename,
|
|
187
|
+
is_system_prompt=is_system_prompt,
|
|
188
|
+
custom_fields=custom_fields
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
self.llm_query_repo.create_or_update_prompt(prompt)
|
|
193
|
+
except Exception as e:
|
|
194
|
+
raise IAToolkitException(IAToolkitException.ErrorType.DATABASE_ERROR,
|
|
195
|
+
f'error creating prompt "{prompt_name}": {str(e)}')
|
|
196
|
+
|
|
197
|
+
def get_prompt_content(self, company: Company, prompt_name: str):
|
|
198
|
+
try:
|
|
199
|
+
# get the user prompt
|
|
200
|
+
user_prompt = self.llm_query_repo.get_prompt_by_name(company, prompt_name)
|
|
201
|
+
if not user_prompt:
|
|
202
|
+
raise IAToolkitException(IAToolkitException.ErrorType.DOCUMENT_NOT_FOUND,
|
|
203
|
+
f"prompt not found '{prompt_name}' for company '{company.short_name}'")
|
|
204
|
+
|
|
205
|
+
try:
|
|
206
|
+
user_prompt_content = self.asset_repo.read_text(
|
|
207
|
+
company.short_name,
|
|
208
|
+
AssetType.PROMPT,
|
|
209
|
+
user_prompt.filename
|
|
210
|
+
)
|
|
211
|
+
except FileNotFoundError:
|
|
212
|
+
raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
|
|
213
|
+
f"prompt file '{user_prompt.filename}' does not exist for company '{company.short_name}'")
|
|
214
|
+
except Exception as e:
|
|
215
|
+
raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
|
|
216
|
+
f"error while reading prompt: '{prompt_name}': {e}")
|
|
217
|
+
|
|
218
|
+
return user_prompt_content
|
|
219
|
+
|
|
220
|
+
except IAToolkitException:
|
|
221
|
+
raise
|
|
222
|
+
except Exception as e:
|
|
223
|
+
logging.exception(
|
|
224
|
+
f"error loading prompt '{prompt_name}' content for '{company.short_name}': {e}")
|
|
225
|
+
raise IAToolkitException(IAToolkitException.ErrorType.PROMPT_ERROR,
|
|
226
|
+
f'error loading prompt "{prompt_name}" content for company {company.short_name}: {str(e)}')
|
|
227
|
+
|
|
228
|
+
def get_system_prompt(self):
|
|
229
|
+
try:
|
|
230
|
+
system_prompt_content = []
|
|
231
|
+
|
|
232
|
+
# read all the system prompts from the database
|
|
233
|
+
system_prompts = self.llm_query_repo.get_system_prompts()
|
|
234
|
+
|
|
235
|
+
for prompt in system_prompts:
|
|
236
|
+
try:
|
|
237
|
+
content = importlib.resources.read_text('iatoolkit.system_prompts', prompt.filename)
|
|
238
|
+
system_prompt_content.append(content)
|
|
239
|
+
except FileNotFoundError:
|
|
240
|
+
logging.warning(f"Prompt file does not exist in the package: {prompt.filename}")
|
|
241
|
+
except Exception as e:
|
|
242
|
+
raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
|
|
243
|
+
f"error reading system prompt '{prompt.filename}': {e}")
|
|
244
|
+
|
|
245
|
+
# join the system prompts into a single string
|
|
246
|
+
return "\n".join(system_prompt_content)
|
|
247
|
+
|
|
248
|
+
except IAToolkitException:
|
|
249
|
+
raise
|
|
250
|
+
except Exception as e:
|
|
251
|
+
logging.exception(
|
|
252
|
+
f"Error al obtener el contenido del prompt de sistema: {e}")
|
|
253
|
+
raise IAToolkitException(IAToolkitException.ErrorType.PROMPT_ERROR,
|
|
254
|
+
f'error reading the system prompts": {str(e)}')
|
|
255
|
+
|
|
256
|
+
def get_user_prompts(self, company_short_name: str) -> dict:
|
|
257
|
+
try:
|
|
258
|
+
# validate company
|
|
259
|
+
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
260
|
+
if not company:
|
|
261
|
+
return {"error": self.i18n_service.t('errors.company_not_found', company_short_name=company_short_name)}
|
|
262
|
+
|
|
263
|
+
# get all the prompts
|
|
264
|
+
all_prompts = self.llm_query_repo.get_prompts(company)
|
|
265
|
+
|
|
266
|
+
# group by category
|
|
267
|
+
prompts_by_category = defaultdict(list)
|
|
268
|
+
for prompt in all_prompts:
|
|
269
|
+
if prompt.active:
|
|
270
|
+
if prompt.category:
|
|
271
|
+
cat_key = (prompt.category.order, prompt.category.name)
|
|
272
|
+
prompts_by_category[cat_key].append(prompt)
|
|
273
|
+
|
|
274
|
+
# sort each category by order
|
|
275
|
+
for cat_key in prompts_by_category:
|
|
276
|
+
prompts_by_category[cat_key].sort(key=lambda p: p.order)
|
|
277
|
+
|
|
278
|
+
categorized_prompts = []
|
|
279
|
+
|
|
280
|
+
# sort categories by order
|
|
281
|
+
sorted_categories = sorted(prompts_by_category.items(), key=lambda item: item[0][0])
|
|
282
|
+
|
|
283
|
+
for (cat_order, cat_name), prompts in sorted_categories:
|
|
284
|
+
categorized_prompts.append({
|
|
285
|
+
'category_name': cat_name,
|
|
286
|
+
'category_order': cat_order,
|
|
287
|
+
'prompts': [
|
|
288
|
+
{
|
|
289
|
+
'prompt': p.name,
|
|
290
|
+
'description': p.description,
|
|
291
|
+
'custom_fields': p.custom_fields,
|
|
292
|
+
'order': p.order
|
|
293
|
+
}
|
|
294
|
+
for p in prompts
|
|
295
|
+
]
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
return {'message': categorized_prompts}
|
|
299
|
+
|
|
300
|
+
except Exception as e:
|
|
301
|
+
logging.error(f"error in get_prompts: {e}")
|
|
302
|
+
return {'error': str(e)}
|
|
303
|
+
|