4545import fuzzysearch
4646import json_repair
4747import asyncio
48+ import configparser
4849
4950max_memo_length = 1500 # Maximum length of the memo send to the AI
5051
@@ -82,11 +83,159 @@ def get_available_models(api_base: str, api_key: str) -> list:
8283 if api_base == '' :
8384 api_base = None
8485 client = OpenAI (api_key = api_key , base_url = api_base )
85- response = client .models .list (timeout = 6 .0 )
86+ response = client .models .list (timeout = 4 .0 )
8687 model_dict = response .model_dump ().get ('data' , [])
8788 model_list = sorted ([model ['id' ] for model in model_dict ])
8889 return model_list
8990
91+ def get_default_ai_models ():
92+ ini_string = """
93+ [ai_model_OpenAI GPT4.1]
94+ desc = Powerful and large model from OpenAI, for complex tasks.
95+ You need an API-key from OpenAI and have paid for credits in your account.
96+ OpenAI will charge a small amount for every use.
97+ access_info_url = https://platform.openai.com/api-keys
98+ large_model = gpt-4.1
99+ large_model_context_window = 1000000
100+ fast_model = gpt-4.1-mini
101+ fast_model_context_window = 128000
102+ api_base =
103+ api_key =
104+
105+ [ai_model_OpenAI_GPT4o]
106+ desc = General use model from OpenAI, faster and cheaper than other options.
107+ You need an API-key from OpenAI and have paid for credits in your account.
108+ OpenAI will charge a small amount for every use.
109+ access_info_url = https://platform.openai.com/api-keys
110+ large_model = gpt-4o
111+ large_model_context_window = 1000000
112+ fast_model = gpt-4o-mini
113+ fast_model_context_window = 128000
114+ api_base =
115+ api_key =
116+
117+ [ai_model_Blablador]
118+ desc = Free and open source models, excellent privacy, but not as powerful
119+ as the commercial offerings. Blablador runs on a server of the Helmholtz
120+ Society, a large non-profit research organization in Germany. To gain
121+ access and get an API-key, you have to identify yourself once with your
122+ university, ORCID, GitHub, or Google account.
123+ access_info_url = https://sdlaml.pages.jsc.fz-juelich.de/ai/guides/blablador_api_access/
124+ large_model = alias-large
125+ large_model_context_window = 128000
126+ fast_model = alias-fast
127+ fast_model_context_window = 32000
128+ api_base = https://helmholtz-blablador.fz-juelich.de:8000/v1
129+ api_key =
130+
131+ [ai_model_Blablador Huge]
132+ desc = Llama 3.1 405b, very large and powerful. Availability might change.
133+ Blablador is free to use and runs on a server of the Helmholtz Society,
134+ a large non-profit research organization in Germany. To gain
135+ access and get an API-key, you have to identify yourself once with your
136+ university, ORCID, GitHub, or Google account.
137+ access_info_url = https://sdlaml.pages.jsc.fz-juelich.de/ai/guides/blablador_api_access/
138+ large_model = alias-llama3-huge
139+ large_model_context_window = 128000
140+ fast_model = alias-fast
141+ fast_model_context_window = 128000
142+ api_base = https://helmholtz-blablador.fz-juelich.de:8000/v1
143+ api_key =
144+
145+ [ai_model_Anthropic Claude]
146+ desc = Claude is a family of high quality models from Anthropic.
147+ You need an API-key from Anthropic and credits in your account.
148+ Anthropic will charge a small amount for every use.
149+ access_info_url = https://console.anthropic.com/settings/keys
150+ large_model = claude-opus-4-20250514
151+ large_model_context_window = 200000
152+ fast_model = claude-sonnet-4-20250514
153+ fast_model_context_window = 200000
154+ api_base = https://api.anthropic.com/v1/
155+ api_key =
156+
157+ [ai_model_Google Gemini]
158+ desc = Google offers several free and paid models on their servers.
159+ Select one in the Advanced AI options below.
160+ You need an API-key from Google.
161+ access_info_url = https://ai.google.dev/gemini-api/docs
162+ large_model = gemini-2.5-flash
163+ large_model_context_window = 1000000
164+ fast_model = gemini-2.5-flash
165+ fast_model_context_window = 1000000
166+ api_base = https://generativelanguage.googleapis.com/v1beta/openai/
167+ api_key =
168+
169+ [ai_model_Deepseek Chat V3]
170+ desc = Deepseek is a high quality Chinese chat model.
171+ You will need an an API-key from Deepseek and have payed credits in your account.
172+ Deepseek will charge a small amount for every use.
173+ access_info_url = https://platform.deepseek.com/api_keys
174+ large_model = deepseek-chat
175+ large_model_context_window = 64000
176+ fast_model = deepseek-chat
177+ fast_model_context_window = 64000
178+ api_base = https://api.deepseek.com
179+ api_key =
180+
181+ [ai_model_OpenRouter]
182+ desc = OpenRouter is a unified interface to access many different AI language
183+ models, both free and paid. You need an API-key from OpenRouter.
184+ Select a model in the Advanced AI Options below.
185+ access_info_url = https://openrouter.ai/
186+ large_model = deepseek/deepseek-chat:free
187+ large_model_context_window = 64000
188+ fast_model = deepseek/deepseek-chat:free
189+ fast_model_context_window = 64000
190+ api_base = https://openrouter.ai/api/v1
191+ api_key =
192+
193+ [ai_model_Ollama local AI]
194+ desc = Ollama is an open source server that lets you run LLMs locally on
195+ your computer. To use it in QualCoder, you must have Ollama set up and
196+ running first. Use the Advanced AI Options below to select between your
197+ locally installed models.
198+ access_info_url = https://ollama.com
199+ large_model = test
200+ large_model_context_window = 1
201+ fast_model = test
202+ fast_model_context_window = 1
203+ api_base = http://localhost:11434/v1/
204+ api_key = <no API key needed>
205+ """
206+
207+ config = configparser .ConfigParser ()
208+ config .read_string (ini_string )
209+ ai_models = []
210+ for section in config .sections ():
211+ if section .startswith ('ai_model_' ):
212+ model = {
213+ 'name' : section [9 :],
214+ 'desc' : config [section ].get ('desc' , '' ),
215+ 'access_info_url' : config [section ].get ('access_info_url' , '' ),
216+ 'large_model' : config [section ].get ('large_model' , '' ),
217+ 'large_model_context_window' : config [section ].get ('large_model_context_window' , '32768' ),
218+ 'fast_model' : config [section ].get ('fast_model' , '' ),
219+ 'fast_model_context_window' : config [section ].get ('fast_model_context_window' , '32768' ),
220+ 'api_base' : config [section ].get ('api_base' , '' ),
221+ 'api_key' : config [section ].get ('api_key' , '' )
222+ }
223+ ai_models .append (model )
224+ return ai_models
225+
226+ def update_ai_models (current_models : list , current_model_index : int ) -> tuple [list , int ]:
227+ default_models = get_default_ai_models ()
228+ current_models_names = {model ['name' ] for model in current_models }
229+ for model in default_models :
230+ if not model ['name' ] in current_models_names :
231+ if model ['name' ] == 'OpenAI GPT4.1' : # insert this at the top, because it is the current default model
232+ current_models .insert (0 , model )
233+ if current_model_index >= 0 :
234+ current_model_index += 1
235+ else :
236+ current_models .append (model )
237+ return current_models , current_model_index
238+
90239class AiLLM ():
91240 """ This manages the communication between qualcoder, the vectorstore
92241 and the LLM (large language model, e.g. GPT-4)."""
@@ -150,7 +299,7 @@ def init_llm(self, main_window, rebuild_vectorstore=False, enable_ai=False):
150299 if int (self .app .settings ['ai_model_index' ]) >= len (self .app .ai_models ): # model index out of range
151300 self .app .settings ['ai_model_index' ] = - 1
152301 if int (self .app .settings ['ai_model_index' ]) < 0 :
153- msg = _ ('AI: Please set up the AI model' )
302+ msg = _ ('AI: In the follwoing window, please set up the AI model. ' )
154303 Message (self .app , _ ('AI Setup' ), msg ).exec ()
155304
156305 main_window .change_settings (section = 'AI' , enable_ai = True )
@@ -167,13 +316,15 @@ def init_llm(self, main_window, rebuild_vectorstore=False, enable_ai=False):
167316 curr_model = self .app .ai_models [int (self .app .settings ['ai_model_index' ])]
168317
169318 large_model = curr_model ['large_model' ]
319+ if large_model .find ('gpt-4-turbo' ) > - 1 :
320+ self .parent_text_edit .append (_ ('AI: You are still using the outdated GPT-4 turbo. Consider switching to a newer model, such as GPT 4.1. Go to Project > Settings to change the AI profile and model.' ))
170321 self .large_llm_context_window = int (curr_model ['large_model_context_window' ])
171322 fast_model = curr_model ['fast_model' ]
172323 self .fast_llm_context_window = int (curr_model ['fast_model_context_window' ])
173324 api_base = curr_model ['api_base' ]
174325 api_key = curr_model ['api_key' ]
175326 if api_key == '' :
176- msg = _ ('Please enter an API-key for the AI in the following dialog (or "None" if not API-key is needed) .' )
327+ msg = _ ('Please enter an API-key for the AI in the following dialog.' )
177328 Message (self .app , _ ('AI API-key' ), msg ).exec ()
178329 main_window .change_settings (section = 'AI' , enable_ai = True )
179330 curr_model = self .app .ai_models [int (self .app .settings ['ai_model_index' ])]
@@ -187,8 +338,6 @@ def init_llm(self, main_window, rebuild_vectorstore=False, enable_ai=False):
187338 # Success, API-key was set. But since the "change_settings" function will start
188339 # a new "init_llm" anyways, we are going to quit here
189340 return
190- #elif api_key == 'None':
191- # api_key = ''
192341 if large_model == '' or fast_model == '' :
193342 msg = _ ('In the following dialog, go to "Advanced AI Options" and select a large and a fast AI model (both can be the same).' )
194343 Message (self .app , _ ('AI Model Selection' ), msg ).exec ()
0 commit comments