├── .nvmrc ├── assets ├── message.private.js ├── style.css └── index.html ├── package.json ├── functions └── chatgpt.js ├── README.md ├── .gitignore └── .twilioserverlessrc /.nvmrc: -------------------------------------------------------------------------------- 1 | 16 -------------------------------------------------------------------------------- /assets/message.private.js: -------------------------------------------------------------------------------- 1 | const privateMessage = () => { 2 | return 'This is private!'; 3 | }; 4 | 5 | module.exports = privateMessage; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatgpt-sms", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "start": "twilio-run", 8 | "deploy": "twilio-run deploy" 9 | }, 10 | "dependencies": { 11 | "@twilio/runtime-handler": "1.3.0", 12 | "openai": "^3.1.0", 13 | "twilio": "^3.56" 14 | }, 15 | "devDependencies": { 16 | "twilio-run": "^3.5.2" 17 | }, 18 | "engines": { 19 | "node": "16" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /functions/chatgpt.js: -------------------------------------------------------------------------------- 1 | const { Configuration, OpenAIApi } = require("openai"); 2 | exports.handler = async function(context, event, callback) { 3 | const twiml = new Twilio.twiml.MessagingResponse(); 4 | const inbMsg = event.Body.toLowerCase().trim(); 5 | const configuration = new Configuration({ 6 | //organization: "org-Oyoa0o8GqjpBw4Bbhb5ek8ou", 7 | apiKey: process.env.OPENAI_API_KEY 8 | }); 9 | const openai = new OpenAIApi(configuration); 10 | const response = await openai.createCompletion({ 11 | model: "text-davinci-003", 12 | prompt: inbMsg, 13 | temperature: 0.7, //A number between 0 and 1 that determines how many creative risks the engine takes when generating text. 14 | max_tokens: 160, // Maximum completion length. 15 | frequency_penalty: 0.7 // # between 0 and 1. The higher this value, the bigger the effort the model will make in not repeating itself. 16 | }); 17 | twiml.message(response.data.choices[0].text); 18 | callback(null, twiml); 19 | }; 20 | -------------------------------------------------------------------------------- /assets/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | ::selection { 8 | background: #f22f46; 9 | color: white; 10 | } 11 | 12 | body { 13 | font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, 14 | 'Helvetica Neue', Arial, sans-serif; 15 | color: #0d122b; 16 | border-top: 5px solid #f22f46; 17 | } 18 | 19 | header { 20 | padding: 2em; 21 | margin-bottom: 2em; 22 | max-width: 800px; 23 | margin: 0 auto; 24 | } 25 | 26 | header h1 { 27 | padding-bottom: 14px; 28 | border-bottom: 1px solid rgba(148, 151, 155, 0.2); 29 | } 30 | 31 | a { 32 | color: #008cff; 33 | } 34 | 35 | main { 36 | margin: 0 auto 6em; 37 | padding: 0 2em; 38 | max-width: 800px; 39 | } 40 | 41 | main p { 42 | margin-bottom: 2em; 43 | } 44 | 45 | main p code { 46 | font-size: 16px; 47 | font-family: 'Fira Mono', monospace; 48 | color: #f22f46; 49 | background-color: #f9f9f9; 50 | box-shadow: inset 0 0 0 1px #e8e8e8; 51 | font-size: inherit; 52 | line-height: 1.2; 53 | padding: 0.15em 0.4em; 54 | border-radius: 4px; 55 | display: inline-block; 56 | white-space: pre-wrap; 57 | } 58 | 59 | main h2 { 60 | margin-bottom: 1em; 61 | } 62 | 63 | footer { 64 | margin: 0 auto; 65 | max-width: 800px; 66 | text-align: center; 67 | } 68 | 69 | footer p { 70 | border-top: 1px solid rgba(148, 151, 155, 0.2); 71 | padding-top: 2em; 72 | margin: 0 2em; 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chatGPT-SMS 2 | 3 | Use ChatGPT without the browser! Text +17622490430. 4 | ![image](https://user-images.githubusercontent.com/8932430/210679442-9c740918-d31b-48ee-b936-6d50a829c830.png) 5 | 6 | 7 | You'll need an OpenAI API Key. You can [get one here](https://beta.openai.com/account/api-keys) by clicking on `+ Create new secret key`. 8 | ![image](https://user-images.githubusercontent.com/8932430/210679481-f28e7deb-94c0-4bd1-8ae5-a30a40c83584.png) 9 | 10 | ## Set an Environment Variable with Twilio Functions and Assets 11 | Open up your `.env file` for your Functions project in your root directory and add the following line: 12 | 13 | ```bash 14 | OPENAI_API_KEY=YOUR-OPENAI-API-KEY 15 | ``` 16 | Now you can access this API Key if you'd like to do so in your code with `context.OPENAI_API_KEY`. 17 | 18 | ## Configure the Serverless Function with a Twilio Phone Number 19 | 20 | To open up our app to the web with a public-facing URL, run `twilio serverless:deploy` from the root directory. 21 | ![image](https://user-images.githubusercontent.com/8932430/210679657-5fe03667-35fe-4562-8fa3-2c8da685245d.png) 22 | Grab the Function URL corresponding to your app (the one that ends with `/chatgpt`) and [configure a Twilio phone number](https://www.google.com/url?q=https://www.twilio.com/console/phone-numbers/incoming&sa=D&source=editors&ust=1672884776711184&usg=AOvVaw3wjORqsU1VSnRNp5fXjwn2) with it as shown below: select a Twilio number you purchased in your Twilio phone numbers console and scroll down to the `Messaging` section. Paste the link in the text field for `A MESSAGE COMES IN` webhook making sure that it's set to `HTTP POST`. When you click `Save` it should look like this! 23 | ![image](https://user-images.githubusercontent.com/8932430/210679812-3d6c91a5-4045-4c08-bdef-e2b9da43e6f1.png) 24 | 25 | Now take out your phone and text a question or prompt to your Twilio number. 26 | ![image](https://user-images.githubusercontent.com/8932430/210679847-6ab42526-7925-404e-8770-90f25e960538.png) 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Twilio Serverless 2 | .twiliodeployinfo 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # Snowpack dependency directory (https://snowpack.dev/) 49 | web_modules/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Optional stylelint cache 61 | .stylelintcache 62 | 63 | # Microbundle cache 64 | .rpt2_cache/ 65 | .rts2_cache_cjs/ 66 | .rts2_cache_es/ 67 | .rts2_cache_umd/ 68 | 69 | # Optional REPL history 70 | .node_repl_history 71 | 72 | # Output of 'npm pack' 73 | *.tgz 74 | 75 | # Yarn Integrity file 76 | .yarn-integrity 77 | 78 | # dotenv environment variable files 79 | .env 80 | .env.development.local 81 | .env.test.local 82 | .env.production.local 83 | .env.local 84 | 85 | # parcel-bundler cache (https://parceljs.org/) 86 | .cache 87 | .parcel-cache 88 | 89 | # Next.js build output 90 | .next 91 | out 92 | 93 | # Nuxt.js build / generate output 94 | .nuxt 95 | dist 96 | 97 | # Gatsby files 98 | .cache/ 99 | # Comment in the public line in if your project uses Gatsby and not Next.js 100 | # https://nextjs.org/blog/next-9-1#public-directory-support 101 | # public 102 | 103 | # vuepress build output 104 | .vuepress/dist 105 | 106 | # vuepress v2.x temp and cache directory 107 | .temp 108 | .cache 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | -------------------------------------------------------------------------------- /assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Hello Twilio Serverless! 9 | 10 | 11 |

