datamule 1.0.2__py3-none-any.whl → 1.0.6__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.
Files changed (43) hide show
  1. datamule/__init__.py +2 -13
  2. datamule/document.py +0 -1
  3. datamule/helper.py +85 -105
  4. datamule/portfolio.py +105 -29
  5. datamule/submission.py +0 -38
  6. {datamule-1.0.2.dist-info → datamule-1.0.6.dist-info}/METADATA +2 -8
  7. datamule-1.0.6.dist-info/RECORD +10 -0
  8. datamule/book/__init__.py +0 -0
  9. datamule/book/book.py +0 -34
  10. datamule/book/eftsquery.py +0 -127
  11. datamule/book/xbrl_retriever.py +0 -88
  12. datamule/data/company_former_names.csv +0 -8148
  13. datamule/data/company_metadata.csv +0 -10049
  14. datamule/data/company_tickers.csv +0 -9999
  15. datamule/data/sec-glossary.csv +0 -728
  16. datamule/data/xbrl_descriptions.csv +0 -10024
  17. datamule/downloader/downloader.py +0 -374
  18. datamule/downloader/premiumdownloader.py +0 -335
  19. datamule/mapping_dicts/txt_mapping_dicts.py +0 -232
  20. datamule/mapping_dicts/xml_mapping_dicts.py +0 -19
  21. datamule/monitor.py +0 -238
  22. datamule/mulebot/__init__.py +0 -1
  23. datamule/mulebot/helper.py +0 -35
  24. datamule/mulebot/mulebot.py +0 -130
  25. datamule/mulebot/mulebot_server/__init__.py +0 -1
  26. datamule/mulebot/mulebot_server/server.py +0 -87
  27. datamule/mulebot/mulebot_server/static/css/minimalist.css +0 -174
  28. datamule/mulebot/mulebot_server/static/scripts/artifacts.js +0 -68
  29. datamule/mulebot/mulebot_server/static/scripts/chat.js +0 -92
  30. datamule/mulebot/mulebot_server/static/scripts/filingArtifacts.js +0 -56
  31. datamule/mulebot/mulebot_server/static/scripts/listArtifacts.js +0 -15
  32. datamule/mulebot/mulebot_server/static/scripts/main.js +0 -57
  33. datamule/mulebot/mulebot_server/static/scripts/prefilledPrompt.js +0 -27
  34. datamule/mulebot/mulebot_server/static/scripts/suggestions.js +0 -47
  35. datamule/mulebot/mulebot_server/static/scripts/tableArtifacts.js +0 -129
  36. datamule/mulebot/mulebot_server/static/scripts/utils.js +0 -28
  37. datamule/mulebot/mulebot_server/templates/chat-minimalist.html +0 -91
  38. datamule/mulebot/search.py +0 -52
  39. datamule/mulebot/tools.py +0 -82
  40. datamule/packageupdater.py +0 -207
  41. datamule-1.0.2.dist-info/RECORD +0 -43
  42. {datamule-1.0.2.dist-info → datamule-1.0.6.dist-info}/WHEEL +0 -0
  43. {datamule-1.0.2.dist-info → datamule-1.0.6.dist-info}/top_level.txt +0 -0
