added new libraries

This commit is contained in:
Saifeddine ALOUI 2024-08-19 23:12:58 +02:00
parent 9814aafc45
commit cd483c1104
10 changed files with 1135 additions and 5 deletions

View File

@ -0,0 +1,40 @@
# LoLLMs Anything to Markdown Library
## Overview
JavaScript library to convert various file types to Markdown.
## Key Features
- Supports: txt, docx, pdf, pptx, and more
- Asynchronous processing
- Object-oriented design
## Import
```html
<script src="/lollms_assets/js/lollms_anything_to_markdown"></script>
```
## Core Class: LollmsFileLoader
### Methods
- `loadFile(file)`: Main method to process files
- `readTextFile(file)`, `readDocxFile(file)`, `readPdfFile(file)`, `readPptxFile(file)`: Type-specific readers
- `convertToMarkdown(content, fileExtension)`: Converts content to Markdown
## Usage
```javascript
const lollmsFileLoader = new LollmsFileLoader();
const markdown = await lollmsFileLoader.loadFile(file);
```
## Extensibility
- Add new file types by creating reader methods
- Enhance Markdown conversion logic
- Implement caching or post-processing
## Error Handling
Uses Promise-based approach. Wrap `loadFile` in try-catch.
## Dependencies
Requires external libraries for DOCX, PDF, and PPTX processing.
This concise documentation provides the essential information for an LLM-based developer to understand and work with the library, while saving context tokens.

View File

