Converting OpenStax Textbooks for use by LLMs—with an Example Application to Chemistry Education

David Reiss, Wolfram Solutions

dreiss@wolfram.com
(RowDefault[, (Spacer1), , (Spacer1), ])  #WolframTechConf

ABSTRACT

OpenStax textbooks are a set of around 50 open source textbooks. Their user-friendly versions (PDF, HTML,DOCX, Print) are built off of XML source files written in a custom XML format, referred to as CNXML. While these source files are not useful in their raw form for use by LLMs, the Wolfram Language can be used to parse and process them into a variety of forms that are ideal for LLM use. In particular these can be forms that to be used in Chatbooks, LLMTools, SemanticSearchIndices, APIFunctions, VectorDatabases, Notebook versions—and for use in RAG (Retrieval Augmented Generation) Educational endpoints. We show a paclet—an R&D development —with a user interface and backend Wolfram Language functions that implement these methods for any OpenStax textbook. In particular we show illustrative applications based on the OpenStax Chemistry textbooks.

Conference Talk URL: https://wolfr.am/1q1ScRIgY

A 15 km high tour of an application of Wolfram technology...

This talk is based on an unpublished R&D paclet and therefore this presentation notebook is  mostly “read only”. Fell free to contact the author with any questions!

OpenStax

Open source initiative out of Rice university

“OpenStax is part of Rice University, which is a 501(c)(3) nonprofit charitable corporation. As an educational initiative, it’s our mission to improve educational access and learning for everyone. Through our partnerships with philanthropic foundations and our alliance with other educational resource companies, we’re breaking down the most common barriers to learning. Because we believe that everyone should and can have access to knowledge.”

https://openstax.org/about

Has around 60 free/opensource textbooks

Available in PDF, HTML, Docx, Dead Trees, formats...

All but Dead Trees are free

Note that all OpenStax content is used under the Creative Commons License.  For each OpenStax textbook, the relevant Creative Commons License is located in its GIT repository directory: https://github.com/orgs/openstax/repositories?q=osbooks

OpenStax Open Source Textbooks

Produced from a custom XML markup source files called CNXML

“CNXML is a lightweight XML markup language for marking up educational content.”

Because of this we can use Wolfram Language and associated technologies to parse the CNXML source into a version amenable to a variety of post-processing workflows.

Books’ CNXML sources in Github

https://github.com/orgs/openstax/repositories?q=osbooks

Chemistry example on-line

OpenStax Github for Chemistry Example:

https://github.com/openstax/osbooks-chemistry-bundle

Individual .cnxml files are not well suited for passing onto an LLM for use or post-processing

Wolfram tech stack to the rescue

Create computable versions that can be purposed to a variety of workflow endpoints

Leveraging the Wolfram Technology Stack to Scrape an OpenStax Textbook

Import CNXML as Wolfram Language SymbolicXML

Convert SymbolicXML to a String marked up for easy transformation into a variety of computable contents

Example CNXML source (from the “Molecular Structure and Polarity” section of the “Chemistry: Atoms First 2e” textbook)

https://wolfr.am/1q2XSt7Ea

cnxmlSource=;

The CNXML source (equations are in MathML):

Framed@Pane[cnxmlSource,
ImageSize->{900,UpTo[300]},Scrollbars->True,BaseStyle->{14}]

Import as “XML” to create an XMLObject version:

Framed@Pane[ImportString[cnxmlSource,"XML"],
ImageSize->{900,UpTo[300]},Scrollbars->True,BaseStyle->{14}]

Exhaustive list of CNXML tags (excluding MathML markup tags):

A well-defined, relatively small, list

Using Wolfram Language, all MathML converted to LATEX

Replacement rules for all XMLElements

ReplaceRepeated converts XMLElements for all CNXML tags to lists of Strings

Example of such replacement rules with Custom markup strings for post processing with StringPatterns, StringCases, etc...:

XMLElement["exercise",_,x_]:>Flatten@{"<Exercise>",x,"</Exercise>"},

													

math:XMLElement[{"http://www.w3.org/1998/Math/MathML","math"},{___},_]:>
			List[" ","<TeX>",formatMathMLXMLElementByWL[math,mathMLOptions],"</TeX>"],
			
math:XMLElement["math",{{"http://www.w3.org/2000/xmlns/","xmlns"}->"http://www.w3.org/1998/Math/MathML",___},_]:>
			List[" ","<TeX>",formatMathMLXMLElementByWL[math,mathMLOptions],"</TeX>"],

