Skip to content

Commit 1844756

Browse files
committed
framelib example
1 parent fa5f4f0 commit 1844756

File tree

6 files changed

+77
-17
lines changed

6 files changed

+77
-17
lines changed

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,40 @@
1-
# python-frames
1+
# framelib
22

33
lightweight library for building farcaster frames using python and flask
44

5+
- easily render frames that conform to the farcaster specification
6+
- configurable frame design
7+
- parse frame action messages
8+
- verify the frame action signatures using neynar
9+
- query user profile info from warpcast
10+
511

612
## quickstart
713

14+
install `framelib` from pip
815
```
916
pip install framelib
1017
```
18+
19+
simple example
20+
```python
21+
from flask import Flask, url_for
22+
from framelib import render_frame
23+
24+
app = Flask(__name__)
25+
26+
@app.route('/', methods=['GET', 'POST'])
27+
def home():
28+
return render_frame(
29+
image='https://opengraph.githubassets.com/0x/devinaconley/python-frames',
30+
button1='next',
31+
post_url=url_for('second_page', _external=True),
32+
)
33+
```
34+
35+
## examples
36+
37+
see a complete example using python + flask + vercel [here](https://github.com/devinaconley/python-frames/tree/main/examples/simple)
38+
39+
and for a more advanced example involving multiplayer games, supabase integration, dynamic image rendering, and more,
40+
see [rock paper scissors](https://github.com/devinaconley/rock-paper-scissors)

examples/simple/README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,12 @@ you can run the frame debugger provided by [frames.js](https://github.com/frames
3333

3434
## deployment
3535

36-
_TODO_
36+
make sure your project has been pushed to a github repo
37+
38+
import your project to [vercel](https://vercel.com/) with the flask framework
39+
40+
register with [neynar](https://neynar.com/) to get an api key
41+
42+
define the `NEYNAR_KEY` environment variable in your vercel project settings
43+
44+
deploy!

examples/simple/api/index.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
"""
22
main entry point for example framelib flask app
33
"""
4-
import json
5-
import time
6-
from flask import Flask, render_template, url_for, request, make_response, jsonify
7-
from framelib.models import FrameMessage
4+
import os
5+
from flask import Flask, url_for, jsonify
6+
from framelib import render_frame, message, validate_message_or_mock_vercel
87

98
app = Flask(__name__)
109

1110

12-
class BadRequest(Exception):
13-
pass
14-
15-
16-
@app.errorhandler(BadRequest)
11+
@app.errorhandler(ValueError)
1712
def handle_invalid_usage(e):
1813
response = jsonify({'status_code': 403, 'message': str(e)})
1914
response.status_code = 403
@@ -22,9 +17,34 @@ def handle_invalid_usage(e):
2217

2318
@app.route('/', methods=['GET', 'POST'])
2419
def home():
25-
return jsonify({'status_code': 200, 'message': 'hello world'})
20+
# initial frame
21+
return render_frame(
22+
image='https://opengraph.githubassets.com/0x/devinaconley/python-frames',
23+
button1='hello \U0001F44B',
24+
post_url=url_for('second_page', _external=True),
25+
button2='github',
26+
button2_action='link',
27+
button2_target='https://github.com/devinaconley/python-frames'
28+
)
2629

2730

2831
@app.route('/page2', methods=['POST'])
2932
def second_page():
30-
return jsonify({'status_code': 200, 'message': 'hello world, page 2'})
33+
# parse frame message
34+
msg = message()
35+
print(f'received frame message, fid: {msg.untrustedData.fid}, button: {msg.untrustedData.buttonIndex}')
36+
37+
# validate frame message with neynar
38+
api_key = os.getenv('NEYNAR_KEY')
39+
msg_val = validate_message_or_mock_vercel(msg, api_key)
40+
print(f'validated frame message, fid: {msg_val.interactor.fid}, button: {msg_val.tapped_button}')
41+
42+
return render_frame(
43+
image='https://opengraph.githubassets.com/0x/devinaconley/python-frames',
44+
button1='back \U0001F519',
45+
post_url=url_for('home', _external=True),
46+
input_text=f'hello {msg_val.interactor.username}!',
47+
button2='github',
48+
button2_action='link',
49+
button2_target='https://github.com/devinaconley/python-frames'
50+
)

examples/simple/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# requirements.txt
2-
framelib
2+
framelib~=0.0.0b5
33
Flask~=3.0.1
44
pydantic

framelib/neynar.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def validate_message(msg: FrameMessage, api_key: str) -> ValidatedMessage:
4949
def validate_message_or_mock(msg: FrameMessage, api_key: str, mock: bool = False) -> ValidatedMessage:
5050
if mock:
5151
# mock
52+
# TODO option to populate with warpcast profile
5253
return ValidatedMessage(
5354
object='validated_frame_action',
5455
interactor=Interactor(
@@ -72,5 +73,6 @@ def validate_message_or_mock(msg: FrameMessage, api_key: str, mock: bool = False
7273
return validate_message(msg, api_key)
7374

7475

75-
def validate_message_or_mock_vercel(msg: FrameMessage, api_key: str) -> (bool, ValidatedMessage):
76-
return validate_message_or_mock(msg, api_key, os.getenv('VERCEL_ENV') is None)
76+
def validate_message_or_mock_vercel(msg: FrameMessage, api_key: str) -> ValidatedMessage:
77+
vercel_env = os.getenv('VERCEL_ENV')
78+
return validate_message_or_mock(msg, api_key, vercel_env is None or vercel_env == 'development')

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name='framelib',
8-
version='0.0.0.b4',
8+
version='0.0.0.b5',
99
author='Devin A. Conley',
1010
author_email='devinaconley@gmail.com',
1111
description='lightweight library for building farcaster frames using python and flask',

0 commit comments

Comments
 (0)