@ -0,0 +1,157 @@
# LoLLMs Anything to Markdown Library
## Overview
The LoLLMs Anything to Markdown Library is a versatile JavaScript tool designed to convert various file types into Markdown format. This library simplifies the process of extracting text content from different file formats and presenting it in a universally readable Markdown structure.
## Features
- Supports multiple file formats including plain text, DOCX, PDF, and PPTX
- Asynchronous file processing
- Object-oriented design for easy extensibility
- Basic Markdown conversion with room for customization
- Error handling for unsupported file types and processing errors
## Installation
To use the LoLLMs Anything to Markdown Library, include the following script in your HTML file:
```html
<script src="path/to/lollms-anything-to-markdown"></script>
```
Make sure to also include the necessary dependencies for processing specific file types:
- For DOCX: [Mammoth.js](https://github.com/mwilliamson/mammoth.js)
- For PDF: [PDF.js](https://mozilla.github.io/pdf.js/)
- For PPTX: A custom PptxTextExtractor library (not provided in this documentation)
## Usage
### Basic Usage
```javascript
const lollmsFileLoader = new LollmsFileLoader();
async function handleFileUpload(event) {
const file = event.target.files[0];
if (!file) return;
try {
const markdown = await lollmsFileLoader.loadFile(file);
console.log(markdown);
// Use the markdown content as needed
} catch (error) {
console.error('Error processing file:', error);
alert('Error processing file: ' + error.message);
}
}
```
### Supported File Types
The library supports the following file extensions:
- Plain text: txt, md, markdown, rtf, log, csv, json, xml, html, htm, css, js, py, java, c, cpp
- Microsoft Word: docx
- PDF: pdf
- Microsoft PowerPoint: pptx
## API Reference
### LollmsFileLoader Class
The main class of the library, responsible for loading and converting files.
#### Methods
##### `constructor()`
Initializes a new LollmsFileLoader instance.
##### `async loadFile(file)`
Loads and converts a file to Markdown.
- Parameters:
- `file`: File object to be processed
- Returns: A Promise that resolves with the Markdown content of the file
- Throws: Error if the file type is unsupported or if processing fails
##### `readTextFile(file)`
Reads the content of a text-based file.
- Parameters:
- `file`: File object to be read
- Returns: A Promise that resolves with the text content of the file
##### `readDocxFile(file)`
Extracts text content from a DOCX file.
- Parameters:
- `file`: DOCX File object to be processed
- Returns: A Promise that resolves with the extracted text content
##### `readPdfFile(file)`
Extracts text content from a PDF file.
- Parameters:
- `file`: PDF File object to be processed
- Returns: A Promise that resolves with the extracted text content
##### `readPptxFile(file)`
Extracts text content from a PPTX file.
- Parameters:
- `file`: PPTX File object to be processed
- Returns: A Promise that resolves with the extracted text content
##### `convertToMarkdown(content, fileExtension)`
Converts the extracted content to Markdown format.
- Parameters:
- `content`: String containing the extracted text content
- `fileExtension`: String representing the original file's extension
- Returns: A string containing the Markdown-formatted content
## Extending the Library
The LoLLMs Anything to Markdown Library is designed to be easily extensible. Here are some ways you can extend its functionality:
1. Add support for new file types by creating new read methods and adding the file extension to the `supportedExtensions` array.
2. Enhance the Markdown conversion logic in the `convertToMarkdown` method to handle more complex document structures.
3. Implement additional post-processing steps for specific file types.
4. Add a caching mechanism to store processed files for quicker access.
## Error Handling
The library uses a Promise-based approach for error handling. Errors are thrown in the following scenarios:
- Unsupported file type
- Failure to read or process a file
- Missing dependencies (e.g., PptxTextExtractor for PPTX files)
It's recommended to wrap the `loadFile` method call in a try-catch block to handle these errors gracefully in your application.
## Limitations
- The current implementation provides basic Markdown conversion and may not capture all formatting details from complex documents.
- Processing large files, especially PDFs with many pages, may be time-consuming.
- The library relies on external dependencies for processing DOCX, PDF, and PPTX files, which need to be included separately.
## Contributing
Contributions to the LoLLMs Anything to Markdown Library are welcome. Please ensure that your code adheres to the existing style and includes appropriate test coverage for new features or bug fixes.
## License
[Specify the license under which the library is released, e.g., MIT, Apache 2.0, etc.]
---
This documentation provides a comprehensive overview of the LoLLMs Anything to Markdown Library, including its features, usage instructions, API reference, and guidelines for extension. You can further customize this documentation to fit the specific needs and policies of your project.

View File

@ -0,0 +1,101 @@
# LollmsFlow Documentation
LollmsFlow is a JavaScript library for creating and visualizing workflows. It allows you to build, connect, and execute nodes in a workflow, as well as visualize the workflow in an interactive SVG-based interface.
## Key Components
1. **WorkflowNode**: Represents a single node in the workflow.
2. **Workflow**: Manages the entire workflow, including nodes and their connections.
3. **WorkflowVisualizer**: Handles the visual representation and interaction of the workflow.
## Supported Data Types
LollmsFlow supports the following data types for node inputs and outputs:
1. **number**: Represents numeric values (integers or floating-point numbers).
2. **string**: Represents text data.
3. **boolean**: Represents true/false values.
4. **object**: Represents complex data structures or custom objects.
Each data type is associated with a specific color in the workflow visualization:
- number: blue
- string: green
- boolean: red
- object: purple
Any other type not explicitly defined will be represented with a gray color.
## Basic Usage
### 0. Import the LollmsFlow Library
First, include the LollmsFlow library in your HTML file:
```html
<script src="/lollms_assets/js/lollms_flow"></script>
```
### 1. Create a Workflow Visualizer
```javascript
const visualizer = new WorkflowVisualizer("workflow-container");
```
### 2. Define Node Operations
```javascript
const nodeOperations = {
"Add": (inputs) => ({ sum: inputs.a + inputs.b }),
"Multiply": (inputs) => ({ product: inputs.x * inputs.y }),
"Output": (inputs) => console.log("Result:", inputs.result)
};
```
### 3. Create and Add Nodes
```javascript
const addNode = new WorkflowNode(0, "Add",
[{ name: "a", type: "number" }, { name: "b", type: "number" }],
[{ name: "sum", type: "number" }],
nodeOperations["Add"], 50, 50
);
visualizer.addNode(addNode);
```
### 4. Connect Nodes
```javascript
visualizer.connectNodes(sourceId, sourceOutput, targetId, targetInput);
```
### 5. Execute the Workflow
```javascript
const results = visualizer.execute();
```
## Advanced Features
- **Save/Load Workflow**: Use `saveToJSON()` and `loadFromJSON()` methods.
- **Local Storage**: Save/load workflows using `saveToLocalStorage()` and `loadFromLocalStorage()`.
- **Drag and Drop**: Nodes can be moved around in the visualizer.
## Key Methods for AI Usage
1. `addNode(node)`: Add a new node to the workflow.
2. `connectNodes(sourceId, sourceOutput, targetId, targetInput)`: Connect two nodes.
3. `execute()`: Run the workflow and get results.
4. `saveToJSON()`: Convert the workflow to a JSON string.
5. `loadFromJSON(json, nodeOperations)`: Load a workflow from a JSON string.
## Tips for AI Implementation
1. Define a set of node types and their operations, using the supported data types.
2. Create nodes dynamically based on user input or predefined templates.
3. Use the visualization features to display the workflow to users, leveraging the color-coding for different data types.
4. Implement save/load functionality to persist workflows.
5. Utilize the execution feature to process data through the workflow.
6. When creating custom nodes, ensure that the input and output types match one of the supported data types for proper visualization and connection validation.
This library provides a flexible framework for creating visual, interactive workflows in web applications. It can be particularly useful for data processing, algorithm visualization, or any application requiring a flow-based interface. The support for various data types allows for diverse and complex workflows to be created and managed effectively.

View File

@ -0,0 +1,164 @@
# Lollms Flow
Lollms Flow is a powerful JavaScript library for building and visualizing workflows of execution. It provides an intuitive way to create, connect, and manage nodes in a workflow, as well as visualize and interact with the workflow through a drag-and-drop interface.
## Features
- Create custom workflow nodes with inputs and outputs
- Connect nodes to form complex workflows
- Visualize workflows with an interactive SVG-based interface
- Drag-and-drop functionality for easy node positioning
- Save and load workflows to/from JSON
- Execute workflows and obtain results
- Integration with local storage for persistent workflows
- Customizable node operations
## Installation
### For Lollms Users
If you're using Lollms with the server running, you can include Lollms Flow directly in your HTML:
```html
<script src="/lollms_assets/js/lollms_flow"></script>
```
### For Non-Lollms Users
If you're not using Lollms or need to specify the full server path:
```html
<script src="http://localhost:9600/lollms_assets/js/lollms_flow"></script>
```
Note: Make sure to activate the server of the app in Lollms, or the CORS policy may prevent access.
## Usage
1. Create a container for the workflow in your HTML:
```html
<div id="workflow-container"></div>
```
2. Initialize the WorkflowVisualizer:
```javascript
const visualizer = new WorkflowVisualizer("workflow-container");
```
3. Define node operations:
```javascript
const nodeOperations = {
"Add": (inputs) => ({ sum: inputs.a + inputs.b }),
"Multiply": (inputs) => ({ product: inputs.x * inputs.y }),
"Output": (inputs) => console.log("Result:", inputs.result)
};
```
4. Create and add nodes:
```javascript
const addNode = new WorkflowNode(0, "Add", [
{ name: "a", type: "number" },
{ name: "b", type: "number" }
], [
{ name: "sum", type: "number" }
], nodeOperations["Add"], 50, 50);
visualizer.addNode(addNode);
```
5. Connect nodes:
```javascript
visualizer.connectNodes(0, 0, 1, 0);
```
6. Execute the workflow:
```javascript
const results = visualizer.execute();
console.log(results);
```
## API Reference
### WorkflowNode
Constructor: `WorkflowNode(id, name, inputs, outputs, operation, x = 0, y = 0)`
Methods:
- `connect(outputIndex, targetNode, inputIndex)`
- `execute(inputs)`
- `toJSON()`
- `static fromJSON(json, operation)`
### Workflow
Constructor: `Workflow()`
Methods:
- `addNode(node)`
- `connectNodes(sourceId, sourceOutput, targetId, targetInput)`
- `canConnect(sourceNode, sourceOutput, targetNode, targetInput)`
- `execute()`
- `toJSON()`
- `static fromJSON(json, nodeOperations)`
### WorkflowVisualizer
Constructor: `WorkflowVisualizer(containerId)`
Methods:
- `addNode(node)`
- `connectNodes(sourceId, sourceOutput, targetId, targetInput)`
- `execute()`
- `saveToJSON()`
- `loadFromJSON(json, nodeOperations)`
- `saveToLocalStorage(key)`
- `loadFromLocalStorage(key, nodeOperations)`
- `redraw()`
## Example
```javascript
const visualizer = new WorkflowVisualizer("workflow-container");
const addNode = new WorkflowNode(0, "Add", [
{ name: "a", type: "number" },
{ name: "b", type: "number" }
], [
{ name: "sum", type: "number" }
], nodeOperations["Add"], 50, 50);
const multiplyNode = new WorkflowNode(1, "Multiply", [
{ name: "x", type: "number" },
{ name: "y", type: "number" }
], [
{ name: "product", type: "number" }
], nodeOperations["Multiply"], 250, 50);
const outputNode = new WorkflowNode(2, "Output", [
{ name: "result", type: "number" }
], [], nodeOperations["Output"], 450, 50);
visualizer.addNode(addNode);
visualizer.addNode(multiplyNode);
visualizer.addNode(outputNode);
visualizer.connectNodes(0, 0, 1, 0);
visualizer.connectNodes(1, 0, 2, 0);
const results = visualizer.execute();
console.log(results);
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the MIT License.

View File

@ -3,9 +3,8 @@
Quick reference for AI-assisted development of the WebAppLocalizer class.
## Import
```javascript
// Served by LoLLMs system
import WebAppLocalizer from '/lollms_assets/js/web.app.localizer';
```html
<script src="/lollms_assets/js/web.app.localizer"></script>
```
## Initialization

View File

@ -0,0 +1,157 @@
class LollmsFileLoader {
constructor() {
this.supportedExtensions = [
'txt', 'md', 'markdown', 'rtf', 'log', 'csv', 'json', 'xml',
'html', 'htm', 'css', 'js', 'py', 'java', 'c', 'cpp',
'docx', 'pdf', 'pptx'
];
}
async loadFile(file) {
const fileExtension = file.name.split('.').pop().toLowerCase();
if (!this.supportedExtensions.includes(fileExtension)) {
throw new Error('Unsupported file type');
}
let content = '';
switch (fileExtension) {
case 'docx':
content = await this.readDocxFile(file);
break;
case 'pdf':
content = await this.readPdfFile(file);
break;
case 'pptx':
content = await this.readPptxFile(file);
break;
default:
content = await this.readTextFile(file);
}
return this.convertToMarkdown(content, fileExtension);
}
readTextFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = (e) => reject(e);
reader.readAsText(file);
});
}
readDocxFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function(e) {
mammoth.extractRawText({arrayBuffer: e.target.result})
.then(result => resolve(result.value))
.catch(reject);
};
reader.onerror = (e) => reject(e);
reader.readAsArrayBuffer(file);
});
}
async readPdfFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async function(e) {
try {
const pdf = await pdfjsLib.getDocument({data: e.target.result}).promise;
let content = '';
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const textContent = await page.getTextContent();
content += textContent.items.map(item => item.str).join(' ') + '\n\n';
}
resolve(content.trim());
} catch (error) {
console.error("Error processing PDF:", error);
reject(error);
}
};
reader.onerror = (e) => reject(e);
reader.readAsArrayBuffer(file);
});
}
readPptxFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async function(e) {
try {
if (typeof PptxTextExtractor === 'undefined') {
throw new Error('PptxTextExtractor is not defined. The library might not be loaded correctly.');
}
const text = await PptxTextExtractor.extractText(e.target.result);
resolve(text.join('\n'));
} catch (error) {
console.error('Error extracting text from PPTX:', error);
reject(new Error('Unable to process PPTX file. ' + error.message));
}
};
reader.onerror = (e) => reject(e);
reader.readAsArrayBuffer(file);
});
}
convertToMarkdown(content, fileExtension) {
// Basic conversion to markdown
// This can be extended for more sophisticated conversions
let markdown = '';
const lines = content.split('\n');
let inCodeBlock = false;
for (let line of lines) {
line = line.trim();
if (line === '') {
markdown += '\n';
continue;
}
// Check for headings
if (line.startsWith('#')) {
markdown += line + '\n';
}
// Check for lists
else if (line.match(/^[\u2022\u25E6\u25AA\u25AB\u25CF\u25CB\u25A0\u25A1]/)) {
markdown += '- ' + line.substring(1).trim() + '\n';
}
// Check for code blocks
else if (line.startsWith('```')) {
inCodeBlock = !inCodeBlock;
markdown += line + '\n';
}
// Regular text
else {
if (inCodeBlock) {
markdown += line + '\n';
} else {
markdown += line + '\n\n';
}
}
}
return markdown.trim();
}
}
// Usage example:
async function handleFileUpload(event) {
const file = event.target.files[0];
if (!file) return;
const fileLoader = new LollmsFileLoader();
try {
const markdown = await fileLoader.loadFile(file);
console.log(markdown);
// You can now use the markdown content as needed
} catch (error) {
console.error('Error processing file:', error);
alert('Error processing file: ' + error.message);
}
}

