IO4IT 4.0.25__tar.gz → 4.0.26__tar.gz

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.
Files changed (115) hide show
  1. {io4it-4.0.25 → io4it-4.0.26}/PKG-INFO +1 -1
  2. {io4it-4.0.25 → io4it-4.0.26}/io4it.egg-info/PKG-INFO +1 -1
  3. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/custom_api.py +84 -43
  4. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWCustomLLMApi.py +15 -3
  5. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +2 -2
  6. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWProcessPoolExecutor.py +44 -21
  7. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owprocesspoolexecutor.ui +17 -30
  8. {io4it-4.0.25 → io4it-4.0.26}/setup.py +1 -1
  9. {io4it-4.0.25 → io4it-4.0.26}/io4it.egg-info/SOURCES.txt +0 -0
  10. {io4it-4.0.25 → io4it-4.0.26}/io4it.egg-info/dependency_links.txt +0 -0
  11. {io4it-4.0.25 → io4it-4.0.26}/io4it.egg-info/entry_points.txt +0 -0
  12. {io4it-4.0.25 → io4it-4.0.26}/io4it.egg-info/namespace_packages.txt +0 -0
  13. {io4it-4.0.25 → io4it-4.0.26}/io4it.egg-info/requires.txt +0 -0
  14. {io4it-4.0.25 → io4it-4.0.26}/io4it.egg-info/top_level.txt +0 -0
  15. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/__init__.py +0 -0
  16. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
  17. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
  18. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/toolViews/designer/key_manager_ui.ui +0 -0
  19. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/toolViews/designer/link_workflow_manager_ui.ui +0 -0
  20. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/toolViews/key_manager_ui.py +0 -0
  21. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/toolViews/linkHTLMWorkflow_manager_ui.py +0 -0
  22. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/__init__.py +0 -0
  23. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/environment_collector.py +0 -0
  24. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/file2images.py +0 -0
  25. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/keys_manager.py +0 -0
  26. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/mail.py +0 -0
  27. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/pool_exec_utils.py +0 -0
  28. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/pst_extractor/TigerODMPST.dll +0 -0
  29. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/pst_extractor/__init__.py +0 -0
  30. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/pst_extractor/export_pst.py +0 -0
  31. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/pst_extractor/libpff.dll +0 -0
  32. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/pst_extractor/z.dll +0 -0
  33. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/secret_manager.py +0 -0
  34. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/utils/utils_md.py +0 -0
  35. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWChatGpt.py +0 -0
  36. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +0 -0
  37. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py +0 -0
  38. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py +0 -0
  39. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py +0 -0
  40. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWJsonToDataTable.py +0 -0
  41. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWMD2HTML.py +0 -0
  42. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWMarkdownLoader.py +0 -0
  43. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -0
  44. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWOfficeNormalizer.py +0 -0
  45. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWPPTX2JPG.py +0 -0
  46. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWParserHTML.py +0 -0
  47. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWPdfType.py +0 -0
  48. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWPipAuditor.py +0 -0
  49. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +0 -0
  50. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWS3downloader.py +0 -0
  51. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWS3list.py +0 -0
  52. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWWebSearch.py +0 -0
  53. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWXLSX_insert.py +0 -0
  54. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWmailLoader.py +0 -0
  55. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWmailSender.py +0 -0
  56. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +0 -0
  57. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
  58. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
  59. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
  60. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/ow_extract_tables_docx_to_xlsx.ui +0 -0
  61. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
  62. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/ow_json_to_data_table.ui +0 -0
  63. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -0
  64. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owcustomllmapi.ui +0 -0
  65. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
  66. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui +0 -0
  67. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -0
  68. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owfile2images.ui +0 -0
  69. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui +0 -0
  70. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owinsertdatatoexcel.ui +0 -0
  71. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
  72. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
  73. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -0
  74. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owmarkdownloader.ui +0 -0
  75. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owmd2html.ui +0 -0
  76. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owofficenormalizer.ui +0 -0
  77. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owparserhtml.ui +0 -0
  78. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owpdftype.ui +0 -0
  79. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owpipauditor.ui +0 -0
  80. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
  81. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
  82. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/owwebsearch.ui +0 -0
  83. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
  84. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
  85. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
  86. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/check_pdf.png +0 -0
  87. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
  88. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/dep_md_old.png +0 -0
  89. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
  90. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
  91. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/extract_table.png +0 -0
  92. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/file2images.png +0 -0
  93. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
  94. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/html.png +0 -0
  95. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/json-file.png +0 -0
  96. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
  97. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/load_md.png +0 -0
  98. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
  99. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
  100. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
  101. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/monitor-email.svg +0 -0
  102. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/office_normalizer.png +0 -0
  103. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/owcustomllmapi.svg +0 -0
  104. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/owmd2html.svg +0 -0
  105. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/pip_auditor.png +0 -0
  106. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/process_pool_executor.png +0 -0
  107. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
  108. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
  109. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
  110. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/websearch.png +0 -0
  111. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
  112. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons/xlsx_insert.png +0 -0
  113. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
  114. {io4it-4.0.25 → io4it-4.0.26}/orangecontrib/__init__.py +0 -0
  115. {io4it-4.0.25 → io4it-4.0.26}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: io4it
