From d1389e109257ffc01a22ecefe562e158f68c02b9 Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 12:17:41 -0700 Subject: [PATCH 1/9] remove code --- .well-known/ai-plugin.json | 8 ++-- .well-known/logo.png | Bin 17842 -> 8085 bytes .well-known/openapi.yaml | 82 ------------------------------------- main.py | 47 --------------------- test_main.py | 46 --------------------- 5 files changed, 4 insertions(+), 179 deletions(-) delete mode 100644 .well-known/openapi.yaml delete mode 100644 main.py delete mode 100644 test_main.py diff --git a/.well-known/ai-plugin.json b/.well-known/ai-plugin.json index 2eeab96..e035612 100644 --- a/.well-known/ai-plugin.json +++ b/.well-known/ai-plugin.json @@ -1,9 +1,9 @@ { "schema_version": "v1", - "name_for_human": "TODO app", - "name_for_model": "TODO_APP", - "description_for_human": "Todo app for managing your tasks", - "description_for_model": "Todo app for managing your tasks", + "name_for_human": "My app", + "name_for_model": "my_app", + "description_for_human": "This app is", + "description_for_model": "This app is", "auth": { "type": "user_http", "authorization_type": "bearer" diff --git a/.well-known/logo.png b/.well-known/logo.png index 5bffb38822fcb471378d6a870e73cc1699160111..0f237a226583e08f89f14a15d86aa330a11151ae 100644 GIT binary patch literal 8085 zcmeHM_cI(0u-AKu8cvOb-09`??(`_vkSG!T^dwG#J`k%+d z^oKSD1=Sy@1=7gmp~XMX|I7b(;QwF;?g zFp=Y7pcjiS>)$xPI-Py_P@7uHrD$lYE7Mw-Nk3)acbfvO-qgjX5Q*^7<7?#yb8)w+ z;O`4$mxJa9D>2iPnhs@|Vi+av`&U!U3aQuY;@tl*UOYpQcj zbZ1XqOs_Y3dz0V%>GiOYai|Ag?cJbIwUR~Dd_?mjR2q4wvY;U_*0J{I-F9x?CpTca z|9uB7#gA#`V|%{Pp-Y@TPcLY^dEtL=g`+C<$jaS+_=;&G53F)>1^8}a4*-6b_sc(?&dEa!Rl zt3~!IGs`=bOp4O}N;hsW-kV0+SOo}|-RLUG@cAs86idVX0_tBL?QzX9lvcU4o&=z( zt}6epWoiNfWlgmtmmPaDREg*1^L}GmFl^|99?dX|@?Eg`n0RR$a*i1JGj7Jq3sw`2 zoV2eQ`pPv{vm307lr*ujE$j-gRh*`#EY=DLRJuw?R91L-uC0E7>pB4U?m61uzgHeJ z34hdFa~npPBPCEU=kWbk*7$nbLBo_RPX;2kZ7}{Yc*lQod+AEd9>6XMvb%69QY_Uf z%B8Hy*pv6S{7dHOR2SA(FVxj!Z)wp=Z?Erq>df9e8w(#eeOST5blCPd!f=}NWc2s1 z#Lx4e#=V3uK^viq-O2ofT%TFnqor)``4wO`>}XTjBW!$O_zF{?^=CJNI-odxXYQ$9 z?!?vA!SxyP8`kLf_PX>I9xlkE1w$pcBcD;4;$R}iRh$!)k69{eIkTO$MM~ta4CZ2z z-w)|@P3&r{wGO}E+v*H>`*Ue;6%qYi>BsFr$suqdKdaL_iF7>1^D79+b;kR18q9Ho z1~@95`L{~p2iq}KHizN)cjYN+C1H610!ooCy0bTVVYN%HEiRwoGY_T@)n=KEVF7)j zEnXf{GopSr1%@HtH<1Hz;P~&87G*LTtOt)tA7`>RT6mwlWqAT35YL0|N@X|be zeHjH1tK^sZgd{FKy~G0 z>AlJ*C-_+nN-Mj5z;A;N*W$0ehtMi|?Dk)eTloDS6G>D#C4nYKY{(Hj)~sc>Z4Y$T z3kdm`-nN=efF?f~nQ;H9K>Ef@-%KNtUP)&9CabWUX72Fo0HLy!aLDz+;6N;=~i?4uO)-bZt0K8EUNa=0@wx z+P+$k3@n8ugXoE+_wSjUir)U7y>YBy&m=+ z<)&lfKBPsT?!a%H=|3{HY_!QQ!ld+ej}EFozbyE$=TXuvr|8;y{#8{f7PoY;DU#SQ z>R~mzI5A8KXjd`V3Fo+#NJ<8!sq-60f65;j>mb%>p5vv6B}vjn4s?onN#~j9 z38)6=D8uNlkLP%pvq!@u=s*=rPrV)!kl`&KpF8j>u682pH2tgE+n^t?mQ{dJ(MXqm zO_i*>&&a^;)=1;(x%Z__ax+^mkELwe8KaBGts1nXpmFS;Xy&(s)e7wV=xxplEp4cL-rPRPm-$V+#vy6xgiOdQDyqIBX8#c027 zBs*H9!4h$K1D%m zm2b_!Q3CC}o1c200^dDi_*=aEG#_sCTmKX73xa;~&9E+fe(jkp@!8ojqjBU9nyw?8 zc1*h{n_^-g>e^#&*FNC$<6G_AB#gp9oKqpL>o-c*hUOSh6*P*ai(|S4bLVL1BFzh$ z5A8)q{{F>jtu;R?@)Jn$1(VTTupDvBkEiS!8I z|7$F@s6g9QFE5*tP)H7Afo#>F;)+k8kQ>M=#q7i@59Q_mux30)Qv42G280{eP>MNJ zH6%5W&Gm_EQ|S!43I&p$B4~ATHFqeLRYFoNIYtp7k`k4Z9gH9@e&Lsm56h;C_^K{M z`ffacyx5dLzQ$%tQf>CzN2CL22{#e9y6}Rm6HAdmWd%88PK^mq|0-?X6&b^0+z5mY ze;tKtTJR$BCva)_7geQ~PM5pfsbNIyN?}4Q{<2nxKpr0zFZft zrsra-j*wk3uQaGRUu2WP724NC4sTP~EDtBHD}YVU5CsCye}2t_>hB4aJSPW(M$pSo zM0seWXShqzkfT*rfMxtme9^X{M})7w-K->u!4y6t`NKSV!72{mm}B2G6jf{geIvhe z!YU{w?KGSyo^DB~_#l_2hj{ok9BqW*+b$oy*hdpTy1W2o$;B%2J3;VO(RUzd=lE`Z zK;aphNaX>{I!1l&Wlumr*G! zA1vGVJh0_sRZI^7lj}XQ-)l*8bV)ukivV^19X-f$*$1R*h=(a=JN875?jy2pW5(15TaiRaH zB`^s`!2$rcY|v`t3%TBprdejuT=aTV)Lz~m$1Z$4`0fUww0Mm+MqaDoN{e5mH%HLB z2h#Z%0jde_jNotGP{I`#lW*{tWq_CdlxgyK8a-VvN|JRfR*0FWRO6mf7z8#z-ePld zvl|`Uej<-DkDaS2WNLJk&aU|@o}!p;8&_+88&#Sj@)z_OgI8gT&Xsx(L^M3|MYX;M z$2~qdu;yy#@iAXQtplFsDYmg2*q!NQ3nWFhY!~jqT>bWdbQET`OsX-IeSNfTZfpt@C^=NSiAvl zzik{$`f=+b&ef^p^n#8)0B`E!Ch{hpYM`ln z&}+0VBbkbMaG3TTmo#_D-S?^;0!;ej1#nj{vB4U!P@;pvD`T@>7rc_V&ep;NRIjU< z1oKmnZa0j6R55;IphbsDW!{I{1j0WwXNDIEf3VA#Uno&*mAP97t>^cs2p^vrg&KGGSA24S&NuJTdDNdO zAGi|h!C}0%fN@}uHugx=NNlOZb$JIk;CH3oh6}qdr_j0)TCeBAc^Xfb;oBzu7t_ssh-1*PbYdCvy z9ElLx1I)@!HArQ^>vvB6Dzrv0`CG@@+dAGr8(^VqHTQf=i!*;xSHvpsfF8etqb;Mx+mDI%y1O^Rj4|uK zQIzGKgN!noN%Uh5_?~@ho8My}m6Y+mpPont`sN*|2Jou!Nix&%1de=cFb9n+2iDup zK7w-*LmRa=kVFXhB@+Q&1rA!&Kr74h=gfL>b1&~$YFsnNy1s4=Pqdb`V_yeo76&+* zT2#YQ+2VaV3h0)2PJgCqw6{^W{+PAQBg)Nm8;%@bmSy4D4rK^k>A;FA4SZ3ipt23iPV@%$R}xUGh2RkQUYc{Z?Y1`{!Ql>$M!!Ew43GMpBc9le5DZw3TN504n3%z($w6@x08K z7VnGj_W2y9#a+a1bC@>6-jT3T`f_}9WcjMt4ap1DqMz3z_9g9U+Li0W_qdP>SV8m- z>PNH>HlI?B(?=jRNt_gc>wI*S{E!437isl;T^ch0q3|;3vqfMsM)zn~HNX`2|0YTr z9A?MW#x8lgn7fIn@%U6MCR|}vQ5lUi6rDSFcn|=&=!*5g!+wP9e5O#88@{u0l-rpv zg{4e?!<|B}Zn60X*IY^UFdt4qDlJYjqwH6GPr3{E7fV-SjfftPRFgsfr|;vyEUeH& zMY13h3vQI>sO0tpze!Yed`&2}+! zkhgU|v|=MR@u3#dh6%k*A6>kHUk+Rzxc*=!ujtDc>%5nh?9^!q8vNGLzpqV`p76`R zg-Ve=g~;)9(ptFgff&?8BoC;WKK6qWW~idYi!BIAO1(GgXWX|oFWRD14R%UD-2f)o zQ{cNX#4^%Bv&mMl5ojFkd99suv#OMvzZA<+CVZ>)Iw2|U4QW1b^SIoi%mp*|7U~Rl zcT6e$WNrPKU7@g4oA1+8js=oC8?Wet}kF=qevlbY{?VnC-#WknUEa&`3;Ary0U zZw2OupnSF*6T5L&Kx91+S8MO1Yj7o0){Bf?%?=5@PwIC=T*q>rAwLg=}2yKhnk9jrdFs zn2EezAv;1e72_@(v<#Nf>0q>6t4)>gXK8f5?IF=Ss|jY}qwsLvt0?u7G?>a7GS!5z zwj1W9g5=MPwNe2Pr!6~sXm?&~M%EjX(J6UHF@_uD$;5+HVy(-3$33e`J?UY|t z7h*=7EYGh?dFoC1zW1(O=cs{F^9m8(N1Z|^o>N6!E+n0Ny~_LpXIu~4L~_b3PloM? zDkjnpz0K)q_TTqQO@Fb3-2dT# z9K~a$Eo{{FWGWYuG`P**P_ZBFa9Z&=pGM)jqsj8YGLD?+cmvEl>~le6o&U``Hs$Tl zl-DQ9ztM$^%hfdjnXZzi6mLM(BQX*?NIgsQ40wI%AWeoTwK&=9jC&p#FZ*%ue(>HFFf(UL8+>pLfP%Vs2aFlXk>Qq~0>%28N~`xr7ze z;vWZjcC-HDER)=(hV{SOGo=Wte4rN|FOo=;iLcg~dDHT;o?7--6xEjnSn-&}mz;-2 zX>z4RS0k&IMOmZHSg)P(s=`MjIg>|xHhzLsQ{j5i18ej5{z{=FAG_XLe^xV+EeTgG z`=AT~9)h%Fev8`^o8?)PnpBEQ)!N;89l5m%s9?$qk2;4?D<773|JET7X7X-Hs*`{2 z?vXkcqHfBK+P`0HoY9v>ZMeWt4{cH;VBYz(mtjFPBE(J0)SacSaXyDv?qq~_1 z+PErdYAT=4trr50kr-b+|As4ip`gtl;QgZ5VDE!|0Rg4dEe}7VS*d`A$-hEw(ua-J zP(HK^N@`4a=Nehs|4N3k*}vp&C4*Xx7q|A}w{~cY|Mk9}`>{t&PfGt#ZSF-~$i_qc z*`kGp5uU*I)i8}6c!vSgcHJ{Y-R|U4DZvsM zgZOT?JF8I79_f&Yh5szQ6TFY+J1JiPZRmeY?uDz*;Ey<3s-P0(xl6(sinYT2@@=xS z9N(WkF1&mcxbA$#H)l6{T^92Wv|=pMr+w2ONf<>>kqtN=n$1e)GZ2$81DSzuik?+s zW^@=M-UTF#4{Elo#bJ*h5Z<|=JS~*-^PR7U6>UB@M<_oGWCDQ0;R}xMDi4ZDjgsT< z59ai>lg1otPeD-LGgFD7!X9lI@hAHOTTW6oq{x%aiKo_f`R9fO?e9ttt{lDfnP2!W z$=o24@gdhJwo2z(IWM4EuW%f4!3t;nwO&J7CoGe4Do@N ze0?Ll3dwo@{iYp#v(Ab@iu1V*Nd0WW%y%7Ycgm%TI%dE*^Zlzb;Uhg0A6&3A; z3$@v&ySaopv0}FWB8WeaG8=5Zylt^Q`DAnG#Ewv+qf_R=MT~yt>(o&FW*9<9bP;$PZo3SFV)wKG!23>VdH*S2$tpd9+h8 vm{h2v9Dij;CQqNNYK7N)pA@v57rGMY^ijcdQjk#p`&BhFvNEhSco6eHk%;zp literal 17842 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 diff --git a/.well-known/openapi.yaml b/.well-known/openapi.yaml deleted file mode 100644 index d043e2c..0000000 --- a/.well-known/openapi.yaml +++ /dev/null @@ -1,82 +0,0 @@ -openapi: 3.0.2 -info: - title: OpenAI plugin for a simple todo app - description: Todo app for managing your tasks on ChatGPT - version: 1.0.0 - servers: - - url: https://your-app-url.com -paths: - /todos: - post: - summary: Create a new TODO item - description: Accepts a string and adds as new TODO item - operationId: create_todo - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/TodoItem" - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/TodoItem" - get: - summary: Get a list of all TODO items - operationId: list_todos - responses: - "200": - description: OK - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/TodoList" - /todos/{todo_id}: - get: - summary: Get a TODO item by ID - operationId: get_todo - parameters: - - name: todo_id - in: path - required: true - description: ID of the TODO item to retrieve - schema: - type: integer - format: int64 - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: "#/components/schemas/TodoItem" - "404": - description: Todo not found - delete: - summary: Delete a TODO item by ID - operationId: delete_todo - parameters: - - name: todo_id - in: path - required: true - description: ID of the TODO item to delete - schema: - type: integer - format: int64 - responses: - "204": - description: Todo deleted - "404": - description: Todo not found -components: - schemas: - TodoItem: - type: object - properties: - title: - type: string \ No newline at end of file diff --git a/main.py b/main.py deleted file mode 100644 index e5ca87f..0000000 --- a/main.py +++ /dev/null @@ -1,47 +0,0 @@ -from fastapi import FastAPI, HTTPException -from fastapi.staticfiles import StaticFiles -import os -import redis - -redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True) - -app = FastAPI() -app.mount("/.well-known", StaticFiles(directory=".well-known"), name="static") - -# Route to list all TODOs -@app.get("/todos") -def list_todos(): - todos = {} - for key in redis_client.keys(): - if key != 'todo_id': - todos[key] = "["+key+"] "+str(redis_client.get(key)) - return todos - -# Route to list a specific TODO -@app.get("/todos/{todo_id}") -def list_todo(todo_id: int): - todo = redis_client.get(str(todo_id)) - if todo: - return {"todo_id": todo_id, "todo": todo} - else: - raise HTTPException(status_code=404, detail="Todo not found") - -# Route to add a TODO -@app.post("/todos") -def add_todo(todo: str): - # Generate a unique todo_id - todo_id = redis_client.incr('todo_id') - redis_client.set(str(todo_id), todo) - return {"todo_id": todo_id, "todo": todo} - -# Route to delete a TODO -@app.delete("/todos/{todo_id}") -def delete_todo(todo_id: int): - if not redis_client.exists(str(todo_id)): - raise HTTPException(status_code=404, detail="Todo not found") - redis_client.delete(str(todo_id)) - return {"result": "Todo deleted"} - -if __name__ == "__main__": - import uvicorn - uvicorn.run("main:app", host="0.0.0.0", port=8000, log_level="info") diff --git a/test_main.py b/test_main.py deleted file mode 100644 index b6a682d..0000000 --- a/test_main.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest -from fastapi.testclient import TestClient - -from main import app - - -@pytest.fixture -def client(): - return TestClient(app) - - -def test_list_todos_empty(client): - response = client.get("/todos") - assert response.status_code == 200 - assert response.json() == {} - - -def test_list_todo_not_found(client): - response = client.get("/todos/1") - assert response.status_code == 404 - assert response.json() == {"detail": "Todo not found"} - - -def test_add_todo(client): - response = client.post("/todos", params={"todo": "Buy groceries"}) - assert response.status_code == 200 - assert response.json() == {"todo_id": 1, "todo": "Buy groceries"} - - -def test_list_todo(client): - client.post("/todos", params={"todo": "Buy groceries"}) - response = client.get("/todos/1") - assert response.status_code == 200 - assert response.json() == {"todo_id": 1, "todo": "Buy groceries"} - - -def test_delete_todo(client): - response = client.delete("/todos/1") - assert response.status_code == 200 - assert response.json() == {"result": "Todo deleted"} - - -def test_delete_todo_not_found(client): - response = client.delete("/todos/1") - assert response.status_code == 404 - assert response.json() == {"detail": "Todo not found"} \ No newline at end of file From 4bbc293fc522878250f2d366fbe7ff5808ce5bde Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 12:27:03 -0700 Subject: [PATCH 2/9] no default py int path --- .devcontainer/devcontainer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index bff8387..1ce5c7e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -19,7 +19,6 @@ // Set *default* container specific settings.json values on container create. "settings": { "[python]": { - "defaultInterpreterPath": "/opt/conda/envs/myenv/bin/python", "editor.formatOnType": true, "editor.formatOnSave": true } From 9c921b850a5c2779c45ac140a0111541851093ee Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 12:44:04 -0700 Subject: [PATCH 3/9] no flush db --- flush_db.py | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 flush_db.py diff --git a/flush_db.py b/flush_db.py deleted file mode 100644 index 9b12b58..0000000 --- a/flush_db.py +++ /dev/null @@ -1,4 +0,0 @@ -import redis - -redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True) -redis_client.flushdb() \ No newline at end of file From 0c6f87e48b976fb7e7e55e9efb47152bb69d5377 Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 12:51:16 -0700 Subject: [PATCH 4/9] req path --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 22b6d67..f11086e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -7,5 +7,5 @@ RUN python3 -m pip install --upgrade pip # Copy requirements.txt (if found) to a temp location so we update the environment. Also # copy "setup.sh" so the COPY instruction does not fail if no requirements.txt exists. -COPY ../requirements.txt setup.sh /tmp/pip/ +COPY requirements.txt* setup.sh /tmp/pip/ RUN if [ -f "/tmp/pip/requirements.txt" ]; then umask 0002 && python3 -m pip install -r /tmp/pip/requirements.txt && sudo rm -rf /tmp/pip; fi From 1faed2a15d7e2b310eacd1eb7e4ca1f7bd443a8a Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 20:03:06 +0000 Subject: [PATCH 5/9] pip install in setup --- .devcontainer/Dockerfile | 5 --- .devcontainer/setup.sh | 2 ++ .well-known/ai-plugin.json | 14 ++++---- .well-known/openapi.yaml | 73 ++++++++++++++++++++++++++++++++++++++ main.py | 44 +++++++++++++++++++++++ 5 files changed, 126 insertions(+), 12 deletions(-) create mode 100644 .well-known/openapi.yaml create mode 100644 main.py diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f11086e..0b48faf 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -4,8 +4,3 @@ ARG VARIANT=bullseye FROM mcr.microsoft.com/devcontainers/python:${VERSION}-${VARIANT} RUN python3 -m pip install --upgrade pip - -# Copy requirements.txt (if found) to a temp location so we update the environment. Also -# copy "setup.sh" so the COPY instruction does not fail if no requirements.txt exists. -COPY requirements.txt* setup.sh /tmp/pip/ -RUN if [ -f "/tmp/pip/requirements.txt" ]; then umask 0002 && python3 -m pip install -r /tmp/pip/requirements.txt && sudo rm -rf /tmp/pip; fi diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index e624149..4160fc1 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -1,6 +1,8 @@ #!/bin/sh # set -eu +chmod +x ./requirements.txt && pip install -r ./requirements.txt +echo # Check if the "redis" container is running if ! docker ps --filter "status=running" --format "{{.Names}}" | grep -q "redis"; then # If the "redis" container is not running, start it using docker-compose diff --git a/.well-known/ai-plugin.json b/.well-known/ai-plugin.json index e035612..7c53c4e 100644 --- a/.well-known/ai-plugin.json +++ b/.well-known/ai-plugin.json @@ -1,19 +1,19 @@ { "schema_version": "v1", - "name_for_human": "My app", - "name_for_model": "my_app", - "description_for_human": "This app is", - "description_for_model": "This app is", + "name_for_human": "Todo app", + "name_for_model": "todo_app", + "description_for_human": "A todo app for managing your tasks", + "description_for_model": "A todo app for managing tasks", "auth": { "type": "user_http", "authorization_type": "bearer" }, "api": { "type": "openapi", - "url": "https://your-app-url.com/.well-known/openapi.yaml", + "url": "https://your-app-url.com/openapi.yaml", "is_user_authenticated": "false" }, - "logo_url": "https://your-app-url.com/.well-known/logo.png", + "logo_url": "https://your-app-url.com/logo.png", "contact_email": "example@company.com", "legal_info_url": "https://example.com/legal" -} +} \ No newline at end of file diff --git a/.well-known/openapi.yaml b/.well-known/openapi.yaml new file mode 100644 index 0000000..739289c --- /dev/null +++ b/.well-known/openapi.yaml @@ -0,0 +1,73 @@ +openapi: 3.0.0 +info: + title: Todo app + description: A todo app for managing your tasks + version: 1.0.0 +servers: + - url: http://localhost:8000 +paths: + /todos/: + post: + summary: Create a new todo + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Todo' + responses: + '200': + description: Todo created successfully + get: + summary: Get all todos + responses: + '200': + description: List of todos + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Todo' + /todos/{todo_id}: + get: + summary: Get a todo by ID + parameters: + - name: todo_id + in: path + required: true + schema: + type: integer + responses: + '200': + description: Todo found + content: + application/json: + schema: + $ref: '#/components/schemas/Todo' + '404': + description: Todo not found + delete: + summary: Delete a todo by ID + parameters: + - name: todo_id + in: path + required: true + schema: + type: integer + responses: + '200': + description: Todo deleted successfully + '404': + description: Todo not found +components: + schemas: + Todo: + type: object + properties: + todo_id: + type: integer + title: + type: string + description: + type: string diff --git a/main.py b/main.py new file mode 100644 index 0000000..b1819f1 --- /dev/null +++ b/main.py @@ -0,0 +1,44 @@ +from fastapi import FastAPI, HTTPException +from redis import Redis +from pydantic import BaseModel +from fastapi.staticfiles import StaticFiles + +app = FastAPI() +redis = Redis(host="redis", port=6379) + +app.mount("/.well-known", StaticFiles(directory=".well-known"), name="static") + +class Todo(BaseModel): + todo_id: int + title: str + description: str + +@app.post("/todos/") +async def create_todo(todo: Todo): + redis.set(todo.todo_id, todo.json()) + return {"message": "Todo created successfully"} + +@app.get("/todos/") +async def get_todos(): + todos = [] + for key in redis.keys(): + todos.append(redis.get(key)) + return todos + +@app.get("/todos/{todo_id}") +async def get_todo_by_id(todo_id: int): + todo = redis.get(todo_id) + if not todo: + raise HTTPException(status_code=404, detail="Todo not found") + return todo + +@app.delete("/todos/{todo_id}") +async def delete_todo_by_id(todo_id: int): + if not redis.get(todo_id): + raise HTTPException(status_code=404, detail="Todo not found") + redis.delete(todo_id) + return {"message": "Todo deleted successfully"} + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8000) \ No newline at end of file From e42862f8b84cebb2e35aa4f40d563b1857d9e2ae Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 13:04:46 -0700 Subject: [PATCH 6/9] rm code --- .well-known/ai-plugin.json | 19 ---------- .well-known/openapi.yaml | 73 -------------------------------------- main.py | 44 ----------------------- 3 files changed, 136 deletions(-) delete mode 100644 .well-known/ai-plugin.json delete mode 100644 .well-known/openapi.yaml delete mode 100644 main.py diff --git a/.well-known/ai-plugin.json b/.well-known/ai-plugin.json deleted file mode 100644 index 7c53c4e..0000000 --- a/.well-known/ai-plugin.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "schema_version": "v1", - "name_for_human": "Todo app", - "name_for_model": "todo_app", - "description_for_human": "A todo app for managing your tasks", - "description_for_model": "A todo app for managing tasks", - "auth": { - "type": "user_http", - "authorization_type": "bearer" - }, - "api": { - "type": "openapi", - "url": "https://your-app-url.com/openapi.yaml", - "is_user_authenticated": "false" - }, - "logo_url": "https://your-app-url.com/logo.png", - "contact_email": "example@company.com", - "legal_info_url": "https://example.com/legal" -} \ No newline at end of file diff --git a/.well-known/openapi.yaml b/.well-known/openapi.yaml deleted file mode 100644 index 739289c..0000000 --- a/.well-known/openapi.yaml +++ /dev/null @@ -1,73 +0,0 @@ -openapi: 3.0.0 -info: - title: Todo app - description: A todo app for managing your tasks - version: 1.0.0 -servers: - - url: http://localhost:8000 -paths: - /todos/: - post: - summary: Create a new todo - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Todo' - responses: - '200': - description: Todo created successfully - get: - summary: Get all todos - responses: - '200': - description: List of todos - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Todo' - /todos/{todo_id}: - get: - summary: Get a todo by ID - parameters: - - name: todo_id - in: path - required: true - schema: - type: integer - responses: - '200': - description: Todo found - content: - application/json: - schema: - $ref: '#/components/schemas/Todo' - '404': - description: Todo not found - delete: - summary: Delete a todo by ID - parameters: - - name: todo_id - in: path - required: true - schema: - type: integer - responses: - '200': - description: Todo deleted successfully - '404': - description: Todo not found -components: - schemas: - Todo: - type: object - properties: - todo_id: - type: integer - title: - type: string - description: - type: string diff --git a/main.py b/main.py deleted file mode 100644 index b1819f1..0000000 --- a/main.py +++ /dev/null @@ -1,44 +0,0 @@ -from fastapi import FastAPI, HTTPException -from redis import Redis -from pydantic import BaseModel -from fastapi.staticfiles import StaticFiles - -app = FastAPI() -redis = Redis(host="redis", port=6379) - -app.mount("/.well-known", StaticFiles(directory=".well-known"), name="static") - -class Todo(BaseModel): - todo_id: int - title: str - description: str - -@app.post("/todos/") -async def create_todo(todo: Todo): - redis.set(todo.todo_id, todo.json()) - return {"message": "Todo created successfully"} - -@app.get("/todos/") -async def get_todos(): - todos = [] - for key in redis.keys(): - todos.append(redis.get(key)) - return todos - -@app.get("/todos/{todo_id}") -async def get_todo_by_id(todo_id: int): - todo = redis.get(todo_id) - if not todo: - raise HTTPException(status_code=404, detail="Todo not found") - return todo - -@app.delete("/todos/{todo_id}") -async def delete_todo_by_id(todo_id: int): - if not redis.get(todo_id): - raise HTTPException(status_code=404, detail="Todo not found") - redis.delete(todo_id) - return {"message": "Todo deleted successfully"} - -if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) \ No newline at end of file From 03859d0d94d950c4c3df40d31bd3a4aadeca0f45 Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 14:52:24 -0700 Subject: [PATCH 7/9] no hostconfig --- .devcontainer/setup.sh | 4 --- hostconfig.sh | 59 ------------------------------------------ 2 files changed, 63 deletions(-) delete mode 100755 hostconfig.sh diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 4160fc1..31b2bea 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -23,10 +23,6 @@ export DATASTORE=redis export BEARER_TOKEN=footoken export PLUGIN_HOSTNAME=https://$CODESPACE_NAME-8000.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN -echo -echo "Setting host configuration (from ./hostconfig.sh)..." -chmod +x ./hostconfig.sh && ./hostconfig.sh - echo echo "Click on GitHub Codespaces PORTS tab. Right click on port 8000, and set Port Visibility to Public. Once Port 8000 if Public, press Enter to continue..." read -r placeholder_var diff --git a/hostconfig.sh b/hostconfig.sh deleted file mode 100755 index 40542cb..0000000 --- a/hostconfig.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -set -eu - -# Check if CODESPACES environment variable is set to true -if [ "$CODESPACES" = "true" ]; then - # If CODESPACES is true and PLUGIN_HOSTNAME is undefined or empty, set PLUGIN_HOSTNAME - if [ -z "$PLUGIN_HOSTNAME" ]; then - # Check if CODESPACE_NAME and GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN are set - if [ -z "$CODESPACE_NAME" ] || [ -z "$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN" ]; then - echo "CODESPACE_NAME and/or GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN environment variables are not set." - exit 1 - fi - # Set PLUGIN_HOSTNAME to the expanded version of the URL - PLUGIN_HOSTNAME="https://$CODESPACE_NAME-8000.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN" - fi -else - # If CODESPACES is not true, check if PLUGIN_HOSTNAME is set - if [ -z "$PLUGIN_HOSTNAME" ]; then - echo "PLUGIN_HOSTNAME environment variable is not set." - exit 1 - fi -fi - -# Input JSON file -json_input_file="./.well-known/ai-plugin.json" - -# Input YAML file -yaml_input_file="./.well-known/openapi.yaml" - -# Create temporary files to store the modified JSON and YAML -temp_json_file=$(mktemp) -temp_yaml_file=$(mktemp) - -# Read the JSON file and perform the substitutions using jq -jq --arg plugin_hostname "$PLUGIN_HOSTNAME" ' - .api.url = ($plugin_hostname + "/.well-known/openapi.yaml") | - .logo_url = ($plugin_hostname + "/.well-known/logo.png") -' "$json_input_file" > "$temp_json_file" - -# Find the line number where the "servers:" key is located in the YAML file -servers_line_number=$(grep -n "servers:" "$yaml_input_file" | cut -d: -f1) - -# Update the YAML file using sed and awk -awk -v line_number="$servers_line_number" -v plugin_hostname="$PLUGIN_HOSTNAME" ' - NR == line_number + 1 { - sub(/url: .*/, "url: " plugin_hostname) - } - { print } -' "$yaml_input_file" > "$temp_yaml_file" - -# Overwrite the original JSON file with the modified contents -mv "$temp_json_file" "$json_input_file" - -# Overwrite the original YAML file with the modified contents -mv "$temp_yaml_file" "$yaml_input_file" - -# Print success messages -echo "$json_input_file has been updated successfully." -echo "$yaml_input_file file has been updated successfully." From 41ebfa392162f7833019d6a3cf9d1ede4364796b Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 22:26:00 +0000 Subject: [PATCH 8/9] demo code complete --- .well-known/ai-plugin.json | 19 ++++++++ .well-known/logo.png | Bin 8085 -> 17842 bytes .well-known/openapi.yaml | 89 +++++++++++++++++++++++++++++++++++++ flushdb.py | 4 ++ main.py | 47 ++++++++++++++++++++ requirements.txt | 0 test_main.py | 46 +++++++++++++++++++ 7 files changed, 205 insertions(+) create mode 100644 .well-known/ai-plugin.json create mode 100644 .well-known/openapi.yaml create mode 100644 flushdb.py create mode 100644 main.py mode change 100644 => 100755 requirements.txt create mode 100644 test_main.py diff --git a/.well-known/ai-plugin.json b/.well-known/ai-plugin.json new file mode 100644 index 0000000..5ad3cf2 --- /dev/null +++ b/.well-known/ai-plugin.json @@ -0,0 +1,19 @@ +{ + "schema_version": "v1", + "name_for_human": "Todo app", + "name_for_model": "todo_app", + "description_for_human": "Todo app for managing your tasks", + "description_for_model": "Todo app for managing your tasks", + "auth": { + "type": "user_http", + "authorization_type": "bearer" + }, + "api": { + "type": "openapi", + "url": "https://minsa110-cuddly-palm-tree-69gr759q74q24pw4-8000.preview.app.github.dev/.well-known/openapi.yaml", + "is_user_authenticated": "false" + }, + "logo_url": "https://minsa110-cuddly-palm-tree-69gr759q74q24pw4-8000.preview.app.github.dev/.well-known/logo.png", + "contact_email": "example@company.com", + "legal_info_url": "https://example.com/legal" +} \ No newline at end of file diff --git a/.well-known/logo.png b/.well-known/logo.png index 0f237a226583e08f89f14a15d86aa330a11151ae..5bffb38822fcb471378d6a870e73cc1699160111 100644 GIT binary patch literal 17842 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 literal 8085 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 diff --git a/.well-known/openapi.yaml b/.well-known/openapi.yaml new file mode 100644 index 0000000..fb8d485 --- /dev/null +++ b/.well-known/openapi.yaml @@ -0,0 +1,89 @@ +openapi: 3.0.2 +info: + title: OpenAI plugin for a simple todo app + description: Todo app for managing your tasks on ChatGPT + version: 1.0.0 + servers: + - url: https://minsa110-laughing-eureka-979q457rx6q3p954-8000.preview.app.github.dev +paths: + /todos: + post: + summary: Create a new TODO item + description: Accepts a string and adds as new TODO item + operationId: create_todo + parameters: + - in: query + name: todo + schema: + type: string + required: true + description: The description of the TODO item + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/TodoItem" + get: + summary: Get a list of all TODO items + operationId: list_todos + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TodoList" + /todos/{todo_id}: + get: + summary: Get a TODO item by ID + operationId: get_todo + parameters: + - name: todo_id + in: path + required: true + description: ID of the TODO item to retrieve + schema: + type: integer + format: int64 + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/TodoItem" + "404": + description: Todo not found + delete: + summary: Delete a TODO item by ID + operationId: delete_todo + parameters: + - name: todo_id + in: path + required: true + description: ID of the TODO item to delete + schema: + type: integer + format: int64 + responses: + "204": + description: Todo deleted + "404": + description: Todo not found +components: + schemas: + TodoItem: + type: object + properties: + todo: + type: string + todo_id: + type: integer + format: int32 + readOnly: true + required: + - todo \ No newline at end of file diff --git a/flushdb.py b/flushdb.py new file mode 100644 index 0000000..629e03f --- /dev/null +++ b/flushdb.py @@ -0,0 +1,4 @@ +import redis + +redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True) +redis_client.flushdb() \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..bf63a27 --- /dev/null +++ b/main.py @@ -0,0 +1,47 @@ +from fastapi import FastAPI, HTTPException +from fastapi.staticfiles import StaticFiles +import os +import redis + +redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True) + +app = FastAPI() +app.mount("/.well-known", StaticFiles(directory=".well-known"), name="static") + +# Route to list all TODOs +@app.get("/todos") +def list_todos(): + todos = {} + for key in redis_client.keys(): + if key != 'todo_id': + todos[key] = "["+key+"] "+str(redis_client.get(key)) + return todos + +# Route to list a specific TODO +@app.get("/todos/{todo_id}") +def list_todo(todo_id: int): + todo = redis_client.get(str(todo_id)) + if todo: + return {"todo_id": todo_id, "todo": todo} + else: + raise HTTPException(status_code=404, detail="Todo not found") + +# Route to add a TODO +@app.post("/todos") +def add_todo(todo: str): + # Generate a unique todo_id + todo_id = redis_client.incr('todo_id') + redis_client.set(str(todo_id), todo) + return {"todo_id": todo_id, "todo": todo} + +# Route to delete a TODO +@app.delete("/todos/{todo_id}") +def delete_todo(todo_id: int): + if not redis_client.exists(str(todo_id)): + raise HTTPException(status_code=404, detail="Todo not found") + redis_client.delete(str(todo_id)) + return {"result": "Todo deleted"} + +if __name__ == "__main__": + import uvicorn + uvicorn.run("main:app", host="0.0.0.0", port=8000, log_level="info") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt old mode 100644 new mode 100755 diff --git a/test_main.py b/test_main.py new file mode 100644 index 0000000..d7be50f --- /dev/null +++ b/test_main.py @@ -0,0 +1,46 @@ +import pytest +from fastapi.testclient import TestClient + +from main import app + + +@pytest.fixture +def client(): + return TestClient(app) + + +def test_list_todos_empty(client): + response = client.get("/todos") + assert response.status_code == 200 + assert response.json() == {} + + +def test_list_todo_not_found(client): + response = client.get("/todos/1") + assert response.status_code == 404 + assert response.json() == {"detail": "Todo not found"} + + +def test_add_todo(client): + response = client.post("/todos", params={"todo": "Buy groceries"}) + assert response.status_code == 200 + assert response.json() == {"todo_id": 1, "todo": "Buy groceries"} + + +def test_list_todo(client): + client.post("/todos", params={"todo": "Buy groceries"}) + response = client.get("/todos/1") + assert response.status_code == 200 + assert response.json() == {"todo_id": 1, "todo": "Buy groceries"} + + +def test_delete_todo(client): + response = client.delete("/todos/1") + assert response.status_code == 200 + assert response.json() == {"result": "Todo deleted"} + + +def test_delete_todo_not_found(client): + response = client.delete("/todos/1") + assert response.status_code == 404 + assert response.json() == {"detail": "Todo not found"} \ No newline at end of file From aa176e213a0bf27701c1d213774d7fc062935b21 Mon Sep 17 00:00:00 2001 From: "Soojin (Min) Choi" Date: Mon, 10 Apr 2023 15:31:40 -0700 Subject: [PATCH 9/9] azd --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6a082c..3e406c7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Building an Open AI plugin with Codespaces -☁️ **To deploy your app on Azure using Azure Developer CLI and Container Apps, see the [demo-azd](https://github.com/minsa110/devcontainer-fastapi/tree/demo-azd) branch.** +☁️ **To deploy your app on Azure using Azure Developer CLI and Container Apps, see the [azd-demo](https://github.com/minsa110/devcontainer-fastapi/tree/azd-demo) branch.** This is a sample repo for developing OpenAI plugin using the FastAPI framework. There are two main parts of the repo: - Code to help setup development environment for FastAPI framework