@@ -6,19 +6,17 @@ import from byllm { Model, Image }
66
77glob llm = Model(model_name="gpt-4o");
88
9+ # One tiny object replaces a giant schem
910obj MemoryDetails {
1011 has who: list[str];
1112 has what: str;
1213 has where: str;
1314}
14- sem MemoryDetails = "Extract people, event, place, and time from a photo";
15- sem MemoryDetails.who = "Names of people in the photo";
16- sem MemoryDetails.what = "What is happening in the scene";
17- sem MemoryDetails.where = "Location or setting of the photo";
15+ sem MemoryDetails = "Extract people, event, place from the photo";
1816
1917def extract_memory_details(
2018 image: Image, city: str
21- ) -> MemoryDetails by llm();
19+ ) -> MemoryDetails by llm(); # Magic happens
2220
2321with entry {
2422 img = Image("image.png");
@@ -29,6 +27,8 @@ with entry {
2927 {
3028 filename : "oop_example.jac" ,
3129 code : `
30+ # --- Build a living, interconnected world with nodes and walkers ---
31+
3232node Landmark {
3333 has name: str;
3434 can react with Tourist entry {
@@ -40,7 +40,7 @@ node Landmark {
4040node Cafe {
4141 can react with Tourist entry {
4242 print("☕ Tourist gets coffee and continues exploring.");
43- visit [-->];
43+ visit [-->]; # flows to connected nodes
4444 }
4545}
4646
@@ -81,19 +81,42 @@ with entry {
8181 {
8282 filename : "cloud_scaling.jac" ,
8383 code : `
84- # walker automatically becomes an endpoint
85- walker memories {
86- has current_user: str = "";
84+ # nodes + walkers + jac-cloud --> auto-endpoint magic
85+ # Auth & database handled behind the scenes
8786
88- can get_memories with \`root entry {
87+ node Memory {
88+ has memories: list[str] = [];
89+
90+ can add_memory with add_memory entry {
91+ # Simple append, no DB worries
92+ self.memories.append(visitor.memory);
8993 report {
90- "message":
91- f"Hello {self.current_user}, here are your memories!"
94+ "message": f"Memory added: {visitor.memory}"
9295 };
9396 }
97+ can list_memories with get_memories entry {
98+ report { "memories": self.memories };
99+ }
100+ }
101+
102+ # Endpoint ready!, thanks to the walker abstraction
103+ walker add_memory {
104+ has memory: str;
105+
106+ can add_memory with \`root entry {
107+ visit [--> (\`?Memory)] else {
108+ visit root ++> Memory();
109+ }
110+ }
111+ }
112+
113+ walker get_memories {
114+ can list_memories with \`root entry {
115+ visit [--> (\`?Memory)] else {
116+ report { "memories": [] };
117+ }
118+ }
94119}
95- # Auth & database handled by Jac-cloud behind the scenes
96- # No boilerplate here
97120` ,
98121 } ,
99122] ;
@@ -103,48 +126,89 @@ export const pythonTabsData = [
103126 filename : "ai_sentiment_analysis.py" ,
104127 code : `
105128import json, base64
129+ from datetime import datetime
106130from openai import OpenAI
107131
108132client = OpenAI()
109133
134+ # --- Lots of boilerplate just to define a schema ---
110135tools = [{
111136 "type": "function",
112137 "function": {
113138 "name": "process_memory",
139+ "description":
140+ "Extract structured memory details from the photo",
114141 "parameters": {
115142 "type": "object",
116143 "properties": {
117- "who": {"type": "array", "items": {"type": "string"}},
118- "what": {"type": "string"},
119- "where": {"type": "string"}
144+ "who": {
145+ "type": "array",
146+ "items": {"type": "string"},
147+ "description": "Names of people in the photo"
148+ },
149+ "what": {
150+ "type": "string",
151+ "description": "What is happening in the scene"
152+ },
153+ "where": {
154+ "type": "string",
155+ "description":
156+ "Location or setting of the photo"
157+ }
120158 },
121159 "required": ["who", "what", "where"]
122160 }
123161 }
124162}]
125163
164+ # --- The prompt has to sit here like a Novel ---
126165SYS_PROMPT = """
127- # Goal
128- Extract structured memory details from the photo.
129-
130- # Fields
131- - who: list of people or animals involved
132- - what: short description of the activity or event
133- - where: location or place mentioned
134-
135- # Rules
136- - Only use details from the photo and user input
137- - Do not hallucinate or invent missing information
138- - Always return using the \`process_memory\` tool
139-
140- # Guidance
141- - If some fields are missing, leave them empty
142- - Keep responses factual and concise
166+ # Role and Objective
167+ Your goal is to extract structured memory details from
168+ referenced images and user context. Engage in a way that feels
169+ natural, as if you were helping someone document their
170+ experiences, but always return structured output.
171+
172+ # Instructions
173+ - Extract details only based on the image and user input.
174+ - Avoid hallucinations or assumptions if information is missing.
175+ - Always call the \`process_memory\` tool to return results.
176+ - Keep results short, factual, and consistent.
177+
178+ # Sub-categories for more detailed instructions
179+ ## First Turn
180+ - React to the image or context briefly.
181+ - Encourage clarification if information is incomplete.
182+
183+ ## Field Writing (for process_memory)
184+ - **who**: list of people, animals, or notable entities.
185+ - **what**: concise description of the activity or event
186+ (3-5 words).
187+ - **where**: specific place, city, or landmark provided
188+ or visible.
189+
190+ ### Reasoning Steps
191+ - If the user corrects existing information, update the fields.
192+ - If new information is provided, add it without discarding
193+ existing relevant details.
194+ - If a field is not mentioned or visible, leave it empty.
195+
196+ ## Response Writing
197+ - Keep responses factual and grounded in what's visible or given.
198+ - Never ask the user irrelevant questions.
199+ - Use the photo context to refine details when applicable.
200+
201+ # Output Format
202+ Always return JSON via the \`process_memory\` tool with:
203+ - \`who\`: list of strings
204+ - \`what\`: string (short activity/event description)
205+ - \`where\`: string (location or place)
143206"""
144207
145208with open("image.png", "rb") as f:
146209 image_b64 = base64.b64encode(f.read()).decode("utf-8")
147210
211+ # --- Verbose message construction ---
148212messages = [
149213 {"role": "system", "content": SYS_PROMPT},
150214 {
@@ -171,6 +235,7 @@ response = client.chat.completions.create(
171235result = json.loads(
172236 response.choices[0].message.tool_calls[0].function.arguments
173237)
238+
174239print(result)
175240` ,
176241 } ,
@@ -235,12 +300,15 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")
235300client = pymongo.MongoClient("mongodb://localhost:27017/")
236301db = client["mydb"]
237302users_collection = db["users"]
303+ memories_collection = db["memories"]
238304
239305# --- Models ---
240306class User(BaseModel):
241307 username: str
242308 password: str
243309
310+ class MemoryItem(BaseModel):
311+ memory: str
244312
245313# --- Auth Helpers ---
246314def create_token(username: str):
@@ -254,13 +322,18 @@ def create_token(username: str):
254322def verify_token(token: str = Depends(oauth2_scheme)):
255323 """Decode and validate JWT token."""
256324 try:
257- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
325+ payload = jwt.decode(
326+ token, SECRET_KEY, algorithms=[ALGORITHM]
327+ )
258328 return payload["sub"]
259329 except jwt.ExpiredSignatureError:
260- raise HTTPException(status_code=401, detail="Token expired")
330+ raise HTTPException(
331+ status_code=401, detail="Token expired"
332+ )
261333 except jwt.InvalidTokenError:
262- raise HTTPException(status_code=401, detail="Invalid token")
263-
334+ raise HTTPException(
335+ status_code=401, detail="Invalid token"
336+ )
264337
265338# --- Routes ---
266339@app.post("/signup")
@@ -269,15 +342,16 @@ def signup(user: User):
269342 hashed_pw = hashlib.sha256(user.password.encode()).hexdigest()
270343
271344 if users_collection.find_one({"username": user.username}):
272- raise HTTPException(status_code=400, detail="User already exists")
345+ raise HTTPException(
346+ status_code=400, detail="User already exists"
347+ )
273348
274349 users_collection.insert_one({
275350 "username": user.username,
276351 "password": hashed_pw
277352 })
278353 return {"message": "User created successfully"}
279354
280-
281355@app.post("/login")
282356def login(user: User):
283357 """Authenticate user and return JWT token."""
@@ -296,15 +370,30 @@ def login(user: User):
296370 return {"access_token": access_token, "token_type": "bearer"}
297371
298372
299-
300- @app.get("/memories/")
301- def get_memories(current_user: str = Depends(verify_token)):
302- """Protected route: requires valid JWT token."""
303- return {
304- "message": f"Hello {current_user}, here are your memories!"
305- }
306- ` ,
307- } ,
373+ # --- the long road to a simple task ---
374+ @app.post("/add_memory")
375+ def add_memory(
376+ item: MemoryItem,
377+ current_user: str = Depends(verify_token)
378+ ):
379+ """Add a memory for the current user."""
380+ memories_collection.insert_one({
381+ "username": current_user,
382+ "memory": item.memory,
383+ "timestamp": datetime.utcnow()
384+ })
385+ return {"message": f"Memory added: {item.memory}"}
386+
387+
388+ @app.get("/get_memories")
389+ def get_user_memories(current_user: str = Depends(verify_token)):
390+ """Retrieve all memories for the current user."""
391+ user_memories = list(memories_collection.find(
392+ {"username": current_user},
393+ {"_id": 0, "memory": 1, "timestamp": 1}
394+ ))
395+ return {"memories": user_memories}
396+ ` } ,
308397] ;
309398
310399export const tabsData = [
0 commit comments