LittleX Full Guide#
Building an Application with Jaseci#
This guide introduces how the Jaseci Stack accelerates application development by leveraging its graph-based programming model. With Jaseci, we can focus on implementing features rather than setting up complex systems. As you explore Jaseci’s features, you’ll uncover its wide range of use cases. This guide provides a quick introduction, helping you set up the Jaseci framework, define nodes, edges, and walkers, and craft application logic for your project.
What We Will Build#
We’ll develop a web application called LittleX, a streamlined and efficient version of Elon Musk’s X, using the Jaseci Stack. This project highlights the simplicity and power of Jaseci, enabling us to implement advanced features with minimal code and effort, tasks that typically require considerable time in traditional frameworks.
Key Features#
- User authentication: Sign up, log in, and profile management.
- Content management: Create, view, and interact with posts.
- Social interactions: Follow users and explore their content.
With Jaseci, we can focus on building these features seamlessly rather than dealing with the complexities of system setup. This guide focuses on the backend for LittleX, showcasing how Jaseci efficiently handles user authentication and database operations.
Why Jaseci?#
Jaseci empowers developers to build smarter applications with less hassle by:
- Simplifying User Management: It handles signup, login, and security out of the box.
- Connecting Data Easily: Perfect for building apps that need to model relationships, like social networks or recommendation systems.
- Scalability Built-In: Designed for cloud performance, so your app grows seamlessly with your users.
- AI at Your Fingertips: Adds intelligent features like personalization and moderation with minimal effort.
What You Need#
To get started with building LittleX, ensure you have the following:
- About 15 minutes: Time required to set up and explore the basics.
- A favorite text editor or IDE: Any development environment you are comfortable with.
- Python 3.12 or later: Ensure that Python 3.12 or higher is installed in your environment.
- Install required libraries: Jaclang, Jac-Cloud, and MTLLM.
- Node.js (optional): If you plan to integrate a frontend in future steps.
LittleX Architecture#
graph TD
%% Root Nodes
Root1((Root1)):::root --> P1[Profile]:::profile
%% Tweets
P1 -->|Post| T1(Tweet):::tweet
P1 -->|Post| T2(Tweet):::tweet
%% Comments for P1's Tweet
T1 --> C1(Comment):::comment
C1 --> C1a(Comment):::comment
C1 --> C1b(Comment):::comment
graph TD
%% Subgraph 1: Root1
subgraph Cluster1[ ]
direction TB
Root1((Root1)):::root
Root1 --> P1[Profile]:::profile
P1 -->|Post| T1(Tweet):::tweet
P1 -->|Post| T2(Tweet):::tweet
T2 --> C4(Comment):::comment
Root1 -- Follow --> P2
Root1 -- Like --> T3
end
%% Subgraph 2: Root2
subgraph Cluster2[ ]
direction TB
Root2((Root2)):::root
Root2 --> P2[Profile]:::profile
P2 -->|Post| T3(Tweet):::tweet
P2 -->|Post| T4(Tweet):::tweet
T3 --> C1(Comment):::comment
C1 --> C1a(Comment):::comment
C1 --> C1b(Comment):::comment
Root2 --> T7(Tweet):::tweet
T7 --> C5(Comment):::comment
P2 -- Follow --> P3
end
%% Subgraph 3: Root3
subgraph Cluster3[ ]
direction TB
Root3((Root3)):::root
Root3 --> P3[Profile]:::profile
P3 -->|Post| T5(Tweet):::tweet
P3 -->|Post| T6(Tweet):::tweet
T5 --> C2(Comment):::comment
T6 --> C3(Comment):::comment
end
LittleX’s graph-based architecture uses nodes for entities like users and posts and edges for relationships like following or reacting. Nodes store attributes and behaviors, while edges capture properties like timestamps. Walkers traverse the graph, enabling dynamic actions and interactions. This design ensures efficient relationship handling, scalability, and extensibility for social media-like features.
Getting Started#
Set Up Jaseci#
Lesson 1: Creating Nodes#
Jaclang, language used in Jaseci stack, organizes data as interconnected nodes within a spatial or graph-like structure. It focuses on the relationships between data points, rather than processing them step-by-step.
Nodes
A node is the fundamental unit of the Jaseci stack. Each node represents an object, entity, or a piece of data.
First create a node with name Person and attributes name, age.
- The
node
keyword defines a node entity in the graph (Person
). - The
has
keyword specifies the attributes of the node. name
,age
are variable names (attributes of thePerson
node).str
,int
are the corresponding data types of these variables (str
for string,int
for integer).
Abilities
Nodes, Walkers in Jaclang can have abilities defined to perform specific tasks. These abilities are structured as entry and exit points.
Imagine a smart home system where each room is represented as a node. Walkers traverse these nodes, performing tasks like turning lights on or off, adjusting temperature, or sending alerts when entering or exiting a room.
Entry When someone enters a room:
- Lights Turn On: The system detects entry and automatically switches on the lights to ensure the person feels welcomed.
- Room Occupied: The system marks the room as occupied in its database or tracking system.
You enter the Living Room, and the system turns on the lights and logs your presence.
Exit When someone exits a room:
- Lights Turn Off: The system detects the exit and switches off the lights to save energy.
- Room Vacant: It marks the room as unoccupied in its tracking system.
You leave the Living Room, and the system turns off the lights and updates its records to show the room is vacant.
For more details on nodes see the Nodes and Edges documentation
Now, let's create the required nodes for LittleX.
Nodes are essential for representing entities in LittleX. Here are the nodes we need to create:
-
Implement Profile Node#
- Represents the user.
- Fields: username
- Profile node should have the abilities to be updated, retrieved, followed, and unfollowed.
-
Implement Profile Node Abilities#
-
Update Ability#
self.username = here.new_username
updates the username ofProfile
node using new_username attribute of walker(here).report self
outputsProfile
node as response.
-
Get Ability#
impl Profile.get { follwers=[{"id": jid(i), "username": i.username} for i in [self-->(`?Profile)]]; report {"user": self, "followers": follwers}; }
follwers = [...
] creates a list of dictionaries containingid
andusername
for each connectedProfile
node (followers).jid(i)
retrieves the unique Jac ID of each follower node.[self-->(?Profile)]
collects all Profile nodes connected via outgoing edges from current Profile.report {"user": self, "followers": follwers}
returns the currentProfile
node and its list of followers in a structured format.
-
Follow Ability#
impl Profile.follow{ current_profile = [root-->(`?Profile)]; current_profile[0] +>:Follow():+> self; report self; }
current_profile = [root-->(?Profile)]
retrieves all Profile nodes directly connected from the root node.current_profile[0] +>:Follow():+> self
creates aFollow
edge from the first profile node to current Profile, establishing the follow relationship.report self
returns the followedProfile
node as the response.
-
Unfollow Ability#
impl Profile.un_follow { current_profile = [root-->(`?Profile)]; follow_edge = [edge current_profile[0] ->:Follow:-> self]; del follow_edge[0]; report self; }
current_profile = [root-->(?Profile)]
retrieves all Profile nodes connected from the root node.follow_edge = [edge current_profile[0] ->:Follow:-> self]
finds the existingFollow
edge from the current user to first Profiles.del follow_edge[0]
removes the first matched Follow edge, effectively unfollowing the user.report self
returns the unfollowedProfile
node as the response.
-
-
Implement Tweet Node#
- Represents an individual tweet.
- Fields: content, embedding, created_at (timestamp)
- Tweet node should have the abilities to be updated, removed, liked, unliked, commented.
node Tweet { has content: str; has embedding: list; has created_at: str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"); can update with update_tweet exit; can delete with remove_tweet exit; can like_tweet with like_tweet entry; can remove_like with remove_like entry; can comment with comment_tweet entry; def get_info()-> TweetInfo; can get with load_feed entry; }
-
Implement Tweet Node Abilities#
-
Update Ability#
self.content = here.updated_content
updates thecontent
attribute of theTweet
node with the new content provided by the walker (here).report self
returns the updatedTweet
node as the response.
-
Delete Ability#
del self
deletes the currentTweet
node (self
) from the graph.
-
Like Tweet Ability#
impl Tweet.like_tweet { current_profile = [root-->(`?Profile)]; self +>:Like():+> current_profile[0]; report self; }
current_profile = [root-->(?Profile)]
fetches the current user's Profile node from the root.self +>:Like():+> current_profile[0]
creates aLike
edge from theTweet
node (self
) to the current user'sProfile
node.report self
returns theTweet
node after the like operation.
-
Remove Like Tweet Ability#
impl Tweet.remove_like { current_profile = [root-->(`?Profile)]; like_edge = [edge self ->:Like:-> current_profile[0]]; del like_edge[0]; report self; }
current_profile = [root-->(?Profile)]
gets the current user's Profile node.like_edge = [edge self ->:Like:-> current_profile[0]]
finds theLike
edge from theTweet
node (self
) to the current user's profile.del like_edge[0]
deletes the foundLike
edgereport self
returns theTweet
node after removing the like.
-
Comment Ability#
impl Tweet.comment { current_profile = [root-->(`?Profile)]; comment_node = current_profile[0] ++> Comment(content=here.content); _.perm_grant(comment_node[0], level="CONNECT"); self ++> comment_node[0]; report comment_node[0]; }
-
current_profile = [root-->(?Profile)]
fetches the current user's Profile node. -
comment_node = current_profile[0] ++> Comment(content=here.content)
creates aComment
node with the given content, connected from the user's profile. -
_.perm_grant(comment_node[0], level="CONNECT")
grants connection permissions to the newly createdComment
node. -
self ++> comment_node[0]
links theComment
node to theTweet
node (self). -
report comment_node[0]
returns the createdComment
node as the response.
-
-
Get Tweet Information Method#
impl Tweet.get_info { return TweetInfo( username=[self<-:Post:<-][0].username, id=jid(self), content=self.content, embedding=self.embedding, likes=[i.username for i in [self->:Like:->]], comments=[{"username": [i<--(`?Profile)][0].username, "id": jid(i), "content": i.content} for i in [self-->(`?Comment)]] ); }
username=[self<-:Post:<-][0].username
retrieves the username of the profile that posted the tweet.id=jid(self)
gets the uniquejid
of the tweet node.content=self.content
returns the content of the tweet.embedding=self.embedding
returns the embedding associated with the tweet (if any).likes=[i.username for i in [self->:Like:->]]
collects the usernames of profiles who liked the tweet.comments=[{"username": [i<--(?Profile)][0].username, "id": jid(i)
,"content": i.content} for i in [self-->(?Comment)]]
collects comments on the tweet along with the commenter's username, comment ID, and content.
-
Get Tweet Ability#
impl Tweet.get { tweet_info = self.get_info(); similarity = search_tweets(here.search_query, tweet_info.content); here.results.append({"Tweet_Info": tweet_info, "similarity": similarity}); }
-
tweet_info = self.get_info()
retrieves detailed information of the tweet using theget_info
ability. -
similarity = search_tweets(here.search_query, tweet_info.content)
computes the similarity between the tweet content and the provided search query. -
here.results.append({"Tweet_Info": tweet_info, "similarity": similarity})
appends the tweet info and its similarity score to the walker's results.
-
-
-
Implement Comment Node#
- Represents comments for the tweets.
- Fields: content.
-
Implement Comment Node Abilities#
Lesson 2: Creating Edges#
Edges
Edge represents the connections or relationships between nodes. Edges can be unidirectional or bidirectional.
First, create an edge named Relation with the attribute 'since'.
- The
edge
keyword defines a relationship between nodes (Relation). - The
has
keyword specifies the attributes of the edge. int
is used for integer values (years).str
is used for string values (names).
For more details on edges see the Nodes and Edges documentation
Now, let's create the required edges for LittleX.
Edges define the relationships between nodes. Here are the edges we need to create:
Lesson 3: Creating Walkers#
Walkers are graph-traversing agents in Jaclang that perform tasks without requiring initialization and can define abilities for various node types. The Jaseci stack automatically converts walkers into RESTful API endpoints.
First, create a walker named Relation with the attribute 'name'.
As we already mentioned walkers can have abilities that can be executed on entry/exit of specific walker or entry to / exit from a specific node.For more explanation on abilities see Lesson 1: Creating Nodes
For more explanation on walkers see the Walkers documentation
Now Lets create required walkers for LittleX.
Walkers are graph-traversing agents that perform tasks. Here are the walkers we need to create:
-
User Initialization Walker#
-
Implement User Initialization Walker#
- Creates or visits a new profile node for a user.
- Ensures profiles exist in the system for any user action.
-
Implement User Initialization Walker Abilities#
-
Visit Profile Ability#
impl visit_profile.visit_profile { visit [-->(`?Profile)] else { new_profile = here ++> Profile(); _.perm_grant(new_profile[0], level="CONNECT"); visit new_profile; } }
- If current walker enter via
root
,visit_profile
ability will be executed. visit [-->(``?profile)] else {}
Checks whether profile node exist from root, if yes, visit to that profile node. Otherwise execute to else part.here ++> profile()
It creates a profile node and connects with current node(root
).visit new_profile
Walker visit to that node (profile
).
- If current walker enter via
-
-
Test User Initialization Walker#
- To test the
visit_profile
function, we begin by spawning thevisit_profile
walker on the root node. Next, we filter the nodes connected to the root to identify any profile nodes. Finally, we verify whether the connected node is indeed a profile node. - spawn visit_profile walker on root node:
root spawn visit_walker();
- filter profile node:
profile = [root --> (`?Profile)][0];
- check is this node Profile or not :
check isinstance(profile,Profile);
- To test the
-
-
Load User Profile Walker#
-
Implement Load User Profile Walker#
- Loads all profiles from the database.
- Useful for managing or listing all users in the system.
-
Implement Load User Profile Walker Abilities#
-
Load Profiles Ability#
impl load_user_profiles.load_profiles { self.profiles: list = []; for user in NodeAnchor.Collection.find({"name": "Profile"}) { user_node = user.architype; self.profiles.append( {"name": user_node.username, "id": jid(user_node)} ); } report self.profiles; }
static has auth: bool = False
Set disable authentication for that walker.NodeAnchor.Collection.find({"name": "profile"})
Get list of profiles.user.architype
Get architype of user node.jid(user_node)
Get the unique id of an object.
-
-
-
Update Profile Walker#
-
Implement Update Profile Walker#
- Updates a user's profile, specifically the username.
- First
visit_profile
walker is called and it visits toProfile
node. here.username = self.new_username
Update username.- How
update_profile
walker spawned onProfile
node, update the name will be discussed later.
-
Test Update Profile Walker#
- To test this functionality, the
update_profile
walker should be spawned from theroot
node. After execution, the connectedProfile
node can be retrieved and verified to ensure that the username has been correctly updated.
test update_profile { root spawn update_profile( new_username = "test_user" ); profile = [root --> (`?Profile)][0]; check profile.username == "test_user"; }
- spawn update_profile walker on root:
root spawn update_profile();
- filter profile node :
profile = [root --> (`?Profile)][0];
- check updated username :
check profile.username == "test_user";
- To test this functionality, the
-
-
Get Profile Walker#
-
Implement Get Profile Walker#
- Retrieves profile details and logs them.
- First
visit_profile
walker is called and it visits toProfile
node. - How
get_profile
walker spawned onProfile
node, get the profile detailes will be discussed later.
-
-
Follow Request Walker#
-
Implement Follow Request Walker#
- Creates a follow edge.
- Walker
follow_request
, when spawned on the followee profile, will create a Follow edge from the follower to the followee. - How it is executed will be discussed later.
-
Test Follow Request Walker#
- To test
follow_request
, we have to create new profile and it named "Sam," is created to serve as the followee. After executing the walker, the test proceeds by navigating from the followee to confirm the presence of a Follow edge, which indicates the successful creation of the follow request. Finally, the test verifies that the username of the connected profile matches the expected followee. - create followee profile :
followee = Profile("Sam");
. - spawn follow_request walker on profile_node :
followee spawn follow_request();
. - filter followee profile :
followee_profile = [root --> (`?Profile)->:Follow:->(`?Profile)][0];
. - check followee profile username :
check followee_profile.username == "Sam";
.
- To test
-
-
Unfollow Request Walker#
-
Implement Unfollow Request Walker#
- Removes the follow edge.
- Walker
unfollow_request
spawned on followee profile will remove theFollow
edge from follower to followee. - How it is executed will be discussed later.
-
Test Unfollow Request Walker#
-
To test the
unfollow_request
walker, a new profile named "Sam" is first created to act as the followee. A follow relationship is initially established between the root profile and "Sam" using thefollow_request
walker. Then, theunfollow_request
walker is executed to initiate the unfollow action. -
After executing the walker, the test proceeds by navigating from the root profile to verify the removal of the
Follow
edge. The absence of this edge confirms that the unfollow request was successfully processed. Finally, the test ensures that no connection exists between the root profile and the profile previously followed.
test unfollow_request { followee = [root --> (`?Profile)->:Follow:->(`?Profile)][0]; followee spawn unfollow_request(); check len([root --> (`?Profile)->:Follow:->(`?Profile)]) == 0; }
- filter profile node :
followee = [root --> (`?Profile)->:Follow:->(`?Profile)][0];
- spawn unfollow_request walker on profile_node :
followee spawn unfollow_request();
- check length of the profiles that connect within Follow edge :
check len([root --> (`?Profile)->:Follow:->(`?Profile)]) == 0;
-
-
-
Create Tweet Walker#
-
Implement Create Tweet Walker#
- Creates a new tweet for a profile and adds it to the graph using a
Post
edge.
- Creates a new tweet for a profile and adds it to the graph using a
-
Implement Create Tweet Walker Abilities#
-
Create Tweet Ability#
impl create_tweet.tweet { embedding = sentence_transformer.encode(self.content).tolist(); tweet_node = here +>:Post:+> Tweet(content=self.content, embedding=embedding); _.perm_grant(tweet_node[0], level="CONNECT"); report tweet_node; }
embedding = sentence_transformer.encode(self.content).tolist()
Embedding the content.tweet_node = here +>:post:+> tweet(content=self.content, embedding=embedding)+
Create a new tweet with content, its embedding.report tweet_node
reports the newly created tweet node.
-
-
Test Create Tweet Walker#
- To perform
create_tweet
test, thecreate tweet
walker is spawned on the root node. The test then checks whether there are anytweet
nodes connected to theprofile
node. Finally, it validates that the tweet has been correctly created and linked as expected.
test create_tweet { root spawn create_tweet( content = "test_tweet" ); test1 = [root --> (`?Profile) --> (`?Tweet)][0]; check test1.content == "test_tweet"; }
- spawn create_tweet walker on root:
root spawn create_tweet();
- filter tweet node :
test1 = [root --> (`?Profile) --> (`?Tweet)][0];
- check tweet is correctly created :
check test1.content == "test_tweet";
- To perform
-
-
Update Tweet Walker#
-
Implement Update Tweet Walker#
- Updates the content of an existing tweet by its ID.
- Walker
update_tweet
spawned on tweet node, that will update the content of the tweet. - How it is executed will be discussed later.
-
Test Update Tweet Walker#
- To test the
update_tweet
,first we have to filter is there anytweet
nodes connected withprofile
node. Thenupdate_tweet
walker spawn on thetweet_node
. Finally, the test checks whether the tweet's content has been correctly updated. - filter is there any tweets :
tweet1 = [root --> (`?Profile) --> (`?Tweet)][0];
- spawn update_tweet walker on tweet_node :
tweet1 spawn update_tweet();
- check tweet is updated :
check tweet1.content == "new_tweet";
- To test the
-
-
Remove Tweet Walker#
-
Implement Remove Tweet Walker#
- Deletes a tweet by removing its connection to the profile.
- Walker
remove_tweet
, when spawned on a tweet node, will remove the tweet. - How it is executed will be discussed later.
-
Test Remove Tweet Walker#
- To test the
remove_tweet
walker, we have to check is there any tweets connected withprofile
node.Then we can spawnremove_tweet
walker on thetweet_node
. Finally, the test verifies that the tweet node has been successfully removed and is no longer connected to the profile. - checks is there any tweets :
tweet2 = [root --> (`?Profile)--> (`?Tweet)][0];
- spawn remove_tweet walker on tweet_node :
tweet2 spawn remove_tweet();
- check tweet is removed :
check len([root --> (`?Profile) --> (`?Tweet)]) == 0;
- To test the
-
-
Like Tweet Walker#
-
Implement Like Tweet Walker#
- Adds a like edge between a tweet and the profile liking it.
- Walker
like_tweet
spawned on tweet node, that will like the tweet. - How it is executed will be discussed later.
-
Test Like Tweet Walker#
- To test
Like_tweet
,we have to start by creating a tweet from theroot
node and then navigates to the correspondingtweet
node. The process continues by spawning thelike_tweet
walker from thetweet1
node. Finally, it confirms that the username"test_user"
is correctly associated with theLike
relationship on the tweet. - spawn like_walker walker on tweet_node :
root spawn create_tweet(0);
- filter is there any tweets :
tweet1 = [root --> (`?Profile) --> (`?Tweet)][0];
- spawn walker :
tweet1 spawn like_tweet();
- filter is like to tweet :
test1 = [tweet1 ->:Like:-> ][0];
- check liked profile username :
check test1.username == "test_user";
- To test
-
-
Remove Like Walker#
-
Implement Remove Like Walker#
- Removes the like edge
- Walker
remove_like
spawned on tweet node, that will remove the like. - How it is executed will be discussed later.
-
Test Remove Like Walker#
- To test
remove_like
, we have to retrieves an existing tweet; if the tweet exists, it proceeds to visit the tweet node. Then, it spawns theremove_like
walker from thetweet
node. The function subsequently checks whether theLike
relationship has been successfully removed by confirming that the length of the associated likes is zero. - check is there any liked tweets :
tweet1 = [root --> (`?Profile) --> (`?Tweet)][0];
- spawn remove_like walker on tweet_node :
tweet1 spawn remove_like();
- check like is removed :
check len([tweet1 ->:Like:-> ]) == 0;
- To test
-
-
Comment Tweet Walker#
-
Implement Comment Tweet Walker#
- Adds a comment to a tweet by creating a comment node and connecting it to the tweet.
- Walker
comment_tweet
spawned on tweet node, that will add a comment to tweet and create a edge with author of the comment. - How it is executed will be discussed later.
-
Test Comment Tweet Walker#
- To test
comment_tweet
,we have to begin with checking whether there is any tweet with content similar to'test_like'
. If such a tweet exists, it proceeds to visit it. To test thecomment_tweet
functionality, the function spawns acomment_tweet
node on thetweet
node and filters thecomment
node connected to the tweet. Finally, it verifies whether the content of the comment matches the expected value, confirming that the comment was successfully added to the tweet. - filter tweet's content :
tweet = [root --> (`?Profile) --> (`?Tweet)](?content == "test_like")[0];
- spawn comment_tweet walker on tweet_node :
tweet spawn comment_tweet();
- filter commnet :
comment = [tweet --> (`?Comment)][0];
- check comment correctly added or not :
check comment.content == "test_comment";
- To test
-
-
Load Feed Walker#
-
Implement Load Feed Walker#
- Fetches all tweets for a profile, including their comments and likes.
-
Implement Load Feed Walker Abilities#
-
Load Ability#
impl load_feed.load { visit [-->(`?Tweet)]; for user_node in [->:Follow:->(`?Profile)] { visit [user_node-->(`?Tweet)]; } report self.results; }
visit [-->(
?Tweet)]` Load feed walker will visit to all the Tweet nodes connected to root and execute the Tweet node abilities that can be triggered by the entry or exit of load feed walker.[->:Follow:->(
?Profile)]get all the follwee profile nodes from user and
visit [user_node-->(?Tweet)]
visit followee's tweets.load_feed
walker will execute the abilities that can be triggered with its entry or exit.- All the tweets from followee, user will be saved into results and it will be reported.
-
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
|
Test functionality
Using tools like Swagger or Postman, you can test these APIs to confirm their functionality.
-
Start the Server
jac serve filename.jac
run using command line. -
Access Swagger Docs Open your browser and navigate to http://localhost:8000/docs
-
Test an API Endpoint
- Click on an endpoint
- Click "Try it out" to enable input fields.
- Enter required parameters (if any).
- Click "Execute" to send the request.
- View the response (status code, headers, and JSON response body).
Lesson 4: Let's add some AI magic to our application using the power of MTLLM:#
In this lesson, we'll explore how to leverage AI to enhance your application. MTLLM supports easy integration of multiple LLM models, and for this tutorial, we are using Llama. If you need more details on integrating different models, please check the MTLLM documentation. (You can also explore OpenAI’s LittleX for additional insights.) Using Llama, you can summarize tweets to quickly understand trends, major events, and notable interactions in just one line.
Why This Feature Matters
Think of your application as a personalized newsfeed or trend analyzer.
- Save Time: Instead of scrolling through dozens of tweets, users get a quick summary of what's happening.
- Gain Insights: By distilling key information, the application helps users make sense of large volumes of data.
- Engage Users: AI-powered summaries make the experience dynamic and intelligent, setting your platform apart from others.
- Import Lamma with MTLLM
- Summarize Tweets Using Lamma:
- Summarize the latest trends, events, and interactions in tweets
- Test with Swagger
- Run the above mtllm example with
jac serve mtllm_example.jac
. - Register with email and password.
- Login with registered email and password.
- Copy the authentication key and paste it in authentication box.
- Run the get_summary api endpoint.
Lesson 5: Exploring Graph Security#
Up until this point, you’ve successfully created a single-user social media application where a user can post tweets, like them, and interact with comments.
Now, imagine scaling this application to handle multiple users. Questions arise, such as:
- How do you ensure users cannot modify or view others' data without permission?
- How do you securely enable collaboration, such as liking or commenting on someone else's tweet?
This is where graph security in Jaclang simplifies managing access and permissions between users' graphs.
Jaclang offers explicit access control, ensuring data privacy and secure interactions between user graphs. Permissions define what other users can do with specific parts of a graph.
Access Levels
NO_ACCESS
: No access to the current archetype.READ
: Read-only access to the current archetype.CONNECT
: Allows other users' nodes to connect to the current node.WRITE
: Full access, including modification of the current archetype.
Granting and Managing Access
By default, users cannot access other users' nodes. To grant access, permission mapping must be added explicitly.
- Grant Access Using Walkers
- Remove Access
- Grant Read Access to All
- perm_revoke Access
Scenarios
-
Posting a Tweet (Granting Read Access)
- When a user creates a tweet, it is private by default.
- To make it viewable by others, the system explicitly grants READ access to the tweet.
- Create Tweet Walker
Jac.perm_grant(here, level="READ")
perm_grant that tweet node to everyone with read access.
-
Commenting on a Tweet
- Similar to liking, commenting requires CONNECT access.
- A new comment node is created and linked to the tweet while granting READ access for others to view it.
- Comment Tweet Ability
Jac.perm_grant(tweet_node, level="CONNECT")
perm_grant the tweet node to connect level.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
|
Lesson 6: Abilities in Jaclang#
Nodes in Jaclang can have abilities defined to perform specific tasks. These abilities are structured as entry and exit points.
Imagine a smart home system where each room is represented as a node. Walkers traverse these nodes, performing tasks like turning lights on or off, adjusting temperature, or sending alerts when entering or exiting a room.
Entry When someone enters a room:
- Lights Turn On: The system detects entry and automatically switches on the lights to ensure the person feels welcomed.
- Room Occupied: The system marks the room as occupied in its database or tracking system.
You enter the Living Room, and the system turns on the lights and logs your presence.
Exit When someone exits a room:
- Lights Turn Off: The system detects the exit and switches off the lights to save energy.
- Room Vacant: It marks the room as unoccupied in its tracking system.
You leave the Living Room, and the system turns off the lights and updates its records to show the room is vacant.
Scenarios in node
-
Update profile
- A user updates their profile.
- Update Tweet Walker Ability
-
Update Profile Node Ability
- It replaces the abilities in walker.
-
As
update_profile
walker is spawned onProfile
, it visits toProfile
. - With the entry of the
update_profile
walker, Profile will be updated.
-
Get profile
- Get profile details.
- Update Tweet Walker Ability
-
Create get ability
- It replaces the abilities in walker.
-
As
get_profile
walker is spawned onProfile
, It visits toProfile
. - With the entry of the
get_profile
walker, Profile will be reported.
-
Follow profile
- Following a user.
- Update Tweet Walker Ability
-
Follow Request Node Ability
- It replaces the abilities in walker.
-
As
follow_request
walker is spawned onProfile
, it visits toProfile
. - With the entry of the
follow_request
walker,Follow
edge is created and connected. [root-->(
?Profile)]` gets the current user profile.current_profile[0] +>:Follow():+> self
connects the followee with Follow edge.
-
Unfollow profile
- Unfollowing a user.
- Unfollow Profile Walker Ability
-
Unfollow Profile Node Ability
- It replaces the abilities in walker.
-
As
un_follow_request
walker is spawned onProfile
, it visits toProfile
. - With the entry of the
un_follow_request
walker,Follow
edge is disconnected. [root-->(
?Profile)]` gets the current user profile.current_profile[0] del->:Follow:-> self
disconnects the followee with Follow edge.
-
Update Tweet
- User updated their tweet.
-
Update Tweet Walker Ability
```jac walker update_tweet(visit_profile) { has tweet_id: str; has updated_content: str; can visit_tweet with profile entry { tweet_node = &self.tweet_id; visit tweet_node; } can update_tweet with tweet entry { here.content = self.updated_content; report here; } } ```
-
Update Tweet Node Ability
- It replaces the abilities in walker.
-
As
update_tweet
walker is spawned onTweet
, it visits toTweet
. - With the exit of the
update_tweet
walker, the tweet is updated. self.content = here.updated_content
updated the current tweet.
-
Delete Tweet
- Deletes the tweet.
- Delete Tweet Walker Ability
-
Delete Tweet Node Ability
- It replaces the abilities in walker.
-
As
remove_tweet
walker is spawned onTweet
, It visits toTweet
. - With the exit of the
remove_tweet
walker, tweet is deleted. del self
deletes the current tweet.
-
Like Tweet
- User likes the tweet.
- Like Tweet Walker Ability
-
Like Tweet Node Ability
- It replaces the abilities in walker.
-
As
like_tweet
walker is spawned onTweet
, it visits toTweet
. - With the entry of the
like_tweet
walker, tweet is liked. [root-->(
?Profile)]` gets the current user profile.self +>:Like():+> current_profile[0]
connects the user withLike
edge.
-
Remove Like Ability
- User removes the like.
- Remove Like Walker Ability
-
Remove Like Node Ability
- It replaces the abilities in walker.
-
As
remove_like
walker is spawned onTweet
, it visits toTweet
. - With the entry of the
remove_like
walker, like is removed. [root-->(
?Profile)]` gets the current user profile.self del->:Like:-> current_profile[0]
disconnects the user withLike
edge.
-
Comment Ability
- When a user creates a tweet, it is private by default.
- Comment Walker Ability
walker comment_tweet(visit_profile) { has tweet_id: str; has content: str; can add_comment with profile entry { comment_node = here ++> comment(content=self.content); tweet_node = &self.tweet_id; Jac.perm_grant(tweet_node, level="CONNECT"); tweet_node ++> comment_node[0]; report comment_node[0]; } }
-
Comment Ability
- It replaces the abilities in walker.
-
As
comment_tweet
walker is spawned onTweet
, it visits toTweet
. - With the entry of the
comment_tweet
walker, comment is added to the tweet. [root-->(
?Profile)]` gets the current user profile.comment_node = current_profile[0] ++> Comment(content=here.content)
connects the user withComment
node.
-
Load Tweets
- Load tweet information.
- Load Tweet Walker Ability
walker load_tweets(visit_profile) { has if_report: bool = False; has tweets: list = []; can go_to_tweet with profile entry { visit [-->](`?tweet); } can load_tweets with tweet entry { Jac.perm_grant(here, level="READ"); comments = here spawn load_comments(); likes = here spawn load_likes(); tweet_content = here spawn load_tweet(); tweet_info = { "comments": comments.comments, "likes": likes.likes, "tweet": tweet_content.tweet_info }; self.tweets.append(tweet_info); if self.if_report { report self.tweets; } } }
-
Load Tweets Node Ability
- It replaces the abilities in walker.
can get_info()-> TweetInfo { return TweetInfo( id=jid(self), content=self.content, embedding=self.embedding, likes=[i.username for i in [self->:Like:->]], comments=[{"id": jid(i), "content": i.content} for i in [self-->(`?Comment)]] ); }
- This defines a abilitiy named
get_info
within theTweet
node and it returns an instance of theTweetInfo
node. id=jid(self)
retrieves the unique jac identifier (jid) of the currentTweet
node.- This assigns the
content
property of the currentTweet
object to thecontent
field of theTweetInfo
object that has variables id, content, embedding, likes, comments.
- This defines a abilitiy named
- It replaces the abilities in walker.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
|