View File

@ -0,0 +1,391 @@
// Lollms Flow
// A library for building workflows of execution
// By ParisNeo
class WorkflowNode {
constructor(id, name, inputs, outputs, operation, x = 0, y = 0) {
this.id = id;
this.name = name;
this.inputs = inputs;
this.outputs = outputs;
this.operation = operation;
this.inputConnections = {};
this.outputConnections = {};
this.x = x;
this.y = y;
}
connect(outputIndex, targetNode, inputIndex) {
if (!this.outputConnections[outputIndex]) {
this.outputConnections[outputIndex] = [];
}
this.outputConnections[outputIndex].push({ node: targetNode, input: inputIndex });
targetNode.inputConnections[inputIndex] = { node: this, output: outputIndex };
}
execute(inputs) {
return this.operation(inputs);
}
toJSON() {
return {
id: this.id,
name: this.name,
inputs: this.inputs,
outputs: this.outputs,
x: this.x,
y: this.y
};
}
static fromJSON(json, operation) {
return new WorkflowNode(json.id, json.name, json.inputs, json.outputs, operation, json.x, json.y);
}
}
class Workflow {
constructor() {
this.nodes = {};
this.nodeList = [];
}
addNode(node) {
this.nodes[node.id] = node;
this.nodeList.push(node);
}
connectNodes(sourceId, sourceOutput, targetId, targetInput) {
const sourceNode = this.nodes[sourceId];
const targetNode = this.nodes[targetId];
if (this.canConnect(sourceNode, sourceOutput, targetNode, targetInput)) {
sourceNode.connect(sourceOutput, targetNode, targetInput);
return true;
}
return false;
}
canConnect(sourceNode, sourceOutput, targetNode, targetInput) {
return sourceNode.outputs[sourceOutput].type === targetNode.inputs[targetInput].type;
}
execute() {
const executed = new Set();
const results = {};
const executeNode = (node) => {
if (executed.has(node.id)) return results[node.id];
const inputs = {};
for (let i = 0; i < node.inputs.length; i++) {
if (node.inputConnections[i]) {
const { node: sourceNode, output } = node.inputConnections[i];
inputs[node.inputs[i].name] = executeNode(sourceNode)[sourceNode.outputs[output].name];
}
}
results[node.id] = node.execute(inputs);
executed.add(node.id);
return results[node.id];
};
this.nodeList.forEach(node => {
if (Object.keys(node.inputConnections).length === 0) {
executeNode(node);
}
});
return results;
}
toJSON() {
return {
nodes: this.nodeList.map(node => node.toJSON()),
connections: this.nodeList.flatMap(node =>
Object.entries(node.outputConnections).flatMap(([outputIndex, connections]) =>
connections.map(conn => ({
sourceId: node.id,
sourceOutput: parseInt(outputIndex),
targetId: conn.node.id,
targetInput: conn.input
}))
)
)
};
}
static fromJSON(json, nodeOperations) {
const workflow = new Workflow();
json.nodes.forEach(nodeJson => {
const node = WorkflowNode.fromJSON(nodeJson, nodeOperations[nodeJson.name]);
workflow.addNode(node);
});
json.connections.forEach(conn => {
workflow.connectNodes(conn.sourceId, conn.sourceOutput, conn.targetId, conn.targetInput);
});
return workflow;
}
}
class WorkflowVisualizer {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.workflow = new Workflow();
this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
this.container.appendChild(this.svg);
this.nodeElements = {};
this.connectionElements = [];
this.draggedNode = null;
this.offsetX = 0;
this.offsetY = 0;
this.svg.addEventListener('mousedown', this.onMouseDown.bind(this));
this.svg.addEventListener('mousemove', this.onMouseMove.bind(this));
this.svg.addEventListener('mouseup', this.onMouseUp.bind(this));
}
addNode(node) {
this.workflow.addNode(node);
this.drawNode(node);
}
connectNodes(sourceId, sourceOutput, targetId, targetInput) {
if (this.workflow.connectNodes(sourceId, sourceOutput, targetId, targetInput)) {
this.drawConnection(sourceId, sourceOutput, targetId, targetInput);
} else {
console.error("Cannot connect incompatible types");
}
}
drawNode(node) {
const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
g.setAttribute("transform", `translate(${node.x}, ${node.y})`);
g.setAttribute("data-id", node.id);
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("width", "120");
rect.setAttribute("height", "60");
rect.setAttribute("fill", "lightblue");
rect.setAttribute("stroke", "black");
g.appendChild(rect);
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute("x", "60");
text.setAttribute("y", "35");
text.setAttribute("text-anchor", "middle");
text.textContent = node.name;
g.appendChild(text);
// Draw input sockets
node.inputs.forEach((input, index) => {
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", "0");
circle.setAttribute("cy", (index + 1) * 15);
circle.setAttribute("r", "5");
circle.setAttribute("fill", this.getColorForType(input.type));
g.appendChild(circle);
});
// Draw output sockets
node.outputs.forEach((output, index) => {
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", "120");
circle.setAttribute("cy", (index + 1) * 15);
circle.setAttribute("r", "5");
circle.setAttribute("fill", this.getColorForType(output.type));
g.appendChild(circle);
});
this.svg.appendChild(g);
this.nodeElements[node.id] = g;
}
drawConnection(sourceId, sourceOutput, targetId, targetInput) {
const sourceNode = this.workflow.nodes[sourceId];
const targetNode = this.workflow.nodes[targetId];
const line = document.createElementNS("http://www.w3.org/2000/svg", "path");
const sourcePosX = sourceNode.x + 120;
const sourcePosY = sourceNode.y + (sourceOutput + 1) * 15;
const targetPosX = targetNode.x;
const targetPosY = targetNode.y + (targetInput + 1) * 15;
const midX = (sourcePosX + targetPosX) / 2;
const d = `M ${sourcePosX} ${sourcePosY} C ${midX} ${sourcePosY}, ${midX} ${targetPosY}, ${targetPosX} ${targetPosY}`;
line.setAttribute("d", d);
line.setAttribute("fill", "none");
line.setAttribute("stroke", "black");
this.svg.appendChild(line);
this.connectionElements.push({ line, sourceId, sourceOutput, targetId, targetInput });
}
updateConnections() {
this.connectionElements.forEach(conn => {
const sourceNode = this.workflow.nodes[conn.sourceId];
const targetNode = this.workflow.nodes[conn.targetId];
const sourcePosX = sourceNode.x + 120;
const sourcePosY = sourceNode.y + (conn.sourceOutput + 1) * 15;
const targetPosX = targetNode.x;
const targetPosY = targetNode.y + (conn.targetInput + 1) * 15;
const midX = (sourcePosX + targetPosX) / 2;
const d = `M ${sourcePosX} ${sourcePosY} C ${midX} ${sourcePosY}, ${midX} ${targetPosY}, ${targetPosX} ${targetPosY}`;
conn.line.setAttribute("d", d);
});
}
getColorForType(type) {
const colors = {
number: "blue",
string: "green",
boolean: "red",
object: "purple"
};
return colors[type] || "gray";
}
onMouseDown(event) {
const target = event.target.closest("g");
if (target) {
this.draggedNode = this.workflow.nodes[target.getAttribute("data-id")];
const rect = target.getBoundingClientRect();
this.offsetX = event.clientX - rect.left;
this.offsetY = event.clientY - rect.top;
}
}
onMouseMove(event) {
if (this.draggedNode) {
const rect = this.svg.getBoundingClientRect();
this.draggedNode.x = event.clientX - rect.left - this.offsetX;
this.draggedNode.y = event.clientY - rect.top - this.offsetY;
this.nodeElements[this.draggedNode.id].setAttribute("transform", `translate(${this.draggedNode.x}, ${this.draggedNode.y})`);
this.updateConnections();
}
}
onMouseUp() {
this.draggedNode = null;
}
execute() {
return this.workflow.execute();
}
saveToJSON() {
return JSON.stringify(this.workflow.toJSON());
}
loadFromJSON(json, nodeOperations) {
this.workflow = Workflow.fromJSON(JSON.parse(json), nodeOperations);
this.redraw();
}
saveToLocalStorage(key) {
localStorage.setItem(key, this.saveToJSON());
}
loadFromLocalStorage(key, nodeOperations) {
const json = localStorage.getItem(key);
if (json) {
this.loadFromJSON(json, nodeOperations);
}
}
redraw() {
this.svg.innerHTML = '';
this.nodeElements = {};
this.connectionElements = [];
this.workflow.nodeList.forEach(node => this.drawNode(node));
this.workflow.nodeList.forEach(node => {
Object.entries(node.outputConnections).forEach(([outputIndex, connections]) => {
connections.forEach(conn => {
this.drawConnection(node.id, parseInt(outputIndex), conn.node.id, conn.input);
});
});
});
}
}
// Usage example
const nodeOperations = {
"Add": (inputs) => ({ sum: inputs.a + inputs.b }),
"Multiply": (inputs) => ({ product: inputs.x * inputs.y }),
"Output": (inputs) => console.log("Result:", inputs.result)
};
const visualizer = new WorkflowVisualizer("workflow-container");
const addNode = new WorkflowNode(0, "Add", [
{ name: "a", type: "number" },
{ name: "b", type: "number" }
], [
{ name: "sum", type: "number" }
], nodeOperations["Add"], 50, 50);
const multiplyNode = new WorkflowNode(1, "Multiply", [
{ name: "x", type: "number" },
{ name: "y", type: "number" }
], [
{ name: "product", type: "number" }
], nodeOperations["Multiply"], 250, 50);
const outputNode = new WorkflowNode(2, "Output", [
{ name: "result", type: "number" }
], [], nodeOperations["Output"], 450, 50);
visualizer.addNode(addNode);
visualizer.addNode(multiplyNode);
visualizer.addNode(outputNode);
visualizer.connectNodes(0, 0, 1, 0);
visualizer.connectNodes(1, 0, 2, 0);
// Add save and load buttons
const saveButton = document.createElement("button");
saveButton.textContent = "Save";
saveButton.onclick = () => {
const json = visualizer.saveToJSON();
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "workflow.json";
a.click();
URL.revokeObjectURL(url);
};
document.body.appendChild(saveButton);
const loadButton = document.createElement("button");
loadButton.textContent = "Load";
loadButton.onclick = () => {
const input = document.createElement("input");
input.type = "file";
input.accept = "application/json";
input.onchange = (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
visualizer.loadFromJSON(e.target.result, nodeOperations);
};
reader.readAsText(file);
};
input.click();
};
document.body.appendChild(loadButton);
// Add save and load to/from localStorage buttons
const saveLocalButton = document.createElement("button");
saveLocalButton.textContent = "Save to LocalStorage";
saveLocalButton.onclick = () => visualizer.saveToLocalStorage("workflow");
document.body.appendChild(saveLocalButton);
const loadLocalButton = document.createElement("button");
loadLocalButton.textContent = "Load from LocalStorage";
loadLocalButton.onclick = () => visualizer.loadFromLocalStorage("workflow", nodeOperations);
document.body.appendChild(loadLocalButton);
const executeButton = document.createElement("button");
executeButton.textContent = "Execute";
executeButton.onclick = () => {
const results = visualizer.execute();
console.log(results);
};
document.body.appendChild(executeButton);