@@ -1,68 +0,0 @@
1
- // artifacts.js
2
- import { renderTableArtifact } from './tableArtifacts.js';
3
- import { renderListArtifact } from './listArtifacts.js';
4
- import { renderFilingArtifact } from './filingArtifacts.js';
5
-
6
- export let artifactContent = null;
7
- export let artifactContainer = null;
8
- export let suggestionContainer = null;
9
- export let toggleArtifactsBtn = null;
10
- export let allArtifacts = [];
11
-
12
- export function initializeArtifacts() {
13
- artifactContent = document.getElementById('artifact-content');
14
- artifactContainer = document.getElementById('artifact-container');
15
- suggestionContainer = document.querySelector('.suggestion-box');
16
- toggleArtifactsBtn = document.getElementById('toggle-artifacts');
17
-
18
- if (toggleArtifactsBtn) {
19
- toggleArtifactsBtn.addEventListener('click', toggleArtifacts);
20
- }
21
-
22
- // Initially hide artifacts
23
- hideArtifacts();
24
- }
25
-
26
- export function renderArtifact(artifactData, artifactType) {
27
- if (artifactType === 'artifact-table') {
28
- const newArtifacts = Array.isArray(artifactData) ? artifactData : [artifactData];
29
- newArtifacts.forEach(artifact => {
30
- artifact.type = artifactType;
31
- });
32
- allArtifacts = [...allArtifacts, ...newArtifacts];
33
- renderTableArtifact(artifactData[0]);
34
- }
35
- else if (artifactType === 'artifact-list') {
36
- renderListArtifact(artifactData);
37
- }
38
- else if (artifactType === 'artifact-filing') {
39
- renderFilingArtifact(artifactData);
40
- }
41
- else {
42
- console.log('Unsupported artifact type:', artifactType);
43
- }
44
- }
45
-
46
- export function showArtifacts() {
47
- if (artifactContainer && suggestionContainer) {
48
- artifactContainer.style.display = 'block';
49
- suggestionContainer.style.display = 'none';
50
- if (toggleArtifactsBtn) toggleArtifactsBtn.textContent = 'Hide Artifacts';
51
- }
52
- }
53
-
54
- export function hideArtifacts() {
55
- if (artifactContainer && suggestionContainer) {
56
- artifactContainer.style.display = 'none';
57
- suggestionContainer.style.display = 'block';
58
- if (toggleArtifactsBtn) toggleArtifactsBtn.textContent = 'Show Artifacts';
59
- }
60
- }
61
-
62
- function toggleArtifacts() {
63
- if (artifactContainer.style.display === 'none') {
64
- showArtifacts();
65
- } else {
66
- hideArtifacts();
67
- }
68
- }
@@ -1,92 +0,0 @@
1
- // chat.js
2
- import { renderArtifact, showArtifacts } from './artifacts.js';
3
-
4
- let thinkingIndicator = null;
5
- let isHandlingResponse = false;
6
-
7
- export function appendMessage(sender, message) {
8
- console.log(`Appending message from ${sender}: ${message}`);
9
- const chatContainer = document.getElementById('chat-container');
10
- const messageElement = document.createElement('div');
11
- messageElement.innerHTML = `<strong>${sender}:</strong> ${message}`;
12
- chatContainer.appendChild(messageElement);
13
- scrollChatToBottom();
14
- }
15
-
16
- function scrollChatToBottom() {
17
- const chatContainer = document.getElementById('chat-container');
18
- chatContainer.scrollTop = chatContainer.scrollHeight;
19
- }
20
-
21
- export function showThinkingIndicator() {
22
- if (!thinkingIndicator) {
23
- thinkingIndicator = document.createElement('div');
24
- thinkingIndicator.className = 'thinking-indicator';
25
- thinkingIndicator.innerHTML = '<span>Bot is thinking</span><span class="dot-animation">...</span>';
26
- document.getElementById('chat-container').appendChild(thinkingIndicator);
27
- }
28
- thinkingIndicator.style.display = 'block';
29
- scrollChatToBottom();
30
- }
31
-
32
- export function hideThinkingIndicator() {
33
- if (thinkingIndicator) {
34
- thinkingIndicator.style.display = 'none';
35
- }
36
- }
37
-
38
- export async function sendMessage(message) {
39
- console.log(`Sending message: ${message}`);
40
- showThinkingIndicator();
41
- try {
42
- const response = await fetch('/chat', {
43
- method: 'POST',
44
- headers: {
45
- 'Content-Type': 'application/json',
46
- },
47
- body: JSON.stringify({ message }),
48
- });
49
- const data = await response.json();
50
- console.log('Received response:', data);
51
- return data;
52
- } finally {
53
- hideThinkingIndicator();
54
- }
55
- }
56
-
57
- export function handleResponse(response) {
58
- if (isHandlingResponse) {
59
- console.log('Already handling a response, skipping.');
60
- return;
61
- }
62
- isHandlingResponse = true;
63
- console.log('Handling response:', response);
64
-
65
- try {
66
- if (response.response.type === 'text') {
67
- appendMessage('Bot', response.response.content);
68
- } else if (response.response.type === 'artifact') {
69
- let artifactType = response.response.artifact_type;
70
- let artifactContent = response.response.content;
71
-
72
- if (artifactType === 'artifact-filing') {
73
- artifactContent = {
74
- content: response.response.content,
75
- data: response.response.data,
76
- section_id: response.response.section_id
77
- };
78
- }
79
-
80
- appendMessage('Bot', `I have prepared an ${artifactType} for you. Please check the artifact view.`);
81
- renderArtifact(artifactContent, artifactType);
82
- showArtifacts();
83
- } else {
84
- appendMessage('Bot', 'I have received a response, but it is not a supported type.');
85
- }
86
- } finally {
87
- isHandlingResponse = false;
88
- }
89
- }
90
-
91
- // Make sendMessage globally accessible
92
- window.sendMessage = sendMessage;
@@ -1,56 +0,0 @@
1
- // filingArtifacts.js
2
- export function renderFilingArtifact(artifactData) {
3
- const { content: html, data, section_id } = artifactData;
4
-
5
- const container = document.createElement('div');
6
- container.className = 'filing-container';
7
- container.style.width = '100%';
8
- container.style.height = '600px';
9
-
10
- const iframe = document.createElement('iframe');
11
- iframe.srcdoc = html;
12
- iframe.style.width = '100%';
13
- iframe.style.height = '100%';
14
- iframe.style.border = 'none';
15
-
16
- container.appendChild(iframe);
17
-
18
- const artifactContent = document.getElementById('artifact-content');
19
- if (artifactContent) {
20
- artifactContent.innerHTML = '';
21
- artifactContent.appendChild(container);
22
- }
23
-
24
- iframe.onload = () => {
25
- if (section_id) {
26
- const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
27
- const targetElement = iframeDocument.getElementById(section_id);
28
- if (targetElement) {
29
- targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
30
- }
31
- }
32
- };
33
-
34
- const buttonContainer = document.createElement('div');
35
- buttonContainer.className = 'mt-3';
36
-
37
- const downloadHtmlBtn = document.createElement('button');
38
- downloadHtmlBtn.className = 'btn btn-secondary me-2';
39
- downloadHtmlBtn.textContent = 'Download Filing HTML';
40
- downloadHtmlBtn.onclick = () => {
41
- const blob = new Blob([html], { type: 'text/html' });
42
- saveAs(blob, 'filing.html');
43
- };
44
- buttonContainer.appendChild(downloadHtmlBtn);
45
-
46
- const downloadJsonBtn = document.createElement('button');
47
- downloadJsonBtn.className = 'btn btn-secondary';
48
- downloadJsonBtn.textContent = 'Download Filing Data (JSON)';
49
- downloadJsonBtn.onclick = () => {
50
- const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
51
- saveAs(blob, 'filing_data.json');
52
- };
53
- buttonContainer.appendChild(downloadJsonBtn);
54
-
55
- artifactContent.appendChild(buttonContainer);
56
- }
@@ -1,15 +0,0 @@
1
- // listArtifacts.js
2
- export function renderListArtifact(listData) {
3
- let html = `<h4>URLs</h4><ul class="list-group">`;
4
-
5
- listData.forEach(url => {
6
- html += `<li class="list-group-item"><a href="${url}" target="_blank">${url}</a></li>`;
7
- });
8
-
9
- html += '</ul>';
10
-
11
- const artifactContent = document.getElementById('artifact-content');
12
- if (artifactContent) {
13
- artifactContent.innerHTML = html;
14
- }
15
- }
@@ -1,57 +0,0 @@
1
- // main.js
2
- import { appendMessage, sendMessage, handleResponse, showThinkingIndicator, hideThinkingIndicator } from './chat.js';
3
- import { initializeArtifacts } from './artifacts.js';
4
- import { handleDocumentClick } from './tableArtifacts.js';
5
- import { initializeSuggestions } from './suggestions.js';
6
- import { handlePrefilledPrompt } from './prefilledPrompt.js';
7
-
8
- let chatInitialized = false;
9
-
10
- function initializeChat() {
11
- if (chatInitialized) return;
12
- chatInitialized = true;
13
-
14
- console.log('Initializing chat');
15
-
16
- initializeArtifacts();
17
- initializeSuggestions();
18
-
19
- const chatForm = document.getElementById('chat-form');
20
- const userInput = document.getElementById('user-input');
21
-
22
- if (chatForm) {
23
- chatForm.addEventListener('submit', async (e) => {
24
- e.preventDefault();
25
- console.log('Form submitted');
26
- const message = userInput.value.trim();
27
- if (message) {
28
- appendMessage('You', message);
29
- userInput.value = '';
30
- showThinkingIndicator();
31
- try {
32
- const response = await sendMessage(message);
33
- handleResponse(response);
34
- } catch (error) {
35
- console.error('Error processing message:', error);
36
- } finally {
37
- hideThinkingIndicator();
38
- }
39
- }
40
- });
41
- }
42
-
43
- document.addEventListener('click', handleDocumentClick);
44
- }
45
-
46
- // Wait for the DOM to be fully loaded before initializing
47
- if (document.readyState === 'loading') {
48
- document.addEventListener('DOMContentLoaded', initializeChat);
49
- } else {
50
- initializeChat();
51
- }
52
-
53
- // Add this new event listener for the window load event
54
- window.addEventListener('load', () => {
55
- console.log('Window fully loaded, handling prefilled prompt');
56
- handlePrefilledPrompt();
57
- });
@@ -1,27 +0,0 @@
1
- // prefilledPrompt.js
2
- import { sendMessage, handleResponse, appendMessage } from './chat.js';
3
-
4
- export function handlePrefilledPrompt() {
5
- const urlParams = new URLSearchParams(window.location.search);
6
- const prefilled_prompt = urlParams.get('prompt');
7
- if (prefilled_prompt) {
8
- const userInput = document.getElementById('user-input');
9
- if (userInput) {
10
- userInput.value = prefilled_prompt;
11
- appendMessage('You', prefilled_prompt); // Show the user's message in the chat
12
- }
13
- if (typeof sendMessage === 'function') {
14
- sendMessage(prefilled_prompt).then(response => {
15
- handleResponse(response);
16
- if (userInput) {
17
- userInput.value = ''; // Clear the input field after sending
18
- }
19
- }).catch(error => {
20
- console.error('Error processing prefilled prompt:', error);
21
- if (userInput) {
22
- userInput.value = ''; // Clear the input field even if there's an error
23
- }
24
- });
25
- }
26
- }
27
- }
@@ -1,47 +0,0 @@
1
- // suggestions.js
2
- import { appendMessage, sendMessage, handleResponse, showThinkingIndicator, hideThinkingIndicator } from './chat.js';
3
- import { renderArtifact, showArtifacts } from './artifacts.js';
4
-
5
- export function initializeSuggestions() {
6
- const userInput = document.getElementById('user-input');
7
- const chatForm = document.getElementById('chat-form');
8
- const suggestionItems = document.querySelectorAll('.suggestion-item');
9
-
10
- // Function to handle suggestion click
11
- function handleSuggestionClick(event) {
12
- const suggestionText = event.target.textContent;
13
- userInput.value = suggestionText;
14
- executeChatRequest(suggestionText);
15
- userInput.value = ''; // Clear the input after executing the request
16
- }
17
-
18
- // Add click event listeners to all suggestion items
19
- suggestionItems.forEach(item => {
20
- item.addEventListener('click', handleSuggestionClick);
21
- });
22
-
23
- // Function to execute chat request
24
- async function executeChatRequest(message) {
25
- try {
26
- appendMessage('You', message);
27
- showThinkingIndicator();
28
- const response = await sendMessage(message);
29
- handleResponse(response);
30
- } catch (error) {
31
- console.error('Error executing chat request:', error);
32
- appendMessage('Bot', 'Sorry, there was an error processing your request.');
33
- } finally {
34
- hideThinkingIndicator();
35
- }
36
- }
37
-
38
- // Prevent default form submission
39
- chatForm.addEventListener('submit', function (event) {
40
- event.preventDefault();
41
- const message = userInput.value.trim();
42
- if (message) {
43
- executeChatRequest(message);
44
- userInput.value = ''; // Clear the input after executing the request
45
- }
46
- });
47
- }
@@ -1,129 +0,0 @@
1
- // tableArtifacts.js
2
- import { renderMetadata, downloadCSV } from './utils.js';
3
- import { allArtifacts } from './artifacts.js';
4
-
5
- export function renderTableArtifact(tableData) {
6
- let html = `
7
- <div class="mb-3 select-wrapper">
8
- <input type="text" id="artifact-select" class="form-control" placeholder="Select a table..." value="${tableData.fact}">
9
- <div id="autocomplete-list" class="autocomplete-items"></div>
10
- </div>
11
- <div class="mb-3">
12
- <button id="download-csv" class="btn btn-secondary me-2">Download Selected Table (CSV)</button>
13
- <button id="download-all-zip" class="btn btn-secondary">Download All Tables (ZIP)</button>
14
- </div>
15
- <div id="metadata-content"></div>
16
- `;
17
-
18
- if (tableData.table && tableData.table.length > 0) {
19
- html += '<table class="table table-striped mt-3"><thead><tr>';
20
- Object.keys(tableData.table[0]).forEach(header => {
21
- html += `<th>${header}</th>`;
22
- });
23
- html += '</tr></thead><tbody>';
24
- tableData.table.forEach(row => {
25
- html += '<tr>';
26
- Object.values(row).forEach(cell => {
27
- html += `<td>${cell}</td>`;
28
- });
29
- html += '</tr>';
30
- });
31
- html += '</tbody></table>';
32
- } else {
33
- html += '<p>No table data available.</p>';
34
- }
35
-
36
- const artifactContent = document.getElementById('artifact-content');
37
- if (artifactContent) {
38
- artifactContent.innerHTML = html;
39
- }
40
- renderMetadata(tableData);
41
- setupTableEventListeners(tableData);
42
- }
43
-
44
- function setupTableEventListeners(tableData) {
45
- const artifactSelect = document.getElementById('artifact-select');
46
- const downloadCsvBtn = document.getElementById('download-csv');
47
- const downloadAllZipBtn = document.getElementById('download-all-zip');
48
-
49
- if (artifactSelect) {
50
- artifactSelect.addEventListener('input', handleArtifactSelectInput);
51
- artifactSelect.addEventListener('focus', handleArtifactSelectFocus);
52
- }
53
-
54
- if (downloadCsvBtn) {
55
- downloadCsvBtn.addEventListener('click', () => downloadCSV(tableData));
56
- }
57
-
58
- if (downloadAllZipBtn) {
59
- downloadAllZipBtn.addEventListener('click', handleDownloadAllZip);
60
- }
61
- }
62
-
63
- export function handleArtifactSelectInput(e) {
64
- const inputValue = e.target.value.toLowerCase().trim();
65
- const filteredTables = allArtifacts.filter(table =>
66
- table.fact.toLowerCase().includes(inputValue)
67
- );
68
- createAutocompleteList(filteredTables);
69
- }
70
-
71
- export function handleArtifactSelectFocus() {
72
- createAutocompleteList(allArtifacts);
73
- }
74
-
75
- function createAutocompleteList(tables) {
76
- const autocompleteList = document.getElementById('autocomplete-list');
77
- if (!autocompleteList) return;
78
-
79
- autocompleteList.innerHTML = '';
80
- autocompleteList.style.display = 'block';
81
-
82
- if (tables.length === 0) {
83
- autocompleteList.innerHTML = '<div style="color: #999;">No matching tables found</div>';
84
- } else {
85
- tables.forEach(table => {
86
- const div = document.createElement("div");
87
- div.textContent = table.fact;
88
- div.addEventListener("click", function () {
89
- document.getElementById('artifact-select').value = this.textContent;
90
- renderTableArtifact(table);
91
- closeAutocompleteList();
92
- });
93
- autocompleteList.appendChild(div);
94
- });
95
- }
96
- }
97
-
98
- export function handleDocumentClick(e) {
99
- if (e.target.id !== 'artifact-select') {
100
- closeAutocompleteList();
101
- }
102
- }
103
-
104
- function closeAutocompleteList() {
105
- const autocompleteList = document.getElementById('autocomplete-list');
106
- if (autocompleteList) {
107
- autocompleteList.style.display = 'none';
108
- }
109
- }
110
-
111
- async function handleDownloadAllZip() {
112
- const tables = allArtifacts.filter(artifact => artifact.type === 'artifact-table');
113
- if (tables.length === 0) {
114
- alert('No tables available to download.');
115
- return;
116
- }
117
- const zip = new JSZip();
118
- tables.forEach(table => {
119
- let csv = '';
120
- const headers = Object.keys(table.table[0]);
121
- csv += headers.join(',') + '\n';
122
- table.table.forEach(row => {
123
- csv += Object.values(row).join(',') + '\n';
124
- });
125
- zip.file(`${table.fact}.csv`, csv);
126
- });
127
- const content = await zip.generateAsync({ type: "blob" });
128
- saveAs(content, "all_tables.zip");
129
- }
@@ -1,28 +0,0 @@
1
- // utils.js
2
- export function renderMetadata(artifactData) {
3
- const metadataHtml = `
4
- <div class="card mb-3">
5
- <div class="card-body">
6
- <h5 class="card-title">Metadata</h5>
7
- <p><strong>Fact:</strong> ${artifactData.fact}</p>
8
- ${artifactData.cik ? `<p><strong>CIK:</strong> ${artifactData.cik}</p>` : ''}
9
- ${artifactData.category ? `<p><strong>Category:</strong> ${artifactData.category}</p>` : ''}
10
- ${artifactData.label ? `<p><strong>Label:</strong> ${artifactData.label}</p>` : ''}
11
- ${artifactData.description ? `<p><strong>Description:</strong> ${artifactData.description}</p>` : ''}
12
- ${artifactData.unit ? `<p><strong>Unit:</strong> ${artifactData.unit}</p>` : ''}
13
- </div>
14
- </div>
15
- `;
16
- document.getElementById('metadata-content').innerHTML = metadataHtml;
17
- }
18
-
19
- export function downloadCSV(table) {
20
- let csv = '';
21
- const headers = Object.keys(table.table[0]);
22
- csv += headers.join(',') + '\n';
23
- table.table.forEach(row => {
24
- csv += Object.values(row).join(',') + '\n';
25
- });
26
- const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
27
- saveAs(blob, `${table.fact}.csv`);
28
- }
@@ -1,91 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Mulebot</title>
8
- <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
10
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
11
- <link rel="stylesheet" href="{{ url_for('static', filename='css/minimalist.css') }}">
12
- </head>
13
-
14
- <body>
15
- <div class="container mt-5">
16
- <div class="d-flex justify-content-between align-items-center mb-4">
17
- <h1>Mulebot</h1>
18
- <div>
19
- <a href="https://github.com/john-friedman/datamule-python" target="_blank" class="social-btn">
20
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
21
- class="bi bi-github" viewBox="0 0 16 16">
22
- <path
23
- d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z" />
24
- </svg>
25
- GitHub
26
- </a>
27
- <a href="https://datamule.xyz" target="_blank" class="social-btn">
28
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
29
- viewBox="0 0 16 16">
30
- <path
31
- d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.539c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.312.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a13.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.694.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.418.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z" />
32
- </svg>
33
- DataMule Website
34
- </a>
35
- </div>
36
- </div>
37
- <div class="row">
38
- <div class="col-md-6">
39
- <div class="card mb-3">
40
- <div class="card-body">
41
- <div id="chat-outer-container">
42
- <div id="chat-container" class="mb-3"></div>
43
- <div id="thinking-indicator" class="thinking-indicator">
44
- <span>Bot is thinking</span><span class="dot-animation">...</span>
45
- </div>
46
- </div>
47
- <form id="chat-form">
48
- <div class="input-group">
49
- <input type="text" id="user-input" class="form-control"
50
- placeholder="Type your message...">
51
- <button type="submit" class="btn btn-primary">Send</button>
52
- </div>
53
- </form>
54
- </div>
55
- </div>
56
- </div>
57
- <div class="col-md-6">
58
- <button id="toggle-artifacts" class="btn btn-secondary mb-3">Show Artifacts</button>
59
- <div id="artifact-container" class="card mb-3" style="display: none;">
60
- <div class="card-body">
61
- <div id="artifact-content"></div>
62
- </div>
63
- </div>
64
- <div class="suggestion-box">
65
- <h5 class="mb-2">Suggested Commands:</h5>
66
- <ul class="list-unstyled">
67
- <li class="suggestion-item">Get all company facts for Tesla</li>
68
- <li class="suggestion-item">Get Ford's CIK</li>
69
- <li class="suggestion-item">Get all 10-K urls for META</li>
70
- <li class="suggestion-item">Get the management discussion and analysis section from
71
- https://www.sec.gov/Archives/edgar/data/1318605/000095017022000796/tsla-20211231.htm</li>
72
- </ul>
73
- </div>
74
- </div>
75
- </div>
76
- </div>
77
- <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
78
-
79
- <!-- Application scripts -->
80
- <script type="module" src="{{ url_for('static', filename='scripts/utils.js') }}"></script>
81
- <script type="module" src="{{ url_for('static', filename='scripts/chat.js') }}"></script>
82
- <script type="module" src="{{ url_for('static', filename='scripts/listArtifacts.js') }}"></script>
83
- <script type="module" src="{{ url_for('static', filename='scripts/filingArtifacts.js') }}"></script>
84
- <script type="module" src="{{ url_for('static', filename='scripts/tableArtifacts.js') }}"></script>
85
- <script type="module" src="{{ url_for('static', filename='scripts/artifacts.js') }}"></script>
86
- <script type="module" src="{{ url_for('static', filename='scripts/suggestions.js') }}"></script>
87
- <script type="module" src="{{ url_for('static', filename='scripts/prefilledPrompt.js') }}"></script>
88
- <script type="module" src="{{ url_for('static', filename='scripts/main.js') }}"></script>
89
- </body>
90
-
91
- </html>
@@ -1,52 +0,0 @@
1
- import difflib
2
- from typing import Dict, List, Any
3
-
4
- def search_filing(query: str, nested_dict: Dict[str, Any], max_matches: int = 20, score_cutoff: float = 0.6) -> List[Dict[str, Any]]:
5
- max_matches = min(max_matches, 20)
6
- query = query.lower() # Convert query to lowercase
7
-
8
- def flatten_dict(d: Dict[str, Any], parent_path: List[str] = None) -> List[Dict[str, Any]]:
9
- parent_path = parent_path or []
10
- items = []
11
-
12
- if isinstance(d, dict):
13
- for k, v in d.items():
14
- new_path = parent_path + [k]
15
- if k == 'title' and isinstance(v, str):
16
- items.append({'path': new_path, 'title': v, 'title_lower': v.lower()})
17
- items.extend(flatten_dict(v, new_path))
18
- elif isinstance(d, list):
19
- for i, item in enumerate(d):
20
- new_path = parent_path + [str(i)]
21
- items.extend(flatten_dict(item, new_path))
22
-
23
- return items
24
-
25
- flat_list = flatten_dict(nested_dict)
26
- all_titles_lower = [item['title_lower'] for item in flat_list]
27
-
28
- matches = difflib.get_close_matches(query, all_titles_lower, n=max_matches, cutoff=score_cutoff)
29
-
30
- results = []
31
- for match in matches:
32
- similarity = difflib.SequenceMatcher(None, query, match).ratio()
33
- for item in flat_list:
34
- if item['title_lower'] == match:
35
- # Navigate to the correct nested dictionary
36
- d = nested_dict
37
- for key in item['path'][:-1]: # Exclude the last 'title' key
38
- if key.isdigit():
39
- d = d[int(key)]
40
- else:
41
- d = d[key]
42
- results.append({
43
- 'path': '.'.join(item['path'][:-1]), # Exclude the last 'title' key
44
- 'content': d,
45
- 'similarity': similarity
46
- })
47
- break
48
-
49
- results.sort(key=lambda x: x['similarity'], reverse=True)
50
-
51
-
52
- return [item['content'] for item in results[:max_matches]]