feat: add algorithm to parse ranges with markup

Signed-off-by: Sphericalkat <amolele@gmail.com>
This commit is contained in:
sphericalkat committed 2023-05-27 22:57:56 +05:30
1 parent 848cd514d0
commit 4b8607b12a
16 files changed
+814 -13

No files matched your search

+2 -1
View File
@@ -1,2 +1,3 @@
.env
node_modules
node_modules
frontend/dist
+25 -1
View File
@@ -1,6 +1,11 @@
package routes
import (
"fmt"
"log"
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/medium.rip/pkg/client"
)
@@ -16,7 +21,26 @@ func show(c *fiber.Ctx) error {
return err
}
return c.JSON(e)
post := e.Data.Post
publishDate := time.UnixMilli(e.Data.Post.CreatedAt)
log.Println(publishDate)
var sb strings.Builder
for _, node := range post.Content.BodyModel.Paragraphs {
switch node.Type {
case "H3":
sb.WriteString(fmt.Sprintf("<h3>%s</h3>", node.Text))
}
}
return c.Render("show", fiber.Map {
"Title": post.Title,
"UserId": post.Creator.ID,
"Author": post.Creator.Name,
"PublishDate": publishDate.Format(time.DateOnly),
"Nodes": post.Content.BodyModel.Paragraphs,
})
}
func index(c *fiber.Ctx) error {
-1
View File
@@ -1 +0,0 @@
*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.text-2xl{font-size:1.5rem;line-height:2rem}:root{--accent: #23b0ff;--background: #1f222a}html,body{width:100%;height:100%}html{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}@media (min-width: 1024px){html{font-size:1.125rem;line-height:1.7777778}}body{background-color:#1f222a;color:#fff;line-height:1.54;letter-spacing:-.02em;font-variant-ligatures:contextual;font-size:1rem}.text-accent{color:var(--accent)}.bg-accent{background:var(--accent)}
+1 -1
View File
@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .Title }}</title>
<link rel="stylesheet" href="/assets/index-4d1e72db.css">
<link rel="stylesheet" href="/assets/index-bab4abd8.css">
</head>
<body>
<h1 class="text-2xl">Hello, World!</h1>
+35
View File
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"
rel="stylesheet">
<title>{{ .Title }}</title>
<link rel="stylesheet" href="/assets/show-1b4526c3.css">
</head>
<body class="flex flex-col h-full w-full items-center">
<article class="prose lg:prose-xl pt-20">
<h2 class="text-2xl">{{.Title}}</h2>
<p><a href="https://medium.com/u/{{.UserId}}">{{.Author}}</a> on {{.PublishDate}}</p>
{{range .Nodes}}
{{if eq .type "H3"}}
<h3>.text</h3>
{{end}}
{{if eq .type "IMG"}}
<h3>.text</h3>
{{end}}
{{end}}
</article>
</body>
</html>
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="src/index.css">
<link rel="stylesheet" href="src/styles.css">
<title>{{ .Title }}</title>
</head>
<body>
+1
View File
@@ -12,6 +12,7 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@tailwindcss/typography": "^0.5.9",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.23",
"tailwindcss": "^3.3.2",
+35
View File
@@ -1,6 +1,9 @@
lockfileVersion: '6.0'
devDependencies:
'@tailwindcss/typography':
specifier: ^0.5.9
version: 0.5.9(tailwindcss@3.3.2)
autoprefixer:
specifier: ^10.4.14
version: 10.4.14(postcss@8.4.23)
@@ -274,6 +277,18 @@ packages:
fastq: 1.15.0
dev: true
/@tailwindcss/typography@0.5.9(tailwindcss@3.3.2):
resolution: {integrity: sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
tailwindcss: 3.3.2
dev: true
/any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
dev: true
@@ -557,6 +572,18 @@ packages:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
/lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
dev: true
/lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
dev: true
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -697,6 +724,14 @@ packages:
postcss-selector-parser: 6.0.13
dev: true
/postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
dev: true
/postcss-selector-parser@6.0.13:
resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==}
engines: {node: '>=4'}
+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="src/show.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"
rel="stylesheet">
<title>{{ .Title }}</title>
</head>
<body class="flex flex-col h-full w-full items-center">
<article class="prose lg:prose-xl pt-20">
<h2 class="text-2xl">{{.Title}}</h2>
<p><a href="https://medium.com/u/{{.UserId}}">{{.Author}}</a> on {{.PublishDate}}</p>
{{range .Nodes}}
{{if eq .type "H3"}}
<h3>.text</h3>
{{end}}
{{if eq .type "IMG"}}
<h3>.text</h3>
{{end}}
{{end}}
</article>
</body>
</html>
+37
View File
@@ -0,0 +1,37 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--accent: #23b0ff;
--background: #1f222a;
}
html, body {
width: 100%;
height: 100%;
}
@media (min-width: 1024px) {
html {
font-size: 1.125rem;
line-height: 1.7777778;
}
}
body {
/* background-color: #1f222a; */
/* color: #ffffff; */
/* line-height: 1.54;
letter-spacing: -0.02em;
font-variant-ligatures: contextual;
font-size: 1rem; */
}
.text-accent {
color: var(--accent);
}
.bg-accent {
background: var(--accent);
}
@@ -12,10 +12,6 @@ html, body {
height: 100%;
}
html {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
}
@media (min-width: 1024px) {
html {
font-size: 1.125rem;
+47 -3
View File
@@ -1,8 +1,52 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.ts", "./*.html"],
content: ["./src/**/*.ts", "./**/*.html"],
theme: {
extend: {},
fontFamily: {
'sans': ['Inter'],
},
extend: {
typography: ({ theme }) => ({
pink: {
css: {
'--tw-prose-body': theme('colors.pink[800]'),
'--tw-prose-headings': theme('colors.pink[900]'),
'--tw-prose-lead': theme('colors.pink[700]'),
'--tw-prose-links': theme('colors.pink[900]'),
'--tw-prose-bold': theme('colors.pink[900]'),
'--tw-prose-counters': theme('colors.pink[600]'),
'--tw-prose-bullets': theme('colors.pink[400]'),
'--tw-prose-hr': theme('colors.pink[300]'),
'--tw-prose-quotes': theme('colors.pink[900]'),
'--tw-prose-quote-borders': theme('colors.pink[300]'),
'--tw-prose-captions': theme('colors.pink[700]'),
'--tw-prose-code': theme('colors.pink[900]'),
'--tw-prose-pre-code': theme('colors.pink[100]'),
'--tw-prose-pre-bg': theme('colors.pink[900]'),
'--tw-prose-th-borders': theme('colors.pink[300]'),
'--tw-prose-td-borders': theme('colors.pink[200]'),
'--tw-prose-invert-body': theme('colors.pink[200]'),
'--tw-prose-invert-headings': theme('colors.white'),
'--tw-prose-invert-lead': theme('colors.pink[300]'),
'--tw-prose-invert-links': theme('colors.white'),
'--tw-prose-invert-bold': theme('colors.white'),
'--tw-prose-invert-counters': theme('colors.pink[400]'),
'--tw-prose-invert-bullets': theme('colors.pink[600]'),
'--tw-prose-invert-hr': theme('colors.pink[700]'),
'--tw-prose-invert-quotes': theme('colors.pink[100]'),
'--tw-prose-invert-quote-borders': theme('colors.pink[700]'),
'--tw-prose-invert-captions': theme('colors.pink[400]'),
'--tw-prose-invert-code': theme('colors.white'),
'--tw-prose-invert-pre-code': theme('colors.pink[300]'),
'--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
'--tw-prose-invert-th-borders': theme('colors.pink[600]'),
'--tw-prose-invert-td-borders': theme('colors.pink[700]'),
},
},
}),
},
},
plugins: [],
plugins: [
require('@tailwindcss/typography'),
],
};
+86
View File
@@ -0,0 +1,86 @@
package converters
import (
"sort"
"github.com/medium.rip/pkg/entities"
)
type RangeWithMarkup struct {
Range []int
Markups []entities.Markup
}
func unique(intSlice []int) []int {
keys := make(map[int]bool)
list := []int{}
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
func ranges(text string, markups []entities.Markup) []RangeWithMarkup {
ranges := make([]RangeWithMarkup, 0)
// first, get all the borders of the markups
markupBoundaries := make([]int, 0)
for _, m := range markups {
markupBoundaries = append(markupBoundaries, []int{int(m.Start), int(m.End)}...)
}
// include the start and end indexes of the text
markupBoundaries = append([]int{0}, markupBoundaries...)
markupBoundaries = append(markupBoundaries, len(text))
// remove duplicates
markupBoundaries = unique(markupBoundaries)
// sort slice
sort.Slice(markupBoundaries, func(i, j int) bool {
return markupBoundaries[i] < markupBoundaries[j]
})
// attach markup to every range
for i := 0; i < len(markupBoundaries)-1; i++ {
start := markupBoundaries[i]
end := markupBoundaries[i+1]
// check if this markup is covered by the range
coveredMarkups := make([]entities.Markup, 0)
for _, m := range markups {
if (int(m.Start) >= start && int(m.Start) < end) || (int(m.End - 1) >= start && int(m.End - 1) < end) {
coveredMarkups = append(coveredMarkups, m)
}
}
// append the range
ranges = append(ranges, RangeWithMarkup{
Range: []int{start, end},
Markups: coveredMarkups,
})
}
return ranges
}
func Convert(text string, markups []entities.Markup) {
// for _, m := range markups {
// switch m.Type {
// case "A":
// if m.Href != nil {
// } else if {
// m.UserID != nil {
// }
// }
// case "CODE":
// case "EM":
// case "STRONG":
// }
// }
}
+58
View File
@@ -0,0 +1,58 @@
package converters
import (
"testing"
"github.com/medium.rip/pkg/entities"
)
func TestRanges(t *testing.T) {
ranges := ranges("strong and emphasized only", []entities.Markup{
{
Type: "STRONG",
Start: 0,
End: 10,
},
{
Type: "EM",
Start: 7,
End: 21,
},
})
if len(ranges) != 4 {
t.Errorf("Expected 4 ranges, got %d", len(ranges))
}
if ranges[0].Range[0] != 0 || ranges[0].Range[1] != 7 {
t.Errorf("Expected range to be [0, 7], got %v", ranges[0].Range)
}
if ranges[0].Markups[0].Type != "STRONG" {
t.Errorf("Expected markup to be STRONG, got %s", ranges[0].Markups[0].Type)
}
if ranges[1].Range[0] != 7 || ranges[1].Range[1] != 10 {
t.Errorf("Expected range to be [7, 10], got %v", ranges[1].Range)
}
if ranges[1].Markups[0].Type != "STRONG" {
t.Errorf("Expected markup to be STRONG, got %s", ranges[1].Markups[0].Type)
}
if ranges[2].Range[0] != 10 || ranges[2].Range[1] != 21 {
t.Errorf("Expected range to be [10, 21], got %v", ranges[2].Range)
}
if ranges[2].Markups[0].Type != "EM" {
t.Errorf("Expected markup to be EM, got %s", ranges[2].Markups[0].Type)
}
if ranges[3].Range[0] != 21 || ranges[3].Range[1] != 26 {
t.Errorf("Expected range to be [21, 26], got %v", ranges[3].Range)
}
if len(ranges[3].Markups) != 0 {
t.Errorf("Expected markup to be empty, got %v", ranges[3].Markups)
}
}
+452 -1
View File
@@ -1 +1,452 @@
{"data":{"post":{"title":"Pandas AI — The Future of Data Analysis","createdAt":1683185501743,"creator":{"id":"b856005e5ecd","name":"Fareed Khan"},"content":{"bodyModel":{"paragraphs":[{"name":"b238","text":"Pandas AI — The Future of Data Analysis","type":"H3","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"cbfd","text":"","type":"IMG","href":null,"layout":"INSET_CENTER","markups":[],"iframe":null,"metadata":{"id":"1*awdsJFX9yyTGK7Ym9I2TtA.png","originalWidth":1481,"originalHeight":758}},{"name":"2c3a","text":"Imagine being able to talk to your data like it’s your best friend. That’s what Pandas AI does! This Python library has generative artificial intelligence capabilities that can turn your dataframes into conversationalists. No more endless hours of staring at rows and columns.","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"a1ee","text":"But don’t worry, Pandas AI is not here to replace your beloved Pandas. It’s here to enhance it! With Pandas AI, you can take your data analysis and manipulation to the next level. Think of it like a superhero sidekick — it’s there to help you save the day and make your life easier.","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"5514","text":"The possibilities with Pandas AI are endless. Imagine having a dataframe that can write its own reports, or one that can analyze complex data and provide you with easy-to-understand summaries.","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"5171","text":"In this quick guide, you’ll get a step-by-step walkthrough of how to use this cutting-edge library, regardless of your level of experience in the field.","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"ab65","text":"Whether you’re an experienced data analyst or a beginner, this guide will equip you with all the tools you need to dive into the world of Pandas AI with confidence. So sit back, relax, and let’s explore the exciting possibilities that Pandas AI has to offer!","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"42f1","text":"Official GitHub Repository — https://github.com/gventuri/pandas-ai","type":"P","href":null,"layout":null,"markups":[{"title":"","type":"A","href":"https://github.com/gventuri/pandas-ai","userId":null,"start":29,"end":66,"anchorType":"LINK"},{"title":null,"type":"STRONG","href":null,"userId":null,"start":0,"end":28,"anchorType":null}],"iframe":null,"metadata":null},{"name":"7b4c","text":"Code— https://colab.research.google.com/drive/1rKz7TudOeCeKGHekw7JFNL4sagN9hon-?usp=sharing","type":"P","href":null,"layout":null,"markups":[{"title":"","type":"A","href":"https://colab.research.google.com/drive/1rKz7TudOeCeKGHekw7JFNL4sagN9hon-?usp=sharing","userId":null,"start":6,"end":91,"anchorType":"LINK"},{"title":null,"type":"STRONG","href":null,"userId":null,"start":0,"end":4,"anchorType":null}],"iframe":null,"metadata":null},{"name":"ae7c","text":"Installing Pandas AI using pip","type":"H4","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"51fe","text":"pip install pandasai","type":"PRE","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"4f69","text":"Our DataFrame contains information about various countries, including their GDP (in millions of USD) and happiness index scores. It consists of 10 rows and 3 columns:","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"4b06","text":"","type":"IMG","href":null,"layout":"INSET_CENTER","markups":[],"iframe":null,"metadata":{"id":"1*FvevlIS-mnRSvqg2Nq5JnQ.png","originalWidth":925,"originalHeight":809}},{"name":"29ef","text":"Importing PandasAI with OpenAI","type":"H4","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"2656","text":"In the next step, we’ll import the pandasai library that we installed earlier and then import the LLM (Large Language Model) feature. As of May 2023, pandasai only supports the OpenAI model, which we’ll be utilizing understand the data.","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"a57a","text":"","type":"IMG","href":null,"layout":"INSET_CENTER","markups":[],"iframe":null,"metadata":{"id":"1*RsVA6lJngSkpSs_BB9yZAg.png","originalWidth":939,"originalHeight":409}},{"name":"e33e","text":"To use the OpenAI API, you must generate your own unique API key. If you haven’t done so already, you can easily create an account on the platform’s official website at platform.openai.com. Once you’ve created your account, you’ll receive an instant $5 credit that can be used to explore and experiment with the API.","type":"P","href":null,"layout":null,"markups":[],"iframe":null,"metadata":null},{"name":"a3ab","text":"Initializing PandasAI and asking Question","typeLine truncated
{
"data": {
"post": {
"title": "Pandas AI — The Future of Data Analysis",
"createdAt": 1683185501743,
"creator": {
"id": "b856005e5ecd",
"name": "Fareed Khan"
},
"content": {
"bodyModel": {
"paragraphs": [
{
"name": "b238",
"text": "Pandas AI — The Future of Data Analysis",
"type": "H3",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "cbfd",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*awdsJFX9yyTGK7Ym9I2TtA.png",
"originalWidth": 1481,
"originalHeight": 758
}
},
{
"name": "2c3a",
"text": "Imagine being able to talk to your data like it’s your best friend. That’s what Pandas AI does! This Python library has generative artificial intelligence capabilities that can turn your dataframes into conversationalists. No more endless hours of staring at rows and columns.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "a1ee",
"text": "But don’t worry, Pandas AI is not here to replace your beloved Pandas. It’s here to enhance it! With Pandas AI, you can take your data analysis and manipulation to the next level. Think of it like a superhero sidekick — it’s there to help you save the day and make your life easier.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "5514",
"text": "The possibilities with Pandas AI are endless. Imagine having a dataframe that can write its own reports, or one that can analyze complex data and provide you with easy-to-understand summaries.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "5171",
"text": "In this quick guide, you’ll get a step-by-step walkthrough of how to use this cutting-edge library, regardless of your level of experience in the field.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "ab65",
"text": "Whether you’re an experienced data analyst or a beginner, this guide will equip you with all the tools you need to dive into the world of Pandas AI with confidence. So sit back, relax, and let’s explore the exciting possibilities that Pandas AI has to offer!",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "42f1",
"text": "Official GitHub Repository — https://github.com/gventuri/pandas-ai",
"type": "P",
"href": null,
"layout": null,
"markups": [
{
"title": "",
"type": "A",
"href": "https://github.com/gventuri/pandas-ai",
"userId": null,
"start": 29,
"end": 66,
"anchorType": "LINK"
},
{
"title": null,
"type": "STRONG",
"href": null,
"userId": null,
"start": 0,
"end": 28,
"anchorType": null
}
],
"iframe": null,
"metadata": null
},
{
"name": "7b4c",
"text": "Code— https://colab.research.google.com/drive/1rKz7TudOeCeKGHekw7JFNL4sagN9hon-?usp=sharing",
"type": "P",
"href": null,
"layout": null,
"markups": [
{
"title": "",
"type": "A",
"href": "https://colab.research.google.com/drive/1rKz7TudOeCeKGHekw7JFNL4sagN9hon-?usp=sharing",
"userId": null,
"start": 6,
"end": 91,
"anchorType": "LINK"
},
{
"title": null,
"type": "STRONG",
"href": null,
"userId": null,
"start": 0,
"end": 4,
"anchorType": null
}
],
"iframe": null,
"metadata": null
},
{
"name": "ae7c",
"text": "Installing Pandas AI using pip",
"type": "H4",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "51fe",
"text": "pip install pandasai",
"type": "PRE",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "4f69",
"text": "Our DataFrame contains information about various countries, including their GDP (in millions of USD) and happiness index scores. It consists of 10 rows and 3 columns:",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "4b06",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*FvevlIS-mnRSvqg2Nq5JnQ.png",
"originalWidth": 925,
"originalHeight": 809
}
},
{
"name": "29ef",
"text": "Importing PandasAI with OpenAI",
"type": "H4",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "2656",
"text": "In the next step, we’ll import the pandasai library that we installed earlier and then import the LLM (Large Language Model) feature. As of May 2023, pandasai only supports the OpenAI model, which we’ll be utilizing understand the data.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "a57a",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*RsVA6lJngSkpSs_BB9yZAg.png",
"originalWidth": 939,
"originalHeight": 409
}
},
{
"name": "e33e",
"text": "To use the OpenAI API, you must generate your own unique API key. If you haven’t done so already, you can easily create an account on the platform’s official website at platform.openai.com. Once you’ve created your account, you’ll receive an instant $5 credit that can be used to explore and experiment with the API.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "a3ab",
"text": "Initializing PandasAI and asking Question",
"type": "H4",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "52ae",
"text": "Afterwards, we’ll provide our OpenAI model to Pandas AI and ask various questions.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "37d9",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*UtA6DMSuzKtKOX5mNyfhCA.png",
"originalWidth": 940,
"originalHeight": 226
}
},
{
"name": "7578",
"text": "When using pandas_ai.run, two parameters are necessary: the dataframe you’re working with and the question you’re seeking an answer to, it returns the top 5 happiest countries based on the supplied dataframe.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "8f1b",
"text": "Asking Complex Questions",
"type": "H4",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "6388",
"text": "Let’s check whether it can draw the plots for us?",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "1495",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*0mLGIH_2j4K0OC9SZzNrZQ.png",
"originalWidth": 940,
"originalHeight": 153
}
},
{
"name": "140d",
"text": "Yes it does plot the graph, based on the question I asked.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "a242",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*zxjcTNyFUFSn2g9aeLrImw.png",
"originalWidth": 900,
"originalHeight": 863
}
},
{
"name": "d6ec",
"text": "Let’s perform a complex task, removing NAN values from the below dataset:",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "48b0",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*5wd-jewNp91MNc69DPDe8Q.png",
"originalWidth": 503,
"originalHeight": 481
}
},
{
"name": "c589",
"text": "This is the output we get:",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "a830",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*VAEUvjecOWIz5JLtMKLCDg.png",
"originalWidth": 940,
"originalHeight": 137
}
},
{
"name": "b01d",
"text": "But when I print the df variable again, it does remove those NAN values from the dataset, removing that row entirely",
"type": "P",
"href": null,
"layout": null,
"markups": [
{
"title": null,
"type": "STRONG",
"href": null,
"userId": null,
"start": 21,
"end": 23,
"anchorType": null
}
],
"iframe": null,
"metadata": null
},
{
"name": "9b78",
"text": "",
"type": "IMG",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": null,
"metadata": {
"id": "1*vomhvRkNY_B4v3M7bhoXJA.png",
"originalWidth": 496,
"originalHeight": 400
}
},
{
"name": "f25e",
"text": "The pandasai library offers an extensive range of possibilities, and you can explore them all by visiting their official repository page, which I’ve shared earlier.",
"type": "P",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "6d46",
"text": "It’s important to note that working with pandasai involves OpenAI pricing, and you can find the most up-to-date pricing information on their website. As of May 2023, the pricing is approximately 1000 tokens per $0.0200 (for the GPT-3.5-Turbo Model). When posing a question, it’s crucial to remember that the entire dataframe is passed along with the question every time, so it may not be an ideal solution for handling large datasets.",
"type": "H4",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
},
{
"name": "67b7",
"text": "If you have any query feel free to ask me!",
"type": "H3",
"href": null,
"layout": null,
"markups": [],
"iframe": null,
"metadata": null
}
]
}
}
}
}
}
View File
Whitespace-only changes.