View File

@ -0,0 +1,122 @@
class LollmsMarkdown2PDF {
constructor() {
this.markdown = '';
this.pdfDoc = null;
}
// Load Markdown content
loadMarkdown(markdown) {
this.markdown = markdown;
}
// Parse Markdown and convert to PDF
async convertToPDF() {
// We'll use the pdfkit library for PDF generation
const PDFDocument = require('pdfkit');
const fs = require('fs');
const showdown = require('showdown');
const cheerio = require('cheerio');
this.pdfDoc = new PDFDocument();
// Convert Markdown to HTML
const converter = new showdown.Converter({tables: true, strikethrough: true});
const html = converter.makeHtml(this.markdown);
// Parse HTML
const $ = cheerio.load(html);
// Process elements
$('body').children().each((i, elem) => {
this.processElement($(elem));
});
return this.pdfDoc;
}
// Process individual elements
processElement(elem) {
switch(elem.get(0).tagName.toLowerCase()) {
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
this.addHeading(elem);
break;
case 'p':
this.addParagraph(elem);
break;
case 'img':
this.addImage(elem);
break;
case 'table':
this.addTable(elem);
break;
case 'pre':
this.addCodeBlock(elem);
break;
// Add more cases for other elements
}
}
// Add heading
addHeading(elem) {
const level = parseInt(elem.get(0).tagName.slice(1));
const fontSize = 24 - (level - 1) * 2;
this.pdfDoc.fontSize(fontSize).text(elem.text(), {bold: true});
this.pdfDoc.moveDown();
}
// Add paragraph
addParagraph(elem) {
this.pdfDoc.fontSize(12).text(elem.text());
this.pdfDoc.moveDown();
}
// Add image
addImage(elem) {
const src = elem.attr('src');
if (src) {
this.pdfDoc.image(src, {fit: [400, 300], align: 'center'});
this.pdfDoc.moveDown();
}
}
// Add table
addTable(elem) {
const rows = elem.find('tr').map((i, row) => {
return $(row).find('td, th').map((j, cell) => {
return $(cell).text().trim();
}).get();
}).get();
this.pdfDoc.table(rows, {
prepareHeader: () => this.pdfDoc.font('Helvetica-Bold'),
prepareRow: (row, i) => this.pdfDoc.font('Helvetica').fontSize(12)
});
this.pdfDoc.moveDown();
}
// Add code block
addCodeBlock(elem) {
const code = elem.text();
this.pdfDoc.font('Courier').fontSize(10).text(code);
this.pdfDoc.moveDown();
}
// Save PDF to file
savePDF(outputPath) {
return new Promise((resolve, reject) => {
const stream = fs.createWriteStream(outputPath);
this.pdfDoc.pipe(stream);
this.pdfDoc.end();
stream.on('finish', resolve);
stream.on('error', reject);
});
}
}
module.exports = LollmsMarkdown2PDF;

View File

@ -88,4 +88,3 @@ class WebAppLocalizer {
});
}
}
export default WebAppLocalizer;

@ -1 +1 @@
Subproject commit 6d626309739761a8efd5616693c0329030c8aad6
Subproject commit a32971f65b5e5b85b98d38d871dc67713c2e9f28