DocUA commited on
Commit
435589f
·
1 Parent(s): 8b6fe7c

Підключено Gemini, але потребує агентної роботи

Browse files
Files changed (8) hide show
  1. Gradio_UI.py +42 -20
  2. agent.py +116 -51
  3. app.py +32 -31
  4. config.py +0 -112
  5. model_init.py +295 -0
  6. models_config.json +11 -61
  7. requirements.txt +2 -1
  8. test_gemini.py +47 -0
Gradio_UI.py CHANGED
@@ -1,7 +1,6 @@
1
  import gradio as gr
2
  import logging
3
  from pathlib import Path
4
- from config import ModelConfig
5
  from typing import Tuple, List
6
 
7
  logger = logging.getLogger(__name__)
@@ -11,24 +10,33 @@ class GradioUI:
11
  self.agent = agent
12
  self.file_upload_folder = Path(file_upload_folder)
13
  self.file_upload_folder.mkdir(exist_ok=True)
14
- self.model_config = ModelConfig()
15
 
16
  def build_interface(self):
17
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
18
- # Model selection dropdown
19
  with gr.Row():
20
- model_choices = self.model_config.get_available_models()
21
  model_dropdown = gr.Dropdown(
22
  choices=[f"{key} - {desc}" for key, desc in model_choices],
23
- value=f"{self.model_config.get_default_model()} - {dict(model_choices)[self.model_config.get_default_model()]}",
24
  label="Оберіть модель",
25
  info="Оберіть модель для обробки запитів"
26
  )
27
 
28
  with gr.Row():
 
29
  chatbot = gr.Chatbot(
30
  label="Research Assistant",
31
- height=600,
 
 
 
 
 
 
 
 
 
32
  show_copy_button=True
33
  )
34
 
@@ -55,15 +63,14 @@ class GradioUI:
55
  clear_btn = gr.Button("Очистити")
56
  toggle_upload_btn = gr.Button("Завантажити файл")
57
 
58
- # Store conversation state
59
  state = gr.State([])
60
  file_history = gr.State([])
61
- current_model = gr.State(self.model_config.get_default_model())
62
 
63
  def change_model(choice):
64
  model_key = choice.split(" - ")[0]
65
- model_config = self.model_config.get_model_config(model_key)
66
- self.agent.update_model(model_config)
67
  return model_key
68
 