Hello Twilio Serverless!

12 | 13 |
14 |

15 | Congratulations you just started a new Twilio 16 | Serverless project. 17 |

18 | 19 |

Assets

20 |

21 | Assets are static files, like HTML, CSS, JavaScript, images or audio 22 | files. 23 |

24 | 25 |

26 | This HTML page is an example of a public asset, you can 27 | access this by loading it in the browser. The HTML also refers to 28 | another public asset for CSS styles. 29 |

30 |

31 | You can also have private assets, there is an example 32 | private asset called message.private.js in the 33 | /assets directory. This file cannot be loaded in the 34 | browser, but you can load it as part of a function by finding its path 35 | using Runtime.getAssets() and then requiring the file. 36 | There is an example of this in 37 | /functions/private-message.js. 38 |

39 | 40 |

Functions

41 |

42 | Functions are JavaScript files that will respond to incoming HTTP 43 | requests. There are public and 44 | protected functions. 45 |

46 | 47 |

48 | Public functions respond to all HTTP requests. There is 49 | an example of a public function in 50 | /functions/hello-world.js. 51 |

52 | 53 |

54 | Protected functions will only respond to HTTP requests 55 | with a valid Twilio signature in the header. You can read more about 56 | validating requests from Twilio in the documentation. There is an example of a protected function in 59 | /functions/sms/reply.protected.js 60 |

