├── .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 | [![GitHub](https://img.shields.io/badge/GitHub-ForOpenAI-blue.svg?style=social&logo=github)](https://github.com/gha3mi/foropenai) 2 | [![Version](https://img.shields.io/github/release/gha3mi/foropenai.svg)](https://github.com/gha3mi/foropenai/releases/latest) 3 | [![Documentation](https://img.shields.io/badge/ford-Documentation%20-blueviolet.svg)](https://gha3mi.github.io/foropenai/) 4 | [![License](https://img.shields.io/github/license/gha3mi/foropenai?color=yellow)](https://github.com/gha3mi/foropenai/blob/main/LICENSE) 5 | [![CI_test](https://github.com/gha3mi/foropenai/actions/workflows/CI_test.yml/badge.svg)](https://github.com/gha3mi/foropenai/actions/workflows/CI_test.yml) 6 | 7 | ForOpenAI 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 | ![Alt text](media/example.png) 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 | image 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 | ForOpenAI 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 | } --------------------------------------------------------------------------------