+ `;
+
+ // Display all available entity info fields
+ for (const [key, value] of Object.entries(entityInfo)) {
+ if (value !== null && value !== undefined && value !== '') {
+ html += `
+
+ Period: ${escapeHtml(data.start_date || '')} to ${escapeHtml(data.end_date || '')}
`;
+ html += '
';
// Title
- html += `
${escapeHtml(data.report_title)}
`;
- html += '
';
+ if (data.report_title) {
+ html += `
+
${escapeHtml(data.report_title)}
+
`;
+ }
// Introduction section
if (data.introduction) {
- html += `
-
- Highlights
-
-
+ html += `
+
Summary
+
${formatIntroduction(data.introduction)}
`;
+ } else {
+ html += `
+
No summary available for this brief.
+
`;
}
- // Entity reports as cards
- if (Array.isArray(data.entity_reports) && data.entity_reports.length > 0) {
- html += '
';
-
- data.entity_reports.forEach(entity => {
- const entityName = (entity.entity_info && (entity.entity_info.name || entity.entity_info.id))
- ? escapeHtml(entity.entity_info.name || entity.entity_info.id)
- : escapeHtml(entity.entity_id);
-
- // Extract entity metadata if available
- const ticker = entity.entity_info?.ticker || entity.entity_info?.symbol || '';
- const country = entity.entity_info?.country || entity.entity_info?.location || '';
- const industry = entity.entity_info?.industry || entity.entity_info?.sector || '';
-
- const highlights = Array.isArray(entity.content) ? entity.content : [];
-
- // Build card: Changed to a dark, blurred background with refined padding and borders.
- html += `
`;
-
- // Company header section
- html += '
';
- // Updated typography for the entity name.
- html += `
${entityName}
`;
-
- html += '
';
- if (ticker) {
- // Polished ticker style.
- html += `${escapeHtml(ticker)}`;
- }
- if (country) {
- // Replaced emoji with a cleaner SVG icon.
- html += `
- ${escapeHtml(country)}
- `;
- }
- if (industry) {
- // Polished industry tag style.
- html += `${escapeHtml(industry)}`;
- }
- html += '
';
- html += '
';
-
- // Divider for better separation.
- html += '';
-
- // Highlights section
- if (highlights.length > 0) {
- const hasMore = highlights.length > 2;
- html += `
`;
-
- highlights.forEach((bp, i) => {
- const isExtra = i >= 2;
- // Updated highlight box style to match the dark theme.
- html += `
`;
- html += `
`; // Set base text color for highlights.
-
- // Source indicator with a restyled tooltip for the dark theme.
- if (Array.isArray(bp.sources) && bp.sources.length > 0) {
- let tooltipContent = '';
-
- // Define SVG icons for a cleaner look (Heroicons)
- const iconSource = ``;
- const iconTitle = ``;
- const iconUrl = ``;
-
- bp.sources.forEach((sourceId, sourceIndex) => {
- // Use optional chaining and provide a default empty object for robustness
- const sourceMetadata = data.source_metadata?.[sourceId] || {};
-
- // Destructure properties with default values
- const {
- text = "No text available",
- headline = 'No headline available',
- source_name: sourceName = 'Unknown Source',
- url
- } = sourceMetadata;
-
- // Use a container for each source to handle spacing, removing the need for
- // This creates a more modern, card-based layout
- tooltipContent += `
-
`;
return;
}
@@ -24,17 +92,18 @@ document.addEventListener('DOMContentLoaded', () => {
// Create the main container for the list item
const listItem = document.createElement('div');
- listItem.className = 'flex justify-between items-center bg-white p-4 border border-gray-200 rounded-md shadow-sm text-xs';
+ listItem.className = 'flex justify-between items-center bg-zinc-900/50 p-3 border border-zinc-700 rounded-lg text-sm';
// Create the text element
const sentenceText = document.createElement('span');
sentenceText.textContent = sentence;
- sentenceText.className = 'text-gray-700';
+ sentenceText.className = 'text-zinc-300 flex-1 mr-3';
// Create the delete button
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
- deleteButton.className = 'bg-red-500 text-white font-semibold px-4 py-1 rounded-md hover:bg-red-600 transition-colors';
+ deleteButton.type = 'button';
+ deleteButton.className = 'bg-red-600/80 text-white font-medium px-3 py-1.5 rounded-md hover:bg-red-600 transition-colors text-xs';
// Add an event listener to the delete button
deleteButton.addEventListener('click', () => {
@@ -52,11 +121,26 @@ document.addEventListener('DOMContentLoaded', () => {
// Function to add a new sentence
const addSentence = () => {
+ if (!input) return;
const newSentence = input.value.trim(); // Get value and remove whitespace
if (newSentence) { // Only add if the input is not empty
+ // Validate that it contains {company}
+ if (!newSentence.includes('{company}')) {
+ alert('Topic must include {company} placeholder');
+ return;
+ }
+ if (!topic_sentences) {
+ topic_sentences = [];
+ }
topic_sentences.push(newSentence);
input.value = ''; // Clear the input field
renderSentences(); // Re-render the list
+
+ // Switch to custom preset if not already
+ const presetSelect = document.getElementById('topicPreset');
+ if (presetSelect && presetSelect.value !== 'custom') {
+ presetSelect.value = 'custom';
+ }
}
};
@@ -67,21 +151,35 @@ document.addEventListener('DOMContentLoaded', () => {
renderSentences(); // Re-render the list
};
+ // Make renderSentences available globally
+ window.renderSentences = renderSentences;
+
// --- EVENT LISTENERS ---
// Listen for form submission (e.g., pressing Enter)
- form.addEventListener('submit', (event) => {
- event.preventDefault(); // Prevent page reload
- addSentence();
- });
+ if (form) {
+ form.addEventListener('submit', (event) => {
+ event.preventDefault(); // Prevent page reload
+ addSentence();
+ });
+ }
// Listen for clicks on the add button
- addButton.addEventListener('click', (event) => {
- event.preventDefault(); // Prevent form submission
- addSentence();
- });
+ if (addButton) {
+ addButton.addEventListener('click', (event) => {
+ event.preventDefault(); // Prevent form submission
+ addSentence();
+ });
+ }
// --- INITIAL RENDER ---
// Render the initial list when the page loads
- renderSentences();
-});
\ No newline at end of file
+ if (listContainer) {
+ renderSentences();
+ }
+});
+
+// Make topic_sentences accessible globally
+if (typeof topic_sentences === 'undefined') {
+ window.topic_sentences = [];
+}
diff --git a/bigdata_briefs/static/scripts/visualization.js b/bigdata_briefs/static/scripts/visualization.js
index 6607d36..1e17a3e 100644
--- a/bigdata_briefs/static/scripts/visualization.js
+++ b/bigdata_briefs/static/scripts/visualization.js
@@ -1,56 +1,73 @@
// Info modal content for each label
const infoContents = {
topics: `Topics: Specify the topics you want to analyze. Each topic must include the {company} placeholder which will be replaced with actual company names during analysis. You can specify multiple topics, one per line. Examples: "What key takeaways emerged from {company}'s latest earnings report?"`,
- companies: `Company Universe: The portfolio of companies you want to create the brief for. You have several input options:
Select one of the public watchlists using the dropdown menu
Write list of RavenPack entity IDs (e.g., 4A6F00, D8442A)
Input a watchlist ID (e.g., 44118802-9104-4265-b97a-2e6d88d74893 )
Watchlists can be created programmatically using the Bigdata.com SDK or through the Bigdata app.`,
- start_date: `Start/End Date: The start and end of the time sample during which you want to generate the brief. Format: YYYY-MM-DD.`,
- novelty: 'Novelty: If set to true, the analysis will focus on novel events that have not been widely reported before, helping to identify emerging risks. If false, all relevant events will be considered, including those that have been frequently reported.',
- sources: `Sources: Optionally, you can filter the analysis to include only events from specific sources. You can provide a list of RavenPack entity IDs separated by commas (e.g., 9D69F1, B5235B). If left empty, events from all sources will be considered.`,
+ companies: `Company Universe: The portfolio of companies you want to create the brief for. You have several input options:
Select one of the public watchlists using the dropdown menu
Upload a CSV file with RavenPack entity IDs (one per line)
Manually enter a list of RavenPack entity IDs separated by commas (e.g., 4A6F00, D8442A)
Input a watchlist ID (e.g., 44118802-9104-4265-b97a-2e6d88d74893)
Watchlists can be created programmatically using the Bigdata.com SDK or through the Bigdata app.`,
+ start_date: `Start Date: The start of the time period for which you want to generate the brief. Format: YYYY-MM-DD.`,
+ end_date: `End Date: The end of the time period for which you want to generate the brief. Format: YYYY-MM-DD.`,
+ novelty: 'Novelty Filter: If enabled, the brief will focus on novel information that has not been included in previously generated briefs. This helps avoid redundant content and highlights new developments.',
+ sources: `Sources: Optionally, you can filter the brief to include only events from specific sources. You can provide a list of RavenPack entity IDs separated by commas (e.g., 9D69F1, B5235B). If left empty, events from all sources will be considered.`,
+ source_rank_boost: `Source Rank Boost (0-10): Controls how much the source rank influences relevance. Set to 0 to ignore source rank, or up to 10 for maximum effect, boosting chunks from premium sources.`,
+ freshness_boost: `Freshness Boost (0-10): Controls the influence of document timestamp on relevance. Set to 0 to ignore publishing time (useful for point-in-time research), or up to 10 to heavily prioritize the most recent documents.`,
+ includeTitleSummary: `Include Title and Summary: When enabled, the brief will include a title and introduction/summary section. This feature is currently being prepared for backend support.`,
load_example: `Load Example: By clicking this button you will load an example output that is preloaded. By using it you can get an idea of the type of output you can expect from this workflow without waiting. The input data for the example is: