-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
17afe82
commit 8ff4e1a
Showing
14 changed files
with
2,038 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Ignore macOS system files | ||
.DS_Store | ||
|
||
# Ignore environment variable files | ||
.env | ||
.env.* | ||
|
||
# Ignore build output directories | ||
build/ | ||
|
||
# Ignore node_modules folders | ||
node_modules/ | ||
|
||
# Ignore logs generated by as-test | ||
logs/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"plugins": ["assemblyscript-prettier"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# ModusPress | ||
|
||
This example shows how to add LLM-backed features to a fictitious web-based blog platform using [Modus](https://docs.hypermode.com/modus), the open source framework for building intelligent APIs. Specifically, this example is a Modus app that exposes a GraphQL endpoint with the | ||
|
||
- generate suggested blog post titles based on the blog post content, in the style of the author | ||
- generate HTML meta tags optimized for SEO based on the blog post content | ||
|
||
 | ||
|
||
## Setup | ||
|
||
Install the Modus CLI (if not already installed): | ||
|
||
``` | ||
npm i -g @hypermode/modus-cli | ||
``` | ||
|
||
**Seed Postgres DB** | ||
|
||
This example pulls author biography data from a Postgres database that represents the backend database for our blog platform. You'll need to create a Postgres database and seed it with author data using the following schema: | ||
|
||
 | ||
|
||
**Set database credentials in .env** | ||
|
||
If using a local Postgres database with defaults your conection credentials will look something like this: | ||
|
||
``` | ||
MODUS_MODUSPRESSDB_USERNAME=<YOUR_USERNAME_HERE> | ||
MODUS_MODUSPRESSDB_HOST=localhost | ||
MODUS_MODUSPRESSDB_PORT=5432 | ||
MODUS_MODUSPRESSDB_DBNAME=<YOUR_DB_NAME_HERE> | ||
``` | ||
|
||
**Connect to Hypermode model hosting** | ||
|
||
This example uses the LLaMa open source LLM hosted on Hypermode. You can create a free Hypermode account to leverage model hosting using the Hypermode Platform with the `hyp` cli. | ||
|
||
Install `hyp` cli: | ||
|
||
``` | ||
npm i -g @hypermode/hyp-cli | ||
``` | ||
|
||
Login to Hypermode: | ||
|
||
``` | ||
hyp login | ||
``` | ||
|
||
This command will open a web browser and prompt you to sign in or create a free Hypermode account, then select an organization. Once complete you will be able to use Hypermode hosted models in your Modus app. | ||
|
||
## Run | ||
|
||
``` | ||
modus dev | ||
``` | ||
|
||
This will build your Modus app and launch a GraphQL API at `localhost:8686/graphql` | ||
|
||
## Query | ||
|
||
You can query the GraphQL endpoint using any GraphQL client or cURL. Here we use Postman to query for suggested titles based on the blog post content and author bio retrived from Postres and then passed to the LLM. | ||
|
||
 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"extends": "./node_modules/@hypermode/modus-sdk-as/plugin.asconfig.json", | ||
"options": { | ||
"transform": ["@hypermode/modus-sdk-as/transform", "json-as/transform"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
This example Modus app exposes two GraphQL Query fields to add LLM-backed features | ||
to a hypothetical blogging platform capable of suggesting blog post titles and HTML | ||
meta tags optimized for SEO based on the blog post content in the style of the | ||
blog post author. | ||
*/ | ||
|
||
import { models, postgresql } from "@hypermode/modus-sdk-as"; | ||
|
||
import { | ||
OpenAIChatModel, | ||
ResponseFormat, | ||
SystemMessage, | ||
UserMessage, | ||
} from "@hypermode/modus-sdk-as/models/openai/chat"; | ||
|
||
// This function generates HTML meta description tag content optimized for SEO based on the blog post content | ||
export function genSEO(postContent: string): string { | ||
const suggestedTag = generateText( | ||
"You are an SEO expert", | ||
`Create the HTML meta description tag for a blog post with the following content, only return the meta tag value: ${postContent}`, | ||
); | ||
|
||
return suggestedTag; | ||
} | ||
|
||
// This function generates a suggested blog post title using the blog post content and category and leverages | ||
// the author's biography data retrieved from a Postgres database to match the author's style | ||
export function genTitle( | ||
postContent: string, | ||
postCategory: string, | ||
authorName: string, | ||
): string { | ||
const author = getAuthorByName(authorName); | ||
|
||
const suggestedTitle = generateText( | ||
"You are a copyeditor", | ||
` | ||
Create a title for the following blog post, in the style of ${author.name}. Only return the title text. | ||
Blog post content: ${postContent} | ||
Blog post category: ${postCategory} | ||
Author biography: ${author.bio} | ||
`, | ||
); | ||
|
||
return suggestedTitle; | ||
} | ||
|
||
// Use our LLM to generate text based on an instruction and prompt | ||
function generateText(instruction: string, prompt: string): string { | ||
const model = models.getModel<OpenAIChatModel>("llama"); | ||
|
||
const input = model.createInput([ | ||
new SystemMessage(instruction), | ||
new UserMessage(prompt), | ||
]); | ||
|
||
input.temperature = 0.7; | ||
const output = model.invoke(input); | ||
|
||
return output.choices[0].message.content.trim(); | ||
} | ||
|
||
// The connection host for our Postgres database, as defined in modus.json | ||
const host = "moduspressdb"; | ||
|
||
// Define a type to represent our author information | ||
@json | ||
class Author { | ||
id: i32 = 0; | ||
name!: string; | ||
bio!: string; | ||
} | ||
|
||
// Query our database to find author information | ||
function getAuthorByName(name: string): Author { | ||
const query = "select * from authors where name = $1"; | ||
|
||
const params = new postgresql.Params(); | ||
params.push(name); | ||
|
||
const response = postgresql.query<Author>(host, query, params); | ||
return response.rows[0]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"extends": "assemblyscript/std/assembly.json", | ||
"include": ["./**/*.ts"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// @ts-check | ||
|
||
import eslint from "@eslint/js"; | ||
import tseslint from "typescript-eslint"; | ||
import aseslint from "@hypermode/modus-sdk-as/tools/assemblyscript-eslint"; | ||
|
||
export default tseslint.config( | ||
eslint.configs.recommended, | ||
...tseslint.configs.recommended, | ||
aseslint.config, | ||
); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"$schema": "https://schema.hypermode.com/modus.json", | ||
"endpoints": { | ||
"default": { | ||
"type": "graphql", | ||
"path": "/graphql", | ||
"auth": "bearer-token" | ||
} | ||
}, | ||
"models": { | ||
"llama": { | ||
"sourceModel": "meta-llama/Meta-Llama-3.1-8B-Instruct", | ||
"provider": "hugging-face", | ||
"connection": "hypermode" | ||
} | ||
}, | ||
"connections": { | ||
"moduspressdb": { | ||
"type": "postgresql", | ||
"connString": "postgresql://{{USERNAME}}@{{HOST}}:{{port}}/{{DBNAME}}" | ||
} | ||
} | ||
} |
Oops, something went wrong.