mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2026-07-17 10:58:08 +00:00
Compare commits
377 Commits
python-v2.
...
v3.0.0-rc3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
720ea5a147 | ||
|
|
a191844a3f | ||
|
|
22396a6fa1 | ||
|
|
f2cad6abaa | ||
|
|
d893a6e5d6 | ||
|
|
8fe73832a6 | ||
|
|
23e8b187a4 | ||
|
|
dc6d01a0bb | ||
|
|
2c8d634b5b | ||
|
|
426aa5eb47 | ||
|
|
81bbeef5b3 | ||
|
|
1712830228 | ||
|
|
f6f265f968 | ||
|
|
6f52f602ef | ||
|
|
d92252cab1 | ||
|
|
6506ba161b | ||
|
|
bed92046d0 | ||
|
|
a1ec6f2150 | ||
|
|
8d6e11fcad | ||
|
|
fc5dc9dd1a | ||
|
|
d4494602e2 | ||
|
|
23e8f43c5a | ||
|
|
31fa575c35 | ||
|
|
6d593d6ea1 | ||
|
|
01870b4a46 | ||
|
|
53fc2d56f6 | ||
|
|
e5d9936d04 | ||
|
|
11823022e2 | ||
|
|
da1823ed7a | ||
|
|
3a61070f82 | ||
|
|
c87ccf4124 | ||
|
|
88f5face2b | ||
|
|
f8a935d8a6 | ||
|
|
029bd318e9 | ||
|
|
d5968f4ab2 | ||
|
|
30febbe3d2 | ||
|
|
88d85be0f9 | ||
|
|
bbf0c2f246 | ||
|
|
9363ffb958 | ||
|
|
8724572d61 | ||
|
|
1a00882276 | ||
|
|
9273b49b62 | ||
|
|
1272b694ae | ||
|
|
986d9d9bb8 | ||
|
|
b999d07d93 | ||
|
|
beaede03fb | ||
|
|
41c9013fa4 | ||
|
|
69f766cbbb | ||
|
|
d43bfa0a53 | ||
|
|
d3d777bc51 | ||
|
|
55d709862f | ||
|
|
a602f7fde7 | ||
|
|
f001897a1a | ||
|
|
636307160e | ||
|
|
8ba7ef4832 | ||
|
|
4e89a9c44f | ||
|
|
8a70f770a2 | ||
|
|
e94177ee9a | ||
|
|
f047f383d0 | ||
|
|
f1b4092ca6 | ||
|
|
0b63ad5eff | ||
|
|
09dd3dc318 | ||
|
|
c779d8a32d | ||
|
|
e021fe130f | ||
|
|
2025d2d15b | ||
|
|
a92d266cea | ||
|
|
d2a99d9bc6 | ||
|
|
a618ca5699 | ||
|
|
fbbf810020 | ||
|
|
7e1e00f331 | ||
|
|
7f1c3d4275 | ||
|
|
9f9d8e636f | ||
|
|
6d8888b267 | ||
|
|
61cefcfd8a | ||
|
|
1427ef7195 | ||
|
|
69720fedaa | ||
|
|
86560f3952 | ||
|
|
5fb9d17c00 | ||
|
|
f26e8d0d87 | ||
|
|
d54e644d05 | ||
|
|
cef74c2be2 | ||
|
|
26eaf598b4 | ||
|
|
d7c47fb6f7 | ||
|
|
577ebd4826 | ||
|
|
855fd22417 | ||
|
|
adaecb7a72 | ||
|
|
27c561aeb7 | ||
|
|
1b87aa2dbc | ||
|
|
6f38fde80b | ||
|
|
a14193623a | ||
|
|
4f3c9bbe3e | ||
|
|
c622921894 | ||
|
|
4193533154 | ||
|
|
baf1dfc5d7 | ||
|
|
0b78b79b1c | ||
|
|
aac00d019a | ||
|
|
ba53ab5da0 | ||
|
|
271d752701 | ||
|
|
be93ee75de | ||
|
|
4ebb0c6ac0 | ||
|
|
2c4c101b2e | ||
|
|
38cc778a0c | ||
|
|
94a9943782 | ||
|
|
e27653219b | ||
|
|
ac498f79ac | ||
|
|
2273cf145e | ||
|
|
3f8257c563 | ||
|
|
46818e466e | ||
|
|
459289b94c | ||
|
|
1e4c62027b | ||
|
|
1b84a48c47 | ||
|
|
790320e170 | ||
|
|
aad502f336 | ||
|
|
77d5adfb02 | ||
|
|
9c23d44ad3 | ||
|
|
4f6c43aec9 | ||
|
|
4852d39699 | ||
|
|
3313c7de0d | ||
|
|
dddaf49428 | ||
|
|
55f3b056b7 | ||
|
|
6c8a44f6c4 | ||
|
|
b743c588e8 | ||
|
|
67843edc7c | ||
|
|
83ada4ca89 | ||
|
|
8d09b2c264 | ||
|
|
446668674e | ||
|
|
adea3811ea | ||
|
|
71db8bdc80 | ||
|
|
71d7f34d1a | ||
|
|
b4bcc5b37c | ||
|
|
f571e7e450 | ||
|
|
0455b80b7f | ||
|
|
271e6a529c | ||
|
|
5732928b93 | ||
|
|
6a22b81f44 | ||
|
|
f50bf856b3 | ||
|
|
df79e45195 | ||
|
|
0e9e5237c5 | ||
|
|
a1bb6084ed | ||
|
|
f30151491d | ||
|
|
c6bd8577a9 | ||
|
|
699410014a | ||
|
|
6c2542e540 | ||
|
|
2bb86f35ee | ||
|
|
255568fb9a | ||
|
|
53f109f519 | ||
|
|
667f29c2a1 | ||
|
|
97de30edd1 | ||
|
|
2c0a660e6e | ||
|
|
406e88b59a | ||
|
|
171f4e488e | ||
|
|
6adaa672b4 | ||
|
|
b68ebb7c15 | ||
|
|
0072860d24 | ||
|
|
ef9717dbe9 | ||
|
|
afbb30a523 | ||
|
|
11db71e0a7 | ||
|
|
5ed9aea410 | ||
|
|
e2f64f89c9 | ||
|
|
0daf37ab8a | ||
|
|
a6a3e0048a | ||
|
|
f36a2874eb | ||
|
|
0cc5a80656 | ||
|
|
c951a5b1d3 | ||
|
|
026ee4e46b | ||
|
|
61d6765361 | ||
|
|
59f99b7f21 | ||
|
|
fe653d1489 | ||
|
|
5c248dbec9 | ||
|
|
6ed3d01f17 | ||
|
|
6c3903a303 | ||
|
|
8ee68d1b6f | ||
|
|
4251b7beaa | ||
|
|
fc169e739a | ||
|
|
028a8db6ba | ||
|
|
26cedb83b0 | ||
|
|
9c755d25c4 | ||
|
|
099459c8b9 | ||
|
|
8474d76fec | ||
|
|
08b5dc8598 | ||
|
|
17dee02287 | ||
|
|
44717682a7 | ||
|
|
a0bd96f75d | ||
|
|
d8c842263f | ||
|
|
5a874be7c1 | ||
|
|
402f515a5d | ||
|
|
2a91ffd73f | ||
|
|
0fc071d228 | ||
|
|
c19b763e03 | ||
|
|
be6d3bf9dc | ||
|
|
83c76be68a | ||
|
|
f2b4809b72 | ||
|
|
9fafca5c94 | ||
|
|
7d1e30766f | ||
|
|
5ddcf61ae4 | ||
|
|
713afb7070 | ||
|
|
4a16a920a3 | ||
|
|
a59645c839 | ||
|
|
f500bcf6e5 | ||
|
|
fc1a281381 | ||
|
|
007d469034 | ||
|
|
7a23b23728 | ||
|
|
f720261d46 | ||
|
|
17a2cdbe35 | ||
|
|
72474a2efa | ||
|
|
f8b1069a1c | ||
|
|
a153cc5b25 | ||
|
|
ef518fae3e | ||
|
|
e7f2ff189f | ||
|
|
88e330ef0e | ||
|
|
fc6c5ea0c7 | ||
|
|
c1dcb3f5b8 | ||
|
|
a010a8a7ca | ||
|
|
ef0a67eb94 | ||
|
|
67bbce43ab | ||
|
|
4fc4d94be4 | ||
|
|
b8f5c74f40 | ||
|
|
c13202a6f5 | ||
|
|
4a8c6d7f9c | ||
|
|
32837fb3a0 | ||
|
|
7810b757c9 | ||
|
|
896fc6fbb7 | ||
|
|
fa0a2129dc | ||
|
|
b0c471aed8 | ||
|
|
67099f80ba | ||
|
|
ad34c2bdd4 | ||
|
|
fbf5e5e732 | ||
|
|
ed0f93977d | ||
|
|
d948a4f2ee | ||
|
|
f2024a1f9e | ||
|
|
6fdec808b2 | ||
|
|
a1471becf3 | ||
|
|
16927d9a76 | ||
|
|
2b40c0beec | ||
|
|
d156bae156 | ||
|
|
85435a84f5 | ||
|
|
eb1081d37e | ||
|
|
e60b388a2e | ||
|
|
fc7e5f4a09 | ||
|
|
79b0866c62 | ||
|
|
6da62a62f0 | ||
|
|
059afb8ee8 | ||
|
|
5dd7378db4 | ||
|
|
dcb0e6c8a8 | ||
|
|
f569ae9b22 | ||
|
|
ec13ba2818 | ||
|
|
2020c23edf | ||
|
|
260a56c748 | ||
|
|
4258bb1f8a | ||
|
|
490404dbb2 | ||
|
|
513a214eca | ||
|
|
78a26cc5e4 | ||
|
|
bf493bb048 | ||
|
|
1b524c4617 | ||
|
|
cb10465127 | ||
|
|
92c025a7f6 | ||
|
|
4461af35c7 | ||
|
|
316b32c525 | ||
|
|
10e3f7bbf5 | ||
|
|
e1eac00ee0 | ||
|
|
111e152a5d | ||
|
|
ffed2ff823 | ||
|
|
a5275ea9e7 | ||
|
|
cdf0fedae2 | ||
|
|
d14b95f4bd | ||
|
|
eadc3b8d80 | ||
|
|
6db5307730 | ||
|
|
0a40e71652 | ||
|
|
b11c3f679e | ||
|
|
061d1969f8 | ||
|
|
f549d5a70a | ||
|
|
38c61493d2 | ||
|
|
29d2c936d1 | ||
|
|
cfa22ab1c4 | ||
|
|
3556f63a29 | ||
|
|
34de19ebf6 | ||
|
|
c1fce502f7 | ||
|
|
363f6659e4 | ||
|
|
6abeefb303 | ||
|
|
697a5f5d2a | ||
|
|
0a45dd384e | ||
|
|
27912f6e1a | ||
|
|
26acdebafa | ||
|
|
c7ea283f1f | ||
|
|
b881598166 | ||
|
|
a9c5f53562 | ||
|
|
15ce428672 | ||
|
|
b98e5f396a | ||
|
|
b7c92c5afd | ||
|
|
e7c4680b51 | ||
|
|
03a9f0bedf | ||
|
|
f8564398fc | ||
|
|
b96406669d | ||
|
|
e51a504550 | ||
|
|
eef604fd64 | ||
|
|
b803d51586 | ||
|
|
7e9786fccf | ||
|
|
f7aeeca884 | ||
|
|
16a84972f6 | ||
|
|
4dbe2634aa | ||
|
|
233f0c4201 | ||
|
|
96cee4f9ac | ||
|
|
2d566710e5 | ||
|
|
a0f7d7ae0e | ||
|
|
38d81c14d0 | ||
|
|
3e99b90c0b | ||
|
|
c72c73a94f | ||
|
|
528eb1e7ad | ||
|
|
d1c56b8b28 | ||
|
|
7aa0f779de | ||
|
|
a1f27072c2 | ||
|
|
3acbef14b7 | ||
|
|
0600f551b3 | ||
|
|
9481762802 | ||
|
|
778264fbab | ||
|
|
1df3da0a88 | ||
|
|
7facb8207b | ||
|
|
dfd8ef0186 | ||
|
|
fb3b1ceba2 | ||
|
|
9e28dfac9c | ||
|
|
012f399639 | ||
|
|
a328f9ed3f | ||
|
|
e4ff972522 | ||
|
|
4862e8b650 | ||
|
|
078c3bd85c | ||
|
|
84749a4ced | ||
|
|
f1c58d0e2c | ||
|
|
76413e1d03 | ||
|
|
db70f1752a | ||
|
|
f3eaa33ce7 | ||
|
|
9e27a118ed | ||
|
|
34555c4934 | ||
|
|
9a3dd8815d | ||
|
|
c1809a23ba | ||
|
|
59ed2a0bea | ||
|
|
eecf351c64 | ||
|
|
abd4703c79 | ||
|
|
4b413a60e4 | ||
|
|
17b346dfe7 | ||
|
|
71e37816cc | ||
|
|
cce5fe2045 | ||
|
|
371e2a5cbc | ||
|
|
d4ce9f4a7c | ||
|
|
8fabf0be4a | ||
|
|
45d76d6234 | ||
|
|
da95bcfb4b | ||
|
|
64101d3af5 | ||
|
|
3c561bcdf2 | ||
|
|
ffef60912f | ||
|
|
bc88271520 | ||
|
|
5508e43466 | ||
|
|
79a5522931 | ||
|
|
f529d55380 | ||
|
|
f5f22fdbd0 | ||
|
|
5c0d077f74 | ||
|
|
131cfcdeae | ||
|
|
dc2e7d6e9b | ||
|
|
7bcd9e8089 | ||
|
|
fd0c501d68 | ||
|
|
14b410a12a | ||
|
|
ab96035bec | ||
|
|
9193a9517a | ||
|
|
8d7a3f26d3 | ||
|
|
3444a47cad | ||
|
|
89a59e7f99 | ||
|
|
f5dd74bcf0 | ||
|
|
78d930516d | ||
|
|
83b8eea611 | ||
|
|
1bebe78c56 | ||
|
|
b75a209374 | ||
|
|
e90263c23f | ||
|
|
f414c28589 | ||
|
|
7e5e84fbb7 | ||
|
|
37b007603a | ||
|
|
c25dc51935 | ||
|
|
34daf240f9 | ||
|
|
721d854095 |
@@ -11,9 +11,9 @@ workflows:
|
||||
base-revision: main
|
||||
config-path: .circleci/continue_config.yml
|
||||
mapping: |
|
||||
.circleci/.* run-all-workflows true
|
||||
gpt4all-backend/.* run-all-workflows true
|
||||
gpt4all-bindings/python/.* run-python-workflow true
|
||||
gpt4all-bindings/typescript/.* run-ts-workflow true
|
||||
gpt4all-bindings/csharp/.* run-csharp-workflow true
|
||||
gpt4all-backend/.* run-chat-workflow true
|
||||
gpt4all-chat/.* run-chat-workflow true
|
||||
.* run-default-workflow true
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
17
.circleci/grab_notary_id.py
Normal file
17
.circleci/grab_notary_id.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
ID_REG = r"id: (.*)"
|
||||
|
||||
def main() -> None:
|
||||
notary_log = sys.argv[1]
|
||||
with open(notary_log, "r") as f:
|
||||
notary_output = f.read()
|
||||
id_m = re.search(ID_REG, notary_output)
|
||||
if id_m:
|
||||
print(id_m.group(1))
|
||||
else:
|
||||
raise RuntimeError("Unable to parse ID from notarization logs")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,3 +1,3 @@
|
||||
[codespell]
|
||||
ignore-words-list = blong, belong, afterall, som, assistent
|
||||
ignore-words-list = blong, afterall, som, assistent, crasher
|
||||
skip = .git,*.pdf,*.svg,*.lock
|
||||
|
||||
35
.github/ISSUE_TEMPLATE/bindings-bug.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/bindings-bug.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: "\U0001F6E0 Bindings Bug Report"
|
||||
about: A bug report for the GPT4All Bindings
|
||||
labels: ["bindings", "bug-unconfirmed"]
|
||||
---
|
||||
|
||||
<!-- Before creating a new issue, please make sure to take a few moments to check the issue tracker for existing issues about the bug. -->
|
||||
|
||||
### Bug Report
|
||||
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
### Example Code
|
||||
|
||||
<!-- Please provide a minimal code example that can be used to experience this issue. Delete this section if it does not apply. -->
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
<!-- List the steps that should be taken to experience this issue. -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
<!-- In a few words, what did you expect to happen? -->
|
||||
|
||||
### Your Environment
|
||||
|
||||
- Bindings version (e.g. "Version" from `pip show gpt4all`):
|
||||
- Operating System:
|
||||
- Chat model used (if applicable):
|
||||
|
||||
<!-- You can freely edit this text, please remove all the lines you believe are unnecessary. -->
|
||||
55
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
55
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: "\U0001F41B Bug Report"
|
||||
description: Submit a bug report to help us improve GPT4All
|
||||
labels: ["02 Bug Report"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
Thank you for taking the time to file a bug report. Before creating a new
|
||||
issue, please make sure to take a few moments to check the issue tracker
|
||||
for existing issues about the bug.
|
||||
|
||||
- type: textarea
|
||||
id: system-info
|
||||
attributes:
|
||||
label: System Info
|
||||
description: Please share your system info with us.
|
||||
placeholder: GPT4All version, platform, python version, etc...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: information-scripts-examples
|
||||
attributes:
|
||||
label: Information
|
||||
description: "The problem arises when using:"
|
||||
options:
|
||||
- label: "The official example notebooks/scripts"
|
||||
- label: "My own modified scripts"
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Reproduction
|
||||
description: |
|
||||
Please provide a [code sample](https://stackoverflow.com/help/minimal-reproducible-example) that reproduces the problem you ran into. It can be a Colab link or just a code snippet.
|
||||
If you have code snippets, error messages, stack traces please provide them here as well.
|
||||
Important! Use code tags to correctly format your code. See https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks#syntax-highlighting
|
||||
Avoid screenshots when possible, as they are hard to read and (more importantly) don't allow others to copy-and-paste your code.
|
||||
|
||||
placeholder: |
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: "A clear and concise description of what you would expect to happen."
|
||||
31
.github/ISSUE_TEMPLATE/chat-bug.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/chat-bug.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: "\U0001F4AC GPT4All Bug Report"
|
||||
about: A bug report for GPT4All Chat
|
||||
labels: ["chat", "bug-unconfirmed"]
|
||||
---
|
||||
|
||||
<!-- Before creating a new issue, please make sure to take a few moments to check the issue tracker for existing issues about the bug. -->
|
||||
|
||||
### Bug Report
|
||||
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
<!-- List the steps that should be taken to experience this issue. Provide any relevant information about your configuration, and describe anything that was unexpected. -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
<!-- In a few words, what did you expect to happen? -->
|
||||
|
||||
### Your Environment
|
||||
|
||||
- GPT4All version:
|
||||
- Operating System:
|
||||
- Chat model used (if applicable):
|
||||
|
||||
<!-- You can freely edit this text, please remove all the lines you believe are unnecessary. -->
|
||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,2 +1 @@
|
||||
blank_issues_enabled: false
|
||||
version: 2.1
|
||||
version: 2.1
|
||||
|
||||
9
.github/ISSUE_TEMPLATE/documentation.md
vendored
Normal file
9
.github/ISSUE_TEMPLATE/documentation.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: "\U0001F4C4 Documentation"
|
||||
about: An issue related to the GPT4All documentation
|
||||
labels: ["documentation"]
|
||||
---
|
||||
|
||||
### Documentation
|
||||
|
||||
<!-- Please describe the issue with the documentation as clearly as possible. -->
|
||||
19
.github/ISSUE_TEMPLATE/documentation.yml
vendored
19
.github/ISSUE_TEMPLATE/documentation.yml
vendored
@@ -1,19 +0,0 @@
|
||||
name: Documentation
|
||||
description: Report an issue related to the GPT4All documentation.
|
||||
title: "DOC: <Please write a comprehensive title after the 'DOC: ' prefix>"
|
||||
labels: [03 - Documentation]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Issue with current documentation:"
|
||||
description: >
|
||||
Please make sure to leave a reference to the document/code you're
|
||||
referring to.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Idea or request for content:"
|
||||
description: >
|
||||
Please describe as clearly as possible what topics you think are missing
|
||||
from the current documentation.
|
||||
10
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: "\U0001F680 Feature Request"
|
||||
about: Submit a proposal/request for a new GPT4All feature
|
||||
title: "[Feature] Feature request title..."
|
||||
labels: ["enhancement"]
|
||||
---
|
||||
|
||||
### Feature Request
|
||||
|
||||
<!-- A clear and concise description of the feature proposal. -->
|
||||
30
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
30
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -1,30 +0,0 @@
|
||||
name: "\U0001F680 Feature Request"
|
||||
description: Submit a proposal/request for a new GPT4All feature
|
||||
labels: ["02 Feature Request"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: feature-request
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Feature request
|
||||
description: |
|
||||
A clear and concise description of the feature proposal. Please provide links to any relevant GitHub repos, papers, or other resources if relevant.
|
||||
|
||||
- type: textarea
|
||||
id: motivation
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: |
|
||||
Please outline the motivation for the proposal. Is your feature request related to a problem? e.g., I'm always frustrated when [...]. If this is related to another GitHub issue, please link here too.
|
||||
|
||||
- type: textarea
|
||||
id: contribution
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Your contribution
|
||||
description: |
|
||||
Is there any way that you could help, e.g. by submitting a PR? Make sure to read the CONTRIBUTING.MD [readme](https://github.com/nomic-ai/gpt4all/blob/main/CONTRIBUTING.md)
|
||||
32
.github/ISSUE_TEMPLATE/other-bug.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/other-bug.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: "\U0001F41B Other Bug Report"
|
||||
about: A bug in another component of GPT4All
|
||||
labels: ["bug-unconfirmed"]
|
||||
---
|
||||
|
||||
<!-- Before creating a new issue, please make sure to take a few moments to check the issue tracker for existing issues about the bug. -->
|
||||
|
||||
### Bug Report
|
||||
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
<!-- List the steps that should be taken to experience this issue. Provide any relevant information about your configuration, and describe anything that was unexpected. If this bug involves original code, please provide a minimal version that can reproduce the issue. -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
<!-- In a few words, what did you expect to happen? -->
|
||||
|
||||
### Your Environment
|
||||
|
||||
- GPT4All version (if applicable):
|
||||
- Operating System:
|
||||
- Chat model used (if applicable):
|
||||
|
||||
<!-- You can freely edit this text, please remove all the lines you believe are unnecessary. -->
|
||||
|
||||
18
.github/ISSUE_TEMPLATE/other.yml
vendored
18
.github/ISSUE_TEMPLATE/other.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Other Issue
|
||||
description: Raise an issue that wouldn't be covered by the other templates.
|
||||
title: "Issue: <Please write a comprehensive title after the 'Issue: ' prefix>"
|
||||
labels: [04 - Other]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Issue you'd like to raise."
|
||||
description: >
|
||||
Please describe the issue you'd like to raise as clearly as possible.
|
||||
Make sure to include any relevant links or references.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Suggestion:"
|
||||
description: >
|
||||
Please outline a suggestion to improve the issue here.
|
||||
2
.github/workflows/codespell.yml
vendored
2
.github/workflows/codespell.yml
vendored
@@ -14,6 +14,6 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Codespell
|
||||
uses: codespell-project/actions-codespell@v2
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -183,4 +183,7 @@ build_*
|
||||
build-*
|
||||
|
||||
# IntelliJ
|
||||
.idea/
|
||||
.idea/
|
||||
|
||||
# LLM models
|
||||
*.gguf
|
||||
|
||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -1,4 +1,7 @@
|
||||
[submodule "llama.cpp-mainline"]
|
||||
path = gpt4all-backend/llama.cpp-mainline
|
||||
url = https://github.com/nomic-ai/llama.cpp.git
|
||||
branch = gguf
|
||||
branch = master
|
||||
[submodule "gpt4all-chat/usearch"]
|
||||
path = gpt4all-chat/usearch
|
||||
url = https://github.com/nomic-ai/usearch.git
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
Software for Open Models License (SOM)
|
||||
Version 1.0 dated August 30th, 2023
|
||||
|
||||
This license governs use of the accompanying Software. If you use the Software, you accept this license. If you do not accept the license, do not use the Software.
|
||||
|
||||
This license is intended to encourage open release of models created, modified, processed, or otherwise used via the Software under open licensing terms, and should be interpreted in light of that intent.
|
||||
|
||||
1. Definitions
|
||||
The “Licensor” is the person or entity who is making the Software available under this license. “Software” is the software made available by Licensor under this license.
|
||||
A “Model” is the output of a machine learning algorithm, and excludes the Software.
|
||||
“Model Source Materials” must include the Model and model weights, and may include any input data, input data descriptions, documentation or training descriptions for the Model.
|
||||
“Open Licensing Terms” means: (a) any open source license approved by the Open Source Initiative, or (b) any other terms that make the Model Source Materials publicly available free of charge, and allow recipients to use, modify and distribute the Model Source Materials. Terms described in (b) may include reasonable restrictions such as non-commercial or non-production limitations, or require use in compliance with law.
|
||||
|
||||
2. Grant of Rights. Subject to the conditions and limitations in section 3:
|
||||
(A) Copyright Grant. Licensor grants you a non-exclusive, worldwide, royalty-free copyright license to copy, modify, and distribute the Software and any modifications of the Software you create under this license. The foregoing license includes without limitation the right to create, modify, and use Models using this Software.
|
||||
|
||||
(B) Patent Grant. Licensor grants you a non-exclusive, worldwide, royalty-free license, under any patents owned or controlled by Licensor, to make, have made, use, sell, offer for sale, import, or otherwise exploit the Software. No license is granted to patent rights that are not embodied in the operation of the Software in the form provided by Licensor.
|
||||
|
||||
3. Conditions and Limitations
|
||||
(A) Model Licensing and Access. If you use the Software to create, modify, process, or otherwise use any Model, including usage to create inferences with a Model, whether or not you make the Model available to others, you must make that Model Source Materials publicly available under Open Licensing Terms.
|
||||
|
||||
(B) No Re-Licensing. If you redistribute the Software, or modifications to the Software made under the license granted above, you must make it available only under the terms of this license. You may offer additional terms such as warranties, maintenance and support, but You, and not Licensor, are responsible for performing such terms.
|
||||
|
||||
(C) No Trademark License. This license does not grant you rights to use the Licensor’s name, logo, or trademarks.
|
||||
|
||||
(D) If you assert in writing a claim against any person or entity alleging that the use of the Software infringes any patent, all of your licenses to the Software under Section 2 end automatically as of the date you asserted the claim.
|
||||
|
||||
(E) If you distribute any portion of the Software, you must retain all copyright, patent, trademark, and attribution notices that are present in the Software, and you must include a copy of this license.
|
||||
|
||||
(F) The Software is licensed “as-is.” You bear the entire risk of using it. Licensor gives You no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws that this license cannot change. To the extent permitted under your local laws, the Licensor disclaims and excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement. To the extent this disclaimer is unlawful, you, and not Licensor, are responsible for any liability.
|
||||
134
README.md
134
README.md
@@ -1,74 +1,74 @@
|
||||
<h1 align="center">GPT4All</h1>
|
||||
|
||||
<p align="center">Open-source assistant-style large language models that run locally on your CPU</p>
|
||||
|
||||
<p align="center"><strong>New</strong>: Now with Nomic Vulkan Universal GPU support. <a href="https://blog.nomic.ai/posts/gpt4all-gpu-inference-with-vulkan">Learn more</a>.</p>
|
||||
|
||||
<p align="center">Privacy-oriented software for chatting with large language models that run on your own computer.</p>
|
||||
<p align="center">
|
||||
<a href="https://gpt4all.io">GPT4All Website</a>
|
||||
<a href="https://gpt4all.io">Official Website</a> • <a href="https://docs.gpt4all.io">Documentation</a> • <a href="https://discord.gg/mGZE39AS3e">Discord</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://docs.gpt4all.io">GPT4All Documentation</a>
|
||||
Official Download Links: <a href="https://gpt4all.io/installers/gpt4all-installer-win64.exe">Windows</a> — <a href="https://gpt4all.io/installers/gpt4all-installer-darwin.dmg">macOS</a> — <a href="https://gpt4all.io/installers/gpt4all-installer-linux.run">Ubuntu</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://discord.gg/mGZE39AS3e">Discord</a>
|
||||
<b>NEW:</b> <a href="https://forms.nomic.ai/gpt4all-release-notes-signup">Subscribe to our mailing list</a> for updates and news!
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://python.langchain.com/en/latest/modules/models/llms/integrations/gpt4all.html">🦜️🔗 Official Langchain Backend</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
GPT4All is made possible by our compute partner <a href="https://www.paperspace.com/">Paperspace</a>.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img width="600" height="365" src="https://user-images.githubusercontent.com/13879686/231876409-e3de1934-93bb-4b4b-9013-b491a969ebbc.gif">
|
||||
</p>
|
||||
<p align="center">
|
||||
Run on an M1 macOS Device (not sped up!)
|
||||
<a href="https://www.phorm.ai/query?projectId=755eecd3-24ad-49cc-abf4-0ab84caacf63"><img src="https://img.shields.io/badge/Phorm-Ask_AI-%23F2777A.svg" alt="phorm.ai"></a>
|
||||
</p>
|
||||
|
||||
## GPT4All: An ecosystem of open-source on-edge large language models.
|
||||
GPT4All is an ecosystem to train and deploy **powerful** and **customized** large language models that run locally on consumer grade CPUs. Note that your CPU needs to support [AVX or AVX2 instructions](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions).
|
||||
<p align="center">
|
||||
<img width="auto" height="400" src="https://github.com/nomic-ai/gpt4all/assets/14168726/495fce3e-769b-4e5a-a394-99f072ac4d29">
|
||||
</p>
|
||||
<p align="center">
|
||||
Run on an M2 MacBook Pro (not sped up!)
|
||||
</p>
|
||||
|
||||
|
||||
## About GPT4All
|
||||
|
||||
GPT4All is an ecosystem to run **powerful** and **customized** large language models that work locally on consumer grade CPUs and NVIDIA and AMD GPUs. Note that your CPU needs to support [AVX instructions](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions).
|
||||
|
||||
Learn more in the [documentation](https://docs.gpt4all.io).
|
||||
|
||||
The goal is simple - be the best instruction tuned assistant-style language model that any person or enterprise can freely use, distribute and build on.
|
||||
|
||||
A GPT4All model is a 3GB - 8GB file that you can download and plug into the GPT4All open-source ecosystem software. **Nomic AI** supports and maintains this software ecosystem to enforce quality and security alongside spearheading the effort to allow any person or enterprise to easily train and deploy their own on-edge large language models.
|
||||
A GPT4All model is a 3GB - 8GB file that you can download and plug into the GPT4All software. **Nomic AI** supports and maintains this software ecosystem to enforce quality and security alongside spearheading the effort to allow any person or enterprise to easily deploy their own on-edge large language models.
|
||||
|
||||
|
||||
### Chat Client
|
||||
Run any GPT4All model natively on your home desktop with the auto-updating desktop chat client. See <a href="https://gpt4all.io">GPT4All Website</a> for a full list of open-source models you can run with this powerful desktop application.
|
||||
### Installation
|
||||
|
||||
Direct Installer Links:
|
||||
The recommended way to install GPT4All is to use one of the online installers linked above in this README, which are also available at the [GPT4All website](https://gpt4all.io/). These require an internet connection at install time, are slightly easier to use on macOS due to code signing, and provide a version of GPT4All that can check for updates.
|
||||
|
||||
* [macOS](https://gpt4all.io/installers/gpt4all-installer-darwin.dmg)
|
||||
An alternative way to install GPT4All is to use one of the offline installers available on the [Releases page](https://github.com/nomic-ai/gpt4all/releases). These do not require an internet connection at install time, and can be used to install an older version of GPT4All if so desired. But using these requires acknowledging a security warning on macOS, and they provide a version of GPT4All that is unable to notify you of updates, so you should enable notifications for Releases on this repository (Watch > Custom > Releases) or sign up for announcements in our [Discord server](https://discord.gg/mGZE39AS3e).
|
||||
|
||||
* [Windows](https://gpt4all.io/installers/gpt4all-installer-win64.exe)
|
||||
|
||||
* [Ubuntu](https://gpt4all.io/installers/gpt4all-installer-linux.run)
|
||||
### What's New
|
||||
- **October 19th, 2023**: GGUF Support Launches with Support for:
|
||||
- Mistral 7b base model, an updated model gallery on [gpt4all.io](https://gpt4all.io), several new local code models including Rift Coder v1.5
|
||||
- [Nomic Vulkan](https://blog.nomic.ai/posts/gpt4all-gpu-inference-with-vulkan) support for Q4\_0 and Q4\_1 quantizations in GGUF.
|
||||
- Offline build support for running old versions of the GPT4All Local LLM Chat Client.
|
||||
- **September 18th, 2023**: [Nomic Vulkan](https://blog.nomic.ai/posts/gpt4all-gpu-inference-with-vulkan) launches supporting local LLM inference on NVIDIA and AMD GPUs.
|
||||
- **July 2023**: Stable support for LocalDocs, a feature that allows you to privately and locally chat with your data.
|
||||
- **June 28th, 2023**: [Docker-based API server] launches allowing inference of local LLMs from an OpenAI-compatible HTTP endpoint.
|
||||
|
||||
Find the most up-to-date information on the [GPT4All Website](https://gpt4all.io/)
|
||||
[Docker-based API server]: https://github.com/nomic-ai/gpt4all/tree/cef74c2be20f5b697055d5b8b506861c7b997fab/gpt4all-api
|
||||
|
||||
### Chat Client building and running
|
||||
|
||||
* Follow the visual instructions on the chat client [build_and_run](gpt4all-chat/build_and_run.md) page
|
||||
### Building From Source
|
||||
|
||||
* Follow the instructions [here](gpt4all-chat/build_and_run.md) to build the GPT4All Chat UI from source.
|
||||
|
||||
|
||||
### Bindings
|
||||
|
||||
* <a href="https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/python/README.md">:snake: Official Python Bindings</a> [](https://pepy.tech/project/gpt4all)
|
||||
* <a href="https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/typescript">:computer: Official Typescript Bindings</a>
|
||||
* <a href="https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/golang">:computer: Official GoLang Bindings</a>
|
||||
* <a href="https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/csharp">:computer: Official C# Bindings</a>
|
||||
* <a href="https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/java">:computer: Official Java Bindings</a>
|
||||
* :snake: <a href="https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/python">Official Python Bindings</a> [](https://pepy.tech/project/gpt4all)
|
||||
* :computer: <a href="https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/typescript">Typescript Bindings</a>
|
||||
|
||||
|
||||
### Integrations
|
||||
|
||||
* 🗃️ [Weaviate Vector Database](https://github.com/weaviate/weaviate) - [module docs](https://weaviate.io/developers/weaviate/modules/retriever-vectorizer-modules/text2vec-gpt4all)
|
||||
* :parrot::link: [Langchain](https://python.langchain.com/en/latest/modules/models/llms/integrations/gpt4all.html)
|
||||
* :card_file_box: [Weaviate Vector Database](https://github.com/weaviate/weaviate) - [module docs](https://weaviate.io/developers/weaviate/modules/retriever-vectorizer-modules/text2vec-gpt4all)
|
||||
* :telescope: [OpenLIT (OTel-native Monitoring)](https://github.com/openlit/openlit) - [Docs](https://docs.openlit.io/latest/integrations/gpt4all)
|
||||
|
||||
|
||||
## Contributing
|
||||
GPT4All welcomes contributions, involvement, and discussion from the open source community!
|
||||
@@ -78,6 +78,59 @@ Check project discord, with project owners, or through existing issues/PRs to av
|
||||
Please make sure to tag all of the above with relevant project identifiers or your contribution could potentially get lost.
|
||||
Example tags: `backend`, `bindings`, `python-bindings`, `documentation`, etc.
|
||||
|
||||
|
||||
## GPT4All 2024 Roadmap
|
||||
To contribute to the development of any of the below roadmap items, make or find the corresponding issue and cross-reference the [in-progress task](https://github.com/orgs/nomic-ai/projects/2/views/1).
|
||||
|
||||
Each item should have an issue link below.
|
||||
|
||||
- Chat UI Language Localization (localize UI into the native languages of users)
|
||||
- [ ] Chinese
|
||||
- [ ] German
|
||||
- [ ] French
|
||||
- [ ] Portuguese
|
||||
- [ ] Your native language here.
|
||||
- UI Redesign: an internal effort at Nomic to improve the UI/UX of gpt4all for all users.
|
||||
- [ ] Design new user interface and gather community feedback
|
||||
- [ ] Implement the new user interface and experience.
|
||||
- Installer and Update Improvements
|
||||
- [ ] Seamless native installation and update process on OSX
|
||||
- [ ] Seamless native installation and update process on Windows
|
||||
- [ ] Seamless native installation and update process on Linux
|
||||
- Model discoverability improvements:
|
||||
- [x] Support huggingface model discoverability
|
||||
- [ ] Support Nomic hosted model discoverability
|
||||
- LocalDocs (towards a local perplexity)
|
||||
- Multilingual LocalDocs Support
|
||||
- [ ] Create a multilingual experience
|
||||
- [ ] Incorporate a multilingual embedding model
|
||||
- [ ] Specify a preferred multilingual LLM for localdocs
|
||||
- Improved RAG techniques
|
||||
- [ ] Query augmentation and re-writing
|
||||
- [ ] Improved chunking and text extraction from arbitrary modalities
|
||||
- [ ] Custom PDF extractor past the QT default (charts, tables, text)
|
||||
- [ ] Faster indexing and local exact search with v1.5 hamming embeddings and reranking (skip ANN index construction!)
|
||||
- Support queries like 'summarize X document'
|
||||
- Multimodal LocalDocs support with Nomic Embed
|
||||
- Nomic Dataset Integration with real-time LocalDocs
|
||||
- [ ] Include an option to allow the export of private LocalDocs collections to Nomic Atlas for debugging data/chat quality
|
||||
- [ ] Allow optional sharing of LocalDocs collections between users.
|
||||
- [ ] Allow the import of a LocalDocs collection from an Atlas Datasets
|
||||
- Chat with live version of Wikipedia, Chat with Pubmed, chat with the latest snapshot of world news.
|
||||
- First class Multilingual LLM Support
|
||||
- [ ] Recommend and set a default LLM for German
|
||||
- [ ] Recommend and set a default LLM for English
|
||||
- [ ] Recommend and set a default LLM for Chinese
|
||||
- [ ] Recommend and set a default LLM for Spanish
|
||||
|
||||
- Server Mode improvements
|
||||
- Improved UI and new requested features:
|
||||
- [ ] Fix outstanding bugs and feature requests around networking configurations.
|
||||
- [ ] Support Nomic Embed inferencing
|
||||
- [ ] First class documentation
|
||||
- [ ] Improving developer use and quality of server mode (e.g. support larger batches)
|
||||
|
||||
|
||||
## Technical Reports
|
||||
|
||||
<p align="center">
|
||||
@@ -92,6 +145,7 @@ Example tags: `backend`, `bindings`, `python-bindings`, `documentation`, etc.
|
||||
<a href="https://s3.amazonaws.com/static.nomic.ai/gpt4all/2023_GPT4All_Technical_Report.pdf">:green_book: Technical Report 1: GPT4All</a>
|
||||
</p>
|
||||
|
||||
|
||||
## Citation
|
||||
|
||||
If you utilize this repository, models or data in a downstream project, please consider citing it with:
|
||||
|
||||
112
gpt4all-api/.gitignore
vendored
112
gpt4all-api/.gitignore
vendored
@@ -1,112 +0,0 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
app/__pycache__/
|
||||
gpt4all_api/__pycache__/
|
||||
gpt4all_api/app/api_v1/__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
*.lock
|
||||
*.cache
|
||||
@@ -1,7 +0,0 @@
|
||||
[settings]
|
||||
known_third_party=geopy,nltk,np,numpy,pandas,pysbd,fire,torch
|
||||
|
||||
line_length=120
|
||||
include_trailing_comma=True
|
||||
multi_line_output=3
|
||||
use_parentheses=True
|
||||
@@ -1,13 +0,0 @@
|
||||
Copyright 2023 Nomic, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,87 +0,0 @@
|
||||
# GPT4All REST API
|
||||
This directory contains the source code to run and build docker images that run a FastAPI app
|
||||
for serving inference from GPT4All models. The API matches the OpenAI API spec.
|
||||
|
||||
## Tutorial
|
||||
|
||||
The following tutorial assumes that you have checked out this repo and cd'd into it.
|
||||
|
||||
### Starting the app
|
||||
|
||||
First change your working directory to `gpt4all/gpt4all-api`.
|
||||
|
||||
Now you can build the FastAPI docker image. You only have to do this on initial build or when you add new dependencies to the requirements.txt file:
|
||||
```bash
|
||||
DOCKER_BUILDKIT=1 docker build -t gpt4all_api --progress plain -f gpt4all_api/Dockerfile.buildkit .
|
||||
```
|
||||
|
||||
Then, start the backend with:
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
This will run both the API and locally hosted GPU inference server. If you want to run the API without the GPU inference server, you can run:
|
||||
|
||||
```bash
|
||||
docker compose up --build gpt4all_api
|
||||
```
|
||||
|
||||
To run the API with the GPU inference server, you will need to include environment variables (like the `MODEL_ID`). Edit the `.env` file and run
|
||||
```bash
|
||||
docker compose --env-file .env up --build
|
||||
```
|
||||
|
||||
|
||||
#### Spinning up your app
|
||||
Run `docker compose up` to spin up the backend. Monitor the logs for errors in-case you forgot to set an environment variable above.
|
||||
|
||||
|
||||
#### Development
|
||||
Run
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
and edit files in the `api` directory. The api will hot-reload on changes.
|
||||
|
||||
You can run the unit tests with
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
#### Viewing API documentation
|
||||
|
||||
Once the FastAPI ap is started you can access its documentation and test the search endpoint by going to:
|
||||
```
|
||||
localhost:80/docs
|
||||
```
|
||||
|
||||
This documentation should match the OpenAI OpenAPI spec located at https://github.com/openai/openai-openapi/blob/master/openapi.yaml
|
||||
|
||||
|
||||
#### Running inference
|
||||
```python
|
||||
import openai
|
||||
openai.api_base = "http://localhost:4891/v1"
|
||||
|
||||
openai.api_key = "not needed for a local LLM"
|
||||
|
||||
|
||||
def test_completion():
|
||||
model = "gpt4all-j-v1.3-groovy"
|
||||
prompt = "Who is Michael Jordan?"
|
||||
response = openai.Completion.create(
|
||||
model=model,
|
||||
prompt=prompt,
|
||||
max_tokens=50,
|
||||
temperature=0.28,
|
||||
top_p=0.95,
|
||||
n=1,
|
||||
echo=True,
|
||||
stream=False
|
||||
)
|
||||
assert len(response['choices'][0]['text']) > len(prompt)
|
||||
print(response)
|
||||
```
|
||||
@@ -1,24 +0,0 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
gpt4all_gpu:
|
||||
image: ghcr.io/huggingface/text-generation-inference:0.9.3
|
||||
container_name: gpt4all_gpu
|
||||
restart: always #restart on error (usually code compilation from save during bad state)
|
||||
environment:
|
||||
- HUGGING_FACE_HUB_TOKEN=token
|
||||
- USE_FLASH_ATTENTION=false
|
||||
- MODEL_ID=''
|
||||
- NUM_SHARD=1
|
||||
command: --model-id $MODEL_ID --num-shard $NUM_SHARD
|
||||
volumes:
|
||||
- ./:/data
|
||||
ports:
|
||||
- "8080:80"
|
||||
shm_size: 1g
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
capabilities: [gpu]
|
||||
@@ -1,19 +0,0 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
gpt4all_api:
|
||||
image: gpt4all_api
|
||||
container_name: gpt4all_api
|
||||
restart: always #restart on error (usually code compilation from save during bad state)
|
||||
ports:
|
||||
- "4891:4891"
|
||||
environment:
|
||||
- APP_ENVIRONMENT=dev
|
||||
- WEB_CONCURRENCY=2
|
||||
- LOGLEVEL=debug
|
||||
- PORT=4891
|
||||
- model=ggml-mpt-7b-chat.bin
|
||||
- inference_mode=cpu
|
||||
volumes:
|
||||
- './gpt4all_api/app:/app'
|
||||
command: ["/start-reload.sh"]
|
||||
@@ -1,23 +0,0 @@
|
||||
# syntax=docker/dockerfile:1.0.0-experimental
|
||||
FROM tiangolo/uvicorn-gunicorn:python3.11
|
||||
|
||||
ARG MODEL_BIN=ggml-mpt-7b-chat.bin
|
||||
|
||||
# Put first so anytime this file changes other cached layers are invalidated.
|
||||
COPY gpt4all_api/requirements.txt /requirements.txt
|
||||
|
||||
RUN pip install --upgrade pip
|
||||
|
||||
# Run various pip install commands with ssh keys from host machine.
|
||||
RUN --mount=type=ssh pip install -r /requirements.txt && \
|
||||
rm -Rf /root/.cache && rm -Rf /tmp/pip-install*
|
||||
|
||||
# Finally, copy app and client.
|
||||
COPY gpt4all_api/app /app
|
||||
|
||||
RUN mkdir -p /models
|
||||
|
||||
# Include the following line to bake a model into the image and not have to download it on API start.
|
||||
RUN wget -q --show-progress=off https://gpt4all.io/models/gguf/${MODEL_BIN} -P /models \
|
||||
&& md5sum /models/${MODEL_BIN}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# FastAPI app for serving GPT4All models
|
||||
@@ -1,9 +0,0 @@
|
||||
from api_v1.routes import chat, completions, engines, health
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(chat.router)
|
||||
router.include_router(completions.router)
|
||||
router.include_router(engines.router)
|
||||
router.include_router(health.router)
|
||||
@@ -1,29 +0,0 @@
|
||||
import logging
|
||||
|
||||
from api_v1.settings import settings
|
||||
from fastapi import HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
from starlette.requests import Request
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
startup_msg_fmt = """
|
||||
Starting up GPT4All API
|
||||
"""
|
||||
|
||||
|
||||
async def on_http_error(request: Request, exc: HTTPException):
|
||||
return JSONResponse({'detail': exc.detail}, status_code=exc.status_code)
|
||||
|
||||
|
||||
async def on_startup(app):
|
||||
startup_msg = startup_msg_fmt.format(settings=settings)
|
||||
log.info(startup_msg)
|
||||
|
||||
|
||||
def startup_event_handler(app):
|
||||
async def start_app() -> None:
|
||||
await on_startup(app)
|
||||
|
||||
return start_app
|
||||
@@ -1,61 +0,0 @@
|
||||
import logging
|
||||
import time
|
||||
from typing import Dict, List
|
||||
|
||||
from api_v1.settings import settings
|
||||
from fastapi import APIRouter, Depends, Response, Security, status
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
### This should follow https://github.com/openai/openai-openapi/blob/master/openapi.yaml
|
||||
|
||||
|
||||
class ChatCompletionMessage(BaseModel):
|
||||
role: str
|
||||
content: str
|
||||
|
||||
|
||||
class ChatCompletionRequest(BaseModel):
|
||||
model: str = Field(..., description='The model to generate a completion from.')
|
||||
messages: List[ChatCompletionMessage] = Field(..., description='The model to generate a completion from.')
|
||||
|
||||
|
||||
class ChatCompletionChoice(BaseModel):
|
||||
message: ChatCompletionMessage
|
||||
index: int
|
||||
finish_reason: str
|
||||
|
||||
|
||||
class ChatCompletionUsage(BaseModel):
|
||||
prompt_tokens: int
|
||||
completion_tokens: int
|
||||
total_tokens: int
|
||||
|
||||
|
||||
class ChatCompletionResponse(BaseModel):
|
||||
id: str
|
||||
object: str = 'text_completion'
|
||||
created: int
|
||||
model: str
|
||||
choices: List[ChatCompletionChoice]
|
||||
usage: ChatCompletionUsage
|
||||
|
||||
|
||||
router = APIRouter(prefix="/chat", tags=["Completions Endpoints"])
|
||||
|
||||
|
||||
@router.post("/completions", response_model=ChatCompletionResponse)
|
||||
async def chat_completion(request: ChatCompletionRequest):
|
||||
'''
|
||||
Completes a GPT4All model response.
|
||||
'''
|
||||
|
||||
return ChatCompletionResponse(
|
||||
id='asdf',
|
||||
created=time.time(),
|
||||
model=request.model,
|
||||
choices=[{}],
|
||||
usage={'prompt_tokens': 0, 'completion_tokens': 0, 'total_tokens': 0},
|
||||
)
|
||||
@@ -1,215 +0,0 @@
|
||||
import json
|
||||
from typing import List, Dict, Iterable, AsyncIterable
|
||||
import logging
|
||||
import time
|
||||
from typing import Dict, List, Union, Optional
|
||||
from uuid import uuid4
|
||||
import aiohttp
|
||||
import asyncio
|
||||
from api_v1.settings import settings
|
||||
from fastapi import APIRouter, Depends, Response, Security, status, HTTPException
|
||||
from fastapi.responses import StreamingResponse
|
||||
from gpt4all import GPT4All
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
### This should follow https://github.com/openai/openai-openapi/blob/master/openapi.yaml
|
||||
|
||||
|
||||
class CompletionRequest(BaseModel):
|
||||
model: str = Field(settings.model, description='The model to generate a completion from.')
|
||||
prompt: Union[List[str], str] = Field(..., description='The prompt to begin completing from.')
|
||||
max_tokens: int = Field(None, description='Max tokens to generate')
|
||||
temperature: float = Field(settings.temp, description='Model temperature')
|
||||
top_p: Optional[float] = Field(settings.top_p, description='top_p')
|
||||
top_k: Optional[int] = Field(settings.top_k, description='top_k')
|
||||
n: int = Field(1, description='How many completions to generate for each prompt')
|
||||
stream: bool = Field(False, description='Stream responses')
|
||||
repeat_penalty: float = Field(settings.repeat_penalty, description='Repeat penalty')
|
||||
|
||||
|
||||
class CompletionChoice(BaseModel):
|
||||
text: str
|
||||
index: int
|
||||
logprobs: float
|
||||
finish_reason: str
|
||||
|
||||
|
||||
class CompletionUsage(BaseModel):
|
||||
prompt_tokens: int
|
||||
completion_tokens: int
|
||||
total_tokens: int
|
||||
|
||||
|
||||
class CompletionResponse(BaseModel):
|
||||
id: str
|
||||
object: str = 'text_completion'
|
||||
created: int
|
||||
model: str
|
||||
choices: List[CompletionChoice]
|
||||
usage: CompletionUsage
|
||||
|
||||
|
||||
class CompletionStreamResponse(BaseModel):
|
||||
id: str
|
||||
object: str = 'text_completion'
|
||||
created: int
|
||||
model: str
|
||||
choices: List[CompletionChoice]
|
||||
|
||||
|
||||
router = APIRouter(prefix="/completions", tags=["Completion Endpoints"])
|
||||
|
||||
def stream_completion(output: Iterable, base_response: CompletionStreamResponse):
|
||||
"""
|
||||
Streams a GPT4All output to the client.
|
||||
|
||||
Args:
|
||||
output: The output of GPT4All.generate(), which is an iterable of tokens.
|
||||
base_response: The base response object, which is cloned and modified for each token.
|
||||
|
||||
Returns:
|
||||
A Generator of CompletionStreamResponse objects, which are serialized to JSON Event Stream format.
|
||||
"""
|
||||
for token in output:
|
||||
chunk = base_response.copy()
|
||||
chunk.choices = [dict(CompletionChoice(
|
||||
text=token,
|
||||
index=0,
|
||||
logprobs=-1,
|
||||
finish_reason=''
|
||||
))]
|
||||
yield f"data: {json.dumps(dict(chunk))}\n\n"
|
||||
|
||||
async def gpu_infer(payload, header):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.post(
|
||||
settings.hf_inference_server_host, headers=header, data=json.dumps(payload)
|
||||
) as response:
|
||||
resp = await response.json()
|
||||
return resp
|
||||
|
||||
except aiohttp.ClientError as e:
|
||||
# Handle client-side errors (e.g., connection error, invalid URL)
|
||||
logger.error(f"Client error: {e}")
|
||||
except aiohttp.ServerError as e:
|
||||
# Handle server-side errors (e.g., internal server error)
|
||||
logger.error(f"Server error: {e}")
|
||||
except json.JSONDecodeError as e:
|
||||
# Handle JSON decoding errors
|
||||
logger.error(f"JSON decoding error: {e}")
|
||||
except Exception as e:
|
||||
# Handle other unexpected exceptions
|
||||
logger.error(f"Unexpected error: {e}")
|
||||
|
||||
@router.post("/", response_model=CompletionResponse)
|
||||
async def completions(request: CompletionRequest):
|
||||
'''
|
||||
Completes a GPT4All model response.
|
||||
'''
|
||||
if settings.inference_mode == "gpu":
|
||||
params = request.dict(exclude={'model', 'prompt', 'max_tokens', 'n'})
|
||||
params["max_new_tokens"] = request.max_tokens
|
||||
params["num_return_sequences"] = request.n
|
||||
|
||||
header = {"Content-Type": "application/json"}
|
||||
if isinstance(request.prompt, list):
|
||||
tasks = []
|
||||
for prompt in request.prompt:
|
||||
payload = {"parameters": params}
|
||||
payload["inputs"] = prompt
|
||||
task = gpu_infer(payload, header)
|
||||
tasks.append(task)
|
||||
results = await asyncio.gather(*tasks)
|
||||
|
||||
choices = []
|
||||
for response in results:
|
||||
scores = response["scores"] if "scores" in response else -1.0
|
||||
choices.append(
|
||||
dict(
|
||||
CompletionChoice(
|
||||
text=response["generated_text"], index=0, logprobs=scores, finish_reason='stop'
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return CompletionResponse(
|
||||
id=str(uuid4()),
|
||||
created=time.time(),
|
||||
model=request.model,
|
||||
choices=choices,
|
||||
usage={'prompt_tokens': 0, 'completion_tokens': 0, 'total_tokens': 0},
|
||||
)
|
||||
|
||||
else:
|
||||
payload = {"parameters": params}
|
||||
# If streaming, we need to return a StreamingResponse
|
||||
payload["inputs"] = request.prompt
|
||||
|
||||
resp = await gpu_infer(payload, header)
|
||||
|
||||
output = resp["generated_text"]
|
||||
# this returns all logprobs
|
||||
scores = resp["scores"] if "scores" in resp else -1.0
|
||||
|
||||
return CompletionResponse(
|
||||
id=str(uuid4()),
|
||||
created=time.time(),
|
||||
model=request.model,
|
||||
choices=[dict(CompletionChoice(text=output, index=0, logprobs=scores, finish_reason='stop'))],
|
||||
usage={'prompt_tokens': 0, 'completion_tokens': 0, 'total_tokens': 0},
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
if request.model != settings.model:
|
||||
raise HTTPException(status_code=400,
|
||||
detail=f"The GPT4All inference server is booted to only infer: `{settings.model}`")
|
||||
|
||||
if isinstance(request.prompt, list):
|
||||
if len(request.prompt) > 1:
|
||||
raise HTTPException(status_code=400, detail="Can only infer one inference per request in CPU mode.")
|
||||
else:
|
||||
request.prompt = request.prompt[0]
|
||||
|
||||
model = GPT4All(model_name=settings.model, model_path=settings.gpt4all_path)
|
||||
|
||||
output = model.generate(prompt=request.prompt,
|
||||
max_tokens=request.max_tokens,
|
||||
streaming=request.stream,
|
||||
top_k=request.top_k,
|
||||
top_p=request.top_p,
|
||||
temp=request.temperature,
|
||||
)
|
||||
|
||||
# If streaming, we need to return a StreamingResponse
|
||||
if request.stream:
|
||||
base_chunk = CompletionStreamResponse(
|
||||
id=str(uuid4()),
|
||||
created=time.time(),
|
||||
model=request.model,
|
||||
choices=[]
|
||||
)
|
||||
return StreamingResponse((response for response in stream_completion(output, base_chunk)),
|
||||
media_type="text/event-stream")
|
||||
else:
|
||||
return CompletionResponse(
|
||||
id=str(uuid4()),
|
||||
created=time.time(),
|
||||
model=request.model,
|
||||
choices=[dict(CompletionChoice(
|
||||
text=output,
|
||||
index=0,
|
||||
logprobs=-1,
|
||||
finish_reason='stop'
|
||||
))],
|
||||
usage={
|
||||
'prompt_tokens': 0, # TODO how to compute this?
|
||||
'completion_tokens': 0,
|
||||
'total_tokens': 0
|
||||
}
|
||||
)
|
||||
@@ -1,65 +0,0 @@
|
||||
from typing import List, Union
|
||||
from fastapi import APIRouter
|
||||
from api_v1.settings import settings
|
||||
from gpt4all import Embed4All
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
### This should follow https://github.com/openai/openai-openapi/blob/master/openapi.yaml
|
||||
|
||||
|
||||
class EmbeddingRequest(BaseModel):
|
||||
model: str = Field(
|
||||
settings.model, description="The model to generate an embedding from."
|
||||
)
|
||||
input: Union[str, List[str], List[int], List[List[int]]] = Field(
|
||||
..., description="Input text to embed, encoded as a string or array of tokens."
|
||||
)
|
||||
|
||||
|
||||
class EmbeddingUsage(BaseModel):
|
||||
prompt_tokens: int = 0
|
||||
total_tokens: int = 0
|
||||
|
||||
|
||||
class Embedding(BaseModel):
|
||||
index: int = 0
|
||||
object: str = "embedding"
|
||||
embedding: List[float]
|
||||
|
||||
|
||||
class EmbeddingResponse(BaseModel):
|
||||
object: str = "list"
|
||||
model: str
|
||||
data: List[Embedding]
|
||||
usage: EmbeddingUsage
|
||||
|
||||
|
||||
router = APIRouter(prefix="/embeddings", tags=["Embedding Endpoints"])
|
||||
|
||||
embedder = Embed4All()
|
||||
|
||||
|
||||
def get_embedding(data: EmbeddingRequest) -> EmbeddingResponse:
|
||||
"""
|
||||
Calculates the embedding for the given input using a specified model.
|
||||
|
||||
Args:
|
||||
data (EmbeddingRequest): An EmbeddingRequest object containing the input data
|
||||
and model name.
|
||||
|
||||
Returns:
|
||||
EmbeddingResponse: An EmbeddingResponse object encapsulating the calculated embedding,
|
||||
usage info, and the model name.
|
||||
"""
|
||||
embedding = embedder.embed(data.input)
|
||||
return EmbeddingResponse(
|
||||
data=[Embedding(embedding=embedding)], usage=EmbeddingUsage(), model=data.model
|
||||
)
|
||||
|
||||
|
||||
@router.post("/", response_model=EmbeddingResponse)
|
||||
def embeddings(data: EmbeddingRequest):
|
||||
"""
|
||||
Creates a GPT4All embedding
|
||||
"""
|
||||
return get_embedding(data)
|
||||
@@ -1,40 +0,0 @@
|
||||
import logging
|
||||
from typing import Dict, List
|
||||
|
||||
from api_v1.settings import settings
|
||||
from fastapi import APIRouter, Depends, Response, Security, status
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
### This should follow https://github.com/openai/openai-openapi/blob/master/openapi.yaml
|
||||
|
||||
|
||||
class ListEnginesResponse(BaseModel):
|
||||
data: List[Dict] = Field(..., description="All available models.")
|
||||
|
||||
|
||||
class EngineResponse(BaseModel):
|
||||
data: List[Dict] = Field(..., description="All available models.")
|
||||
|
||||
|
||||
router = APIRouter(prefix="/engines", tags=["Search Endpoints"])
|
||||
|
||||
|
||||
@router.get("/", response_model=ListEnginesResponse)
|
||||
async def list_engines():
|
||||
'''
|
||||
List all available GPT4All models from
|
||||
https://raw.githubusercontent.com/nomic-ai/gpt4all/main/gpt4all-chat/metadata/models2.json
|
||||
'''
|
||||
raise NotImplementedError()
|
||||
return ListEnginesResponse(data=[])
|
||||
|
||||
|
||||
@router.get("/{engine_id}", response_model=EngineResponse)
|
||||
async def retrieve_engine(engine_id: str):
|
||||
''' '''
|
||||
|
||||
raise NotImplementedError()
|
||||
return EngineResponse()
|
||||
@@ -1,13 +0,0 @@
|
||||
import logging
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/health", tags=["Health"])
|
||||
|
||||
|
||||
@router.get('/', response_class=JSONResponse)
|
||||
async def health_check():
|
||||
"""Runs a health check on this instance of the API."""
|
||||
return JSONResponse({'status': 'ok'}, headers={'Access-Control-Allow-Origin': '*'})
|
||||
@@ -1,19 +0,0 @@
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
app_environment = 'dev'
|
||||
model: str = 'ggml-mpt-7b-chat.bin'
|
||||
gpt4all_path: str = '/models'
|
||||
inference_mode: str = "cpu"
|
||||
hf_inference_server_host: str = "http://gpt4all_gpu:80/generate"
|
||||
sentry_dns: str = None
|
||||
|
||||
temp: float = 0.18
|
||||
top_p: float = 1.0
|
||||
top_k: int = 50
|
||||
repeat_penalty: float = 1.18
|
||||
|
||||
|
||||
|
||||
settings = Settings()
|
||||
@@ -1,3 +0,0 @@
|
||||
desc = 'GPT4All API'
|
||||
|
||||
endpoint_paths = {'health': '/health'}
|
||||
@@ -1,84 +0,0 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
import docs
|
||||
from api_v1 import events
|
||||
from api_v1.api import router as v1_router
|
||||
from api_v1.settings import settings
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
from fastapi.logger import logger as fastapi_logger
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI(title='GPT4All API', description=docs.desc)
|
||||
|
||||
# CORS Configuration (in-case you want to deploy)
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["GET", "POST", "OPTIONS"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
logger.info('Adding v1 endpoints..')
|
||||
|
||||
# add v1
|
||||
app.include_router(v1_router, prefix='/v1')
|
||||
app.add_event_handler('startup', events.startup_event_handler(app))
|
||||
app.add_exception_handler(HTTPException, events.on_http_error)
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
global model
|
||||
if settings.inference_mode == "cpu":
|
||||
logger.info(f"Downloading/fetching model: {os.path.join(settings.gpt4all_path, settings.model)}")
|
||||
from gpt4all import GPT4All
|
||||
|
||||
model = GPT4All(model_name=settings.model, model_path=settings.gpt4all_path)
|
||||
|
||||
logger.info(f"GPT4All API is ready to infer from {settings.model} on CPU.")
|
||||
|
||||
else:
|
||||
# is it possible to do this once the server is up?
|
||||
## TODO block until HF inference server is up.
|
||||
logger.info(f"GPT4All API is ready to infer from {settings.model} on CPU.")
|
||||
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown():
|
||||
logger.info("Shutting down API")
|
||||
|
||||
|
||||
if settings.sentry_dns is not None:
|
||||
import sentry_sdk
|
||||
|
||||
def traces_sampler(sampling_context):
|
||||
if 'health' in sampling_context['transaction_context']['name']:
|
||||
return False
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn=settings.sentry_dns, traces_sample_rate=0.1, traces_sampler=traces_sampler, send_default_pii=False
|
||||
)
|
||||
|
||||
# This is needed to get logs to show up in the app
|
||||
if "gunicorn" in os.environ.get("SERVER_SOFTWARE", ""):
|
||||
gunicorn_error_logger = logging.getLogger("gunicorn.error")
|
||||
gunicorn_logger = logging.getLogger("gunicorn")
|
||||
|
||||
root_logger = logging.getLogger()
|
||||
fastapi_logger.setLevel(gunicorn_logger.level)
|
||||
fastapi_logger.handlers = gunicorn_error_logger.handlers
|
||||
root_logger.setLevel(gunicorn_logger.level)
|
||||
|
||||
uvicorn_logger = logging.getLogger("uvicorn.access")
|
||||
uvicorn_logger.handlers = gunicorn_error_logger.handlers
|
||||
else:
|
||||
# https://github.com/tiangolo/fastapi/issues/2019
|
||||
LOG_FORMAT2 = (
|
||||
"[%(asctime)s %(process)d:%(threadName)s] %(name)s - %(levelname)s - %(message)s | %(filename)s:%(lineno)d"
|
||||
)
|
||||
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT2)
|
||||
@@ -1,59 +0,0 @@
|
||||
"""
|
||||
Use the OpenAI python API to test gpt4all models.
|
||||
"""
|
||||
from typing import List, get_args
|
||||
|
||||
import openai
|
||||
|
||||
openai.api_base = "http://localhost:4891/v1"
|
||||
|
||||
openai.api_key = "not needed for a local LLM"
|
||||
|
||||
|
||||
def test_completion():
|
||||
model = "ggml-mpt-7b-chat.bin"
|
||||
prompt = "Who is Michael Jordan?"
|
||||
response = openai.Completion.create(
|
||||
model=model, prompt=prompt, max_tokens=50, temperature=0.28, top_p=0.95, n=1, echo=True, stream=False
|
||||
)
|
||||
assert len(response['choices'][0]['text']) > len(prompt)
|
||||
|
||||
def test_streaming_completion():
|
||||
model = "ggml-mpt-7b-chat.bin"
|
||||
prompt = "Who is Michael Jordan?"
|
||||
tokens = []
|
||||
for resp in openai.Completion.create(
|
||||
model=model,
|
||||
prompt=prompt,
|
||||
max_tokens=50,
|
||||
temperature=0.28,
|
||||
top_p=0.95,
|
||||
n=1,
|
||||
echo=True,
|
||||
stream=True):
|
||||
tokens.append(resp.choices[0].text)
|
||||
|
||||
assert (len(tokens) > 0)
|
||||
assert (len("".join(tokens)) > len(prompt))
|
||||
|
||||
|
||||
def test_batched_completion():
|
||||
model = "ggml-mpt-7b-chat.bin"
|
||||
prompt = "Who is Michael Jordan?"
|
||||
response = openai.Completion.create(
|
||||
model=model, prompt=[prompt] * 3, max_tokens=50, temperature=0.28, top_p=0.95, n=1, echo=True, stream=False
|
||||
)
|
||||
assert len(response['choices'][0]['text']) > len(prompt)
|
||||
assert len(response['choices']) == 3
|
||||
|
||||
|
||||
def test_embedding():
|
||||
model = "ggml-all-MiniLM-L6-v2-f16.bin"
|
||||
prompt = "Who is Michael Jordan?"
|
||||
response = openai.Embedding.create(model=model, input=prompt)
|
||||
output = response["data"][0]["embedding"]
|
||||
args = get_args(List[float])
|
||||
|
||||
assert response["model"] == model
|
||||
assert isinstance(output, list)
|
||||
assert all(isinstance(x, args) for x in output)
|
||||
@@ -1,12 +0,0 @@
|
||||
aiohttp>=3.6.2
|
||||
aiofiles
|
||||
pydantic>=1.4.0,<2.0.0
|
||||
requests>=2.24.0
|
||||
ujson>=2.0.2
|
||||
fastapi>=0.95.0
|
||||
Jinja2>=3.0
|
||||
gpt4all>=1.0.0
|
||||
pytest
|
||||
openai
|
||||
black
|
||||
isort
|
||||
@@ -1,46 +0,0 @@
|
||||
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
APP_NAME:=gpt4all_api
|
||||
PYTHON:=python3.8
|
||||
SHELL := /bin/bash
|
||||
|
||||
all: dependencies
|
||||
|
||||
fresh: clean dependencies
|
||||
|
||||
testenv: clean_testenv test_build
|
||||
docker compose -f docker-compose.yaml up --build
|
||||
|
||||
testenv_gpu: clean_testenv test_build
|
||||
docker compose -f docker-compose.yaml -f docker-compose.gpu.yaml up --build
|
||||
|
||||
testenv_d: clean_testenv test_build
|
||||
docker compose up --build -d
|
||||
|
||||
test:
|
||||
docker compose exec $(APP_NAME) pytest -svv --disable-warnings -p no:cacheprovider /app/tests
|
||||
|
||||
test_build:
|
||||
DOCKER_BUILDKIT=1 docker build -t $(APP_NAME) --progress plain -f $(APP_NAME)/Dockerfile.buildkit .
|
||||
|
||||
clean_testenv:
|
||||
docker compose down -v
|
||||
|
||||
fresh_testenv: clean_testenv testenv
|
||||
|
||||
venv:
|
||||
if [ ! -d $(ROOT_DIR)/env ]; then $(PYTHON) -m venv $(ROOT_DIR)/env; fi
|
||||
|
||||
dependencies: venv
|
||||
source $(ROOT_DIR)/env/bin/activate; $(PYTHON) -m pip install -r $(ROOT_DIR)/$(APP_NAME)/requirements.txt
|
||||
|
||||
clean: clean_testenv
|
||||
# Remove existing environment
|
||||
rm -rf $(ROOT_DIR)/env;
|
||||
rm -rf $(ROOT_DIR)/$(APP_NAME)/*.pyc;
|
||||
|
||||
|
||||
black:
|
||||
source $(ROOT_DIR)/env/bin/activate; black -l 120 -S --target-version py38 $(APP_NAME)
|
||||
|
||||
isort:
|
||||
source $(ROOT_DIR)/env/bin/activate; isort --ignore-whitespace --atomic -w 120 $(APP_NAME)
|
||||
@@ -1,16 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.21) # for PROJECT_IS_TOP_LEVEL
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
if(APPLE)
|
||||
option(BUILD_UNIVERSAL "Build a Universal binary on macOS" ON)
|
||||
if(BUILD_UNIVERSAL)
|
||||
if (APPLE)
|
||||
option(BUILD_UNIVERSAL "Build a Universal binary on macOS" ON)
|
||||
else()
|
||||
option(LLMODEL_KOMPUTE "llmodel: use Kompute" ON)
|
||||
option(LLMODEL_VULKAN "llmodel: use Vulkan" OFF)
|
||||
option(LLMODEL_CUDA "llmodel: use CUDA" ON)
|
||||
option(LLMODEL_ROCM "llmodel: use ROCm" OFF)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
if (BUILD_UNIVERSAL)
|
||||
# Build a Universal binary on macOS
|
||||
# This requires that the found Qt library is compiled as Universal binaries.
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
else()
|
||||
# Build for the host architecture on macOS
|
||||
if(NOT CMAKE_OSX_ARCHITECTURES)
|
||||
if (NOT CMAKE_OSX_ARCHITECTURES)
|
||||
set(CMAKE_OSX_ARCHITECTURES "${CMAKE_HOST_SYSTEM_PROCESSOR}" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
@@ -39,15 +47,39 @@ else()
|
||||
message(STATUS "Interprocedural optimization support detected")
|
||||
endif()
|
||||
|
||||
if(NOT APPLE)
|
||||
set(LLAMA_KOMPUTE YES)
|
||||
endif()
|
||||
|
||||
set(DIRECTORY llama.cpp-mainline)
|
||||
include(llama.cpp.cmake)
|
||||
|
||||
set(BUILD_VARIANTS default avxonly)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(BUILD_VARIANTS ${BUILD_VARIANTS} metal)
|
||||
set(BUILD_VARIANTS)
|
||||
set(GPTJ_BUILD_VARIANT cpu)
|
||||
if (APPLE)
|
||||
list(APPEND BUILD_VARIANTS metal)
|
||||
endif()
|
||||
if (LLMODEL_KOMPUTE)
|
||||
list(APPEND BUILD_VARIANTS kompute kompute-avxonly)
|
||||
set(GPTJ_BUILD_VARIANT kompute)
|
||||
else()
|
||||
list(PREPEND BUILD_VARIANTS cpu cpu-avxonly)
|
||||
endif()
|
||||
if (LLMODEL_VULKAN)
|
||||
list(APPEND BUILD_VARIANTS vulkan vulkan-avxonly)
|
||||
endif()
|
||||
if (LLMODEL_CUDA)
|
||||
if (DEFINED CMAKE_CUDA_ARCHITECTURES)
|
||||
set(GGML_CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}")
|
||||
endif()
|
||||
|
||||
include(CheckLanguage)
|
||||
check_language(CUDA)
|
||||
if (NOT CMAKE_CUDA_COMPILER)
|
||||
message(WARNING "CUDA Toolkit not found. To build without CUDA, use -DLLMODEL_CUDA=OFF.")
|
||||
endif()
|
||||
enable_language(CUDA)
|
||||
list(APPEND BUILD_VARIANTS cuda cuda-avxonly)
|
||||
endif()
|
||||
if (LLMODEL_ROCM)
|
||||
enable_language(HIP)
|
||||
list(APPEND BUILD_VARIANTS rocm rocm-avxonly)
|
||||
endif()
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
@@ -55,24 +87,34 @@ set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
# Go through each build variant
|
||||
foreach(BUILD_VARIANT IN LISTS BUILD_VARIANTS)
|
||||
# Determine flags
|
||||
if (BUILD_VARIANT STREQUAL avxonly)
|
||||
set(GPT4ALL_ALLOW_NON_AVX NO)
|
||||
if (BUILD_VARIANT MATCHES avxonly)
|
||||
set(GPT4ALL_ALLOW_NON_AVX OFF)
|
||||
else()
|
||||
set(GPT4ALL_ALLOW_NON_AVX YES)
|
||||
set(GPT4ALL_ALLOW_NON_AVX ON)
|
||||
endif()
|
||||
set(LLAMA_AVX2 ${GPT4ALL_ALLOW_NON_AVX})
|
||||
set(LLAMA_F16C ${GPT4ALL_ALLOW_NON_AVX})
|
||||
set(LLAMA_FMA ${GPT4ALL_ALLOW_NON_AVX})
|
||||
|
||||
if (BUILD_VARIANT STREQUAL metal)
|
||||
set(LLAMA_METAL YES)
|
||||
else()
|
||||
set(LLAMA_METAL NO)
|
||||
set(LLAMA_METAL OFF)
|
||||
set(LLAMA_KOMPUTE OFF)
|
||||
set(LLAMA_VULKAN OFF)
|
||||
set(LLAMA_CUDA OFF)
|
||||
set(LLAMA_ROCM OFF)
|
||||
if (BUILD_VARIANT MATCHES metal)
|
||||
set(LLAMA_METAL ON)
|
||||
elseif (BUILD_VARIANT MATCHES kompute)
|
||||
set(LLAMA_KOMPUTE ON)
|
||||
elseif (BUILD_VARIANT MATCHES vulkan)
|
||||
set(LLAMA_VULKAN ON)
|
||||
elseif (BUILD_VARIANT MATCHES cuda)
|
||||
set(LLAMA_CUDA ON)
|
||||
elseif (BUILD_VARIANT MATCHES rocm)
|
||||
set(LLAMA_HIPBLAS ON)
|
||||
endif()
|
||||
|
||||
# Include GGML
|
||||
set(LLAMA_K_QUANTS YES)
|
||||
include_ggml(llama.cpp-mainline -mainline-${BUILD_VARIANT} ON)
|
||||
include_ggml(-mainline-${BUILD_VARIANT})
|
||||
|
||||
# Function for preparing individual implementations
|
||||
function(prepare_target TARGET_NAME BASE_LIB)
|
||||
@@ -97,25 +139,22 @@ foreach(BUILD_VARIANT IN LISTS BUILD_VARIANTS)
|
||||
LLAMA_VERSIONS=>=3 LLAMA_DATE=999999)
|
||||
prepare_target(llamamodel-mainline llama-mainline)
|
||||
|
||||
if (NOT LLAMA_METAL)
|
||||
if (BUILD_VARIANT MATCHES ${GPTJ_BUILD_VARIANT})
|
||||
add_library(gptj-${BUILD_VARIANT} SHARED
|
||||
gptj.cpp utils.h utils.cpp llmodel_shared.cpp llmodel_shared.h)
|
||||
prepare_target(gptj llama-mainline)
|
||||
endif()
|
||||
|
||||
add_library(bert-${BUILD_VARIANT} SHARED
|
||||
bert.cpp utils.h utils.cpp llmodel_shared.cpp llmodel_shared.h)
|
||||
target_compile_definitions(bert-${BUILD_VARIANT} PRIVATE LLAMA_VERSIONS=>=3 LLAMA_DATE=999999)
|
||||
prepare_target(bert llama-mainline)
|
||||
if (NOT PROJECT_IS_TOP_LEVEL AND BUILD_VARIANT STREQUAL cuda)
|
||||
set(CUDAToolkit_BIN_DIR ${CUDAToolkit_BIN_DIR} PARENT_SCOPE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_library(llmodel
|
||||
llmodel.h llmodel.cpp llmodel_shared.cpp
|
||||
llmodel_c.h llmodel_c.cpp
|
||||
dlhandle.h
|
||||
dlhandle.cpp
|
||||
)
|
||||
target_link_libraries(llmodel PRIVATE ggml-mainline-default)
|
||||
target_compile_definitions(llmodel PRIVATE GGML_BUILD_VARIANT="default")
|
||||
target_compile_definitions(llmodel PRIVATE LIB_FILE_EXT="${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
|
||||
set_target_properties(llmodel PROPERTIES
|
||||
|
||||
@@ -1,897 +0,0 @@
|
||||
#define BERT_H_I_KNOW_WHAT_I_AM_DOING_WHEN_INCLUDING_THIS_FILE
|
||||
#include "bert_impl.h"
|
||||
#include "llmodel_shared.h"
|
||||
#include "ggml.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
//#define DEBUG_BERT
|
||||
|
||||
namespace {
|
||||
const char *modelType_ = "Bert";
|
||||
}
|
||||
|
||||
typedef int32_t bert_vocab_id;
|
||||
|
||||
// default hparams (all-MiniLM-L6-v2)
|
||||
struct bert_hparams
|
||||
{
|
||||
int32_t n_vocab = 30522;
|
||||
int32_t n_max_tokens = 512;
|
||||
int32_t n_embd = 256;
|
||||
int32_t n_intermediate = 1536;
|
||||
int32_t n_head = 12;
|
||||
int32_t n_layer = 6;
|
||||
};
|
||||
|
||||
struct bert_layer
|
||||
{
|
||||
// normalization
|
||||
struct ggml_tensor *ln_att_w;
|
||||
struct ggml_tensor *ln_att_b;
|
||||
|
||||
struct ggml_tensor *ln_out_w;
|
||||
struct ggml_tensor *ln_out_b;
|
||||
|
||||
// attention
|
||||
struct ggml_tensor *q_w;
|
||||
struct ggml_tensor *q_b;
|
||||
struct ggml_tensor *k_w;
|
||||
struct ggml_tensor *k_b;
|
||||
struct ggml_tensor *v_w;
|
||||
struct ggml_tensor *v_b;
|
||||
|
||||
struct ggml_tensor *o_w;
|
||||
struct ggml_tensor *o_b;
|
||||
|
||||
// ff
|
||||
struct ggml_tensor *ff_i_w;
|
||||
struct ggml_tensor *ff_i_b;
|
||||
|
||||
struct ggml_tensor *ff_o_w;
|
||||
struct ggml_tensor *ff_o_b;
|
||||
};
|
||||
|
||||
struct bert_vocab
|
||||
{
|
||||
std::map<std::string, bert_vocab_id> token_to_id;
|
||||
std::map<std::string, bert_vocab_id> subword_token_to_id;
|
||||
|
||||
std::map<bert_vocab_id, std::string> _id_to_token;
|
||||
std::map<bert_vocab_id, std::string> _id_to_subword_token;
|
||||
};
|
||||
|
||||
struct bert_model
|
||||
{
|
||||
bert_hparams hparams;
|
||||
|
||||
// embeddings weights
|
||||
struct ggml_tensor *word_embeddings;
|
||||
struct ggml_tensor *token_type_embeddings;
|
||||
struct ggml_tensor *position_embeddings;
|
||||
struct ggml_tensor *ln_e_w;
|
||||
struct ggml_tensor *ln_e_b;
|
||||
|
||||
std::vector<bert_layer> layers;
|
||||
|
||||
struct ggml_context *ctx;
|
||||
};
|
||||
|
||||
// Replacement for std::vector<uint8_t> that doesn't require zero-initialization.
|
||||
struct bert_ctx
|
||||
{
|
||||
bert_model model;
|
||||
bert_vocab vocab;
|
||||
|
||||
size_t mem_per_token;
|
||||
int64_t mem_per_input;
|
||||
int32_t max_batch_n;
|
||||
llm_buffer buf_compute;
|
||||
llm_buffer work_buf;
|
||||
};
|
||||
|
||||
int32_t bert_n_embd(bert_ctx * ctx)
|
||||
{
|
||||
return ctx->model.hparams.n_embd;
|
||||
}
|
||||
|
||||
int32_t bert_n_max_tokens(bert_ctx * ctx)
|
||||
{
|
||||
return ctx->model.hparams.n_max_tokens;
|
||||
}
|
||||
|
||||
const char* bert_vocab_id_to_token(bert_ctx * ctx, bert_vocab_id id) {
|
||||
bert_vocab & vocab = ctx->vocab;
|
||||
auto it = vocab._id_to_token.find(id);
|
||||
if (it != vocab._id_to_token.end())
|
||||
{
|
||||
return it->second.c_str();
|
||||
}
|
||||
it = vocab._id_to_subword_token.find(id);
|
||||
if (it != vocab._id_to_subword_token.end())
|
||||
{
|
||||
return it->second.c_str();
|
||||
}
|
||||
return "[UNK TOKEN from bert_vocab]";
|
||||
}
|
||||
|
||||
//
|
||||
// Tokenizing
|
||||
//
|
||||
|
||||
static size_t utf8_len(char src)
|
||||
{
|
||||
const size_t lookup[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4};
|
||||
uint8_t highbits = static_cast<uint8_t>(src) >> 4;
|
||||
return lookup[highbits];
|
||||
}
|
||||
|
||||
std::string stripAccents(const std::string &inputString)
|
||||
{
|
||||
std::string resultString;
|
||||
std::map<std::string, char> accentMap = {{"À", 'A'},{"Á", 'A'},
|
||||
{"Â", 'A'},{"Ã", 'A'},{"Ä", 'A'},{"Å", 'A'},{"à", 'a'},{"á", 'a'},
|
||||
{"â", 'a'},{"ã", 'a'},{"ä", 'a'},{"å", 'a'},{"È", 'E'},{"É", 'E'},
|
||||
{"Ê", 'E'},{"Ë", 'E'},{"è", 'e'},{"é", 'e'},{"ê", 'e'},{"ë", 'e'},
|
||||
{"Ì", 'I'},{"Í", 'I'},{"Î", 'I'},{"Ï", 'I'},{"ì", 'i'},{"í", 'i'},
|
||||
{"î", 'i'},{"ï", 'i'},{"Ò", 'O'},{"Ó", 'O'},{"Ô", 'O'},{"Õ", 'O'},
|
||||
{"Ö", 'O'},{"ò", 'o'},{"ó", 'o'},{"ô", 'o'},{"õ", 'o'},{"ö", 'o'},
|
||||
{"Ù", 'U'},{"Ú", 'U'},{"Û", 'U'},{"Ü", 'U'},{"ù", 'u'},{"ú", 'u'},
|
||||
{"û", 'u'},{"ü", 'u'},{"Ý", 'Y'},{"ý", 'y'},{"Ç", 'C'},{"ç", 'c'},
|
||||
{"Ñ", 'N'},{"ñ", 'n'},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < inputString.length();)
|
||||
{
|
||||
int len = utf8_len(inputString[i]);
|
||||
std::string curChar = inputString.substr(i, len);
|
||||
auto iter = accentMap.find(curChar);
|
||||
if (iter != accentMap.end())
|
||||
{
|
||||
resultString += iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultString += curChar;
|
||||
}
|
||||
i += len;
|
||||
}
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
std::string bert_normalize_prompt(const std::string &text)
|
||||
{
|
||||
// TODO: handle chinese characters? https://github.com/huggingface/tokenizers/blob/ef5f50605ddf9f8caef1598c0e4853862b9707a7/tokenizers/src/normalizers/bert.rs#L98
|
||||
std::string text2 = stripAccents(text);
|
||||
for (size_t i = 0; i < text2.size(); i += utf8_len(text2[i]))
|
||||
{
|
||||
char c = text2[i];
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
text2[i] = c - 'A' + 'a';
|
||||
}
|
||||
return text2;
|
||||
}
|
||||
|
||||
std::vector<bert_vocab_id> bert_tokenize(
|
||||
struct bert_ctx * ctx,
|
||||
const char * text)
|
||||
{
|
||||
const bert_vocab &vocab = ctx->vocab;
|
||||
|
||||
std::string str = text;
|
||||
|
||||
std::vector<std::string> words;
|
||||
// first split the text into words
|
||||
{
|
||||
str = bert_normalize_prompt(str);
|
||||
|
||||
std::string pat = R"([[:punct:]]|[[:alpha:]]+|[[:digit:]]+)";
|
||||
|
||||
std::regex re(pat);
|
||||
std::smatch m;
|
||||
|
||||
while (std::regex_search(str, m, re))
|
||||
{
|
||||
for (std::string x : m)
|
||||
{
|
||||
words.push_back(x);
|
||||
}
|
||||
str = m.suffix();
|
||||
}
|
||||
}
|
||||
|
||||
// find the longest tokens that form the words:
|
||||
std::vector<bert_vocab_id> tokens;
|
||||
int cls_tok_id = 101;
|
||||
tokens.push_back(cls_tok_id);
|
||||
for (const auto &word : words)
|
||||
{
|
||||
if (word.size() == 0)
|
||||
continue;
|
||||
|
||||
int i = 0;
|
||||
int n = word.size();
|
||||
auto *token_map = &vocab.token_to_id;
|
||||
while (i < n)
|
||||
{
|
||||
int j = n;
|
||||
while (j > i)
|
||||
{
|
||||
auto it = token_map->find(word.substr(i, j - i));
|
||||
if (it != token_map->end())
|
||||
{
|
||||
tokens.push_back(it->second);
|
||||
i = j;
|
||||
token_map = &vocab.subword_token_to_id;
|
||||
}
|
||||
--j;
|
||||
}
|
||||
if (j == i)
|
||||
{
|
||||
fprintf(stderr, "%s: unknown token '%s'\n", __func__, word.substr(i, 1).data());
|
||||
token_map = &vocab.subword_token_to_id;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
void bert_resize_ctx(bert_ctx * ctx, int32_t new_size) {
|
||||
int64_t buf_size_new = ctx->mem_per_input * new_size;
|
||||
|
||||
// TODO: Max memory should be a param? Now just 1 GB
|
||||
int64_t GB = 1 << 30;
|
||||
#if defined(DEBUG_BERT)
|
||||
printf("%s: requested_buf_size %lldMB\n", __func__, buf_size_new / (1 << 20));
|
||||
#endif
|
||||
if (buf_size_new > GB) {
|
||||
int32_t adjusted_new_size = GB / ctx->mem_per_input;
|
||||
if (adjusted_new_size < 1) adjusted_new_size = 1;
|
||||
#if defined(DEBUG_BERT)
|
||||
printf("%s: requested batch size %d, actual new batch size %d\n", __func__, new_size, adjusted_new_size);
|
||||
#endif
|
||||
new_size = adjusted_new_size;
|
||||
buf_size_new = ctx->mem_per_input * new_size;
|
||||
}
|
||||
if (new_size > ctx->max_batch_n) {
|
||||
ctx->buf_compute.resize(buf_size_new);
|
||||
ctx->max_batch_n = new_size;
|
||||
}
|
||||
}
|
||||
|
||||
void bert_eval(
|
||||
struct bert_ctx *ctx,
|
||||
int32_t n_threads,
|
||||
const bert_vocab_id *raw_tokens,
|
||||
int32_t n_tokens,
|
||||
float *embeddings)
|
||||
{
|
||||
const bert_model& model = ctx->model;
|
||||
bool mem_req_mode = !embeddings;
|
||||
|
||||
// batch_embeddings is nullptr for the initial memory requirements run
|
||||
if (!mem_req_mode && 1 > ctx->max_batch_n)
|
||||
bert_resize_ctx(ctx, 1);
|
||||
|
||||
const int N = n_tokens;
|
||||
const auto &tokens = raw_tokens;
|
||||
|
||||
const auto &hparams = model.hparams;
|
||||
|
||||
const int n_embd = hparams.n_embd;
|
||||
const int n_layer = hparams.n_layer;
|
||||
const int n_max_tokens = hparams.n_max_tokens;
|
||||
const int n_head = hparams.n_head;
|
||||
|
||||
const int d_head = n_embd / n_head;
|
||||
|
||||
std::vector<float> result;
|
||||
if (N > n_max_tokens)
|
||||
{
|
||||
fprintf(stderr, "Too many tokens, maximum is %d\n", n_max_tokens);
|
||||
return;
|
||||
}
|
||||
|
||||
auto & mem_per_token = ctx->mem_per_token;
|
||||
auto & buf_compute = ctx->buf_compute;
|
||||
|
||||
struct ggml_init_params params = {
|
||||
.mem_size = buf_compute.size,
|
||||
.mem_buffer = buf_compute.addr,
|
||||
.no_alloc = false,
|
||||
};
|
||||
|
||||
struct ggml_context *ctx0 = ggml_init(params);
|
||||
struct ggml_cgraph gf = {};
|
||||
|
||||
// Embeddings. word_embeddings + token_type_embeddings + position_embeddings
|
||||
struct ggml_tensor *token_layer = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, N);
|
||||
memcpy(token_layer->data, tokens, N * ggml_element_size(token_layer));
|
||||
|
||||
struct ggml_tensor *token_types = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, N);
|
||||
ggml_set_zero(token_types);
|
||||
|
||||
struct ggml_tensor *positions = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, N);
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
ggml_set_i32_1d(positions, i, i);
|
||||
}
|
||||
|
||||
struct ggml_tensor *inpL = ggml_get_rows(ctx0, model.word_embeddings, token_layer);
|
||||
|
||||
inpL = ggml_add(ctx0,
|
||||
ggml_get_rows(ctx0, model.token_type_embeddings, token_types),
|
||||
inpL);
|
||||
inpL = ggml_add(ctx0,
|
||||
ggml_get_rows(ctx0, model.position_embeddings, positions),
|
||||
inpL);
|
||||
|
||||
// embd norm
|
||||
{
|
||||
inpL = ggml_norm(ctx0, inpL, 1e-5f);
|
||||
|
||||
inpL = ggml_add(ctx0,
|
||||
ggml_mul(ctx0,
|
||||
ggml_repeat(ctx0, model.ln_e_w, inpL),
|
||||
inpL),
|
||||
ggml_repeat(ctx0, model.ln_e_b, inpL));
|
||||
}
|
||||
// layers
|
||||
for (int il = 0; il < n_layer; il++)
|
||||
{
|
||||
struct ggml_tensor *cur = inpL;
|
||||
|
||||
// self-attention
|
||||
{
|
||||
struct ggml_tensor *Qcur = cur;
|
||||
Qcur = ggml_reshape_3d(ctx0,
|
||||
ggml_add(ctx0, ggml_repeat(ctx0, model.layers[il].q_b, Qcur),
|
||||
ggml_mul_mat(ctx0, model.layers[il].q_w, Qcur)),
|
||||
d_head, n_head, N);
|
||||
struct ggml_tensor *Q = ggml_permute(ctx0, Qcur, 0, 2, 1, 3);
|
||||
|
||||
struct ggml_tensor *Kcur = cur;
|
||||
Kcur = ggml_reshape_3d(ctx0,
|
||||
ggml_add(ctx0, ggml_repeat(ctx0, model.layers[il].k_b, Kcur),
|
||||
ggml_mul_mat(ctx0, model.layers[il].k_w, Kcur)),
|
||||
d_head, n_head, N);
|
||||
struct ggml_tensor *K = ggml_permute(ctx0, Kcur, 0, 2, 1, 3);
|
||||
|
||||
struct ggml_tensor *Vcur = cur;
|
||||
Vcur = ggml_reshape_3d(ctx0,
|
||||
ggml_add(ctx0, ggml_repeat(ctx0, model.layers[il].v_b, Vcur),
|
||||
ggml_mul_mat(ctx0, model.layers[il].v_w, Vcur)),
|
||||
d_head, n_head, N);
|
||||
struct ggml_tensor *V = ggml_permute(ctx0, Vcur, 0, 2, 1, 3);
|
||||
|
||||
struct ggml_tensor *KQ = ggml_mul_mat(ctx0, K, Q);
|
||||
// KQ = soft_max(KQ / sqrt(head width))
|
||||
KQ = ggml_soft_max(ctx0,
|
||||
ggml_scale(ctx0,
|
||||
KQ,
|
||||
ggml_new_f32(ctx0, 1.0f / sqrt((float)d_head))));
|
||||
|
||||
V = ggml_cont(ctx0, ggml_transpose(ctx0, V));
|
||||
struct ggml_tensor *KQV = ggml_mul_mat(ctx0, V, KQ);
|
||||
KQV = ggml_permute(ctx0, KQV, 0, 2, 1, 3);
|
||||
|
||||
cur = ggml_cpy(ctx0,
|
||||
KQV,
|
||||
ggml_new_tensor_2d(ctx0, GGML_TYPE_F32, n_embd, N));
|
||||
}
|
||||
// attention output
|
||||
cur = ggml_add(ctx0,
|
||||
ggml_repeat(ctx0, model.layers[il].o_b, cur),
|
||||
ggml_mul_mat(ctx0, model.layers[il].o_w, cur));
|
||||
|
||||
// re-add the layer input
|
||||
cur = ggml_add(ctx0, cur, inpL);
|
||||
|
||||
// attention norm
|
||||
{
|
||||
cur = ggml_norm(ctx0, cur, 1e-5f);
|
||||
|
||||
cur = ggml_add(ctx0,
|
||||
ggml_mul(ctx0,
|
||||
ggml_repeat(ctx0, model.layers[il].ln_att_w, cur),
|
||||
cur),
|
||||
ggml_repeat(ctx0, model.layers[il].ln_att_b, cur));
|
||||
}
|
||||
struct ggml_tensor *att_output = cur;
|
||||
// intermediate_output = self.intermediate(attention_output)
|
||||
cur = ggml_mul_mat(ctx0, model.layers[il].ff_i_w, cur);
|
||||
cur = ggml_add(ctx0,
|
||||
ggml_repeat(ctx0, model.layers[il].ff_i_b, cur),
|
||||
cur);
|
||||
cur = ggml_gelu(ctx0, cur);
|
||||
|
||||
// layer_output = self.output(intermediate_output, attention_output)
|
||||
cur = ggml_mul_mat(ctx0, model.layers[il].ff_o_w, cur);
|
||||
cur = ggml_add(ctx0,
|
||||
ggml_repeat(ctx0, model.layers[il].ff_o_b, cur),
|
||||
cur);
|
||||
// attentions bypass the intermediate layer
|
||||
cur = ggml_add(ctx0, att_output, cur);
|
||||
|
||||
// output norm
|
||||
{
|
||||
cur = ggml_norm(ctx0, cur, 1e-5f);
|
||||
|
||||
cur = ggml_add(ctx0,
|
||||
ggml_mul(ctx0,
|
||||
ggml_repeat(ctx0, model.layers[il].ln_out_w, cur),
|
||||
cur),
|
||||
ggml_repeat(ctx0, model.layers[il].ln_out_b, cur));
|
||||
}
|
||||
inpL = cur;
|
||||
}
|
||||
inpL = ggml_cont(ctx0, ggml_transpose(ctx0, inpL));
|
||||
// pooler
|
||||
struct ggml_tensor *sum = ggml_new_tensor_2d(ctx0, GGML_TYPE_F32, N, 1);
|
||||
ggml_set_f32(sum, 1.0f / N);
|
||||
inpL = ggml_mul_mat(ctx0, inpL, sum);
|
||||
|
||||
ggml_tensor *output = inpL;
|
||||
// run the computation
|
||||
ggml_build_forward_expand(&gf, output);
|
||||
//ggml_graph_compute_g4a()
|
||||
ggml_graph_compute_g4a(ctx->work_buf, &gf, n_threads);
|
||||
//ggml_graph_compute(ctx0, &gf);
|
||||
|
||||
|
||||
// float *dat = ggml_get_data_f32(output);
|
||||
// pretty_print_tensor(dat, output->ne, output->nb, output->n_dims - 1, "");
|
||||
|
||||
#ifdef GGML_PERF
|
||||
// print timing information per ggml operation (for debugging purposes)
|
||||
// requires GGML_PERF to be defined
|
||||
ggml_graph_print(&gf);
|
||||
#endif
|
||||
|
||||
if (!mem_req_mode) {
|
||||
memcpy(embeddings, (float *)ggml_get_data(output), sizeof(float) * n_embd);
|
||||
} else {
|
||||
mem_per_token = ggml_used_mem(ctx0) / N;
|
||||
}
|
||||
|
||||
// printf("used_mem = %zu KB \n", ggml_used_mem(ctx0) / 1024);
|
||||
// printf("mem_per_token = %zu KB \n", mem_per_token / 1024);
|
||||
|
||||
ggml_free(ctx0);
|
||||
}
|
||||
|
||||
//
|
||||
// Loading and setup
|
||||
//
|
||||
|
||||
void bert_free(bert_ctx * ctx) {
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
struct bert_ctx * bert_load_from_file(const char *fname)
|
||||
{
|
||||
#if defined(DEBUG_BERT)
|
||||
printf("%s: loading model from '%s' - please wait ...\n", __func__, fname);
|
||||
#endif
|
||||
|
||||
bert_ctx * new_bert = new bert_ctx;
|
||||
bert_model & model = new_bert->model;
|
||||
bert_vocab & vocab = new_bert->vocab;
|
||||
|
||||
struct gguf_init_params params = {
|
||||
/*.no_alloc = */ false,
|
||||
/*.ctx = */ &model.ctx,
|
||||
};
|
||||
gguf_context *ggufctx = gguf_init_from_file(fname, params);
|
||||
if (!ggufctx) {
|
||||
fprintf(stderr, "%s: gguf_init_from_file() failed\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
printf("%s: gguf version = %d\n", __func__, gguf_get_version(ggufctx));
|
||||
printf("%s: gguf alignment = %zu\n", __func__, gguf_get_alignment(ggufctx));
|
||||
printf("%s: gguf data offset = %zu\n", __func__, gguf_get_data_offset(ggufctx));
|
||||
|
||||
// print some standard metadata
|
||||
{
|
||||
int keyidx;
|
||||
|
||||
keyidx = gguf_find_key(ggufctx, "general.name");
|
||||
if (keyidx != -1) { printf("%s: model name = %s\n", __func__, gguf_get_val_str(ggufctx, keyidx)); }
|
||||
keyidx = gguf_find_key(ggufctx, "general.description");
|
||||
if (keyidx != -1) { printf("%s: model description = %s\n", __func__, gguf_get_val_str(ggufctx, keyidx)); }
|
||||
keyidx = gguf_find_key(ggufctx, "general.author");
|
||||
if (keyidx != -1) { printf("%s: model author = %s\n", __func__, gguf_get_val_str(ggufctx, keyidx)); }
|
||||
keyidx = gguf_find_key(ggufctx, "general.license");
|
||||
if (keyidx != -1) { printf("%s: model license = %s\n", __func__, gguf_get_val_str(ggufctx, keyidx)); }
|
||||
keyidx = gguf_find_key(ggufctx, "general.architecture");
|
||||
if (keyidx != -1) { printf("%s: model architecture = %s\n", __func__, gguf_get_val_str(ggufctx, keyidx)); }
|
||||
keyidx = gguf_find_key(ggufctx, "general.file_type");
|
||||
if (keyidx != -1) { printf("%s: model file type = %" PRIu32 "\n", __func__, gguf_get_val_u32(ggufctx, keyidx)); }
|
||||
keyidx = gguf_find_key(ggufctx, "gptneox.tensor_data_layout");
|
||||
if (keyidx != -1) { printf("%s: model data layout = %s\n", __func__, gguf_get_val_str(ggufctx, keyidx)); }
|
||||
keyidx = gguf_find_key(ggufctx, "general.source.huggingface.repository");
|
||||
if (keyidx != -1) { printf("%s: model source HF repo = %s\n", __func__, gguf_get_val_str(ggufctx, keyidx)); }
|
||||
}
|
||||
|
||||
// check required metadata
|
||||
{
|
||||
// check model architecture kv
|
||||
int keyidx = gguf_find_key(ggufctx, "general.architecture");
|
||||
if (keyidx == -1) {
|
||||
fprintf(stderr, "%s: gguf model architecture not found!\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
if (strcmp(gguf_get_val_str(ggufctx, keyidx), "bert") != 0) {
|
||||
fprintf(stderr, "%s: model architecture not supported!\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// load hparams
|
||||
{
|
||||
auto &hparams = model.hparams;
|
||||
|
||||
bool ok = false;
|
||||
int keyidx;
|
||||
|
||||
do {
|
||||
keyidx = gguf_find_key(ggufctx, "bert.context_length");
|
||||
if (keyidx == -1) { break; }
|
||||
hparams.n_max_tokens = gguf_get_val_u32(ggufctx, keyidx);
|
||||
|
||||
keyidx = gguf_find_key(ggufctx, "bert.embedding_length");
|
||||
if (keyidx == -1) { break; }
|
||||
hparams.n_embd = gguf_get_val_u32(ggufctx, keyidx);
|
||||
|
||||
keyidx = gguf_find_key(ggufctx, "bert.feed_forward_length");
|
||||
if (keyidx == -1) { break; }
|
||||
hparams.n_intermediate = gguf_get_val_u32(ggufctx, keyidx);
|
||||
|
||||
keyidx = gguf_find_key(ggufctx, "bert.attention.head_count");
|
||||
if (keyidx == -1) { break; }
|
||||
hparams.n_head = gguf_get_val_u32(ggufctx, keyidx);
|
||||
|
||||
keyidx = gguf_find_key(ggufctx, "bert.block_count");
|
||||
if (keyidx == -1) { break; }
|
||||
hparams.n_layer = gguf_get_val_u32(ggufctx, keyidx);
|
||||
|
||||
ok = true;
|
||||
} while (false);
|
||||
|
||||
if (!ok) {
|
||||
fprintf(stderr, "%s: required hparam missing!\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_BERT)
|
||||
printf("%s: n_max_tokens = %d\n", __func__, hparams.n_max_tokens);
|
||||
printf("%s: n_embd = %d\n", __func__, hparams.n_embd);
|
||||
printf("%s: n_intermediate = %d\n", __func__, hparams.n_intermediate);
|
||||
printf("%s: n_head = %d\n", __func__, hparams.n_head);
|
||||
printf("%s: n_layer = %d\n", __func__, hparams.n_layer);
|
||||
#endif
|
||||
}
|
||||
|
||||
// load vocab
|
||||
{
|
||||
auto & hparams = model.hparams;
|
||||
|
||||
int keyidx = gguf_find_key(ggufctx, "tokenizer.ggml.model");
|
||||
if (keyidx == -1) {
|
||||
fprintf(stderr, "%s: tokenizer model not found!\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
if (strcmp(gguf_get_val_str(ggufctx, keyidx), "bert") != 0) {
|
||||
fprintf(stderr, "%s: tokenizer model not supported!\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int tokens_keyidx = gguf_find_key(ggufctx, "tokenizer.ggml.tokens");
|
||||
if (tokens_keyidx == -1) {
|
||||
fprintf(stderr, "%s: bert tokenizer vocab not found!\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hparams.n_vocab = gguf_get_arr_n(ggufctx, tokens_keyidx);
|
||||
printf("%s: bert tokenizer vocab = %d\n", __func__, int(hparams.n_vocab));
|
||||
|
||||
for (int i = 0; i < hparams.n_vocab; i++) {
|
||||
std::string word = gguf_get_arr_str(ggufctx, tokens_keyidx, i);
|
||||
|
||||
if (word[0] == '#' && word[1] == '#')
|
||||
{
|
||||
vocab.subword_token_to_id[word.substr(2)] = i;
|
||||
vocab._id_to_subword_token[i] = word;
|
||||
}
|
||||
|
||||
if (vocab.token_to_id.count(word) == 0)
|
||||
{
|
||||
vocab.token_to_id[word] = i;
|
||||
vocab._id_to_token[i] = word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto &ctx = model.ctx;
|
||||
|
||||
#if defined(DEBUG_BERT)
|
||||
printf("%s: ggml ctx size = %6.2f MB\n", __func__, ggml_get_mem_size(ctx) / (1024.0 * 1024.0));
|
||||
#endif
|
||||
|
||||
// prepare memory for the weights
|
||||
{
|
||||
const int n_layer = model.hparams.n_layer;
|
||||
model.layers.resize(n_layer);
|
||||
|
||||
model.word_embeddings = ggml_get_tensor(ctx, "token_embd.weight");
|
||||
model.token_type_embeddings = ggml_get_tensor(ctx, "token_types.weight");
|
||||
model.position_embeddings = ggml_get_tensor(ctx, "position_embd.weight");
|
||||
model.ln_e_w = ggml_get_tensor(ctx, "output_norm.weight");
|
||||
model.ln_e_b = ggml_get_tensor(ctx, "output_norm.bias");
|
||||
|
||||
auto name = [](int i, std::string n) {
|
||||
static std::string key;
|
||||
key = "blk." + std::to_string(i) + "." + n;
|
||||
return key.c_str();
|
||||
};
|
||||
|
||||
for (int i = 0; i < n_layer; ++i)
|
||||
{
|
||||
auto &layer = model.layers[i];
|
||||
|
||||
layer.ln_att_w = ggml_get_tensor(ctx, name(i, "attn_norm.weight"));
|
||||
layer.ln_att_b = ggml_get_tensor(ctx, name(i, "attn_norm.bias"));
|
||||
layer.ln_out_w = ggml_get_tensor(ctx, name(i, "ffn_norm.weight"));
|
||||
layer.ln_out_b = ggml_get_tensor(ctx, name(i, "ffn_norm.bias"));
|
||||
layer.q_w = ggml_get_tensor(ctx, name(i, "attn_q.weight"));
|
||||
layer.q_b = ggml_get_tensor(ctx, name(i, "attn_q.bias"));
|
||||
layer.k_w = ggml_get_tensor(ctx, name(i, "attn_k.weight"));
|
||||
layer.k_b = ggml_get_tensor(ctx, name(i, "attn_k.bias"));
|
||||
layer.v_w = ggml_get_tensor(ctx, name(i, "attn_v.weight"));
|
||||
layer.v_b = ggml_get_tensor(ctx, name(i, "attn_v.bias"));
|
||||
layer.o_w = ggml_get_tensor(ctx, name(i, "attn_output.weight"));
|
||||
layer.o_b = ggml_get_tensor(ctx, name(i, "attn_output.bias"));
|
||||
layer.ff_i_w = ggml_get_tensor(ctx, name(i, "ffn_up.weight"));
|
||||
layer.ff_i_b = ggml_get_tensor(ctx, name(i, "ffn_up.bias"));
|
||||
layer.ff_o_w = ggml_get_tensor(ctx, name(i, "ffn_down.weight"));
|
||||
layer.ff_o_b = ggml_get_tensor(ctx, name(i, "ffn_down.bias"));
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate space requirements for setting up context buffers later
|
||||
{
|
||||
bert_vocab_id tokens[] = {0, 1, 2, 3};
|
||||
// TODO: We set the initial buffer size to 16MB and hope it's enough. Maybe there is a better way to do this?
|
||||
new_bert->buf_compute.resize(16 * 1024 * 1024);
|
||||
bert_eval(new_bert, 1, tokens, 4, nullptr);
|
||||
new_bert->max_batch_n = 0;
|
||||
|
||||
// TODO: Max tokens should be a param?
|
||||
int32_t N = new_bert->model.hparams.n_max_tokens;
|
||||
new_bert->mem_per_input = 2.2 * (new_bert->mem_per_token * N); // add 10% to account for ggml object overhead
|
||||
|
||||
}
|
||||
#if defined(DEBUG_BERT)
|
||||
printf("%s: mem_per_token %ld KB, mem_per_input %ld MB\n", __func__, new_bert->mem_per_token / (1 << 10), new_bert->mem_per_input / (1 << 20));
|
||||
#endif
|
||||
|
||||
return new_bert;
|
||||
}
|
||||
|
||||
struct BertPrivate {
|
||||
const std::string modelPath;
|
||||
bool modelLoaded;
|
||||
bert_ctx *ctx = nullptr;
|
||||
int64_t n_threads = 0;
|
||||
};
|
||||
|
||||
Bert::Bert() : d_ptr(new BertPrivate) {
|
||||
d_ptr->modelLoaded = false;
|
||||
}
|
||||
|
||||
Bert::~Bert() {
|
||||
bert_free(d_ptr->ctx);
|
||||
}
|
||||
|
||||
bool Bert::loadModel(const std::string &modelPath)
|
||||
{
|
||||
d_ptr->ctx = bert_load_from_file(modelPath.c_str());
|
||||
d_ptr->n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency());
|
||||
d_ptr->modelLoaded = d_ptr->ctx != nullptr;
|
||||
fflush(stdout);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bert::isModelLoaded() const
|
||||
{
|
||||
return d_ptr->modelLoaded;
|
||||
}
|
||||
|
||||
size_t Bert::requiredMem(const std::string &/*modelPath*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Bert::stateSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Bert::saveState(uint8_t */*dest*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Bert::restoreState(const uint8_t */*src*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Bert::setThreadCount(int32_t n_threads)
|
||||
{
|
||||
d_ptr->n_threads = n_threads;
|
||||
}
|
||||
|
||||
int32_t Bert::threadCount() const
|
||||
{
|
||||
return d_ptr->n_threads;
|
||||
}
|
||||
|
||||
std::vector<float> Bert::embedding(const std::string &text)
|
||||
{
|
||||
const int overlap = 32;
|
||||
const LLModel::Token clsToken = 101;
|
||||
const size_t contextLength = bert_n_max_tokens(d_ptr->ctx);
|
||||
typedef std::vector<LLModel::Token> TokenString;
|
||||
TokenString tokens = ::bert_tokenize(d_ptr->ctx, text.c_str());
|
||||
#if defined(DEBUG_BERT)
|
||||
std::cerr << "embedding: " << tokens.size()
|
||||
<< " contextLength " << contextLength
|
||||
<< "\n";
|
||||
#endif
|
||||
std::vector<double> embeddingsSum(bert_n_embd(d_ptr->ctx), 0);
|
||||
int embeddingsSumTotal = 0;
|
||||
size_t start_pos = 0;
|
||||
bool isFirstChunk = true;
|
||||
while (start_pos < tokens.size()) {
|
||||
TokenString chunk;
|
||||
if (!isFirstChunk)
|
||||
chunk.push_back(clsToken);
|
||||
const size_t l = isFirstChunk ? contextLength : contextLength - 1;
|
||||
if (tokens.size() - start_pos > l) {
|
||||
chunk.insert(chunk.end(), tokens.begin() + start_pos, tokens.begin() + start_pos + l);
|
||||
start_pos = start_pos + contextLength - overlap;
|
||||
} else {
|
||||
chunk.insert(chunk.end(), tokens.begin() + start_pos, tokens.end());
|
||||
start_pos = tokens.size();
|
||||
}
|
||||
#if defined(DEBUG_BERT)
|
||||
std::cerr << "chunk length: " << chunk.size()
|
||||
<< " embeddingsSumTotal " << embeddingsSumTotal
|
||||
<< " contextLength " << contextLength
|
||||
<< " start_pos " << start_pos
|
||||
<< "\n";
|
||||
#endif
|
||||
embeddingsSumTotal++;
|
||||
std::vector<float> embeddings(bert_n_embd(d_ptr->ctx));
|
||||
bert_eval(d_ptr->ctx, d_ptr->n_threads, chunk.data(), chunk.size(), embeddings.data());
|
||||
std::transform(embeddingsSum.begin(), embeddingsSum.end(), embeddings.begin(), embeddingsSum.begin(), std::plus<float>());
|
||||
isFirstChunk = false;
|
||||
}
|
||||
|
||||
std::transform(embeddingsSum.begin(), embeddingsSum.end(), embeddingsSum.begin(), [embeddingsSumTotal](float num){ return num / embeddingsSumTotal; });
|
||||
double magnitude = std::sqrt(std::inner_product(embeddingsSum.begin(), embeddingsSum.end(), embeddingsSum.begin(), 0.0));
|
||||
for (auto &value : embeddingsSum)
|
||||
value /= magnitude;
|
||||
std::vector<float> finalEmbeddings(embeddingsSum.begin(), embeddingsSum.end());
|
||||
return finalEmbeddings;
|
||||
}
|
||||
|
||||
std::vector<LLModel::Token> Bert::tokenize(PromptContext &, const std::string &str) const
|
||||
{
|
||||
return ::bert_tokenize(d_ptr->ctx, str.c_str());
|
||||
}
|
||||
|
||||
LLModel::Token Bert::sampleToken(PromptContext &/*promptCtx*/) const
|
||||
{
|
||||
return 999 /*!*/;
|
||||
}
|
||||
|
||||
std::string Bert::tokenToString(Token id) const
|
||||
{
|
||||
return bert_vocab_id_to_token(d_ptr->ctx, id);
|
||||
}
|
||||
|
||||
bool Bert::evalTokens(PromptContext &ctx, const std::vector<int32_t> &tokens) const
|
||||
{
|
||||
std::vector<float> embeddings(bert_n_embd(d_ptr->ctx));
|
||||
int32_t cls = 101;
|
||||
const bool useCLS = tokens.front() != cls;
|
||||
if (useCLS) {
|
||||
std::vector<int32_t> myTokens;
|
||||
myTokens.push_back(cls);
|
||||
myTokens.insert(myTokens.end(), tokens.begin(), tokens.end());
|
||||
bert_eval(d_ptr->ctx, d_ptr->n_threads, myTokens.data(), myTokens.size(), embeddings.data());
|
||||
} else
|
||||
bert_eval(d_ptr->ctx, d_ptr->n_threads, tokens.data(), tokens.size(), embeddings.data());
|
||||
ctx.n_past = 0; // bert does not store any context
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t Bert::contextLength() const
|
||||
{
|
||||
return bert_n_max_tokens(d_ptr->ctx);
|
||||
}
|
||||
|
||||
const std::vector<LLModel::Token> &Bert::endTokens() const
|
||||
{
|
||||
static const std::vector<LLModel::Token> out = { 102 /*sep*/};
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string get_arch_name(gguf_context *ctx_gguf) {
|
||||
std::string arch_name;
|
||||
const int kid = gguf_find_key(ctx_gguf, "general.architecture");
|
||||
enum gguf_type ktype = gguf_get_kv_type(ctx_gguf, kid);
|
||||
if (ktype != GGUF_TYPE_STRING) {
|
||||
throw std::runtime_error("ERROR: Can't get general architecture from gguf file.");
|
||||
}
|
||||
return gguf_get_val_str(ctx_gguf, kid);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define DLL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define DLL_EXPORT __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
DLL_EXPORT bool is_g4a_backend_model_implementation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
DLL_EXPORT const char *get_model_type() {
|
||||
return modelType_;
|
||||
}
|
||||
|
||||
DLL_EXPORT const char *get_build_variant() {
|
||||
return GGML_BUILD_VARIANT;
|
||||
}
|
||||
|
||||
DLL_EXPORT bool magic_match(const char * fname) {
|
||||
struct ggml_context * ctx_meta = NULL;
|
||||
struct gguf_init_params params = {
|
||||
/*.no_alloc = */ true,
|
||||
/*.ctx = */ &ctx_meta,
|
||||
};
|
||||
gguf_context *ctx_gguf = gguf_init_from_file(fname, params);
|
||||
if (!ctx_gguf)
|
||||
return false;
|
||||
|
||||
bool isValid = gguf_get_version(ctx_gguf) <= 2;
|
||||
isValid = isValid && get_arch_name(ctx_gguf) == "bert";
|
||||
|
||||
gguf_free(ctx_gguf);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
DLL_EXPORT LLModel *construct() {
|
||||
return new Bert;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef BERT_H_I_KNOW_WHAT_I_AM_DOING_WHEN_INCLUDING_THIS_FILE
|
||||
#error This file is NOT meant to be included outside of bert.cpp. Doing so is DANGEROUS. Be sure to know what you are doing before proceeding to #define BERT_H_I_KNOW_WHAT_I_AM_DOING_WHEN_INCLUDING_THIS_FILE
|
||||
#endif
|
||||
#ifndef BERT_H
|
||||
#define BERT_H
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "llmodel.h"
|
||||
|
||||
struct BertPrivate;
|
||||
class Bert : public LLModel {
|
||||
public:
|
||||
Bert();
|
||||
~Bert();
|
||||
|
||||
bool supportsEmbedding() const override { return true; }
|
||||
bool supportsCompletion() const override { return true; }
|
||||
bool loadModel(const std::string &modelPath) override;
|
||||
bool isModelLoaded() const override;
|
||||
size_t requiredMem(const std::string &modelPath) override;
|
||||
size_t stateSize() const override;
|
||||
size_t saveState(uint8_t *dest) const override;
|
||||
size_t restoreState(const uint8_t *src) override;
|
||||
void setThreadCount(int32_t n_threads) override;
|
||||
int32_t threadCount() const override;
|
||||
|
||||
std::vector<float> embedding(const std::string &text) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<BertPrivate> d_ptr;
|
||||
|
||||
protected:
|
||||
std::vector<Token> tokenize(PromptContext &, const std::string&) const override;
|
||||
Token sampleToken(PromptContext &ctx) const override;
|
||||
std::string tokenToString(Token) const override;
|
||||
bool evalTokens(PromptContext &ctx, const std::vector<int32_t> &tokens) const override;
|
||||
int32_t contextLength() const override;
|
||||
const std::vector<Token>& endTokens() const override;
|
||||
};
|
||||
|
||||
#endif // BERT_H
|
||||
73
gpt4all-backend/dlhandle.cpp
Normal file
73
gpt4all-backend/dlhandle.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "dlhandle.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <dlfcn.h>
|
||||
#else
|
||||
# include <cassert>
|
||||
# include <sstream>
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace std::string_literals;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
Dlhandle::Dlhandle(const fs::path &fpath)
|
||||
{
|
||||
chandle = dlopen(fpath.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!chandle) {
|
||||
throw Exception("dlopen: "s + dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
Dlhandle::~Dlhandle()
|
||||
{
|
||||
if (chandle) dlclose(chandle);
|
||||
}
|
||||
|
||||
void *Dlhandle::get_internal(const char *symbol) const
|
||||
{
|
||||
return dlsym(chandle, symbol);
|
||||
}
|
||||
|
||||
#else // defined(_WIN32)
|
||||
|
||||
Dlhandle::Dlhandle(const fs::path &fpath)
|
||||
{
|
||||
fs::path afpath = fs::absolute(fpath);
|
||||
|
||||
// Suppress the "Entry Point Not Found" dialog, caused by outdated nvcuda.dll from the GPU driver
|
||||
UINT lastErrorMode = GetErrorMode();
|
||||
SetErrorMode(lastErrorMode | SEM_FAILCRITICALERRORS);
|
||||
|
||||
chandle = LoadLibraryExW(afpath.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
|
||||
SetErrorMode(lastErrorMode);
|
||||
|
||||
if (!chandle) {
|
||||
DWORD err = GetLastError();
|
||||
std::ostringstream ss;
|
||||
ss << "LoadLibraryExW failed with error 0x" << std::hex << err;
|
||||
throw Exception(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
Dlhandle::~Dlhandle()
|
||||
{
|
||||
if (chandle) FreeLibrary(HMODULE(chandle));
|
||||
}
|
||||
|
||||
void *Dlhandle::get_internal(const char *symbol) const
|
||||
{
|
||||
return GetProcAddress(HMODULE(chandle), symbol);
|
||||
}
|
||||
|
||||
#endif // defined(_WIN32)
|
||||
@@ -1,15 +1,15 @@
|
||||
#ifndef DLHANDLE_H
|
||||
#define DLHANDLE_H
|
||||
#ifndef _WIN32
|
||||
#include <string>
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <dlfcn.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
|
||||
class Dlhandle {
|
||||
void *chandle;
|
||||
void *chandle = nullptr;
|
||||
|
||||
public:
|
||||
class Exception : public std::runtime_error {
|
||||
@@ -17,88 +17,31 @@ public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
Dlhandle() : chandle(nullptr) {}
|
||||
Dlhandle(const std::string& fpath, int flags = RTLD_LAZY | RTLD_LOCAL) {
|
||||
chandle = dlopen(fpath.c_str(), flags);
|
||||
if (!chandle) {
|
||||
throw Exception("dlopen(\""+fpath+"\"): "+dlerror());
|
||||
}
|
||||
}
|
||||
Dlhandle(const Dlhandle& o) = delete;
|
||||
Dlhandle(Dlhandle&& o) : chandle(o.chandle) {
|
||||
Dlhandle() = default;
|
||||
Dlhandle(const fs::path &fpath);
|
||||
Dlhandle(const Dlhandle &o) = delete;
|
||||
Dlhandle(Dlhandle &&o)
|
||||
: chandle(o.chandle)
|
||||
{
|
||||
o.chandle = nullptr;
|
||||
}
|
||||
~Dlhandle() {
|
||||
if (chandle) dlclose(chandle);
|
||||
}
|
||||
|
||||
auto operator =(Dlhandle&& o) {
|
||||
~Dlhandle();
|
||||
|
||||
Dlhandle &operator=(Dlhandle &&o) {
|
||||
chandle = std::exchange(o.chandle, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return chandle != nullptr;
|
||||
}
|
||||
operator bool() const {
|
||||
return is_valid();
|
||||
template <typename T>
|
||||
T *get(const std::string &symbol) const {
|
||||
return reinterpret_cast<T *>(get_internal(symbol.c_str()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* get(const std::string& fname) const {
|
||||
auto fres = reinterpret_cast<T*>(dlsym(chandle, fname.c_str()));
|
||||
return (dlerror()==NULL)?fres:nullptr;
|
||||
}
|
||||
auto get_fnc(const std::string& fname) const {
|
||||
return get<void*(...)>(fname);
|
||||
auto get_fnc(const std::string &symbol) const {
|
||||
return get<void*(...)>(symbol);
|
||||
}
|
||||
|
||||
private:
|
||||
void *get_internal(const char *symbol) const;
|
||||
};
|
||||
#else
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <libloaderapi.h>
|
||||
|
||||
|
||||
|
||||
class Dlhandle {
|
||||
HMODULE chandle;
|
||||
|
||||
public:
|
||||
class Exception : public std::runtime_error {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
Dlhandle() : chandle(nullptr) {}
|
||||
Dlhandle(const std::string& fpath) {
|
||||
chandle = LoadLibraryExA(fpath.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
if (!chandle) {
|
||||
throw Exception("dlopen(\""+fpath+"\"): Error");
|
||||
}
|
||||
}
|
||||
Dlhandle(const Dlhandle& o) = delete;
|
||||
Dlhandle(Dlhandle&& o) : chandle(o.chandle) {
|
||||
o.chandle = nullptr;
|
||||
}
|
||||
~Dlhandle() {
|
||||
if (chandle) FreeLibrary(chandle);
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return chandle != nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* get(const std::string& fname) const {
|
||||
return reinterpret_cast<T*>(GetProcAddress(chandle, fname.c_str()));
|
||||
}
|
||||
auto get_fnc(const std::string& fname) const {
|
||||
return get<void*(...)>(fname);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif // DLHANDLE_H
|
||||
|
||||
@@ -1,33 +1,28 @@
|
||||
#define GPTJ_H_I_KNOW_WHAT_I_AM_DOING_WHEN_INCLUDING_THIS_FILE
|
||||
#include "gptj_impl.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "llmodel.h"
|
||||
#include "llmodel_shared.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <ggml.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include <ggml.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
const char *modelType_ = "GPT-J";
|
||||
@@ -128,7 +123,8 @@ static bool kv_cache_init(
|
||||
}
|
||||
|
||||
// load the model's weights from a file path
|
||||
bool gptj_model_load(const std::string &fname, gptj_model & model, gpt_vocab & vocab, size_t * mem_req = nullptr) {
|
||||
bool gptj_model_load(const std::string &fname, gptj_model & model, gpt_vocab & vocab, size_t * mem_req = nullptr)
|
||||
{
|
||||
printf("%s: loading model from '%s' - please wait ...\n", __func__, fname.c_str());
|
||||
if(mem_req != nullptr) {
|
||||
*mem_req = 0;
|
||||
@@ -343,7 +339,14 @@ bool gptj_eval(
|
||||
};
|
||||
|
||||
struct ggml_context * ctx0 = ggml_init(params);
|
||||
struct ggml_cgraph gf = {};
|
||||
struct ggml_cgraph * gf = ggml_new_graph(ctx0);
|
||||
|
||||
// KQ_pos - contains the positions
|
||||
struct ggml_tensor * KQ_pos = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, N);
|
||||
int * data = (int *) KQ_pos->data;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
data[i] = n_past + i;
|
||||
}
|
||||
|
||||
struct ggml_tensor * embd = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, N);
|
||||
memcpy(embd->data, embd_inp.data(), N*ggml_element_size(embd));
|
||||
@@ -370,8 +373,14 @@ bool gptj_eval(
|
||||
|
||||
// self-attention
|
||||
{
|
||||
struct ggml_tensor * Qcur = ggml_rope(ctx0, ggml_reshape_3d(ctx0, ggml_mul_mat(ctx0, model.layers[il].c_attn_q_proj_w, cur), n_embd/n_head, n_head, N), n_past, n_rot, 0, 0);
|
||||
struct ggml_tensor * Kcur = ggml_rope(ctx0, ggml_reshape_3d(ctx0, ggml_mul_mat(ctx0, model.layers[il].c_attn_k_proj_w, cur), n_embd/n_head, n_head, N), n_past, n_rot, 0, 0);
|
||||
struct ggml_tensor * Qcur = ggml_rope(
|
||||
ctx0, ggml_reshape_3d(ctx0, ggml_mul_mat(ctx0, model.layers[il].c_attn_q_proj_w, cur), n_embd/n_head, n_head, N),
|
||||
KQ_pos, n_rot, 0, 0
|
||||
);
|
||||
struct ggml_tensor * Kcur = ggml_rope(
|
||||
ctx0, ggml_reshape_3d(ctx0, ggml_mul_mat(ctx0, model.layers[il].c_attn_k_proj_w, cur), n_embd/n_head, n_head, N),
|
||||
KQ_pos, n_rot, 0, 0
|
||||
);
|
||||
|
||||
// store key and value to memory
|
||||
{
|
||||
@@ -382,8 +391,8 @@ bool gptj_eval(
|
||||
( n_ctx)*ggml_element_size(model.kv_self.v),
|
||||
(il*n_ctx)*ggml_element_size(model.kv_self.v)*n_embd + n_past*ggml_element_size(model.kv_self.v));
|
||||
|
||||
ggml_build_forward_expand(&gf, ggml_cpy(ctx0, Kcur, k));
|
||||
ggml_build_forward_expand(&gf, ggml_cpy(ctx0, Vcur, v));
|
||||
ggml_build_forward_expand(gf, ggml_cpy(ctx0, Kcur, k));
|
||||
ggml_build_forward_expand(gf, ggml_cpy(ctx0, Vcur, v));
|
||||
}
|
||||
|
||||
// Q = Qcur.contiguous().view(n_embd/n_head, n_head, N).permute(0, 2, 1, 3)
|
||||
@@ -401,11 +410,7 @@ bool gptj_eval(
|
||||
struct ggml_tensor * KQ = ggml_mul_mat(ctx0, K, Q);
|
||||
|
||||
// KQ_scaled = KQ / sqrt(n_embd/n_head)
|
||||
struct ggml_tensor * KQ_scaled =
|
||||
ggml_scale(ctx0,
|
||||
KQ,
|
||||
ggml_new_f32(ctx0, 1.0f/sqrt(float(n_embd)/n_head))
|
||||
);
|
||||
struct ggml_tensor * KQ_scaled = ggml_scale(ctx0, KQ, 1.0f/sqrt(float(n_embd)/n_head));
|
||||
|
||||
// KQ_masked = mask_past(KQ_scaled)
|
||||
struct ggml_tensor * KQ_masked = ggml_diag_mask_inf(ctx0, KQ_scaled, n_past);
|
||||
@@ -502,22 +507,22 @@ bool gptj_eval(
|
||||
// logits -> probs
|
||||
//inpL = ggml_soft_max(ctx0, inpL);
|
||||
|
||||
ggml_build_forward_expand(&gf, inpL);
|
||||
ggml_build_forward_expand(gf, inpL);
|
||||
|
||||
// run the computation
|
||||
{
|
||||
std::unique_ptr<uint8_t []> data;
|
||||
auto plan = ggml_graph_plan(&gf, n_threads);
|
||||
auto plan = ggml_graph_plan(gf, n_threads);
|
||||
if (plan.work_size > 0) {
|
||||
data.reset(new uint8_t[plan.work_size]);
|
||||
plan.work_data = data.get();
|
||||
}
|
||||
ggml_graph_compute(&gf, &plan);
|
||||
ggml_graph_compute(gf, &plan);
|
||||
}
|
||||
|
||||
//if (n_past%100 == 0) {
|
||||
// ggml_graph_print (&gf);
|
||||
// ggml_graph_dump_dot(&gf, NULL, "gpt-2.dot");
|
||||
// ggml_graph_print (gf);
|
||||
// ggml_graph_dump_dot(gf, NULL, "gpt-2.dot");
|
||||
//}
|
||||
|
||||
//embd_w.resize(n_vocab*N);
|
||||
@@ -663,7 +668,10 @@ GPTJ::GPTJ()
|
||||
d_ptr->modelLoaded = false;
|
||||
}
|
||||
|
||||
size_t GPTJ::requiredMem(const std::string &modelPath) {
|
||||
size_t GPTJ::requiredMem(const std::string &modelPath, int n_ctx, int ngl)
|
||||
{
|
||||
(void)n_ctx;
|
||||
(void)ngl;
|
||||
gptj_model dummy_model;
|
||||
gpt_vocab dummy_vocab;
|
||||
size_t mem_req;
|
||||
@@ -671,23 +679,30 @@ size_t GPTJ::requiredMem(const std::string &modelPath) {
|
||||
return mem_req;
|
||||
}
|
||||
|
||||
bool GPTJ::loadModel(const std::string &modelPath) {
|
||||
bool GPTJ::loadModel(const std::string &modelPath, int n_ctx, int ngl)
|
||||
{
|
||||
(void)n_ctx;
|
||||
(void)ngl;
|
||||
d_ptr->modelLoaded = false;
|
||||
|
||||
std::mt19937 rng(time(NULL));
|
||||
d_ptr->rng = rng;
|
||||
|
||||
// load the model
|
||||
if (!gptj_model_load(modelPath, *d_ptr->model, d_ptr->vocab)) {
|
||||
bool ok = gptj_model_load(modelPath, *d_ptr->model, d_ptr->vocab);
|
||||
fflush(stdout);
|
||||
if (!ok) {
|
||||
std::cerr << "GPT-J ERROR: failed to load model from " << modelPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
d_ptr->n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency());
|
||||
d_ptr->modelLoaded = true;
|
||||
fflush(stdout);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPTJ::setThreadCount(int32_t n_threads) {
|
||||
void GPTJ::setThreadCount(int32_t n_threads)
|
||||
{
|
||||
d_ptr->n_threads = n_threads;
|
||||
}
|
||||
|
||||
@@ -721,8 +736,10 @@ size_t GPTJ::restoreState(const uint8_t *src)
|
||||
return gptj_set_state_data(d_ptr->model, &d_ptr->rng, src);
|
||||
}
|
||||
|
||||
std::vector<LLModel::Token> GPTJ::tokenize(PromptContext &, const std::string &str) const
|
||||
std::vector<LLModel::Token> GPTJ::tokenize(PromptContext &ctx, const std::string &str, bool special) const
|
||||
{
|
||||
(void)ctx;
|
||||
(void)special;
|
||||
return ::gpt_tokenize(d_ptr->vocab, str);
|
||||
}
|
||||
|
||||
@@ -767,13 +784,16 @@ const std::vector<LLModel::Token> &GPTJ::endTokens() const
|
||||
return fres;
|
||||
}
|
||||
|
||||
std::string get_arch_name(gguf_context *ctx_gguf) {
|
||||
std::string arch_name;
|
||||
const char *get_arch_name(gguf_context *ctx_gguf)
|
||||
{
|
||||
const int kid = gguf_find_key(ctx_gguf, "general.architecture");
|
||||
if (kid == -1)
|
||||
throw std::runtime_error("key not found in model: general.architecture");
|
||||
|
||||
enum gguf_type ktype = gguf_get_kv_type(ctx_gguf, kid);
|
||||
if (ktype != GGUF_TYPE_STRING) {
|
||||
throw std::runtime_error("ERROR: Can't get general architecture from gguf file.");
|
||||
}
|
||||
if (ktype != GGUF_TYPE_STRING)
|
||||
throw std::runtime_error("key general.architecture has wrong type");
|
||||
|
||||
return gguf_get_val_str(ctx_gguf, kid);
|
||||
}
|
||||
|
||||
@@ -784,36 +804,50 @@ std::string get_arch_name(gguf_context *ctx_gguf) {
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
DLL_EXPORT bool is_g4a_backend_model_implementation() {
|
||||
DLL_EXPORT bool is_g4a_backend_model_implementation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DLL_EXPORT const char *get_model_type() {
|
||||
DLL_EXPORT const char *get_model_type()
|
||||
{
|
||||
return modelType_;
|
||||
}
|
||||
|
||||
DLL_EXPORT const char *get_build_variant() {
|
||||
DLL_EXPORT const char *get_build_variant()
|
||||
{
|
||||
return GGML_BUILD_VARIANT;
|
||||
}
|
||||
|
||||
DLL_EXPORT bool magic_match(const char * fname) {
|
||||
DLL_EXPORT char *get_file_arch(const char *fname)
|
||||
{
|
||||
struct ggml_context * ctx_meta = NULL;
|
||||
struct gguf_init_params params = {
|
||||
/*.no_alloc = */ true,
|
||||
/*.ctx = */ &ctx_meta,
|
||||
};
|
||||
gguf_context *ctx_gguf = gguf_init_from_file(fname, params);
|
||||
if (!ctx_gguf)
|
||||
return false;
|
||||
|
||||
bool isValid = gguf_get_version(ctx_gguf) <= 2;
|
||||
isValid = isValid && get_arch_name(ctx_gguf) == "gptj";
|
||||
char *arch = nullptr;
|
||||
if (ctx_gguf && gguf_get_version(ctx_gguf) <= 3) {
|
||||
try {
|
||||
arch = strdup(get_arch_name(ctx_gguf));
|
||||
} catch (const std::runtime_error &) {
|
||||
// cannot read key -> return null
|
||||
}
|
||||
}
|
||||
|
||||
gguf_free(ctx_gguf);
|
||||
return isValid;
|
||||
return arch;
|
||||
}
|
||||
|
||||
DLL_EXPORT LLModel *construct() {
|
||||
DLL_EXPORT bool is_arch_supported(const char *arch)
|
||||
{
|
||||
return !strcmp(arch, "gptj");
|
||||
}
|
||||
|
||||
DLL_EXPORT LLModel *construct()
|
||||
{
|
||||
return new GPTJ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
#ifndef GPTJ_H
|
||||
#define GPTJ_H
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "llmodel.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct GPTJPrivate;
|
||||
class GPTJ : public LLModel {
|
||||
public:
|
||||
@@ -17,9 +18,9 @@ public:
|
||||
|
||||
bool supportsEmbedding() const override { return false; }
|
||||
bool supportsCompletion() const override { return true; }
|
||||
bool loadModel(const std::string &modelPath) override;
|
||||
bool loadModel(const std::string &modelPath, int n_ctx, int ngl) override;
|
||||
bool isModelLoaded() const override;
|
||||
size_t requiredMem(const std::string &modelPath) override;
|
||||
size_t requiredMem(const std::string &modelPath, int n_ctx, int ngl) override;
|
||||
size_t stateSize() const override;
|
||||
size_t saveState(uint8_t *dest) const override;
|
||||
size_t restoreState(const uint8_t *src) override;
|
||||
@@ -30,12 +31,13 @@ private:
|
||||
GPTJPrivate *d_ptr;
|
||||
|
||||
protected:
|
||||
std::vector<Token> tokenize(PromptContext &, const std::string&) const override;
|
||||
std::vector<Token> tokenize(PromptContext &ctx, const std::string &str, bool special) const override;
|
||||
Token sampleToken(PromptContext &ctx) const override;
|
||||
std::string tokenToString(Token) const override;
|
||||
std::string tokenToString(Token id) const override;
|
||||
bool evalTokens(PromptContext &ctx, const std::vector<int32_t> &tokens) const override;
|
||||
int32_t contextLength() const override;
|
||||
const std::vector<Token>& endTokens() const override;
|
||||
const std::vector<Token> &endTokens() const override;
|
||||
bool shouldAddBOS() const override { return false; }
|
||||
};
|
||||
|
||||
#endif // GPTJ_H
|
||||
|
||||
Submodule gpt4all-backend/llama.cpp-mainline updated: a8ed8c8589...b2db03acf2
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,44 +4,68 @@
|
||||
#ifndef LLAMAMODEL_H
|
||||
#define LLAMAMODEL_H
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "llmodel.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct LLamaPrivate;
|
||||
struct EmbModelSpec;
|
||||
|
||||
class LLamaModel : public LLModel {
|
||||
public:
|
||||
LLamaModel();
|
||||
~LLamaModel();
|
||||
|
||||
bool supportsEmbedding() const override { return false; }
|
||||
bool supportsCompletion() const override { return true; }
|
||||
bool loadModel(const std::string &modelPath) override;
|
||||
bool supportsEmbedding() const override { return m_supportsEmbedding; }
|
||||
bool supportsCompletion() const override { return m_supportsCompletion; }
|
||||
bool loadModel(const std::string &modelPath, int n_ctx, int ngl) override;
|
||||
bool isModelBlacklisted(const std::string &modelPath) const override;
|
||||
bool isEmbeddingModel(const std::string &modelPath) const override;
|
||||
bool isModelLoaded() const override;
|
||||
size_t requiredMem(const std::string &modelPath) override;
|
||||
size_t requiredMem(const std::string &modelPath, int n_ctx, int ngl) override;
|
||||
size_t stateSize() const override;
|
||||
size_t saveState(uint8_t *dest) const override;
|
||||
size_t restoreState(const uint8_t *src) override;
|
||||
void setThreadCount(int32_t n_threads) override;
|
||||
int32_t threadCount() const override;
|
||||
std::vector<GPUDevice> availableGPUDevices(size_t memoryRequired) override;
|
||||
bool initializeGPUDevice(size_t memoryRequired, const std::string& device) override;
|
||||
bool initializeGPUDevice(const GPUDevice &device, std::string *unavail_reason) override;
|
||||
bool initializeGPUDevice(int device) override;
|
||||
bool hasGPUDevice() override;
|
||||
bool usingGPUDevice() override;
|
||||
std::vector<GPUDevice> availableGPUDevices(size_t memoryRequired = 0) const override;
|
||||
bool initializeGPUDevice(size_t memoryRequired, const std::string &name) const override;
|
||||
bool initializeGPUDevice(int device, std::string *unavail_reason = nullptr) const override;
|
||||
bool usingGPUDevice() const override;
|
||||
const char *backendName() const override;
|
||||
const char *gpuDeviceName() const override;
|
||||
|
||||
size_t embeddingSize() const override;
|
||||
// user-specified prefix
|
||||
void embed(const std::vector<std::string> &texts, float *embeddings, std::optional<std::string> prefix,
|
||||
int dimensionality = -1, size_t *tokenCount = nullptr, bool doMean = true, bool atlas = false,
|
||||
EmbedCancelCallback *cancelCb = nullptr) override;
|
||||
// automatic prefix
|
||||
void embed(const std::vector<std::string> &texts, float *embeddings, bool isRetrieval, int dimensionality = -1,
|
||||
size_t *tokenCount = nullptr, bool doMean = true, bool atlas = false) override;
|
||||
|
||||
private:
|
||||
LLamaPrivate *d_ptr;
|
||||
std::unique_ptr<LLamaPrivate> d_ptr;
|
||||
bool m_supportsEmbedding = false;
|
||||
bool m_supportsCompletion = false;
|
||||
|
||||
protected:
|
||||
std::vector<Token> tokenize(PromptContext &, const std::string&) const override;
|
||||
std::string tokenToString(Token) const override;
|
||||
Token sampleToken(PromptContext& ctx) const override;
|
||||
bool evalTokens(PromptContext& ctx, const std::vector<int32_t> &tokens) const override;
|
||||
std::vector<Token> tokenize(PromptContext &ctx, const std::string &str, bool special) const override;
|
||||
std::string tokenToString(Token id) const override;
|
||||
Token sampleToken(PromptContext &ctx) const override;
|
||||
bool evalTokens(PromptContext &ctx, const std::vector<int32_t> &tokens) const override;
|
||||
int32_t contextLength() const override;
|
||||
const std::vector<Token>& endTokens() const override;
|
||||
const std::vector<Token> &endTokens() const override;
|
||||
bool shouldAddBOS() const override;
|
||||
int32_t maxContextLength(std::string const &modelPath) const override;
|
||||
int32_t layerCount(std::string const &modelPath) const override;
|
||||
|
||||
void embedInternal(const std::vector<std::string> &texts, float *embeddings, std::string prefix, int dimensionality,
|
||||
size_t *tokenCount, bool doMean, bool atlas, EmbedCancelCallback *cancelCb,
|
||||
const EmbModelSpec *spec);
|
||||
};
|
||||
|
||||
#endif // LLAMAMODEL_H
|
||||
|
||||
@@ -1,48 +1,70 @@
|
||||
#include "llmodel.h"
|
||||
#include "dlhandle.h"
|
||||
#include "sysinfo.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include "dlhandle.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__aarch64__)
|
||||
# include "sysinfo.h" // for getSystemTotalRAMInBytes
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
#ifndef __APPLE__
|
||||
static const std::string DEFAULT_BACKENDS[] = {"kompute", "cpu"};
|
||||
#elif defined(__aarch64__)
|
||||
static const std::string DEFAULT_BACKENDS[] = {"metal", "cpu"};
|
||||
#else
|
||||
static const std::string DEFAULT_BACKENDS[] = {"cpu"};
|
||||
#endif
|
||||
|
||||
std::string s_implementations_search_path = ".";
|
||||
|
||||
static bool has_at_least_minimal_hardware() {
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
#ifndef _MSC_VER
|
||||
return __builtin_cpu_supports("avx");
|
||||
#else
|
||||
int cpuInfo[4];
|
||||
__cpuid(cpuInfo, 1);
|
||||
return cpuInfo[2] & (1 << 28);
|
||||
#endif
|
||||
#else
|
||||
return true; // Don't know how to handle non-x86_64
|
||||
#endif
|
||||
}
|
||||
#if !(defined(__x86_64__) || defined(_M_X64))
|
||||
// irrelevant on non-x86_64
|
||||
#define cpu_supports_avx() -1
|
||||
#define cpu_supports_avx2() -1
|
||||
#elif defined(_MSC_VER)
|
||||
// MSVC
|
||||
static int get_cpu_info(int func_id, int reg_id) {
|
||||
int info[4];
|
||||
__cpuid(info, func_id);
|
||||
return info[reg_id];
|
||||
}
|
||||
|
||||
static bool requires_avxonly() {
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
#ifndef _MSC_VER
|
||||
return !__builtin_cpu_supports("avx2");
|
||||
#else
|
||||
int cpuInfo[4];
|
||||
__cpuidex(cpuInfo, 7, 0);
|
||||
return !(cpuInfo[1] & (1 << 5));
|
||||
#endif
|
||||
// AVX via EAX=1: Processor Info and Feature Bits, bit 28 of ECX
|
||||
#define cpu_supports_avx() !!(get_cpu_info(1, 2) & (1 << 28))
|
||||
// AVX2 via EAX=7, ECX=0: Extended Features, bit 5 of EBX
|
||||
#define cpu_supports_avx2() !!(get_cpu_info(7, 1) & (1 << 5))
|
||||
#else
|
||||
return false; // Don't know how to handle non-x86_64
|
||||
// gcc/clang
|
||||
#define cpu_supports_avx() !!__builtin_cpu_supports("avx")
|
||||
#define cpu_supports_avx2() !!__builtin_cpu_supports("avx2")
|
||||
#endif
|
||||
}
|
||||
|
||||
LLModel::Implementation::Implementation(Dlhandle &&dlhandle_)
|
||||
: m_dlhandle(new Dlhandle(std::move(dlhandle_))) {
|
||||
@@ -52,14 +74,17 @@ LLModel::Implementation::Implementation(Dlhandle &&dlhandle_)
|
||||
auto get_build_variant = m_dlhandle->get<const char *()>("get_build_variant");
|
||||
assert(get_build_variant);
|
||||
m_buildVariant = get_build_variant();
|
||||
m_magicMatch = m_dlhandle->get<bool(const char*)>("magic_match");
|
||||
assert(m_magicMatch);
|
||||
m_getFileArch = m_dlhandle->get<char *(const char *)>("get_file_arch");
|
||||
assert(m_getFileArch);
|
||||
m_isArchSupported = m_dlhandle->get<bool(const char *)>("is_arch_supported");
|
||||
assert(m_isArchSupported);
|
||||
m_construct = m_dlhandle->get<LLModel *()>("construct");
|
||||
assert(m_construct);
|
||||
}
|
||||
|
||||
LLModel::Implementation::Implementation(Implementation &&o)
|
||||
: m_magicMatch(o.m_magicMatch)
|
||||
: m_getFileArch(o.m_getFileArch)
|
||||
, m_isArchSupported(o.m_isArchSupported)
|
||||
, m_construct(o.m_construct)
|
||||
, m_modelType(o.m_modelType)
|
||||
, m_buildVariant(o.m_buildVariant)
|
||||
@@ -67,38 +92,75 @@ LLModel::Implementation::Implementation(Implementation &&o)
|
||||
o.m_dlhandle = nullptr;
|
||||
}
|
||||
|
||||
LLModel::Implementation::~Implementation() {
|
||||
if (m_dlhandle) delete m_dlhandle;
|
||||
LLModel::Implementation::~Implementation()
|
||||
{
|
||||
delete m_dlhandle;
|
||||
}
|
||||
|
||||
bool LLModel::Implementation::isImplementation(const Dlhandle &dl) {
|
||||
static bool isImplementation(const Dlhandle &dl)
|
||||
{
|
||||
return dl.get<bool(uint32_t)>("is_g4a_backend_model_implementation");
|
||||
}
|
||||
|
||||
const std::vector<LLModel::Implementation> &LLModel::Implementation::implementationList() {
|
||||
// Add the CUDA Toolkit to the DLL search path on Windows.
|
||||
// This is necessary for chat.exe to find CUDA when started from Qt Creator.
|
||||
static void addCudaSearchPath()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (const auto *cudaPath = _wgetenv(L"CUDA_PATH")) {
|
||||
auto libDir = std::wstring(cudaPath) + L"\\bin";
|
||||
if (!AddDllDirectory(libDir.c_str())) {
|
||||
auto err = GetLastError();
|
||||
std::wcerr << L"AddDllDirectory(\"" << libDir << L"\") failed with error 0x" << std::hex << err << L"\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const std::vector<LLModel::Implementation> &LLModel::Implementation::implementationList()
|
||||
{
|
||||
if (cpu_supports_avx() == 0) {
|
||||
throw std::runtime_error("CPU does not support AVX");
|
||||
}
|
||||
|
||||
// NOTE: allocated on heap so we leak intentionally on exit so we have a chance to clean up the
|
||||
// individual models without the cleanup of the static list interfering
|
||||
static auto* libs = new std::vector<Implementation>([] () {
|
||||
std::vector<Implementation> fres;
|
||||
|
||||
addCudaSearchPath();
|
||||
|
||||
std::string impl_name_re = "(gptj|llamamodel-mainline)-(cpu|metal|kompute|vulkan|cuda)";
|
||||
if (cpu_supports_avx2() == 0) {
|
||||
impl_name_re += "-avxonly";
|
||||
}
|
||||
std::regex re(impl_name_re);
|
||||
auto search_in_directory = [&](const std::string& paths) {
|
||||
std::stringstream ss(paths);
|
||||
std::string path;
|
||||
// Split the paths string by the delimiter and process each path.
|
||||
while (std::getline(ss, path, ';')) {
|
||||
std::filesystem::path fs_path(path);
|
||||
std::u8string u8_path(path.begin(), path.end());
|
||||
// Iterate over all libraries
|
||||
for (const auto& f : std::filesystem::directory_iterator(fs_path)) {
|
||||
const std::filesystem::path& p = f.path();
|
||||
for (const auto &f : fs::directory_iterator(u8_path)) {
|
||||
const fs::path &p = f.path();
|
||||
|
||||
if (p.extension() != LIB_FILE_EXT) continue;
|
||||
if (!std::regex_search(p.stem().string(), re)) continue;
|
||||
|
||||
// Add to list if model implementation
|
||||
Dlhandle dl;
|
||||
try {
|
||||
Dlhandle dl(p.string());
|
||||
if (!Implementation::isImplementation(dl)) {
|
||||
continue;
|
||||
}
|
||||
fres.emplace_back(Implementation(std::move(dl)));
|
||||
} catch (...) {}
|
||||
dl = Dlhandle(p);
|
||||
} catch (const Dlhandle::Exception &e) {
|
||||
std::cerr << "Failed to load " << p.filename().string() << ": " << e.what() << "\n";
|
||||
continue;
|
||||
}
|
||||
if (!isImplementation(dl)) {
|
||||
std::cerr << "Not an implementation: " << p.filename().string() << "\n";
|
||||
continue;
|
||||
}
|
||||
fres.emplace_back(Implementation(std::move(dl)));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -111,67 +173,175 @@ const std::vector<LLModel::Implementation> &LLModel::Implementation::implementat
|
||||
return *libs;
|
||||
}
|
||||
|
||||
const LLModel::Implementation* LLModel::Implementation::implementation(const char *fname, const std::string& buildVariant) {
|
||||
for (const auto& i : implementationList()) {
|
||||
if (buildVariant != i.m_buildVariant) continue;
|
||||
if (!i.m_magicMatch(fname)) continue;
|
||||
return &i;
|
||||
static std::string applyCPUVariant(const std::string &buildVariant)
|
||||
{
|
||||
if (buildVariant != "metal" && cpu_supports_avx2() == 0) {
|
||||
return buildVariant + "-avxonly";
|
||||
}
|
||||
return nullptr;
|
||||
return buildVariant;
|
||||
}
|
||||
|
||||
LLModel *LLModel::Implementation::construct(const std::string &modelPath, std::string buildVariant) {
|
||||
if (!has_at_least_minimal_hardware()) {
|
||||
std::cerr << "LLModel ERROR: CPU does not support AVX\n";
|
||||
const LLModel::Implementation* LLModel::Implementation::implementation(const char *fname, const std::string& buildVariant)
|
||||
{
|
||||
bool buildVariantMatched = false;
|
||||
std::optional<std::string> archName;
|
||||
for (const auto& i : implementationList()) {
|
||||
if (buildVariant != i.m_buildVariant) continue;
|
||||
buildVariantMatched = true;
|
||||
|
||||
char *arch = i.m_getFileArch(fname);
|
||||
if (!arch) continue;
|
||||
archName = arch;
|
||||
|
||||
bool archSupported = i.m_isArchSupported(arch);
|
||||
free(arch);
|
||||
if (archSupported) return &i;
|
||||
}
|
||||
|
||||
if (!buildVariantMatched)
|
||||
return nullptr;
|
||||
if (!archName)
|
||||
throw UnsupportedModelError("Unsupported file format");
|
||||
|
||||
throw BadArchError(std::move(*archName));
|
||||
}
|
||||
|
||||
LLModel *LLModel::Implementation::construct(const std::string &modelPath, const std::string &backend, int n_ctx)
|
||||
{
|
||||
std::vector<std::string> desiredBackends;
|
||||
if (backend != "auto") {
|
||||
desiredBackends.push_back(backend);
|
||||
} else {
|
||||
desiredBackends.insert(desiredBackends.end(), DEFAULT_BACKENDS, std::end(DEFAULT_BACKENDS));
|
||||
}
|
||||
|
||||
for (const auto &desiredBackend: desiredBackends) {
|
||||
const auto *impl = implementation(modelPath.c_str(), applyCPUVariant(desiredBackend));
|
||||
|
||||
if (impl) {
|
||||
// Construct llmodel implementation
|
||||
auto *fres = impl->m_construct();
|
||||
fres->m_implementation = impl;
|
||||
|
||||
#if defined(__APPLE__) && defined(__aarch64__) // FIXME: See if metal works for intel macs
|
||||
/* TODO(cebtenzzre): after we fix requiredMem, we should change this to happen at
|
||||
* load time, not construct time. right now n_ctx is incorrectly hardcoded 2048 in
|
||||
* most (all?) places where this is called, causing underestimation of required
|
||||
* memory. */
|
||||
if (backend == "auto" && desiredBackend == "metal") {
|
||||
// on a 16GB M2 Mac a 13B q4_0 (0.52) works for me but a 13B q4_K_M (0.55) does not
|
||||
size_t req_mem = fres->requiredMem(modelPath, n_ctx, 100);
|
||||
if (req_mem >= size_t(0.53f * getSystemTotalRAMInBytes())) {
|
||||
delete fres;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)n_ctx;
|
||||
#endif
|
||||
|
||||
return fres;
|
||||
}
|
||||
}
|
||||
|
||||
throw MissingImplementationError("Could not find any implementations for backend: " + backend);
|
||||
}
|
||||
|
||||
LLModel *LLModel::Implementation::constructGlobalLlama(const std::optional<std::string> &backend)
|
||||
{
|
||||
static std::unordered_map<std::string, std::unique_ptr<LLModel>> implCache;
|
||||
|
||||
const std::vector<Implementation> *impls;
|
||||
try {
|
||||
impls = &implementationList();
|
||||
} catch (const std::runtime_error &e) {
|
||||
std::cerr << __func__ << ": implementationList failed: " << e.what() << "\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get correct implementation
|
||||
const Implementation* impl = nullptr;
|
||||
|
||||
#if defined(__APPLE__) && defined(__arm64__) // FIXME: See if metal works for intel macs
|
||||
if (buildVariant == "auto") {
|
||||
size_t total_mem = getSystemTotalRAMInBytes();
|
||||
impl = implementation(modelPath.c_str(), "metal");
|
||||
if(impl) {
|
||||
LLModel* metalimpl = impl->m_construct();
|
||||
metalimpl->m_implementation = impl;
|
||||
size_t req_mem = metalimpl->requiredMem(modelPath);
|
||||
float req_to_total = (float) req_mem / (float) total_mem;
|
||||
// on a 16GB M2 Mac a 13B q4_0 (0.52) works for me but a 13B q4_K_M (0.55) does not
|
||||
if (req_to_total >= 0.53) {
|
||||
delete metalimpl;
|
||||
impl = nullptr;
|
||||
} else {
|
||||
return metalimpl;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!impl) {
|
||||
//TODO: Auto-detect CUDA/OpenCL
|
||||
if (buildVariant == "auto") {
|
||||
if (requires_avxonly()) {
|
||||
buildVariant = "avxonly";
|
||||
} else {
|
||||
buildVariant = "default";
|
||||
}
|
||||
}
|
||||
impl = implementation(modelPath.c_str(), buildVariant);
|
||||
if (!impl) return nullptr;
|
||||
std::vector<std::string> desiredBackends;
|
||||
if (backend) {
|
||||
desiredBackends.push_back(backend.value());
|
||||
} else {
|
||||
desiredBackends.insert(desiredBackends.end(), DEFAULT_BACKENDS, std::end(DEFAULT_BACKENDS));
|
||||
}
|
||||
|
||||
// Construct and return llmodel implementation
|
||||
auto fres = impl->m_construct();
|
||||
fres->m_implementation = impl;
|
||||
return fres;
|
||||
const Implementation *impl = nullptr;
|
||||
|
||||
for (const auto &desiredBackend: desiredBackends) {
|
||||
auto cacheIt = implCache.find(desiredBackend);
|
||||
if (cacheIt != implCache.end())
|
||||
return cacheIt->second.get(); // cached
|
||||
|
||||
for (const auto &i: *impls) {
|
||||
if (i.m_modelType == "LLaMA" && i.m_buildVariant == applyCPUVariant(desiredBackend)) {
|
||||
impl = &i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (impl) {
|
||||
auto *fres = impl->m_construct();
|
||||
fres->m_implementation = impl;
|
||||
implCache[desiredBackend] = std::unique_ptr<LLModel>(fres);
|
||||
return fres;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << __func__ << ": could not find Llama implementation for backend: " << backend.value_or("default") << "\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LLModel::Implementation::setImplementationsSearchPath(const std::string& path) {
|
||||
std::vector<LLModel::GPUDevice> LLModel::Implementation::availableGPUDevices(size_t memoryRequired)
|
||||
{
|
||||
std::vector<LLModel::GPUDevice> devices;
|
||||
#ifndef __APPLE__
|
||||
static const std::string backends[] = {"kompute", "cuda"};
|
||||
for (const auto &backend: backends) {
|
||||
auto *llama = constructGlobalLlama(backend);
|
||||
if (llama) {
|
||||
auto backendDevs = llama->availableGPUDevices(memoryRequired);
|
||||
devices.insert(devices.end(), backendDevs.begin(), backendDevs.end());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return devices;
|
||||
}
|
||||
|
||||
int32_t LLModel::Implementation::maxContextLength(const std::string &modelPath)
|
||||
{
|
||||
auto *llama = constructGlobalLlama();
|
||||
return llama ? llama->maxContextLength(modelPath) : -1;
|
||||
}
|
||||
|
||||
int32_t LLModel::Implementation::layerCount(const std::string &modelPath)
|
||||
{
|
||||
auto *llama = constructGlobalLlama();
|
||||
return llama ? llama->layerCount(modelPath) : -1;
|
||||
}
|
||||
|
||||
bool LLModel::Implementation::isEmbeddingModel(const std::string &modelPath)
|
||||
{
|
||||
auto *llama = constructGlobalLlama();
|
||||
return llama && llama->isEmbeddingModel(modelPath);
|
||||
}
|
||||
|
||||
void LLModel::Implementation::setImplementationsSearchPath(const std::string& path)
|
||||
{
|
||||
s_implementations_search_path = path;
|
||||
}
|
||||
|
||||
const std::string& LLModel::Implementation::implementationsSearchPath() {
|
||||
const std::string& LLModel::Implementation::implementationsSearchPath()
|
||||
{
|
||||
return s_implementations_search_path;
|
||||
}
|
||||
|
||||
bool LLModel::Implementation::hasSupportedCPU()
|
||||
{
|
||||
return cpu_supports_avx() != 0;
|
||||
}
|
||||
|
||||
int LLModel::Implementation::cpuSupportsAVX2()
|
||||
{
|
||||
return cpu_supports_avx2();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
#ifndef LLMODEL_H
|
||||
#define LLMODEL_H
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string_view>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
#define LLMODEL_MAX_PROMPT_BATCH 128
|
||||
|
||||
@@ -15,28 +22,100 @@ class Dlhandle;
|
||||
class LLModel {
|
||||
public:
|
||||
using Token = int32_t;
|
||||
|
||||
class BadArchError: public std::runtime_error {
|
||||
public:
|
||||
BadArchError(std::string arch)
|
||||
: runtime_error("Unsupported model architecture: " + arch)
|
||||
, m_arch(std::move(arch))
|
||||
{}
|
||||
|
||||
const std::string &arch() const noexcept { return m_arch; }
|
||||
|
||||
private:
|
||||
std::string m_arch;
|
||||
};
|
||||
|
||||
class MissingImplementationError: public std::runtime_error {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
class UnsupportedModelError: public std::runtime_error {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
struct GPUDevice {
|
||||
const char *backend;
|
||||
int index;
|
||||
int type;
|
||||
size_t heapSize;
|
||||
std::string name;
|
||||
std::string vendor;
|
||||
|
||||
GPUDevice(const char *backend, int index, int type, size_t heapSize, std::string name, std::string vendor):
|
||||
backend(backend), index(index), type(type), heapSize(heapSize), name(std::move(name)),
|
||||
vendor(std::move(vendor)) {}
|
||||
|
||||
std::string selectionName() const
|
||||
{
|
||||
assert(backend == "cuda"s || backend == "kompute"s);
|
||||
return backendName() + ": " + name;
|
||||
}
|
||||
|
||||
std::string backendName() const { return backendIdToName(backend); }
|
||||
|
||||
static std::string backendIdToName(const std::string &backend) { return s_backendNames.at(backend); }
|
||||
|
||||
static std::string updateSelectionName(const std::string &name) {
|
||||
if (name == "Auto" || name == "CPU" || name == "Metal")
|
||||
return name;
|
||||
auto it = std::find_if(s_backendNames.begin(), s_backendNames.end(), [&name](const auto &entry) {
|
||||
return name.starts_with(entry.second + ": ");
|
||||
});
|
||||
if (it != s_backendNames.end())
|
||||
return name;
|
||||
return "Vulkan: " + name; // previously, there were only Vulkan devices
|
||||
}
|
||||
|
||||
private:
|
||||
static inline const std::unordered_map<std::string, std::string> s_backendNames {
|
||||
{"cpu", "CPU"}, {"metal", "Metal"}, {"cuda", "CUDA"}, {"kompute", "Vulkan"},
|
||||
};
|
||||
};
|
||||
|
||||
class Implementation {
|
||||
public:
|
||||
Implementation(Dlhandle&&);
|
||||
Implementation(const Implementation&) = delete;
|
||||
Implementation(Implementation&&);
|
||||
Implementation(const Implementation &) = delete;
|
||||
Implementation(Implementation &&);
|
||||
~Implementation();
|
||||
|
||||
std::string_view modelType() const { return m_modelType; }
|
||||
std::string_view buildVariant() const { return m_buildVariant; }
|
||||
|
||||
static bool isImplementation(const Dlhandle&);
|
||||
static const std::vector<Implementation>& implementationList();
|
||||
static const Implementation *implementation(const char *fname, const std::string& buildVariant);
|
||||
static LLModel *construct(const std::string &modelPath, std::string buildVariant = "auto");
|
||||
static void setImplementationsSearchPath(const std::string& path);
|
||||
static const std::string& implementationsSearchPath();
|
||||
static LLModel *construct(const std::string &modelPath, const std::string &backend = "auto", int n_ctx = 2048);
|
||||
static std::vector<GPUDevice> availableGPUDevices(size_t memoryRequired = 0);
|
||||
static int32_t maxContextLength(const std::string &modelPath);
|
||||
static int32_t layerCount(const std::string &modelPath);
|
||||
static bool isEmbeddingModel(const std::string &modelPath);
|
||||
static void setImplementationsSearchPath(const std::string &path);
|
||||
static const std::string &implementationsSearchPath();
|
||||
static bool hasSupportedCPU();
|
||||
// 0 for no, 1 for yes, -1 for non-x86_64
|
||||
static int cpuSupportsAVX2();
|
||||
|
||||
private:
|
||||
bool (*m_magicMatch)(const char *fname);
|
||||
Implementation(Dlhandle &&);
|
||||
|
||||
static const std::vector<Implementation> &implementationList();
|
||||
static const Implementation *implementation(const char *fname, const std::string &buildVariant);
|
||||
static LLModel *constructGlobalLlama(const std::optional<std::string> &backend = std::nullopt);
|
||||
|
||||
char *(*m_getFileArch)(const char *fname);
|
||||
bool (*m_isArchSupported)(const char *arch);
|
||||
LLModel *(*m_construct)();
|
||||
|
||||
private:
|
||||
std::string_view m_modelType;
|
||||
std::string_view m_buildVariant;
|
||||
Dlhandle *m_dlhandle;
|
||||
@@ -50,73 +129,109 @@ public:
|
||||
int32_t n_predict = 200;
|
||||
int32_t top_k = 40;
|
||||
float top_p = 0.9f;
|
||||
float min_p = 0.0f;
|
||||
float temp = 0.9f;
|
||||
int32_t n_batch = 9;
|
||||
float repeat_penalty = 1.10f;
|
||||
int32_t repeat_last_n = 64; // last n tokens to penalize
|
||||
float contextErase = 0.75f; // percent of context to erase if we exceed the context
|
||||
// window
|
||||
float contextErase = 0.75f; // percent of context to erase if we exceed the context window
|
||||
int32_t n_last_batch_tokens = 0;
|
||||
};
|
||||
|
||||
struct GPUDevice {
|
||||
int index = 0;
|
||||
int type = 0;
|
||||
size_t heapSize = 0;
|
||||
std::string name;
|
||||
std::string vendor;
|
||||
};
|
||||
using ProgressCallback = std::function<bool(float progress)>;
|
||||
|
||||
explicit LLModel() {}
|
||||
virtual ~LLModel() {}
|
||||
|
||||
virtual bool supportsEmbedding() const = 0;
|
||||
virtual bool supportsCompletion() const = 0;
|
||||
virtual bool loadModel(const std::string &modelPath) = 0;
|
||||
virtual bool loadModel(const std::string &modelPath, int n_ctx, int ngl) = 0;
|
||||
virtual bool isModelBlacklisted(const std::string &modelPath) const { (void)modelPath; return false; };
|
||||
virtual bool isEmbeddingModel(const std::string &modelPath) const { (void)modelPath; return false; }
|
||||
virtual bool isModelLoaded() const = 0;
|
||||
virtual size_t requiredMem(const std::string &modelPath) = 0;
|
||||
virtual size_t requiredMem(const std::string &modelPath, int n_ctx, int ngl) = 0;
|
||||
virtual size_t stateSize() const { return 0; }
|
||||
virtual size_t saveState(uint8_t */*dest*/) const { return 0; }
|
||||
virtual size_t restoreState(const uint8_t */*src*/) { return 0; }
|
||||
virtual size_t saveState(uint8_t *dest) const { (void)dest; return 0; }
|
||||
virtual size_t restoreState(const uint8_t *src) { (void)src; return 0; }
|
||||
|
||||
// This method requires the model to return true from supportsCompletion otherwise it will throw
|
||||
// an error
|
||||
virtual void prompt(const std::string &prompt,
|
||||
const std::string &promptTemplate,
|
||||
std::function<bool(int32_t)> promptCallback,
|
||||
std::function<bool(int32_t, const std::string&)> responseCallback,
|
||||
std::function<bool(bool)> recalculateCallback,
|
||||
PromptContext &ctx);
|
||||
PromptContext &ctx,
|
||||
bool special = false,
|
||||
std::string *fakeReply = nullptr);
|
||||
|
||||
virtual std::vector<float> embedding(const std::string &text);
|
||||
using EmbedCancelCallback = bool(unsigned *batchSizes, unsigned nBatch, const char *backend);
|
||||
|
||||
virtual void setThreadCount(int32_t /*n_threads*/) {}
|
||||
virtual size_t embeddingSize() const {
|
||||
throw std::logic_error(std::string(implementation().modelType()) + " does not support embeddings");
|
||||
}
|
||||
// user-specified prefix
|
||||
virtual void embed(const std::vector<std::string> &texts, float *embeddings, std::optional<std::string> prefix,
|
||||
int dimensionality = -1, size_t *tokenCount = nullptr, bool doMean = true, bool atlas = false,
|
||||
EmbedCancelCallback *cancelCb = nullptr);
|
||||
// automatic prefix
|
||||
virtual void embed(const std::vector<std::string> &texts, float *embeddings, bool isRetrieval,
|
||||
int dimensionality = -1, size_t *tokenCount = nullptr, bool doMean = true, bool atlas = false);
|
||||
|
||||
virtual void setThreadCount(int32_t n_threads) { (void)n_threads; }
|
||||
virtual int32_t threadCount() const { return 1; }
|
||||
|
||||
const Implementation& implementation() const {
|
||||
const Implementation &implementation() const {
|
||||
return *m_implementation;
|
||||
}
|
||||
|
||||
virtual std::vector<GPUDevice> availableGPUDevices(size_t /*memoryRequired*/) { return std::vector<GPUDevice>(); }
|
||||
virtual bool initializeGPUDevice(size_t /*memoryRequired*/, const std::string& /*device*/) { return false; }
|
||||
virtual bool initializeGPUDevice(const GPUDevice &/*device*/, std::string *unavail_reason = nullptr) {
|
||||
virtual std::vector<GPUDevice> availableGPUDevices(size_t memoryRequired) const {
|
||||
(void)memoryRequired;
|
||||
return {};
|
||||
}
|
||||
|
||||
virtual bool initializeGPUDevice(size_t memoryRequired, const std::string &name) const {
|
||||
(void)memoryRequired;
|
||||
(void)name;
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool initializeGPUDevice(int device, std::string *unavail_reason = nullptr) const {
|
||||
(void)device;
|
||||
if (unavail_reason) {
|
||||
*unavail_reason = "model has no GPU support";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual bool initializeGPUDevice(int /*device*/) { return false; }
|
||||
virtual bool hasGPUDevice() { return false; }
|
||||
virtual bool usingGPUDevice() { return false; }
|
||||
static std::vector<GPUDevice> availableGPUDevices();
|
||||
|
||||
virtual bool usingGPUDevice() const { return false; }
|
||||
virtual const char *backendName() const { return "cpu"; }
|
||||
virtual const char *gpuDeviceName() const { return nullptr; }
|
||||
|
||||
void setProgressCallback(ProgressCallback callback) { m_progressCallback = callback; }
|
||||
|
||||
protected:
|
||||
// These are pure virtual because subclasses need to implement as the default implementation of
|
||||
// 'prompt' above calls these functions
|
||||
virtual std::vector<Token> tokenize(PromptContext &, const std::string&) const = 0;
|
||||
virtual std::string tokenToString(Token) const = 0;
|
||||
virtual std::vector<Token> tokenize(PromptContext &ctx, const std::string &str, bool special = false) const = 0;
|
||||
virtual std::string tokenToString(Token id) const = 0;
|
||||
virtual Token sampleToken(PromptContext &ctx) const = 0;
|
||||
virtual bool evalTokens(PromptContext &/*ctx*/, const std::vector<int32_t>& /*tokens*/) const = 0;
|
||||
virtual bool evalTokens(PromptContext &ctx, const std::vector<int32_t> &tokens) const = 0;
|
||||
virtual int32_t contextLength() const = 0;
|
||||
virtual const std::vector<Token>& endTokens() const = 0;
|
||||
virtual const std::vector<Token> &endTokens() const = 0;
|
||||
virtual bool shouldAddBOS() const = 0;
|
||||
|
||||
virtual int32_t maxContextLength(std::string const &modelPath) const
|
||||
{
|
||||
(void)modelPath;
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual int32_t layerCount(std::string const &modelPath) const
|
||||
{
|
||||
(void)modelPath;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This is a helper function called from the default implementation of 'prompt' but it can be
|
||||
// shared by all base classes so it isn't virtual
|
||||
@@ -124,6 +239,24 @@ protected:
|
||||
|
||||
const Implementation *m_implementation = nullptr;
|
||||
|
||||
ProgressCallback m_progressCallback;
|
||||
static bool staticProgressCallback(float progress, void* ctx)
|
||||
{
|
||||
LLModel* model = static_cast<LLModel*>(ctx);
|
||||
if (model && model->m_progressCallback)
|
||||
return model->m_progressCallback(progress);
|
||||
return true;
|
||||
}
|
||||
|
||||
void decodePrompt(std::function<bool(int32_t)> promptCallback,
|
||||
std::function<bool(int32_t, const std::string&)> responseCallback,
|
||||
std::function<bool(bool)> recalculateCallback,
|
||||
PromptContext &promptCtx,
|
||||
std::vector<Token> embd_inp);
|
||||
void generateResponse(std::function<bool(int32_t, const std::string&)> responseCallback,
|
||||
std::function<bool(bool)> recalculateCallback,
|
||||
PromptContext &promptCtx);
|
||||
|
||||
private:
|
||||
friend class LLMImplementation;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
#include "llmodel_c.h"
|
||||
|
||||
#include "llmodel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <utility>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct LLModelWrapper {
|
||||
LLModel *llModel = nullptr;
|
||||
@@ -11,121 +20,102 @@ struct LLModelWrapper {
|
||||
~LLModelWrapper() { delete llModel; }
|
||||
};
|
||||
|
||||
|
||||
thread_local static std::string last_error_message;
|
||||
|
||||
|
||||
llmodel_model llmodel_model_create(const char *model_path) {
|
||||
auto fres = llmodel_model_create2(model_path, "auto", nullptr);
|
||||
llmodel_model llmodel_model_create(const char *model_path)
|
||||
{
|
||||
const char *error;
|
||||
auto fres = llmodel_model_create2(model_path, "auto", &error);
|
||||
if (!fres) {
|
||||
fprintf(stderr, "Invalid model file\n");
|
||||
fprintf(stderr, "Unable to instantiate model: %s\n", error);
|
||||
}
|
||||
return fres;
|
||||
}
|
||||
|
||||
llmodel_model llmodel_model_create2(const char *model_path, const char *build_variant, llmodel_error *error) {
|
||||
auto wrapper = new LLModelWrapper;
|
||||
int error_code = 0;
|
||||
static void llmodel_set_error(const char **errptr, const char *message)
|
||||
{
|
||||
thread_local static std::string last_error_message;
|
||||
if (errptr) {
|
||||
last_error_message = message;
|
||||
*errptr = last_error_message.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
llmodel_model llmodel_model_create2(const char *model_path, const char *backend, const char **error)
|
||||
{
|
||||
LLModel *llModel;
|
||||
try {
|
||||
wrapper->llModel = LLModel::Implementation::construct(model_path, build_variant);
|
||||
llModel = LLModel::Implementation::construct(model_path, backend);
|
||||
} catch (const std::exception& e) {
|
||||
error_code = EINVAL;
|
||||
last_error_message = e.what();
|
||||
llmodel_set_error(error, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!wrapper->llModel) {
|
||||
delete std::exchange(wrapper, nullptr);
|
||||
// Get errno and error message if none
|
||||
if (error_code == 0) {
|
||||
if (errno != 0) {
|
||||
error_code = errno;
|
||||
last_error_message = std::strerror(error_code);
|
||||
} else {
|
||||
error_code = ENOTSUP;
|
||||
last_error_message = "Model format not supported (no matching implementation found)";
|
||||
}
|
||||
}
|
||||
// Set error argument
|
||||
if (error) {
|
||||
error->message = last_error_message.c_str();
|
||||
error->code = error_code;
|
||||
}
|
||||
auto wrapper = new LLModelWrapper;
|
||||
wrapper->llModel = llModel;
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
void llmodel_model_destroy(llmodel_model model)
|
||||
{
|
||||
delete static_cast<LLModelWrapper *>(model);
|
||||
}
|
||||
|
||||
size_t llmodel_required_mem(llmodel_model model, const char *model_path, int n_ctx, int ngl)
|
||||
{
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->requiredMem(model_path, n_ctx, ngl);
|
||||
}
|
||||
|
||||
bool llmodel_loadModel(llmodel_model model, const char *model_path, int n_ctx, int ngl)
|
||||
{
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
|
||||
std::string modelPath(model_path);
|
||||
if (wrapper->llModel->isModelBlacklisted(modelPath)) {
|
||||
size_t slash = modelPath.find_last_of("/\\");
|
||||
auto basename = slash == std::string::npos ? modelPath : modelPath.substr(slash + 1);
|
||||
std::cerr << "warning: model '" << basename << "' is out-of-date, please check for an updated version\n";
|
||||
}
|
||||
return reinterpret_cast<llmodel_model*>(wrapper);
|
||||
}
|
||||
|
||||
void llmodel_model_destroy(llmodel_model model) {
|
||||
delete reinterpret_cast<LLModelWrapper*>(model);
|
||||
}
|
||||
|
||||
size_t llmodel_required_mem(llmodel_model model, const char *model_path)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
return wrapper->llModel->requiredMem(model_path);
|
||||
}
|
||||
|
||||
bool llmodel_loadModel(llmodel_model model, const char *model_path)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
return wrapper->llModel->loadModel(model_path);
|
||||
return wrapper->llModel->loadModel(modelPath, n_ctx, ngl);
|
||||
}
|
||||
|
||||
bool llmodel_isModelLoaded(llmodel_model model)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->isModelLoaded();
|
||||
}
|
||||
|
||||
uint64_t llmodel_get_state_size(llmodel_model model)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->stateSize();
|
||||
}
|
||||
|
||||
uint64_t llmodel_save_state_data(llmodel_model model, uint8_t *dest)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->saveState(dest);
|
||||
}
|
||||
|
||||
uint64_t llmodel_restore_state_data(llmodel_model model, const uint8_t *src)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->restoreState(src);
|
||||
}
|
||||
|
||||
// Wrapper functions for the C callbacks
|
||||
bool prompt_wrapper(int32_t token_id, void *user_data) {
|
||||
llmodel_prompt_callback callback = reinterpret_cast<llmodel_prompt_callback>(user_data);
|
||||
return callback(token_id);
|
||||
}
|
||||
|
||||
bool response_wrapper(int32_t token_id, const std::string &response, void *user_data) {
|
||||
llmodel_response_callback callback = reinterpret_cast<llmodel_response_callback>(user_data);
|
||||
return callback(token_id, response.c_str());
|
||||
}
|
||||
|
||||
bool recalculate_wrapper(bool is_recalculating, void *user_data) {
|
||||
llmodel_recalculate_callback callback = reinterpret_cast<llmodel_recalculate_callback>(user_data);
|
||||
return callback(is_recalculating);
|
||||
}
|
||||
|
||||
void llmodel_prompt(llmodel_model model, const char *prompt,
|
||||
const char *prompt_template,
|
||||
llmodel_prompt_callback prompt_callback,
|
||||
llmodel_response_callback response_callback,
|
||||
llmodel_recalculate_callback recalculate_callback,
|
||||
llmodel_prompt_context *ctx)
|
||||
llmodel_prompt_context *ctx,
|
||||
bool special,
|
||||
const char *fake_reply)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
|
||||
// Create std::function wrappers that call the C function pointers
|
||||
std::function<bool(int32_t)> prompt_func =
|
||||
std::bind(&prompt_wrapper, std::placeholders::_1, reinterpret_cast<void*>(prompt_callback));
|
||||
std::function<bool(int32_t, const std::string&)> response_func =
|
||||
std::bind(&response_wrapper, std::placeholders::_1, std::placeholders::_2, reinterpret_cast<void*>(response_callback));
|
||||
std::function<bool(bool)> recalc_func =
|
||||
std::bind(&recalculate_wrapper, std::placeholders::_1, reinterpret_cast<void*>(recalculate_callback));
|
||||
auto response_func = [response_callback](int32_t token_id, const std::string &response) {
|
||||
return response_callback(token_id, response.c_str());
|
||||
};
|
||||
|
||||
if (size_t(ctx->n_past) < wrapper->promptContext.tokens.size())
|
||||
wrapper->promptContext.tokens.resize(ctx->n_past);
|
||||
@@ -136,14 +126,20 @@ void llmodel_prompt(llmodel_model model, const char *prompt,
|
||||
wrapper->promptContext.n_predict = ctx->n_predict;
|
||||
wrapper->promptContext.top_k = ctx->top_k;
|
||||
wrapper->promptContext.top_p = ctx->top_p;
|
||||
wrapper->promptContext.min_p = ctx->min_p;
|
||||
wrapper->promptContext.temp = ctx->temp;
|
||||
wrapper->promptContext.n_batch = ctx->n_batch;
|
||||
wrapper->promptContext.repeat_penalty = ctx->repeat_penalty;
|
||||
wrapper->promptContext.repeat_last_n = ctx->repeat_last_n;
|
||||
wrapper->promptContext.contextErase = ctx->context_erase;
|
||||
|
||||
std::string fake_reply_str;
|
||||
if (fake_reply) { fake_reply_str = fake_reply; }
|
||||
auto *fake_reply_p = fake_reply ? &fake_reply_str : nullptr;
|
||||
|
||||
// Call the C++ prompt method
|
||||
wrapper->llModel->prompt(prompt, prompt_func, response_func, recalc_func, wrapper->promptContext);
|
||||
wrapper->llModel->prompt(prompt, prompt_template, prompt_callback, response_func, recalculate_callback,
|
||||
wrapper->promptContext, special, fake_reply_p);
|
||||
|
||||
// Update the C context by giving access to the wrappers raw pointers to std::vector data
|
||||
// which involves no copies
|
||||
@@ -158,6 +154,7 @@ void llmodel_prompt(llmodel_model model, const char *prompt,
|
||||
ctx->n_predict = wrapper->promptContext.n_predict;
|
||||
ctx->top_k = wrapper->promptContext.top_k;
|
||||
ctx->top_p = wrapper->promptContext.top_p;
|
||||
ctx->min_p = wrapper->promptContext.min_p;
|
||||
ctx->temp = wrapper->promptContext.temp;
|
||||
ctx->n_batch = wrapper->promptContext.n_batch;
|
||||
ctx->repeat_penalty = wrapper->promptContext.repeat_penalty;
|
||||
@@ -165,38 +162,58 @@ void llmodel_prompt(llmodel_model model, const char *prompt,
|
||||
ctx->context_erase = wrapper->promptContext.contextErase;
|
||||
}
|
||||
|
||||
float *llmodel_embedding(llmodel_model model, const char *text, size_t *embedding_size)
|
||||
{
|
||||
if (model == nullptr || text == nullptr || !strlen(text)) {
|
||||
*embedding_size = 0;
|
||||
float *llmodel_embed(
|
||||
llmodel_model model, const char **texts, size_t *embedding_size, const char *prefix, int dimensionality,
|
||||
size_t *token_count, bool do_mean, bool atlas, llmodel_emb_cancel_callback cancel_cb, const char **error
|
||||
) {
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
|
||||
if (!texts || !*texts) {
|
||||
llmodel_set_error(error, "'texts' is NULL or empty");
|
||||
return nullptr;
|
||||
}
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
std::vector<float> embeddingVector = wrapper->llModel->embedding(text);
|
||||
float *embedding = (float *)malloc(embeddingVector.size() * sizeof(float));
|
||||
if (embedding == nullptr) {
|
||||
*embedding_size = 0;
|
||||
|
||||
std::vector<std::string> textsVec;
|
||||
while (*texts) { textsVec.emplace_back(*texts++); }
|
||||
|
||||
size_t embd_size;
|
||||
float *embedding;
|
||||
|
||||
try {
|
||||
embd_size = wrapper->llModel->embeddingSize();
|
||||
if (dimensionality > 0 && dimensionality < int(embd_size))
|
||||
embd_size = dimensionality;
|
||||
|
||||
embd_size *= textsVec.size();
|
||||
|
||||
std::optional<std::string> prefixStr;
|
||||
if (prefix) { prefixStr = prefix; }
|
||||
|
||||
embedding = new float[embd_size];
|
||||
wrapper->llModel->embed(textsVec, embedding, prefixStr, dimensionality, token_count, do_mean, atlas, cancel_cb);
|
||||
} catch (std::exception const &e) {
|
||||
llmodel_set_error(error, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
std::copy(embeddingVector.begin(), embeddingVector.end(), embedding);
|
||||
*embedding_size = embeddingVector.size();
|
||||
|
||||
*embedding_size = embd_size;
|
||||
return embedding;
|
||||
}
|
||||
|
||||
void llmodel_free_embedding(float *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
void llmodel_setThreadCount(llmodel_model model, int32_t n_threads)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
wrapper->llModel->setThreadCount(n_threads);
|
||||
}
|
||||
|
||||
int32_t llmodel_threadCount(llmodel_model model)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->threadCount();
|
||||
}
|
||||
|
||||
@@ -210,56 +227,74 @@ const char *llmodel_get_implementation_search_path()
|
||||
return LLModel::Implementation::implementationsSearchPath().c_str();
|
||||
}
|
||||
|
||||
struct llmodel_gpu_device* llmodel_available_gpu_devices(llmodel_model model, size_t memoryRequired, int* num_devices)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
std::vector<LLModel::GPUDevice> devices = wrapper->llModel->availableGPUDevices(memoryRequired);
|
||||
// RAII wrapper around a C-style struct
|
||||
struct llmodel_gpu_device_cpp: llmodel_gpu_device {
|
||||
llmodel_gpu_device_cpp() = default;
|
||||
|
||||
// Set the num_devices
|
||||
llmodel_gpu_device_cpp(const llmodel_gpu_device_cpp &) = delete;
|
||||
llmodel_gpu_device_cpp( llmodel_gpu_device_cpp &&) = delete;
|
||||
|
||||
const llmodel_gpu_device_cpp &operator=(const llmodel_gpu_device_cpp &) = delete;
|
||||
llmodel_gpu_device_cpp &operator=( llmodel_gpu_device_cpp &&) = delete;
|
||||
|
||||
~llmodel_gpu_device_cpp() {
|
||||
free(const_cast<char *>(name));
|
||||
free(const_cast<char *>(vendor));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(llmodel_gpu_device_cpp) == sizeof(llmodel_gpu_device));
|
||||
|
||||
struct llmodel_gpu_device *llmodel_available_gpu_devices(size_t memoryRequired, int *num_devices)
|
||||
{
|
||||
static thread_local std::unique_ptr<llmodel_gpu_device_cpp[]> c_devices;
|
||||
|
||||
auto devices = LLModel::Implementation::availableGPUDevices(memoryRequired);
|
||||
*num_devices = devices.size();
|
||||
|
||||
if (*num_devices == 0) return nullptr; // Return nullptr if no devices are found
|
||||
if (devices.empty()) { return nullptr; /* no devices */ }
|
||||
|
||||
// Allocate memory for the output array
|
||||
struct llmodel_gpu_device* output = (struct llmodel_gpu_device*) malloc(*num_devices * sizeof(struct llmodel_gpu_device));
|
||||
|
||||
for (int i = 0; i < *num_devices; i++) {
|
||||
output[i].index = devices[i].index;
|
||||
output[i].type = devices[i].type;
|
||||
output[i].heapSize = devices[i].heapSize;
|
||||
output[i].name = strdup(devices[i].name.c_str()); // Convert std::string to char* and allocate memory
|
||||
output[i].vendor = strdup(devices[i].vendor.c_str()); // Convert std::string to char* and allocate memory
|
||||
c_devices = std::make_unique<llmodel_gpu_device_cpp[]>(devices.size());
|
||||
for (unsigned i = 0; i < devices.size(); i++) {
|
||||
const auto &dev = devices[i];
|
||||
auto &cdev = c_devices[i];
|
||||
cdev.backend = dev.backend;
|
||||
cdev.index = dev.index;
|
||||
cdev.type = dev.type;
|
||||
cdev.heapSize = dev.heapSize;
|
||||
cdev.name = strdup(dev.name.c_str());
|
||||
cdev.vendor = strdup(dev.vendor.c_str());
|
||||
}
|
||||
|
||||
return output;
|
||||
return c_devices.get();
|
||||
}
|
||||
|
||||
bool llmodel_gpu_init_gpu_device_by_string(llmodel_model model, size_t memoryRequired, const char *device)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->initializeGPUDevice(memoryRequired, std::string(device));
|
||||
}
|
||||
|
||||
bool llmodel_gpu_init_gpu_device_by_struct(llmodel_model model, const llmodel_gpu_device *device)
|
||||
{
|
||||
LLModel::GPUDevice d;
|
||||
d.index = device->index;
|
||||
d.type = device->type;
|
||||
d.heapSize = device->heapSize;
|
||||
d.name = device->name;
|
||||
d.vendor = device->vendor;
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
return wrapper->llModel->initializeGPUDevice(d);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->initializeGPUDevice(device->index);
|
||||
}
|
||||
|
||||
bool llmodel_gpu_init_gpu_device_by_int(llmodel_model model, int device)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->initializeGPUDevice(device);
|
||||
}
|
||||
|
||||
bool llmodel_has_gpu_device(llmodel_model model)
|
||||
const char *llmodel_model_backend_name(llmodel_model model)
|
||||
{
|
||||
LLModelWrapper *wrapper = reinterpret_cast<LLModelWrapper*>(model);
|
||||
return wrapper->llModel->hasGPUDevice();
|
||||
const auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->backendName();
|
||||
}
|
||||
|
||||
const char *llmodel_model_gpu_device_name(llmodel_model model)
|
||||
{
|
||||
const auto *wrapper = static_cast<LLModelWrapper *>(model);
|
||||
return wrapper->llModel->gpuDeviceName();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef LLMODEL_C_H
|
||||
#define LLMODEL_C_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define DEPRECATED __attribute__ ((deprecated))
|
||||
@@ -23,17 +23,6 @@ extern "C" {
|
||||
*/
|
||||
typedef void *llmodel_model;
|
||||
|
||||
/**
|
||||
* Structure containing any errors that may eventually occur
|
||||
*/
|
||||
struct llmodel_error {
|
||||
const char *message; // Human readable error description; Thread-local; guaranteed to survive until next llmodel C API call
|
||||
int code; // errno; 0 if none
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef struct llmodel_error llmodel_error;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* llmodel_prompt_context structure for holding the prompt context.
|
||||
* NOTE: The implementation takes care of all the memory handling of the raw logits pointer and the
|
||||
@@ -50,6 +39,7 @@ struct llmodel_prompt_context {
|
||||
int32_t n_predict; // number of tokens to predict
|
||||
int32_t top_k; // top k logits to sample from
|
||||
float top_p; // nucleus sampling probability threshold
|
||||
float min_p; // Min P sampling
|
||||
float temp; // temperature to adjust model's output distribution
|
||||
int32_t n_batch; // number of predictions to generate in parallel
|
||||
float repeat_penalty; // penalty factor for repeated tokens
|
||||
@@ -58,9 +48,10 @@ struct llmodel_prompt_context {
|
||||
};
|
||||
|
||||
struct llmodel_gpu_device {
|
||||
int index = 0;
|
||||
int type = 0; // same as VkPhysicalDeviceType
|
||||
size_t heapSize = 0;
|
||||
const char * backend;
|
||||
int index;
|
||||
int type; // same as VkPhysicalDeviceType
|
||||
size_t heapSize;
|
||||
const char * name;
|
||||
const char * vendor;
|
||||
};
|
||||
@@ -92,6 +83,15 @@ typedef bool (*llmodel_response_callback)(int32_t token_id, const char *response
|
||||
*/
|
||||
typedef bool (*llmodel_recalculate_callback)(bool is_recalculating);
|
||||
|
||||
/**
|
||||
* Embedding cancellation callback for use with llmodel_embed.
|
||||
* @param batch_sizes The number of tokens in each batch that will be embedded.
|
||||
* @param n_batch The number of batches that will be embedded.
|
||||
* @param backend The backend that will be used for embedding. One of "cpu", "kompute", "cuda", or "metal".
|
||||
* @return True to cancel llmodel_embed, false to continue.
|
||||
*/
|
||||
typedef bool (*llmodel_emb_cancel_callback)(unsigned *batch_sizes, unsigned n_batch, const char *backend);
|
||||
|
||||
/**
|
||||
* Create a llmodel instance.
|
||||
* Recognises correct model type from file at model_path
|
||||
@@ -104,11 +104,11 @@ DEPRECATED llmodel_model llmodel_model_create(const char *model_path);
|
||||
* Create a llmodel instance.
|
||||
* Recognises correct model type from file at model_path
|
||||
* @param model_path A string representing the path to the model file; will only be used to detect model type.
|
||||
* @param build_variant A string representing the implementation to use (auto, default, avxonly, ...),
|
||||
* @param error A pointer to a llmodel_error; will only be set on error.
|
||||
* @param backend A string representing the implementation to use. One of 'auto', 'cpu', 'metal', 'kompute', or 'cuda'.
|
||||
* @param error A pointer to a string; will only be set on error.
|
||||
* @return A pointer to the llmodel_model instance; NULL on error.
|
||||
*/
|
||||
llmodel_model llmodel_model_create2(const char *model_path, const char *build_variant, llmodel_error *error);
|
||||
llmodel_model llmodel_model_create2(const char *model_path, const char *backend, const char **error);
|
||||
|
||||
/**
|
||||
* Destroy a llmodel instance.
|
||||
@@ -121,17 +121,21 @@ void llmodel_model_destroy(llmodel_model model);
|
||||
* Estimate RAM requirement for a model file
|
||||
* @param model A pointer to the llmodel_model instance.
|
||||
* @param model_path A string representing the path to the model file.
|
||||
* @param n_ctx Maximum size of context window
|
||||
* @param ngl Number of GPU layers to use (Vulkan)
|
||||
* @return size greater than 0 if the model was parsed successfully, 0 if file could not be parsed.
|
||||
*/
|
||||
size_t llmodel_required_mem(llmodel_model model, const char *model_path);
|
||||
size_t llmodel_required_mem(llmodel_model model, const char *model_path, int n_ctx, int ngl);
|
||||
|
||||
/**
|
||||
* Load a model from a file.
|
||||
* @param model A pointer to the llmodel_model instance.
|
||||
* @param model_path A string representing the path to the model file.
|
||||
* @param n_ctx Maximum size of context window
|
||||
* @param ngl Number of GPU layers to use (Vulkan)
|
||||
* @return true if the model was loaded successfully, false otherwise.
|
||||
*/
|
||||
bool llmodel_loadModel(llmodel_model model, const char *model_path);
|
||||
bool llmodel_loadModel(llmodel_model model, const char *model_path, int n_ctx, int ngl);
|
||||
|
||||
/**
|
||||
* Check if a model is loaded.
|
||||
@@ -170,29 +174,48 @@ uint64_t llmodel_restore_state_data(llmodel_model model, const uint8_t *src);
|
||||
* Generate a response using the model.
|
||||
* @param model A pointer to the llmodel_model instance.
|
||||
* @param prompt A string representing the input prompt.
|
||||
* @param prompt_template A string representing the input prompt template.
|
||||
* @param prompt_callback A callback function for handling the processing of prompt.
|
||||
* @param response_callback A callback function for handling the generated response.
|
||||
* @param recalculate_callback A callback function for handling recalculation requests.
|
||||
* @param special True if special tokens in the prompt should be processed, false otherwise.
|
||||
* @param fake_reply A string to insert into context as the model's reply, or NULL to generate one.
|
||||
* @param ctx A pointer to the llmodel_prompt_context structure.
|
||||
*/
|
||||
void llmodel_prompt(llmodel_model model, const char *prompt,
|
||||
const char *prompt_template,
|
||||
llmodel_prompt_callback prompt_callback,
|
||||
llmodel_response_callback response_callback,
|
||||
llmodel_recalculate_callback recalculate_callback,
|
||||
llmodel_prompt_context *ctx);
|
||||
llmodel_prompt_context *ctx,
|
||||
bool special,
|
||||
const char *fake_reply);
|
||||
|
||||
/**
|
||||
* Generate an embedding using the model.
|
||||
* NOTE: If given NULL pointers for the model or text, or an empty text, a NULL pointer will be
|
||||
* returned. Bindings should signal an error when NULL is the return value.
|
||||
* @param model A pointer to the llmodel_model instance.
|
||||
* @param text A string representing the text to generate an embedding for.
|
||||
* @param texts A pointer to a NULL-terminated array of strings representing the texts to generate an
|
||||
* embedding for.
|
||||
* @param embedding_size A pointer to a size_t type that will be set by the call indicating the length
|
||||
* of the returned floating point array.
|
||||
* @param prefix The model-specific prefix representing the embedding task, without the trailing colon. NULL for no
|
||||
* prefix.
|
||||
* @param dimensionality The embedding dimension, for use with Matryoshka-capable models. Set to -1 to for full-size.
|
||||
* @param token_count Return location for the number of prompt tokens processed, or NULL.
|
||||
* @param do_mean True to average multiple embeddings if the text is longer than the model can accept, False to
|
||||
* truncate.
|
||||
* @param atlas Try to be fully compatible with the Atlas API. Currently, this means texts longer than 8192 tokens with
|
||||
* long_text_mode="mean" will raise an error. Disabled by default.
|
||||
* @param cancel_cb Cancellation callback, or NULL. See the documentation of llmodel_emb_cancel_callback.
|
||||
* @param error Return location for a malloc()ed string that will be set on error, or NULL.
|
||||
* @return A pointer to an array of floating point values passed to the calling method which then will
|
||||
* be responsible for lifetime of this memory.
|
||||
* be responsible for lifetime of this memory. NULL if an error occurred.
|
||||
*/
|
||||
float *llmodel_embedding(llmodel_model model, const char *text, size_t *embedding_size);
|
||||
float *llmodel_embed(llmodel_model model, const char **texts, size_t *embedding_size, const char *prefix,
|
||||
int dimensionality, size_t *token_count, bool do_mean, bool atlas,
|
||||
llmodel_emb_cancel_callback cancel_cb, const char **error);
|
||||
|
||||
/**
|
||||
* Frees the memory allocated by the llmodel_embedding function.
|
||||
@@ -230,9 +253,10 @@ const char *llmodel_get_implementation_search_path();
|
||||
|
||||
/**
|
||||
* Get a list of available GPU devices given the memory required.
|
||||
* @param memoryRequired The minimum amount of VRAM, in bytes
|
||||
* @return A pointer to an array of llmodel_gpu_device's whose number is given by num_devices.
|
||||
*/
|
||||
struct llmodel_gpu_device* llmodel_available_gpu_devices(llmodel_model model, size_t memoryRequired, int* num_devices);
|
||||
struct llmodel_gpu_device* llmodel_available_gpu_devices(size_t memoryRequired, int* num_devices);
|
||||
|
||||
/**
|
||||
* Initializes a GPU device based on a specified string criterion.
|
||||
@@ -268,9 +292,14 @@ bool llmodel_gpu_init_gpu_device_by_struct(llmodel_model model, const llmodel_gp
|
||||
bool llmodel_gpu_init_gpu_device_by_int(llmodel_model model, int device);
|
||||
|
||||
/**
|
||||
* @return True if a GPU device is successfully initialized, false otherwise.
|
||||
* @return The name of the llama.cpp backend currently in use. One of "cpu", "kompute", or "metal".
|
||||
*/
|
||||
bool llmodel_has_gpu_device(llmodel_model model);
|
||||
const char *llmodel_model_backend_name(llmodel_model model);
|
||||
|
||||
/**
|
||||
* @return The name of the GPU device currently in use, or NULL for backends other than Kompute.
|
||||
*/
|
||||
const char *llmodel_model_gpu_device_name(llmodel_model model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
#include "llmodel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifdef GGML_USE_KOMPUTE
|
||||
#include "ggml-vulkan.h"
|
||||
#endif
|
||||
// TODO(cebtenzzre): replace this with llama_kv_cache_seq_shift for llamamodel (GPT-J needs this as-is)
|
||||
void LLModel::recalculateContext(PromptContext &promptCtx, std::function<bool(bool)> recalculate)
|
||||
{
|
||||
int n_keep = shouldAddBOS();
|
||||
const int32_t n_discard = (promptCtx.n_ctx - n_keep) * promptCtx.contextErase;
|
||||
|
||||
void LLModel::recalculateContext(PromptContext &promptCtx, std::function<bool(bool)> recalculate) {
|
||||
size_t i = 0;
|
||||
promptCtx.n_past = 0;
|
||||
// Erase the first percentage of context from the tokens
|
||||
std::cerr << implementation().modelType() << ": reached the end of the context window so resizing\n";
|
||||
promptCtx.tokens.erase(promptCtx.tokens.begin() + n_keep, promptCtx.tokens.begin() + n_keep + n_discard);
|
||||
|
||||
size_t i = n_keep;
|
||||
promptCtx.n_past = n_keep;
|
||||
while (i < promptCtx.tokens.size()) {
|
||||
size_t batch_end = std::min(i + promptCtx.n_batch, promptCtx.tokens.size());
|
||||
std::vector<int32_t> batch(promptCtx.tokens.begin() + i, promptCtx.tokens.begin() + batch_end);
|
||||
@@ -30,11 +44,37 @@ stop_generating:
|
||||
recalculate(false);
|
||||
}
|
||||
|
||||
static bool parsePromptTemplate(const std::string &tmpl, std::vector<std::smatch> &placeholders, std::string &err)
|
||||
{
|
||||
static const std::regex placeholderRegex(R"(%[1-2](?![0-9]))");
|
||||
|
||||
auto it = std::sregex_iterator(tmpl.begin(), tmpl.end(), placeholderRegex);
|
||||
placeholders.clear();
|
||||
placeholders.insert(placeholders.end(), it, std::sregex_iterator());
|
||||
|
||||
if (placeholders.size() > 2) {
|
||||
err = "ERROR: expected at most two placeholders, got " + std::to_string(placeholders.size());
|
||||
return false;
|
||||
}
|
||||
if (placeholders.size() >= 1 && placeholders[0].str() != "%1") {
|
||||
err = "ERROR: first placeholder must be %1, got " + placeholders[0].str();
|
||||
return false;
|
||||
}
|
||||
if (placeholders.size() >= 2 && placeholders[1].str() != "%2") {
|
||||
err = "ERROR: second placeholder must be %2, got " + placeholders[1].str();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLModel::prompt(const std::string &prompt,
|
||||
const std::string &promptTemplate,
|
||||
std::function<bool(int32_t)> promptCallback,
|
||||
std::function<bool(int32_t, const std::string&)> responseCallback,
|
||||
std::function<bool(bool)> recalculateCallback,
|
||||
PromptContext &promptCtx)
|
||||
PromptContext &promptCtx,
|
||||
bool special,
|
||||
std::string *fakeReply)
|
||||
{
|
||||
if (!isModelLoaded()) {
|
||||
std::cerr << implementation().modelType() << " ERROR: prompt won't work with an unloaded model!\n";
|
||||
@@ -42,15 +82,89 @@ void LLModel::prompt(const std::string &prompt,
|
||||
}
|
||||
|
||||
if (!supportsCompletion()) {
|
||||
std::string errorMessage = "ERROR: this model does not support text completion or chat!\n";
|
||||
std::string errorMessage = "ERROR: this model does not support text completion or chat!";
|
||||
responseCallback(-1, errorMessage);
|
||||
std::cerr << implementation().modelType() << errorMessage;
|
||||
std::cerr << implementation().modelType() << " " << errorMessage << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// tokenize the prompt
|
||||
std::vector<Token> embd_inp = tokenize(promptCtx, prompt);
|
||||
// parse the prompt template
|
||||
std::vector<std::smatch> placeholders;
|
||||
{
|
||||
std::string err;
|
||||
if (!parsePromptTemplate(promptTemplate, placeholders, err)) {
|
||||
responseCallback(-1, err);
|
||||
std::cerr << err << "\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto old_n_past = promptCtx.n_past; // prepare to fake n_past for tokenize
|
||||
|
||||
// tokenize the user prompt
|
||||
std::vector<Token> embd_inp;
|
||||
if (placeholders.empty()) {
|
||||
// this is unusual, but well-defined
|
||||
std::cerr << __func__ << ": prompt template has no placeholder\n";
|
||||
embd_inp = tokenize(promptCtx, promptTemplate, true);
|
||||
} else {
|
||||
// template: beginning of user prompt
|
||||
const auto &phUser = placeholders[0];
|
||||
std::string userPrefix(phUser.prefix());
|
||||
if (!userPrefix.empty()) {
|
||||
embd_inp = tokenize(promptCtx, userPrefix, true);
|
||||
promptCtx.n_past += embd_inp.size();
|
||||
}
|
||||
|
||||
// user input (shouldn't have special token processing)
|
||||
auto tokens = tokenize(promptCtx, prompt, special);
|
||||
embd_inp.insert(embd_inp.end(), tokens.begin(), tokens.end());
|
||||
promptCtx.n_past += tokens.size();
|
||||
|
||||
// template: end of user prompt + start of assistant prompt
|
||||
size_t start = phUser.position() + phUser.length();
|
||||
size_t end = placeholders.size() >= 2 ? placeholders[1].position() : promptTemplate.length();
|
||||
auto userToAsst = promptTemplate.substr(start, end - start);
|
||||
if (!userToAsst.empty()) {
|
||||
tokens = tokenize(promptCtx, userToAsst, true);
|
||||
embd_inp.insert(embd_inp.end(), tokens.begin(), tokens.end());
|
||||
promptCtx.n_past += tokens.size();
|
||||
}
|
||||
}
|
||||
|
||||
promptCtx.n_past = old_n_past; // restore n_past so decodePrompt can increment it
|
||||
|
||||
// decode the user prompt
|
||||
decodePrompt(promptCallback, responseCallback, recalculateCallback, promptCtx, embd_inp);
|
||||
|
||||
// decode the assistant's reply, either generated or spoofed
|
||||
if (fakeReply == nullptr) {
|
||||
generateResponse(responseCallback, recalculateCallback, promptCtx);
|
||||
} else {
|
||||
embd_inp = tokenize(promptCtx, *fakeReply, false);
|
||||
decodePrompt(promptCallback, responseCallback, recalculateCallback, promptCtx, embd_inp);
|
||||
}
|
||||
|
||||
// decode the rest of the prompt template
|
||||
// template: end of assistant prompt
|
||||
std::string asstSuffix;
|
||||
if (placeholders.size() >= 2) {
|
||||
size_t start = placeholders[1].position() + placeholders[1].length();
|
||||
asstSuffix = promptTemplate.substr(start);
|
||||
} else {
|
||||
asstSuffix = "\n\n"; // default to a blank link, good for e.g. Alpaca
|
||||
}
|
||||
if (!asstSuffix.empty()) {
|
||||
embd_inp = tokenize(promptCtx, asstSuffix, true);
|
||||
decodePrompt(promptCallback, responseCallback, recalculateCallback, promptCtx, embd_inp);
|
||||
}
|
||||
}
|
||||
|
||||
void LLModel::decodePrompt(std::function<bool(int32_t)> promptCallback,
|
||||
std::function<bool(int32_t, const std::string&)> responseCallback,
|
||||
std::function<bool(bool)> recalculateCallback,
|
||||
PromptContext &promptCtx,
|
||||
std::vector<Token> embd_inp) {
|
||||
// save the context size
|
||||
promptCtx.n_ctx = contextLength();
|
||||
|
||||
@@ -73,11 +187,6 @@ void LLModel::prompt(const std::string &prompt,
|
||||
|
||||
// Check if the context has run out...
|
||||
if (promptCtx.n_past + int32_t(batch.size()) > promptCtx.n_ctx) {
|
||||
const int32_t erasePoint = promptCtx.n_ctx * promptCtx.contextErase;
|
||||
// Erase the first percentage of context from the tokens...
|
||||
std::cerr << implementation().modelType() << ": reached the end of the context window so resizing\n";
|
||||
promptCtx.tokens.erase(promptCtx.tokens.begin(), promptCtx.tokens.begin() + erasePoint);
|
||||
promptCtx.n_past = promptCtx.tokens.size();
|
||||
recalculateContext(promptCtx, recalculateCallback);
|
||||
assert(promptCtx.n_past + int32_t(batch.size()) <= promptCtx.n_ctx);
|
||||
}
|
||||
@@ -98,7 +207,11 @@ void LLModel::prompt(const std::string &prompt,
|
||||
}
|
||||
i = batch_end;
|
||||
}
|
||||
}
|
||||
|
||||
void LLModel::generateResponse(std::function<bool(int32_t, const std::string&)> responseCallback,
|
||||
std::function<bool(bool)> recalculateCallback,
|
||||
PromptContext &promptCtx) {
|
||||
std::string cachedResponse;
|
||||
std::vector<Token> cachedTokens;
|
||||
std::unordered_set<std::string> reversePrompts
|
||||
@@ -112,11 +225,6 @@ void LLModel::prompt(const std::string &prompt,
|
||||
|
||||
// Check if the context has run out...
|
||||
if (promptCtx.n_past + 1 > promptCtx.n_ctx) {
|
||||
const int32_t erasePoint = promptCtx.n_ctx * promptCtx.contextErase;
|
||||
// Erase the first percentage of context from the tokens...
|
||||
std::cerr << implementation().modelType() << ": reached the end of the context window so resizing\n";
|
||||
promptCtx.tokens.erase(promptCtx.tokens.begin(), promptCtx.tokens.begin() + erasePoint);
|
||||
promptCtx.n_past = promptCtx.tokens.size();
|
||||
recalculateContext(promptCtx, recalculateCallback);
|
||||
assert(promptCtx.n_past + 1 <= promptCtx.n_ctx);
|
||||
}
|
||||
@@ -169,34 +277,31 @@ void LLModel::prompt(const std::string &prompt,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> LLModel::embedding(const std::string &/*text*/)
|
||||
{
|
||||
if (!supportsCompletion()) {
|
||||
std::string errorMessage = "ERROR: this model does not support generating embeddings!\n";
|
||||
std::cerr << implementation().modelType() << errorMessage;
|
||||
}
|
||||
return std::vector<float>();
|
||||
void LLModel::embed(
|
||||
const std::vector<std::string> &texts, float *embeddings, std::optional<std::string> prefix, int dimensionality,
|
||||
size_t *tokenCount, bool doMean, bool atlas, EmbedCancelCallback *cancelCb
|
||||
) {
|
||||
(void)texts;
|
||||
(void)embeddings;
|
||||
(void)prefix;
|
||||
(void)dimensionality;
|
||||
(void)tokenCount;
|
||||
(void)doMean;
|
||||
(void)atlas;
|
||||
(void)cancelCb;
|
||||
throw std::logic_error(std::string(implementation().modelType()) + " does not support embeddings");
|
||||
}
|
||||
|
||||
std::vector<LLModel::GPUDevice> LLModel::availableGPUDevices()
|
||||
{
|
||||
#if defined(GGML_USE_KOMPUTE)
|
||||
std::vector<ggml_vk_device> vkDevices = ggml_vk_available_devices(0);
|
||||
|
||||
std::vector<LLModel::GPUDevice> devices;
|
||||
for(const auto& vkDevice : vkDevices) {
|
||||
LLModel::GPUDevice device;
|
||||
device.index = vkDevice.index;
|
||||
device.type = vkDevice.type;
|
||||
device.heapSize = vkDevice.heapSize;
|
||||
device.name = vkDevice.name;
|
||||
device.vendor = vkDevice.vendor;
|
||||
|
||||
devices.push_back(device);
|
||||
}
|
||||
|
||||
return devices;
|
||||
#else
|
||||
return std::vector<LLModel::GPUDevice>();
|
||||
#endif
|
||||
void LLModel::embed(
|
||||
const std::vector<std::string> &texts, float *embeddings, bool isRetrieval, int dimensionality, size_t *tokenCount,
|
||||
bool doMean, bool atlas
|
||||
) {
|
||||
(void)texts;
|
||||
(void)embeddings;
|
||||
(void)isRetrieval;
|
||||
(void)dimensionality;
|
||||
(void)tokenCount;
|
||||
(void)doMean;
|
||||
(void)atlas;
|
||||
throw std::logic_error(std::string(implementation().modelType()) + " does not support embeddings");
|
||||
}
|
||||
|
||||
@@ -1,52 +1,11 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include <ggml.h>
|
||||
|
||||
#if defined(GGML_USE_KOMPUTE)
|
||||
#include "ggml-vulkan.h"
|
||||
struct llm_buffer {
|
||||
uint8_t * addr = NULL;
|
||||
size_t size = 0;
|
||||
ggml_vk_memory memory;
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
llm_buffer() = default;
|
||||
|
||||
void resize(size_t size) {
|
||||
free();
|
||||
|
||||
if (!ggml_vk_has_device()) {
|
||||
this->addr = new uint8_t[size];
|
||||
this->size = size;
|
||||
} else {
|
||||
this->memory = ggml_vk_allocate(size);
|
||||
this->addr = (uint8_t*)memory.data;
|
||||
this->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
void free() {
|
||||
if (!memory.primaryMemory) {
|
||||
delete[] addr;
|
||||
} else if (memory.data) {
|
||||
ggml_vk_free_memory(memory);
|
||||
}
|
||||
this->addr = NULL;
|
||||
this->size = 0;
|
||||
}
|
||||
|
||||
~llm_buffer() {
|
||||
free();
|
||||
}
|
||||
|
||||
// disable copy and move
|
||||
llm_buffer(const llm_buffer&) = delete;
|
||||
llm_buffer(llm_buffer&&) = delete;
|
||||
llm_buffer& operator=(const llm_buffer&) = delete;
|
||||
llm_buffer& operator=(llm_buffer&&) = delete;
|
||||
};
|
||||
#else
|
||||
struct llm_buffer {
|
||||
uint8_t * addr = NULL;
|
||||
size_t size = 0;
|
||||
@@ -61,7 +20,6 @@ struct llm_buffer {
|
||||
delete[] addr;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct llm_kv_cache {
|
||||
struct ggml_tensor * k;
|
||||
@@ -80,7 +38,8 @@ struct llm_kv_cache {
|
||||
}
|
||||
};
|
||||
|
||||
inline void ggml_graph_compute_g4a(llm_buffer& buf, ggml_cgraph * graph, int n_threads) {
|
||||
inline void ggml_graph_compute_g4a(llm_buffer& buf, ggml_cgraph * graph, int n_threads)
|
||||
{
|
||||
struct ggml_cplan plan = ggml_graph_plan(graph, n_threads);
|
||||
if (plan.work_size > 0) {
|
||||
buf.resize(plan.work_size);
|
||||
|
||||
@@ -27,7 +27,7 @@ from pathlib import Path
|
||||
|
||||
import gguf
|
||||
import numpy as np
|
||||
from transformers import AutoTokenizer, GPTJConfig, GPTJForCausalLM
|
||||
from transformers import AutoConfig, AutoTokenizer, GPTJForCausalLM
|
||||
from transformers.models.gpt2 import tokenization_gpt2
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ gguf_writer = gguf.GGUFWriter(fname_out, gguf.MODEL_ARCH_NAMES[ARCH])
|
||||
|
||||
print("gguf: get model metadata")
|
||||
|
||||
config = GPTJConfig(dir_model)
|
||||
config = AutoConfig.from_pretrained(dir_model)
|
||||
|
||||
block_count = config.n_layer
|
||||
gguf_writer.add_name("GPT-J")
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Convert Hugging Face fine-tuned bloom-like models to ggml format
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# python3 models/convert-h5-to-ggml.py
|
||||
#
|
||||
# This script is similar to "convert-pt-to-ggml.py"
|
||||
#
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import gguf
|
||||
import numpy as np
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM, AutoConfig, MptConfig
|
||||
from transformers.models.gpt2 import tokenization_gpt2
|
||||
|
||||
|
||||
if not 3 <= len(sys.argv) < 5:
|
||||
print("Usage: {} model-name dir-output [ftype]".format(Path(__file__).name))
|
||||
print(" model-name: name of the model to convert. Example: 'bigscience/bloomz-560m'")
|
||||
print(" dir-output: directory where the output file will be written")
|
||||
print(" ftype == 0 -> float32")
|
||||
print(" ftype == 1 -> float16")
|
||||
sys.exit(1)
|
||||
|
||||
dir_model = Path(sys.argv[1])
|
||||
dir_out = Path(sys.argv[2])
|
||||
|
||||
# make sure the output directory exists
|
||||
dir_out.mkdir(exist_ok=True)
|
||||
|
||||
# possible data types
|
||||
# ftype == 0 -> float32
|
||||
# ftype == 1 -> float16
|
||||
#
|
||||
# map from ftype to string
|
||||
ftype_str = ["f32", "f16"]
|
||||
|
||||
ftype = 1
|
||||
if len(sys.argv) > 3:
|
||||
ftype = int(sys.argv[3])
|
||||
if ftype < 0 or ftype > 1:
|
||||
print("Invalid ftype: " + str(ftype))
|
||||
sys.exit(1)
|
||||
|
||||
fname_out = dir_out / f"ggml-model-{dir_model.name}-{ftype_str[ftype]}.gguf"
|
||||
|
||||
|
||||
ARCH = gguf.MODEL_ARCH.MPT
|
||||
gguf_writer = gguf.GGUFWriter(fname_out, gguf.MODEL_ARCH_NAMES[ARCH])
|
||||
|
||||
print("gguf: get model metadata")
|
||||
|
||||
config = AutoConfig.from_pretrained(dir_model, trust_remote_code=True)
|
||||
|
||||
block_count = config.n_layers
|
||||
gguf_writer.add_name("MPT")
|
||||
gguf_writer.add_context_length(config.max_seq_len)
|
||||
gguf_writer.add_embedding_length(config.d_model)
|
||||
gguf_writer.add_block_count(block_count)
|
||||
gguf_writer.add_feed_forward_length(4 * config.d_model)
|
||||
gguf_writer.add_head_count(config.n_heads)
|
||||
if kv_n_heads := config.attn_config.get('kv_n_heads'):
|
||||
gguf_writer.add_head_count_kv(kv_n_heads)
|
||||
gguf_writer.add_max_alibi_bias(config.attn_config['alibi_bias_max'])
|
||||
gguf_writer.add_layer_norm_eps(MptConfig().layer_norm_epsilon) # use default from upstream transformers
|
||||
gguf_writer.add_file_type(ftype)
|
||||
|
||||
clip_qkv = config.attn_config['clip_qkv']
|
||||
if clip_qkv is not None:
|
||||
gguf_writer.add_clamp_kqv(clip_qkv)
|
||||
|
||||
print("gguf: get gpt2 tokenizer vocab")
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(dir_model)
|
||||
|
||||
special_ids = tokenizer.all_special_ids
|
||||
|
||||
reverse_vocab = {id: encoded_tok for encoded_tok, id in tokenizer.vocab.items()}
|
||||
added_tokens = tokenizer.get_added_vocab().values()
|
||||
byte_encoder = tokenization_gpt2.bytes_to_unicode()
|
||||
byte_decoder = {v: k for k, v in byte_encoder.items()}
|
||||
|
||||
tokens: list[bytearray] = []
|
||||
toktypes: list[gguf.TokenType] = []
|
||||
|
||||
# The number of tokens in tokenizer.json can differ from the expected vocab size.
|
||||
# This causes downstream issues with mismatched tensor sizes when running the inference
|
||||
for i in range(config.vocab_size):
|
||||
if i not in reverse_vocab:
|
||||
print(f"Key {i} not in tokenizer vocabulary. Padding with an arbitrary token.")
|
||||
pad_token = f"[PAD{i}]".encode("utf8")
|
||||
text = bytearray(pad_token)
|
||||
elif i in added_tokens:
|
||||
# these tokens are not encoded, for some reason
|
||||
text = bytearray(reverse_vocab[i].encode('utf-8'))
|
||||
else:
|
||||
text = bytearray([byte_decoder[c] for c in reverse_vocab[i]])
|
||||
|
||||
tokens.append(text)
|
||||
|
||||
# TODO(cebtenzzre): is there a better way to do this?
|
||||
toktypes.append(gguf.TokenType.CONTROL if i in special_ids else gguf.TokenType.NORMAL)
|
||||
|
||||
gguf_writer.add_tokenizer_model("gpt2")
|
||||
gguf_writer.add_token_list(tokens)
|
||||
gguf_writer.add_token_types(toktypes)
|
||||
|
||||
special_vocab = gguf.SpecialVocab(dir_model, load_merges=True)
|
||||
special_vocab.add_to_gguf(gguf_writer)
|
||||
|
||||
print("gguf: get tensor metadata")
|
||||
|
||||
print("Loading model:", dir_model)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
dir_model, config=config, torch_dtype=torch.float16 if ftype == 1 else torch.float32,
|
||||
low_cpu_mem_usage=True, trust_remote_code=True,
|
||||
)
|
||||
print("Model loaded:", dir_model)
|
||||
|
||||
tensor_map = gguf.get_tensor_name_map(ARCH, block_count)
|
||||
|
||||
list_vars = model.state_dict()
|
||||
for name in list_vars.keys():
|
||||
data = list_vars[name].squeeze().numpy()
|
||||
print("Processing variable:", name, "with shape:", data.shape)
|
||||
|
||||
n_dims = len(data.shape)
|
||||
|
||||
# ftype == 0 -> float32, ftype == 1 -> float16
|
||||
ftype_cur = 0
|
||||
# Keep token embeddings in fp32
|
||||
if ftype == 1 and name[-7:] == ".weight" and n_dims == 2 and ".wte" not in name:
|
||||
print(" Converting to float16")
|
||||
data = data.astype(np.float16)
|
||||
ftype_cur = 1
|
||||
elif ftype == 1 or data.dtype != np.float32:
|
||||
print(" Converting to float32")
|
||||
data = data.astype(np.float32)
|
||||
ftype_cur = 0
|
||||
|
||||
# map tensor names
|
||||
new_name = tensor_map.get_name(name, try_suffixes=(".weight", ".bias"))
|
||||
if new_name is None:
|
||||
print("Can not map tensor '" + name + "'")
|
||||
sys.exit()
|
||||
|
||||
gguf_writer.add_tensor(new_name, data)
|
||||
|
||||
|
||||
print("gguf: write header")
|
||||
gguf_writer.write_header_to_file()
|
||||
print("gguf: write metadata")
|
||||
gguf_writer.write_kv_data_to_file()
|
||||
print("gguf: write tensors")
|
||||
gguf_writer.write_tensors_to_file()
|
||||
|
||||
gguf_writer.close()
|
||||
|
||||
print(f"gguf: model successfully exported to '{fname_out}'")
|
||||
print()
|
||||
@@ -1,145 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import gguf
|
||||
import numpy as np
|
||||
from sentencepiece import SentencePieceProcessor
|
||||
from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
|
||||
if not 2 <= len(sys.argv) < 4:
|
||||
print("Usage: {} dir-model [ftype]\n".format(Path(__file__).name))
|
||||
print(" ftype == 0 -> float32")
|
||||
print(" ftype == 1 -> float16")
|
||||
sys.exit(1)
|
||||
|
||||
# output in the same directory as the model
|
||||
dir_model = Path(sys.argv[1])
|
||||
|
||||
# possible data types
|
||||
# ftype == 0 -> float32
|
||||
# ftype == 1 -> float16
|
||||
#
|
||||
# map from ftype to string
|
||||
ftype_str = ["f32", "f16"]
|
||||
|
||||
ftype = 1
|
||||
if len(sys.argv) > 2:
|
||||
ftype = int(sys.argv[2])
|
||||
if ftype < 0 or ftype > 1:
|
||||
print("Invalid ftype: " + str(ftype))
|
||||
sys.exit(1)
|
||||
|
||||
fname_out = dir_model / ("ggml-replit-code-v1-3b-" + ftype_str[ftype] + ".gguf")
|
||||
|
||||
|
||||
ARCH = gguf.MODEL_ARCH.MPT
|
||||
gguf_writer = gguf.GGUFWriter(fname_out, gguf.MODEL_ARCH_NAMES[ARCH])
|
||||
|
||||
print("gguf: get model metadata")
|
||||
|
||||
config = AutoConfig.from_pretrained(dir_model)
|
||||
|
||||
block_count = config.n_layers
|
||||
gguf_writer.add_name("Replit")
|
||||
gguf_writer.add_context_length(config.max_seq_len)
|
||||
gguf_writer.add_embedding_length(config.d_model)
|
||||
gguf_writer.add_block_count(block_count)
|
||||
gguf_writer.add_feed_forward_length(4 * config.d_model)
|
||||
gguf_writer.add_head_count(config.n_heads)
|
||||
gguf_writer.add_max_alibi_bias(config.attn_config.alibi_bias_max)
|
||||
gguf_writer.add_layer_norm_eps(config.layer_norm_epsilon)
|
||||
gguf_writer.add_file_type(ftype)
|
||||
|
||||
clip_qkv = config.attn_config.clip_qkv
|
||||
if clip_qkv is not None:
|
||||
gguf_writer.add_clamp_kqv(clip_qkv)
|
||||
|
||||
print("gguf: get sentencepiece tokenizer vocab")
|
||||
|
||||
tokenizer = SentencePieceProcessor(str(dir_model / "spiece.model"))
|
||||
#print(tokenizer.encode('I believe the meaning of life is'))
|
||||
|
||||
tokens: list[bytearray] = []
|
||||
scores: list[float] = []
|
||||
toktypes: list[int] = []
|
||||
|
||||
for i in range(tokenizer.vocab_size()):
|
||||
tokens.append(tokenizer.id_to_piece(i).encode('utf-8'))
|
||||
scores.append(tokenizer.get_score(i))
|
||||
|
||||
toktype = gguf.TokenType.NORMAL
|
||||
if tokenizer.is_unknown(i):
|
||||
toktype = gguf.TokenType.UNKNOWN
|
||||
elif tokenizer.is_control(i):
|
||||
toktype = gguf.TokenType.CONTROL
|
||||
elif tokenizer.is_unused(i):
|
||||
toktype = gguf.TokenType.UNUSED
|
||||
elif tokenizer.is_byte(i):
|
||||
toktype = gguf.TokenType.BYTE
|
||||
|
||||
toktypes.append(toktype)
|
||||
|
||||
gguf_writer.add_tokenizer_model("llama") # sentencepiece
|
||||
gguf_writer.add_token_list(tokens)
|
||||
gguf_writer.add_token_scores(scores)
|
||||
gguf_writer.add_token_types(toktypes)
|
||||
|
||||
special_vocab = gguf.SpecialVocab(dir_model, load_merges=True)
|
||||
special_vocab.add_to_gguf(gguf_writer)
|
||||
|
||||
print("gguf: get tensor metadata")
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(dir_model, config=config, low_cpu_mem_usage=True)
|
||||
#print(model)
|
||||
|
||||
tensor_map = gguf.get_tensor_name_map(ARCH, block_count)
|
||||
|
||||
list_vars = model.state_dict()
|
||||
for name in list_vars.keys():
|
||||
print(name, list_vars[name].shape, list_vars[name].dtype)
|
||||
|
||||
print(config)
|
||||
|
||||
for name in list_vars.keys():
|
||||
data = list_vars[name].squeeze().numpy()
|
||||
print("Processing variable:", name, "with shape:", data.shape)
|
||||
|
||||
n_dims = len(data.shape)
|
||||
|
||||
# ftype == 0 -> float32, ftype == 1 -> float16
|
||||
ftype_cur = 0
|
||||
if ftype == 1 and name[-7:] == ".weight" and n_dims == 2:
|
||||
print(" Converting to float16")
|
||||
data = data.astype(np.float16)
|
||||
ftype_cur = 1
|
||||
elif ftype == 1 or data.dtype != np.float32:
|
||||
print(" Converting to float32")
|
||||
data = data.astype(np.float32)
|
||||
ftype_cur = 0
|
||||
|
||||
# map tensor names
|
||||
new_name = tensor_map.get_name(name, try_suffixes=(".weight", ".bias"))
|
||||
if new_name is None:
|
||||
print("Can not map tensor '" + name + "'")
|
||||
sys.exit()
|
||||
|
||||
gguf_writer.add_tensor(new_name, data)
|
||||
|
||||
|
||||
print("gguf: write header")
|
||||
gguf_writer.write_header_to_file()
|
||||
print("gguf: write metadata")
|
||||
gguf_writer.write_kv_data_to_file()
|
||||
print("gguf: write tensors")
|
||||
gguf_writer.write_tensors_to_file()
|
||||
|
||||
gguf_writer.close()
|
||||
|
||||
print(f"gguf: model successfully exported to '{fname_out}'")
|
||||
print()
|
||||
@@ -2,17 +2,21 @@
|
||||
#define SYSINFO_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <unistd.h>
|
||||
# include <unistd.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
static long long getSystemTotalRAMInBytes()
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
|
||||
void replace(std::string & str, const std::string & needle, const std::string & replacement) {
|
||||
void replace(std::string & str, const std::string & needle, const std::string & replacement)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = str.find(needle, pos)) != std::string::npos) {
|
||||
str.replace(pos, needle.length(), replacement);
|
||||
@@ -11,7 +17,8 @@ void replace(std::string & str, const std::string & needle, const std::string &
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, int32_t> json_parse(const std::string & fname) {
|
||||
std::map<std::string, int32_t> json_parse(const std::string & fname)
|
||||
{
|
||||
std::map<std::string, int32_t> result;
|
||||
|
||||
// read file into string
|
||||
@@ -102,7 +109,8 @@ std::map<std::string, int32_t> json_parse(const std::string & fname) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<gpt_vocab::id> gpt_tokenize_inner(const gpt_vocab & vocab, const std::string & text) {
|
||||
std::vector<gpt_vocab::id> gpt_tokenize_inner(const gpt_vocab & vocab, const std::string & text)
|
||||
{
|
||||
std::vector<std::string> words;
|
||||
|
||||
// first split the text into words
|
||||
@@ -157,12 +165,14 @@ std::vector<gpt_vocab::id> gpt_tokenize_inner(const gpt_vocab & vocab, const std
|
||||
return tokens;
|
||||
}
|
||||
|
||||
std::string regex_escape(const std::string &s) {
|
||||
std::string regex_escape(const std::string &s)
|
||||
{
|
||||
static const std::regex metacharacters(R"([\.\^\$\-\+\(\)\[\]\{\}\|\?\*])");
|
||||
return std::regex_replace(s, metacharacters, "\\$&");
|
||||
}
|
||||
|
||||
std::vector<gpt_vocab::id> gpt_tokenize(const gpt_vocab & vocab, const std::string & text) {
|
||||
std::vector<gpt_vocab::id> gpt_tokenize(const gpt_vocab & vocab, const std::string & text)
|
||||
{
|
||||
// Generate the subpattern from the special_tokens vector if it's not empty
|
||||
if (!vocab.special_tokens.empty()) {
|
||||
std::vector<gpt_vocab::id> out;
|
||||
@@ -198,7 +208,8 @@ std::vector<gpt_vocab::id> gpt_tokenize(const gpt_vocab & vocab, const std::stri
|
||||
}
|
||||
|
||||
|
||||
bool gpt_vocab_init(const std::string & fname, gpt_vocab & vocab) {
|
||||
bool gpt_vocab_init(const std::string & fname, gpt_vocab & vocab)
|
||||
{
|
||||
printf("%s: loading vocab from '%s'\n", __func__, fname.c_str());
|
||||
|
||||
vocab.token_to_id = ::json_parse(fname);
|
||||
@@ -325,4 +336,4 @@ gpt_vocab::id gpt_sample_top_k_top_p(
|
||||
int idx = dist(rng);
|
||||
|
||||
return logits_id[idx].second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
//
|
||||
// General purpose inline functions
|
||||
//
|
||||
constexpr inline unsigned long long operator ""_MiB(unsigned long long bytes) {
|
||||
constexpr inline unsigned long long operator ""_MiB(unsigned long long bytes)
|
||||
{
|
||||
return bytes*1024*1024;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
# GPT4All Bindings
|
||||
This directory will contain language specific bindings on top of the C/C++ model backends.
|
||||
We will have one directory per language binding (e.g. Python, Typescript, Golang, etc.).
|
||||
# GPT4All Language Bindings
|
||||
These are the language bindings for the GPT4All backend. They provide functionality to load GPT4All models (and other llama.cpp models), generate text, and (in the case of the Python bindings) embed text as a vector representation.
|
||||
|
||||
See their respective folders for language-specific documentation.
|
||||
|
||||
### Languages
|
||||
- [Python](https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/python) (Nomic official, maintained by [@cebtenzzre](https://github.com/cebtenzzre))
|
||||
- [Node.js/Typescript](https://github.com/nomic-ai/gpt4all/tree/main/gpt4all-bindings/typescript) (community, maintained by [@jacoobes](https://github.com/jacoobes) and [@iimez](https://github.com/iimez))
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<details><summary><b>Archived Bindings</b></summary>
|
||||
<br/>
|
||||
|
||||
The following bindings have been removed from this repository due to lack of maintenance. If adopted, they can be brought back—feel free to message a developer on Dicsord if you are interested in maintaining one of them. Below are links to their last available version (not necessarily the last working version).
|
||||
- C#: [41c9013f](https://github.com/nomic-ai/gpt4all/tree/41c9013fa46a194b3e4fee6ced1b9d1b65e177ac/gpt4all-bindings/csharp)
|
||||
- Java: [41c9013f](https://github.com/nomic-ai/gpt4all/tree/41c9013fa46a194b3e4fee6ced1b9d1b65e177ac/gpt4all-bindings/java)
|
||||
- Go: [41c9013f](https://github.com/nomic-ai/gpt4all/tree/41c9013fa46a194b3e4fee6ced1b9d1b65e177ac/gpt4all-bindings/golang)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -40,5 +40,5 @@ directory, if necessary.
|
||||
If you have already saved a model beforehand, specify its path with the `-m`/`--model` argument,
|
||||
for example:
|
||||
```shell
|
||||
python app.py repl --model /home/user/my-gpt4all-models/GPT4All-13B-snoozy.ggmlv3.q4_0.bin
|
||||
python app.py repl --model /home/user/my-gpt4all-models/gpt4all-13b-snoozy-q4_0.gguf
|
||||
```
|
||||
|
||||
11
gpt4all-bindings/cli/app.py
Normal file → Executable file
11
gpt4all-bindings/cli/app.py
Normal file → Executable file
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
"""GPT4All CLI
|
||||
|
||||
The GPT4All CLI is a self-contained script based on the `gpt4all` and `typer` packages. It offers a
|
||||
@@ -53,14 +54,18 @@ def repl(
|
||||
model: Annotated[
|
||||
str,
|
||||
typer.Option("--model", "-m", help="Model to use for chatbot"),
|
||||
] = "ggml-gpt4all-j-v1.3-groovy",
|
||||
] = "mistral-7b-instruct-v0.1.Q4_0.gguf",
|
||||
n_threads: Annotated[
|
||||
int,
|
||||
typer.Option("--n-threads", "-t", help="Number of threads to use for chatbot"),
|
||||
] = None,
|
||||
device: Annotated[
|
||||
str,
|
||||
typer.Option("--device", "-d", help="Device to use for chatbot, e.g. gpu, amd, nvidia, intel. Defaults to CPU."),
|
||||
] = None,
|
||||
):
|
||||
"""The CLI read-eval-print loop."""
|
||||
gpt4all_instance = GPT4All(model)
|
||||
gpt4all_instance = GPT4All(model, device=device)
|
||||
|
||||
# if threads are passed, set them
|
||||
if n_threads is not None:
|
||||
@@ -115,6 +120,7 @@ def _old_loop(gpt4all_instance):
|
||||
n_predict=200,
|
||||
top_k=40,
|
||||
top_p=0.9,
|
||||
min_p=0.0,
|
||||
temp=0.9,
|
||||
n_batch=9,
|
||||
repeat_penalty=1.1,
|
||||
@@ -151,6 +157,7 @@ def _new_loop(gpt4all_instance):
|
||||
temp=0.9,
|
||||
top_k=40,
|
||||
top_p=0.9,
|
||||
min_p=0.0,
|
||||
repeat_penalty=1.1,
|
||||
repeat_last_n=64,
|
||||
n_batch=9,
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Don't use tabs for indentation.
|
||||
[*]
|
||||
indent_style = space
|
||||
# (Please don't specify an indent_size here; that has too many unintended consequences.)
|
||||
|
||||
# Code files
|
||||
[*.{cs,csx,vb,vbx}]
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
charset = utf-8-bom
|
||||
|
||||
# XML project files
|
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
|
||||
indent_size = 4
|
||||
|
||||
# XML config files
|
||||
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
|
||||
indent_size = 2
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
# Powershell files
|
||||
[*.ps1]
|
||||
indent_size = 2
|
||||
|
||||
# Shell script files
|
||||
[*.sh]
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
# Dotnet code style settings:
|
||||
[*.{cs,vb}]
|
||||
|
||||
# IDE0055: Fix formatting
|
||||
dotnet_diagnostic.IDE0055.severity = error
|
||||
|
||||
# Sort using and Import directives with System.* appearing first
|
||||
dotnet_sort_system_directives_first = true
|
||||
dotnet_separate_import_directive_groups = false
|
||||
|
||||
# Avoid "this." and "Me." if not necessary
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
|
||||
# Use language keywords instead of framework type names for type references
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
|
||||
dotnet_style_predefined_type_for_member_access = true:warning
|
||||
|
||||
# Suggest more modern language features when available
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
|
||||
# Whitespace options
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = false
|
||||
|
||||
# Private fields are camelCase with '_' prefix
|
||||
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
|
||||
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
|
||||
dotnet_naming_rule.private_members_with_underscore.severity = error
|
||||
dotnet_naming_symbols.private_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
|
||||
dotnet_naming_style.prefix_underscore.capitalization = camel_case
|
||||
dotnet_naming_style.prefix_underscore.required_prefix = _
|
||||
|
||||
# Non-private static fields are PascalCase
|
||||
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
|
||||
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
|
||||
|
||||
dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
|
||||
|
||||
dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
|
||||
|
||||
# Non-private readonly fields are PascalCase
|
||||
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
|
||||
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_static_field_style
|
||||
|
||||
dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly
|
||||
|
||||
dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
|
||||
|
||||
# Constants are PascalCase
|
||||
dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
|
||||
dotnet_naming_rule.constants_should_be_pascal_case.style = non_private_static_field_style
|
||||
|
||||
dotnet_naming_symbols.constants.applicable_kinds = field, local
|
||||
dotnet_naming_symbols.constants.required_modifiers = const
|
||||
|
||||
dotnet_naming_style.constant_style.capitalization = pascal_case
|
||||
|
||||
# Static fields are camelCase and start with s_
|
||||
dotnet_naming_rule.static_fields_should_be_camel_case.severity = none
|
||||
dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
|
||||
dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
|
||||
|
||||
dotnet_naming_symbols.static_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.static_fields.required_modifiers = static
|
||||
|
||||
dotnet_naming_style.static_field_style.capitalization = camel_case
|
||||
dotnet_naming_style.static_field_style.required_prefix = s_
|
||||
|
||||
# Instance fields are camelCase and start with _
|
||||
dotnet_naming_rule.instance_fields_should_be_camel_case.severity = none
|
||||
dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
|
||||
dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
|
||||
|
||||
dotnet_naming_symbols.instance_fields.applicable_kinds = field
|
||||
|
||||
dotnet_naming_style.instance_field_style.capitalization = camel_case
|
||||
dotnet_naming_style.instance_field_style.required_prefix = _
|
||||
|
||||
# Locals and parameters are camelCase
|
||||
dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
|
||||
dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
|
||||
dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
|
||||
|
||||
dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
|
||||
|
||||
dotnet_naming_style.camel_case_style.capitalization = camel_case
|
||||
|
||||
# Local functions are PascalCase
|
||||
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
|
||||
dotnet_naming_rule.local_functions_should_be_pascal_case.style = non_private_static_field_style
|
||||
|
||||
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
|
||||
|
||||
dotnet_naming_style.local_function_style.capitalization = pascal_case
|
||||
|
||||
# By default, name items with PascalCase
|
||||
dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
|
||||
dotnet_naming_rule.members_should_be_pascal_case.style = non_private_static_field_style
|
||||
|
||||
dotnet_naming_symbols.all_members.applicable_kinds = *
|
||||
|
||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||
|
||||
# error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}'
|
||||
dotnet_diagnostic.RS2008.severity = none
|
||||
|
||||
# IDE0073: File header
|
||||
dotnet_diagnostic.IDE0073.severity = none
|
||||
#file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license.\nSee the LICENSE file in the project root for more information.
|
||||
|
||||
# IDE0035: Remove unreachable code
|
||||
dotnet_diagnostic.IDE0035.severity = warning
|
||||
|
||||
# IDE0036: Order modifiers
|
||||
dotnet_diagnostic.IDE0036.severity = warning
|
||||
|
||||
# IDE0043: Format string contains invalid placeholder
|
||||
dotnet_diagnostic.IDE0043.severity = warning
|
||||
|
||||
# IDE0044: Make field readonly
|
||||
dotnet_diagnostic.IDE0044.severity = warning
|
||||
|
||||
# IDE1006: Naming rule violation
|
||||
#dotnet_diagnostic.IDE1006.severity = none
|
||||
|
||||
# RS0016: Only enable if API files are present
|
||||
dotnet_public_api_analyzer.require_api_files = true
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
|
||||
# CSharp code style settings:
|
||||
[*.cs]
|
||||
# Newline settings
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = flush_left
|
||||
|
||||
# Whitespace options
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = false
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false
|
||||
|
||||
# Prefer "var" everywhere
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
|
||||
# Prefer method-like constructs to have a block body
|
||||
csharp_style_expression_bodied_methods = false:none
|
||||
csharp_style_expression_bodied_constructors = false:none
|
||||
csharp_style_expression_bodied_operators = false:none
|
||||
|
||||
# Prefer property-like constructs to have an expression-body
|
||||
csharp_style_expression_bodied_properties = true:none
|
||||
csharp_style_expression_bodied_indexers = true:none
|
||||
csharp_style_expression_bodied_accessors = true:none
|
||||
|
||||
# Suggest more modern language features when available
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = do_not_ignore
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# Blocks are allowed
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
# Target-type new expressio
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
|
||||
# Currently only enabled for C# due to crash in VB analyzer. VB can be enabled once
|
||||
# https://github.com/dotnet/roslyn/pull/54259 has been published.
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = false
|
||||
dotnet_diagnostic.RCS0003.severity=warning
|
||||
dotnet_diagnostic.RCS1036.severity=error
|
||||
dotnet_diagnostic.IDE0005.severity=warning
|
||||
dotnet_diagnostic.IDE0007.severity=error
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
csharp_style_namespace_declarations = block_scoped:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||
dotnet_diagnostic.RCS1075.severity = suggestion
|
||||
|
||||
[src/CodeStyle/**.{cs,vb}]
|
||||
# warning RS0005: Do not use generic CodeAction.Create to create CodeAction
|
||||
dotnet_diagnostic.RS0005.severity = none
|
||||
|
||||
[src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}]
|
||||
|
||||
# IDE0011: Add braces
|
||||
csharp_prefer_braces = when_multiline:warning
|
||||
# NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201
|
||||
dotnet_diagnostic.IDE0011.severity = warning
|
||||
|
||||
# IDE0040: Add accessibility modifiers
|
||||
dotnet_diagnostic.IDE0040.severity = warning
|
||||
|
||||
# CONSIDER: Are IDE0051 and IDE0052 too noisy to be warnings for IDE editing scenarios? Should they be made build-only warnings?
|
||||
# IDE0051: Remove unused private member
|
||||
dotnet_diagnostic.IDE0051.severity = warning
|
||||
|
||||
# IDE0052: Remove unread private member
|
||||
dotnet_diagnostic.IDE0052.severity = warning
|
||||
|
||||
# IDE0059: Unnecessary assignment to a value
|
||||
dotnet_diagnostic.IDE0059.severity = warning
|
||||
|
||||
# IDE0060: Remove unused parameter
|
||||
dotnet_diagnostic.IDE0060.severity = warning
|
||||
|
||||
# CA1012: Abstract types should not have public constructors
|
||||
dotnet_diagnostic.CA1012.severity = warning
|
||||
|
||||
# CA1822: Make member static
|
||||
dotnet_diagnostic.CA1822.severity = warning
|
||||
|
||||
# Prefer "var" everywhere
|
||||
dotnet_diagnostic.IDE0007.severity = warning
|
||||
csharp_style_var_for_built_in_types = true:warning
|
||||
csharp_style_var_when_type_is_apparent = true:warning
|
||||
csharp_style_var_elsewhere = true:warning
|
||||
|
||||
# dotnet_style_allow_multiple_blank_lines_experimental
|
||||
dotnet_diagnostic.IDE2000.severity = warning
|
||||
|
||||
# csharp_style_allow_embedded_statements_on_same_line_experimental
|
||||
dotnet_diagnostic.IDE2001.severity = warning
|
||||
|
||||
# csharp_style_allow_blank_lines_between_consecutive_braces_experimental
|
||||
dotnet_diagnostic.IDE2002.severity = warning
|
||||
|
||||
# dotnet_style_allow_statement_immediately_after_block_experimental
|
||||
dotnet_diagnostic.IDE2003.severity = warning
|
||||
|
||||
# csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental
|
||||
dotnet_diagnostic.IDE2004.severity = warning
|
||||
|
||||
[src/{VisualStudio}/**/*.{cs,vb}]
|
||||
# CA1822: Make member static
|
||||
# There is a risk of accidentally breaking an internal API that partners rely on though IVT.
|
||||
dotnet_code_quality.CA1822.api_surface = private
|
||||
379
gpt4all-bindings/csharp/.gitignore
vendored
379
gpt4all-bindings/csharp/.gitignore
vendored
@@ -1,379 +0,0 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
runtimes
|
||||
**/*nuget
|
||||
|
||||
*.zip
|
||||
include/
|
||||
*.exp
|
||||
*.lib
|
||||
*.dll
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
Tests/**/launchSettings.json
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# JetBrains Rider
|
||||
.idea
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode
|
||||
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Company></Company>
|
||||
<Copyright></Copyright>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<Version>0.6.3-alpha</Version>
|
||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(Version)$(VersionSuffix)</Version>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<RepositoryUrl></RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<AnalysisLevel>latest-minimum</AnalysisLevel>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System"/>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Features>strict</Features>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Roslynator.Analyzers" Version="4.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Roslynator.Formatting.Analyzers" Version="4.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,32 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Gpt4All\Gpt4All.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Windows -->
|
||||
<None Include="..\runtimes\win-x64\native\*.dll" Pack="true" PackagePath="runtimes\win-x64\native\%(Filename)%(Extension)" />
|
||||
<!-- Linux -->
|
||||
<None Include="..\runtimes\linux-x64\native\*.so" Pack="true" PackagePath="runtimes\linux-x64\native\%(Filename)%(Extension)" />
|
||||
<!-- MacOS -->
|
||||
<None Include="..\runtimes\osx\native\*.dylib" Pack="true" PackagePath="runtimes\osx\native\%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Windows -->
|
||||
<None Condition="$([MSBuild]::IsOSPlatform('Windows'))" Include="..\runtimes\win-x64\native\*.dll" Visible="False" CopyToOutputDirectory="PreserveNewest" />
|
||||
<!-- Linux -->
|
||||
<None Condition="$([MSBuild]::IsOSPlatform('Linux'))" Include="..\runtimes\linux-x64\native\*.so" Visible="False" CopyToOutputDirectory="PreserveNewest" />
|
||||
<!-- MacOS -->
|
||||
<None Condition="$([MSBuild]::IsOSPlatform('OSX'))" Include="..\runtimes\osx\native\*.dylib" Visible="False" CopyToOutputDirectory="PreserveNewest" />
|
||||
<Content Condition="$([MSBuild]::IsOSPlatform('OSX'))" Include="..\runtimes\osx\native\*.metal" Visible="False" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,22 +0,0 @@
|
||||
using Gpt4All;
|
||||
|
||||
var modelFactory = new Gpt4AllModelFactory();
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Console.WriteLine($"Usage: Gpt4All.Samples <model-path> <prompt>");
|
||||
return;
|
||||
}
|
||||
|
||||
var modelPath = args[0];
|
||||
var prompt = args[1];
|
||||
|
||||
using var model = modelFactory.LoadModel(modelPath);
|
||||
|
||||
var result = await model.GetStreamingPredictionAsync(
|
||||
prompt,
|
||||
PredictRequestOptions.Defaults);
|
||||
|
||||
await foreach (var token in result.GetPredictionStreamingAsync())
|
||||
{
|
||||
Console.Write(token);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Gpt4All.Tests;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const string MODELS_BASE_DIR = "../../../models";
|
||||
public const string LLAMA_MODEL_PATH = $"{MODELS_BASE_DIR}/ggml-gpt4all-l13b-snoozy.bin";
|
||||
public const string GPTJ_MODEL_PATH = $"{MODELS_BASE_DIR}/ggml-gpt4all-j-v1.3-groovy.bin";
|
||||
public const string MPT_MODEL_PATH = $"{MODELS_BASE_DIR}/ggml-mpt-7b-chat.bin";
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.2" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Gpt4All\Gpt4All.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Windows -->
|
||||
<None Include="..\runtimes\win-x64\native\*.dll" Pack="true" PackagePath="runtimes\win-x64\native\%(Filename)%(Extension)" />
|
||||
<!-- Linux -->
|
||||
<None Include="..\runtimes\linux-x64\native\*.so" Pack="true" PackagePath="runtimes\linux-x64\native\%(Filename)%(Extension)" />
|
||||
<!-- MacOS -->
|
||||
<None Include="..\runtimes\osx\native\*.dylib" Pack="true" PackagePath="runtimes\osx\native\%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Windows -->
|
||||
<None Condition="$([MSBuild]::IsOSPlatform('Windows'))" Include="..\runtimes\win-x64\native\*.dll" Visible="False" CopyToOutputDirectory="PreserveNewest" />
|
||||
<!-- Linux -->
|
||||
<None Condition="$([MSBuild]::IsOSPlatform('Linux'))" Include="..\runtimes\linux-x64\native\*.so" Visible="False" CopyToOutputDirectory="PreserveNewest" />
|
||||
<!-- MacOS -->
|
||||
<None Condition="$([MSBuild]::IsOSPlatform('OSX'))" Include="..\runtimes\osx\native\*.dylib" Visible="False" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Roslynator.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Update="Roslynator.CodeAnalysis.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Update="Roslynator.Formatting.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,34 +0,0 @@
|
||||
using Xunit;
|
||||
|
||||
namespace Gpt4All.Tests;
|
||||
|
||||
public class ModelFactoryTests
|
||||
{
|
||||
private readonly Gpt4AllModelFactory _modelFactory;
|
||||
|
||||
public ModelFactoryTests()
|
||||
{
|
||||
_modelFactory = new Gpt4AllModelFactory();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(Traits.SkipOnCI, "True")]
|
||||
public void CanLoadLlamaModel()
|
||||
{
|
||||
using var model = _modelFactory.LoadModel(Constants.LLAMA_MODEL_PATH);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(Traits.SkipOnCI, "True")]
|
||||
public void CanLoadGptjModel()
|
||||
{
|
||||
using var model = _modelFactory.LoadModel(Constants.GPTJ_MODEL_PATH);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(Traits.SkipOnCI, "True")]
|
||||
public void CanLoadMptModel()
|
||||
{
|
||||
using var model = _modelFactory.LoadModel(Constants.MPT_MODEL_PATH);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System.IO;
|
||||
using Gpt4All.LibraryLoader;
|
||||
using Xunit;
|
||||
|
||||
namespace Gpt4All.Tests;
|
||||
|
||||
public class NativeLibraryLoaderTests
|
||||
{
|
||||
[Fact]
|
||||
public void NativeLibraryShouldLoad()
|
||||
{
|
||||
var result = NativeLibraryLoader.LoadNativeLibrary(bypassLoading: false);
|
||||
Assert.True(result.IsSuccess);
|
||||
}
|
||||
|
||||
private const string LLModelLib = "libllmodel.{0}";
|
||||
|
||||
[PlatformSpecificFact(Platforms.Windows)]
|
||||
public void NativeLibraryShouldLoad_Windows()
|
||||
{
|
||||
var libraryLoader = new WindowsLibraryLoader();
|
||||
|
||||
var libraryPath = Path.Combine(
|
||||
Environment.CurrentDirectory,
|
||||
string.Format(LLModelLib, "dll"));
|
||||
|
||||
var result = libraryLoader.OpenLibrary(libraryPath);
|
||||
Assert.True(result.IsSuccess);
|
||||
}
|
||||
|
||||
[PlatformSpecificFact(Platforms.Linux)]
|
||||
public void NativeLibraryShouldLoad_Linux()
|
||||
{
|
||||
var libraryLoader = new LinuxLibraryLoader();
|
||||
|
||||
var libraryPath = Path.Combine(
|
||||
Environment.CurrentDirectory,
|
||||
string.Format(LLModelLib, "so"));
|
||||
|
||||
var result = libraryLoader.OpenLibrary(libraryPath);
|
||||
Assert.True(result.IsSuccess);
|
||||
}
|
||||
|
||||
[PlatformSpecificFact(Platforms.MacOS)]
|
||||
public void NativeLibraryShouldLoad_MacOS()
|
||||
{
|
||||
var libraryLoader = new MacOsLibraryLoader();
|
||||
|
||||
var libraryPath = Path.Combine(
|
||||
Environment.CurrentDirectory,
|
||||
string.Format(LLModelLib, "dylib"));
|
||||
|
||||
var result = libraryLoader.OpenLibrary(libraryPath);
|
||||
Assert.True(result.IsSuccess);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using Xunit;
|
||||
|
||||
namespace Gpt4All.Tests;
|
||||
|
||||
public static class Platforms
|
||||
{
|
||||
public const string Windows = "windows";
|
||||
public const string Linux = "linux";
|
||||
public const string MacOS = "macOS";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This attribute ensures the Fact is only run on the specified platform.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="OperatingSystem.IsOSPlatform(string)"/> for info about the platform string.
|
||||
/// </remarks>
|
||||
public class PlatformSpecificFactAttribute : FactAttribute
|
||||
{
|
||||
public PlatformSpecificFactAttribute(string platform)
|
||||
{
|
||||
if (!OperatingSystem.IsOSPlatform(platform))
|
||||
{
|
||||
Skip = $"Test only runs on {platform}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Gpt4All.Tests;
|
||||
|
||||
public static class Traits
|
||||
{
|
||||
public const string SkipOnCI = "SKIP_ON_CI";
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.33516.290
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gpt4All.Samples", "Gpt4All.Samples\Gpt4All.Samples.csproj", "{59864AE8-E45D-42F7-A7C0-1308EF185F39}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA396C11-CEAD-4368-8234-FB12255A30D2}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.gitignore = .gitignore
|
||||
build_linux.sh = build_linux.sh
|
||||
build_win-mingw.ps1 = build_win-mingw.ps1
|
||||
build_win-msvc.ps1 = build_win-msvc.ps1
|
||||
docs\gpt4all_csharp.md = docs\gpt4all_csharp.md
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gpt4All", "Gpt4All\Gpt4All.csproj", "{6015C62B-2008-426B-A334-740D6F1FE38B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gpt4All.Tests", "Gpt4All.Tests\Gpt4All.Tests.csproj", "{33A72341-52C1-4EAE-878B-A98BC77F686A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{59864AE8-E45D-42F7-A7C0-1308EF185F39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{59864AE8-E45D-42F7-A7C0-1308EF185F39}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{59864AE8-E45D-42F7-A7C0-1308EF185F39}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{59864AE8-E45D-42F7-A7C0-1308EF185F39}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6015C62B-2008-426B-A334-740D6F1FE38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6015C62B-2008-426B-A334-740D6F1FE38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6015C62B-2008-426B-A334-740D6F1FE38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6015C62B-2008-426B-A334-740D6F1FE38B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{33A72341-52C1-4EAE-878B-A98BC77F686A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{33A72341-52C1-4EAE-878B-A98BC77F686A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{33A72341-52C1-4EAE-878B-A98BC77F686A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{33A72341-52C1-4EAE-878B-A98BC77F686A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {17632027-F4C2-4903-B88F-310CE3DE386B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,31 +0,0 @@
|
||||
namespace Gpt4All.Bindings;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the interface exposed by the universal wrapper for GPT4All language models built around llmodel C-API.
|
||||
/// </summary>
|
||||
public interface ILLModel : IDisposable
|
||||
{
|
||||
ModelType ModelType { get; }
|
||||
|
||||
ulong GetStateSizeBytes();
|
||||
|
||||
int GetThreadCount();
|
||||
|
||||
void SetThreadCount(int threadCount);
|
||||
|
||||
bool IsLoaded();
|
||||
|
||||
bool Load(string modelPath);
|
||||
|
||||
void Prompt(
|
||||
string text,
|
||||
LLModelPromptContext context,
|
||||
Func<ModelPromptEventArgs, bool>? promptCallback = null,
|
||||
Func<ModelResponseEventArgs, bool>? responseCallback = null,
|
||||
Func<ModelRecalculatingEventArgs, bool>? recalculateCallback = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
unsafe ulong RestoreStateData(byte* destination);
|
||||
|
||||
unsafe ulong SaveStateData(byte* source);
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace Gpt4All.Bindings;
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for the response processing callback
|
||||
/// </summary>
|
||||
/// <param name="TokenId">The token id of the response</param>
|
||||
/// <param name="Response"> The response string. NOTE: a token_id of -1 indicates the string is an error string</param>
|
||||
/// <return>
|
||||
/// A bool indicating whether the model should keep generating
|
||||
/// </return>
|
||||
public record ModelResponseEventArgs(int TokenId, string Response)
|
||||
{
|
||||
public bool IsError => TokenId == -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for the prompt processing callback
|
||||
/// </summary>
|
||||
/// <param name="TokenId">The token id of the prompt</param>
|
||||
/// <return>
|
||||
/// A bool indicating whether the model should keep processing
|
||||
/// </return>
|
||||
public record ModelPromptEventArgs(int TokenId)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for the recalculating callback
|
||||
/// </summary>
|
||||
/// <param name="IsRecalculating"> whether the model is recalculating the context.</param>
|
||||
/// <return>
|
||||
/// A bool indicating whether the model should keep generating
|
||||
/// </return>
|
||||
public record ModelRecalculatingEventArgs(bool IsRecalculating);
|
||||
|
||||
/// <summary>
|
||||
/// Base class and universal wrapper for GPT4All language models built around llmodel C-API.
|
||||
/// </summary>
|
||||
public class LLModel : ILLModel
|
||||
{
|
||||
protected readonly IntPtr _handle;
|
||||
private readonly ModelType _modelType;
|
||||
private readonly ILogger _logger;
|
||||
private bool _disposed;
|
||||
|
||||
public ModelType ModelType => _modelType;
|
||||
|
||||
internal LLModel(IntPtr handle, ModelType modelType, ILogger? logger = null)
|
||||
{
|
||||
_handle = handle;
|
||||
_modelType = modelType;
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new model from a pointer
|
||||
/// </summary>
|
||||
/// <param name="handle">Pointer to underlying model</param>
|
||||
/// <param name="modelType">The model type</param>
|
||||
public static LLModel Create(IntPtr handle, ModelType modelType, ILogger? logger = null)
|
||||
{
|
||||
return new LLModel(handle, modelType, logger: logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a response using the model
|
||||
/// </summary>
|
||||
/// <param name="text">The input promp</param>
|
||||
/// <param name="context">The context</param>
|
||||
/// <param name="promptCallback">A callback function for handling the processing of prompt</param>
|
||||
/// <param name="responseCallback">A callback function for handling the generated response</param>
|
||||
/// <param name="recalculateCallback">A callback function for handling recalculation requests</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public void Prompt(
|
||||
string text,
|
||||
LLModelPromptContext context,
|
||||
Func<ModelPromptEventArgs, bool>? promptCallback = null,
|
||||
Func<ModelResponseEventArgs, bool>? responseCallback = null,
|
||||
Func<ModelRecalculatingEventArgs, bool>? recalculateCallback = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
GC.KeepAlive(promptCallback);
|
||||
GC.KeepAlive(responseCallback);
|
||||
GC.KeepAlive(recalculateCallback);
|
||||
GC.KeepAlive(cancellationToken);
|
||||
|
||||
_logger.LogInformation("Prompt input='{Prompt}' ctx={Context}", text, context.Dump());
|
||||
|
||||
NativeMethods.llmodel_prompt(
|
||||
_handle,
|
||||
text,
|
||||
(tokenId) =>
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return false;
|
||||
if (promptCallback == null) return true;
|
||||
var args = new ModelPromptEventArgs(tokenId);
|
||||
return promptCallback(args);
|
||||
},
|
||||
(tokenId, response) =>
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogDebug("ResponseCallback evt=CancellationRequested");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseCallback == null) return true;
|
||||
var args = new ModelResponseEventArgs(tokenId, response);
|
||||
return responseCallback(args);
|
||||
},
|
||||
(isRecalculating) =>
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return false;
|
||||
if (recalculateCallback == null) return true;
|
||||
var args = new ModelRecalculatingEventArgs(isRecalculating);
|
||||
return recalculateCallback(args);
|
||||
},
|
||||
ref context.UnderlyingContext
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the number of threads to be used by the model.
|
||||
/// </summary>
|
||||
/// <param name="threadCount">The new thread count</param>
|
||||
public void SetThreadCount(int threadCount)
|
||||
{
|
||||
NativeMethods.llmodel_setThreadCount(_handle, threadCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of threads used by the model.
|
||||
/// </summary>
|
||||
/// <returns>the number of threads used by the model</returns>
|
||||
public int GetThreadCount()
|
||||
{
|
||||
return NativeMethods.llmodel_threadCount(_handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the size of the internal state of the model.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This state data is specific to the type of model you have created.
|
||||
/// </remarks>
|
||||
/// <returns>the size in bytes of the internal state of the model</returns>
|
||||
public ulong GetStateSizeBytes()
|
||||
{
|
||||
return NativeMethods.llmodel_get_state_size(_handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the internal state of the model to the specified destination address.
|
||||
/// </summary>
|
||||
/// <param name="source">A pointer to the src</param>
|
||||
/// <returns>The number of bytes copied</returns>
|
||||
public unsafe ulong SaveStateData(byte* source)
|
||||
{
|
||||
return NativeMethods.llmodel_save_state_data(_handle, source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the internal state of the model using data from the specified address.
|
||||
/// </summary>
|
||||
/// <param name="destination">A pointer to destination</param>
|
||||
/// <returns>the number of bytes read</returns>
|
||||
public unsafe ulong RestoreStateData(byte* destination)
|
||||
{
|
||||
return NativeMethods.llmodel_restore_state_data(_handle, destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the model is loaded.
|
||||
/// </summary>
|
||||
/// <returns>true if the model was loaded successfully, false otherwise.</returns>
|
||||
public bool IsLoaded()
|
||||
{
|
||||
return NativeMethods.llmodel_isModelLoaded(_handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the model from a file.
|
||||
/// </summary>
|
||||
/// <param name="modelPath">The path to the model file.</param>
|
||||
/// <returns>true if the model was loaded successfully, false otherwise.</returns>
|
||||
public bool Load(string modelPath)
|
||||
{
|
||||
return NativeMethods.llmodel_loadModel(_handle, modelPath);
|
||||
}
|
||||
|
||||
protected void Destroy()
|
||||
{
|
||||
NativeMethods.llmodel_model_destroy(_handle);
|
||||
}
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
// dispose managed state
|
||||
}
|
||||
|
||||
switch (_modelType)
|
||||
{
|
||||
default:
|
||||
Destroy();
|
||||
break;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
namespace Gpt4All.Bindings;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper around the llmodel_prompt_context structure for holding the prompt context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The implementation takes care of all the memory handling of the raw logits pointer and the
|
||||
/// raw tokens pointer.Attempting to resize them or modify them in any way can lead to undefined behavior
|
||||
/// </remarks>
|
||||
public unsafe class LLModelPromptContext
|
||||
{
|
||||
private llmodel_prompt_context _ctx;
|
||||
|
||||
internal ref llmodel_prompt_context UnderlyingContext => ref _ctx;
|
||||
|
||||
public LLModelPromptContext()
|
||||
{
|
||||
_ctx = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// logits of current context
|
||||
/// </summary>
|
||||
public Span<float> Logits => new(_ctx.logits, (int)_ctx.logits_size);
|
||||
|
||||
/// <summary>
|
||||
/// the size of the raw logits vector
|
||||
/// </summary>
|
||||
public nuint LogitsSize
|
||||
{
|
||||
get => _ctx.logits_size;
|
||||
set => _ctx.logits_size = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// current tokens in the context window
|
||||
/// </summary>
|
||||
public Span<int> Tokens => new(_ctx.tokens, (int)_ctx.tokens_size);
|
||||
|
||||
/// <summary>
|
||||
/// the size of the raw tokens vector
|
||||
/// </summary>
|
||||
public nuint TokensSize
|
||||
{
|
||||
get => _ctx.tokens_size;
|
||||
set => _ctx.tokens_size = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// top k logits to sample from
|
||||
/// </summary>
|
||||
public int TopK
|
||||
{
|
||||
get => _ctx.top_k;
|
||||
set => _ctx.top_k = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// nucleus sampling probability threshold
|
||||
/// </summary>
|
||||
public float TopP
|
||||
{
|
||||
get => _ctx.top_p;
|
||||
set => _ctx.top_p = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// temperature to adjust model's output distribution
|
||||
/// </summary>
|
||||
public float Temperature
|
||||
{
|
||||
get => _ctx.temp;
|
||||
set => _ctx.temp = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// number of tokens in past conversation
|
||||
/// </summary>
|
||||
public int PastNum
|
||||
{
|
||||
get => _ctx.n_past;
|
||||
set => _ctx.n_past = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// number of predictions to generate in parallel
|
||||
/// </summary>
|
||||
public int Batches
|
||||
{
|
||||
get => _ctx.n_batch;
|
||||
set => _ctx.n_batch = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// number of tokens to predict
|
||||
/// </summary>
|
||||
public int TokensToPredict
|
||||
{
|
||||
get => _ctx.n_predict;
|
||||
set => _ctx.n_predict = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// penalty factor for repeated tokens
|
||||
/// </summary>
|
||||
public float RepeatPenalty
|
||||
{
|
||||
get => _ctx.repeat_penalty;
|
||||
set => _ctx.repeat_penalty = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// last n tokens to penalize
|
||||
/// </summary>
|
||||
public int RepeatLastN
|
||||
{
|
||||
get => _ctx.repeat_last_n;
|
||||
set => _ctx.repeat_last_n = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// number of tokens possible in context window
|
||||
/// </summary>
|
||||
public int ContextSize
|
||||
{
|
||||
get => _ctx.n_ctx;
|
||||
set => _ctx.n_ctx = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// percent of context to erase if we exceed the context window
|
||||
/// </summary>
|
||||
public float ContextErase
|
||||
{
|
||||
get => _ctx.context_erase;
|
||||
set => _ctx.context_erase = value;
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Gpt4All.Bindings;
|
||||
|
||||
public unsafe partial struct llmodel_prompt_context
|
||||
{
|
||||
public float* logits;
|
||||
|
||||
[NativeTypeName("size_t")]
|
||||
public nuint logits_size;
|
||||
|
||||
[NativeTypeName("int32_t *")]
|
||||
public int* tokens;
|
||||
|
||||
[NativeTypeName("size_t")]
|
||||
public nuint tokens_size;
|
||||
|
||||
[NativeTypeName("int32_t")]
|
||||
public int n_past;
|
||||
|
||||
[NativeTypeName("int32_t")]
|
||||
public int n_ctx;
|
||||
|
||||
[NativeTypeName("int32_t")]
|
||||
public int n_predict;
|
||||
|
||||
[NativeTypeName("int32_t")]
|
||||
public int top_k;
|
||||
|
||||
public float top_p;
|
||||
|
||||
public float temp;
|
||||
|
||||
[NativeTypeName("int32_t")]
|
||||
public int n_batch;
|
||||
|
||||
public float repeat_penalty;
|
||||
|
||||
[NativeTypeName("int32_t")]
|
||||
public int repeat_last_n;
|
||||
|
||||
public float context_erase;
|
||||
}
|
||||
#pragma warning disable CA2101
|
||||
internal static unsafe partial class NativeMethods
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
public delegate bool LlmodelResponseCallback(int token_id, [MarshalAs(UnmanagedType.LPUTF8Str)] string response);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
public delegate bool LlmodelPromptCallback(int token_id);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
public delegate bool LlmodelRecalculateCallback(bool isRecalculating);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
[return: NativeTypeName("llmodel_model")]
|
||||
public static extern IntPtr llmodel_model_create2(
|
||||
[NativeTypeName("const char *")][MarshalAs(UnmanagedType.LPUTF8Str)] string model_path,
|
||||
[NativeTypeName("const char *")][MarshalAs(UnmanagedType.LPUTF8Str)] string build_variant,
|
||||
out IntPtr error);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void llmodel_model_destroy([NativeTypeName("llmodel_model")] IntPtr model);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
public static extern bool llmodel_loadModel(
|
||||
[NativeTypeName("llmodel_model")] IntPtr model,
|
||||
[NativeTypeName("const char *")][MarshalAs(UnmanagedType.LPUTF8Str)] string model_path);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
public static extern bool llmodel_isModelLoaded([NativeTypeName("llmodel_model")] IntPtr model);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
[return: NativeTypeName("uint64_t")]
|
||||
public static extern ulong llmodel_get_state_size([NativeTypeName("llmodel_model")] IntPtr model);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
[return: NativeTypeName("uint64_t")]
|
||||
public static extern ulong llmodel_save_state_data([NativeTypeName("llmodel_model")] IntPtr model, [NativeTypeName("uint8_t *")] byte* dest);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
[return: NativeTypeName("uint64_t")]
|
||||
public static extern ulong llmodel_restore_state_data([NativeTypeName("llmodel_model")] IntPtr model, [NativeTypeName("const uint8_t *")] byte* src);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
public static extern void llmodel_prompt(
|
||||
[NativeTypeName("llmodel_model")] IntPtr model,
|
||||
[NativeTypeName("const char *")][MarshalAs(UnmanagedType.LPUTF8Str)] string prompt,
|
||||
LlmodelPromptCallback prompt_callback,
|
||||
LlmodelResponseCallback response_callback,
|
||||
LlmodelRecalculateCallback recalculate_callback,
|
||||
ref llmodel_prompt_context ctx);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void llmodel_setThreadCount([NativeTypeName("llmodel_model")] IntPtr model, [NativeTypeName("int32_t")] int n_threads);
|
||||
|
||||
[DllImport("libllmodel", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
[return: NativeTypeName("int32_t")]
|
||||
public static extern int llmodel_threadCount([NativeTypeName("llmodel_model")] IntPtr model);
|
||||
}
|
||||
#pragma warning restore CA2101
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Gpt4All.Bindings;
|
||||
|
||||
/// <summary>Defines the type of a member as it was used in the native signature.</summary>
|
||||
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = true)]
|
||||
[Conditional("DEBUG")]
|
||||
internal sealed partial class NativeTypeNameAttribute : Attribute
|
||||
{
|
||||
private readonly string _name;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="NativeTypeNameAttribute" /> class.</summary>
|
||||
/// <param name="name">The name of the type that was used in the native signature.</param>
|
||||
public NativeTypeNameAttribute(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
/// <summary>Gets the name of the type that was used in the native signature.</summary>
|
||||
public string Name => _name;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using Gpt4All.Bindings;
|
||||
|
||||
namespace Gpt4All;
|
||||
|
||||
internal static class LLPromptContextExtensions
|
||||
{
|
||||
public static string Dump(this LLModelPromptContext context)
|
||||
{
|
||||
var ctx = context.UnderlyingContext;
|
||||
return @$"
|
||||
{{
|
||||
logits_size = {ctx.logits_size}
|
||||
tokens_size = {ctx.tokens_size}
|
||||
n_past = {ctx.n_past}
|
||||
n_ctx = {ctx.n_ctx}
|
||||
n_predict = {ctx.n_predict}
|
||||
top_k = {ctx.top_k}
|
||||
top_p = {ctx.top_p}
|
||||
temp = {ctx.temp}
|
||||
n_batch = {ctx.n_batch}
|
||||
repeat_penalty = {ctx.repeat_penalty}
|
||||
repeat_last_n = {ctx.repeat_last_n}
|
||||
context_erase = {ctx.context_erase}
|
||||
}}";
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Gpt4All.Bindings;
|
||||
|
||||
namespace Gpt4All;
|
||||
|
||||
public static class PredictRequestOptionsExtensions
|
||||
{
|
||||
public static LLModelPromptContext ToPromptContext(this PredictRequestOptions opts)
|
||||
{
|
||||
return new LLModelPromptContext
|
||||
{
|
||||
LogitsSize = opts.LogitsSize,
|
||||
TokensSize = opts.TokensSize,
|
||||
TopK = opts.TopK,
|
||||
TopP = opts.TopP,
|
||||
PastNum = opts.PastConversationTokensNum,
|
||||
RepeatPenalty = opts.RepeatPenalty,
|
||||
Temperature = opts.Temperature,
|
||||
RepeatLastN = opts.RepeatLastN,
|
||||
Batches = opts.Batches,
|
||||
ContextErase = opts.ContextErase,
|
||||
ContextSize = opts.ContextSize,
|
||||
TokensToPredict = opts.TokensToPredict
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
--config
|
||||
exclude-funcs-with-body
|
||||
--with-access-specifier
|
||||
*=Public
|
||||
--include-directory
|
||||
..\..\..\gpt4all-backend\
|
||||
--file
|
||||
..\..\..\gpt4all-backend\llmodel_c.h
|
||||
--libraryPath
|
||||
libllmodel
|
||||
--remap
|
||||
sbyte*=IntPtr
|
||||
void*=IntPtr
|
||||
--namespace
|
||||
Gpt4All.Bindings
|
||||
--methodClassName
|
||||
NativeMethods
|
||||
--output
|
||||
.\Bindings\NativeMethods.cs
|
||||
--output-mode
|
||||
CSharp
|
||||
@@ -1,135 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Gpt4All.Bindings;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
[assembly: InternalsVisibleTo("Gpt4All.Tests")]
|
||||
|
||||
namespace Gpt4All;
|
||||
|
||||
public class Gpt4All : IGpt4AllModel
|
||||
{
|
||||
private readonly ILLModel _model;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private const string ResponseErrorMessage =
|
||||
"The model reported an error during token generation error={ResponseError}";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPromptFormatter? PromptFormatter { get; set; }
|
||||
|
||||
internal Gpt4All(ILLModel model, ILogger? logger = null)
|
||||
{
|
||||
_model = model;
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
PromptFormatter = new DefaultPromptFormatter();
|
||||
}
|
||||
|
||||
private string FormatPrompt(string prompt)
|
||||
{
|
||||
if (PromptFormatter == null) return prompt;
|
||||
|
||||
return PromptFormatter.FormatPrompt(prompt);
|
||||
}
|
||||
|
||||
public Task<ITextPredictionResult> GetPredictionAsync(string text, PredictRequestOptions opts, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(text);
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
_logger.LogInformation("Start prediction task");
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = new TextPredictionResult();
|
||||
var context = opts.ToPromptContext();
|
||||
var prompt = FormatPrompt(text);
|
||||
|
||||
try
|
||||
{
|
||||
_model.Prompt(prompt, context, responseCallback: e =>
|
||||
{
|
||||
if (e.IsError)
|
||||
{
|
||||
_logger.LogWarning(ResponseErrorMessage, e.Response);
|
||||
result.Success = false;
|
||||
result.ErrorMessage = e.Response;
|
||||
return false;
|
||||
}
|
||||
result.Append(e.Response);
|
||||
return true;
|
||||
}, cancellationToken: cancellationToken);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Prompt error");
|
||||
result.Success = false;
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
_logger.LogInformation("Prediction task completed elapsed={Elapsed}s", sw.Elapsed.TotalSeconds);
|
||||
|
||||
return (ITextPredictionResult)result;
|
||||
}, CancellationToken.None);
|
||||
}
|
||||
|
||||
public Task<ITextPredictionStreamingResult> GetStreamingPredictionAsync(string text, PredictRequestOptions opts, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(text);
|
||||
|
||||
var result = new TextPredictionStreamingResult();
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
_logger.LogInformation("Start streaming prediction task");
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
try
|
||||
{
|
||||
var context = opts.ToPromptContext();
|
||||
var prompt = FormatPrompt(text);
|
||||
|
||||
_model.Prompt(prompt, context, responseCallback: e =>
|
||||
{
|
||||
if (e.IsError)
|
||||
{
|
||||
_logger.LogWarning(ResponseErrorMessage, e.Response);
|
||||
result.Success = false;
|
||||
result.ErrorMessage = e.Response;
|
||||
return false;
|
||||
}
|
||||
result.Append(e.Response);
|
||||
return true;
|
||||
}, cancellationToken: cancellationToken);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Prompt error");
|
||||
result.Success = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
result.Complete();
|
||||
sw.Stop();
|
||||
_logger.LogInformation("Prediction task completed elapsed={Elapsed}s", sw.Elapsed.TotalSeconds);
|
||||
}
|
||||
}, CancellationToken.None);
|
||||
|
||||
return Task.FromResult((ITextPredictionStreamingResult)result);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_model.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Windows -->
|
||||
<None Include="..\runtimes\win-x64\native\*.dll" Pack="true" PackagePath="runtimes\win-x64\native\%(Filename)%(Extension)" />
|
||||
<!-- Linux -->
|
||||
<None Include="..\runtimes\linux-x64\native\*.so" Pack="true" PackagePath="runtimes\linux-x64\native\%(Filename)%(Extension)" />
|
||||
<!-- MacOS -->
|
||||
<None Include="..\runtimes\osx\native\*.dylib" Pack="true" PackagePath="runtimes\osx\native\%(Filename)%(Extension)" />
|
||||
<Content Include="..\runtimes\osx\native\*.metal" Pack="true" PackagePath="contentFiles\any\any;content">
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Gpt4All.LibraryLoader;
|
||||
|
||||
public interface ILibraryLoader
|
||||
{
|
||||
LoadResult OpenLibrary(string? fileName);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Gpt4All.LibraryLoader;
|
||||
|
||||
internal class LinuxLibraryLoader : ILibraryLoader
|
||||
{
|
||||
#pragma warning disable CA2101
|
||||
[DllImport("libdl.so", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlopen")]
|
||||
#pragma warning restore CA2101
|
||||
public static extern IntPtr NativeOpenLibraryLibdl(string? filename, int flags);
|
||||
|
||||
#pragma warning disable CA2101
|
||||
[DllImport("libdl.so.2", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlopen")]
|
||||
#pragma warning restore CA2101
|
||||
public static extern IntPtr NativeOpenLibraryLibdl2(string? filename, int flags);
|
||||
|
||||
[DllImport("libdl.so", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlerror")]
|
||||
public static extern IntPtr GetLoadError();
|
||||
|
||||
[DllImport("libdl.so.2", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlerror")]
|
||||
public static extern IntPtr GetLoadError2();
|
||||
|
||||
public LoadResult OpenLibrary(string? fileName)
|
||||
{
|
||||
IntPtr loadedLib;
|
||||
try
|
||||
{
|
||||
// open with rtls lazy flag
|
||||
loadedLib = NativeOpenLibraryLibdl2(fileName, 0x00001);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
loadedLib = NativeOpenLibraryLibdl(fileName, 0x00001);
|
||||
}
|
||||
|
||||
if (loadedLib == IntPtr.Zero)
|
||||
{
|
||||
string errorMessage;
|
||||
try
|
||||
{
|
||||
errorMessage = Marshal.PtrToStringAnsi(GetLoadError2()) ?? "Unknown error";
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
errorMessage = Marshal.PtrToStringAnsi(GetLoadError()) ?? "Unknown error";
|
||||
}
|
||||
|
||||
return LoadResult.Failure(errorMessage);
|
||||
}
|
||||
|
||||
return LoadResult.Success;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
namespace Gpt4All.LibraryLoader;
|
||||
|
||||
public class LoadResult
|
||||
{
|
||||
private LoadResult(bool isSuccess, string? errorMessage)
|
||||
{
|
||||
IsSuccess = isSuccess;
|
||||
ErrorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public static LoadResult Success { get; } = new(true, null);
|
||||
|
||||
public static LoadResult Failure(string errorMessage)
|
||||
{
|
||||
return new(false, errorMessage);
|
||||
}
|
||||
|
||||
public bool IsSuccess { get; }
|
||||
public string? ErrorMessage { get; }
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Gpt4All.LibraryLoader;
|
||||
|
||||
internal class MacOsLibraryLoader : ILibraryLoader
|
||||
{
|
||||
#pragma warning disable CA2101
|
||||
[DllImport("libdl.dylib", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlopen")]
|
||||
#pragma warning restore CA2101
|
||||
public static extern IntPtr NativeOpenLibraryLibdl(string? filename, int flags);
|
||||
|
||||
[DllImport("libdl.dylib", ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = "dlerror")]
|
||||
public static extern IntPtr GetLoadError();
|
||||
|
||||
public LoadResult OpenLibrary(string? fileName)
|
||||
{
|
||||
var loadedLib = NativeOpenLibraryLibdl(fileName, 0x00001);
|
||||
|
||||
if (loadedLib == IntPtr.Zero)
|
||||
{
|
||||
var errorMessage = Marshal.PtrToStringAnsi(GetLoadError()) ?? "Unknown error";
|
||||
|
||||
return LoadResult.Failure(errorMessage);
|
||||
}
|
||||
|
||||
return LoadResult.Success;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
#if !IOS && !MACCATALYST && !TVOS && !ANDROID
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace Gpt4All.LibraryLoader;
|
||||
|
||||
public static class NativeLibraryLoader
|
||||
{
|
||||
private static ILibraryLoader? defaultLibraryLoader;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the library loader used to load the native libraries. Overwrite this only if you want some custom loading.
|
||||
/// </summary>
|
||||
/// <param name="libraryLoader">The library loader to be used.</param>
|
||||
public static void SetLibraryLoader(ILibraryLoader libraryLoader)
|
||||
{
|
||||
defaultLibraryLoader = libraryLoader;
|
||||
}
|
||||
|
||||
internal static LoadResult LoadNativeLibrary(string? path = default, bool bypassLoading = true)
|
||||
{
|
||||
// If the user has handled loading the library themselves, we don't need to do anything.
|
||||
if (bypassLoading)
|
||||
{
|
||||
return LoadResult.Success;
|
||||
}
|
||||
|
||||
var architecture = RuntimeInformation.OSArchitecture switch
|
||||
{
|
||||
Architecture.X64 => "x64",
|
||||
Architecture.X86 => "x86",
|
||||
Architecture.Arm => "arm",
|
||||
Architecture.Arm64 => "arm64",
|
||||
_ => throw new PlatformNotSupportedException(
|
||||
$"Unsupported OS platform, architecture: {RuntimeInformation.OSArchitecture}")
|
||||
};
|
||||
|
||||
var (platform, extension) = Environment.OSVersion.Platform switch
|
||||
{
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.Windows) => ("win", "dll"),
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.Linux) => ("linux", "so"),
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.OSX) => ("osx", "dylib"),
|
||||
_ => throw new PlatformNotSupportedException(
|
||||
$"Unsupported OS platform, architecture: {RuntimeInformation.OSArchitecture}")
|
||||
};
|
||||
|
||||
// If the user hasn't set the path, we'll try to find it ourselves.
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
var libraryName = "libllmodel";
|
||||
var assemblySearchPath = new[]
|
||||
{
|
||||
AppDomain.CurrentDomain.RelativeSearchPath,
|
||||
Path.GetDirectoryName(typeof(NativeLibraryLoader).Assembly.Location),
|
||||
Path.GetDirectoryName(Environment.GetCommandLineArgs()[0])
|
||||
}.FirstOrDefault(it => !string.IsNullOrEmpty(it));
|
||||
// Search for the library dll within the assembly search path. If it doesn't exist, for whatever reason, use the default path.
|
||||
path = Directory.EnumerateFiles(assemblySearchPath ?? string.Empty, $"{libraryName}.{extension}", SearchOption.AllDirectories).FirstOrDefault() ?? Path.Combine("runtimes", $"{platform}-{architecture}", $"{libraryName}.{extension}");
|
||||
}
|
||||
|
||||
if (defaultLibraryLoader != null)
|
||||
{
|
||||
return defaultLibraryLoader.OpenLibrary(path);
|
||||
}
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new FileNotFoundException($"Native Library not found in path {path}. " +
|
||||
$"Verify you have have included the native Gpt4All library in your application.");
|
||||
}
|
||||
|
||||
ILibraryLoader libraryLoader = platform switch
|
||||
{
|
||||
"win" => new WindowsLibraryLoader(),
|
||||
"osx" => new MacOsLibraryLoader(),
|
||||
"linux" => new LinuxLibraryLoader(),
|
||||
_ => throw new PlatformNotSupportedException($"Currently {platform} platform is not supported")
|
||||
};
|
||||
return libraryLoader.OpenLibrary(path);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Gpt4All.LibraryLoader;
|
||||
|
||||
internal class WindowsLibraryLoader : ILibraryLoader
|
||||
{
|
||||
public LoadResult OpenLibrary(string? fileName)
|
||||
{
|
||||
var loadedLib = LoadLibrary(fileName);
|
||||
|
||||
if (loadedLib == IntPtr.Zero)
|
||||
{
|
||||
var errorCode = Marshal.GetLastWin32Error();
|
||||
var errorMessage = new Win32Exception(errorCode).Message;
|
||||
return LoadResult.Failure(errorMessage);
|
||||
}
|
||||
|
||||
return LoadResult.Success;
|
||||
}
|
||||
|
||||
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPWStr)] string? lpFileName);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace Gpt4All;
|
||||
|
||||
public class DefaultPromptFormatter : IPromptFormatter
|
||||
{
|
||||
public string FormatPrompt(string prompt)
|
||||
{
|
||||
return $"""
|
||||
### Instruction:
|
||||
The prompt below is a question to answer, a task to complete, or a conversation
|
||||
to respond to; decide which and write an appropriate response.
|
||||
### Prompt:
|
||||
{prompt}
|
||||
### Response:
|
||||
""";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user