Flatten and StringJoin the result

Example Processed Text:

Framed@Pane[["ScrapedData"],
  ImageSize -> {900, UpTo[300]}, Scrollbars -> True, BaseStyle -> {14}]

Example of extracting content: (TEX strings and converting them to Wolfram Language formatted expressions)

StringCases[["ScrapedData"],Shortest["<TeX>"~~tex__~~"</TeX>"]:>tex]

NotebookPut[Notebook[
Cell[
TextData[
ImportString[#,{"TeX","Cell"}]
],"Text"]&/@StringCases[["ScrapedData"],Shortest["<TeX>"~~tex__~~"</TeX>"]:>tex]
]
];

Some Wolfram Technologies Used

Generally no need to leave the tech stack!

SymbolicXML

Import/Export of MathML original markup

Round trips

SymbolicXML⟷ MathML⟷LaTeX⟷Wolfram Language Formatted Expressions

Hundreds of instances for a typical math textbook chapter

Good test of Wolfram Language’s ability to translate LATEX strings

Wolfram Cloud

Store SemanticSearchIndices, visual media, etc...

LLMTool

E. g. with SemanticSearch, Wolfram Alpha Step-by-step LLM API, etc...

Chatbook

LLMSynthesize

Various Other Parts of the Wolfram Language LLM-related Technology Stack

An Example of a MathML Round Trip

symbolicMathExpression=

mathMLString=ExportString[symbolicMathExpression,"XML"];
Framed@Pane[mathMLString,
ImageSize->{600,UpTo[600]},Scrollbars->True,BaseStyle->{14}]

boxOutput=Quiet@ImportString[mathMLString,{"MathML","Boxes"}]

CellPrint[Cell[BoxData[boxOutput],"Text"]]

((30x(y^3))/(5xy)).

teXOutput=StringTrim[Quiet@ExportString[RawBoxes@boxOutput,"TeXFragment"]]

Cell[
TextData[
ImportString[teXOutput,{"TeX","Cell"}]
],"Text"]//CellPrint

((30x(y^3))/(5xy)).

An LLM can also be used to convert MathML to a TEX string  if there is a need (less than 0.5% require this):

llmTeXOutput=
LLMSynthesize[{"Convert this MathML expression in to a LaTeX string: ",mathMLString},LLMEvaluator->
<|"Model" :>\[LeftAssociation]"Service"->"OpenAI","Name"->"gpt-4o"\[RightAssociation],"Prompts" -> {}|>,ProgressReporting->False];
llmTeXOutput=StringReplace[llmTeXOutput,"\\\\"->"\\"]

Cell[
TextData[
ImportString[llmTeXOutput,{"TeX","Cell"}]
],"Text"]//CellPrint

((30x(y^3))/(5xy)).

“Laboratory” R& D User Interface for CNXML Processing

Paclet: LLMDocumentProcessingLaboratory (the “Content Studio”)

laboratoryUI[];

Example: m68742MolecularStructureandPolarity textbook section

Example Chatbook

“Can you illustrate Lewis structures for me?”

Generating Various Workflows From an OpenStax Textbook Chapter

Process CNXML

Contains our custom computable markup

Allows us to pull out conceptually different parts

Full Text, Examples, Exercises, LATEX, ...

Have LLM create a custom prompt for the full chapter text

Prompt the LLM to create a prompt based on the chapter text

Have LLM identify the separate ‘lessons” of the full chapter text

Have the LLM provide a brief summary of each lessons

Have the LLM create a curriculum for each lesson based on (a) each summary and (b) the full content of the chapter

Have the LLM create a custom prompt for each lesson based on the created curriculum

Have LLM create an AITutor curriculum notebook

See Theo Gray’s talk for the AITutor environment (example from the chemistry textbook)

Use CreateSemanticSearchIndex to produce an SemanticSearchIndex searchable with SemanticSearch in Retrieval Augmented Generation (RAG) applications

Note that workflows within the Wolfram Language may be better called CAG (Computation Augmented Generation)

Create LLMTools that uses the SemanticSearch with the SemanticSearchIndex for RAG/CAG

Use the LLMTools in a Chatbook with a persona/prompt specialized to the textbook chapter’s content

Some Workflow Paths

All workflows start with the conversion of the CNXML source for a textbook to a computable String

“RAG”= “Retrieval Augmented Generation”
“CAG”= “Computation Augmented Generation”

Theo Gray’s Conference Talk on AITutor: https://wolfr.am/1q1RoTUIo

An alternative entry point is to use a Mathematica notebook as the authoring environment for the CNXML source

“Write your own ‘computable textbook’”

Example Full Chapter Output

$currentProcessedXMLData parameter holds the output of the UI’s processing.

$currentProcessedXMLData=;

Keys[$currentProcessedXMLData]

Top level workflow products

ScrapedData: the full result of processing the CNXML file for the chapter

Examples: StringCases used to pull out expository examples from the text

Examples = example content presented within the lesson to illustrate concept

Exercises: StringCases to pull out section exercises

Exercises = “exam”/”quiz”/”homework” problems

ScrapeDataPrompt: Prompt created by LLM to use with the full chapter’s content

For example, in a chatbook

LicenseText and ReadMeText: additional materials from the GIT repository for this chapter

Subcontent: see below...

TabView[Framed@Pane[#,
ImageSize->{900,UpTo[600]},Scrollbars->True]&/@$currentProcessedXMLData,BaseStyle->{14}]

Subcontent workflow—an example of using an LLM to partition a chapter into separate lessons:

Have the LLM determine the distinct pedagogical “daily lessons” in the chapter (“subsections”)

When determining each lesson have the LLM create a brief summary

For each lesson

Have the LLM create  the brief summary and the full content to create
	⊳ Custom curriculum content for the individual lesson
	⊳ Custom prompt specifically for the lesson’s custom curriculum

Column[Keys[$currentProcessedXMLData["Subcontent"]],Frame->All,FrameStyle->Darker@LightBlue,BaseStyle->{14}]

TabView[Framed@Pane[#,
ImageSize->{900,UpTo[650]},Scrollbars->True]&/@
(
TabView[Framed@Pane[#,
ImageSize->{700,UpTo[450]},Scrollbars->True]&/@#]&/@$currentProcessedXMLData["Subcontent"]
),BaseStyle->{14},
Appearance->{"Limited",2}]

Use ResourceFunction[“ImportMarkdownString”] to see the lessons

The LLM was prompted to produce the lesson content in MarkDown

This can be easily reviewed using this: ResourceFunction[“ImportMarkdownString”]

With[{tem=ResourceFunction["ImportMarkdownString"][StringDelete[#,"<Markdown>"|"</Markdown>"]]&/@Query[All,"CurriculumText"]@$currentProcessedXMLData["Subcontent"]},
NotebookPut@Notebook[Flatten[{KeyValueMap[{Cell[#1,"Title"],Cell[#2,"Text"]}&,tem]}]]
];

Batch-processed Textbook Workflow Endpoints

Batch processing of the full textbook

Uploading media to the WolframCloud & batch process all sections

Creation of full textbook SemanticSearchIndex and AITutor curriculum notebooks

Creation Template Notebook⟶

SemanticSearchIndex for the full textbook

Tagged by chapter and content type (ScrapedText, Examples, Exercises) for filtering queries

Note that SemanticSearchIndex[“ChemistryAtomsFirst2e”] is a SemanticSearchIndex that was locally stored on the presenter’s system.

index = SemanticSearchIndex["ChemistryAtomsFirst2e"];
searchExample = SemanticSearch[index, "Tell me about the history of acids and bases", "Items", "MaxItems" -> 5];

Framed@Pane[Column[searchExample,
   Frame -> All, FrameStyle -> {Thick, Purple}],
  ImageSize -> {900, UpTo[400]}, Scrollbars -> True, BaseStyle -> {14}]

({{"<Title>Brønsted-Lowry Acids and Bases</Title>\n<Paragraph>\nBy the end of this section, you will be able to:\n</Paragraph>\n<Item>Identify acids, bases, and conjugate acid-base pairs according to the Brønsted-Lowry definition</Item>\n<Item>Write equations for acid and base ionization reactions</Item>\n<Item>Use the ion-product constant for water to calculate hydronium and hydroxide ion concentrations</Item>\n<Item>Describe the acid-base behavior of amphiprotic substances</Item>\n\n\n\n"}, {"<Paragraph>\nThe acid-base reaction class has been studied for quite some time. In 1680, Robert   Boyle   reported traits of acid solutions that included their ability to dissolve many substances, to change the colors of certain natural dyes, and to lose these traits after coming in contact with alkali (base) solutions. In the eighteenth century, it was recognized that acids have a sour taste, react with limestone to liberate a gaseous substance (now known to be CO _2  ), and interact with alkalis to form neutral substances. In 1815, Humphry   Davy   contributed greatly to the development of the modern acid-base concept by demonstrating that hydrogen is the essential constituent of acids. Around that same time, Joseph Louis Gay-Lussac concluded that acids are substances that can neutralize bases and that these two classes of substances can be defined only in terms of each other. The significance of hydrogen was reemphasized in 1884 when Svante   Arrhenius   defined an acid as a compound that dissolves in water to yield hydrogen cations (now recognized to be hydronium ions) and a base as a compound that dissolves in water to yield hydroxide anions.\n</Paragraph>\n<Paragraph>\nJohannes Brønsted and Thomas Lowry proposed a more general description in 1923 in which acids and bases were defined in terms of the transfer of hydrogen ions, H ^+  . (Note that these hydrogen ions are often referred to simply as   protons  , since that subatomic particle is the only component of cations derived from the most abundant hydrogen isotope,  ^1  H.) A compound that donates a proton to another compound is called a   Brønsted-Lowry acid  , and a compound that accepts a proton is called a   Brønsted-Lowry base  . An acid-base reaction is, thus, the transfer of a proton from a donor (acid) to an acceptor (base).\n</Paragraph>\n<Paragraph>\nThe concept of   conjugate pairs   is useful in describing Brønsted-Lowry acid-base reactions (and other reversible reactions, as well). When an acid donates H ^+  , the species that remains is called the   conjugate base   of the acid because it reacts as a proton acceptor in the reverse reaction. Likewise, when a base accepts H ^+  , it is converted to its   conjugate acid  . The reaction between water and ammonia illustrates this idea. In the forward direction, water acts as an acid by donating a proton to ammonia and subsequently becoming a hydroxide ion, OH ^−  , the conjugate base of water. The ammonia acts as a base in accepting this proton, becoming an ammonium ion,   <TeX>$\\text{NH}_4{}^+,$</TeX>  the conjugate acid of ammonia. In the reverse direction, a hydroxide ion acts as a base in accepting a proton from ammonium ion, which acts as an acid.\n</Paragraph>"}, {"<Title>Introduction</Title>\n<Item>Brønsted-Lowry Acids and Bases</Item>\n<Item>pH and pOH</Item>\n<Item>Relative Strengths of Acids and Bases</Item>\n<Item>Hydrolysis of Salt Solutions</Item>\n<Item>Polyprotic Acids</Item>\n<Item>Buffers</Item>\n<Item>Acid-Base Titrations</Item>\n\n\n\n\n<ImageRef>\n![A photograph is shown of a pond formed in a sinkhole. Layers of limestone with trees and shrubs surround the murky green water of the pond.](https://www.wolframcloud.com/obj//Chemistry/CNX_Chem_14_00_Sinkhole.jpg)\n</ImageRef>\nSinkholes such as this are the result of reactions between acidic groundwaters and basic rock formations, like limestone. (credit: modification of work by Emil Kehnel) <Paragraph>\nLiquid water is essential to life on our planet, and chemistry involving the characteristic ions of water, H ^+   and OH ^–  , is widely encountered in nature and society. As introduced in another chapter of this text, acid-base chemistry involves the transfer of hydrogen ions from donors (acids) to acceptors (bases). These H+ transfer reactions are reversible, and the equilibria established by acid-base systems are essential aspects of phenomena ranging from sinkhole formation (   <<reference: CNX_Chem_14_00_Sinkhole>>  ) to oxygen transport in the human body. This chapter will further explore acid-base chemistry with an emphasis on the equilibrium aspects of this important reaction class.\n</Paragraph>\n   "}, {"<Title>Lewis Acids and Bases</Title>\n<Paragraph>\nBy the end of this section, you will be able to:\n</Paragraph>\n<Item>Explain the Lewis model of acid-base chemistry</Item>\n\n<Item>Write equations for the formation of adducts and complex ions</Item>\n\n<Item>Perform equilibrium calculations involving formation constants</Item>\n\n\n\n<Paragraph>\nIn 1923, G. N.   Lewis   proposed a generalized definition of acid-base behavior in which acids and bases are identified by their ability to accept or to donate a pair of electrons and form a coordinate covalent bond.\n</Paragraph>\n<Paragraph>\nA   coordinate covalent bond   (or dative bond) occurs when one of the atoms in the bond provides both bonding electrons. For example, a coordinate covalent bond occurs when a water molecule combines with a hydrogen ion to form a hydronium ion. A coordinate covalent bond also results when an ammonia molecule combines with a hydrogen ion to form an ammonium ion. Both of these equations are shown here.\n</Paragraph>\n\n"}, {"</Section>\n<Section>\n<Title>Acid-Base Reactions</Title>\n<Paragraph>\nAn   acid-base reaction   is one in which a hydrogen ion, H ^+  , is transferred from one chemical species to another. Such reactions are of central importance to numerous natural and technological processes, ranging from the chemical transformations that take place within cells and the lakes and oceans, to the industrial-scale production of fertilizers, pharmaceuticals, and other substances essential to society. The subject of acid-base chemistry, therefore, is worthy of thorough discussion, and a full chapter is devoted to this topic later in the text.\n</Paragraph>\n<Paragraph>\nFor purposes of this brief introduction, we will consider only the more common types of acid-base reactions that take place in aqueous solutions. In this context, an   acid   is a substance that will dissolve in water to yield hydronium ions, H _3  O ^+  . As an example, consider the equation shown here:\n</Paragraph>\n <TeX>$\\text{HCl}(aq)+H_2O(l)\\longrightarrow \\text{Cl}^-(aq)+H_3O^+(aq)$</TeX><Paragraph>\nThe process represented by this equation confirms that hydrogen chloride is an acid. When dissolved in water, H _3  O ^+   ions are produced by a chemical reaction in which H ^+   ions are transferred from HCl molecules to H _2  O molecules (   <<reference: CNX_Chem_04_02_HClsoln>>  ).\n</Paragraph>\n\n<ImageRef>\n"}})

This may be post processed to re-sort with “ReRanking”

Full Chatbook Example

openStaxTutorChatbook["ChemistryAtomsFirst2e"];

Example1: “What is an acid and how does it relate to orbitals”

Example2: Ask for a quiz question and then have the WolframAlpha step-by-step LLM API find the steps

({{, }})

Mathematica Notebooks as a CNXML Authoring Environment

Mathematica notebooks are the archetype of a computational document

Use Mathematica notebooks as an authoring environment for CNXML

Early prototype

Authoring notebook example input:

Early development experimental code snipped

Catch@Module[{notebookFile,notebook,targetDirectory,contentAssociation},

	notebookFile=FileNameJoin[{NotebookDirectory[],"NotebookAuthoringEnvironment","Phases and Classification of Matter.nb"}];

	
	targetDirectory=
		FileNameJoin[{NotebookDirectory[],
			"ExampleCNXMLDocument"<>DateString[Riffle[{"Year","Month","Day","Hour","Minute","Second"},"_"],TimeZone->"GMT"]}];
		
	CreateDirectory[targetDirectory];
	
	createCNXMLDirectoryHierarchy[targetDirectory];
	
	contentAssociation=
		<|
			"booktitle"->"Example Document",
			"bookname"->"example-document",
			"content"->
			"<col:subcollection>
	      <md:title>This is an Example of a CNXML Document</md:title>
	      <col:content>
	        <col:module document=\"m00001\"/>
	      </col:content>
	    </col:subcollection>",
	    
	    "Modules"->
				{
					importNBAsCNXML[notebookFile,{"Example Document 101","m00001"},"MediaDirectory"->FileNameJoin[{targetDirectory,"media"}]]
				}
		|>;
		
		If[AnyTrue[contentAssociation["Modules"],FailureQ],
			Throw[$Failed]
		];
		
		exportCNXMLContent[contentAssociation,targetDirectory];
		
		Button["Open Output CNXML Directory",SystemOpen[#]]&[targetDirectory]
	]

Creates a CNXML directory

Then, process the result in the User Interface:

Some workflow products from this:

Chatbook with SemanticSearch LLMTool for RAG

AITutor Curriculum Notebook

AITutor Curriculum “Expanded” Notebook

Etc...

Summary

Using the Wolfram Tech Stack we can process any textbook in CNXML format into a computable form for a wide variety of possible Workflow endpoints

Mathematica notebooks potentially are an ideal authoring environment for CNXML content

Recommendation: Write your course materials in Mathematica notebooks! Then use this tech stack to transform them into various LLM endpoints...