61 | 62 |

twilio-run

63 | 64 |

65 | Functions and assets are served, deployed and debugged using 66 | twilio-run. You can serve the project locally with the command 69 | npm start which is really running 70 | twilio-run --env under the hood. If you want to see what 71 | else you can do with twilio-run enter 72 | npx twilio-run --help on the command line or check out 73 | the project documentation on GitHub. 76 |

77 |
78 | 79 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /.twilioserverlessrc: -------------------------------------------------------------------------------- 1 | { 2 | "commands": {}, 3 | "environments": {}, 4 | "projects": {}, 5 | // "assets": true /* Upload assets. Can be turned off with --no-assets */, 6 | // "assetsFolder": null /* Specific folder name to be used for static assets */, 7 | // "buildSid": null /* An existing Build SID to deploy to the new environment */, 8 | // "createEnvironment": false /* Creates environment if it couldn't find it. */, 9 | // "cwd": null /* Sets the directory of your existing Serverless project. Defaults to current directory */, 10 | // "detailedLogs": false /* Toggles detailed request logging by showing request body and query params */, 11 | // "edge": null /* Twilio API Region */, 12 | // "env": null /* Path to .env file for environment variables that should be installed */, 13 | // "environment": "dev" /* The environment name (domain suffix) you want to use for your deployment. Alternatively you can specify an environment SID starting with ZE. */, 14 | // "extendedOutput": false /* Show an extended set of properties on the output */, 15 | // "force": false /* Will run deployment in force mode. Can be dangerous. */, 16 | // "forkProcess": true /* Disable forking function processes to emulate production environment */, 17 | // "functionSid": null /* Specific Function SID to retrieve logs for */, 18 | // "functions": true /* Upload functions. Can be turned off with --no-functions */, 19 | // "functionsFolder": null /* Specific folder name to be used for static functions */, 20 | // "inspect": null /* Enables Node.js debugging protocol */, 21 | // "inspectBrk": null /* Enables Node.js debugging protocol, stops execution until debugger is attached */, 22 | // "legacyMode": false /* Enables legacy mode, it will prefix your asset paths with /assets */, 23 | // "live": true /* Always serve from the current functions (no caching) */, 24 | // "loadLocalEnv": false /* Includes the local environment variables */, 25 | // "loadSystemEnv": false /* Uses system environment variables as fallback for variables specified in your .env file. Needs to be used with --env explicitly specified. */, 26 | // "logCacheSize": null /* Tailing the log endpoint will cache previously seen entries to avoid duplicates. The cache is topped at a maximum of 1000 by default. This option can change that. */, 27 | // "logLevel": "info" /* Level of logging messages. */, 28 | // "logs": true /* Toggles request logging */, 29 | // "ngrok": null /* Uses ngrok to create a public url. Pass a string to set the subdomain (requires a paid-for ngrok account). */, 30 | // "outputFormat": "" /* Output the results in a different format */, 31 | // "overrideExistingProject": false /* Deploys Serverless project to existing service if a naming conflict has been found. */, 32 | // "port": "3000" /* Override default port of 3000 */, 33 | // "production": false /* Promote build to the production environment (no domain suffix). Overrides environment flag */, 34 | // "properties": null /* Specify the output properties you want to see. Works best on single types */, 35 | // "region": null /* Twilio API Region */, 36 | "runtime": "node16" /* The version of Node.js to deploy the build to. (node16) */, 37 | // "serviceName": null /* Overrides the name of the Serverless project. Default: the name field in your package.json */, 38 | // "serviceSid": null /* SID of the Twilio Serverless Service to deploy to */, 39 | // "sourceEnvironment": null /* SID or suffix of an existing environment you want to deploy from. */, 40 | // "tail": false /* Continuously stream the logs */, 41 | // "template": null /* undefined */, 42 | } --------------------------------------------------------------------------------