├── .github
└── workflows
│ ├── CI_doc.yml
│ └── CI_test.yml
├── .gitignore
├── LICENSE
├── README.md
├── VERSION
├── app
└── main.f90
├── chat_history
├── chat_input
├── ford.yml
├── foropenai.json
├── fpm.toml
├── media
├── example.png
├── logo.png
└── logo.svg
├── src
├── foropenai.f90
├── foropenai_ChatCompletion.f90
├── foropenai_ImageGeneration.f90
├── foropenai_Transcription.f90
├── foropenai_Translation.f90
└── foropenai_base.f90
├── test
├── audio.mp3
├── audio_de.mp3
├── image.png
├── test1.f90
├── test2.f90
├── test3.f90
├── test4.f90
└── test5.f90
└── workspace.code-workspace
/.github/workflows/CI_doc.yml:
--------------------------------------------------------------------------------
1 | name: doc
2 | on: [push]
3 | jobs:
4 |
5 | Build:
6 | runs-on: ${{ matrix.os }}
7 | permissions:
8 | contents: write
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | os: [ubuntu-latest]
13 | python-version: [3.12]
14 |
15 | steps:
16 | - name: Checkout Code
17 | uses: actions/checkout@v3
18 | with:
19 | submodules: recursive
20 |
21 | - name: Install Python
22 | uses: actions/setup-python@v4
23 | with:
24 | python-version: ${{ matrix.python-version }}
25 |
26 | - name: Setup Graphviz
27 | uses: ts-graphviz/setup-graphviz@v1
28 |
29 | - name: Install FORD
30 | if: contains( matrix.os, 'ubuntu')
31 | run: |
32 | python -m pip install --upgrade pip
33 | pip install ford
34 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
35 |
36 | - name: Build FORD Documentation
37 | run: ford ./ford.yml
38 |
39 | - name: Deploy Documentation
40 | uses: JamesIves/github-pages-deploy-action@v4.4.3
41 | with:
42 | branch: gh-pages
43 | folder: doc
--------------------------------------------------------------------------------
/.github/workflows/CI_test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 | on: [push]
3 | jobs:
4 |
5 | Build:
6 | runs-on: ${{ matrix.os }}
7 | permissions:
8 | contents: write
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | os: [ubuntu-latest]
13 | toolchain:
14 | - {compiler: gcc}
15 |
16 | steps:
17 | - name: Checkout code
18 | uses: actions/checkout@v3
19 | with:
20 | submodules: recursive
21 |
22 | - name: Setup Fortran Package Manager (fpm)
23 | uses: fortran-lang/setup-fpm@v5
24 | with:
25 | github-token: ${{ secrets.GITHUB_TOKEN }}
26 |
27 | - name: Setup Fortran Compiler
28 | uses: fortran-lang/setup-fortran@v1
29 | id: setup-fortran
30 | with:
31 | compiler: ${{ matrix.toolchain.compiler }}
32 | version: ${{ matrix.toolchain.version }}
33 |
34 | - name: Install libcurl
35 | run: sudo apt install -y libcurl4-openssl-dev
36 |
37 | - name: Run demo (Debug)
38 | run: fpm test --profile debug --compiler ${{ env.FC}}
39 | env:
40 | FC: ${{ steps.setup-fortran.outputs.fc }}
41 |
42 | - name: Run demo (Release)
43 | run: fpm test --profile release --compiler ${{ env.FC}}
44 | env:
45 | FC: ${{ steps.setup-fortran.outputs.fc }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /bin
3 | /doc
4 | /.vscode
5 | /mod
6 | /include
7 | /lib
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Seyed Ali Ghasemi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/gha3mi/foropenai)
2 | [](https://github.com/gha3mi/foropenai/releases/latest)
3 | [](https://gha3mi.github.io/foropenai/)
4 | [](https://github.com/gha3mi/foropenai/blob/main/LICENSE)
5 | [](https://github.com/gha3mi/foropenai/actions/workflows/CI_test.yml)
6 |
7 |
8 |
9 | **ForOpenAI**: An **unofficial** Fortran library for OpenAI.
10 |
11 | ## How to use
12 |
13 | **Prerequisites:**
14 |
15 | On Ubuntu, you need to install the curl development headers. Use the following command:
16 |
17 | ```shell
18 | sudo apt install -y libcurl4-openssl-dev
19 | ```
20 |
21 | **Clone the repository:**
22 |
23 | You can clone the ForOpenAI repository from GitHub using the following command:
24 |
25 | ```shell
26 | git clone https://github.com/gha3mi/foropenai.git
27 | ```
28 |
29 | ```shell
30 | cd foropenai
31 | ```
32 |
33 | **OpenAI API Key Configuration:**
34 |
35 | Your Secret API key can be located by accessing the OpenAI [User settings](https://platform.openai.com/account/api-keys).
36 |
37 | For enhanced security and convenience, it is strongly recommended to configure the API key as an environment variable.
38 |
39 | - On Ubuntu, use the following command, replacing `"your_api_key"` with your actual API key:
40 |
41 | ```shell
42 | export OPENAI_API_KEY="your_api_key"
43 | ```
44 |
45 | - (Optional) If desired for organizational purposes, you can also establish an optional environment variable on Ubuntu:
46 |
47 | ```shell
48 | export OPENAI_ORG="your_organization"
49 | ```
50 |
51 | - Alternatively, the OpenAI API key can be included in the `foropenai.json` configuration file.
52 |
53 | ```json
54 | {
55 | "base": {
56 | "api_key": "OPENAI_API_KEY",
57 | "organization": ""
58 | }
59 | }
60 | ```
61 |
62 | **Use ChatGPT from the terminal:**
63 |
64 | ```shell
65 | fpm run
66 | ```
67 |
68 | **Example**
69 |
70 | 
71 |
72 | ## Audio
73 |
74 | ### Create transcription
75 |
76 | ```fortran
77 | program test_Transcription
78 |
79 | use foropenai, only: Transcription
80 |
81 | implicit none
82 |
83 | type(Transcription) :: trs
84 |
85 | call trs%set_base_data(file_name='foropenai.json')
86 | call trs%set(file_name='foropenai.json')
87 |
88 | call trs%create(file='test/audio.mp3')
89 | call trs%print_file()
90 | call trs%print_assistant_response()
91 |
92 | call trs%finalize()
93 |
94 | end program test_Transcription
95 | ```
96 |
97 | #### Settings
98 |
99 | `foropenai.json`
100 |
101 | ```json
102 | {
103 | "base": {
104 | "api_key": "OPENAI_API_KEY",
105 | "organization": ""
106 | },
107 |
108 | "Transcription": {
109 | "url": "https://api.openai.com/v1/audio/transcriptions",
110 | "model": "whisper-1",
111 | "temperature": 0.0,
112 | "language": "en",
113 | "response_format": "json"
114 | }
115 | }
116 | ```
117 |
118 |
119 |
120 | #### Result
121 |
122 | ```shell
123 | file: test/audio.mp3
124 | Whisper: FORTRAN stands for Formula Translation.
125 | ```
126 |
127 | ### Create translation
128 |
129 | ```fortran
130 | program test_Translation
131 |
132 | use foropenai, only: Translation
133 |
134 | implicit none
135 |
136 | type(Translation) :: trs
137 |
138 | call trs%set_base_data(file_name='foropenai.json')
139 | call trs%set(file_name='foropenai.json')
140 |
141 | call trs%create(file='test/audio_de.mp3')
142 | call trs%print_file()
143 | call trs%print_assistant_response()
144 |
145 | call trs%finalize()
146 |
147 | end program test_Translation
148 | ```
149 |
150 | #### Settings
151 |
152 | `foropenai.json`
153 |
154 | ```json
155 | {
156 | "base": {
157 | "api_key": "OPENAI_API_KEY",
158 | "organization": ""
159 | },
160 |
161 | "Translation": {
162 | "url": "https://api.openai.com/v1/audio/translations",
163 | "model": "whisper-1",
164 | "temperature": 0.0,
165 | "response_format": "json"
166 | }
167 | }
168 | ```
169 |
170 |
171 |
172 | #### Result
173 |
174 | ```shell
175 | file: test/audio_de.mp3
176 | Whisper: FORTRAN stands for Formula Translation and is a programming language.
177 | ```
178 |
179 | ## Chat
180 |
181 | ### Create chat completion
182 |
183 | ```fortran
184 | program test_ChatCompletion
185 |
186 | use foropenai, only: ChatCompletion
187 |
188 | implicit none
189 |
190 | type(ChatCompletion) :: chat
191 |
192 | call chat%set_base_data(file_name='foropenai.json')
193 | call chat%set(file_name='foropenai.json')
194 |
195 | call chat%init_messages(n=3)
196 | call chat%messages(1)%set(role='system', content='You are a helpful assistant.')
197 | call chat%messages(2)%set(role='user', content='Hello?')
198 | call chat%messages(3)%set(role='assistant', content='')
199 |
200 | call chat%print_user_message()
201 | call chat%create()
202 | call chat%print_assistant_response()
203 |
204 | call chat%usage%print()
205 |
206 | call chat%finalize()
207 |
208 | end program test_ChatCompletion
209 | ```
210 |
211 | #### Settings
212 |
213 | `foropenai.json`
214 |
215 | ```json
216 | {
217 | "base": {
218 | "api_key": "OPENAI_API_KEY",
219 | "organization": ""
220 | },
221 |
222 | "ChatCompletion": {
223 | "user_name": "Ali",
224 | "url": "https://api.openai.com/v1/chat/completions",
225 | "model": "gpt-3.5-turbo",
226 | "temperature": 1.0,
227 | "max_tokens": 200,
228 | "top_p": 1.0,
229 | "frequency_penalty": 0.0,
230 | "presence_penalty": 0.0,
231 | "n": 1,
232 | "stream": false
233 | }
234 | }
235 | ```
236 |
237 | #### Result
238 |
239 | ```shell
240 | Ali: Hello?
241 | ChatGPT: Hello! How can I assist you today?
242 | ```
243 |
244 | ## Image
245 |
246 | ### Image Generation
247 |
248 | ```fortran
249 | program test_ImageGeneration
250 |
251 | use foropenai, only: ImageGeneration
252 |
253 | implicit none
254 |
255 | type(ImageGeneration) :: image
256 |
257 | call image%set_base_data(file_name='foropenai.json')
258 | call image%set(file_name='foropenai.json')
259 |
260 | call image%create(prompt='a cat with a computer')
261 | call image%print_prompt()
262 | call image%print_assistant_response()
263 |
264 | call image%finalize()
265 |
266 | end program test_ImageGeneration
267 | ```
268 |
269 | #### Settings
270 |
271 | `foropenai.json`
272 |
273 | ```json
274 | {
275 | "base": {
276 | "api_key": "OPENAI_API_KEY",
277 | "organization": ""
278 | },
279 |
280 | "ImageGeneration": {
281 | "user_name": "Ali",
282 | "url": "https://api.openai.com/v1/images/generations",
283 | "size": "1024x1024",
284 | "n": 1,
285 | "response_format": "url"
286 | }
287 | }
288 | ```
289 |
290 | #### Result
291 |
292 |
293 |
294 | ## fpm dependency
295 |
296 | If you want to use `ForOpenAI` as a dependency in your own fpm project,
297 | you can easily include it by adding the following line to your `fpm.toml` file:
298 |
299 | ```toml
300 | [dependencies]
301 | foropenai = {git="https://github.com/gha3mi/foropenai.git"}
302 | ```
303 |
304 | ## API documentation
305 |
306 | The most up-to-date API documentation for the master branch is available
307 | [here](https://gha3mi.github.io/foropenai/).
308 | To generate the API documentation for `ForOpenAI` using
309 | [ford](https://github.com/Fortran-FOSS-Programmers/ford) run the following
310 | command:
311 |
312 | ```shell
313 | ford ford.yml
314 | ```
315 |
316 | ## Contributing
317 |
318 | Contributions to `ForOpenAI` are welcome!
319 | If you find any issues or would like to suggest improvements, please open an issue.
320 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.5.0
--------------------------------------------------------------------------------
/app/main.f90:
--------------------------------------------------------------------------------
1 | program main
2 |
3 | use foropenai, only: ChatCompletion
4 | implicit none
5 |
6 | type(ChatCompletion) :: chat
7 |
8 | call chat%conversation(&
9 | file_name_base = 'foropenai.json',&
10 | file_name_ChatCompletion = 'foropenai.json',&
11 | input_file = 'chat_input',&
12 | output_file = 'chat_history',&
13 | inputfile_command = ':ifile',&
14 | exit_command = ':q')
15 |
16 | call chat%finalize()
17 |
18 | end program main
19 |
--------------------------------------------------------------------------------
/chat_history:
--------------------------------------------------------------------------------
1 | User: hello!
2 | ChatGPT: Hi there! How can I assist you today?
3 |
--------------------------------------------------------------------------------
/chat_input:
--------------------------------------------------------------------------------
1 | hello!
--------------------------------------------------------------------------------
/ford.yml:
--------------------------------------------------------------------------------
1 | project: ForOpenAI
2 | version: {!VERSION!}
3 | year: 2023
4 | project_github: https://github.com/gha3mi/foropenai
5 | author: Seyed Ali Ghasemi
6 | email: info@gha3mi.com
7 | github: https://github.com/gha3mi
8 | src_dir: ./src
9 | ./test
10 | output_dir: ./doc
11 | source: true
12 | graph: true
13 | coloured_edges: true
14 | search: true
15 | display: public
16 | private
17 | protected
18 | print_creation_date: true
19 | favicon: ./media/logo.png
20 | media_dir: ./media
21 |
22 | {!README.md!}
--------------------------------------------------------------------------------
/foropenai.json:
--------------------------------------------------------------------------------
1 | {
2 | "base": {
3 | "api_key": "api_key",
4 | "organization": ""
5 | },
6 |
7 | "ChatCompletion": {
8 | "user_name": "Ali",
9 | "url": "https://api.openai.com/v1/chat/completions",
10 | "model": "gpt-3.5-turbo",
11 | "temperature": 1.0,
12 | "max_tokens": 200,
13 | "top_p": 1.0,
14 | "frequency_penalty": 0.0,
15 | "presence_penalty": 0.0,
16 | "n": 1,
17 | "stream": false
18 | },
19 |
20 | "Transcription": {
21 | "url": "https://api.openai.com/v1/audio/transcriptions",
22 | "model": "whisper-1",
23 | "temperature": 0.0,
24 | "language": "en",
25 | "response_format": "json"
26 | },
27 |
28 | "Translation": {
29 | "url": "https://api.openai.com/v1/audio/translations",
30 | "model": "whisper-1",
31 | "temperature": 0.0,
32 | "response_format": "json"
33 | },
34 |
35 | "ImageGeneration": {
36 | "user_name": "Ali",
37 | "url": "https://api.openai.com/v1/images/generations",
38 | "size": "1024x1024",
39 | "n": 1,
40 | "response_format": "url"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/fpm.toml:
--------------------------------------------------------------------------------
1 | name = "foropenai"
2 | version = "VERSION"
3 | author = "Seyed Ali Ghasemi"
4 | maintainer = "info@gha3mi.com"
5 | copyright = "Copyright (c) 2023, Seyed Ali Ghasemi"
6 | license = "LICENSE"
7 |
8 | [build]
9 | auto-executables = false
10 | auto-tests = false
11 | auto-examples = false
12 | module-naming = false
13 |
14 | [install]
15 | library = true
16 |
17 | [fortran]
18 | implicit-typing = false
19 | implicit-external = false
20 | source-form = "free"
21 |
22 | [dependencies]
23 | http = { git = "https://github.com/fortran-lang/http-client.git" }
24 | stdlib = "*"
25 | json-fortran = { git = "https://github.com/jacobwilliams/json-fortran" }
26 | FACE = { git = "https://github.com/szaghi/FACE" }
27 |
28 |
29 | [[test]]
30 | name = "test1"
31 | source-dir = "test"
32 | main = "test1.f90"
33 |
34 | [[test]]
35 | name = "test2"
36 | source-dir = "test"
37 | main = "test2.f90"
38 |
39 | [[test]]
40 | name = "test3"
41 | source-dir = "test"
42 | main = "test3.f90"
43 |
44 | [[test]]
45 | name = "test4"
46 | source-dir = "test"
47 | main = "test4.f90"
48 |
49 | [[test]]
50 | name = "test5"
51 | source-dir = "test"
52 | main = "test5.f90"
53 |
--------------------------------------------------------------------------------
/media/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gha3mi/foropenai/952a0eff4bb9f5bcd39bfa48e075c7901184c572/media/example.png
--------------------------------------------------------------------------------
/media/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gha3mi/foropenai/952a0eff4bb9f5bcd39bfa48e075c7901184c572/media/logo.png
--------------------------------------------------------------------------------
/media/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
85 |
--------------------------------------------------------------------------------
/src/foropenai.f90:
--------------------------------------------------------------------------------
1 | module foropenai
2 | use foropenai_base
3 | use foropenai_ChatCompletion
4 | use foropenai_Transcription
5 | use foropenai_Translation
6 | use foropenai_ImageGeneration
7 | end module foropenai
8 |
--------------------------------------------------------------------------------
/src/foropenai_ChatCompletion.f90:
--------------------------------------------------------------------------------
1 | module foropenai_ChatCompletion
2 |
3 | use foropenai_base
4 |
5 | implicit none
6 |
7 | private
8 | public :: ChatCompletion
9 |
10 | !===============================================================================
11 | !> author: Seyed Ali Ghasemi
12 | type usage
13 | integer :: prompt_tokens=0
14 | integer :: completion_tokens=0
15 | integer :: total_tokens=0
16 | contains
17 | procedure, private :: print_prompt_tokens
18 | procedure, private :: print_completion_tokens
19 | procedure, private :: print_total_tokens
20 | procedure :: print => print_usage
21 | end type usage
22 | !===============================================================================
23 |
24 |
25 | !===============================================================================
26 | !> author: Seyed Ali Ghasemi
27 | type :: ChatCompletion_messages
28 | character(len=:), allocatable :: role
29 | character(len=:), allocatable :: content
30 | character(len=:), allocatable :: name
31 | contains
32 | procedure, private :: deallocate_role
33 | procedure, private :: deallocate_content
34 | procedure, private :: deallocate_name
35 | procedure :: finalize => deallocate_ChatCompletion_messages
36 | procedure :: set => set_message
37 | procedure, private :: set_role
38 | procedure, private :: set_content
39 | procedure, private :: set_name
40 | end type ChatCompletion_messages
41 | !===============================================================================
42 |
43 |
44 | !===============================================================================
45 | !> author: Seyed Ali Ghasemi
46 | type, extends(openai) :: ChatCompletion
47 | character(len=:), allocatable :: url
48 | character(len=:), allocatable :: model
49 | character(len=:), allocatable :: user_name
50 | character(len=256), allocatable :: model_list(:)
51 | type(ChatCompletion_messages), allocatable :: messages(:)
52 | integer :: max_tokens
53 | type(usage) :: usage
54 | real :: temperature=1.0
55 | real :: presence_penalty=0.0
56 | real :: frequency_penalty=0.0
57 | real :: top_p=1.0
58 | logical :: stream=.false.
59 | integer :: n=1
60 | character(len=:), allocatable :: finish_reason
61 | contains
62 | procedure :: check => check_chat_completion
63 | procedure :: create => create_chat_completion
64 | procedure :: conversation
65 | procedure, private :: deallocate_messages
66 | procedure, private :: deallocate_model_list
67 | procedure, private :: deallocate_url
68 | procedure, private :: deallocate_model
69 | procedure, private :: deallocate_user_name
70 | procedure, private :: deallocate_finish_reason
71 | procedure :: finalize => deallocate_ChatCompletion
72 | procedure, private :: get_assistant_response
73 | procedure, private :: get_user_message
74 | procedure :: init_messages
75 | procedure, private :: load => load_ChatCompletion_data
76 | procedure, private :: load_user_name
77 | procedure, private :: load_url
78 | procedure, private :: load_model
79 | procedure, private :: load_temperature
80 | procedure, private :: load_presence_penalty
81 | procedure, private :: load_frequency_penalty
82 | procedure, private :: load_top_p
83 | procedure, private :: load_n
84 | procedure, private :: load_stream
85 | procedure, private :: load_max_tokens
86 | procedure, private :: read_user_message
87 | procedure, private :: print_user_name
88 | procedure, private :: print_model_list
89 | procedure, private :: print_model
90 | procedure, private :: print_temperature
91 | procedure, private :: print_presence_penalty
92 | procedure, private :: print_frequency_penalty
93 | procedure, private :: print_top_p
94 | procedure, private :: print_n
95 | procedure, private :: print_stream
96 | procedure, private :: print_max_tokens
97 | procedure :: print_user_message
98 | procedure :: print_assistant_response
99 | procedure, private :: set_user_name
100 | procedure, private :: set_url
101 | procedure, private :: set_model
102 | procedure, private :: set_model_list
103 | procedure, private :: select_model
104 | procedure, private :: set_temperature
105 | procedure, private :: set_presence_penalty
106 | procedure, private :: set_frequency_penalty
107 | procedure, private :: set_top_p
108 | procedure, private :: set_n
109 | procedure, private :: set_stream
110 | procedure, private :: set_max_tokens
111 | procedure, private :: set_asisstant_response
112 | procedure, private :: set_user_message
113 | procedure :: set => set_ChatCompletion_data
114 | procedure, private :: write_history
115 | procedure, private :: print_finish_reason
116 | end type ChatCompletion
117 | !===============================================================================
118 |
119 | contains
120 |
121 | !===============================================================================
122 | !> author: Seyed Ali Ghasemi
123 | elemental impure subroutine print_usage(this)
124 | class(usage), intent(inout) :: this
125 | call this%print_prompt_tokens()
126 | call this%print_completion_tokens()
127 | call this%print_total_tokens()
128 | end subroutine print_usage
129 | !===============================================================================
130 |
131 |
132 | !===============================================================================
133 | !> author: Seyed Ali Ghasemi
134 | elemental impure subroutine set_ChatCompletion_data(this, file_name, &
135 | url, model, user_name, temperature, presence_penalty, frequency_penalty, top_p, n, stream, max_tokens)
136 | class(ChatCompletion), intent(inout) :: this
137 | character(len=*), optional, intent(in) :: file_name
138 | character(len=*), optional, intent(in) :: url
139 | character(len=*), optional, intent(in) :: model
140 | character(len=*), optional, intent(in) :: user_name
141 | real, optional, intent(in) :: temperature
142 | real, optional, intent(in) :: presence_penalty
143 | real, optional, intent(in) :: frequency_penalty
144 | real, optional, intent(in) :: top_p
145 | integer, optional, intent(in) :: n
146 | logical, optional, intent(in) :: stream
147 | integer, optional, intent(in) :: max_tokens
148 | if (present(url)) call this%set_url(url=url)
149 | if (present(model)) call this%set_model(model=model)
150 | if (present(user_name)) call this%set_user_name(user_name=user_name)
151 | if (present(temperature)) call this%set_temperature(temperature=temperature)
152 | if (present(presence_penalty)) call this%set_presence_penalty(presence_penalty=presence_penalty)
153 | if (present(frequency_penalty)) call this%set_frequency_penalty(frequency_penalty=frequency_penalty)
154 | if (present(top_p)) call this%set_top_p(top_p=top_p)
155 | if (present(n)) call this%set_n(n=n)
156 | if (present(stream)) call this%set_stream(stream=stream)
157 | if (present(max_tokens)) call this%set_max_tokens(max_tokens=max_tokens)
158 |
159 | if (present(file_name)) then
160 | call this%set_file_name(file_name)
161 | call this%load(file_name)
162 | end if
163 | end subroutine set_ChatCompletion_data
164 | !===============================================================================
165 |
166 |
167 | !===============================================================================
168 | !> author: Seyed Ali Ghasemi
169 | elemental pure subroutine set_user_message(this, message)
170 | class(ChatCompletion), intent(inout) :: this
171 | character(len=*), intent(in) :: message
172 | integer :: i
173 | do i = 1, size(this%messages)
174 | if (this%messages(i)%role == 'user') then
175 | call this%messages(i)%set_content(content=message)
176 | end if
177 | end do
178 | end subroutine set_user_message
179 | !===============================================================================
180 |
181 |
182 | !===============================================================================
183 | !> author: Seyed Ali Ghasemi
184 | elemental pure subroutine set_asisstant_response(this, response)
185 | class(ChatCompletion), intent(inout) :: this
186 | character(len=*), intent(in) :: response
187 | integer :: i
188 | do i = 1, size(this%messages)
189 | if (this%messages(i)%role == 'assistant') then
190 | call this%messages(i)%set_content(content=response)
191 | end if
192 | end do
193 | end subroutine set_asisstant_response
194 | !===============================================================================
195 |
196 |
197 | !===============================================================================
198 | !> author: Seyed Ali Ghasemi
199 | pure function get_assistant_response(this) result(response)
200 | class(ChatCompletion), intent(in) :: this
201 | character(len=:), allocatable :: response
202 | integer :: i
203 | do i = 1, size(this%messages)
204 | if (this%messages(i)%role == 'assistant') then
205 | response = this%messages(i)%content
206 | end if
207 | end do
208 | end function
209 | !===============================================================================
210 |
211 |
212 | !===============================================================================
213 | !> author: Seyed Ali Ghasemi
214 | pure function get_user_message(this) result(message)
215 | class(ChatCompletion), intent(in) :: this
216 | character(len=:), allocatable :: message
217 | integer :: i
218 | do i = 1, size(this%messages)
219 | if (this%messages(i)%role == 'user') then
220 | message = this%messages(i)%content
221 | end if
222 | end do
223 | end function
224 | !===============================================================================
225 |
226 |
227 | !===============================================================================
228 | !> author: Seyed Ali Ghasemi
229 | elemental impure subroutine print_assistant_response(this)
230 | use face, only: colorize
231 | class(ChatCompletion), intent(inout) :: this
232 | integer :: i
233 | do i = 1, size(this%messages)
234 | if (this%messages(i)%role == 'assistant') then
235 | print "(A,': ',A)", colorize("ChatGPT", color_bg='blue'), this%messages(i)%content
236 | end if
237 | end do
238 | end subroutine print_assistant_response
239 | !===============================================================================
240 |
241 |
242 | !===============================================================================
243 | !> author: Seyed Ali Ghasemi
244 | elemental impure subroutine print_user_message(this)
245 | use face, only: colorize
246 | class(ChatCompletion), intent(inout) :: this
247 | integer :: i
248 | do i = 1, size(this%messages)
249 | if (this%messages(i)%role == 'user') then
250 | print "(A,': ',A)", colorize(trim(this%user_name), color_bg='green'), this%messages(i)%content
251 | end if
252 | end do
253 | end subroutine print_user_message
254 | !===============================================================================
255 |
256 |
257 | !===============================================================================
258 | !> author: Seyed Ali Ghasemi
259 | elemental pure subroutine deallocate_finish_reason(this)
260 | class(ChatCompletion), intent(inout) :: this
261 | if (allocated(this%finish_reason)) deallocate(this%finish_reason)
262 | end subroutine deallocate_finish_reason
263 | !===============================================================================
264 |
265 |
266 | !===============================================================================
267 | !> author: Seyed Ali Ghasemi
268 | elemental impure subroutine print_finish_reason(this)
269 | class(ChatCompletion), intent(inout) :: this
270 | print "('finish reason: ',A)", trim(this%finish_reason)
271 | end subroutine print_finish_reason
272 | !===============================================================================
273 |
274 |
275 | !===============================================================================
276 | !> author: Seyed Ali Ghasemi
277 | elemental impure subroutine conversation(this, file_name_base, file_name_ChatCompletion, &
278 | input_file, output_file, inputfile_command, exit_command)
279 | class(ChatCompletion), intent(inout) :: this
280 | character(len=*), intent(in) :: file_name_base
281 | character(len=*), intent(in) :: file_name_ChatCompletion
282 | character(len=*), intent(in) :: input_file
283 | character(len=*), intent(in) :: output_file
284 | character(len=*), intent(in) :: inputfile_command
285 | character(len=*), intent(in) :: exit_command
286 |
287 | call this%set_base_data(file_name_base)
288 | call this%set(file_name_ChatCompletion)
289 |
290 | call this%init_messages(n=3)
291 | call this%messages(1)%set(role='system', content='You are a helpful assistant.')
292 | call this%messages(2)%set(role='assistant', content='')
293 | call this%messages(3)%set_role(role='user')
294 |
295 | do
296 | call this%read_user_message(file_name=trim(input_file), command=trim(inputfile_command))
297 | if (trim(this%get_user_message()) == trim(exit_command)) exit
298 | call this%create()
299 | call this%set_asisstant_response(response=this%get_assistant_response())
300 | call this%print_assistant_response()
301 | call this%write_history(file_name=trim(output_file))
302 | end do
303 |
304 | call this%usage%print_prompt_tokens()
305 | call this%usage%print_completion_tokens()
306 | call this%usage%print_total_tokens()
307 | end subroutine conversation
308 | !===============================================================================
309 |
310 |
311 | !===============================================================================
312 | !> author: Seyed Ali Ghasemi
313 | elemental impure subroutine write_history(this, file_name)
314 | class(ChatCompletion), intent(inout) :: this
315 | character(len=*), intent(in) :: file_name
316 | integer :: iounit
317 |
318 | open(newunit=iounit, file=trim(file_name), status='unknown', access='append', action='write')
319 | write(iounit,"(A,': ',A)") this%user_name, this%get_user_message()
320 | write(iounit,"('ChatGPT: ',A)") this%get_assistant_response()
321 | close(iounit)
322 | end subroutine write_history
323 | !===============================================================================
324 |
325 |
326 | !===============================================================================
327 | !> author: Seyed Ali Ghasemi
328 | elemental impure subroutine read_user_message(this, file_name, command)
329 | use face, only: colorize
330 | class(ChatCompletion), intent(inout) :: this
331 | character(len=*), intent(in) :: file_name
332 | character(len=*), intent(in) :: command
333 | character(len=:), allocatable :: message
334 | character(len=:), allocatable :: whole_message
335 | character(len=1000000) :: tmp
336 | integer :: iounit, iostat
337 |
338 | write(*,"(A,': ')",advance='no') colorize(trim(this%user_name), color_bg='green')
339 | read*, tmp
340 | message = trim(tmp)
341 | if (trim(message) == trim(command)) then
342 | open(newunit=iounit, file=trim(file_name), status='old', action='read')
343 | whole_message = ''
344 | do
345 | read(iounit,'(A)',iostat=iostat) tmp
346 | if (iostat /= 0) exit
347 | whole_message = trim(whole_message) // trim(tmp) // new_line(' ')
348 | end do
349 | close(iounit)
350 | call this%set_user_message(message=whole_message)
351 | else
352 | call this%set_user_message(message=message)
353 | end if
354 | end subroutine read_user_message
355 | !===============================================================================
356 |
357 |
358 | !===============================================================================
359 | !> author: Seyed Ali Ghasemi
360 | elemental pure subroutine deallocate_ChatCompletion_messages(this)
361 | class(ChatCompletion_messages), intent(inout) :: this
362 | call this%deallocate_role()
363 | call this%deallocate_content()
364 | call this%deallocate_name()
365 | end subroutine deallocate_ChatCompletion_messages
366 | !===============================================================================
367 |
368 |
369 | !===============================================================================
370 | !> author: Seyed Ali Ghasemi
371 | elemental pure subroutine deallocate_ChatCompletion(this)
372 | class(ChatCompletion), intent(inout) :: this
373 | call this%deallocate_messages()
374 | call this%deallocate_model_list()
375 | call this%deallocate_url()
376 | call this%deallocate_model()
377 | call this%deallocate_user_name()
378 | call this%deallocate_finish_reason()
379 | end subroutine deallocate_ChatCompletion
380 | !===============================================================================
381 |
382 |
383 | !===============================================================================
384 | !> author: Seyed Ali Ghasemi
385 | elemental pure subroutine deallocate_url(this)
386 | class(ChatCompletion), intent(inout) :: this
387 | if (allocated(this%url)) deallocate(this%url)
388 | end subroutine deallocate_url
389 | !===============================================================================
390 |
391 |
392 | !===============================================================================
393 | !> author: Seyed Ali Ghasemi
394 | elemental pure subroutine deallocate_model(this)
395 | class(ChatCompletion), intent(inout) :: this
396 | if (allocated(this%model)) deallocate(this%model)
397 | end subroutine deallocate_model
398 | !===============================================================================
399 |
400 |
401 | !===============================================================================
402 | !> author: Seyed Ali Ghasemi
403 | elemental pure subroutine deallocate_user_name(this)
404 | class(ChatCompletion), intent(inout) :: this
405 | if (allocated(this%user_name)) deallocate(this%user_name)
406 | end subroutine deallocate_user_name
407 | !===============================================================================
408 |
409 |
410 | !===============================================================================
411 | !> author: Seyed Ali Ghasemi
412 | elemental impure subroutine load_ChatCompletion_data(this, file_name)
413 | class(ChatCompletion), intent(inout) :: this
414 | character(len=*), intent(in) :: file_name
415 | call this%set_file_name(trim(file_name))
416 | call this%load_url()
417 | call this%load_model()
418 | call this%load_user_name()
419 | call this%load_temperature()
420 | call this%load_presence_penalty()
421 | call this%load_frequency_penalty()
422 | call this%load_top_p()
423 | call this%load_n()
424 | call this%load_stream()
425 | call this%load_max_tokens()
426 | end subroutine load_ChatCompletion_data
427 | !===============================================================================
428 |
429 |
430 | !===============================================================================
431 | !> author: Seyed Ali Ghasemi
432 | elemental pure subroutine set_message(this, role, content, name)
433 | class(ChatCompletion_messages), intent(inout) :: this
434 | character(len=*), intent(in) :: role
435 | character(len=*), intent(in) :: content
436 | character(len=*), optional, intent(in) :: name
437 | this%role = trim(role)
438 | this%content = trim(content)
439 | if (present(name)) this%name = trim(name)
440 | end subroutine set_message
441 | !===============================================================================
442 |
443 |
444 | !===============================================================================
445 | !> author: Seyed Ali Ghasemi
446 | elemental impure subroutine load_max_tokens(this)
447 | use json_module, only: json_file
448 | class(ChatCompletion), intent(inout) :: this
449 | type(json_file) :: json
450 | call json%initialize()
451 | call json%load_file(trim(this%file_name))
452 | call json%get("ChatCompletion.max_tokens", this%max_tokens)
453 | call json%destroy()
454 | end subroutine load_max_tokens
455 | !===============================================================================
456 |
457 |
458 | !===============================================================================
459 | !> author: Seyed Ali Ghasemi
460 | elemental impure subroutine load_temperature(this)
461 | use json_module, only: json_file
462 | class(ChatCompletion), intent(inout) :: this
463 | type(json_file) :: json
464 | real :: tmp
465 | logical :: found
466 | call json%initialize()
467 | call json%load_file(trim(this%file_name))
468 | call json%get("ChatCompletion.temperature", tmp, found=found)
469 | if (found) this%temperature = tmp
470 | call json%destroy()
471 | end subroutine load_temperature
472 | !===============================================================================
473 |
474 |
475 | !===============================================================================
476 | !> author: Seyed Ali Ghasemi
477 | elemental impure subroutine load_presence_penalty(this)
478 | use json_module, only: json_file
479 | class(ChatCompletion), intent(inout) :: this
480 | type(json_file) :: json
481 | real :: tmp
482 | logical :: found
483 | call json%initialize()
484 | call json%load_file(trim(this%file_name))
485 | call json%get("ChatCompletion.presence_penalty", tmp, found=found)
486 | if (found) this%presence_penalty = tmp
487 | call json%destroy()
488 | end subroutine load_presence_penalty
489 | !===============================================================================
490 |
491 |
492 | !===============================================================================
493 | !> author: Seyed Ali Ghasemi
494 | elemental impure subroutine load_frequency_penalty(this)
495 | use json_module, only: json_file
496 | class(ChatCompletion), intent(inout) :: this
497 | type(json_file) :: json
498 | real :: tmp
499 | logical :: found
500 | call json%initialize()
501 | call json%load_file(trim(this%file_name))
502 | call json%get("ChatCompletion.frequency_penalty", tmp, found=found)
503 | if (found) this%frequency_penalty = tmp
504 | call json%destroy()
505 | end subroutine load_frequency_penalty
506 | !===============================================================================
507 |
508 |
509 | !===============================================================================
510 | !> author: Seyed Ali Ghasemi
511 | elemental impure subroutine load_top_p(this)
512 | use json_module, only: json_file
513 | class(ChatCompletion), intent(inout) :: this
514 | type(json_file) :: json
515 | real :: tmp
516 | logical :: found
517 | call json%initialize()
518 | call json%load_file(trim(this%file_name))
519 | call json%get("ChatCompletion.top_p", tmp, found=found)
520 | if (found) this%top_p = tmp
521 | call json%destroy()
522 | end subroutine load_top_p
523 | !===============================================================================
524 |
525 |
526 | !===============================================================================
527 | !> author: Seyed Ali Ghasemi
528 | elemental impure subroutine load_n(this)
529 | use json_module, only: json_file
530 | class(ChatCompletion), intent(inout) :: this
531 | type(json_file) :: json
532 | integer :: tmp
533 | logical :: found
534 | call json%initialize()
535 | call json%load_file(trim(this%file_name))
536 | call json%get("ChatCompletion.n", tmp, found=found)
537 | if (found) this%n=tmp
538 | call json%destroy()
539 | end subroutine load_n
540 | !===============================================================================
541 |
542 |
543 | !===============================================================================
544 | !> author: Seyed Ali Ghasemi
545 | elemental impure subroutine load_stream(this)
546 | use json_module, only: json_file
547 | class(ChatCompletion), intent(inout) :: this
548 | type(json_file) :: json
549 | logical :: tmp
550 | logical :: found
551 | call json%initialize()
552 | call json%load_file(trim(this%file_name))
553 | call json%get("ChatCompletion.stream", tmp, found=found)
554 | if (found) this%stream = tmp
555 | call json%destroy()
556 | end subroutine load_stream
557 | !===============================================================================
558 |
559 |
560 | !===============================================================================
561 | !> author: Seyed Ali Ghasemi
562 | elemental impure subroutine load_url(this)
563 | use json_module, only: json_file
564 | class(ChatCompletion), intent(inout) :: this
565 | type(json_file) :: json
566 | call json%initialize()
567 | call json%load_file(trim(this%file_name))
568 | call json%get("ChatCompletion.url", this%url)
569 | call json%destroy()
570 | end subroutine load_url
571 | !===============================================================================
572 |
573 |
574 | !===============================================================================
575 | !> author: Seyed Ali Ghasemi
576 | elemental impure subroutine load_model(this)
577 | use json_module, only: json_file
578 | class(ChatCompletion), intent(inout) :: this
579 | type(json_file) :: json
580 | call json%initialize()
581 | call json%load_file(trim(this%file_name))
582 | call json%get("ChatCompletion.model", this%model)
583 | call json%destroy()
584 | end subroutine load_model
585 | !===============================================================================
586 |
587 |
588 | !===============================================================================
589 | !> author: Seyed Ali Ghasemi
590 | elemental impure subroutine load_user_name(this)
591 | use json_module, only: json_file
592 | class(ChatCompletion), intent(inout) :: this
593 | type(json_file) :: json
594 | call json%initialize()
595 | call json%load_file(trim(this%file_name))
596 | call json%get("ChatCompletion.user_name", this%user_name)
597 | call json%destroy()
598 | end subroutine load_user_name
599 | !===============================================================================
600 |
601 |
602 | !===============================================================================
603 | !> author: Seyed Ali Ghasemi
604 | elemental pure subroutine deallocate_model_list(this)
605 | class(ChatCompletion), intent(inout) :: this
606 | if (allocated(this%model_list)) deallocate(this%model_list)
607 | end subroutine deallocate_model_list
608 | !===============================================================================
609 |
610 |
611 | !===============================================================================
612 | !> author: Seyed Ali Ghasemi
613 | elemental pure subroutine set_model_list(this)
614 | class(ChatCompletion), intent(inout) :: this
615 | if (.not. allocated(this%model_list)) allocate(this%model_list(8))
616 | this%model_list(1) = trim('gpt-4')
617 | this%model_list(2) = trim('gpt-4-0613')
618 | this%model_list(3) = trim('gpt-4-32k')
619 | this%model_list(4) = trim('gpt-4-32k-0613')
620 | this%model_list(5) = trim('gpt-3.5-turbo')
621 | this%model_list(6) = trim('gpt-3.5-turbo-0613')
622 | this%model_list(7) = trim('gpt-3.5-turbo-16k')
623 | this%model_list(8) = trim('gpt-3.5-turbo-16k-0613')
624 | end subroutine set_model_list
625 | !===============================================================================
626 |
627 |
628 | !===============================================================================
629 | !> author: Seyed Ali Ghasemi
630 | elemental impure subroutine print_model_list(this)
631 | class(ChatCompletion), intent(inout) :: this
632 | integer :: i
633 | call this%set_model_list()
634 | do i = 1, size(this%model_list)
635 | print "(I1,': ',A)",i,trim(this%model_list(i))
636 | end do
637 | end subroutine print_model_list
638 | !===============================================================================
639 |
640 |
641 | !===============================================================================
642 | !> author: Seyed Ali Ghasemi
643 | elemental pure subroutine set_temperature(this, temperature)
644 | class(ChatCompletion), intent(inout) :: this
645 | real, intent(in) :: temperature
646 | this%temperature = temperature
647 | end subroutine set_temperature
648 | !===============================================================================
649 |
650 |
651 | !===============================================================================
652 | !> author: Seyed Ali Ghasemi
653 | elemental pure subroutine set_presence_penalty(this, presence_penalty)
654 | class(ChatCompletion), intent(inout) :: this
655 | real, intent(in) :: presence_penalty
656 | this%presence_penalty = presence_penalty
657 | end subroutine set_presence_penalty
658 | !===============================================================================
659 |
660 |
661 | !===============================================================================
662 | !> author: Seyed Ali Ghasemi
663 | elemental pure subroutine set_frequency_penalty(this, frequency_penalty)
664 | class(ChatCompletion), intent(inout) :: this
665 | real, intent(in) :: frequency_penalty
666 | this%frequency_penalty = frequency_penalty
667 | end subroutine set_frequency_penalty
668 | !===============================================================================
669 |
670 |
671 | !===============================================================================
672 | !> author: Seyed Ali Ghasemi
673 | elemental pure subroutine set_top_p(this, top_p)
674 | class(ChatCompletion), intent(inout) :: this
675 | real, intent(in) :: top_p
676 | this%top_p = top_p
677 | end subroutine set_top_p
678 | !===============================================================================
679 |
680 |
681 | !===============================================================================
682 | !> author: Seyed Ali Ghasemi
683 | elemental pure subroutine set_n(this, n)
684 | class(ChatCompletion), intent(inout) :: this
685 | integer, intent(in) :: n
686 | this%n = n
687 | end subroutine set_n
688 | !===============================================================================
689 |
690 |
691 | !===============================================================================
692 | !> author: Seyed Ali Ghasemi
693 | elemental pure subroutine set_stream(this, stream)
694 | class(ChatCompletion), intent(inout) :: this
695 | logical, intent(in) :: stream
696 | this%stream = stream
697 | end subroutine set_stream
698 | !===============================================================================
699 |
700 |
701 | !===============================================================================
702 | !> author: Seyed Ali Ghasemi
703 | elemental pure subroutine set_url(this, url)
704 | class(ChatCompletion), intent(inout) :: this
705 | character(len=*), intent(in) :: url
706 | this%url = trim(url)
707 | end subroutine set_url
708 | !===============================================================================
709 |
710 |
711 | !===============================================================================
712 | !> author: Seyed Ali Ghasemi
713 | elemental pure subroutine set_model(this, model)
714 | class(ChatCompletion), intent(inout) :: this
715 | character(len=*), intent(in) :: model
716 | this%model = trim(model)
717 | end subroutine set_model
718 | !===============================================================================
719 |
720 |
721 | !===============================================================================
722 | !> author: Seyed Ali Ghasemi
723 | elemental pure subroutine init_messages(this, n)
724 | class(ChatCompletion), intent(inout) :: this
725 | integer, intent(in) :: n
726 | if (.not. allocated(this%messages)) allocate(this%messages(n))
727 | end subroutine init_messages
728 | !===============================================================================
729 |
730 |
731 | !===============================================================================
732 | !> author: Seyed Ali Ghasemi
733 | elemental pure subroutine set_role(this, role)
734 | class(ChatCompletion_messages), intent(inout) :: this
735 | character(len=*), intent(in) :: role
736 | this%role = trim(role)
737 | end subroutine set_role
738 | !===============================================================================
739 |
740 |
741 | !===============================================================================
742 | !> author: Seyed Ali Ghasemi
743 | elemental pure subroutine set_content(this, content)
744 | class(ChatCompletion_messages), intent(inout) :: this
745 | character(len=*), intent(in) :: content
746 | this%content = trim(content)
747 | end subroutine set_content
748 | !===============================================================================
749 |
750 |
751 | !===============================================================================
752 | !> author: Seyed Ali Ghasemi
753 | elemental pure subroutine set_name(this, name)
754 | class(ChatCompletion_messages), intent(inout) :: this
755 | character(len=*), intent(in) :: name
756 | this%name = trim(name)
757 | end subroutine set_name
758 | !===============================================================================
759 |
760 |
761 | !===============================================================================
762 | !> author: Seyed Ali Ghasemi
763 | elemental impure subroutine check_chat_completion(this, error)
764 | class(ChatCompletion), intent(inout) :: this
765 | integer, intent(out) :: error
766 | integer :: i
767 |
768 | if (len_trim(this%api_key) == 0) then
769 | print '(A)', 'Error: api_key is not set.'
770 | error = 1
771 | stop
772 | end if
773 |
774 | if (len_trim(this%url) == 0) then
775 | print '(A)', 'Error: url is not set.'
776 | error = 2
777 | stop
778 | end if
779 |
780 | if (len_trim(this%model) == 0) then
781 | print '(A)', 'Error: model is not set.'
782 | error = 3
783 | stop
784 | end if
785 |
786 | if (.not. allocated(this%messages)) then
787 | print '(A)', 'Error: messages is not set.'
788 | error = 4
789 | stop
790 | end if
791 |
792 | do i = 1, size(this%messages)
793 | if (len_trim(this%messages(i)%role) == 0) then
794 | print '(A,I1,A)', 'Error: messages(',i,')%role is not set.'
795 | error = 5
796 | stop
797 | end if
798 | end do
799 |
800 | do i = 1, size(this%messages)
801 | if (.not. allocated(this%messages(i)%content)) then
802 | print '(A,I1,A)', 'Error: messages(',i,')%content is not set.'
803 | error = 6
804 | stop
805 | end if
806 | end do
807 |
808 | if (this%temperature < 0.0 .or. this%temperature > 2.0) then
809 | print '(A)', 'Error: temperature must be between 0.0 and 2.0.'
810 | error = 7
811 | stop
812 | end if
813 |
814 | if (this%max_tokens < 1) then
815 | print '(A)', 'Error: max_tokens must be greater than 1'
816 | error = 8
817 | stop
818 | end if
819 |
820 | if (len_trim(this%user_name) == 0) then
821 | print '(A)', 'Error: user_name is not set.'
822 | error = 9
823 | stop
824 | end if
825 |
826 | error = 0
827 |
828 | end subroutine check_chat_completion
829 | !===============================================================================
830 |
831 |
832 | !===============================================================================
833 | !> author: Seyed Ali Ghasemi
834 | elemental impure subroutine create_chat_completion(this)
835 | use http, only: response_type, request, HTTP_POST, pair_type
836 | use json_module, only: json_file
837 |
838 | class(ChatCompletion), intent(inout) :: this
839 | character(len=:), allocatable :: assistant_response
840 | character(len=:), allocatable :: jsonstr
841 | type(pair_type), allocatable :: req_header(:)
842 | type(response_type) :: response
843 | type(json_file) :: json
844 | logical :: found
845 | integer :: i
846 | character(len=10) :: i_str
847 | integer :: error
848 |
849 | call this%check(error)
850 | if (error == 0) then
851 |
852 | req_header = [&
853 | pair_type('Content-Type', 'application/json'),&
854 | pair_type('Authorization', 'Bearer '//trim(this%api_key)),&
855 | pair_type('OpenAI-Organization', ' '//trim(this%organization))&
856 | ]
857 |
858 | call json%initialize()
859 | call json%add('model', trim(this%model))
860 | do i = 1, size(this%messages)
861 | write (i_str, "(I10)") i
862 | call json%add('messages('//trim(i_str)//').role', this%messages(i)%role)
863 | call json%add('messages('//trim(i_str)//').content', this%messages(i)%content)
864 | ! call json%add('messages('//trim(i_str)//').name', this%messages(i)%name)
865 | end do
866 | call json%add('user', this%user_name)
867 | call json%add('temperature', this%temperature)
868 | call json%add('max_tokens', this%max_tokens)
869 | call json%add('stream', this%stream)
870 | call json%add('n', this%n)
871 | call json%add('presence_penalty', this%presence_penalty)
872 | call json%add('frequency_penalty', this%frequency_penalty)
873 | call json%add('top_p', this%top_p)
874 | call json%print_to_string(jsonstr)
875 | call json%destroy()
876 |
877 | response = request(url=this%url, method=HTTP_POST, data=jsonstr, header=req_header)
878 |
879 | if (response%ok) then
880 | call json%initialize()
881 | call json%deserialize(response%content)
882 |
883 | call json%get("choices(1).message.content", assistant_response, found=found)
884 | if (found) then
885 | call json%get("choices(1).finish_reason", this%finish_reason)
886 |
887 | call json%get("usage.prompt_tokens", this%usage%prompt_tokens)
888 | call json%get("usage.completion_tokens", this%usage%completion_tokens)
889 | call json%get("usage.total_tokens", this%usage%total_tokens)
890 | else
891 | call json%get("error.message", jsonstr)
892 | assistant_response = jsonstr
893 | end if
894 | call this%set_asisstant_response(response=assistant_response)
895 | call json%destroy()
896 | else
897 | print '(A)', 'Sorry, an error occurred while processing your request.'
898 | print '(A)', 'Error message:', response%err_msg
899 | end if
900 |
901 | end if
902 | end subroutine create_chat_completion
903 | !===============================================================================
904 |
905 |
906 | !===============================================================================
907 | !> author: Seyed Ali Ghasemi
908 | elemental pure subroutine deallocate_role(this)
909 | class(ChatCompletion_messages), intent(inout) :: this
910 | if (allocated(this%role)) deallocate(this%role)
911 | end subroutine deallocate_role
912 | !===============================================================================
913 |
914 |
915 | !===============================================================================
916 | !> author: Seyed Ali Ghasemi
917 | elemental pure subroutine deallocate_content(this)
918 | class(ChatCompletion_messages), intent(inout) :: this
919 | if (allocated(this%content)) deallocate(this%content)
920 | end subroutine deallocate_content
921 | !===============================================================================
922 |
923 |
924 | !===============================================================================
925 | !> author: Seyed Ali Ghasemi
926 | elemental pure subroutine deallocate_name(this)
927 | class(ChatCompletion_messages), intent(inout) :: this
928 | if (allocated(this%name)) deallocate(this%name)
929 | end subroutine deallocate_name
930 | !===============================================================================
931 |
932 |
933 | !===============================================================================
934 | !> author: Seyed Ali Ghasemi
935 | elemental pure subroutine deallocate_messages(this)
936 | class(ChatCompletion), intent(inout) :: this
937 | if (allocated(this%messages)) deallocate(this%messages)
938 | end subroutine deallocate_messages
939 | !===============================================================================
940 |
941 |
942 | !===============================================================================
943 | !> author: Seyed Ali Ghasemi
944 | elemental pure subroutine select_model(this,n)
945 | class(ChatCompletion), intent(inout) :: this
946 | integer, intent(in) :: n
947 | call this%set_model_list()
948 | this%model = this%model_list(n)
949 | end subroutine select_model
950 | !===============================================================================
951 |
952 |
953 | !===============================================================================
954 | !> author: Seyed Ali Ghasemi
955 | elemental impure subroutine print_model(this)
956 | class(ChatCompletion), intent(inout) :: this
957 | print "('model: ',A)", trim(this%model)
958 | end subroutine print_model
959 | !===============================================================================
960 |
961 |
962 | !===============================================================================
963 | !> author: Seyed Ali Ghasemi
964 | elemental impure subroutine print_temperature(this)
965 | class(ChatCompletion), intent(inout) :: this
966 | print "('temperature: ',F3.1)", this%temperature
967 | end subroutine print_temperature
968 | !===============================================================================
969 |
970 |
971 | !===============================================================================
972 | !> author: Seyed Ali Ghasemi
973 | elemental impure subroutine print_presence_penalty(this)
974 | class(ChatCompletion), intent(inout) :: this
975 | print "('presence_penalty: ',F3.1)", this%presence_penalty
976 | end subroutine print_presence_penalty
977 | !===============================================================================
978 |
979 |
980 | !===============================================================================
981 | !> author: Seyed Ali Ghasemi
982 | elemental impure subroutine print_frequency_penalty(this)
983 | class(ChatCompletion), intent(inout) :: this
984 | print "('frequency_penalty: ',F3.1)", this%frequency_penalty
985 | end subroutine print_frequency_penalty
986 | !===============================================================================
987 |
988 |
989 | !===============================================================================
990 | !> author: Seyed Ali Ghasemi
991 | elemental impure subroutine print_top_p(this)
992 | class(ChatCompletion), intent(inout) :: this
993 | print "('top_p: ',F3.1)", this%top_p
994 | end subroutine print_top_p
995 | !===============================================================================
996 |
997 |
998 | !===============================================================================
999 | !> author: Seyed Ali Ghasemi
1000 | elemental impure subroutine print_n(this)
1001 | class(ChatCompletion), intent(inout) :: this
1002 | print "('n: ',I10)", this%n
1003 | end subroutine print_n
1004 | !===============================================================================
1005 |
1006 |
1007 | !===============================================================================
1008 | !> author: Seyed Ali Ghasemi
1009 | elemental impure subroutine print_stream(this)
1010 | class(ChatCompletion), intent(inout) :: this
1011 | print "('stream: ',L1)", this%stream
1012 | end subroutine print_stream
1013 | !===============================================================================
1014 |
1015 |
1016 | !===============================================================================
1017 | !> author: Seyed Ali Ghasemi
1018 | elemental pure subroutine set_max_tokens(this, max_tokens)
1019 | class(ChatCompletion), intent(inout) :: this
1020 | integer, intent(in) :: max_tokens
1021 | this%max_tokens = max_tokens
1022 | end subroutine set_max_tokens
1023 | !===============================================================================
1024 |
1025 |
1026 | !===============================================================================
1027 | !> author: Seyed Ali Ghasemi
1028 | elemental impure subroutine print_max_tokens(this)
1029 | class(ChatCompletion), intent(inout) :: this
1030 | print "('max tokens: ',I4)", this%max_tokens
1031 | end subroutine print_max_tokens
1032 | !===============================================================================
1033 |
1034 |
1035 | !===============================================================================
1036 | !> author: Seyed Ali Ghasemi
1037 | elemental pure subroutine set_user_name(this, user_name)
1038 | class(ChatCompletion), intent(inout) :: this
1039 | character(len=*), intent(in) :: user_name
1040 | this%user_name = trim(user_name)
1041 | end subroutine set_user_name
1042 | !===============================================================================
1043 |
1044 |
1045 | !===============================================================================
1046 | !> author: Seyed Ali Ghasemi
1047 | elemental impure subroutine print_user_name(this)
1048 | class(ChatCompletion), intent(inout) :: this
1049 | print "('user name: ',A)", trim(this%user_name)
1050 | end subroutine print_user_name
1051 | !===============================================================================
1052 |
1053 |
1054 | !===============================================================================
1055 | !> author: Seyed Ali Ghasemi
1056 | elemental impure subroutine print_prompt_tokens(this)
1057 | class(usage), intent(inout) :: this
1058 | print "('prompt tokens: ',g0)", this%prompt_tokens
1059 | end subroutine print_prompt_tokens
1060 | !===============================================================================
1061 |
1062 |
1063 | !===============================================================================
1064 | !> author: Seyed Ali Ghasemi
1065 | elemental impure subroutine print_completion_tokens(this)
1066 | class(usage), intent(inout) :: this
1067 | print "('completion tokens: ',g0)", this%completion_tokens
1068 | end subroutine print_completion_tokens
1069 | !===============================================================================
1070 |
1071 |
1072 | !===============================================================================
1073 | !> author: Seyed Ali Ghasemi
1074 | elemental impure subroutine print_total_tokens(this)
1075 | class(usage), intent(inout) :: this
1076 | print "('total tokens: ',g0)", this%total_tokens
1077 | end subroutine print_total_tokens
1078 | !===============================================================================
1079 |
1080 | end module foropenai_ChatCompletion
1081 |
--------------------------------------------------------------------------------
/src/foropenai_ImageGeneration.f90:
--------------------------------------------------------------------------------
1 | module foropenai_ImageGeneration
2 |
3 | use foropenai_base
4 |
5 | implicit none
6 |
7 | private
8 | public :: ImageGeneration
9 |
10 | !===============================================================================
11 | !> author: Seyed Ali Ghasemi
12 | type, extends(openai) :: ImageGeneration
13 | character(len=:), allocatable :: url
14 | character(len=9) :: size='1024x1024'
15 | character(len=1000) :: prompt
16 | character(len=4) :: response_format='url'
17 | integer :: n=1
18 | character(len=:), allocatable :: user_name
19 | character(len=1024), allocatable :: assistant_response(:)
20 | contains
21 | procedure :: create => create_image
22 | procedure, private :: deallocate_url
23 | procedure, private :: deallocate_user_name
24 | procedure, private :: deallocate_assistant_response
25 | procedure :: finalize => deallocate_ImageGeneration
26 | procedure, private :: load_url
27 | procedure, private :: load_size
28 | procedure, private :: load_response_format
29 | procedure, private :: load_n
30 | procedure, private :: load_user_name
31 | procedure, private :: load => load_ImageGeneration_data
32 | procedure, private :: print_url
33 | procedure, private :: print_size
34 | procedure :: print_prompt
35 | procedure, private :: print_response_format
36 | procedure, private :: print_n
37 | procedure, private :: print_user_name
38 | procedure :: print_assistant_response
39 | procedure, private :: set_url
40 | procedure, private :: set_size
41 | procedure, private :: set_prompt
42 | procedure, private :: set_response_format
43 | procedure, private :: set_n
44 | procedure, private :: set_user_name
45 | procedure, private :: set_assistant_response
46 | procedure :: set => set_ImageGeneration_data
47 | end type ImageGeneration
48 | !===============================================================================
49 |
50 | contains
51 |
52 | !===============================================================================
53 | !> author: Seyed Ali Ghasemi
54 | elemental impure subroutine create_image(this, prompt, n, size, response_format, user_name)
55 | use http, only: response_type, request, HTTP_POST, pair_type
56 | use json_module, only: json_file
57 |
58 | class(ImageGeneration), intent(inout) :: this
59 | character(len=*), intent(in) :: prompt
60 | integer, intent(in), optional :: n
61 | character(len=*), intent(in), optional :: size
62 | character(len=*), intent(in), optional :: response_format
63 | character(len=*), intent(in), optional :: user_name
64 | character(len=:), allocatable :: assistant_response
65 | character(len=:), allocatable :: jsonstr
66 | type(pair_type), allocatable :: req_header(:)
67 | type(response_type) :: response
68 | type(json_file) :: json
69 | logical :: found
70 | integer :: i
71 | character(len=10) :: i_str
72 |
73 | call this%set_prompt(prompt=prompt)
74 | if (present(n)) call this%set_n(n=n)
75 | if (present(size)) call this%set_size(size=size)
76 | if (present(response_format)) call this%set_response_format(response_format=response_format)
77 | if (present(user_name)) call this%set_user_name(user_name=user_name)
78 |
79 | req_header = [&
80 | pair_type('Content-Type', 'application/json'),&
81 | pair_type('Authorization', 'Bearer '//trim(this%api_key)//''),&
82 | pair_type('OpenAI-Organization', ' '//trim(this%organization)//'')&
83 | ]
84 |
85 | call json%initialize()
86 | call json%add('prompt', trim(this%prompt))
87 | call json%add('n', this%n)
88 | call json%add('size', trim(this%size))
89 | call json%add('response_format', trim(this%response_format))
90 | call json%add('user', trim(this%user_name))
91 | call json%print_to_string(jsonstr)
92 | call json%destroy()
93 |
94 | response = request(url=trim(this%url), method=HTTP_POST, data=jsonstr, header=req_header)
95 |
96 | if (response%ok) then
97 | allocate(this%assistant_response(this%n))
98 | call json%initialize()
99 | call json%deserialize(response%content)
100 | do i = 1, this%n
101 | write (i_str, "(I10)") i
102 | call json%get("data("//trim(i_str)//").url", assistant_response, found=found)
103 | if (.not. found) then
104 | call json%get("error.message", assistant_response)
105 | call this%set_assistant_response(assistant_response=assistant_response, i=i)
106 | exit
107 | end if
108 | call this%set_assistant_response(assistant_response=assistant_response, i=i)
109 | end do
110 | call json%destroy()
111 | else
112 | print '(A)', 'Sorry, an error occurred while processing your request.'
113 | print '(A)', 'Error message:', response%err_msg
114 | end if
115 |
116 | end subroutine create_image
117 | !===============================================================================
118 |
119 |
120 | !===============================================================================
121 | !> author: Seyed Ali Ghasemi
122 | elemental impure subroutine load_url(this)
123 | use json_module, only: json_file
124 | class(ImageGeneration), intent(inout) :: this
125 | type(json_file) :: json
126 | character(len=:), allocatable :: tmp
127 | logical :: found
128 | call json%initialize()
129 | call json%load_file(trim(this%file_name))
130 | call json%get("ImageGeneration.url", tmp, found=found)
131 | if (found) this%url = trim(tmp)
132 | call json%destroy()
133 | end subroutine load_url
134 | !===============================================================================
135 |
136 |
137 | !===============================================================================
138 | !> author: Seyed Ali Ghasemi
139 | elemental impure subroutine load_size(this)
140 | use json_module, only: json_file
141 | class(ImageGeneration), intent(inout) :: this
142 | type(json_file) :: json
143 | character(len=:), allocatable :: tmp
144 | logical :: found
145 | call json%initialize()
146 | call json%load_file(trim(this%file_name))
147 | call json%get("ImageGeneration.size", tmp, found=found)
148 | if (found) this%size = trim(tmp)
149 | call json%destroy()
150 | end subroutine load_size
151 | !===============================================================================
152 |
153 |
154 | !===============================================================================
155 | !> author: Seyed Ali Ghasemi
156 | elemental impure subroutine load_response_format(this)
157 | use json_module, only: json_file
158 | class(ImageGeneration), intent(inout) :: this
159 | type(json_file) :: json
160 | character(len=:), allocatable :: tmp
161 | logical :: found
162 | call json%initialize()
163 | call json%load_file(trim(this%file_name))
164 | call json%get("ImageGeneration.response_format", tmp, found=found)
165 | if (found) this%response_format = trim(tmp)
166 | call json%destroy()
167 | end subroutine load_response_format
168 | !===============================================================================
169 |
170 |
171 | !===============================================================================
172 | !> author: Seyed Ali Ghasemi
173 | elemental impure subroutine load_n(this)
174 | use json_module, only: json_file
175 | class(ImageGeneration), intent(inout) :: this
176 | type(json_file) :: json
177 | integer :: tmp
178 | logical :: found
179 | call json%initialize()
180 | call json%load_file(trim(this%file_name))
181 | call json%get("ImageGeneration.n", tmp, found=found)
182 | if (found) this%n = tmp
183 | call json%destroy()
184 | end subroutine load_n
185 | !================================================================================
186 |
187 |
188 | !===============================================================================
189 | !> author: Seyed Ali Ghasemi
190 | elemental impure subroutine load_user_name(this)
191 | use json_module, only: json_file
192 | class(ImageGeneration), intent(inout) :: this
193 | type(json_file) :: json
194 | character(len=:), allocatable :: tmp
195 | logical :: found
196 | call json%initialize()
197 | call json%load_file(trim(this%file_name))
198 | call json%get("ImageGeneration.user_name", tmp, found=found)
199 | if (found) this%user_name = trim(tmp)
200 | call json%destroy()
201 | end subroutine load_user_name
202 | !===============================================================================
203 |
204 |
205 | !===============================================================================
206 | !> author: Seyed Ali Ghasemi
207 | elemental impure subroutine print_url(this)
208 | class(ImageGeneration), intent(in) :: this
209 | print *, "url: ", this%url
210 | end subroutine print_url
211 | !===============================================================================
212 |
213 |
214 | !===============================================================================
215 | !> author: Seyed Ali Ghasemi
216 | elemental impure subroutine print_size(this)
217 | class(ImageGeneration), intent(in) :: this
218 | print *, "size: ", this%size
219 | end subroutine print_size
220 | !===============================================================================
221 |
222 |
223 | !===============================================================================
224 | !> author: Seyed Ali Ghasemi
225 | elemental impure subroutine print_prompt(this)
226 | use face, only: colorize
227 | class(ImageGeneration), intent(in) :: this
228 | print "(A,': ',A)", colorize(trim(this%user_name), color_bg='green'), trim(this%prompt)
229 | end subroutine print_prompt
230 | !===============================================================================
231 |
232 |
233 | !===============================================================================
234 | !> author: Seyed Ali Ghasemi
235 | elemental impure subroutine print_response_format(this)
236 | class(ImageGeneration), intent(in) :: this
237 | print *, "response_format: ", this%response_format
238 | end subroutine print_response_format
239 | !===============================================================================
240 |
241 |
242 | !===============================================================================
243 | !> author: Seyed Ali Ghasemi
244 | elemental impure subroutine print_n(this)
245 | class(ImageGeneration), intent(in) :: this
246 | print *, "n: ", this%n
247 | end subroutine print_n
248 | !===============================================================================
249 |
250 |
251 | !===============================================================================
252 | !> author: Seyed Ali Ghasemi
253 | elemental impure subroutine print_user_name(this)
254 | class(ImageGeneration), intent(in) :: this
255 | print *, "user_name: ", this%user_name
256 | end subroutine print_user_name
257 | !===============================================================================
258 |
259 |
260 | !===============================================================================
261 | !> author: Seyed Ali Ghasemi
262 | elemental impure subroutine print_assistant_response(this)
263 | use face, only: colorize
264 | class(ImageGeneration), intent(in) :: this
265 | integer :: i
266 | do i = 1, this%n
267 | print "(a,': ',a)",colorize("DALL-E", color_bg='blue'), trim(this%assistant_response(i))
268 | end do
269 | end subroutine print_assistant_response
270 | !===============================================================================
271 |
272 |
273 | !===============================================================================
274 | !> author: Seyed Ali Ghasemi
275 | elemental pure subroutine set_url(this, url)
276 | class(ImageGeneration), intent(inout) :: this
277 | character(len=*), intent(in) :: url
278 | this%url = trim(url)
279 | end subroutine set_url
280 | !===============================================================================
281 |
282 |
283 | !===============================================================================
284 | !> author: Seyed Ali Ghasemi
285 | elemental pure subroutine set_size(this, size)
286 | class(ImageGeneration), intent(inout) :: this
287 | character(len=*), intent(in) :: size
288 | this%size = trim(size)
289 | end subroutine set_size
290 | !===============================================================================
291 |
292 |
293 | !===============================================================================
294 | !> author: Seyed Ali Ghasemi
295 | elemental pure subroutine set_prompt(this, prompt)
296 | class(ImageGeneration), intent(inout) :: this
297 | character(len=*), intent(in) :: prompt
298 | this%prompt = trim(prompt)
299 | end subroutine set_prompt
300 | !===============================================================================
301 |
302 |
303 | !===============================================================================
304 | !> author: Seyed Ali Ghasemi
305 | elemental pure subroutine set_response_format(this, response_format)
306 | class(ImageGeneration), intent(inout) :: this
307 | character(len=*), intent(in) :: response_format
308 | this%response_format = trim(response_format)
309 | end subroutine set_response_format
310 | !===============================================================================
311 |
312 |
313 | !===============================================================================
314 | !> author: Seyed Ali Ghasemi
315 | elemental pure subroutine set_n(this, n)
316 | class(ImageGeneration), intent(inout) :: this
317 | integer, intent(in) :: n
318 | this%n = n
319 | end subroutine set_n
320 | !===============================================================================
321 |
322 |
323 | !===============================================================================
324 | !> author: Seyed Ali Ghasemi
325 | elemental pure subroutine set_user_name(this, user_name)
326 | class(ImageGeneration), intent(inout) :: this
327 | character(len=*), intent(in) :: user_name
328 | this%user_name = trim(user_name)
329 | end subroutine set_user_name
330 | !===============================================================================
331 |
332 |
333 | !===============================================================================
334 | !> author: Seyed Ali Ghasemi
335 | elemental pure subroutine set_assistant_response(this, assistant_response, i)
336 | class(ImageGeneration), intent(inout) :: this
337 | character(len=*), intent(in) :: assistant_response
338 | integer, intent(in) :: i
339 | this%assistant_response(i) = trim(assistant_response)
340 | end subroutine set_assistant_response
341 | !===============================================================================
342 |
343 |
344 | !===============================================================================
345 | !> author: Seyed Ali Ghasemi
346 | elemental impure subroutine set_ImageGeneration_data(this, file_name, &
347 | url, size, prompt, response_format, n, user_name)
348 | class(ImageGeneration), intent(inout) :: this
349 | character(len=*), optional, intent(in) :: file_name
350 | character(len=*), optional, intent(in) :: url
351 | character(len=*), optional, intent(in) :: size
352 | character(len=*), optional, intent(in) :: prompt
353 | character(len=*), optional, intent(in) :: response_format
354 | integer, optional, intent(in) :: n
355 | character(len=*), optional, intent(in) :: user_name
356 |
357 | if (present(url)) call this%set_url(url=url)
358 | if (present(size)) call this%set_size(size=size)
359 | if (present(prompt)) call this%set_prompt(prompt=prompt)
360 | if (present(response_format)) call this%set_response_format(response_format=response_format)
361 | if (present(n)) call this%set_n(n=n)
362 | if (present(user_name)) call this%set_user_name(user_name=user_name)
363 |
364 | if (present(file_name)) then
365 | call this%set_file_name(file_name)
366 | call this%load(file_name)
367 | end if
368 | end subroutine set_ImageGeneration_data
369 | !===============================================================================
370 |
371 |
372 | !===============================================================================
373 | !> author: Seyed Ali Ghasemi
374 | elemental impure subroutine load_ImageGeneration_data(this, file_name)
375 | class(ImageGeneration), intent(inout) :: this
376 | character(len=*), intent(in) :: file_name
377 | call this%set_file_name(trim(file_name))
378 | call this%load_url()
379 | call this%load_size()
380 | call this%load_response_format()
381 | call this%load_n()
382 | call this%load_user_name()
383 | end subroutine load_ImageGeneration_data
384 | !===============================================================================
385 |
386 |
387 | !===============================================================================
388 | !> author: Seyed Ali Ghasemi
389 | elemental pure subroutine deallocate_url(this)
390 | class(ImageGeneration), intent(inout) :: this
391 | if (allocated(this%url)) deallocate(this%url)
392 | end subroutine deallocate_url
393 | !===============================================================================
394 |
395 |
396 | !===============================================================================
397 | !> author: Seyed Ali Ghasemi
398 | elemental pure subroutine deallocate_user_name(this)
399 | class(ImageGeneration), intent(inout) :: this
400 | if (allocated(this%user_name)) deallocate(this%user_name)
401 | end subroutine deallocate_user_name
402 | !===============================================================================
403 |
404 |
405 | !===============================================================================
406 | !> author: Seyed Ali Ghasemi
407 | elemental pure subroutine deallocate_assistant_response(this)
408 | class(ImageGeneration), intent(inout) :: this
409 | if (allocated(this%assistant_response)) deallocate(this%assistant_response)
410 | end subroutine deallocate_assistant_response
411 | !===============================================================================
412 |
413 |
414 | !===============================================================================
415 | !> author: Seyed Ali Ghasemi
416 | elemental pure subroutine deallocate_ImageGeneration(this)
417 | class(ImageGeneration), intent(inout) :: this
418 | call this%deallocate_url()
419 | call this%deallocate_user_name()
420 | call this%deallocate_assistant_response()
421 | end subroutine deallocate_ImageGeneration
422 | !===============================================================================
423 |
424 | end module foropenai_ImageGeneration
425 |
--------------------------------------------------------------------------------
/src/foropenai_Transcription.f90:
--------------------------------------------------------------------------------
1 | module foropenai_Transcription
2 |
3 | use foropenai_base
4 |
5 | implicit none
6 |
7 | private
8 | public :: Transcription
9 |
10 | !===============================================================================
11 | !> author: Seyed Ali Ghasemi
12 | type, extends(openai) :: Transcription
13 | character(len=:), allocatable :: url
14 | character(len=:), allocatable :: model
15 | character(len=:), allocatable :: language
16 | character(len=:), allocatable :: prompt
17 | character(len=:), allocatable :: file
18 | character(len=:), allocatable :: assistant_response
19 | character(len=4) :: response_format='json'
20 | real :: temperature=0.0
21 | contains
22 | procedure :: create => create_transcription
23 | procedure, private :: deallocate_url
24 | procedure, private :: deallocate_model
25 | procedure, private :: deallocate_language
26 | procedure, private :: deallocate_prompt
27 | procedure, private :: deallocate_file
28 | procedure, private :: deallocate_assistant_response
29 | procedure :: finalize => deallocate_Transcription
30 | procedure, private :: load => load_Transcription_data
31 | procedure, private :: load_url
32 | procedure, private :: load_model
33 | procedure, private :: load_temperature
34 | procedure, private :: load_language
35 | procedure, private :: load_response_format
36 | procedure, private :: print_model
37 | procedure, private :: print_temperature
38 | procedure, private :: print_language
39 | procedure, private :: print_response_format
40 | procedure, private :: print_prompt
41 | procedure :: print_assistant_response
42 | procedure :: print_file
43 | procedure, private :: set_assistant_response
44 | procedure, private :: set_prompt
45 | procedure, private :: set_url
46 | procedure, private :: set_model
47 | procedure, private :: set_temperature
48 | procedure, private :: set_language
49 | procedure, private :: set_response_format
50 | procedure, private :: set_file
51 | procedure :: set => set_Transcription_data
52 | end type Transcription
53 | !===============================================================================
54 |
55 | contains
56 |
57 | !===============================================================================
58 | !> author: Seyed Ali Ghasemi
59 | elemental impure subroutine print_file(this)
60 | use face, only: colorize
61 | class(Transcription), intent(inout) :: this
62 | print "(A,': ',A)", colorize('file', color_bg='green'), this%file
63 | end subroutine print_file
64 | !===============================================================================
65 |
66 |
67 | !===============================================================================
68 | !> author: Seyed Ali Ghasemi
69 | elemental impure subroutine print_assistant_response(this)
70 | use face, only: colorize
71 | class(Transcription), intent(inout) :: this
72 | print "(A,': ',A)", colorize("Whisper", color_bg='blue'), this%assistant_response
73 | end subroutine print_assistant_response
74 | !===============================================================================
75 |
76 |
77 | !===============================================================================
78 | !> author: Seyed Ali Ghasemi
79 | elemental pure subroutine set_assistant_response(this, assistant_response)
80 | class(Transcription), intent(inout) :: this
81 | character(len=*), intent(in) :: assistant_response
82 | this%assistant_response = trim(assistant_response)
83 | end subroutine set_assistant_response
84 | !===============================================================================
85 |
86 |
87 | !===============================================================================
88 | !> author: Seyed Ali Ghasemi
89 | elemental impure subroutine print_prompt(this)
90 | class(Transcription), intent(inout) :: this
91 | print "('prompt: ',A)", trim(this%prompt)
92 | end subroutine print_prompt
93 | !===============================================================================
94 |
95 |
96 | !===============================================================================
97 | !> author: Seyed Ali Ghasemi
98 | elemental pure subroutine set_prompt(this, prompt)
99 | class(Transcription), intent(inout) :: this
100 | character(len=*), intent(in) :: prompt
101 | this%prompt = trim(prompt)
102 | end subroutine set_prompt
103 | !===============================================================================
104 |
105 |
106 | !===============================================================================
107 | !> author: Seyed Ali Ghasemi
108 | elemental pure subroutine deallocate_Transcription(this)
109 | class(Transcription), intent(inout) :: this
110 | call this%deallocate_url()
111 | call this%deallocate_model()
112 | call this%deallocate_language()
113 | call this%deallocate_prompt()
114 | call this%deallocate_file()
115 | call this%deallocate_assistant_response()
116 | end subroutine deallocate_Transcription
117 | !===============================================================================
118 |
119 |
120 | !===============================================================================
121 | !> author: Seyed Ali Ghasemi
122 | elemental pure subroutine deallocate_url(this)
123 | class(Transcription), intent(inout) :: this
124 | if (allocated(this%url)) deallocate(this%url)
125 | end subroutine deallocate_url
126 | !===============================================================================
127 |
128 |
129 | !===============================================================================
130 | !> author: Seyed Ali Ghasemi
131 | elemental pure subroutine deallocate_model(this)
132 | class(Transcription), intent(inout) :: this
133 | if (allocated(this%model)) deallocate(this%model)
134 | end subroutine deallocate_model
135 | !===============================================================================
136 |
137 |
138 | !===============================================================================
139 | !> author: Seyed Ali Ghasemi
140 | elemental pure subroutine deallocate_language(this)
141 | class(Transcription), intent(inout) :: this
142 | if (allocated(this%language)) deallocate(this%language)
143 | end subroutine deallocate_language
144 | !===============================================================================
145 |
146 |
147 | !===============================================================================
148 | !> author: Seyed Ali Ghasemi
149 | elemental pure subroutine deallocate_prompt(this)
150 | class(Transcription), intent(inout) :: this
151 | if (allocated(this%prompt)) deallocate(this%prompt)
152 | end subroutine deallocate_prompt
153 | !===============================================================================
154 |
155 |
156 | !===============================================================================
157 | !> author: Seyed Ali Ghasemi
158 | elemental pure subroutine deallocate_file(this)
159 | class(Transcription), intent(inout) :: this
160 | if (allocated(this%file)) deallocate(this%file)
161 | end subroutine deallocate_file
162 | !===============================================================================
163 |
164 |
165 | !===============================================================================
166 | !> author: Seyed Ali Ghasemi
167 | elemental pure subroutine deallocate_assistant_response(this)
168 | class(Transcription), intent(inout) :: this
169 | if (allocated(this%assistant_response)) deallocate(this%assistant_response)
170 | end subroutine deallocate_assistant_response
171 | !===============================================================================
172 |
173 |
174 | !===============================================================================
175 | !> author: Seyed Ali Ghasemi
176 | elemental pure subroutine set_response_format(this, response_format)
177 | class(Transcription), intent(inout) :: this
178 | character(len=*), intent(in) :: response_format
179 | this%response_format = trim(response_format)
180 | end subroutine set_response_format
181 | !===============================================================================
182 |
183 |
184 | !===============================================================================
185 | !> author: Seyed Ali Ghasemi
186 | elemental impure subroutine load_response_format(this)
187 | use json_module, only: json_file
188 | class(Transcription), intent(inout) :: this
189 | type(json_file) :: json
190 | character(len=:), allocatable :: tmp
191 | logical :: found
192 | call json%initialize()
193 | call json%load_file(trim(this%file_name))
194 | call json%get("Transcription.response_format", tmp, found=found)
195 | if (found) this%response_format = trim(tmp)
196 | call json%destroy()
197 | end subroutine load_response_format
198 | !===============================================================================
199 |
200 |
201 | !===============================================================================
202 | !> author: Seyed Ali Ghasemi
203 | elemental impure subroutine print_response_format(this)
204 | class(Transcription), intent(inout) :: this
205 | print "('response_format: ',A)", trim(this%response_format)
206 | end subroutine print_response_format
207 | !===============================================================================
208 |
209 |
210 | !===============================================================================
211 | !> author: Seyed Ali Ghasemi
212 | elemental impure subroutine load_language(this)
213 | use json_module, only: json_file
214 | class(Transcription), intent(inout) :: this
215 | type(json_file) :: json
216 | character(len=:), allocatable :: tmp
217 | logical :: found
218 | call json%initialize()
219 | call json%load_file(trim(this%file_name))
220 | call json%get("Transcription.language", tmp, found=found)
221 | if (found) this%language = trim(tmp)
222 | call json%destroy()
223 | end subroutine load_language
224 | !===============================================================================
225 |
226 |
227 | !===============================================================================
228 | !> author: Seyed Ali Ghasemi
229 | elemental impure subroutine print_language(this)
230 | class(Transcription), intent(inout) :: this
231 | print "('language: ',A)", trim(this%language)
232 | end subroutine print_language
233 | !===============================================================================
234 |
235 |
236 | !===============================================================================
237 | !> author: Seyed Ali Ghasemi
238 | elemental pure subroutine set_language(this, language)
239 | class(Transcription), intent(inout) :: this
240 | character(len=*), intent(in) :: language
241 | this%language = trim(language)
242 | end subroutine set_language
243 | !===============================================================================
244 |
245 |
246 | !===============================================================================
247 | !> author: Seyed Ali Ghasemi
248 | elemental pure subroutine set_file(this, file)
249 | class(Transcription), intent(inout) :: this
250 | character(len=*), intent(in) :: file
251 | this%file = trim(file)
252 | end subroutine set_file
253 | !===============================================================================
254 |
255 |
256 | !===============================================================================
257 | !> author: Seyed Ali Ghasemi
258 | elemental impure subroutine set_Transcription_data(this, file_name, &
259 | url, model, temperature, language, response_format)
260 | class(Transcription), intent(inout) :: this
261 | character(len=*), optional, intent(in) :: file_name
262 | character(len=*), optional, intent(in) :: url
263 | character(len=*), optional, intent(in) :: model
264 | real, optional, intent(in) :: temperature
265 | character(len=*), optional, intent(in) :: language
266 | character(len=*), optional, intent(in) :: response_format
267 |
268 | if (present(url)) call this%set_url(url=url)
269 | if (present(model)) call this%set_model(model=model)
270 | if (present(temperature)) call this%set_temperature(temperature=temperature)
271 | if (present(language)) call this%set_language(language=language)
272 | if (present(response_format)) call this%set_response_format(response_format=response_format)
273 |
274 | if (present(file_name)) then
275 | call this%set_file_name(file_name)
276 | call this%load(file_name)
277 | end if
278 | end subroutine set_Transcription_data
279 | !===============================================================================
280 |
281 |
282 | !===============================================================================
283 | !> author: Seyed Ali Ghasemi
284 | elemental impure subroutine load_Transcription_data(this, file_name)
285 | class(Transcription), intent(inout) :: this
286 | character(len=*), intent(in) :: file_name
287 | call this%set_file_name(trim(file_name))
288 | call this%load_url()
289 | call this%load_model()
290 | call this%load_temperature()
291 | call this%load_language()
292 | call this%load_response_format()
293 | end subroutine load_Transcription_data
294 | !===============================================================================
295 |
296 |
297 | !===============================================================================
298 | !> author: Seyed Ali Ghasemi
299 | elemental impure subroutine load_temperature(this)
300 | use json_module, only: json_file
301 | class(Transcription), intent(inout) :: this
302 | type(json_file) :: json
303 | real :: tmp
304 | logical :: found
305 | call json%initialize()
306 | call json%load_file(trim(this%file_name))
307 | call json%get("Transcription.temperature", tmp, found=found)
308 | if (found) this%temperature = tmp
309 | call json%destroy()
310 | end subroutine load_temperature
311 | !===============================================================================
312 |
313 |
314 | !===============================================================================
315 | !> author: Seyed Ali Ghasemi
316 | elemental impure subroutine load_url(this)
317 | use json_module, only: json_file
318 | class(Transcription), intent(inout) :: this
319 | type(json_file) :: json
320 | character(len=:), allocatable :: tmp
321 | logical :: found
322 | call json%initialize()
323 | call json%load_file(trim(this%file_name))
324 | call json%get("Transcription.url", tmp, found=found)
325 | if (found) this%url = trim(tmp)
326 | call json%destroy()
327 | end subroutine load_url
328 | !===============================================================================
329 |
330 |
331 | !===============================================================================
332 | !> author: Seyed Ali Ghasemi
333 | elemental impure subroutine load_model(this)
334 | use json_module, only: json_file
335 | class(Transcription), intent(inout) :: this
336 | type(json_file) :: json
337 | character(len=:), allocatable :: tmp
338 | logical :: found
339 | call json%initialize()
340 | call json%load_file(trim(this%file_name))
341 | call json%get("Transcription.model", tmp, found=found)
342 | if (found) this%model = trim(tmp)
343 | call json%destroy()
344 | end subroutine load_model
345 | !===============================================================================
346 |
347 |
348 | !===============================================================================
349 | !> author: Seyed Ali Ghasemi
350 | elemental pure subroutine set_temperature(this, temperature)
351 | class(Transcription), intent(inout) :: this
352 | real, intent(in) :: temperature
353 | this%temperature = temperature
354 | end subroutine set_temperature
355 | !===============================================================================
356 |
357 |
358 | !===============================================================================
359 | !> author: Seyed Ali Ghasemi
360 | elemental pure subroutine set_url(this, url)
361 | class(Transcription), intent(inout) :: this
362 | character(len=*), intent(in) :: url
363 | this%url = trim(url)
364 | end subroutine set_url
365 | !===============================================================================
366 |
367 |
368 | !===============================================================================
369 | !> author: Seyed Ali Ghasemi
370 | elemental pure subroutine set_model(this, model)
371 | class(Transcription), intent(inout) :: this
372 | character(len=*), intent(in) :: model
373 | this%model = trim(model)
374 | end subroutine set_model
375 | !===============================================================================
376 |
377 |
378 | !===============================================================================
379 | !> author: Seyed Ali Ghasemi
380 | elemental impure subroutine create_transcription(this, file, prompt)
381 | use http, only: response_type, request, HTTP_POST, pair_type
382 | use json_module, only: json_file
383 |
384 | class(Transcription), intent(inout) :: this
385 | character(len=*), intent(in) :: file
386 | character(len=*), intent(in), optional :: prompt
387 | type(pair_type), allocatable :: req_header(:), form_data(:), file_data
388 | type(response_type) :: response
389 | type(json_file) :: json
390 | character(len=1024) :: temperature_str
391 | character(len=:), allocatable :: assistant_response
392 | logical :: found
393 |
394 | call this%set_file(file=file)
395 |
396 | if (present(prompt)) then
397 | call this%set_prompt(prompt=prompt)
398 | else
399 | call this%set_prompt(prompt='')
400 | end if
401 |
402 | req_header = [&
403 | pair_type('Authorization', 'Bearer '//trim(this%api_key)//''),&
404 | pair_type('Content-Type', 'multipart/form-data')&
405 | ]
406 |
407 | write(temperature_str,'(f3.1)') this%temperature
408 |
409 | form_data = [&
410 | pair_type('model', trim(this%model)),&
411 | pair_type(' language', trim(this%language)),&
412 | pair_type(' response_format', trim(this%response_format)),&
413 | pair_type(' prompt', trim(this%prompt)),&
414 | pair_type(' temperature', trim(temperature_str))&
415 | ]
416 |
417 | file_data = pair_type('file', trim(this%file))
418 |
419 | response = request(url = this%url, method = HTTP_POST , header = req_header, form=form_data, file=file_data)
420 |
421 | if (response%ok) then
422 | call json%initialize()
423 | call json%deserialize(response%content)
424 | call json%get("text", assistant_response, found=found)
425 | if (.not. found) then
426 | call json%get("error.message", assistant_response)
427 | end if
428 | this%assistant_response = trim(assistant_response)
429 | call json%destroy()
430 | else
431 | print '(A)', 'Sorry, an error occurred while processing your request.'
432 | print '(A)', 'Error message:', response%err_msg
433 | end if
434 |
435 | end subroutine create_transcription
436 | !===============================================================================
437 |
438 |
439 | !===============================================================================
440 | !> author: Seyed Ali Ghasemi
441 | elemental impure subroutine print_model(this)
442 | class(Transcription), intent(inout) :: this
443 | print "('model: ',A)", trim(this%model)
444 | end subroutine print_model
445 | !===============================================================================
446 |
447 |
448 | !===============================================================================
449 | !> author: Seyed Ali Ghasemi
450 | elemental impure subroutine print_temperature(this)
451 | class(Transcription), intent(inout) :: this
452 | print "('temperature: ',F3.1)", this%temperature
453 | end subroutine print_temperature
454 | !===============================================================================
455 |
456 | end module foropenai_Transcription
457 |
--------------------------------------------------------------------------------
/src/foropenai_Translation.f90:
--------------------------------------------------------------------------------
1 | module foropenai_Translation
2 |
3 | use foropenai_base
4 |
5 | implicit none
6 |
7 | private
8 | public :: Translation
9 |
10 | !===============================================================================
11 | !> author: Seyed Ali Ghasemi
12 | type, extends(openai) :: Translation
13 | character(len=:), allocatable :: url
14 | character(len=:), allocatable :: model
15 | character(len=:), allocatable :: prompt
16 | character(len=:), allocatable :: file
17 | character(len=:), allocatable :: assistant_response
18 | character(len=4) :: response_format='json'
19 | real :: temperature=0.0
20 | contains
21 | procedure :: create => create_translation
22 | procedure, private :: deallocate_url
23 | procedure, private :: deallocate_model
24 | procedure, private :: deallocate_prompt
25 | procedure, private :: deallocate_file
26 | procedure, private :: deallocate_assistant_response
27 | procedure :: finalize => deallocate_Translation
28 | procedure, private :: load => load_Translation_data
29 | procedure, private :: load_url
30 | procedure, private :: load_model
31 | procedure, private :: load_temperature
32 | procedure, private :: load_response_format
33 | procedure, private :: print_model
34 | procedure, private :: print_temperature
35 | procedure, private :: print_response_format
36 | procedure, private :: print_prompt
37 | procedure :: print_assistant_response
38 | procedure :: print_file
39 | procedure, private :: set_assistant_response
40 | procedure, private :: set_prompt
41 | procedure, private :: set_url
42 | procedure, private :: set_model
43 | procedure, private :: set_temperature
44 | procedure, private :: set_response_format
45 | procedure, private :: set_file
46 | procedure :: set => set_Translation_data
47 | end type Translation
48 | !===============================================================================
49 |
50 | contains
51 |
52 | !===============================================================================
53 | !> author: Seyed Ali Ghasemi
54 | elemental impure subroutine print_file(this)
55 | use face, only: colorize
56 | class(Translation), intent(inout) :: this
57 | print "(A,': ',A)", colorize('file', color_bg='green'), this%file
58 | end subroutine print_file
59 | !===============================================================================
60 |
61 |
62 | !===============================================================================
63 | !> author: Seyed Ali Ghasemi
64 | elemental impure subroutine print_assistant_response(this)
65 | use face, only: colorize
66 | class(Translation), intent(inout) :: this
67 | print "(A,': ',A)", colorize("Whisper", color_bg='blue'), this%assistant_response
68 | end subroutine print_assistant_response
69 | !===============================================================================
70 |
71 |
72 | !===============================================================================
73 | !> author: Seyed Ali Ghasemi
74 | elemental pure subroutine set_assistant_response(this, assistant_response)
75 | class(Translation), intent(inout) :: this
76 | character(len=*), intent(in) :: assistant_response
77 | this%assistant_response = trim(assistant_response)
78 | end subroutine set_assistant_response
79 | !===============================================================================
80 |
81 |
82 | !===============================================================================
83 | !> author: Seyed Ali Ghasemi
84 | elemental impure subroutine print_prompt(this)
85 | class(Translation), intent(inout) :: this
86 | print "('prompt: ',A)", trim(this%prompt)
87 | end subroutine print_prompt
88 | !===============================================================================
89 |
90 |
91 | !===============================================================================
92 | !> author: Seyed Ali Ghasemi
93 | elemental pure subroutine set_prompt(this, prompt)
94 | class(Translation), intent(inout) :: this
95 | character(len=*), intent(in) :: prompt
96 | this%prompt = trim(prompt)
97 | end subroutine set_prompt
98 | !===============================================================================
99 |
100 |
101 | !===============================================================================
102 | !> author: Seyed Ali Ghasemi
103 | elemental pure subroutine deallocate_Translation(this)
104 | class(Translation), intent(inout) :: this
105 | call this%deallocate_url()
106 | call this%deallocate_model()
107 | call this%deallocate_prompt()
108 | call this%deallocate_file()
109 | call this%deallocate_assistant_response()
110 | end subroutine deallocate_Translation
111 | !===============================================================================
112 |
113 |
114 | !===============================================================================
115 | !> author: Seyed Ali Ghasemi
116 | elemental pure subroutine deallocate_url(this)
117 | class(Translation), intent(inout) :: this
118 | if (allocated(this%url)) deallocate(this%url)
119 | end subroutine deallocate_url
120 | !===============================================================================
121 |
122 |
123 | !===============================================================================
124 | !> author: Seyed Ali Ghasemi
125 | elemental pure subroutine deallocate_model(this)
126 | class(Translation), intent(inout) :: this
127 | if (allocated(this%model)) deallocate(this%model)
128 | end subroutine deallocate_model
129 | !===============================================================================
130 |
131 |
132 | !===============================================================================
133 | !> author: Seyed Ali Ghasemi
134 | elemental pure subroutine deallocate_prompt(this)
135 | class(Translation), intent(inout) :: this
136 | if (allocated(this%prompt)) deallocate(this%prompt)
137 | end subroutine deallocate_prompt
138 | !===============================================================================
139 |
140 |
141 | !===============================================================================
142 | !> author: Seyed Ali Ghasemi
143 | elemental pure subroutine deallocate_file(this)
144 | class(Translation), intent(inout) :: this
145 | if (allocated(this%file)) deallocate(this%file)
146 | end subroutine deallocate_file
147 | !===============================================================================
148 |
149 |
150 | !===============================================================================
151 | !> author: Seyed Ali Ghasemi
152 | elemental pure subroutine deallocate_assistant_response(this)
153 | class(Translation), intent(inout) :: this
154 | if (allocated(this%assistant_response)) deallocate(this%assistant_response)
155 | end subroutine deallocate_assistant_response
156 | !===============================================================================
157 |
158 |
159 | !===============================================================================
160 | !> author: Seyed Ali Ghasemi
161 | elemental pure subroutine set_response_format(this, response_format)
162 | class(Translation), intent(inout) :: this
163 | character(len=*), intent(in) :: response_format
164 | this%response_format = trim(response_format)
165 | end subroutine set_response_format
166 | !===============================================================================
167 |
168 |
169 | !===============================================================================
170 | !> author: Seyed Ali Ghasemi
171 | elemental impure subroutine load_response_format(this)
172 | use json_module, only: json_file
173 | class(Translation), intent(inout) :: this
174 | type(json_file) :: json
175 | character(len=:), allocatable :: tmp
176 | logical :: found
177 | call json%initialize()
178 | call json%load_file(trim(this%file_name))
179 | call json%get("Translation.response_format", tmp, found=found)
180 | if (found) this%response_format = trim(tmp)
181 | call json%destroy()
182 | end subroutine load_response_format
183 | !===============================================================================
184 |
185 |
186 | !===============================================================================
187 | !> author: Seyed Ali Ghasemi
188 | elemental impure subroutine print_response_format(this)
189 | class(Translation), intent(inout) :: this
190 | print "('response_format: ',A)", trim(this%response_format)
191 | end subroutine print_response_format
192 | !===============================================================================
193 |
194 |
195 | !===============================================================================
196 | !> author: Seyed Ali Ghasemi
197 | elemental pure subroutine set_file(this, file)
198 | class(Translation), intent(inout) :: this
199 | character(len=*), intent(in) :: file
200 | this%file = trim(file)
201 | end subroutine set_file
202 | !===============================================================================
203 |
204 |
205 | !===============================================================================
206 | !> author: Seyed Ali Ghasemi
207 | elemental impure subroutine set_Translation_data(this, file_name, &
208 | url, model, temperature, response_format)
209 | class(Translation), intent(inout) :: this
210 | character(len=*), optional, intent(in) :: file_name
211 | character(len=*), optional, intent(in) :: url
212 | character(len=*), optional, intent(in) :: model
213 | real, optional, intent(in) :: temperature
214 | character(len=*), optional, intent(in) :: response_format
215 |
216 | if (present(url)) call this%set_url(url=url)
217 | if (present(model)) call this%set_model(model=model)
218 | if (present(temperature)) call this%set_temperature(temperature=temperature)
219 | if (present(response_format)) call this%set_response_format(response_format=response_format)
220 |
221 | if (present(file_name)) then
222 | call this%set_file_name(file_name)
223 | call this%load(file_name)
224 | end if
225 | end subroutine set_Translation_data
226 | !===============================================================================
227 |
228 |
229 | !===============================================================================
230 | !> author: Seyed Ali Ghasemi
231 | elemental impure subroutine load_Translation_data(this, file_name)
232 | class(Translation), intent(inout) :: this
233 | character(len=*), intent(in) :: file_name
234 | call this%set_file_name(trim(file_name))
235 | call this%load_url()
236 | call this%load_model()
237 | call this%load_temperature()
238 | call this%load_response_format()
239 | end subroutine load_Translation_data
240 | !===============================================================================
241 |
242 |
243 | !===============================================================================
244 | !> author: Seyed Ali Ghasemi
245 | elemental impure subroutine load_temperature(this)
246 | use json_module, only: json_file
247 | class(Translation), intent(inout) :: this
248 | type(json_file) :: json
249 | real :: tmp
250 | logical :: found
251 | call json%initialize()
252 | call json%load_file(trim(this%file_name))
253 | call json%get("Translation.temperature", tmp, found=found)
254 | if (found) this%temperature = tmp
255 | call json%destroy()
256 | end subroutine load_temperature
257 | !===============================================================================
258 |
259 |
260 | !===============================================================================
261 | !> author: Seyed Ali Ghasemi
262 | elemental impure subroutine load_url(this)
263 | use json_module, only: json_file
264 | class(Translation), intent(inout) :: this
265 | type(json_file) :: json
266 | character(len=:), allocatable :: tmp
267 | logical :: found
268 | call json%initialize()
269 | call json%load_file(trim(this%file_name))
270 | call json%get("Translation.url", tmp, found=found)
271 | if (found) this%url = trim(tmp)
272 | call json%destroy()
273 | end subroutine load_url
274 | !===============================================================================
275 |
276 |
277 | !===============================================================================
278 | !> author: Seyed Ali Ghasemi
279 | elemental impure subroutine load_model(this)
280 | use json_module, only: json_file
281 | class(Translation), intent(inout) :: this
282 | type(json_file) :: json
283 | character(len=:), allocatable :: tmp
284 | logical :: found
285 | call json%initialize()
286 | call json%load_file(trim(this%file_name))
287 | call json%get("Translation.model", tmp, found=found)
288 | if (found) this%model = trim(tmp)
289 | call json%destroy()
290 | end subroutine load_model
291 | !===============================================================================
292 |
293 |
294 | !===============================================================================
295 | !> author: Seyed Ali Ghasemi
296 | elemental pure subroutine set_temperature(this, temperature)
297 | class(Translation), intent(inout) :: this
298 | real, intent(in) :: temperature
299 | this%temperature = temperature
300 | end subroutine set_temperature
301 | !===============================================================================
302 |
303 |
304 | !===============================================================================
305 | !> author: Seyed Ali Ghasemi
306 | elemental pure subroutine set_url(this, url)
307 | class(Translation), intent(inout) :: this
308 | character(len=*), intent(in) :: url
309 | this%url = trim(url)
310 | end subroutine set_url
311 | !===============================================================================
312 |
313 |
314 | !===============================================================================
315 | !> author: Seyed Ali Ghasemi
316 | elemental pure subroutine set_model(this, model)
317 | class(Translation), intent(inout) :: this
318 | character(len=*), intent(in) :: model
319 | this%model = trim(model)
320 | end subroutine set_model
321 | !===============================================================================
322 |
323 |
324 | !===============================================================================
325 | !> author: Seyed Ali Ghasemi
326 | elemental impure subroutine create_translation(this, file, prompt)
327 | use http, only: response_type, request, HTTP_POST, pair_type
328 | use json_module, only: json_file
329 |
330 | class(Translation), intent(inout) :: this
331 | character(len=*), intent(in) :: file
332 | character(len=*), intent(in), optional :: prompt
333 | type(pair_type), allocatable :: req_header(:), form_data(:), file_data
334 | type(response_type) :: response
335 | type(json_file) :: json
336 | character(len=1024) :: temperature_str
337 | character(len=:), allocatable :: assistant_response
338 | logical :: found
339 |
340 | call this%set_file(file=file)
341 |
342 | if (present(prompt)) then
343 | call this%set_prompt(prompt=prompt)
344 | else
345 | call this%set_prompt(prompt='')
346 | end if
347 |
348 | req_header = [&
349 | pair_type('Authorization', 'Bearer '//trim(this%api_key)),&
350 | pair_type('Content-Type', 'multipart/form-data')&
351 | ]
352 |
353 | write(temperature_str,'(f3.1)') this%temperature
354 |
355 | form_data = [&
356 | pair_type('model', trim(this%model)),&
357 | pair_type('prompt', trim(this%prompt)),&
358 | pair_type('response_format', trim(this%response_format))&
359 | ! pair_type('temperature', trim(temperature_str))&
360 | ]
361 |
362 | file_data = pair_type('file', trim(this%file))
363 |
364 | response = request(url=this%url, method=HTTP_POST, header=req_header, form=form_data, file=file_data)
365 |
366 | if (response%ok) then
367 | call json%initialize()
368 | call json%deserialize(response%content)
369 | call json%get("text", assistant_response, found=found)
370 | if (.not. found) then
371 | call json%get("error.message", assistant_response)
372 | end if
373 | this%assistant_response = trim(assistant_response)
374 |
375 | call json%destroy()
376 | else
377 | print '(A)', 'Sorry, an error occurred while processing your request.'
378 | print '(A)', 'Error message:', response%err_msg
379 | end if
380 |
381 | end subroutine create_translation
382 | !===============================================================================
383 |
384 |
385 | !===============================================================================
386 | !> author: Seyed Ali Ghasemi
387 | elemental impure subroutine print_model(this)
388 | class(Translation), intent(inout) :: this
389 | print "('model: ',A)", trim(this%model)
390 | end subroutine print_model
391 | !===============================================================================
392 |
393 |
394 | !===============================================================================
395 | !> author: Seyed Ali Ghasemi
396 | elemental impure subroutine print_temperature(this)
397 | class(Translation), intent(inout) :: this
398 | print "('temperature: ',F3.1)", this%temperature
399 | end subroutine print_temperature
400 | !===============================================================================
401 |
402 | end module foropenai_Translation
403 |
--------------------------------------------------------------------------------
/src/foropenai_base.f90:
--------------------------------------------------------------------------------
1 | module foropenai_base
2 |
3 | implicit none
4 |
5 | private
6 | public :: openai
7 |
8 | !===============================================================================
9 | !> author: Seyed Ali Ghasemi
10 | type openai
11 | character(len=:), allocatable :: organization
12 | character(len=:), allocatable :: api_key
13 | character(len=:), allocatable :: file_name
14 | character(len=14) :: api_key_env = 'OPENAI_API_KEY'
15 | character(len=10) :: organization_env = 'OPENAI_ORG'
16 | contains
17 | procedure, private :: deallocate_api_key
18 | procedure, private :: deallocate_organization
19 | procedure, private :: deallocate_file_name
20 | procedure :: finalize => deallocate_openai
21 | procedure, private :: load_api_key
22 | procedure, private :: load_organization
23 | procedure :: load_base_data
24 | procedure :: print_api_key
25 | procedure :: print_organization
26 | procedure :: print_file_name
27 | procedure :: set_file_name
28 | procedure, private :: set_api_key
29 | procedure, private :: set_organization
30 | procedure, private :: set_api_key_env
31 | procedure, private :: set_organization_env
32 | procedure :: set_base_data
33 | end type openai
34 | !===============================================================================
35 |
36 | contains
37 |
38 | !===============================================================================
39 | !> author: Seyed Ali Ghasemi
40 | elemental impure subroutine set_base_data(this, file_name, api_key, organization)
41 | class(openai), intent(inout) :: this
42 | character(len=*), optional, intent(in) :: file_name
43 | character(len=*), optional, intent(in) :: api_key
44 | character(len=*), optional, intent(in) :: organization
45 | integer :: stat_api_key, stat_organization
46 |
47 | if (present(api_key)) call this%set_api_key(api_key)
48 | if (present(organization)) call this%set_organization(organization)
49 |
50 | if (present(file_name)) call this%set_file_name(file_name)
51 |
52 | call this%set_api_key_env(status=stat_api_key)
53 | if (stat_api_key == 1) call this%load_api_key(file_name)
54 |
55 | call this%set_organization_env(status=stat_organization)
56 | if (stat_organization == 1) call this%load_organization(file_name)
57 | end subroutine set_base_data
58 | !===============================================================================
59 |
60 |
61 | !===============================================================================
62 | !> author: Seyed Ali Ghasemi
63 | elemental impure subroutine set_api_key_env(this, status)
64 | class(openai), intent(inout) :: this
65 | integer, intent(out), optional :: status
66 | character(len=1024) :: tmp
67 | call get_environment_variable(this%api_key_env, tmp, status = status)
68 | if (status==0) call this%set_api_key(trim(tmp))
69 | end subroutine set_api_key_env
70 | !===============================================================================
71 |
72 |
73 | !===============================================================================
74 | !> author: Seyed Ali Ghasemi
75 | elemental impure subroutine set_organization_env(this, status)
76 | class(openai), intent(inout) :: this
77 | integer, intent(out), optional :: status
78 | character(len=1024) :: tmp
79 | call get_environment_variable(this%organization_env, tmp, status = status)
80 | if (status==0) call this%set_organization(trim(tmp))
81 | end subroutine set_organization_env
82 | !===============================================================================
83 |
84 |
85 | !===============================================================================
86 | !> author: Seyed Ali Ghasemi
87 | elemental pure subroutine deallocate_openai(this)
88 | class(openai), intent(inout) :: this
89 | call this%deallocate_api_key()
90 | call this%deallocate_organization()
91 | call this%deallocate_file_name()
92 | end subroutine deallocate_openai
93 | !===============================================================================
94 |
95 |
96 | !===============================================================================
97 | !> author: Seyed Ali Ghasemi
98 | elemental pure subroutine deallocate_api_key(this)
99 | class(openai), intent(inout) :: this
100 | if (allocated(this%api_key)) deallocate(this%api_key)
101 | end subroutine deallocate_api_key
102 | !===============================================================================
103 |
104 |
105 | !===============================================================================
106 | !> author: Seyed Ali Ghasemi
107 | elemental pure subroutine deallocate_organization(this)
108 | class(openai), intent(inout) :: this
109 | if (allocated(this%organization)) deallocate(this%organization)
110 | end subroutine deallocate_organization
111 | !===============================================================================
112 |
113 |
114 | !===============================================================================
115 | !> author: Seyed Ali Ghasemi
116 | elemental pure subroutine deallocate_file_name(this)
117 | class(openai), intent(inout) :: this
118 | if (allocated(this%file_name)) deallocate(this%file_name)
119 | end subroutine deallocate_file_name
120 | !===============================================================================
121 |
122 |
123 | !===============================================================================
124 | !> author: Seyed Ali Ghasemi
125 | elemental impure subroutine load_base_data(this, file_name)
126 | class(openai), intent(inout) :: this
127 | character(len=*), intent(in) :: file_name
128 | call this%set_file_name(trim(file_name))
129 | call this%load_api_key()
130 | call this%load_organization()
131 | end subroutine load_base_data
132 | !===============================================================================
133 |
134 |
135 | !===============================================================================
136 | !> author: Seyed Ali Ghasemi
137 | elemental pure subroutine set_organization(this, organization)
138 | class(openai), intent(inout) :: this
139 | character(len=*), intent(in) :: organization
140 | this%organization = trim(organization)
141 | end subroutine set_organization
142 | !===============================================================================
143 |
144 |
145 | !===============================================================================
146 | !> author: Seyed Ali Ghasemi
147 | elemental pure subroutine set_api_key(this, api_key)
148 | class(openai), intent(inout) :: this
149 | character(len=*), intent(in) :: api_key
150 | this%api_key = trim(api_key)
151 | end subroutine set_api_key
152 | !===============================================================================
153 |
154 |
155 | !===============================================================================
156 | !> author: Seyed Ali Ghasemi
157 | elemental impure subroutine load_api_key(this, file_name)
158 | use json_module, only: json_file
159 | class(openai), intent(inout) :: this
160 | character(len=*), intent(in), optional :: file_name
161 | type(json_file) :: json
162 | if (present(file_name)) call this%set_file_name(file_name)
163 | call json%initialize()
164 | call json%load_file(trim(this%file_name))
165 | call json%get("base.api_key", this%api_key)
166 | call json%destroy()
167 | end subroutine load_api_key
168 | !===============================================================================
169 |
170 |
171 | !===============================================================================
172 | !> author: Seyed Ali Ghasemi
173 | elemental pure subroutine set_file_name(this, file_name)
174 | class(openai), intent(inout) :: this
175 | character(len=*), intent(in) :: file_name
176 | this%file_name = trim(file_name)
177 | end subroutine set_file_name
178 | !===============================================================================
179 |
180 |
181 | !===============================================================================
182 | !> author: Seyed Ali Ghasemi
183 | elemental impure subroutine load_organization(this, file_name)
184 | use json_module, only: json_file
185 | class(openai), intent(inout) :: this
186 | character(len=*), intent(in), optional :: file_name
187 | type(json_file) :: json
188 | if (present(file_name)) call this%set_file_name(file_name)
189 | call json%initialize()
190 | call json%load_file(trim(this%file_name))
191 | call json%get("base.organization", this%organization)
192 | call json%destroy()
193 | end subroutine load_organization
194 | !===============================================================================
195 |
196 |
197 | !===============================================================================
198 | !> author: Seyed Ali Ghasemi
199 | elemental impure subroutine print_api_key(this)
200 | class(openai), intent(inout) :: this
201 | print "('api key: ',A)", trim(this%api_key)
202 | end subroutine print_api_key
203 | !===============================================================================
204 |
205 |
206 | !===============================================================================
207 | !> author: Seyed Ali Ghasemi
208 | elemental impure subroutine print_organization(this)
209 | class(openai), intent(inout) :: this
210 | print "('organization: ',A)", trim(this%organization)
211 | end subroutine print_organization
212 | !===============================================================================
213 |
214 |
215 | !===============================================================================
216 | !> author: Seyed Ali Ghasemi
217 | elemental impure subroutine print_file_name(this)
218 | class(openai), intent(inout) :: this
219 | print "('file name: ',A)", trim(this%file_name)
220 | end subroutine print_file_name
221 | !===============================================================================
222 |
223 | end module foropenai_base
224 |
--------------------------------------------------------------------------------
/test/audio.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gha3mi/foropenai/952a0eff4bb9f5bcd39bfa48e075c7901184c572/test/audio.mp3
--------------------------------------------------------------------------------
/test/audio_de.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gha3mi/foropenai/952a0eff4bb9f5bcd39bfa48e075c7901184c572/test/audio_de.mp3
--------------------------------------------------------------------------------
/test/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gha3mi/foropenai/952a0eff4bb9f5bcd39bfa48e075c7901184c572/test/image.png
--------------------------------------------------------------------------------
/test/test1.f90:
--------------------------------------------------------------------------------
1 | program test_base
2 |
3 | use foropenai, only: openai
4 |
5 | implicit none
6 |
7 | type(openai) :: base
8 |
9 | call base%set_base_data(file_name='foropenai.json')
10 |
11 | call base%print_api_key()
12 | call base%print_organization()
13 | call base%print_file_name()
14 |
15 | call base%finalize()
16 |
17 | end program test_base
18 |
--------------------------------------------------------------------------------
/test/test2.f90:
--------------------------------------------------------------------------------
1 | program test_ChatCompletion
2 |
3 | use foropenai, only: ChatCompletion
4 |
5 | implicit none
6 |
7 | type(ChatCompletion) :: chat
8 |
9 | call chat%set_base_data(file_name='foropenai.json')
10 | call chat%set(file_name='foropenai.json')
11 |
12 | call chat%init_messages(n=3)
13 | call chat%messages(1)%set(role='system', content='You are a helpful assistant.')
14 | call chat%messages(2)%set(role='user', content='Hello?')
15 | call chat%messages(3)%set(role='assistant', content='')
16 |
17 | call chat%print_user_message()
18 | call chat%create()
19 | call chat%print_assistant_response()
20 |
21 | call chat%usage%print()
22 |
23 | call chat%finalize()
24 |
25 | end program test_ChatCompletion
26 |
--------------------------------------------------------------------------------
/test/test3.f90:
--------------------------------------------------------------------------------
1 | program test_Transcription
2 |
3 | use foropenai, only: Transcription
4 |
5 | implicit none
6 |
7 | type(Transcription) :: trs
8 |
9 | call trs%set_base_data(file_name='foropenai.json')
10 | call trs%set(file_name='foropenai.json')
11 |
12 | call trs%create(file='test/audio.mp3')
13 | call trs%print_file()
14 | call trs%print_assistant_response()
15 |
16 | call trs%finalize()
17 |
18 | end program test_Transcription
19 |
--------------------------------------------------------------------------------
/test/test4.f90:
--------------------------------------------------------------------------------
1 | program test_ImageGeneration
2 |
3 | use foropenai, only: ImageGeneration
4 |
5 | implicit none
6 |
7 | type(ImageGeneration) :: image
8 |
9 | call image%set_base_data(file_name='foropenai.json')
10 | call image%set(file_name='foropenai.json')
11 |
12 | call image%create(prompt='a cat with a computer')
13 | call image%print_prompt()
14 | call image%print_assistant_response()
15 |
16 | call image%finalize()
17 |
18 | end program test_ImageGeneration
19 |
--------------------------------------------------------------------------------
/test/test5.f90:
--------------------------------------------------------------------------------
1 | program test_Translation
2 |
3 | use foropenai, only: Translation
4 |
5 | implicit none
6 |
7 | type(Translation) :: trs
8 |
9 | call trs%set_base_data(file_name='foropenai.json')
10 | call trs%set(file_name='foropenai.json')
11 |
12 | call trs%create(file='test/audio_de.mp3')
13 | call trs%print_file()
14 | call trs%print_assistant_response()
15 |
16 | call trs%finalize()
17 |
18 | end program test_Translation
19 |
--------------------------------------------------------------------------------
/workspace.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "name": "foropenai",
5 | "path": "."
6 | }
7 | ],
8 | "settings": {
9 | "fortran.linter.modOutput": "${workspaceFolder}/mod/",
10 | "fortran.fortls.directories": [
11 | "${workspaceFolder}/src",
12 | "${workspaceFolder}/test",
13 | "${workspaceFolder}/app"
14 | ]
15 | }
16 | }
--------------------------------------------------------------------------------