69
  model_dropdown.change(
@@ -104,38 +111,53 @@ class GradioUI:
104
  if files:
105
  message += f"\nДоступні файли для аналізу: {', '.join(files)}"
106
  chat_history.append((message, None))
107
- return "", chat_history
108
 
109
- def bot_response(chat_history, files):
110
  try:
 
 
 
 
 
 
 
 
 
 
111
  response = self.agent.process_query(
112
  chat_history[-1][0],
113
  available_files=files if files else None
114
  )
 
 
115
  chat_history[-1] = (chat_history[-1][0], response)
116
- return chat_history
 
 
117
  except Exception as e:
118
  logger.error(f"Помилка відповіді: {e}")
119
- chat_history[-1] = (chat_history[-1][0], f"Помилка: {str(e)}")
120
- return chat_history
 
121
 
122
  submit_btn.click(
123
  user_message,
124
  [text_input, state, file_history],
125
- [text_input, chatbot]
126
  ).then(
127
  bot_response,
128
- [chatbot, file_history],
129
- [chatbot]
130
  )
131
 
132
  def clear_chat():
133
- return [], []
134
 
135
  clear_btn.click(
136
  clear_chat,
137
  None,
138
- [chatbot, file_history],
139
  queue=False
140
  )
141
 
 
1
  import gradio as gr
2
  import logging
3
  from pathlib import Path
 
4
  from typing import Tuple, List
5
 
6
  logger = logging.getLogger(__name__)
 
10
  self.agent = agent
11
  self.file_upload_folder = Path(file_upload_folder)
12
  self.file_upload_folder.mkdir(exist_ok=True)
 
13
 
14
  def build_interface(self):
15
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
16
+ # Вибір моделі
17
  with gr.Row():
18
+ model_choices = self.agent.model_initializer.get_available_models()
19
  model_dropdown = gr.Dropdown(
20
  choices=[f"{key} - {desc}" for key, desc in model_choices],
21
+ value=f"{self.agent.model_initializer.config['default_model']} - {dict(model_choices)[self.agent.model_initializer.config['default_model']]}",
22
  label="Оберіть модель",
23
  info="Оберіть модель для обробки запитів"
24
  )
25
 
26
  with gr.Row():
27
+ # Основний чат
28
  chatbot = gr.Chatbot(
29
  label="Research Assistant",
30
+ height=400,
31
+ show_copy_button=True
32
+ )
33
+
34
+ # Лог проміжних кроків
35
+ steps_log = gr.Textbox(
36
+ label="Process Steps",
37
+ lines=10,
38
+ max_lines=20,
39
+ interactive=False,
40
  show_copy_button=True
41
  )
42
 
 
63
  clear_btn = gr.Button("Очистити")
64
  toggle_upload_btn = gr.Button("Завантажити файл")
65
 
66
+ # Зберігання стану
67
  state = gr.State([])
68
  file_history = gr.State([])
69
+ current_model = gr.State(self.agent.model_initializer.config['default_model'])
70
 
71
  def change_model(choice):
72
  model_key = choice.split(" - ")[0]
73
+ self.agent.update_model(model_key)
 
74
  return model_key
75
 
76
  model_dropdown.change(
 
111
  if files:
112
  message += f"\nДоступні файли для аналізу: {', '.join(files)}"
113
  chat_history.append((message, None))
114
+ return "", chat_history, "Початок обробки запиту...\n"
115
 
116
+ def bot_response(chat_history, files, steps_text):
117
  try:
118
+ # Оновлюємо лог кроків
119
+ steps = []
120
+ def step_callback(step_info):
121
+ steps.append(f"Step {len(steps)+1}: {step_info}")
122
+ return "\n".join(steps)
123
+
124
+ # Додаємо callback до агента
125
+ self.agent.step_callback = step_callback
126
+
127
+ # Обробляємо запит
128
  response = self.agent.process_query(
129
  chat_history[-1][0],
130
  available_files=files if files else None
131
  )
132
+
133
+ # Оновлюємо історію чату
134
  chat_history[-1] = (chat_history[-1][0], response)
135
+
136
+ # Повертаємо оновлену історію та лог кроків
137
+ return chat_history, "\n".join(steps) + "\n\nОбробку завершено."
138
  except Exception as e:
139
  logger.error(f"Помилка відповіді: {e}")
140
+ error_msg = f"Помилка: {str(e)}"
141
+ chat_history[-1] = (chat_history[-1][0], error_msg)
142
+ return chat_history, steps_text + f"\nПомилка: {str(e)}"
143
 
144
  submit_btn.click(
145
  user_message,
146
  [text_input, state, file_history],
147
+ [text_input, chatbot, steps_log]
148
  ).then(
149
  bot_response,
150
+ [chatbot, file_history, steps_log],
151
+ [chatbot, steps_log]
152
  )
153
 
154
  def clear_chat():
155
+ return [], [], ""
156
 
157
  clear_btn.click(
158
  clear_chat,
159
  None,
160
+ [chatbot, file_history, steps_log],
161
  queue=False
162
  )
163
 
agent.py CHANGED
@@ -8,35 +8,127 @@ logger = logging.getLogger(__name__)
8
 
9
  class ResearchAgent(CodeAgent):
10
  """
11
- Research-focused agent for scientific literature search and analysis.
12
- Inherits from CodeAgent and specializes in academic research tasks.
13
  """
14
 
15
  def __init__(self, model, tools, **kwargs):
16
  """
17
- Initialize the research agent.
18
-
19
- Args:
20
- model: The language model to use
21
- tools: List of available tools
22
- **kwargs: Additional arguments passed to CodeAgent
23
  """
24
  super().__init__(model=model, tools=tools, **kwargs)
25
  self.available_tools = {tool.name: tool for tool in tools}
26
- logger.info(f"ResearchAgent initialized with tools: {list(self.available_tools.keys())}")
 
 
27
 
28
- def format_research_report(self, content: Dict[str, Any]) -> str:
 
 
 
 
 
29
  """
30
- Format research results into a structured report.
31
-
32
- Args:
33
- content (Dict[str, Any]): Research content to format
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- Returns:
36
- str: Formatted research report
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  """
38
  try:
39
- # Default sections for research report
40
  sections = [
41
  "Executive Summary",
42
  "Introduction",
@@ -47,75 +139,48 @@ class ResearchAgent(CodeAgent):
47
  "References"
48
  ]
49
 
50
- # Create report header
51
  report = [
52
  "# Науковий звіт",
53
  f"*Згенеровано: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n"
54
  ]
55
 
56
- # Add each section
57
  for section in sections:
58
  section_content = content.get(section, f"Розділ {section} не надано")
59
  report.extend([
60
  f"## {section}",
61
  section_content,
62
- "" # Empty line for readability
63
  ])
64
 
65
  return "\n".join(report)
66
 
67
  except Exception as e:
68
  logger.error(f"Error formatting research report: {e}")
69
- return str(content) # Return raw content if formatting fails
70
-
71
- def update_model(self, model_config):
72
- """Update the model configuration"""
73
- try:
74
- from smolagents import HfApiModel
75
- self.model = HfApiModel(
76
- model_id=model_config['model_id'],
77
- token=os.getenv('HF_API_TOKEN'),
78
- temperature=model_config['parameters'].get('temperature', 0.7)
79
- )
80
- logger.info(f"Model updated to: {model_config['model_id']}")
81
- except Exception as e:
82
- logger.error(f"Error updating model: {e}")
83
- raise
84
 
85
  def process_query(self, query: str, available_files: Optional[List[str]] = None) -> str:
86
  """
87
- Process a research query and return formatted results.
88
-
89
- Args:
90
- query (str): The research query to process
91
- available_files (Optional[List[str]]): List of available file paths
92
-
93
- Returns:
94
- str: Formatted research results
95
  """
96
  try:
97
- logger.info(f"Processing research query: {query}")
98
 
99
- # Execute query
100
  result = self.run(
101
  task=query,
102
- stream=False, # We want complete results
103
- reset=True # Fresh start for each query
104
  )
105
 
106
- # Validate results
107
  if not result:
108
  return "Не вдалося отримати результати. Будь ласка, спробуйте переформулювати запит."
109
 
110
- # If result is already a string, return it
111
  if isinstance(result, str):
112
  return result
113
 
114
- # If result is a dict, format it as a report
115
  if isinstance(result, dict):
116
  return self.format_research_report(result)
117
 
118
- # Default case
119
  return str(result)
120
 
121
  except Exception as e:
 
8
 
9
  class ResearchAgent(CodeAgent):
10
  """
11
+ Дослідницький агент для наукового пошуку та аналізу.
 
12
  """
13
 
14
  def __init__(self, model, tools, **kwargs):
15
  """
16
+ Ініціалізація дослідницького агента.
 
 
 
 
 
17
  """
18
  super().__init__(model=model, tools=tools, **kwargs)
19
  self.available_tools = {tool.name: tool for tool in tools}
20
+ self.model_initializer = None
21
+ self.step_callback = None
22
+ logger.info(f"ResearchAgent ініціалізовано з інструментами: {list(self.available_tools.keys())}")
23
 
24
+ def _update_steps(self, step_info: str):
25
+ """Оновлення інформації про кроки"""
26
+ if self.step_callback:
27
+ self.step_callback(step_info)
28
+
29
+ def run(self, task: str, stream=False, reset=True) -> str:
30
  """
31
+ Перевизначений метод run для кращої обробки запитів.
32
+ """
33
+ try:
34
+ self._update_steps("Початок обробки запиту")
35
+
36
+ # Step 1: Web Search
37
+ self._update_steps("Пошук інформації в інтернеті")
38
+ search_results = self.available_tools['web_search'](query=task)
39
+
40
+ # Step 2: Формування запиту до моделі
41
+ prompt = (
42
+ "As a research assistant, analyze the following information and create a detailed report.\n\n"
43
+ f"Task: {task}\n\n"
44
+ f"Search Results:\n{search_results}\n\n"
45
+ "Create a comprehensive report with references to sources."
46
+ )
47
+
48
+ self._update_steps("Генерація звіту на основі знайденої інформації")
49
+ result = self.model(prompt)
50
 
51
+ self._update_steps("Форматування фінального звіту")
52
+ return result
53
+
54
+ except Exception as e:
55
+ error_msg = f"Error in run method: {str(e)}"
56
+ logger.error(error_msg)
57
+ self._update_steps(f"Помилка: {error_msg}")
58
+ return error_msg
59
+
60
+ def process_query(self, query: str, available_files: Optional[List[str]] = None) -> str:
61
+ """
62
+ Обробка дослідницького запиту.
63
+ """
64
+ try:
65
+ logger.info(f"Обробка дослідницького запиту: {query}")
66
+ self._update_steps("Початок обробки запиту")
67
+
68
+ # Виконання запиту
69
+ result = self.run(
70
+ task=query,
71
+ stream=False,
72
+ reset=True
73
+ )
74
+
75
+ if not result:
76
+ self._update_steps("Не отримано результатів")
77
+ return "Не вдалося отримати результати. Будь ласка, спробуйте переформулювати запит."
78
+
79
+ self._update_steps("Запит успішно оброблено")
80
+
81
+ if isinstance(result, str):
82
+ return result
83
+
84
+ if isinstance(result, dict):
85
+ return self.format_research_report(result)
86
+
87
+ return str(result)
88
+
89
+ except Exception as e:
90
+ error_msg = f"Помилка при обробці запиту: {str(e)}"
91
+ logger.error(error_msg)
92
+ self._update_steps(f"Помилка: {error_msg}")
93
+ return error_msg
94
+ """
95
+ Дослідницький агент для наукового пошуку та аналізу.
96
+ """
97
+
98
+ def __init__(self, model, tools, **kwargs):
99
+ """
100
+ Ініціалізація дослідницького агента.
101
+ """
102
+ super().__init__(model=model, tools=tools, **kwargs)
103
+ self.available_tools = {tool.name: tool for tool in tools}
104
+ self.model_initializer = None
105
+ logger.info(f"ResearchAgent ініціалізовано з інструментами: {list(self.available_tools.keys())}")
106
+
107
+ def run(self, task: str, stream=False, reset=True) -> str:
108
+ """
109
+ Перевизначений метод run для кращої обробки запитів.
110
+ """
111
+ try:
112
+ # Формуємо простий текстовий запит
113
+ prompt = (
114
+ "You are a research assistant. Your task is to:\n"
115
+ f"{task}\n\n"
116
+ "Provide a detailed response."
117
+ )
118
+ logger.info(f"Sending prompt to model: {prompt[:100]}...")
119
+
120
+ result = self.model(prompt)
121
+ return result
122
+
123
+ except Exception as e:
124
+ logger.error(f"Error in run method: {str(e)}")
125
+ return f"Error processing request: {str(e)}"
126
+
127
+ def format_research_report(self, content: Dict[str, Any]) -> str:
128
+ """
129
+ Форматування результатів у звіт.
130
  """
131
  try:
 
132
  sections = [
133
  "Executive Summary",
134
  "Introduction",
 
139
  "References"
140
  ]
141
 
 
142
  report = [
143
  "# Науковий звіт",
144
  f"*Згенеровано: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n"
145
  ]
146
 
 
147
  for section in sections:
148
  section_content = content.get(section, f"Розділ {section} не надано")
149
  report.extend([
150
  f"## {section}",
151
  section_content,
152
+ ""
153
  ])
154
 
155
  return "\n".join(report)
156
 
157
  except Exception as e:
158
  logger.error(f"Error formatting research report: {e}")
159
+ return str(content)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  def process_query(self, query: str, available_files: Optional[List[str]] = None) -> str:
162
  """
163
+ Обробка дослідницького запиту.
 
 
 
 
 
 
 
164
  """
165
  try:
166
+ logger.info(f"Обробка дослідницького запиту: {query}")
167
 
168
+ # Виконання запиту
169
  result = self.run(
170
  task=query,
171
+ stream=False,
172
+ reset=True
173
  )
174
 
 
175
  if not result:
176
  return "Не вдалося отримати результати. Будь ласка, спробуйте переформулювати запит."
177
 
 
178
  if isinstance(result, str):
179
  return result
180
 
 
181
  if isinstance(result, dict):
182
  return self.format_research_report(result)
183
 
 
184
  return str(result)
185
 
186
  except Exception as e:
app.py CHANGED
@@ -1,15 +1,15 @@
1
- from smolagents import HfApiModel
2
  from tools.web_search import DuckDuckGoSearchTool
3
  from tools.final_answer import FinalAnswerTool
4
  from tools.healthcare_llm_visualizer import HealthcareLLMVisualizerTool
5
  from Gradio_UI import GradioUI
6
  from agent import ResearchAgent
 
7
  import os
8
  from dotenv import load_dotenv
9
  import logging
10
- from config import ModelConfig
11
 
12
- # Configure logging
13
  logging.basicConfig(
14
  level=logging.INFO,
15
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
@@ -20,12 +20,12 @@ logging.basicConfig(
20
  )
21
  logger = logging.getLogger(__name__)
22
 
23
- # Load environment variables
24
  load_dotenv()
25
 
26
  def initialize_tools():
27
- """Initialize all available tools with proper configuration"""
28
- logger.info("Initializing tools...")
29
  try:
30
  tools = [
31
  DuckDuckGoSearchTool(
@@ -34,50 +34,51 @@ def initialize_tools():
34
  FinalAnswerTool(),
35
  HealthcareLLMVisualizerTool()
36
  ]
37
- logger.info("Tools initialized successfully")
38
  return tools
39
  except Exception as e:
40
- logger.error(f"Error initializing tools: {e}")
41
  raise
42
 
43
- def initialize_model():
44
- """Initialize the language model"""
45
- logger.info("Initializing language model...")
46
  try:
47
- model_config = ModelConfig()
48
- default_model = model_config.get_model_config()
 
49
 
50
- model = HfApiModel(
51
- model_id=default_model['model_id'],
52
- token=os.getenv('HF_API_TOKEN'),
53
- temperature=default_model['parameters'].get('temperature', 0.7),
54
- max_tokens=default_model['parameters'].get('max_tokens', 2048)
55
- )
56
- logger.info(f"Model initialized: {default_model['model_id']}")
57
- return model
58
  except Exception as e:
59
- logger.error(f"Error initializing model: {e}")
60
  raise
61
 
62
  def main():
63
- """Main application entry point"""
64
  try:
65
- logger.info("Starting Research Agent application...")
66
 
67
- # Initialize components
68
  tools = initialize_tools()
69
- model = initialize_model()
70
 
71
- # Initialize research agent with increased max_steps
72
  agent = ResearchAgent(
73
  model=model,
74
  tools=tools,
75
- max_steps=int(os.getenv('MAX_STEPS', 10)), # Increased from 6 to 10
76
  verbosity_level=int(os.getenv('VERBOSITY_LEVEL', 1))
77
  )
78
 
79
- # Launch UI
80
- logger.info("Launching Gradio interface...")
 
 
 
81
  ui = GradioUI(agent)
82
  ui.launch(
83
  debug=os.getenv('DEBUG_MODE', 'False').lower() == 'true',
@@ -87,7 +88,7 @@ def main():
87
  )
88
 
89
  except Exception as e:
90
- logger.error(f"Application startup failed: {e}")
91
  raise
92
 
93
  if __name__ == "__main__":
 
 
1
  from tools.web_search import DuckDuckGoSearchTool
2
  from tools.final_answer import FinalAnswerTool
3
  from tools.healthcare_llm_visualizer import HealthcareLLMVisualizerTool
4
  from Gradio_UI import GradioUI
5
  from agent import ResearchAgent
6
+ from model_init import ModelInitializer # Новий імпорт
7
  import os
8
  from dotenv import load_dotenv
9
  import logging
10
+ from pathlib import Path
11
 
12
+ # Налаштування логування
13
  logging.basicConfig(
14
  level=logging.INFO,
15
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
 
20
  )
21
  logger = logging.getLogger(__name__)
22
 
23
+ # Завантаження змінних середовища
24
  load_dotenv()
25
 
26
  def initialize_tools():
27
+ """Ініціалізація всіх доступних інструментів"""
28
+ logger.info("Ініціалізація інструментів...")
29
  try:
30
  tools = [
31
  DuckDuckGoSearchTool(
 
34
  FinalAnswerTool(),
35
  HealthcareLLMVisualizerTool()
36
  ]
37
+ logger.info("Інструменти успішно ініціалізовано")
38
  return tools
39
  except Exception as e:
40
+ logger.error(f"Помилка ініціалізації інструментів: {e}")
41
  raise
42
 
43
+ def initialize_model(model_key=None):
44
+ """Ініціалізація моделі"""
45
+ logger.info("Ініціалізація мовної моделі...")
46
  try:
47
+ config_path = Path("models_config.json")
48
+ model_initializer = ModelInitializer(config_path)
49
+ model = model_initializer.initialize_model(model_key)
50
 
51
+ if model_key:
52
+ logger.info(f"Модель ініціалізовано: {model_key}")
53
+ else:
54
+ logger.info("Ініціалізовано модель за замовчуванням")
55
+ return model, model_initializer
 
 
 
56
  except Exception as e:
57
+ logger.error(f"Помилка ініціалізації моделі: {e}")
58
  raise
59
 
60
  def main():
61
+ """Головна точка входу в програму"""
62
  try:
63
+ logger.info("Запуск Research Agent...")
64
 
65
+ # Ініціалізація компонентів
66
  tools = initialize_tools()
67
+ model, model_initializer = initialize_model()
68
 
69
+ # Ініціалізація дослідницького агента
70
  agent = ResearchAgent(
71
  model=model,
72
  tools=tools,
73
+ max_steps=int(os.getenv('MAX_STEPS', 10)),
74
  verbosity_level=int(os.getenv('VERBOSITY_LEVEL', 1))
75
  )
76
 
77
+ # Додавання model_initializer до агента для можливості зміни моделі
78
+ agent.model_initializer = model_initializer
79
+
80
+ # Запуск інтерфейсу
81
+ logger.info("Запуск Gradio інтерфейсу...")
82
  ui = GradioUI(agent)
83
  ui.launch(
84
  debug=os.getenv('DEBUG_MODE', 'False').lower() == 'true',
 
88
  )
89
 
90
  except Exception as e:
91
+ logger.error(f"Помилка запуску програми: {e}")
92
  raise
93
 
94
  if __name__ == "__main__":
config.py DELETED
@@ -1,112 +0,0 @@
1
- import json
2
- from pathlib import Path
3
-
4
- class ModelConfig:
5
- def __init__(self, config_path='models_config.json'): # Changed path
6
- self.config_path = Path(config_path)
7
- self.ensure_config_exists()
8
- self.load_config()
9
-
10
- def ensure_config_exists(self):
11
- """Ensure config file exists"""
12
- if not self.config_path.exists():
13
- default_config = {
14
- "models": {
15
- "deepseek-r1": {
16
- "model_id": "deepseek-ai/DeepSeek-R1",
17
- "description": "Найбільш рейтингова модель за кількістю лайків",
18
- "likes": 8659,
19
- "downloads": 3468420,
20
- "parameters": {
21
- "max_tokens": 2048,
22
- "temperature": 0.7,
23
- "top_p": 0.95,
24
- "frequency_penalty": 0.0,
25
- "presence_penalty": 0.0
26
- },
27
- "recommended_use": ["складні дослідницькі завдання", "аналітика", "генерація тексту"]
28
- },
29
- "llama-3-instruct": {
30
- "model_id": "meta-llama/Llama-3.1-8B-Instruct",
31
- "description": "Потужна інструктивна модель від Meta",
32
- "likes": 3612,
33
- "downloads": 6035070,
34
- "parameters": {
35
- "max_tokens": 4096,
36
- "temperature": 0.8,
37
- "top_p": 0.9,
38
- "frequency_penalty": 0.0,
39
- "presence_penalty": 0.0
40
- },
41
- "recommended_use": ["діалоги", "інструкції", "навчальні матеріали"]
42
- },
43
- "mistral-instruct": {
44
- "model_id": "mistralai/Mistral-7B-Instruct-v0.2",
45
- "description": "Оптимізована інструктивна модель",
46
- "likes": 2650,
47
- "downloads": 3415777,
48
- "parameters": {
49
- "max_tokens": 2048,
50
- "temperature": 0.3,
51
- "top_p": 0.9,
52
- "frequency_penalty": 0.0,
53
- "presence_penalty": 0.0
54
- },
55
- "recommended_use": ["наукові дослідження", "структуровані відповіді"]
56
- },
57
- "gpt2": {
58
- "model_id": "openai-community/gpt2",
59
- "description": "Найбільш завантажувана модель",
60
- "likes": 2565,
61
- "downloads": 18299067,
62
- "parameters": {
63
- "max_tokens": 1024,
64
- "temperature": 0.9,
65
- "top_p": 0.9,
66
- "frequency_penalty": 0.0,
67
- "presence_penalty": 0.0
68
- },
69
- "recommended_use": ["базова генерація тексту", "прості завдання"]
70
- },
71
- "llama-3-1b": {
72
- "model_id": "meta-llama/Llama-3.2-1B",
73
- "description": "Легка версія Llama 3",
74
- "likes": 1559,
75
- "downloads": 8244484,
76
- "parameters": {
77
- "max_tokens": 2048,
78
- "temperature": 0.8,
79
- "top_p": 0.9,
80
- "frequency_penalty": 0.0,
81
- "presence_penalty": 0.0
82
- },
83
- "recommended_use": ["швидкі відповіді", "базова генерація"]
84
- }
85
- },
86
- "default_model": "mistral-instruct",
87
- "model_selection_criteria": {
88
- "research": ["deepseek-r1", "mistral-instruct", "llama-3-instruct"],
89
- "general": ["gpt2", "llama-3-1b"],
90
- "instruction": ["mistral-instruct", "llama-3-instruct"]
91
- }
92
- }
93
- self.config_path.write_text(json.dumps(default_config, indent=4, ensure_ascii=False))
94
-
95
- def load_config(self):
96
- """Load configuration from file"""
97
- self.config = json.loads(self.config_path.read_text())
98
-
99
- def get_model_config(self, model_key=None):
100
- """Get configuration for specific model or default model"""
101
- if model_key is None:
102
- model_key = self.config['default_model']
103
- return self.config['models'].get(model_key)
104
-
105
- def get_available_models(self):
106
- """Get list of available models"""
107
- return [(key, model['description'])
108
- for key, model in self.config['models'].items()]
109
-
110
- def get_default_model(self):
111
- """Get default model key"""
112
- return self.config['default_model']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model_init.py ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional, Dict, Any
2
+ import os
3
+ import google.generativeai as genai
4
+ from huggingface_hub import HfApi
5
+ import logging
6
+ from smolagents import HfApiModel
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class ModelWrapper:
11
+ """Спрощена обгортка для моделей"""
12
+
13
+ def __init__(self, model, model_type):
14
+ self.model = model
15
+ self.model_type = model_type
16
+
17
+ def __call__(self, prompt, **kwargs):
18
+ try:
19
+ if self.model_type == 'gemini':
20
+ # Якщо prompt - це словник з роллю і контентом
21
+ if isinstance(prompt, dict) and 'content' in prompt:
22
+ text = prompt['content']
23
+ # Якщо prompt - це список повідомлень
24
+ elif isinstance(prompt, list):
25
+ # Беремо останнє повідомлення
26
+ last_message = prompt[-1]
27
+ text = last_message.get('content', '') if isinstance(last_message, dict) else str(last_message)
28
+ else:
29
+ text = str(prompt)
30
+
31
+ logger.info(f"Prompt для Gemini: {text[:100]}...")
32
+ response = self.model.generate_content(text)
33
+ return response.text
34
+ else:
35
+ kwargs.pop('stop_sequences', None) # Видаляємо stop_sequences для HF моделей
36
+ return self.model(prompt, **kwargs)
37
+
38
+ except Exception as e:
39
+ logger.error(f"Помилка ModelWrapper: {str(e)}")
40
+ logger.error(f"Тип prompt: {type(prompt)}")
41
+ logger.error(f"Prompt: {str(prompt)[:200]}")
42
+ raise
43
+ """Обгортка для уніфікації інтерфейсу різних моделей"""
44
+
45
+ def __init__(self, model, model_type):
46
+ self.model = model
47
+ self.model_type = model_type
48
+
49
+ def _extract_text_from_input(self, input_data):
50
+ """Витягує текст з різних форматів вхідних даних"""
51
+ try:
52
+ if isinstance(input_data, str):
53
+ return input_data
54
+
55
+ elif isinstance(input_data, list):
56
+ # Обробка списку повідомлень
57
+ messages = []
58
+ for msg in input_data:
59
+ if isinstance(msg, dict):
60
+ # Витягуємо контент з повідомлення
61
+ content = msg.get('content', '')
62
+ if isinstance(content, list):
63
+ # Якщо контент - список, обробляємо кожен елемент
64
+ for item in content:
65
+ if isinstance(item, dict) and 'text' in item:
66
+ messages.append(item['text'])
67
+ else:
68
+ messages.append(str(item))
69
+ else:
70
+ messages.append(str(content))
71
+ else:
72
+ messages.append(str(msg))
73
+ return ' '.join(messages)
74
+
75
+ elif isinstance(input_data, dict):
76
+ # Обробка одиночного повідомлення
77
+ content = input_data.get('content', '')
78
+ if isinstance(content, list):
79
+ return ' '.join(item.get('text', str(item)) for item in content if isinstance(item, dict))
80
+ return str(content)
81
+
82
+ return str(input_data)
83
+
84
+ except Exception as e:
85
+ logger.error(f"Помилка при обробці вхідних даних: {e}")
86
+ logger.error(f"Тип даних: {type(input_data)}")
87
+ logger.error(f"Дані: {str(input_data)[:200]}")
88
+ return str(input_data)
89
+
90
+ def __call__(self, prompt: str, **kwargs) -> str:
91
+ """
92
+ Виклик моделі з підтримкою додаткових параметрів.
93
+
94
+ Args:
95
+ prompt: Текст запиту
96
+ **kwargs: Додаткові параметри (ігноруються для Gemini)
97
+ """
98
+ try:
99
+ if self.model_type == 'gemini':
100
+ # Для Gemini ігноруємо додаткові параметри і просто передаємо текст
101
+ text = self._extract_text_from_input(prompt)
102
+ logger.info(f"Gemini отримав запит: {text[:200]}...") # Логуємо перші 200 символів
103
+
104
+ response = self.model.generate_content(text)
105
+
106
+ if response and hasattr(response, 'text'):
107
+ logger.info("Gemini успішно згенерував відповідь")
108
+ return response.text
109
+ else:
110
+ error_msg = "Gemini повернув порожню або неправильну відповідь"
111
+ logger.error(error_msg)
112
+ raise ValueError(error_msg)
113
+ else: # huggingface model
114
+ # Видаляємо stop_sequences, якщо він є
115
+ kwargs.pop('stop_sequences', None)
116
+ return self.model(prompt, **kwargs)
117
+ except Exception as e:
118
+ logger.error(f"Помилка при виклику моделі {self.model_type}: {e}")
119
+ logger.error(f"Тип вхідних даних: {type(prompt)}")
120
+ logger.error(f"Вміст вхідних даних: {str(prompt)[:200]}")
121
+ raise
122
+ """Обгортка для уніфікації інтерфейсу різних моделей"""
123
+
124
+ def __init__(self, model, model_type):
125
+ self.model = model
126
+ self.model_type = model_type
127
+
128
+ def _extract_text_from_input(self, input_data):
129
+ """Витягує текст з різних форматів вхідних даних"""
130
+ if isinstance(input_data, str):
131
+ return input_data
132
+ elif isinstance(input_data, dict):
133
+ return input_data.get('content', str(input_data))
134
+ elif isinstance(input_data, list):
135
+ return ' '.join(self._extract_text_from_input(item) for item in input_data)
136
+ return str(input_data)
137
+
138
+ def __call__(self, prompt: str, **kwargs) -> str:
139
+ """
140
+ Виклик моделі з підтримкою додаткових параметрів.
141
+
142
+ Args:
143
+ prompt: Текст запиту
144
+ **kwargs: Додаткові параметри (ігноруються для Gemini)
145
+ """
146
+ try:
147
+ if self.model_type == 'gemini':
148
+ # Для Gemini ігноруємо додаткові параметри і просто передаємо текст
149
+ text = self._extract_text_from_input(prompt)
150
+ logger.info(f"Gemini отримав запит: {text[:200]}...") # Логуємо перші 200 символів
151
+
152
+ response = self.model.generate_content(text)
153
+
154
+ if response and hasattr(response, 'text'):
155
+ logger.info("Gemini успішно згенерував відповідь")
156
+ return response.text
157
+ else:
158
+ error_msg = "Gemini повернув порожню або неправильну відповідь"
159
+ logger.error(error_msg)
160
+ raise ValueError(error_msg)
161
+ else: # huggingface model
162
+ # Видаляємо stop_sequences, якщо він є
163
+ kwargs.pop('stop_sequences', None)
164
+ return self.model(prompt, **kwargs)
165
+ except Exception as e:
166
+ logger.error(f"Помилка при виклику моделі {self.model_type}: {e}")
167
+ logger.error(f"Тип вхідних даних: {type(prompt)}")
168
+ logger.error(f"Вміст вхідних даних: {str(prompt)[:200]}") # Логуємо перші 200 символів
169
+ raise
170
+
171
+ class ModelInitializer:
172
+ def __init__(self, config_path: str = 'models_config.json'):
173
+ self.config = self._load_config(config_path)
174
+ self._setup_api_keys()
175
+
176
+ def _setup_api_keys(self):
177
+ """Налаштування API ключів"""
178
+ self.hf_api_token = os.getenv('HF_API_TOKEN')
179
+ self.gemini_api_key = os.getenv('GEMINI_API_KEY')
180
+ if self.gemini_api_key:
181
+ genai.configure(api_key=self.gemini_api_key)
182
+ logger.info("API ключ Gemini успішно налаштовано")
183
+ else:
184
+ logger.warning("API ключ Gemini не знайдено")
185
+
186
+ def _load_config(self, config_path: str) -> Dict[str, Any]:
187
+ """Завантаження конфігурації моделей"""
188
+ import json
189
+ try:
190
+ with open(config_path, 'r', encoding='utf-8') as f:
191
+ config = json.load(f)
192
+ logger.info(f"Конфігурацію успішно завантажено з {config_path}")
193
+ return config
194
+ except Exception as e:
195
+ logger.error(f"Помилка завантаження конфігурації: {e}")
196
+ raise
197
+
198
+ def initialize_model(self, model_key: Optional[str] = None) -> Any:
199
+ """Ініціалізація вибраної моделі"""
200
+ try:
201
+ if model_key is None:
202
+ model_key = self.config['default_model']
203
+ logger.info(f"Використовуємо модель за замовчуванням: {model_key}")
204
+
205
+ model_config = self.config['models'].get(model_key)
206
+ if not model_config:
207
+ error_msg = f"Модель {model_key} не знайдена в конфігурації"
208
+ logger.error(error_msg)
209
+ raise ValueError(error_msg)
210
+
211
+ if model_key == 'gemini-flash':
212
+ model = self._initialize_gemini(model_config)
213
+ logger.info("Ініціалізовано Gemini модель")
214
+ return ModelWrapper(model, 'gemini')
215
+ else:
216
+ model = self._initialize_huggingface(model_config)
217
+ logger.info("Ініціалізовано HuggingFace модель")
218
+ return ModelWrapper(model, 'huggingface')
219
+ except Exception as e:
220
+ error_msg = f"Помилка ініціалізації моделі: {e}"
221
+ logger.error(error_msg)
222
+ raise ValueError(error_msg)
223
+
224
+ def _initialize_gemini(self, config: Dict[str, Any]) -> Any:
225
+ """Ініціалізація Gemini моделі"""
226
+ if not self.gemini_api_key:
227
+ raise ValueError("GEMINI_API_KEY не знайдено в змінних середовища")
228
+
229
+ try:
230
+ # Налаштування безпеки (вимикаємо всі обмеження для наукових досліджень)
231
+ safety_settings = [
232
+ {
233
+ "category": "HARM_CATEGORY_HARASSMENT",
234
+ "threshold": "BLOCK_NONE"
235
+ },
236
+ {
237
+ "category": "HARM_CATEGORY_HATE_SPEECH",
238
+ "threshold": "BLOCK_NONE"
239
+ },
240
+ {
241
+ "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
242
+ "threshold": "BLOCK_NONE"
243
+ },
244
+ {
245
+ "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
246
+ "threshold": "BLOCK_NONE"
247
+ }
248
+ ]
249
+
250
+ # Створюємо модель з мінімальними обмеженнями
251
+ model = genai.GenerativeModel(
252
+ model_name='gemini-pro',
253
+ safety_settings=safety_settings
254
+ )
255
+
256
+ # Тестуємо модель
257
+ try:
258
+ logger.info("Тестування з'єднання з Gemini...")
259
+ test_response = model.generate_content("Test connection")
260
+ if test_response and hasattr(test_response, 'text'):
261
+ logger.info("Gemini модель успішно ініціалізовано та протестовано")
262
+ return model
263
+ else:
264
+ raise ValueError("Тестова генерація не повернула текст")
265
+ except Exception as e:
266
+ raise ValueError(f"Помилка тестування Gemini: {str(e)}")
267
+
268
+ except Exception as e:
269
+ error_msg = f"Помилка ініціалізації Gemini: {str(e)}"
270
+ logger.error(error_msg)
271
+ raise ValueError(error_msg)
272
+
273
+ def _initialize_huggingface(self, config: Dict[str, Any]) -> Any:
274
+ """Ініціалізація Hugging Face моделі"""
275
+ if not self.hf_api_token:
276
+ raise ValueError("HF_API_TOKEN не знайдено в змінних середовища")
277
+
278
+ try:
279
+ model = HfApiModel(
280
+ model_id=config['model_id'],
281
+ token=self.hf_api_token,
282
+ temperature=config['parameters']['temperature'],
283
+ max_tokens=config['parameters']['max_tokens']
284
+ )
285
+
286
+ return model
287
+ except Exception as e:
288
+ error_msg = f"Помилка ініціалізації HuggingFace: {str(e)}"
289
+ logger.error(error_msg)
290
+ raise ValueError(error_msg)
291
+
292
+ def get_available_models(self) -> list:
293
+ """Отримання списку доступних моделей"""
294
+ return [(key, model['description'])
295
+ for key, model in self.config['models'].items()]
models_config.json CHANGED
@@ -1,80 +1,30 @@
1
  {
2
  "models": {
3
- "deepseek-r1": {
4
- "model_id": "deepseek-ai/DeepSeek-R1",
5
- "description": "Найбільш рейтингова модель за кількістю лайків",
6
- "likes": 8659,
7
- "downloads": 3468420,
8
  "parameters": {
9
- "max_tokens": 2048,
10
- "temperature": 0.7,
11
  "top_p": 0.95,
12
- "frequency_penalty": 0.0,
13
- "presence_penalty": 0.0
14
- },
15
- "recommended_use": ["складні дослідницькі завдання", "аналітика", "генерація тексту"]
16
- },
17
- "llama-3-instruct": {
18
- "model_id": "meta-llama/Llama-3.1-8B-Instruct",
19
- "description": "Потужна інструктивна модель від Meta",
20
- "likes": 3612,
21
- "downloads": 6035070,
22
- "parameters": {
23
- "max_tokens": 4096,
24
- "temperature": 0.8,
25
- "top_p": 0.9,
26
- "frequency_penalty": 0.0,
27
- "presence_penalty": 0.0
28
- },
29
- "recommended_use": ["діалоги", "інструкції", "навчальні матеріали"]
30
  },
31
  "mistral-instruct": {
32
  "model_id": "mistralai/Mistral-7B-Instruct-v0.2",
33
  "description": "Оптимізована інструктивна модель",
34
- "likes": 2650,
35
- "downloads": 3415777,
36
  "parameters": {
37
  "max_tokens": 2048,
38
  "temperature": 0.3,
39
  "top_p": 0.9,
40
  "frequency_penalty": 0.0,
41
  "presence_penalty": 0.0
42
- },
43
- "recommended_use": ["наукові дослідження", "структуровані відповіді"]
44
- },
45
- "gpt2": {
46
- "model_id": "openai-community/gpt2",
47
- "description": "Найбільш завантажувана модель",
48
- "likes": 2565,
49
- "downloads": 18299067,
50
- "parameters": {
51
- "max_tokens": 1024,
52
- "temperature": 0.9,
53
- "top_p": 0.9,
54
- "frequency_penalty": 0.0,
55
- "presence_penalty": 0.0
56
- },
57
- "recommended_use": ["базова генерація тексту", "прості завдання"]
58
- },
59
- "llama-3-1b": {
60
- "model_id": "meta-llama/Llama-3.2-1B",
61
- "description": "Легка версія Llama 3",
62
- "likes": 1559,
63
- "downloads": 8244484,
64
- "parameters": {
65
- "max_tokens": 2048,
66
- "temperature": 0.8,
67
- "top_p": 0.9,
68
- "frequency_penalty": 0.0,
69
- "presence_penalty": 0.0
70
- },
71
- "recommended_use": ["швидкі відповіді", "базова генерація"]
72
  }
73
  },
74
- "default_model": "mistral-instruct",
75
  "model_selection_criteria": {
76
- "research": ["deepseek-r1", "mistral-instruct", "llama-3-instruct"],
77
- "general": ["gpt2", "llama-3-1b"],
78
- "instruction": ["mistral-instruct", "llama-3-instruct"]
79
  }
80
  }
 
1
  {
2
  "models": {
3
+ "gemini-flash": {
4
+ "model_id": "gemini-pro",
5
+ "description": "Швидка та потужна модель від Google",
 
 
6
  "parameters": {
7
+ "max_tokens": 8192,
8
+ "temperature": 1.0,
9
  "top_p": 0.95,
10
+ "top_k": 40
11
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  },
13
  "mistral-instruct": {
14
  "model_id": "mistralai/Mistral-7B-Instruct-v0.2",
15
  "description": "Оптимізована інструктивна модель",
 
 
16
  "parameters": {
17
  "max_tokens": 2048,
18
  "temperature": 0.3,
19
  "top_p": 0.9,
20
  "frequency_penalty": 0.0,
21
  "presence_penalty": 0.0
22
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
  },
25
+ "default_model": "gemini-flash",
26
  "model_selection_criteria": {
27
+ "research": ["gemini-flash", "mistral-instruct"],
28
+ "instruction": ["gemini-flash", "mistral-instruct"]
 
29
  }
30
  }
requirements.txt CHANGED
@@ -6,4 +6,5 @@ duckduckgo-search>=3.0.0
6
  markdownify>=0.11.0
7
  requests>=2.28.0
8
  pandas>=1.3.0
9
- numpy>=1.21.0
 
 
6
  markdownify>=0.11.0
7
  requests>=2.28.0
8
  pandas>=1.3.0
9
+ numpy>=1.21.0
10
+ google-generativeai>=0.3.0
test_gemini.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import google.generativeai as genai
3
+ from dotenv import load_dotenv
4
+ import logging
5
+
6
+ # Налаштування логування
7
+ logging.basicConfig(level=logging.INFO)
8
+ logger = logging.getLogger(__name__)
9
+
10
+ def test_gemini():
11
+ try:
12
+ # Завантаження API ключа
13
+ load_dotenv()
14
+ api_key = os.getenv('GEMINI_API_KEY')
15
+ if not api_key:
16
+ raise ValueError("GEMINI_API_KEY не знайдено")
17
+
18
+ # Конфігурація Gemini
19
+ genai.configure(api_key=api_key)
20
+
21
+ # Створення моделі
22
+ model = genai.GenerativeModel('gemini-pro')
23
+
24
+ # Тестовий запит
25
+ prompt = "What is 2+2? Answer in one word."
26
+ logger.info(f"Sending test prompt: {prompt}")
27
+
28
+ # Генерація відповіді
29
+ response = model.generate_content(prompt)
30
+
31
+ if response and hasattr(response, 'text'):
32
+ logger.info(f"Response received: {response.text}")
33
+ return True
34
+ else:
35
+ logger.error("No valid response received")
36
+ return False
37
+
38
+ except Exception as e:
39
+ logger.error(f"Error testing Gemini: {str(e)}")
40
+ return False
41
+
42
+ if __name__ == "__main__":
43
+ print("Testing Gemini connection...")
44
+ if test_gemini():
45
+ print("Test successful!")
46
+ else:
47
+ print("Test failed!")