├── .devcontainer └── devcontainer.json ├── .flake8 ├── .github └── dependabot.yml ├── .gitignore ├── .mypy.ini ├── .pylintrc ├── .vscode └── settings.json ├── README.md ├── requirements.txt └── solutions ├── chainlit_conversational_memory.py ├── chainlit_hello_world.py ├── chainlit_stream.py ├── chainlit_use_model.py ├── chat_prompt.py ├── conversational_memory.py ├── exercises ├── basic_prompting.py ├── change_chatbots.py └── llama2.py ├── langchain ├── chainlit_with_langchain.py └── langchain_demo.py ├── simple_completion.py └── stream_answer.py /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/python 3 | { 4 | "name": "Python 3", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/python:1-3.11-bullseye", 7 | "features": { 8 | "ghcr.io/devcontainers-contrib/features/black:2": { 9 | "version": "latest" 10 | }, 11 | "ghcr.io/devcontainers-contrib/features/flake8:2": { 12 | "version": "latest", 13 | "plugins": "flake8-black" 14 | } 15 | }, 16 | "customizations": { 17 | // Configure properties specific to VS Code. 18 | "vscode": { 19 | // Set *default* container specific settings.json values on container create. 20 | "extensions": [ 21 | "dbaeumer.vscode-eslint", 22 | "GitHub.codespaces", 23 | "GitHub.github-vscode-theme", 24 | "GitHub.vscode-pull-request-github", 25 | "ms-python.black-formatter", 26 | "ms-python.debugpy", 27 | "ms-python.flake8", 28 | "ms-python.python", 29 | "ms-python.vscode-pylance" 30 | ] 31 | } 32 | }, 33 | "postCreateCommand": "pip3 install --user -r requirements.txt" 34 | // Features to add to the dev container. More info: https://containers.dev/features. 35 | // "features": {}, 36 | 37 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 38 | // "forwardPorts": [], 39 | 40 | // Use 'postCreateCommand' to run commands after the container is created. 41 | 42 | // Configure tool-specific properties. 43 | // "customizations": {}, 44 | 45 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 46 | // "remoteUser": "root" 47 | } 48 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E501 -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for more information: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | # https://containers.dev/guide/dependabot 6 | 7 | version: 2 8 | updates: 9 | - package-ecosystem: "devcontainers" 10 | directory: "/" 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /.mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | exclude=.* 3 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MAIN] 2 | 3 | # Analyse import fallback blocks. This can be used to support both Python 2 and 4 | # 3 compatible code, which means that the block might have code that exists 5 | # only in one or another interpreter, leading to false positives when analysed. 6 | analyse-fallback-blocks=no 7 | 8 | # Clear in-memory caches upon conclusion of linting. Useful if running pylint 9 | # in a server-like mode. 10 | clear-cache-post-run=no 11 | 12 | # Load and enable all available extensions. Use --list-extensions to see a list 13 | # all available extensions. 14 | #enable-all-extensions= 15 | 16 | # In error mode, messages with a category besides ERROR or FATAL are 17 | # suppressed, and no reports are done by default. Error mode is compatible with 18 | # disabling specific errors. 19 | #errors-only= 20 | 21 | # Always return a 0 (non-error) status code, even if lint errors are found. 22 | # This is primarily useful in continuous integration scripts. 23 | #exit-zero= 24 | 25 | # A comma-separated list of package or module names from where C extensions may 26 | # be loaded. Extensions are loading into the active Python interpreter and may 27 | # run arbitrary code. 28 | extension-pkg-allow-list= 29 | 30 | # A comma-separated list of package or module names from where C extensions may 31 | # be loaded. Extensions are loading into the active Python interpreter and may 32 | # run arbitrary code. (This is an alternative name to extension-pkg-allow-list 33 | # for backward compatibility.) 34 | extension-pkg-whitelist= 35 | 36 | # Return non-zero exit code if any of these messages/categories are detected, 37 | # even if score is above --fail-under value. Syntax same as enable. Messages 38 | # specified are enabled, while categories only check already-enabled messages. 39 | fail-on= 40 | 41 | # Specify a score threshold under which the program will exit with error. 42 | fail-under=10 43 | 44 | # Interpret the stdin as a python script, whose filename needs to be passed as 45 | # the module_or_package argument. 46 | #from-stdin= 47 | 48 | # Files or directories to be skipped. They should be base names, not paths. 49 | ignore=CVS 50 | 51 | # Add files or directories matching the regular expressions patterns to the 52 | # ignore-list. The regex matches against paths and can be in Posix or Windows 53 | # format. Because '\\' represents the directory delimiter on Windows systems, 54 | # it can't be used as an escape character. 55 | ignore-paths= 56 | 57 | # Files or directories matching the regular expression patterns are skipped. 58 | # The regex matches against base names, not paths. The default value ignores 59 | # Emacs file locks 60 | ignore-patterns=^\.# 61 | 62 | # List of module names for which member attributes should not be checked 63 | # (useful for modules/projects where namespaces are manipulated during runtime 64 | # and thus existing member attributes cannot be deduced by static analysis). It 65 | # supports qualified module names, as well as Unix pattern matching. 66 | ignored-modules= 67 | 68 | # Python code to execute, usually for sys.path manipulation such as 69 | # pygtk.require(). 70 | #init-hook= 71 | 72 | # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the 73 | # number of processors available to use, and will cap the count on Windows to 74 | # avoid hangs. 75 | jobs=1 76 | 77 | # Control the amount of potential inferred values when inferring a single 78 | # object. This can help the performance when dealing with large functions or 79 | # complex, nested conditions. 80 | limit-inference-results=100 81 | 82 | # List of plugins (as comma separated values of python module names) to load, 83 | # usually to register additional checkers. 84 | load-plugins= 85 | 86 | # Pickle collected data for later comparisons. 87 | persistent=yes 88 | 89 | # Minimum Python version to use for version dependent checks. Will default to 90 | # the version used to run pylint. 91 | py-version=3.11 92 | 93 | # Discover python modules and packages in the file system subtree. 94 | recursive=no 95 | 96 | # Add paths to the list of the source roots. Supports globbing patterns. The 97 | # source root is an absolute path or a path relative to the current working 98 | # directory used to determine a package namespace for modules located under the 99 | # source root. 100 | source-roots= 101 | 102 | # When enabled, pylint would attempt to guess common misconfiguration and emit 103 | # user-friendly hints instead of false-positive error messages. 104 | suggestion-mode=yes 105 | 106 | # Allow loading of arbitrary C extensions. Extensions are imported into the 107 | # active Python interpreter and may run arbitrary code. 108 | unsafe-load-any-extension=no 109 | 110 | # In verbose mode, extra non-checker-related info will be displayed. 111 | #verbose= 112 | 113 | 114 | [BASIC] 115 | 116 | # Naming style matching correct argument names. 117 | argument-naming-style=snake_case 118 | 119 | # Regular expression matching correct argument names. Overrides argument- 120 | # naming-style. If left empty, argument names will be checked with the set 121 | # naming style. 122 | #argument-rgx= 123 | 124 | # Naming style matching correct attribute names. 125 | attr-naming-style=snake_case 126 | 127 | # Regular expression matching correct attribute names. Overrides attr-naming- 128 | # style. If left empty, attribute names will be checked with the set naming 129 | # style. 130 | #attr-rgx= 131 | 132 | # Bad variable names which should always be refused, separated by a comma. 133 | bad-names=foo, 134 | bar, 135 | baz, 136 | toto, 137 | tutu, 138 | tata 139 | 140 | # Bad variable names regexes, separated by a comma. If names match any regex, 141 | # they will always be refused 142 | bad-names-rgxs= 143 | 144 | # Naming style matching correct class attribute names. 145 | class-attribute-naming-style=any 146 | 147 | # Regular expression matching correct class attribute names. Overrides class- 148 | # attribute-naming-style. If left empty, class attribute names will be checked 149 | # with the set naming style. 150 | #class-attribute-rgx= 151 | 152 | # Naming style matching correct class constant names. 153 | class-const-naming-style=UPPER_CASE 154 | 155 | # Regular expression matching correct class constant names. Overrides class- 156 | # const-naming-style. If left empty, class constant names will be checked with 157 | # the set naming style. 158 | #class-const-rgx= 159 | 160 | # Naming style matching correct class names. 161 | class-naming-style=PascalCase 162 | 163 | # Regular expression matching correct class names. Overrides class-naming- 164 | # style. If left empty, class names will be checked with the set naming style. 165 | #class-rgx= 166 | 167 | # Naming style matching correct constant names. 168 | const-naming-style=UPPER_CASE 169 | 170 | # Regular expression matching correct constant names. Overrides const-naming- 171 | # style. If left empty, constant names will be checked with the set naming 172 | # style. 173 | #const-rgx= 174 | 175 | # Minimum line length for functions/classes that require docstrings, shorter 176 | # ones are exempt. 177 | docstring-min-length=-1 178 | 179 | # Naming style matching correct function names. 180 | function-naming-style=snake_case 181 | 182 | # Regular expression matching correct function names. Overrides function- 183 | # naming-style. If left empty, function names will be checked with the set 184 | # naming style. 185 | #function-rgx= 186 | 187 | # Good variable names which should always be accepted, separated by a comma. 188 | good-names=i, 189 | j, 190 | k, 191 | ex, 192 | Run, 193 | _ 194 | 195 | # Good variable names regexes, separated by a comma. If names match any regex, 196 | # they will always be accepted 197 | good-names-rgxs= 198 | 199 | # Include a hint for the correct naming format with invalid-name. 200 | include-naming-hint=no 201 | 202 | # Naming style matching correct inline iteration names. 203 | inlinevar-naming-style=any 204 | 205 | # Regular expression matching correct inline iteration names. Overrides 206 | # inlinevar-naming-style. If left empty, inline iteration names will be checked 207 | # with the set naming style. 208 | #inlinevar-rgx= 209 | 210 | # Naming style matching correct method names. 211 | method-naming-style=snake_case 212 | 213 | # Regular expression matching correct method names. Overrides method-naming- 214 | # style. If left empty, method names will be checked with the set naming style. 215 | #method-rgx= 216 | 217 | # Naming style matching correct module names. 218 | module-naming-style=snake_case 219 | 220 | # Regular expression matching correct module names. Overrides module-naming- 221 | # style. If left empty, module names will be checked with the set naming style. 222 | #module-rgx= 223 | 224 | # Colon-delimited sets of names that determine each other's naming style when 225 | # the name regexes allow several styles. 226 | name-group= 227 | 228 | # Regular expression which should only match function or class names that do 229 | # not require a docstring. 230 | no-docstring-rgx=^_ 231 | 232 | # List of decorators that produce properties, such as abc.abstractproperty. Add 233 | # to this list to register other decorators that produce valid properties. 234 | # These decorators are taken in consideration only for invalid-name. 235 | property-classes=abc.abstractproperty 236 | 237 | # Regular expression matching correct type alias names. If left empty, type 238 | # alias names will be checked with the set naming style. 239 | #typealias-rgx= 240 | 241 | # Regular expression matching correct type variable names. If left empty, type 242 | # variable names will be checked with the set naming style. 243 | #typevar-rgx= 244 | 245 | # Naming style matching correct variable names. 246 | variable-naming-style=snake_case 247 | 248 | # Regular expression matching correct variable names. Overrides variable- 249 | # naming-style. If left empty, variable names will be checked with the set 250 | # naming style. 251 | #variable-rgx= 252 | 253 | 254 | [CLASSES] 255 | 256 | # Warn about protected attribute access inside special methods 257 | check-protected-access-in-special-methods=no 258 | 259 | # List of method names used to declare (i.e. assign) instance attributes. 260 | defining-attr-methods=__init__, 261 | __new__, 262 | setUp, 263 | asyncSetUp, 264 | __post_init__ 265 | 266 | # List of member names, which should be excluded from the protected access 267 | # warning. 268 | exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit 269 | 270 | # List of valid names for the first argument in a class method. 271 | valid-classmethod-first-arg=cls 272 | 273 | # List of valid names for the first argument in a metaclass class method. 274 | valid-metaclass-classmethod-first-arg=mcs 275 | 276 | 277 | [DESIGN] 278 | 279 | # List of regular expressions of class ancestor names to ignore when counting 280 | # public methods (see R0903) 281 | exclude-too-few-public-methods= 282 | 283 | # List of qualified class names to ignore when counting class parents (see 284 | # R0901) 285 | ignored-parents= 286 | 287 | # Maximum number of arguments for function / method. 288 | max-args=5 289 | 290 | # Maximum number of attributes for a class (see R0902). 291 | max-attributes=7 292 | 293 | # Maximum number of boolean expressions in an if statement (see R0916). 294 | max-bool-expr=5 295 | 296 | # Maximum number of branch for function / method body. 297 | max-branches=12 298 | 299 | # Maximum number of locals for function / method body. 300 | max-locals=15 301 | 302 | # Maximum number of parents for a class (see R0901). 303 | max-parents=7 304 | 305 | # Maximum number of public methods for a class (see R0904). 306 | max-public-methods=20 307 | 308 | # Maximum number of return / yield for function / method body. 309 | max-returns=6 310 | 311 | # Maximum number of statements in function / method body. 312 | max-statements=50 313 | 314 | # Minimum number of public methods for a class (see R0903). 315 | min-public-methods=2 316 | 317 | 318 | [EXCEPTIONS] 319 | 320 | # Exceptions that will emit a warning when caught. 321 | overgeneral-exceptions=builtins.BaseException,builtins.Exception 322 | 323 | 324 | [FORMAT] 325 | 326 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 327 | expected-line-ending-format= 328 | 329 | # Regexp for a line that is allowed to be longer than the limit. 330 | ignore-long-lines=^\s*(# )??$ 331 | 332 | # Number of spaces of indent required inside a hanging or continued line. 333 | indent-after-paren=4 334 | 335 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 336 | # tab). 337 | indent-string=' ' 338 | 339 | # Maximum number of characters on a single line. 340 | max-line-length=100 341 | 342 | # Maximum number of lines in a module. 343 | max-module-lines=1000 344 | 345 | # Allow the body of a class to be on the same line as the declaration if body 346 | # contains single statement. 347 | single-line-class-stmt=no 348 | 349 | # Allow the body of an if to be on the same line as the test if there is no 350 | # else. 351 | single-line-if-stmt=no 352 | 353 | 354 | [IMPORTS] 355 | 356 | # List of modules that can be imported at any level, not just the top level 357 | # one. 358 | allow-any-import-level= 359 | 360 | # Allow explicit reexports by alias from a package __init__. 361 | allow-reexport-from-package=no 362 | 363 | # Allow wildcard imports from modules that define __all__. 364 | allow-wildcard-with-all=no 365 | 366 | # Deprecated modules which should not be used, separated by a comma. 367 | deprecated-modules= 368 | 369 | # Output a graph (.gv or any supported image format) of external dependencies 370 | # to the given file (report RP0402 must not be disabled). 371 | ext-import-graph= 372 | 373 | # Output a graph (.gv or any supported image format) of all (i.e. internal and 374 | # external) dependencies to the given file (report RP0402 must not be 375 | # disabled). 376 | import-graph= 377 | 378 | # Output a graph (.gv or any supported image format) of internal dependencies 379 | # to the given file (report RP0402 must not be disabled). 380 | int-import-graph= 381 | 382 | # Force import order to recognize a module as part of the standard 383 | # compatibility libraries. 384 | known-standard-library= 385 | 386 | # Force import order to recognize a module as part of a third party library. 387 | known-third-party=enchant 388 | 389 | # Couples of modules and preferred modules, separated by a comma. 390 | preferred-modules= 391 | 392 | 393 | [LOGGING] 394 | 395 | # The type of string formatting that logging methods do. `old` means using % 396 | # formatting, `new` is for `{}` formatting. 397 | logging-format-style=old 398 | 399 | # Logging modules to check that the string format arguments are in logging 400 | # function parameter format. 401 | logging-modules=logging 402 | 403 | 404 | [MESSAGES CONTROL] 405 | 406 | # Only show warnings with the listed confidence levels. Leave empty to show 407 | # all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, 408 | # UNDEFINED. 409 | confidence=HIGH, 410 | CONTROL_FLOW, 411 | INFERENCE, 412 | INFERENCE_FAILURE, 413 | UNDEFINED 414 | 415 | # Disable the message, report, category or checker with the given id(s). You 416 | # can either give multiple identifiers separated by comma (,) or put this 417 | # option multiple times (only on the command line, not in the configuration 418 | # file where it should appear only once). You can also use "--disable=all" to 419 | # disable everything first and then re-enable specific checks. For example, if 420 | # you want to run only the similarities checker, you can use "--disable=all 421 | # --enable=similarities". If you want to run only the classes checker, but have 422 | # no Warning level messages displayed, use "--disable=all --enable=classes 423 | # --disable=W". 424 | disable=raw-checker-failed, 425 | bad-inline-option, 426 | locally-disabled, 427 | file-ignored, 428 | suppressed-message, 429 | useless-suppression, 430 | deprecated-pragma, 431 | use-symbolic-message-instead, 432 | use-implicit-booleaness-not-comparison-to-string, 433 | use-implicit-booleaness-not-comparison-to-zero, 434 | C0301,C0114,C0116,W0601,W0105,W0621,C0103,R0801 435 | 436 | # Enable the message, report, category or checker with the given id(s). You can 437 | # either give multiple identifier separated by comma (,) or put this option 438 | # multiple time (only on the command line, not in the configuration file where 439 | # it should appear only once). See also the "--disable" option for examples. 440 | enable= 441 | 442 | 443 | [METHOD_ARGS] 444 | 445 | # List of qualified names (i.e., library.method) which require a timeout 446 | # parameter e.g. 'requests.api.get,requests.api.post' 447 | timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request 448 | 449 | 450 | [MISCELLANEOUS] 451 | 452 | # List of note tags to take in consideration, separated by a comma. 453 | notes=FIXME, 454 | XXX, 455 | TODO 456 | 457 | # Regular expression of note tags to take in consideration. 458 | notes-rgx= 459 | 460 | 461 | [REFACTORING] 462 | 463 | # Maximum number of nested blocks for function / method body 464 | max-nested-blocks=5 465 | 466 | # Complete name of functions that never returns. When checking for 467 | # inconsistent-return-statements if a never returning function is called then 468 | # it will be considered as an explicit return statement and no message will be 469 | # printed. 470 | never-returning-functions=sys.exit,argparse.parse_error 471 | 472 | 473 | [REPORTS] 474 | 475 | # Python expression which should return a score less than or equal to 10. You 476 | # have access to the variables 'fatal', 'error', 'warning', 'refactor', 477 | # 'convention', and 'info' which contain the number of messages in each 478 | # category, as well as 'statement' which is the total number of statements 479 | # analyzed. This score is used by the global evaluation report (RP0004). 480 | evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) 481 | 482 | # Template used to display messages. This is a python new-style format string 483 | # used to format the message information. See doc for all details. 484 | msg-template= 485 | 486 | # Set the output format. Available formats are: text, parseable, colorized, 487 | # json2 (improved json format), json (old json format) and msvs (visual 488 | # studio). You can also give a reporter class, e.g. 489 | # mypackage.mymodule.MyReporterClass. 490 | #output-format= 491 | 492 | # Tells whether to display a full report or only the messages. 493 | reports=no 494 | 495 | # Activate the evaluation score. 496 | score=yes 497 | 498 | 499 | [SIMILARITIES] 500 | 501 | # Comments are removed from the similarity computation 502 | ignore-comments=yes 503 | 504 | # Docstrings are removed from the similarity computation 505 | ignore-docstrings=yes 506 | 507 | # Imports are removed from the similarity computation 508 | ignore-imports=yes 509 | 510 | # Signatures are removed from the similarity computation 511 | ignore-signatures=yes 512 | 513 | # Minimum lines number of a similarity. 514 | min-similarity-lines=4 515 | 516 | 517 | [SPELLING] 518 | 519 | # Limits count of emitted suggestions for spelling mistakes. 520 | max-spelling-suggestions=4 521 | 522 | # Spelling dictionary name. No available dictionaries : You need to install 523 | # both the python package and the system dependency for enchant to work. 524 | spelling-dict= 525 | 526 | # List of comma separated words that should be considered directives if they 527 | # appear at the beginning of a comment and should not be checked. 528 | spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: 529 | 530 | # List of comma separated words that should not be checked. 531 | spelling-ignore-words= 532 | 533 | # A path to a file that contains the private dictionary; one word per line. 534 | spelling-private-dict-file= 535 | 536 | # Tells whether to store unknown words to the private dictionary (see the 537 | # --spelling-private-dict-file option) instead of raising a message. 538 | spelling-store-unknown-words=no 539 | 540 | 541 | [STRING] 542 | 543 | # This flag controls whether inconsistent-quotes generates a warning when the 544 | # character used as a quote delimiter is used inconsistently within a module. 545 | check-quote-consistency=no 546 | 547 | # This flag controls whether the implicit-str-concat should generate a warning 548 | # on implicit string concatenation in sequences defined over several lines. 549 | check-str-concat-over-line-jumps=no 550 | 551 | 552 | [TYPECHECK] 553 | 554 | # List of decorators that produce context managers, such as 555 | # contextlib.contextmanager. Add to this list to register other decorators that 556 | # produce valid context managers. 557 | contextmanager-decorators=contextlib.contextmanager 558 | 559 | # List of members which are set dynamically and missed by pylint inference 560 | # system, and so shouldn't trigger E1101 when accessed. Python regular 561 | # expressions are accepted. 562 | generated-members= 563 | 564 | # Tells whether to warn about missing members when the owner of the attribute 565 | # is inferred to be None. 566 | ignore-none=yes 567 | 568 | # This flag controls whether pylint should warn about no-member and similar 569 | # checks whenever an opaque object is returned when inferring. The inference 570 | # can return multiple potential results while evaluating a Python object, but 571 | # some branches might not be evaluated, which results in partial inference. In 572 | # that case, it might be useful to still emit no-member and other checks for 573 | # the rest of the inferred objects. 574 | ignore-on-opaque-inference=yes 575 | 576 | # List of symbolic message names to ignore for Mixin members. 577 | ignored-checks-for-mixins=no-member, 578 | not-async-context-manager, 579 | not-context-manager, 580 | attribute-defined-outside-init 581 | 582 | # List of class names for which member attributes should not be checked (useful 583 | # for classes with dynamically set attributes). This supports the use of 584 | # qualified names. 585 | ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace 586 | 587 | # Show a hint with possible names when a member name was not found. The aspect 588 | # of finding the hint is based on edit distance. 589 | missing-member-hint=yes 590 | 591 | # The minimum edit distance a name should have in order to be considered a 592 | # similar match for a missing member name. 593 | missing-member-hint-distance=1 594 | 595 | # The total number of similar names that should be taken in consideration when 596 | # showing a hint for a missing member. 597 | missing-member-max-choices=1 598 | 599 | # Regex pattern to define which classes are considered mixins. 600 | mixin-class-rgx=.*[Mm]ixin 601 | 602 | # List of decorators that change the signature of a decorated function. 603 | signature-mutators= 604 | 605 | 606 | [VARIABLES] 607 | 608 | # List of additional names supposed to be defined in builtins. Remember that 609 | # you should avoid defining new builtins when possible. 610 | additional-builtins= 611 | 612 | # Tells whether unused global variables should be treated as a violation. 613 | allow-global-unused-variables=yes 614 | 615 | # List of names allowed to shadow builtins 616 | allowed-redefined-builtins= 617 | 618 | # List of strings which can identify a callback function by name. A callback 619 | # name must start or end with one of those strings. 620 | callbacks=cb_, 621 | _cb 622 | 623 | # A regular expression matching the name of dummy variables (i.e. expected to 624 | # not be used). 625 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ 626 | 627 | # Argument names that match this expression will be ignored. 628 | ignored-argument-names=_.*|^ignored_|^unused_ 629 | 630 | # Tells whether we should check for unused import in __init__ files. 631 | init-import=no 632 | 633 | # List of qualified module names which can have objects that can redefine 634 | # builtins. 635 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io 636 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.flake8Args": [ 3 | "--max-line-length=160", 4 | "--ignore=E402,F841,F401,E302,E305", 5 | ], 6 | "editor.defaultFormatter": "ms-python.black-formatter", 7 | "editor.formatOnSave": true, 8 | "python.createEnvironment.trigger": "off" 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Local LLM Crash Course - Build Your Own GPT in 2 hours! 2 | This is the courseware and Codespace for the [The Local LLM Crash Course - Build Your Own GPT in 2 hours](https://www.udemy.com/course/the-local-llm-crash-course-build-a-hugging-face-ai-chatbot/?referralCode=EAD6017AA0001257DD9A)! Have fun with the course and use the Q&A if you run into any issues! 3 | 4 | # Course Resources 5 | 6 | ### Codespaces Pricing and Free Credits 7 | https://docs.github.com/en/billing/managing-billing-for-github-codespaces/about-billing-for-github-codespaces 8 | 9 | ### Hugging Face 10 | * The Orca Model's Model Card: https://huggingface.co/zoltanctoth/orca_mini_3B-GGUF 11 | 12 | ### Installing `ctransformers` and Chainlit 13 | Just for reference. Remember, you don't need to do this as it's pre-installed in your Codespace. 14 | ``` 15 | pip install ctransformers chainlit 16 | ``` 17 | 18 | ## The Open Orca Dataset 19 | The dataset on Hugging Face: https://huggingface.co/datasets/Open-Orca/OpenOrca 20 | 21 | ## Chainlit and Streamlit 22 | * Chainlit: https://docs.chainlit.io/get-started/overview 23 | * Streamlit: https://streamlit.io/ 24 | 25 | ## LangChain 26 | 27 | ### Installation 28 | ``` 29 | pip install langchain langchain-community 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==23.2.1 2 | aiohttp==3.9.3 3 | aiosignal==1.3.1 4 | annotated-types==0.6.0 5 | anyio==3.7.1 6 | asyncer==0.0.2 7 | attrs==23.2.0 8 | backoff==2.2.1 9 | bidict==0.22.1 10 | certifi==2024.2.2 11 | chainlit==1.0.200 12 | charset-normalizer==3.3.2 13 | click==8.1.7 14 | ctransformers==0.2.27 15 | dataclasses-json==0.5.14 16 | Deprecated==1.2.14 17 | fastapi==0.108.0 18 | fastapi-socketio==0.0.10 19 | filelock==3.13.1 20 | filetype==1.2.0 21 | frozenlist==1.4.1 22 | fsspec==2024.2.0 23 | googleapis-common-protos==1.62.0 24 | greenlet==3.0.3 25 | grpcio==1.60.1 26 | h11==0.14.0 27 | httpcore==0.17.3 28 | httpx==0.24.1 29 | huggingface-hub==0.20.3 30 | idna==3.6 31 | importlib-metadata==6.11.0 32 | isort==5.13.2 33 | jsonpatch==1.33 34 | jsonpointer==2.4 35 | langchain==0.1.16 36 | langchain-community==0.0.34 37 | langchain-core==0.1.45 38 | langchain-text-splitters==0.0.1 39 | langsmith==0.1.49 40 | Lazify==0.4.0 41 | literalai==0.0.103 42 | llamacpp==0.1.14 43 | marshmallow==3.20.2 44 | multidict==6.0.5 45 | mypy-extensions==1.0.0 46 | nest-asyncio==1.6.0 47 | numpy==1.26.4 48 | opentelemetry-api==1.22.0 49 | opentelemetry-exporter-otlp==1.22.0 50 | opentelemetry-exporter-otlp-proto-common==1.22.0 51 | opentelemetry-exporter-otlp-proto-grpc==1.22.0 52 | opentelemetry-exporter-otlp-proto-http==1.22.0 53 | opentelemetry-instrumentation==0.43b0 54 | opentelemetry-proto==1.22.0 55 | opentelemetry-sdk==1.22.0 56 | opentelemetry-semantic-conventions==0.43b0 57 | orjson==3.10.1 58 | packaging==23.2 59 | protobuf==4.25.2 60 | py-cpuinfo==9.0.0 61 | pydantic==2.6.1 62 | pydantic_core==2.16.2 63 | PyJWT==2.8.0 64 | python-dotenv==1.0.1 65 | python-engineio==4.9.0 66 | python-graphql-client==0.4.3 67 | python-multipart==0.0.6 68 | python-socketio==5.11.1 69 | PyYAML==6.0.1 70 | requests==2.31.0 71 | simple-websocket==1.0.0 72 | sniffio==1.3.0 73 | SQLAlchemy==2.0.29 74 | starlette==0.32.0.post1 75 | syncer==2.0.3 76 | tenacity==8.2.3 77 | tomli==2.0.1 78 | tqdm==4.66.1 79 | typing-inspect==0.9.0 80 | typing_extensions==4.9.0 81 | uptrace==1.22.0 82 | urllib3==2.2.0 83 | uvicorn==0.25.0 84 | watchfiles==0.20.0 85 | websockets==12.0 86 | wrapt==1.16.0 87 | wsproto==1.2.0 88 | yarl==1.9.4 89 | zipp==3.17.0 90 | -------------------------------------------------------------------------------- /solutions/chainlit_conversational_memory.py: -------------------------------------------------------------------------------- 1 | import chainlit as cl 2 | from ctransformers import AutoModelForCausalLM 3 | 4 | 5 | def get_prompt(instruction: str, history: list[str]) -> str: 6 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 7 | prompt = f"### System:\n{system}\n\n### User:\n" 8 | if len(history) > 0: 9 | prompt += f"This is the conversation history: {''.join(history)}. Now answer the question: " 10 | prompt += f"{instruction}\n\n### Response:\n" 11 | print(f"Prompt created: {prompt}") 12 | return prompt 13 | 14 | 15 | @cl.on_message 16 | async def on_message(message: cl.Message): 17 | message_history = cl.user_session.get("message_history") 18 | msg = cl.Message(content="") 19 | await msg.send() 20 | 21 | prompt = get_prompt(message.content, message_history) 22 | answer = "" 23 | for word in llm(prompt, stream=True): 24 | await msg.stream_token(word) 25 | answer += word 26 | message_history.append(answer) 27 | await msg.update() 28 | 29 | 30 | @cl.on_chat_start 31 | async def on_chat_start(): 32 | global llm 33 | llm = AutoModelForCausalLM.from_pretrained( 34 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 35 | ) 36 | 37 | cl.user_session.set("message_history", []) 38 | 39 | await cl.Message("Model initialized. How can I help you?").send() 40 | -------------------------------------------------------------------------------- /solutions/chainlit_hello_world.py: -------------------------------------------------------------------------------- 1 | import chainlit as cl 2 | from ctransformers import AutoModelForCausalLM 3 | 4 | llm = AutoModelForCausalLM.from_pretrained( 5 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 6 | ) 7 | 8 | 9 | def get_prompt(instruction: str, history: list[str] | None = None) -> str: 10 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 11 | prompt = f"### System:\n{system}\n\n### User:\n" 12 | if history is not None: 13 | prompt += f"This is the conversation history: {''.join(history)}. Now answer the question: " 14 | prompt += f"{instruction}\n\n### Response:\n" 15 | print(f"Prompt created: {prompt}") 16 | return prompt 17 | 18 | 19 | @cl.on_message 20 | async def on_message(message: cl.Message): 21 | response = f"Hello World! You just sent: {message.content}!" 22 | await cl.Message(response).send() 23 | 24 | 25 | """ 26 | history = [] 27 | 28 | question = "Which city is the capital of India?" 29 | prompt = get_prompt(question) 30 | answer = "" 31 | for word in llm(prompt, stream=True): 32 | print(word, end="", flush=True) 33 | answer += word 34 | print() 35 | history.append(answer) 36 | 37 | question = "And of the United States?" 38 | prompt = get_prompt(question, history) 39 | for word in llm(prompt, stream=True): 40 | print(word, end="", flush=True) 41 | print() 42 | """ 43 | -------------------------------------------------------------------------------- /solutions/chainlit_stream.py: -------------------------------------------------------------------------------- 1 | import chainlit as cl 2 | from ctransformers import AutoModelForCausalLM 3 | 4 | 5 | def get_prompt(instruction: str, history: list[str] | None = None) -> str: 6 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 7 | prompt = f"### System:\n{system}\n\n### User:\n" 8 | if history is not None: 9 | prompt += f"This is the conversation history: {''.join(history)}. Now answer the question: " 10 | prompt += f"{instruction}\n\n### Response:\n" 11 | print(f"Prompt created: {prompt}") 12 | return prompt 13 | 14 | 15 | @cl.on_message 16 | async def on_message(message: cl.Message): 17 | msg = cl.Message(content="") 18 | await msg.send() 19 | 20 | prompt = get_prompt(message.content) 21 | for word in llm(prompt, stream=True): 22 | await msg.stream_token(word) 23 | await msg.update() 24 | 25 | 26 | @cl.on_chat_start 27 | async def on_chat_start(): 28 | global llm 29 | 30 | llm = AutoModelForCausalLM.from_pretrained( 31 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 32 | ) 33 | await cl.Message("Model initialized. How can I help you?").send() 34 | -------------------------------------------------------------------------------- /solutions/chainlit_use_model.py: -------------------------------------------------------------------------------- 1 | import chainlit as cl 2 | from ctransformers import AutoModelForCausalLM 3 | 4 | 5 | def get_prompt(instruction: str, history: list[str] | None = None) -> str: 6 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 7 | prompt = f"### System:\n{system}\n\n### User:\n" 8 | if history is not None: 9 | prompt += f"This is the conversation history: {''.join(history)}. Now answer the question: " 10 | prompt += f"{instruction}\n\n### Response:\n" 11 | return prompt 12 | 13 | 14 | @cl.on_message 15 | async def on_message(message: cl.Message): 16 | prompt = get_prompt(message.content) 17 | response = llm(prompt) 18 | await cl.Message(response).send() 19 | 20 | 21 | @cl.on_chat_start 22 | async def on_chat_start(): 23 | global llm 24 | 25 | llm = AutoModelForCausalLM.from_pretrained( 26 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 27 | ) 28 | await cl.Message("Model initialized. How can I help you?").send() 29 | 30 | 31 | """ 32 | history = [] 33 | 34 | question = "WWhich city is the capital of India?" 35 | prompt = get_prompt(question) 36 | answer = "" 37 | for word in llm(prompt, stream=True): 38 | print(word, end="", flush=True) 39 | answer += word 40 | print() 41 | history.append(answer) 42 | 43 | question = "And of the United States?" 44 | prompt = get_prompt(question, history) 45 | for word in llm(prompt, stream=True): 46 | print(word, end="", flush=True) 47 | print() 48 | """ 49 | -------------------------------------------------------------------------------- /solutions/chat_prompt.py: -------------------------------------------------------------------------------- 1 | from ctransformers import AutoModelForCausalLM 2 | 3 | llm = AutoModelForCausalLM.from_pretrained( 4 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 5 | ) 6 | 7 | 8 | def get_prompt(instruction: str) -> str: 9 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 10 | prompt = f"### System:\n{system}\n\n### User:\n{instruction}\n\n### Response:\n" 11 | print(f"Prompt created: {prompt}") 12 | return prompt 13 | 14 | 15 | question = "Which city is the capital of India?" 16 | prompt = get_prompt(question) 17 | for word in llm(prompt, stream=True): 18 | print(word, end="", flush=True) 19 | print() 20 | -------------------------------------------------------------------------------- /solutions/conversational_memory.py: -------------------------------------------------------------------------------- 1 | from ctransformers import AutoModelForCausalLM 2 | 3 | llm = AutoModelForCausalLM.from_pretrained( 4 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 5 | ) 6 | 7 | 8 | def get_prompt(instruction: str, history: list[str] | None = None) -> str: 9 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 10 | prompt = f"### System:\n{system}\n\n### User:\n" 11 | if history is not None: 12 | prompt += f"This is the conversation history: {''.join(history)}. Now answer the question: " 13 | prompt += f"{instruction}\n\n### Response:\n" 14 | print(f"Prompt created: {prompt}") 15 | return prompt 16 | 17 | 18 | history = [] 19 | 20 | question = "Which city is the capital of India?" 21 | prompt = get_prompt(question) 22 | answer = "" 23 | for word in llm(prompt, stream=True): 24 | print(word, end="", flush=True) 25 | answer += word 26 | print() 27 | history.append(answer) 28 | 29 | question = "And of the United States?" 30 | prompt = get_prompt(question, history) 31 | for word in llm(prompt, stream=True): 32 | print(word, end="", flush=True) 33 | print() 34 | -------------------------------------------------------------------------------- /solutions/exercises/basic_prompting.py: -------------------------------------------------------------------------------- 1 | from ctransformers import AutoModelForCausalLM 2 | 3 | llm = AutoModelForCausalLM.from_pretrained( 4 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 5 | ) 6 | 7 | # # Probably not that good of a prompt - too vague 8 | # prompt = "The capital of India is" 9 | # print(prompt + llm(prompt)) 10 | # print() 11 | # print() 12 | 13 | # # A much better prompt, but it might give a long answer 14 | # prompt = "The name of the capital city of India is" 15 | # print(prompt + llm(prompt)) 16 | # print() 17 | # print() 18 | 19 | # Good prompts are very specific 20 | prompt = "What is the name of the capital city of India, she asked. Please only respond with the city name and then stop talking. He answered: " 21 | print(prompt + llm(prompt)) 22 | -------------------------------------------------------------------------------- /solutions/exercises/change_chatbots.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import chainlit as cl 4 | from ctransformers import AutoModelForCausalLM 5 | 6 | 7 | def get_prompt_orca(instruction: str, history: List[str] = None) -> str: 8 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 9 | prompt = f"### System:\n{system}\n\n### User:\n" 10 | if history is not None: 11 | prompt += f"This is the conversation history: {''.join(history)}. Now answer the question: " 12 | prompt += f"{instruction}\n\n### Response:\n" 13 | print(f"Prompt created: {prompt}") 14 | return prompt 15 | 16 | 17 | def get_prompt_llama2(instruction: str, history: List[str] = None) -> str: 18 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 19 | prompt = f"[INST] <>\n{system}\n<>\n\n" 20 | if history is not None: 21 | prompt += f"This is the conversation history: {''.join(history)}. Now answer the question: " 22 | prompt += f"{instruction} [/INST]" 23 | print(f"Prompt created: {prompt}") 24 | return prompt 25 | 26 | 27 | def select_llm(llm_name: str): 28 | global llm, get_prompt 29 | if llm_name == "llama2": 30 | llm = AutoModelForCausalLM.from_pretrained( 31 | "TheBloke/Llama-2-7b-Chat-GGUF", model_file="llama-2-7b-chat.Q5_K_M.gguf" 32 | ) 33 | get_prompt = get_prompt_llama2 34 | return "Model changed to Llama" 35 | elif llm_name == "orca": 36 | llm = AutoModelForCausalLM.from_pretrained( 37 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 38 | ) 39 | get_prompt = get_prompt_orca 40 | return "Model changed to Orca" 41 | else: 42 | return "Model not found, keeping old model" 43 | 44 | 45 | @cl.on_message 46 | async def on_message(message: cl.Message): 47 | if message.content.lower() in ["use llama2", "use orca"]: 48 | model_name = message.content.lower().split()[1] 49 | response = select_llm(model_name) 50 | await cl.Message(response).send() 51 | return 52 | if message.content.lower() == "forget everything": 53 | cl.user_session.set("message_history", []) 54 | await cl.Message("Uh oh, I've just forgotten our conversation history").send() 55 | return 56 | 57 | message_history = cl.user_session.get("message_history") 58 | msg = cl.Message(content="") 59 | await msg.send() 60 | 61 | prompt = get_prompt(message.content, message_history) 62 | answer = "" 63 | for word in llm(prompt, stream=True): 64 | await msg.stream_token(word) 65 | answer += word 66 | message_history.append(answer) 67 | await msg.update() 68 | 69 | 70 | @cl.on_chat_start 71 | async def on_chat_start(): 72 | await cl.Message("Loading model Orca...").send() 73 | select_llm("orca") 74 | cl.user_session.set("message_history", []) 75 | 76 | await cl.Message("Model initialized. How can I help you?").send() 77 | -------------------------------------------------------------------------------- /solutions/exercises/llama2.py: -------------------------------------------------------------------------------- 1 | from ctransformers import AutoModelForCausalLM 2 | 3 | llm = AutoModelForCausalLM.from_pretrained( 4 | "TheBloke/Llama-2-7b-Chat-GGUF", model_file="llama-2-7b-chat.Q5_K_M.gguf" 5 | ) 6 | 7 | 8 | def get_prompt(instruction: str) -> str: 9 | system = "You are an AI assistant that gives helpful answers. You answer the question in a short and concise way." 10 | prompt = f"[INST] <>\n{system}\n<>\n\n{instruction} [/INST]" 11 | print(f"Prompt created: {prompt}") 12 | return prompt 13 | 14 | 15 | question = "Which city is the capital of India?" 16 | prompt = get_prompt(question) 17 | for word in llm(prompt, stream=True): 18 | print(word, end="", flush=True) 19 | print() 20 | -------------------------------------------------------------------------------- /solutions/langchain/chainlit_with_langchain.py: -------------------------------------------------------------------------------- 1 | import chainlit as cl 2 | from langchain.callbacks.base import BaseCallbackHandler 3 | from langchain.chains import LLMChain 4 | from langchain.memory import ConversationBufferMemory 5 | from langchain_community.llms import CTransformers 6 | from langchain_core.prompts import PromptTemplate 7 | 8 | 9 | class StreamHandler(BaseCallbackHandler): 10 | def __init__(self): 11 | self.msg = cl.Message(content="") 12 | 13 | async def on_llm_new_token(self, token: str, **kwargs): 14 | await self.msg.stream_token(token) 15 | 16 | async def on_llm_end(self, response: str, **kwargs): 17 | await self.msg.send() 18 | self.msg = cl.Message(content="") 19 | 20 | 21 | # Load quantized Llama 2 22 | llm = CTransformers( 23 | model="TheBloke/Llama-2-7B-Chat-GGUF", 24 | model_file="llama-2-7b-chat.Q2_K.gguf", 25 | model_type="llama2", 26 | max_new_tokens=20, 27 | ) 28 | 29 | template = """ 30 | [INST] <> 31 | You are a helpful, respectful and honest assistant. 32 | Always provide a concise answer and use the following Context: 33 | {context} 34 | <> 35 | User: 36 | {instruction}[/INST]""" 37 | 38 | prompt = PromptTemplate(template=template, input_variables=["context", "instruction"]) 39 | 40 | 41 | @cl.on_chat_start 42 | def on_chat_start(): 43 | memory = ConversationBufferMemory(memory_key="context") 44 | llm_chain = LLMChain(prompt=prompt, llm=llm, verbose=False, memory=memory) 45 | cl.user_session.set("llm_chain", llm_chain) 46 | 47 | 48 | @cl.on_message 49 | async def on_message(message: cl.Message): 50 | llm_chain = cl.user_session.get("llm_chain") 51 | 52 | await llm_chain.ainvoke( 53 | message.content, 54 | config={"callbacks": [cl.AsyncLangchainCallbackHandler(), StreamHandler()]}, 55 | ) 56 | -------------------------------------------------------------------------------- /solutions/langchain/langchain_demo.py: -------------------------------------------------------------------------------- 1 | from langchain.chains import LLMChain 2 | from langchain.memory import ConversationBufferMemory 3 | from langchain_community.llms import CTransformers 4 | from langchain_core.prompts import PromptTemplate 5 | 6 | llm = CTransformers( 7 | model="zoltanctoth/orca_mini_3B-GGUF", 8 | model_file="orca-mini-3b.q4_0.gguf", 9 | model_type="llama2", 10 | max_new_tokens=20, 11 | ) 12 | 13 | prompt_template = """### System:\nYou are an AI assistant that gives helpful answers. 14 | You answer the question in a short and concise way. Take this context into account when answering the question: {context}\n 15 | \n\n### User:\n{instruction}\n\n### Response:\n""" 16 | 17 | prompt = PromptTemplate(template=prompt_template, input_variables=["instruction"]) 18 | memory = ConversationBufferMemory(memory_key="context") 19 | 20 | chain = LLMChain(llm=llm, prompt=prompt, verbose=True, memory=memory) 21 | 22 | print(chain.invoke({"instruction": "Which city is the capital of India?"})) 23 | print( 24 | chain.invoke({"instruction": "Which city is has the same functionality in the US?"}) 25 | ) 26 | -------------------------------------------------------------------------------- /solutions/simple_completion.py: -------------------------------------------------------------------------------- 1 | from ctransformers import AutoModelForCausalLM 2 | 3 | llm = AutoModelForCausalLM.from_pretrained( 4 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 5 | ) 6 | 7 | prompt = "Hi! What is your dog's" 8 | 9 | print(llm(prompt)) 10 | -------------------------------------------------------------------------------- /solutions/stream_answer.py: -------------------------------------------------------------------------------- 1 | from ctransformers import AutoModelForCausalLM 2 | 3 | llm = AutoModelForCausalLM.from_pretrained( 4 | "zoltanctoth/orca_mini_3B-GGUF", model_file="orca-mini-3b.q4_0.gguf" 5 | ) 6 | 7 | prompt = "The name of the capital of India is" 8 | 9 | for word in llm(prompt, stream=True): 10 | print(word, end="", flush=True) 11 | print() 12 | --------------------------------------------------------------------------------