3
- Version: 4.0.25
3
+ Version: 4.0.26
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: io4it
3
- Version: 4.0.25
3
+ Version: 4.0.26
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -1,11 +1,18 @@
1
- import base64
2
- import mimetypes
3
1
  import os
2
+ import re
3
+ import json
4
+ import copy
5
+ import numpy as np
4
6
 
5
7
  import requests
6
8
 
7
- import Orange.data
8
- from Orange.data import StringVariable
9
+ from Orange.data import StringVariable, Table
10
+
11
+
12
+ if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
13
+ from Orange.widgets.orangecontrib.AAIT.llm.answers_llama import write_tokens_to_file, prompt_to_messages, conv_to_messages
14
+ else:
15
+ from orangecontrib.AAIT.llm.answers_llama import write_tokens_to_file, prompt_to_messages, conv_to_messages
9
16
 
10
17
 
11
18
  def build_headers(header_name, auth_scheme, api_key):
@@ -15,37 +22,25 @@ def build_headers(header_name, auth_scheme, api_key):
15
22
  return {"Content-Type": "application/json", header_name: value}
16
23
 
17
24
 
18
- def image_to_data_uri(file_path):
19
- """Encode a local image file as a base64 data URI."""
20
- mime_type, _ = mimetypes.guess_type(file_path)
21
- mime_type = mime_type or "application/octet-stream"
22
- with open(file_path, "rb") as f:
23
- encoded = base64.b64encode(f.read()).decode("utf-8")
24
- return f"data:{mime_type};base64,{encoded}"
25
-
26
-
27
- def build_user_content(prompt, image_paths):
28
- """Build the 'content' field of a user message, attaching images when provided."""
29
- if not image_paths:
30
- return str(prompt)
31
-
32
- content = []
33
- for image_path in image_paths:
34
- image_path = image_path.strip().strip("'").strip('"')
35
- if not image_path:
36
- continue
37
- if not os.path.exists(image_path):
38
- content.append({"type": "text", "text": f"[ERROR] Image not found: {image_path}"})
39
- continue
40
- try:
41
- content.append({"type": "image_url", "image_url": {"url": image_to_data_uri(image_path)}})
42
- except Exception as e:
43
- content.append({"type": "text", "text": f"[ERROR] Unable to read image {image_path}: {e}"})
44
- content.append({"type": "text", "text": str(prompt)})
45
- return content
25
+ def search_for_streamed_token(decoded_line):
26
+ r"""
27
+ /!\ This function is meant to be updated whenever a new response format is identified /!\
46
28
 
47
-
48
- def call_chat_completion(prompt, system_prompt, config, image_paths=None):
29
+ Parse a decoded stream response "line" to find the token generated by a LLM.
30
+ """
31
+ known_keys = ["content", "reasoning"]
32
+ dict_regex = r"\{[\s\S]*\}"
33
+ match = re.search(dict_regex, decoded_line)
34
+ if not match:
35
+ return "Token not found"
36
+
37
+ json_data = json.loads(match.group())
38
+ delta = json_data["choices"][0]["delta"]
39
+ token = next((delta[key] for key in known_keys if key in delta), "Token not found")
40
+ return token
41
+
42
+
43
+ def call_chat_completion(messages, config, stream=False, workflow_id="Request_RAG"):
49
44
  """
50
45
  Call a /chat/completions endpoint using the widely adopted chat-completions
51
46
  message format. Vision-capable models can be reached by passing image_paths,
@@ -58,11 +53,6 @@ def call_chat_completion(prompt, system_prompt, config, image_paths=None):
58
53
  url = config["base_url"].rstrip("/") + config["route"]
59
54
  headers = build_headers(config["header_name"], config["auth_scheme"], config["api_key"])
60
55
 
61
- messages = []
62
- if system_prompt:
63
- messages.append({"role": "system", "content": str(system_prompt)})
64
- messages.append({"role": "user", "content": build_user_content(prompt, image_paths)})
65
-
66
56
  payload = {
67
57
  "model": config["model"],
68
58
  "messages": messages,
@@ -86,10 +76,25 @@ def call_chat_completion(prompt, system_prompt, config, image_paths=None):
86
76
  proxy_url = config.get("proxy_url") or ""
87
77
  kwargs["proxies"] = {"http": proxy_url, "https": proxy_url}
88
78
 
89
- response = requests.post(url, headers=headers, json=payload, **kwargs)
79
+ response = requests.post(url, headers=headers, json=payload, stream=stream, **kwargs)
90
80
  response.raise_for_status()
91
- data = response.json()
92
- return data["choices"][0]["message"]["content"]
81
+
82
+ if not stream:
83
+ data = response.json()
84
+ return data["choices"][0]["message"]["content"]
85
+ else:
86
+ answer = ""
87
+ for line in response.iter_lines():
88
+ if line:
89
+ decoded_line = line.decode("utf-8")
90
+ try:
91
+ token = search_for_streamed_token(decoded_line)
92
+ except Exception as e:
93
+ token = "Error"
94
+ print("An error occured when trying to get token from stream response:", e)
95
+ answer += token
96
+ write_tokens_to_file(token, workflow_id=workflow_id)
97
+ return answer
93
98
 
94
99
 
95
100
  def generate_answers(data, config, progress_callback=None):
@@ -116,8 +121,9 @@ def generate_answers(data, config, progress_callback=None):
116
121
  prompt = prompts[i]
117
122
  system_prompt = system_prompts[i] if system_prompts is not None else None
118
123
  image_paths = image_paths_column[i].split(";") if image_paths_column is not None else None
124
+ messages = prompt_to_messages(prompt, system_prompt, image_paths)
119
125
  try:
120
- answer = call_chat_completion(prompt, system_prompt, config, image_paths)
126
+ answer = call_chat_completion(messages, config, stream=True)
121
127
  except requests.HTTPError as e:
122
128
  body = e.response.text if e.response is not None else str(e)
123
129
  answer = f"[ERROR] HTTP {e.response.status_code if e.response is not None else '?'}: {body}"
@@ -130,3 +136,38 @@ def generate_answers(data, config, progress_callback=None):
130
136
 
131
137
  answer_var = StringVariable("Answer")
132
138
  return data.add_column(answer_var, answers)
139
+
140
+
141
+
142
+ def continue_conversation(table, config, progress_callback=None):
143
+ """
144
+ Runs call_chat_completion considering the table as a conversation (list of messages).
145
+ """
146
+ data = copy.deepcopy(table)
147
+ messages = conv_to_messages(data)
148
+ if not messages:
149
+ return data
150
+
151
+ try:
152
+ answer = call_chat_completion(messages, config, stream=True)
153
+ except requests.HTTPError as e:
154
+ body = e.response.text if e.response is not None else str(e)
155
+ answer = f"[ERROR] HTTP {e.response.status_code if e.response is not None else '?'}: {body}"
156
+ except Exception as e:
157
+ answer = f"[ERROR] {e}"
158
+
159
+ # Create output table
160
+ meta = data.metas[-1].copy()
161
+ meta_names = [m.name for m in data.domain.metas]
162
+ meta[meta_names.index("role")] = "assistant"
163
+ meta[meta_names.index("type")] = "text"
164
+ meta[meta_names.index("content")] = answer
165
+ empty_x = np.zeros((1, len(data.domain.attributes)))
166
+
167
+ new_row = Table.from_numpy(
168
+ data.domain,
169
+ X=empty_x,
170
+ metas=np.array([meta], dtype=object)
171
+ )
172
+ out_data = Table.concatenate([data, new_row])
173
+ return out_data
@@ -13,11 +13,13 @@ from AnyQt.QtWidgets import (
13
13
  if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
14
14
  from Orange.widgets.orangecontrib.IO4IT.utils import custom_api
15
15
  from Orange.widgets.orangecontrib.AAIT.utils import thread_management
16
+ from Orange.widgets.orangecontrib.AAIT.llm.answers_llama import identify_table_type
16
17
  from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
17
18
  from Orange.widgets.orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
18
19
  else:
19
20
  from orangecontrib.IO4IT.utils import custom_api
20
21
  from orangecontrib.AAIT.utils import thread_management
22
+ from orangecontrib.AAIT.llm.answers_llama import identify_table_type
21
23
  from orangecontrib.AAIT.utils.import_uic import uic
22
24
  from orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
23
25
 
@@ -192,8 +194,14 @@ class OWCustomLLMApi(widget.OWWidget):
192
194
  if self.data is None:
193
195
  self.Outputs.data.send(None)
194
196
  return
195
- if "prompt" not in self.data.domain:
196
- self.error("Input table needs a 'prompt' column.")
197
+
198
+ table_type = identify_table_type(self.data)
199
+ if table_type == "error":
200
+ self.error("The table must contain either (StringVariable):\n- role + type + content\nor:\n- prompt (image paths)")
201
+ self.Outputs.data.send(None)
202
+ return
203
+ elif table_type == "multiple":
204
+ self.error("Cannot have role/type/content and prompt simultaneously.")
197
205
  self.Outputs.data.send(None)
198
206
  return
199
207
 
@@ -213,7 +221,11 @@ class OWCustomLLMApi(widget.OWWidget):
213
221
  self.progressBarInit()
214
222
  self.textBrowser.setText("")
215
223
 
216
- self.thread = thread_management.Thread(custom_api.generate_answers, self.data, self.build_config())
224
+
225
+ if table_type == "batch":
226
+ self.thread = thread_management.Thread(custom_api.generate_answers, self.data, self.build_config())
227
+ elif table_type == "conversation":
228
+ self.thread = thread_management.Thread(custom_api.continue_conversation, self.data, self.build_config())
217
229
  self.thread.progress.connect(self.handle_progress)
218
230
  self.thread.result.connect(self.handle_result)
219
231
  self.thread.finish.connect(self.handle_finish)
@@ -265,8 +265,8 @@ class OWExportMarkdown(widget.OWWidget):
265
265
  )
266
266
  self.ajouter_entete_pied_pptx(
267
267
  pptx_out,
268
- "Orange AI – Présentation",
269
- "Page générée automatiquement"
268
+ "TigerODM – Présentation",
269
+ "Page générée automatiquement par IA"
270
270
  )
271
271
  produced_pptx = pptx_out if os.path.isfile(pptx_out) else ""
272
272
 
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import sys
3
- from AnyQt.QtWidgets import QSpinBox, QLabel, QPushButton, QGroupBox, QCheckBox
3
+ from AnyQt.QtWidgets import QSpinBox, QLabel, QPushButton, QGroupBox, QCheckBox, QApplication
4
+ from AnyQt.QtCore import QTimer
4
5
  from Orange.widgets import widget
5
6
  from Orange.widgets.utils.signals import Output
6
7
  from Orange.widgets.settings import Setting
@@ -8,9 +9,11 @@ from Orange.widgets.settings import Setting
8
9
  if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
9
10
  from Orange.widgets.orangecontrib.IO4IT.utils import pool_exec_utils
10
11
  from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
12
+ from Orange.widgets.orangecontrib.AAIT.utils import help_management
11
13
  else:
12
14
  from orangecontrib.IO4IT.utils import pool_exec_utils
13
15
  from orangecontrib.AAIT.utils.import_uic import uic
16
+ from orangecontrib.AAIT.utils import help_management
14
17
 
15
18
 
16
19
  class OWProcessPoolExecutor(widget.OWWidget):
@@ -24,7 +27,8 @@ class OWProcessPoolExecutor(widget.OWWidget):
24
27
  want_control_area = False
25
28
  priority = 900
26
29
 
27
- auto_send = Setting(False)
30
+ str_workers: str = Setting("4")
31
+ str_autosend: str = Setting("False")
28
32
 
29
33
  class Outputs:
30
34
  executor = Output("ProcessPoolExecutor", object)
@@ -41,51 +45,70 @@ class OWProcessPoolExecutor(widget.OWWidget):
41
45
 
42
46
  self.cpu_label = self.findChild(QLabel, "cpu_label")
43
47
  self.spin_workers = self.findChild(QSpinBox, "spin_workers")
44
- self.btn_create = self.findChild(QPushButton, "btn_create")
45
48
  self.info_label = self.findChild(QLabel, "info_label")
46
49
  self.group_box = self.findChild(QGroupBox, "groupBox")
47
50
  self.checkBox_send = self.findChild(QCheckBox, "checkBox_send")
51
+ self.pushButton_send = self.findChild(QPushButton, "pushButton_send")
48
52
 
53
+ # Initialisation de la vue du nombre de CPU et SpinBox
54
+ max_cpus = max(1, pool_exec_utils.available_cpus())
49
55
  if self.cpu_label:
50
56
  self.cpu_label.setText(pool_exec_utils.cpu_label_text())
51
57
 
52
58
  if self.spin_workers:
53
59
  self.spin_workers.setMinimum(1)
54
- max_cpus = max(1, pool_exec_utils.available_cpus())
55
60
  self.spin_workers.setMaximum(max_cpus)
56
- self.spin_workers.setValue(min(4, max_cpus))
61
+
62
+ # Restauration du nombre de workers depuis les Settings
63
+ try:
64
+ val = int(self.str_workers)
65
+ except ValueError:
66
+ val = min(4, max_cpus)
67
+ self.spin_workers.setValue(min(max(1, val), max_cpus))
57
68
  self.spin_workers.valueChanged.connect(self._on_workers_changed)
58
69
 
70
+ # Restauration de l'état Auto Send
59
71
  if self.checkBox_send:
60
- self.checkBox_send.setChecked(self.auto_send)
61
- self.checkBox_send.toggled.connect(self._on_autorun_toggled)
72
+ self.checkBox_send.setChecked(self.str_autosend == "True")
73
+ self.checkBox_send.clicked.connect(self._on_autorun_toggled)
62
74
 
63
- if self.btn_create:
64
- self.btn_create.setEnabled(not self.auto_send)
65
- self.btn_create.clicked.connect(self.create_or_update_clicked)
75
+ # Bouton d'exécution manuelle
76
+ if self.pushButton_send:
77
+ self.pushButton_send.setEnabled(self.str_autosend != "True")
78
+ self.pushButton_send.clicked.connect(self.create_or_update_clicked)
66
79
 
67
80
  self.error("")
68
81
  self.warning("")
69
82
  self.post_initialized()
70
83
 
71
- # Lancement automatique initial si coché
72
- if self.auto_send:
84
+ QTimer.singleShot(0, lambda: help_management.override_help_action(self))
85
+
86
+ # Lancement automatique initial si activé dans les Settings
87
+ if self.str_autosend == "True":
73
88
  self.create_or_update_clicked()
74
89
 
75
90
  # ------------------------------------------------------------------
76
- # Slots UI
91
+ # Settings & UI Synchronization
77
92
  # ------------------------------------------------------------------
78
- def _on_autorun_toggled(self, checked: bool):
79
- self.auto_send = checked
80
- if self.btn_create:
81
- self.btn_create.setEnabled(not self.auto_send)
82
- # On relance automatiquement s'il vient d'être activé
83
- if self.auto_send:
93
+ def update_setting_from_qt_view(self):
94
+ """Met à jour les attributs de Setting à partir des composants Qt."""
95
+ if self.spin_workers:
96
+ self.str_workers = str(self.spin_workers.value())
97
+
98
+ if self.checkBox_send:
99
+ self.str_autosend = "True" if self.checkBox_send.isChecked() else "False"
100
+
101
+ if self.pushButton_send and self.checkBox_send:
102
+ self.pushButton_send.setEnabled(not self.checkBox_send.isChecked())
103
+
104
+ def _on_autorun_toggled(self):
105
+ self.update_setting_from_qt_view()
106
+ if self.str_autosend == "True":
84
107
  self.create_or_update_clicked()
85
108
 
86
109
  def _on_workers_changed(self):
87
- """Déclenche la mise à jour si le nombre de workers change et que auto_send est actif."""
88
- if self.auto_send:
110
+ self.update_setting_from_qt_view()
111
+ if self.str_autosend == "True":
89
112
  self.create_or_update_clicked()
90
113
 
91
114
  # ------------------------------------------------------------------
@@ -11,15 +11,15 @@
11
11
  </rect>
12
12
  </property>
13
13
  <property name="windowTitle">
14
- <string>Form</string>
14
+ <string>Process Pool Executor</string>
15
15
  </property>
16
16
  <widget class="QGroupBox" name="groupBox">
17
17
  <property name="geometry">
18
18
  <rect>
19
19
  <x>10</x>
20
- <y>30</y>
20
+ <y>20</y>
21
21
  <width>451</width>
22
- <height>201</height>
22
+ <height>200</height>
23
23
  </rect>
24
24
  </property>
25
25
  <property name="title">
@@ -29,9 +29,9 @@
29
29
  <property name="geometry">
30
30
  <rect>
31
31
  <x>10</x>
32
- <y>16</y>
32
+ <y>20</y>
33
33
  <width>431</width>
34
- <height>51</height>
34
+ <height>45</height>
35
35
  </rect>
36
36
  </property>
37
37
  <property name="text">
@@ -50,7 +50,7 @@
50
50
  <x>10</x>
51
51
  <y>70</y>
52
52
  <width>431</width>
53
- <height>21</height>
53
+ <height>20</height>
54
54
  </rect>
55
55
  </property>
56
56
  <property name="text">
@@ -61,9 +61,9 @@
61
61
  <property name="geometry">
62
62
  <rect>
63
63
  <x>10</x>
64
- <y>110</y>
64
+ <y>100</y>
65
65
  <width>431</width>
66
- <height>21</height>
66
+ <height>20</height>
67
67
  </rect>
68
68
  </property>
69
69
  <property name="text">
@@ -74,40 +74,27 @@
74
74
  <property name="geometry">
75
75
  <rect>
76
76
  <x>10</x>
77
- <y>140</y>
77
+ <y>130</y>
78
78
  <width>431</width>
79
- <height>22</height>
79
+ <height>25</height>
80
80
  </rect>
81
81
  </property>
82
82
  </widget>
83
- <widget class="QPushButton" name="btn_create">
84
- <property name="geometry">
85
- <rect>
86
- <x>10</x>
87
- <y>170</y>
88
- <width>431</width>
89
- <height>23</height>
90
- </rect>
91
- </property>
92
- <property name="text">
93
- <string>(Re)create / Update executor</string>
94
- </property>
95
- </widget>
96
83
  </widget>
97
84
  <widget class="QPushButton" name="pushButton_send">
98
85
  <property name="enabled">
99
- <bool>false</bool>
86
+ <bool>true</bool>
100
87
  </property>
101
88
  <property name="geometry">
102
89
  <rect>
103
90
  <x>170</x>
104
- <y>244</y>
91
+ <y>235</y>
105
92
  <width>291</width>
106
- <height>31</height>
93
+ <height>32</height>
107
94
  </rect>
108
95
  </property>
109
96
  <property name="text">
110
- <string>Run</string>
97
+ <string>(Re)create / Update executor</string>
111
98
  </property>
112
99
  </widget>
113
100
  <widget class="QCheckBox" name="checkBox_send">
@@ -117,9 +104,9 @@
117
104
  <property name="geometry">
118
105
  <rect>
119
106
  <x>10</x>
120
- <y>250</y>
121
- <width>131</width>
122
- <height>16</height>
107
+ <y>240</y>
108
+ <width>150</width>
109
+ <height>20</height>
123
110
  </rect>
124
111
  </property>
125
112
  <property name="text">
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  # Configuration
4
4
  NAME = "io4it"
5
- VERSION = "4.0.25"
5
+ VERSION = "4.0.26"
6
6
 
7
7
  INSTALL_REQUIRES = [
8
8
  "torchvision",
File without changes
File without changes