This is page 15 of 20. Use http://codebase.md/fujitsu-ai/mcp-server-for-mas-developments?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .gitattributes ├── .gitignore ├── agents │ ├── __init__.py │ ├── AgentInterface │ │ ├── __init__.py │ │ ├── Python │ │ │ ├── __init__.py │ │ │ ├── agent.py │ │ │ ├── color.py │ │ │ ├── config.py │ │ │ ├── language.py │ │ │ ├── local_file_handler.py │ │ │ └── network.py │ │ └── requirements.txt │ ├── AgentMonitoring │ │ ├── ChatBot-Agent Dashboard Example - Grafana.json │ │ ├── images │ │ │ ├── Grafana.png │ │ │ └── Prometheus.png │ │ ├── IoT-Agent Dashboard Example - Grafana.json │ │ ├── OpenAI compatible API - Agent Dashboard Example - Grafana.json │ │ ├── prometheus Example.yml │ │ └── README.md │ ├── ChatBotAgent │ │ ├── __init__.py │ │ ├── config.json.example │ │ ├── html │ │ │ ├── favicon.ico │ │ │ ├── index_de.html │ │ │ ├── index.html │ │ │ ├── Logo_light.svg │ │ │ ├── start_http_server.ps1 │ │ │ └── start_http_server.sh │ │ ├── Python │ │ │ ├── __init__.py │ │ │ └── chatbot_agent.py │ │ ├── README.md │ │ └── requirements.txt │ ├── IoTAgent │ │ ├── config_example.json │ │ ├── Python │ │ │ ├── iot_mqtt_agent.py │ │ │ └── language.py │ │ ├── README.md │ │ └── requirements.txt │ ├── MCP-Client │ │ ├── __init__.py │ │ ├── .env.example │ │ ├── Python │ │ │ ├── __init__.py │ │ │ ├── chat_handler.py │ │ │ ├── config.py │ │ │ ├── environment.py │ │ │ ├── llm_client.py │ │ │ ├── mcp_client_sse.py │ │ │ ├── mcp_client.py │ │ │ ├── messages │ │ │ │ ├── __init__.py │ │ │ │ ├── message_types │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── incrementing_id_message.py │ │ │ │ │ ├── initialize_message.py │ │ │ │ │ ├── json_rpc_message.py │ │ │ │ │ ├── ping_message.py │ │ │ │ │ ├── prompts_messages.py │ │ │ │ │ ├── prompts_models.py │ │ │ │ │ ├── resources_messages.py │ │ │ │ │ └── tools_messages.py │ │ │ │ ├── send_call_tool.py │ │ │ │ ├── send_initialize_message.py │ │ │ │ ├── send_message.py │ │ │ │ ├── send_ping.py │ │ │ │ ├── send_prompts.py │ │ │ │ ├── send_resources.py │ │ │ │ └── send_tools_list.py │ │ │ ├── system_prompt_generator.py │ │ │ ├── tools_handler.py │ │ │ └── transport │ │ │ ├── __init__.py │ │ │ └── stdio │ │ │ ├── __init__.py │ │ │ ├── stdio_client.py │ │ │ ├── stdio_server_parameters.py │ │ │ └── stdio_server_shutdown.py │ │ ├── README.md │ │ ├── requirements.txt │ │ └── server_config.json │ ├── OpenAI_Compatible_API_Agent │ │ ├── __init__.py │ │ ├── docker-compose.yml │ │ ├── Dockerfile │ │ ├── pgpt_openai_api_mcp.json.example │ │ ├── pgpt_openai_api_proxy.json.example │ │ ├── Python │ │ │ ├── __init__.py │ │ │ ├── client_tests │ │ │ │ ├── __init__.py │ │ │ │ ├── openai_test_client_structured.py │ │ │ │ ├── openai_test_client_tools.py │ │ │ │ ├── openai_test_client.py │ │ │ │ ├── vllm_client_multimodal.py │ │ │ │ ├── vllm_client.py │ │ │ │ ├── vllm_structured.py │ │ │ │ └── vllm_structured2.py │ │ │ ├── generate_api_key.py │ │ │ ├── open_ai_helper.py │ │ │ ├── openai_compatible_api.py │ │ │ ├── openai_mcp_api.py │ │ │ ├── pgpt_api.py │ │ │ ├── privategpt_api.py │ │ │ └── vllmproxy.py │ │ ├── README.md │ │ └── requirements.txt │ └── SourceManagerAgent │ ├── __init__.py │ ├── config.json.example │ └── Python │ ├── __init__.py │ ├── file_tools │ │ └── loader_factory.py │ ├── file_upload_agent.py │ └── local_db.py ├── clients │ ├── __init__.py │ ├── C# .Net │ │ ├── 1.0 mcp_login │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_login.deps.json │ │ │ │ ├── mcp_login.dll │ │ │ │ ├── mcp_login.exe │ │ │ │ ├── mcp_login.pdb │ │ │ │ ├── mcp_login.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_login.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_login.AssemblyInfo.cs │ │ │ │ │ ├── mcp_login.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_login.assets.cache │ │ │ │ │ ├── mcp_login.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_login.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_login.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_login.csproj.Up2Date │ │ │ │ │ ├── mcp_login.dll │ │ │ │ │ ├── mcp_login.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_login.genruntimeconfig.cache │ │ │ │ │ ├── mcp_login.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_login.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_login.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_login.dll │ │ │ │ ├── mcp_login.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_login.csproj.nuget.g.props │ │ │ │ ├── mcp_login.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 1.1 mcp_logout │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_logout.deps.json │ │ │ │ ├── mcp_logout.dll │ │ │ │ ├── mcp_logout.exe │ │ │ │ ├── mcp_logout.pdb │ │ │ │ ├── mcp_logout.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_logout.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_logout.AssemblyInfo.cs │ │ │ │ │ ├── mcp_logout.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_logout.assets.cache │ │ │ │ │ ├── mcp_logout.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_logout.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_logout.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_logout.csproj.Up2Date │ │ │ │ │ ├── mcp_logout.dll │ │ │ │ │ ├── mcp_logout.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_logout.genruntimeconfig.cache │ │ │ │ │ ├── mcp_logout.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_logout.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_logout.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_logout.dll │ │ │ │ ├── mcp_logout.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_logout.csproj.nuget.g.props │ │ │ │ ├── mcp_logout.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 2.0 mcp_chat │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_chat.deps.json │ │ │ │ ├── mcp_chat.dll │ │ │ │ ├── mcp_chat.exe │ │ │ │ ├── mcp_chat.pdb │ │ │ │ ├── mcp_chat.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_chat.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_chat.AssemblyInfo.cs │ │ │ │ │ ├── mcp_chat.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_chat.assets.cache │ │ │ │ │ ├── mcp_chat.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_chat.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_chat.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_chat.csproj.Up2Date │ │ │ │ │ ├── mcp_chat.dll │ │ │ │ │ ├── mcp_chat.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_chat.genruntimeconfig.cache │ │ │ │ │ ├── mcp_chat.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_chat.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_chat.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_chat.dll │ │ │ │ ├── mcp_chat.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_chat.csproj.nuget.g.props │ │ │ │ ├── mcp_chat.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 2.1 mcp_continue_chat │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_continue_chat.deps.json │ │ │ │ ├── mcp_continue_chat.dll │ │ │ │ ├── mcp_continue_chat.exe │ │ │ │ ├── mcp_continue_chat.pdb │ │ │ │ ├── mcp_continue_chat.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_continue_chat.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_cont.EF178231.Up2Date │ │ │ │ │ ├── mcp_continue_chat.AssemblyInfo.cs │ │ │ │ │ ├── mcp_continue_chat.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_continue_chat.assets.cache │ │ │ │ │ ├── mcp_continue_chat.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_continue_chat.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_continue_chat.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_continue_chat.dll │ │ │ │ │ ├── mcp_continue_chat.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_continue_chat.genruntimeconfig.cache │ │ │ │ │ ├── mcp_continue_chat.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_continue_chat.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_continue_chat.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_continue_chat.dll │ │ │ │ ├── mcp_continue_chat.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_continue_chat.csproj.nuget.g.props │ │ │ │ ├── mcp_continue_chat.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 2.2 mcp_get_chat_info │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_get_chat_info.deps.json │ │ │ │ ├── mcp_get_chat_info.dll │ │ │ │ ├── mcp_get_chat_info.exe │ │ │ │ ├── mcp_get_chat_info.pdb │ │ │ │ ├── mcp_get_chat_info.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── Dokumente - Verknüpfung.lnk │ │ │ ├── mcp_get_chat_info.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_get_.DFF47B4E.Up2Date │ │ │ │ │ ├── mcp_get_chat_info.AssemblyInfo.cs │ │ │ │ │ ├── mcp_get_chat_info.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_get_chat_info.assets.cache │ │ │ │ │ ├── mcp_get_chat_info.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_get_chat_info.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_get_chat_info.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_get_chat_info.dll │ │ │ │ │ ├── mcp_get_chat_info.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_get_chat_info.genruntimeconfig.cache │ │ │ │ │ ├── mcp_get_chat_info.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_get_chat_info.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_get_chat_info.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_get_chat_info.dll │ │ │ │ ├── mcp_get_chat_info.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_get_chat_info.csproj.nuget.g.props │ │ │ │ ├── mcp_get_chat_info.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 3.0 mcp_create_source │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_create_source.deps.json │ │ │ │ ├── mcp_create_source.dll │ │ │ │ ├── mcp_create_source.exe │ │ │ │ ├── mcp_create_source.pdb │ │ │ │ ├── mcp_create_source.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_create_source.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_crea.CB4ED912.Up2Date │ │ │ │ │ ├── mcp_create_source.AssemblyInfo.cs │ │ │ │ │ ├── mcp_create_source.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_create_source.assets.cache │ │ │ │ │ ├── mcp_create_source.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_create_source.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_create_source.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_create_source.dll │ │ │ │ │ ├── mcp_create_source.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_create_source.genruntimeconfig.cache │ │ │ │ │ ├── mcp_create_source.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_create_source.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_create_source.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_create_source.dll │ │ │ │ ├── mcp_create_source.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_create_source.csproj.nuget.g.props │ │ │ │ ├── mcp_create_source.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 3.1 mcp_get_source │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_get_source.deps.json │ │ │ │ ├── mcp_get_source.dll │ │ │ │ ├── mcp_get_source.exe │ │ │ │ ├── mcp_get_source.pdb │ │ │ │ ├── mcp_get_source.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_get_source.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_get_.4E61956F.Up2Date │ │ │ │ │ ├── mcp_get_source.AssemblyInfo.cs │ │ │ │ │ ├── mcp_get_source.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_get_source.assets.cache │ │ │ │ │ ├── mcp_get_source.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_get_source.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_get_source.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_get_source.dll │ │ │ │ │ ├── mcp_get_source.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_get_source.genruntimeconfig.cache │ │ │ │ │ ├── mcp_get_source.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_get_source.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_get_source.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_get_source.dll │ │ │ │ ├── mcp_get_source.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_get_source.csproj.nuget.g.props │ │ │ │ ├── mcp_get_source.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 3.2 mcp_list_sources │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_list_sources.deps.json │ │ │ │ ├── mcp_list_sources.dll │ │ │ │ ├── mcp_list_sources.exe │ │ │ │ ├── mcp_list_sources.pdb │ │ │ │ ├── mcp_list_sources.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_list_sources.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_list_sources.AssemblyInfo.cs │ │ │ │ │ ├── mcp_list_sources.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_list_sources.assets.cache │ │ │ │ │ ├── mcp_list_sources.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_list_sources.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_list_sources.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_list_sources.dll │ │ │ │ │ ├── mcp_list_sources.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_list_sources.genruntimeconfig.cache │ │ │ │ │ ├── mcp_list_sources.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_list_sources.pdb │ │ │ │ │ ├── mcp_list.A720E197.Up2Date │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_list_sources.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_list_sources.dll │ │ │ │ ├── mcp_list_sources.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_list_sources.csproj.nuget.g.props │ │ │ │ ├── mcp_list_sources.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 3.3 mcp_edit_source │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_edit_source.deps.json │ │ │ │ ├── mcp_edit_source.dll │ │ │ │ ├── mcp_edit_source.exe │ │ │ │ ├── mcp_edit_source.pdb │ │ │ │ ├── mcp_edit_source.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_edit_source.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_edit_source.AssemblyInfo.cs │ │ │ │ │ ├── mcp_edit_source.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_edit_source.assets.cache │ │ │ │ │ ├── mcp_edit_source.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_edit_source.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_edit_source.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_edit_source.dll │ │ │ │ │ ├── mcp_edit_source.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_edit_source.genruntimeconfig.cache │ │ │ │ │ ├── mcp_edit_source.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_edit_source.pdb │ │ │ │ │ ├── mcp_edit.7303BE3B.Up2Date │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_edit_source.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_edit_source.dll │ │ │ │ ├── mcp_edit_source.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_edit_source.csproj.nuget.g.props │ │ │ │ ├── mcp_edit_source.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 3.4 mcp_delete_source │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_delete_source.deps.json │ │ │ │ ├── mcp_delete_source.dll │ │ │ │ ├── mcp_delete_source.exe │ │ │ │ ├── mcp_delete_source.pdb │ │ │ │ ├── mcp_delete_source.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_delete_source.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_dele.67DD13F9.Up2Date │ │ │ │ │ ├── mcp_delete_source.AssemblyInfo.cs │ │ │ │ │ ├── mcp_delete_source.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_delete_source.assets.cache │ │ │ │ │ ├── mcp_delete_source.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_delete_source.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_delete_source.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_delete_source.dll │ │ │ │ │ ├── mcp_delete_source.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_delete_source.genruntimeconfig.cache │ │ │ │ │ ├── mcp_delete_source.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_delete_source.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_delete_source.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_delete_source.dll │ │ │ │ ├── mcp_delete_source.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_delete_source.csproj.nuget.g.props │ │ │ │ ├── mcp_delete_source.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 4.0 mcp_list_groups │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_list_groups.deps.json │ │ │ │ ├── mcp_list_groups.dll │ │ │ │ ├── mcp_list_groups.exe │ │ │ │ ├── mcp_list_groups.pdb │ │ │ │ ├── mcp_list_groups.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_list_groups.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_list_groups.AssemblyInfo.cs │ │ │ │ │ ├── mcp_list_groups.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_list_groups.assets.cache │ │ │ │ │ ├── mcp_list_groups.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_list_groups.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_list_groups.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_list_groups.dll │ │ │ │ │ ├── mcp_list_groups.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_list_groups.genruntimeconfig.cache │ │ │ │ │ ├── mcp_list_groups.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_list_groups.pdb │ │ │ │ │ ├── mcp_list.EBD5E0D2.Up2Date │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_list_groups.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_list_groups.dll │ │ │ │ ├── mcp_list_groups.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_list_groups.csproj.nuget.g.props │ │ │ │ ├── mcp_list_groups.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 4.1 mcp_store_group │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_store_group.deps.json │ │ │ │ ├── mcp_store_group.dll │ │ │ │ ├── mcp_store_group.exe │ │ │ │ ├── mcp_store_group.pdb │ │ │ │ ├── mcp_store_group.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_store_group.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_stor.AFB4AA35.Up2Date │ │ │ │ │ ├── mcp_store_group.AssemblyInfo.cs │ │ │ │ │ ├── mcp_store_group.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_store_group.assets.cache │ │ │ │ │ ├── mcp_store_group.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_store_group.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_store_group.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_store_group.dll │ │ │ │ │ ├── mcp_store_group.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_store_group.genruntimeconfig.cache │ │ │ │ │ ├── mcp_store_group.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_store_group.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_store_group.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_store_group.dll │ │ │ │ ├── mcp_store_group.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_store_group.csproj.nuget.g.props │ │ │ │ ├── mcp_store_group.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 4.2 mcp_delete_group │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_delete_group.deps.json │ │ │ │ ├── mcp_delete_group.dll │ │ │ │ ├── mcp_delete_group.exe │ │ │ │ ├── mcp_delete_group.pdb │ │ │ │ ├── mcp_delete_group.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_delete_group.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_dele.FE1C6298.Up2Date │ │ │ │ │ ├── mcp_delete_group.AssemblyInfo.cs │ │ │ │ │ ├── mcp_delete_group.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_delete_group.assets.cache │ │ │ │ │ ├── mcp_delete_group.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_delete_group.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_delete_group.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_delete_group.dll │ │ │ │ │ ├── mcp_delete_group.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_delete_group.genruntimeconfig.cache │ │ │ │ │ ├── mcp_delete_group.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_delete_group.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_delete_group.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_delete_group.dll │ │ │ │ ├── mcp_delete_group.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_delete_group.csproj.nuget.g.props │ │ │ │ ├── mcp_delete_group.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 5.0 mcp_store_user │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_store_user.deps.json │ │ │ │ ├── mcp_store_user.dll │ │ │ │ ├── mcp_store_user.exe │ │ │ │ ├── mcp_store_user.pdb │ │ │ │ ├── mcp_store_user.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_store_user.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_stor.6C0F0C8A.Up2Date │ │ │ │ │ ├── mcp_store_user.AssemblyInfo.cs │ │ │ │ │ ├── mcp_store_user.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_store_user.assets.cache │ │ │ │ │ ├── mcp_store_user.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_store_user.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_store_user.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_store_user.dll │ │ │ │ │ ├── mcp_store_user.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_store_user.genruntimeconfig.cache │ │ │ │ │ ├── mcp_store_user.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_store_user.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_store_user.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_store_user.dll │ │ │ │ ├── mcp_store_user.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_store_user.csproj.nuget.g.props │ │ │ │ ├── mcp_store_user.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 5.1 mcp_edit_user │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_edit_user.deps.json │ │ │ │ ├── mcp_edit_user.dll │ │ │ │ ├── mcp_edit_user.exe │ │ │ │ ├── mcp_edit_user.pdb │ │ │ │ ├── mcp_edit_user.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_edit_user.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_edit_user.AssemblyInfo.cs │ │ │ │ │ ├── mcp_edit_user.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_edit_user.assets.cache │ │ │ │ │ ├── mcp_edit_user.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_edit_user.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_edit_user.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_edit_user.dll │ │ │ │ │ ├── mcp_edit_user.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_edit_user.genruntimeconfig.cache │ │ │ │ │ ├── mcp_edit_user.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_edit_user.pdb │ │ │ │ │ ├── mcp_edit.94A30270.Up2Date │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_edit_user.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_edit_user.dll │ │ │ │ ├── mcp_edit_user.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_edit_user.csproj.nuget.g.props │ │ │ │ ├── mcp_edit_user.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── 5.2 mcp_delete_user │ │ │ ├── bin │ │ │ │ └── Debug │ │ │ │ └── net9.0 │ │ │ │ ├── mcp_delete_user.deps.json │ │ │ │ ├── mcp_delete_user.dll │ │ │ │ ├── mcp_delete_user.exe │ │ │ │ ├── mcp_delete_user.pdb │ │ │ │ ├── mcp_delete_user.runtimeconfig.json │ │ │ │ └── Newtonsoft.Json.dll │ │ │ ├── mcp_delete_user.csproj │ │ │ ├── obj │ │ │ │ ├── Debug │ │ │ │ │ └── net9.0 │ │ │ │ │ ├── .NETCoreApp,Version=v9.0.AssemblyAttributes.cs │ │ │ │ │ ├── apphost.exe │ │ │ │ │ ├── mcp_dele.CEB7E33D.Up2Date │ │ │ │ │ ├── mcp_delete_user.AssemblyInfo.cs │ │ │ │ │ ├── mcp_delete_user.AssemblyInfoInputs.cache │ │ │ │ │ ├── mcp_delete_user.assets.cache │ │ │ │ │ ├── mcp_delete_user.csproj.AssemblyReference.cache │ │ │ │ │ ├── mcp_delete_user.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── mcp_delete_user.csproj.FileListAbsolute.txt │ │ │ │ │ ├── mcp_delete_user.dll │ │ │ │ │ ├── mcp_delete_user.GeneratedMSBuildEditorConfig.editorconfig │ │ │ │ │ ├── mcp_delete_user.genruntimeconfig.cache │ │ │ │ │ ├── mcp_delete_user.GlobalUsings.g.cs │ │ │ │ │ ├── mcp_delete_user.pdb │ │ │ │ │ ├── ref │ │ │ │ │ │ └── mcp_delete_user.dll │ │ │ │ │ └── refint │ │ │ │ │ └── mcp_delete_user.dll │ │ │ │ ├── mcp_delete_user.csproj.nuget.dgspec.json │ │ │ │ ├── mcp_delete_user.csproj.nuget.g.props │ │ │ │ ├── mcp_delete_user.csproj.nuget.g.targets │ │ │ │ ├── project.assets.json │ │ │ │ └── project.nuget.cache │ │ │ └── Program.cs │ │ ├── Code Archiv │ │ │ ├── mcp_chat.cs │ │ │ ├── mcp_continue_chat.cs │ │ │ ├── mcp_create_source.cs │ │ │ ├── mcp_delete_group.cs │ │ │ ├── mcp_delete_source.cs │ │ │ ├── mcp_delete_user.cs │ │ │ ├── mcp_edit_source.cs │ │ │ ├── mcp_edit_user.cs │ │ │ ├── mcp_get_chat_info.cs │ │ │ ├── mcp_get_source.cs │ │ │ ├── mcp_list_groups.cs │ │ │ ├── mcp_list_sources.cs │ │ │ ├── mcp_login.cs │ │ │ ├── mcp_logout.cs │ │ │ ├── mcp_store_group.cs │ │ │ └── mcp_store_user.cs │ │ └── README.md │ ├── C++ │ │ ├── .vscode │ │ │ └── launch.json │ │ ├── 1.0 mcp_login │ │ │ ├── MCPLoginClient.cpp │ │ │ └── Non-TLS version │ │ │ ├── MCPLoginClient.cpp │ │ │ └── MCPLoginClient.exe │ │ ├── 1.1 mcp_logout │ │ │ ├── MCPLogoutClient.cpp │ │ │ └── MCPLogoutClient.exe │ │ ├── 2.0 mcp_chat │ │ │ ├── MCPChatClient.cpp │ │ │ └── MCPChatClient.exe │ │ ├── 2.1 mcp_continue_chat │ │ │ ├── MCPChatContinuationClient.cpp │ │ │ └── MCPChatContinuationClient.exe │ │ ├── 2.2 mcp_get_chat_info │ │ │ ├── MCPGetChatInfoClient.cpp │ │ │ └── MCPGetChatInfoClient.exe │ │ ├── 3.0 mcp_create_source │ │ │ ├── MCPCreateSourceClient.cpp │ │ │ └── MCPCreateSourceClient.exe │ │ ├── 3.1 mcp_get_source │ │ │ ├── MCPGetSourceClient.cpp │ │ │ └── MCPGetSourceClient.exe │ │ ├── 3.2 mcp_list_sources │ │ │ ├── MCPListSourcesClient.cpp │ │ │ └── MCPListSourcesClient.exe │ │ ├── 3.3 mcp_edit_source │ │ │ ├── MCPEditSourceClient.cpp │ │ │ └── MCPEditSourceClient.exe │ │ ├── 3.4 mcp_delete_source │ │ │ ├── MCPDeleteSourceClient.cpp │ │ │ └── MCPDeleteSourceClient.exe │ │ ├── 4.0 mcp_list_groups │ │ │ ├── MCPListGroupsClient.cpp │ │ │ └── MCPListGroupsClient.exe │ │ ├── 4.1 mcp_store_group │ │ │ ├── MCPStoreGroupClient.cpp │ │ │ └── MCPStoreGroupClient.exe │ │ ├── 4.2 mcp_delete_group │ │ │ ├── MPCDeleteGroupClient.cpp │ │ │ └── MPCDeleteGroupClient.exe │ │ ├── 5.0 mcp_store_user │ │ │ ├── MCPStoreUserClient.cpp │ │ │ └── MCPStoreUserClient.exe │ │ ├── 5.1 mcp_edit_user │ │ │ ├── MCPEditUserClient.cpp │ │ │ └── MCPEditUserClient.exe │ │ ├── 5.2 mcp_delete_user │ │ │ ├── MCPDeleteUserClient.cpp │ │ │ └── MCPDeleteUserClient.exe │ │ ├── 9.0 mcp_keygen │ │ │ ├── MCPKeygenClient.cpp │ │ │ └── MCPKeygenClient.exe │ │ └── README.md │ ├── Go │ │ ├── 1.0 mcp_login │ │ │ ├── go.mod │ │ │ ├── MCPLoginClient.exe │ │ │ └── MCPLoginClient.go │ │ ├── 1.1 mcp_logout │ │ │ ├── MCPLogoutClient.exe │ │ │ └── MCPLogoutClient.go │ │ ├── 2.0 mcp_chat │ │ │ ├── MCPChatClient.exe │ │ │ └── MCPChatClient.go │ │ ├── 2.1 mcp_continue_chat │ │ │ ├── MCPChatContinuationClient.exe │ │ │ └── MCPChatContinuationClient.go │ │ ├── 2.2 mcp_get_chat_info │ │ │ ├── MCPGetChatInfoClient.exe │ │ │ └── MCPGetChatInfoClient.go │ │ ├── 3.0 mcp_create_source │ │ │ ├── MCPCreateSourceClient.exe │ │ │ └── MCPCreateSourceClient.go │ │ ├── 3.1 mcp_get_source │ │ │ ├── MCPGetSourceClient.exe │ │ │ └── MCPGetSourceClient.go │ │ ├── 3.2 mcp_list_sources │ │ │ ├── MCPListSourcesClient.exe │ │ │ └── MCPListSourcesClient.go │ │ ├── 3.3 mcp_edit_source │ │ │ ├── MCPEditSourceClient.exe │ │ │ └── MCPEditSourceClient.go │ │ ├── 3.4 mcp_delete_source │ │ │ ├── MCPDeleteSourceClient.exe │ │ │ └── MCPDeleteSourceClient.go │ │ ├── 4.0 mcp_list_groups │ │ │ ├── MCPListGroupsClient.exe │ │ │ └── MCPListGroupsClient.go │ │ ├── 4.1 mcp_store_group │ │ │ ├── MCPStoreGroupClient.exe │ │ │ └── MCPStoreGroupClient.go │ │ ├── 4.2 mcp_delete_group │ │ │ ├── MCPDeleteGroupClient.exe │ │ │ └── MCPDeleteGroupClient.go │ │ ├── 5.0 mcp_store_user │ │ │ ├── MCPStoreUserClient.exe │ │ │ └── MCPStoreUserClient.go │ │ ├── 5.1 mcp_edit_user │ │ │ ├── MCPEditUserClient.exe │ │ │ └── MCPEditUserClient.go │ │ ├── 5.2 mcp_delete_user │ │ │ ├── MCPDeleteUserClient.exe │ │ │ └── MCPDeleteUserClient.go │ │ ├── 9.0 mcp_keygen │ │ │ ├── MCPKeygenClient.exe │ │ │ └── MCPKeygenClient.go │ │ └── README.md │ ├── Gradio │ │ ├── Api.py │ │ ├── config.json.example │ │ ├── config.py │ │ ├── favicon.ico │ │ ├── file_tools │ │ │ └── loader_factory.py │ │ ├── language.py │ │ ├── logos │ │ │ ├── fsas.png │ │ │ └── Logo_dark.svg │ │ ├── main.py │ │ ├── mcp_client.py │ │ ├── mcp_servers │ │ │ ├── arxiv │ │ │ │ ├── arxiv-stdio.js │ │ │ │ ├── package.json │ │ │ │ ├── README.md │ │ │ │ ├── requirements.txt │ │ │ │ └── server_config.example.json │ │ │ ├── demo-mcp-server │ │ │ │ ├── demo-tools-sse.js │ │ │ │ ├── demo-tools-stdio.js │ │ │ │ └── tools │ │ │ │ ├── assets.js │ │ │ │ ├── calculator.js │ │ │ │ └── weather.js │ │ │ ├── filesystem │ │ │ │ ├── Dockerfile │ │ │ │ ├── index.ts │ │ │ │ ├── package.json │ │ │ │ ├── README.md │ │ │ │ ├── test │ │ │ │ │ └── new.txt │ │ │ │ └── tsconfig.json │ │ │ ├── moondream │ │ │ │ └── server.py │ │ │ ├── pgpt │ │ │ │ ├── __init__.py │ │ │ │ ├── Api.py │ │ │ │ ├── config.json.example │ │ │ │ ├── config.py │ │ │ │ ├── language.py │ │ │ │ ├── pyproject.toml │ │ │ │ ├── README.md │ │ │ │ └── server.py │ │ │ ├── replicate_flux │ │ │ │ └── server.py │ │ │ └── sqlite │ │ │ ├── .python-version │ │ │ ├── Dockerfile │ │ │ ├── pyproject.toml │ │ │ ├── README.md │ │ │ └── src │ │ │ └── mcp_server_sqlite │ │ │ ├── __init__.py │ │ │ └── server.py │ │ ├── messages │ │ │ ├── __init__.py │ │ │ ├── message_types │ │ │ │ ├── __init__.py │ │ │ │ ├── incrementing_id_message.py │ │ │ │ ├── initialize_message.py │ │ │ │ ├── json_rpc_message.py │ │ │ │ ├── ping_message.py │ │ │ │ ├── prompts_messages.py │ │ │ │ ├── prompts_models.py │ │ │ │ ├── resources_messages.py │ │ │ │ └── tools_messages.py │ │ │ ├── send_call_tool.py │ │ │ ├── send_initialize_message.py │ │ │ ├── send_message.py │ │ │ ├── send_ping.py │ │ │ ├── send_prompts.py │ │ │ ├── send_resources.py │ │ │ └── send_tools_list.py │ │ ├── README.md │ │ ├── requirements.txt │ │ ├── server_config.json │ │ ├── SourceManagement.py │ │ ├── transport │ │ │ ├── __init__.py │ │ │ └── stdio │ │ │ ├── __init__.py │ │ │ ├── stdio_client.py │ │ │ ├── stdio_server_parameters.py │ │ │ └── stdio_server_shutdown.py │ │ ├── tsconfig.json │ │ └── UserManagement.py │ ├── Java │ │ ├── 1.0 mcp_login │ │ │ ├── json-20241224.jar │ │ │ ├── MCPLoginClient.class │ │ │ └── MCPLoginClient.java │ │ ├── 1.1 mcp_logout │ │ │ ├── json-20241224.jar │ │ │ ├── MCPLogoutClient.class │ │ │ └── MCPLogoutClient.java │ │ ├── 2.0 mcp_chat │ │ │ ├── json-20241224.jar │ │ │ ├── MCPChatClient.class │ │ │ └── MCPChatClient.java │ │ ├── 2.1 mcp_continue_chat │ │ │ ├── json-20241224.jar │ │ │ ├── MCPContinueChatClient.class │ │ │ └── MCPContinueChatClient.java │ │ ├── 2.2 mcp_get_chat_info │ │ │ ├── json-20241224.jar │ │ │ ├── MCPGetChatInfoClient.class │ │ │ └── MCPGetChatInfoClient.java │ │ ├── 3.0 mcp_create_source │ │ │ ├── json-20241224.jar │ │ │ ├── MCPCreateSourceClient.class │ │ │ └── MCPCreateSourceClient.java │ │ ├── 3.1 mcp_get_source │ │ │ ├── json-20241224.jar │ │ │ ├── MCPGetSourceClient.class │ │ │ └── MCPGetSourceClient.java │ │ ├── 3.2 mcp_list_sources │ │ │ ├── json-20241224.jar │ │ │ ├── MCPListSourcesClient.class │ │ │ └── MCPListSourcesClient.java │ │ ├── 3.3 mcp_edit_source │ │ │ ├── json-20241224.jar │ │ │ ├── MCPEditSourceClient.class │ │ │ └── MCPEditSourceClient.java │ │ ├── 3.4 mcp_delete_source │ │ │ ├── json-20241224.jar │ │ │ ├── MCPDeleteSourceClient.class │ │ │ └── MCPDeleteSourceClient.java │ │ ├── 4.0 mcp_list_groups │ │ │ ├── json-20241224.jar │ │ │ ├── MCPListGroupsClient.class │ │ │ └── MCPListGroupsClient.java │ │ ├── 4.1 mcp_store_group │ │ │ ├── json-20241224.jar │ │ │ ├── MCPStoreGroupClient.class │ │ │ └── MCPStoreGroupClient.java │ │ ├── 4.2 mcp_delete_group │ │ │ ├── json-20241224.jar │ │ │ ├── MCPDeleteGroupClient.class │ │ │ └── MCPDeleteGroupClient.java │ │ ├── 5.0 mcp_store_user │ │ │ ├── json-20241224.jar │ │ │ ├── MCPStoreUserClient.class │ │ │ └── MCPStoreUserClient.java │ │ ├── 5.1 mcp_edit_user │ │ │ ├── json-20241224.jar │ │ │ ├── MCPEditUserClient.class │ │ │ └── MCPEditUserClient.java │ │ ├── 5.2 mcp_delete_user │ │ │ ├── json-20241224.jar │ │ │ ├── MCPDeleteUserClient.class │ │ │ └── MCPDeleteUserClient.java │ │ └── README.md │ ├── JavaScript │ │ ├── 1.0 mcp_login │ │ │ └── MCPLoginClient.js │ │ ├── 1.1 mcp_logout │ │ │ └── MCPLogoutClient.js │ │ ├── 2.0 mcp_chat │ │ │ └── MCPChatClient.js │ │ ├── 2.1 mcp_continue_chat │ │ │ └── MCPContinueChatClient.js │ │ ├── 2.2 mcp_get_chat_info │ │ │ └── MCPGetChatInfoClient.js │ │ ├── 3.0 mcp_create_source │ │ │ └── MCPCreateSourceClient.js │ │ ├── 3.1 mcp_get_source │ │ │ └── MCPGetSourceClient.js │ │ ├── 3.2 mcp_list_sources │ │ │ └── MCPListSourcesClient.js │ │ ├── 3.3 mcp_edit_source │ │ │ └── MCPEditSourceClient.js │ │ ├── 3.4 mcp_delete_source │ │ │ └── MCPDeleteSourceClient.js │ │ ├── 4.0 mcp_list_groups │ │ │ └── MCPListGroupsClient.js │ │ ├── 4.1 mcp_store_group │ │ │ └── MCPStoreGroupClient.js │ │ ├── 4.2 mcp_delete_group │ │ │ └── MCPDeleteGroupClient.js │ │ ├── 5.0 mcp_store_user │ │ │ └── MCPStoreUserClient.js │ │ ├── 5.1 mcp_edit_user │ │ │ └── MCPEditUserClient.js │ │ ├── 5.2 mcp_delete_user │ │ │ └── MCPDeleteUserClient.js │ │ ├── 9.0 mcp_keygen │ │ │ └── MCPKeygenClient.js │ │ └── README.md │ ├── PHP │ │ ├── 1.0 mcp_login │ │ │ └── MCPLoginClient.php │ │ ├── 1.1 mcp_logout │ │ │ └── MCPLogoutClient.php │ │ ├── 2.0 mcp_chat │ │ │ └── MCPChatClient.php │ │ ├── 2.1 mcp_continue_chat │ │ │ └── MCPContinueChatClient.php │ │ ├── 2.2 mcp_get_chat_info │ │ │ └── MCPGetChatInfoClient.php │ │ ├── 3.0 mcp_create_source │ │ │ └── MCPCreateSourceClient.php │ │ ├── 3.1 mcp_get_source │ │ │ └── MCPGetSourceClient.php │ │ ├── 3.2 mcp_list_sources │ │ │ └── MCPListSourcesClient.php │ │ ├── 3.3 mcp_edit_source │ │ │ └── MCPEditSourceClient.php │ │ ├── 3.4 mcp_delete_source │ │ │ └── MCPDeleteSourceClient.php │ │ ├── 4.0 mcp_list_groups │ │ │ └── MCPListGroupsClient.php │ │ ├── 4.1 mcp_store_group │ │ │ └── MCPStoreGroupClient.php │ │ ├── 4.2 mcp_delete_group │ │ │ └── MCPDeleteGroupClient.php │ │ ├── 5.0 mcp_store_user │ │ │ └── MCPStoreUserClient.php │ │ ├── 5.1 mcp_edit_user │ │ │ └── MCPEditUserClient.php │ │ ├── 5.2 mcp_delete_user │ │ │ └── MCPDeleteUserClient.php │ │ ├── 9.0 mcp_keygen │ │ │ └── MCPKeygenClient.php │ │ └── README.md │ └── Python │ ├── __init__.py │ ├── 1.0 mcp_login │ │ └── MCPLoginClient.py │ ├── 1.1 mcp_logout │ │ └── MCPLogoutClient.py │ ├── 2.0 mcp_chat │ │ └── MCPChatClient.py │ ├── 2.1 mcp_continue_chat │ │ └── MCPContinueChatClient.py │ ├── 2.2 mcp_get_chat_info │ │ └── MCPGetChatInfoClient.py │ ├── 2.3 mcp_delete_all_chats │ │ └── MCPDeleteAllChatsClient.py │ ├── 2.4 mcp_delete_chat │ │ └── MCPDeleteChatClient.py │ ├── 3.0 mcp_create_source │ │ └── MCPCreateSourceClient.py │ ├── 3.1 mcp_get_source │ │ └── MCPGetSourceClient.py │ ├── 3.2 mcp_list_sources │ │ └── MCPListSourcesClient.py │ ├── 3.3 mcp_edit_source │ │ └── MCPEditSourceClient.py │ ├── 3.4 mcp_delete_source │ │ └── MCPDeleteSourceClient.py │ ├── 4.0 mcp_list_groups │ │ └── MCPListGroupsClient.py │ ├── 4.1 mcp_store_group │ │ └── MCPStoreGroupClient.py │ ├── 4.2 mcp_delete_group │ │ └── MCPDeleteGroupClient.py │ ├── 5.0 mcp_store_user │ │ └── MCPStoreUserClient.py │ ├── 5.1 mcp_edit_user │ │ └── MCPEditUserClient.py │ ├── 5.2 mcp_delete_user │ │ └── MCPDeleteUserClient.py │ ├── 9.0 mcp_keygen │ │ └── MCPKeygenClient.py │ ├── Gradio │ │ ├── __init__.py │ │ └── server_config.json │ └── README.md ├── examples │ ├── create_users_from_csv │ │ ├── config.json.example │ │ ├── config.py │ │ ├── create_users_from_csv.py │ │ └── language.py │ ├── dynamic_sources │ │ └── rss_reader │ │ ├── Api.py │ │ ├── config.json.example │ │ ├── config.py │ │ ├── demo_dynamic_sources.py │ │ └── rss_parser.py │ ├── example_users_to_add_no_tz.csv │ └── sftp_upload_with_id │ ├── Api.py │ ├── config_ftp.json.example │ ├── config.py │ ├── demo_upload.py │ ├── language.py │ └── requirements.txt ├── images │ ├── alternative mcp client.png │ ├── favicon │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ └── site.webmanifest │ ├── mcp-general-architecture.png │ ├── privateGPT-MCP.png │ └── privateGPT.png ├── InstallMPCServer.sh ├── jest.config.js ├── LICENSE ├── package.json ├── pgpt.env.json.example ├── README.md ├── security │ ├── generate_decrypted_password.js │ └── generate_encrypted_password.js ├── src │ ├── helper.js │ ├── index.js │ ├── logger.js │ ├── pgpt-messages.js │ ├── public │ │ ├── index.html │ │ └── pgpt-mcp-logo.png │ ├── services │ │ └── pgpt-service.ts │ └── types │ └── api.ts ├── start_chatbot_agent.ps1 ├── start_chatbot_agent.sh ├── start_iot_agent.ps1 ├── start_iot_agent.sh ├── start_openai_compatible_api_agent.ps1 ├── start_openai_compatible_api_agent.sh ├── tsconfig.json ├── ver │ ├── index_np.js │ └── index_proxy_np.js └── WORKLOG.md ``` # Files -------------------------------------------------------------------------------- /agents/MCP-Client/Python/mcp_client.py: -------------------------------------------------------------------------------- ```python 1 | # src/__main__.py 2 | import argparse 3 | import asyncio 4 | import json 5 | import logging 6 | import os 7 | import signal 8 | import sys 9 | from pathlib import Path 10 | from typing import List 11 | 12 | import anyio 13 | # Rich imports 14 | from rich import print 15 | from rich.markdown import Markdown 16 | from rich.panel import Panel 17 | 18 | from .chat_handler import handle_chat_mode, get_input 19 | from .config import load_config 20 | from .messages.send_ping import send_ping 21 | from .messages.send_prompts import send_prompts_list 22 | from .messages.send_resources import send_resources_list 23 | from .messages.send_initialize_message import send_initialize 24 | from .messages.send_call_tool import send_call_tool 25 | from .messages.send_tools_list import send_tools_list 26 | from .transport.stdio.stdio_client import stdio_client 27 | 28 | # Default path for the configuration file 29 | DEFAULT_CONFIG_FILE = config_file = Path.absolute(Path(__file__).parent.parent / "server_config.json") 30 | 31 | # Configure logging 32 | logging.basicConfig( 33 | level=logging.CRITICAL, 34 | format="%(asctime)s - %(levelname)s - %(message)s", 35 | stream=sys.stderr, 36 | ) 37 | 38 | def signal_handler(sig, frame): 39 | # Ignore subsequent SIGINT signals 40 | signal.signal(signal.SIGINT, signal.SIG_IGN) 41 | 42 | # pretty exit 43 | print("\n[bold red]Goodbye![/bold red]") 44 | 45 | # Immediately and forcibly kill the process 46 | os.kill(os.getpid(), signal.SIGKILL) 47 | 48 | 49 | # signal handler 50 | signal.signal(signal.SIGINT, signal_handler) 51 | 52 | 53 | async def handle_command(command: str, server_streams: List[tuple]) -> bool: 54 | """Handle specific commands dynamically with multiple servers.""" 55 | try: 56 | if command == "ping": 57 | print("[cyan]\nPinging Servers...[/cyan]") 58 | for i, (read_stream, write_stream) in enumerate(server_streams): 59 | result = await send_ping(read_stream, write_stream) 60 | server_num = i + 1 61 | if result: 62 | ping_md = f"## Server {server_num} Ping Result\n\n✅ **Server is up and running**" 63 | print(Panel(Markdown(ping_md), style="bold green")) 64 | else: 65 | ping_md = f"## Server {server_num} Ping Result\n\n❌ **Server ping failed**" 66 | print(Panel(Markdown(ping_md), style="bold red")) 67 | 68 | elif command == "list-tools": 69 | print("[cyan]\nFetching Tools List from all servers...[/cyan]") 70 | for i, (read_stream, write_stream) in enumerate(server_streams): 71 | response = await send_tools_list(read_stream, write_stream) 72 | tools_list = response.get("tools", []) 73 | server_num = i + 1 74 | 75 | if not tools_list: 76 | tools_md = ( 77 | f"## Server {server_num} Tools List\n\nNo tools available." 78 | ) 79 | else: 80 | tools_md = f"## Server {server_num} Tools List\n\n" + "\n".join( 81 | [ 82 | f"- **{t.get('name')}**: {t.get('description', 'No description')}" 83 | for t in tools_list 84 | ] 85 | ) 86 | print( 87 | Panel( 88 | Markdown(tools_md), 89 | title=f"Server {server_num} Tools", 90 | style="bold cyan", 91 | ) 92 | ) 93 | 94 | elif command == "call-tool": 95 | tool_name = await get_input("[bold magenta]Enter tool name[/bold magenta]") 96 | if not tool_name: 97 | print("[red]Tool name cannot be empty.[/red]") 98 | return True 99 | 100 | arguments_str = await get_input("[bold magenta]Enter tool arguments as JSON (e.g., {'key': 'value'})[/bold magenta]") 101 | try: 102 | arguments = json.loads(arguments_str) 103 | except json.JSONDecodeError as e: 104 | print(f"[red]Invalid JSON arguments format:[/red] {e}") 105 | return True 106 | 107 | print(f"[cyan]\nCalling tool '{tool_name}' with arguments:\n[/cyan]") 108 | print( 109 | Panel( 110 | Markdown(f"```json\n{json.dumps(arguments, indent=2)}\n```"), 111 | style="dim", 112 | ) 113 | ) 114 | 115 | for read_stream, write_stream in server_streams: 116 | result = await send_call_tool(tool_name, arguments, read_stream, write_stream) 117 | if result.get("isError"): 118 | # print(f"[red]Error calling tool:[/red] {result.get('error')}") 119 | continue 120 | response_content = result.get("content", "No content") 121 | try: 122 | if response_content[0]['text'].startswith('Error:'): 123 | continue 124 | except: 125 | pass 126 | print( 127 | Panel( 128 | Markdown(f"### Tool Response\n\n{response_content}"), 129 | style="green", 130 | ) 131 | ) 132 | 133 | elif command == "list-resources": 134 | print("[cyan]\nFetching Resources List from all servers...[/cyan]") 135 | for i, (read_stream, write_stream) in enumerate(server_streams): 136 | response = await send_resources_list(read_stream, write_stream) 137 | resources_list = response.get("resources", []) if response else None 138 | server_num = i + 1 139 | 140 | if not resources_list: 141 | resources_md = f"## Server {server_num} Resources List\n\nNo resources available." 142 | else: 143 | resources_md = f"## Server {server_num} Resources List\n" 144 | for r in resources_list: 145 | if isinstance(r, dict): 146 | json_str = json.dumps(r, indent=2) 147 | resources_md += f"\n```json\n{json_str}\n```" 148 | else: 149 | resources_md += f"\n- {r}" 150 | print( 151 | Panel( 152 | Markdown(resources_md), 153 | title=f"Server {server_num} Resources", 154 | style="bold cyan", 155 | ) 156 | ) 157 | 158 | elif command == "list-prompts": 159 | print("[cyan]\nFetching Prompts List from all servers...[/cyan]") 160 | for i, (read_stream, write_stream) in enumerate(server_streams): 161 | response = await send_prompts_list(read_stream, write_stream) 162 | prompts_list = response.get("prompts", []) if response else None 163 | server_num = i + 1 164 | 165 | if not prompts_list: 166 | prompts_md = ( 167 | f"## Server {server_num} Prompts List\n\nNo prompts available." 168 | ) 169 | else: 170 | prompts_md = f"## Server {server_num} Prompts List\n\n" + "\n".join( 171 | [f"- {p}" for p in prompts_list] 172 | ) 173 | print( 174 | Panel( 175 | Markdown(prompts_md), 176 | title=f"Server {server_num} Prompts", 177 | style="bold cyan", 178 | ) 179 | ) 180 | 181 | elif command == "chat": 182 | provider = os.getenv("LLM_PROVIDER", "openai") 183 | model = os.getenv("LLM_MODEL", "gpt-4o-mini") 184 | 185 | # Clear the screen first 186 | if sys.platform == "win32": 187 | os.system("cls") 188 | else: 189 | os.system("clear") 190 | 191 | chat_info_text = ( 192 | "Welcome to the Chat!\n\n" 193 | f"**Provider:** {provider} | **Model:** {model}\n\n" 194 | "Type 'exit' to quit." 195 | ) 196 | 197 | print( 198 | Panel( 199 | Markdown(chat_info_text), 200 | style="bold cyan", 201 | title="Chat Mode", 202 | title_align="center", 203 | ) 204 | ) 205 | await handle_chat_mode(server_streams, provider, model) 206 | 207 | elif command in ["quit", "exit"]: 208 | print("\n[bold red]Goodbye![/bold red]") 209 | return False 210 | 211 | elif command == "clear": 212 | if sys.platform == "win32": 213 | os.system("cls") 214 | else: 215 | os.system("clear") 216 | 217 | elif command == "help": 218 | help_md = print_help() 219 | print(Panel(help_md)) 220 | 221 | else: 222 | print(f"[red]\nUnknown command: {command}[/red]") 223 | print("[yellow]Type 'help' for available commands[/yellow]") 224 | except Exception as e: 225 | print(f"\n[red]Error executing command:[/red] {e}") 226 | 227 | return True 228 | 229 | def print_help(): 230 | return Markdown( 231 | """ 232 | # Available Commands 233 | 234 | - **ping**: Check if server is responsive 235 | - **list-tools**: Display available tools 236 | - **list-resources**: Display available resources 237 | - **list-prompts**: Display available prompts 238 | - **chat**: Enter chat mode 239 | - **clear**: Clear the screen 240 | - **help**: Show this help message 241 | - **quit/exit**: Exit the program 242 | 243 | **Note:** Commands use dashes (e.g., `list-tools` not `list tools`). 244 | """) 245 | 246 | async def interactive_mode(server_streams: List[tuple]): 247 | """Run the CLI in interactive mode with multiple servers.""" 248 | welcome_text = """ 249 | # Welcome to the Interactive MCP Command-Line Tool (Multi-Server Mode) 250 | 251 | Type 'help' for available commands or 'quit' to exit. 252 | """ 253 | print(Panel(Markdown(welcome_text), style="bold cyan")) 254 | 255 | help_md = print_help() 256 | print(Panel(help_md, style="yellow")) 257 | 258 | while True: 259 | try: 260 | command = await get_input("[bold green]\n>[/bold green]") 261 | command = command.lower() 262 | if not command: 263 | continue 264 | should_continue = await handle_command(command, server_streams) 265 | if not should_continue: 266 | return 267 | except EOFError: 268 | break 269 | except Exception as e: 270 | print(f"\n[red]Error:[/red] {e}") 271 | 272 | 273 | class GracefulExit(Exception): 274 | """Custom exception for handling graceful exits.""" 275 | 276 | pass 277 | 278 | 279 | async def run(config_path: str, server_names: List[str], command: str = None) -> None: 280 | """Main function to manage server initialization, communication, and shutdown.""" 281 | # Clear screen before rendering anything 282 | if sys.platform == "win32": 283 | os.system("cls") 284 | else: 285 | os.system("clear") 286 | 287 | # Load server configurations and establish connections for all servers 288 | server_streams = [] 289 | context_managers = [] 290 | for server_name in server_names: 291 | server_params = await load_config(config_path, server_name) 292 | 293 | # Establish stdio communication for each server 294 | cm = stdio_client(server_params) 295 | (read_stream, write_stream) = await cm.__aenter__() 296 | context_managers.append(cm) 297 | server_streams.append((read_stream, write_stream)) 298 | 299 | init_result = await send_initialize(read_stream, write_stream) 300 | if not init_result: 301 | print(f"[red]Server initialization failed for {server_name}[/red]") 302 | return 303 | 304 | try: 305 | if command: 306 | # Single command mode 307 | await handle_command(command, server_streams) 308 | else: 309 | # Interactive mode 310 | await interactive_mode(server_streams) 311 | finally: 312 | # Clean up all streams 313 | for cm in context_managers: 314 | with anyio.move_on_after(1): # wait up to 1 second 315 | await cm.__aexit__() 316 | 317 | def cli_main(): 318 | # setup the parser 319 | parser = argparse.ArgumentParser(description="MCP Client") 320 | 321 | parser.add_argument( 322 | "--config-file", 323 | default=DEFAULT_CONFIG_FILE, 324 | help="Path to the JSON configuration file containing server details.", 325 | ) 326 | 327 | parser.add_argument( 328 | "--server", 329 | action="append", 330 | dest="servers", 331 | help="Server configuration(s) to use. Can be specified multiple times.", 332 | default=[], 333 | ) 334 | 335 | parser.add_argument( 336 | "--all", 337 | action="store_true", 338 | dest="all", 339 | default=False 340 | ) 341 | 342 | parser.add_argument( 343 | "command", 344 | nargs="?", 345 | choices=["ping", "list-tools", "list-resources", "list-prompts"], 346 | help="Command to execute (optional - if not provided, enters interactive mode).", 347 | ) 348 | 349 | parser.add_argument( 350 | "--model", 351 | help=( 352 | "Model to use. Defaults to 'pgpt-mistral-nemo-12b'"), 353 | ) 354 | 355 | args = parser.parse_args() 356 | 357 | # Set default model based on provider 358 | model = args.model or ( 359 | "pgpt-mistral-nemo-12b" 360 | ) 361 | os.environ["LLM_PROVIDER"] = "pgpt" 362 | os.environ["LLM_MODEL"] = model 363 | 364 | try: 365 | if args.all: 366 | with open(args.config_file,'r') as f: 367 | args.servers = list(json.load(f)['mcpServers'].keys()) 368 | result = anyio.run(run, args.config_file, args.servers, args.command) 369 | sys.exit(result) 370 | except Exception as e: 371 | print(f"[red]Error occurred:[/red] {e}") 372 | sys.exit(1) 373 | 374 | 375 | if __name__ == "__main__": 376 | cli_main() 377 | 378 | ``` -------------------------------------------------------------------------------- /agents/OpenAI_Compatible_API_Agent/Python/privategpt_api.py: -------------------------------------------------------------------------------- ```python 1 | import json 2 | import re 3 | from pathlib import Path 4 | 5 | import requests 6 | import urllib3 7 | import base64 8 | 9 | from httpcore import NetworkError 10 | 11 | from ...AgentInterface.Python.config import Config 12 | 13 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 14 | 15 | 16 | def initialize_session(proxy_user, proxy_password, access_header): 17 | """Set up the session with proxy authentication.""" 18 | session = requests.Session() 19 | session.verify = False 20 | headers = { 21 | 'Accept': 'application/json', 22 | 'Content-Type': 'application/json', 23 | } 24 | if access_header is not None: 25 | headers['X-Custom-Header'] = access_header 26 | elif proxy_user is not None and proxy_password is not None: 27 | auth = base64.b64encode(f"{proxy_user}:{proxy_password}".encode()).decode() 28 | headers['Authorization'] = f'Basic {auth}' 29 | session.headers.update(headers) 30 | return session 31 | 32 | 33 | class PrivateGPTAPI: 34 | def __init__(self, config, client_api_key=None): 35 | """Initialize the chat client with proxy authentication.""" 36 | self.token = None 37 | self.chat_id = None 38 | 39 | self.base_url = config.get("base_url") 40 | self.proxy_user = config.get("proxy_user", None) 41 | if self.proxy_user == "": 42 | self.proxy_user = None 43 | self.proxy_password = config.get("proxy_password", None) 44 | if self.proxy_password == "": 45 | self.proxy_password = None 46 | self.access_header = config.get("access_header", None) 47 | if self.access_header == "": 48 | self.access_header = None 49 | 50 | self.chosen_groups = config.data["groups"] or [] 51 | self.language = config.get("language", "en") 52 | self.use_public = config.get("use_public", True) 53 | self.whitelist_keys = config.get("whitelist_keys", []) 54 | self.logged_in = False 55 | 56 | 57 | if client_api_key is not None: 58 | self.email, self.password = decrypt_api_key(client_api_key) 59 | if len(self.whitelist_keys) > 0: 60 | if client_api_key not in self.whitelist_keys: 61 | print("not authorized") 62 | 63 | self.session = initialize_session(self.proxy_user, self.proxy_password, self.access_header) 64 | if self.login(): 65 | self.logged_in = True 66 | 67 | 68 | def login(self): 69 | """Authenticate the user and retrieve the token.""" 70 | url = f"{self.base_url}/login" 71 | payload = {"email": self.email, "password": self.password} 72 | try: 73 | response = self.session.post(url, json=payload) 74 | print(response.content) 75 | response.raise_for_status() 76 | data = response.json() 77 | self.token = data['data']['token'] 78 | 79 | # Prüfen, ob der Header bereits existiert 80 | if 'Authorization' in self.session.headers: 81 | self.session.headers['Authorization'] += f', Bearer {self.token}' 82 | else: 83 | self.session.headers['Authorization'] = f'Bearer {self.token}' 84 | self.chat_id = None 85 | print("✅ Login successful.") 86 | return True 87 | except requests.exceptions.RequestException as e: 88 | print(f"❌ Login failed: {e}") 89 | return False 90 | 91 | def create_chat(self, user_input): 92 | """Start a new chat session. 93 | 94 | This method sends a POST request to the '/chats' endpoint with the provided parameters. 95 | It initializes a new chat session and stores the chat ID for future use. 96 | """ 97 | url = f"{self.base_url}/chats" 98 | payload = { 99 | "language": self.language, 100 | "question": user_input, # Initial question to start the chat 101 | "usePublic": self.use_public, 102 | "groups": self.chosen_groups 103 | } 104 | try: 105 | response = self.session.post(url, json=payload) 106 | response.raise_for_status() # Raise an exception if the response was not successful 107 | data = response.json() 108 | self.chat_id = data['data']['chatId'] # Store the chat ID for future use 109 | print("✅ Chat initialized.") 110 | resp = response.json() 111 | try: 112 | answer = resp.get('data', None).get('answer', "error") 113 | except: 114 | print(response.json()) 115 | resp = {"data": 116 | {"answer": "error"} 117 | } 118 | answer = "error" 119 | 120 | if answer.startswith("{\"role\":"): 121 | answerj = json.loads(answer) 122 | resp["data"]["answer"] = answerj["content"] 123 | resp["data"]["chatId"] = "0" 124 | 125 | print(f"💡 Response: {answer}") 126 | return resp 127 | except requests.exceptions.RequestException as e: 128 | # It seems we get disconnections from time to time.. 129 | # print(f"⚠️ Failed to get response on first try, trying again..: {e}") 130 | try: 131 | response = self.session.patch(url, json=payload) 132 | response.raise_for_status() 133 | data = response.json() 134 | answer = data.get('data', {}).get('answer', "No answer provided.") 135 | print(f"💡 Response: {answer}") 136 | return data 137 | except: 138 | print(f"❌ Failed to get response: {e}") 139 | return {"error": f"❌ Failed to get response: {e}"} 140 | 141 | def list_personal_groups(self): 142 | url = f"{self.base_url}/groups" 143 | try: 144 | resp = self.session.get(url) 145 | data_block = resp.content.get("data") 146 | if not data_block: 147 | return [] 148 | 149 | if data_block.get("status") == 200 and data_block.get("message") == "success": 150 | personal = data_block.get("personalGroups", []) 151 | return personal 152 | else: 153 | return [] 154 | except NetworkError as e: 155 | return [] 156 | 157 | def query_private_gpt(self, user_input) -> json: 158 | """Send a question to the chat and retrieve the response.""" 159 | if not self.chat_id: 160 | print("❌ Chat session not initialized.") 161 | return False 162 | url = f"{self.base_url}/chats/{self.chat_id}" 163 | payload = {"question": user_input} 164 | try: 165 | response = self.session.patch(url, json=payload) 166 | #response.raise_for_status() 167 | resp = response.json() 168 | try: 169 | answer = resp.get('data', None).get('answer', "error") 170 | except: 171 | print(response.json()) 172 | resp = {"data" : 173 | {"answer": "error"} 174 | } 175 | answer = "error" 176 | 177 | if answer.startswith("{\"role\":"): 178 | answerj = json.loads(answer) 179 | resp["data"]["answer"] = answerj["content"] 180 | resp["data"]["chatId"] = "0" 181 | 182 | print(f"💡 Response: {answer}") 183 | return resp 184 | except requests.exceptions.RequestException as e: 185 | # It seems we get disconnections from time to time.. 186 | #print(f"⚠️ Failed to get response on first try, trying again..: {e}") 187 | try: 188 | response = self.session.patch(url, json=payload) 189 | response.raise_for_status() 190 | data = response.json() 191 | answer = data.get('data', {}).get('answer', "No answer provided.") 192 | print(f"💡 Response: {answer}") 193 | return data 194 | except: 195 | print(f"❌ Failed to get response: {e}") 196 | return {"error": f"❌ Failed to get response: {e}"} 197 | 198 | 199 | def get_document_info(self, source_id): 200 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 201 | url = f"{self.base_url}/sources/{source_id}" 202 | try: 203 | response = self.session.get(url) 204 | data = response.json() 205 | info = data.get('data', {}) 206 | print(f"💡 Response: {str(info)}") 207 | return data 208 | except requests.exceptions.RequestException as e: 209 | print(f"❌ Failed to get response: {e}") 210 | return {"error": f"❌ Failed to get response: {e}"} 211 | 212 | 213 | def respond_with_context(self, messages, response_format=None, request_tools=None): 214 | last_user_message = next((p for p in reversed(messages) if p.role == "user"), None) 215 | user_input = "" 216 | 217 | 218 | for message in messages: 219 | if message.role == "system": 220 | user_input = str(message) + "\n" 221 | 222 | if last_user_message is not None: 223 | user_input += last_user_message.content 224 | 225 | last_assistant_message = next((p for p in reversed(messages) if p.role == "assistant"), None) 226 | last_tool_message = next((p for p in reversed(messages) if p.role == "tool"), None) 227 | 228 | hastoolresult = False 229 | if last_tool_message is not None and last_assistant_message is not None and last_assistant_message.tool_calls is not None and len(last_assistant_message.tool_calls) > 0: 230 | user_input += "\nYou called the tool: " + str(last_assistant_message.tool_calls[0]) + ". The result was: " + last_tool_message.content 231 | hastoolresult = True 232 | 233 | 234 | print(f"💁 Request: " + user_input) 235 | 236 | # PGPT manages history and context itself so we don't need to forward the history. 237 | add_context = False 238 | if add_context: 239 | messages.pop() 240 | user_input += "\nHere is some context about the previous conversation:\n" 241 | for message in messages: 242 | user_input += f"{message.role}: {message.content}\n" 243 | 244 | if response_format is not None: 245 | print("Response format: " + str(response_format)) 246 | user_input += add_response_format(response_format) 247 | 248 | if request_tools is not None and not hastoolresult: 249 | user_input += add_tools(request_tools, last_tool_message) 250 | 251 | if not self.logged_in: 252 | self.login() 253 | else: 254 | if self.chat_id is None: 255 | result = self.create_chat(user_input) 256 | else: 257 | result = self.query_private_gpt(user_input) 258 | 259 | if 'data' in result: 260 | response_data = result.get("data") 261 | if request_tools is not None and not hastoolresult and is_json(clean_response(response_data.get("answer"))): 262 | response_data["tool_call"] = clean_response(response_data.get("answer", "")) 263 | return response_data 264 | elif 'error' in result: 265 | # Try to login again and send the query once more on error. 266 | if self.login(): 267 | if self.chat_id is None: 268 | result = self.create_chat(user_input) 269 | else: 270 | result = self.query_private_gpt(user_input) 271 | 272 | if 'data' in result: 273 | return result['data'] 274 | else: 275 | return result 276 | 277 | else: 278 | return result 279 | 280 | def is_json(myjson): 281 | try: 282 | json.loads(myjson) 283 | except ValueError as e: 284 | return False 285 | return True 286 | 287 | def add_response_format(response_format): 288 | #prompt = "\nPlease fill in the following template with realistic and appropriate information. Be creative. The field 'type' defines the output format. In your reply, only return the generated json\n" 289 | prompt = "\nPlease fill in the following json template with realistic and appropriate information. In your reply, only return the generated json. If you can't answer return an empty json.\n" 290 | prompt += json.dumps(response_format) 291 | return prompt 292 | 293 | 294 | def add_tools(response_tools, last_tool_message): 295 | 296 | prompt = "\nPlease select the fitting provided tool to create your answer. Only return the generated result of the tool. Do not describe what you are doing, just return the json.\n" 297 | index = 1 298 | for tool in response_tools: 299 | prompt += "\n" + json.dumps(tool) + "\n" 300 | index += 1 301 | 302 | return prompt 303 | 304 | def clean_response(response): 305 | # Remove artefacts from reply here 306 | response = response.replace("[TOOL_CALLS]", "") 307 | return response 308 | 309 | def decrypt_api_key(api_key): 310 | """ 311 | This is PoC code and methods should be replaced with a more secure way to deal with credentials (e.g. in a db) 312 | """ 313 | try: 314 | base64_bytes = api_key.encode("ascii") 315 | decoded_string_bytes = base64.b64decode(base64_bytes) 316 | decoded_key = decoded_string_bytes.decode("ascii") 317 | except Exception as e: 318 | print(e) 319 | decoded_key = "invalid:invalid" 320 | 321 | return decoded_key.split(":")[0], decoded_key.split(":")[1] 322 | 323 | 324 | def main(): 325 | """Main function to run the chat application.""" 326 | config_file = Path.absolute(Path(__file__).parent.parent / "pgpt_openai_api_proxy.json") 327 | config = Config(config_file=config_file, required_fields=["base_url"]) 328 | chat = PrivateGPTAPI(config) 329 | 330 | print("Type your questions below. Type 'quit' to exit.") 331 | while True: 332 | try: 333 | question = input("❓ Question: ").strip() 334 | if question.lower() == 'quit': 335 | break 336 | if question: 337 | chat.query_private_gpt(question) 338 | except KeyboardInterrupt: 339 | print("\nExiting chat...") 340 | break 341 | except Exception as e: 342 | print(f"❌ Error: {str(e)}") 343 | break 344 | 345 | 346 | if __name__ == "__main__": 347 | main() ``` -------------------------------------------------------------------------------- /clients/Gradio/logos/Logo_dark.svg: -------------------------------------------------------------------------------- ``` 1 | <svg width="2227" height="1024" viewBox="0 0 600 1024" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M2811.31 775.828V157.115H2568.68V19.2558H3220.48V157.115H2976.74V775.828H2811.31Z" fill="url(#paint0_linear_3311_10229)" fill-opacity="0.9"/> 3 | <path d="M1881.39 775.828V19.2558H2275.12C2329.52 19.2558 2374.74 29.5493 2410.77 50.1363C2447.53 69.988 2475.1 98.2952 2493.48 135.058C2512.6 171.085 2522.16 214.097 2522.16 264.094C2522.16 314.091 2512.23 357.839 2492.38 395.336C2473.27 432.099 2444.96 460.774 2407.46 481.361C2369.96 501.948 2324.01 512.241 2269.6 512.241H2045.72V775.828H1881.39ZM2045.72 377.69H2247.54C2282.1 377.69 2308.57 367.764 2326.95 347.913C2346.07 328.061 2355.63 300.489 2355.63 265.197C2355.63 240.934 2351.58 220.714 2343.49 204.539C2335.41 188.363 2323.27 175.864 2307.1 167.041C2291.66 158.218 2271.81 153.807 2247.54 153.807H2045.72V377.69Z" fill="url(#paint1_linear_3311_10229)" fill-opacity="0.9"/> 4 | <path d="M1353.48 789.065C1234.37 789.065 1142.47 757.449 1077.76 694.217C1013.8 630.25 981.814 531.359 981.814 397.544C981.814 308.579 997.254 235.421 1028.13 178.072C1059.01 119.987 1103.86 76.9747 1162.69 49.0352C1221.51 20.3604 1292.09 6.02307 1374.44 6.02307C1423.7 6.02307 1470.02 11.5374 1513.4 22.5662C1556.78 33.5949 1595.01 50.5057 1628.1 73.2984C1661.92 96.0912 1688.02 124.766 1706.4 159.323C1725.52 193.144 1735.08 233.583 1735.08 280.639H1568.54C1568.54 257.846 1563.4 237.627 1553.1 219.981C1543.54 202.335 1529.94 187.63 1512.3 175.866C1494.65 164.102 1474.43 155.279 1451.64 149.397C1428.85 143.515 1404.95 140.574 1379.95 140.574C1341.72 140.574 1308.26 145.721 1279.59 156.014C1250.92 165.572 1227.02 180.645 1207.9 201.232C1189.52 221.084 1175.55 246.082 1165.99 276.228C1156.44 306.373 1151.66 341.297 1151.66 381.001V414.087C1151.66 469.231 1159.74 514.449 1175.92 549.741C1192.1 585.033 1216.36 611.502 1248.71 629.148C1281.06 646.058 1321.13 654.514 1368.92 654.514C1408.63 654.514 1443.55 648.632 1473.7 636.868C1504.58 624.369 1528.47 606.723 1545.38 583.93C1563.03 561.137 1571.85 533.198 1571.85 500.111V492.391H1345.76V366.663H1735.08V775.83H1627L1612.66 694.217C1590.6 715.539 1566.71 733.186 1540.97 747.155C1515.97 761.125 1488.03 771.419 1457.15 778.036C1426.27 785.388 1391.72 789.065 1353.48 789.065Z" fill="url(#paint2_linear_3311_10229)" fill-opacity="0.9"/> 5 | <path fill-rule="evenodd" clip-rule="evenodd" d="M6.02344 89.6842C6.02344 50.135 37.9352 18.074 77.3003 18.074H481.202C691.15 18.074 861.346 189.066 861.346 399.995C861.346 610.924 691.15 781.916 481.202 781.916H250.986L47.4726 1009.97C32.9221 1026.28 6.02344 1015.94 6.02344 994.04V89.6842ZM218.262 247.835C218.262 238.435 225.864 230.815 235.241 230.815H480.672C573.696 230.815 649.107 306.405 649.107 399.649C649.107 492.893 573.696 568.483 480.672 568.483H355.38L246.959 686.671C228.889 698.718 218.262 685.675 218.262 674.629V247.835Z" fill="url(#paint3_linear_3311_10229)"/> 6 | <path fill-rule="evenodd" clip-rule="evenodd" d="M1374.44 12.0468C1292.77 12.0468 1223.14 26.2657 1165.32 54.4498L1165.27 54.4763C1107.63 81.8548 1063.73 123.944 1033.45 180.899L1033.44 180.928C1003.17 237.137 987.837 309.228 987.837 397.544C987.837 530.507 1019.62 627.541 1082 689.935C1145.25 751.736 1235.45 783.042 1353.48 783.042C1391.34 783.042 1425.42 779.401 1455.76 772.177L1455.89 772.145C1486.24 765.641 1513.61 755.546 1538.03 741.898L1538.1 741.862C1563.33 728.165 1586.79 710.848 1608.47 689.887L1616.63 682.003L1632.05 769.807H1729.05V372.687H1351.79V486.368H1577.88V500.112C1577.88 534.302 1568.74 563.575 1550.19 587.566C1532.51 611.369 1507.66 629.618 1475.96 642.452L1475.89 642.479C1444.9 654.57 1409.21 660.538 1368.92 660.538C1320.45 660.538 1279.36 651.965 1245.92 634.486L1245.82 634.437C1212.27 616.134 1187.13 588.657 1170.44 552.251C1153.79 515.913 1145.63 469.759 1145.63 414.087V381.001C1145.63 340.83 1150.47 305.269 1160.25 274.407C1170.03 243.559 1184.41 217.744 1203.48 197.14C1223.32 175.773 1248.09 160.176 1277.62 150.322C1307.07 139.759 1341.22 134.551 1379.95 134.551C1405.43 134.551 1429.83 137.548 1453.14 143.565C1476.52 149.597 1497.37 158.677 1515.64 170.854C1534.03 183.113 1548.31 198.51 1558.36 217.032C1568.29 234.088 1573.61 253.327 1574.45 274.616H1729C1728.22 230.974 1718.86 193.6 1701.16 162.287L1701.08 162.153C1683.18 128.504 1657.77 100.559 1624.73 78.2938L1624.68 78.2591C1592.25 55.9144 1554.68 39.2771 1511.92 28.4042C1469.07 17.5104 1423.25 12.0468 1374.44 12.0468ZM1160.07 43.6073C1219.9 14.4512 1291.42 0 1374.44 0C1424.15 0 1470.97 5.56508 1514.88 16.7288C1558.86 27.9096 1597.75 45.0862 1631.48 68.3154C1666.06 91.6183 1692.82 120.997 1711.68 156.424C1731.38 191.309 1741.1 232.793 1741.1 280.639V286.663H1562.52V280.639C1562.52 258.787 1557.6 239.638 1547.9 223.016L1547.85 222.934L1547.81 222.85C1538.74 206.116 1525.83 192.129 1508.96 180.878C1491.93 169.527 1472.34 160.961 1450.13 155.23C1427.86 149.482 1404.47 146.598 1379.95 146.598C1342.24 146.598 1309.5 151.676 1281.62 161.684L1281.5 161.73C1253.71 170.993 1230.7 185.537 1212.32 205.325C1194.64 224.425 1181.07 248.607 1171.74 278.048C1162.4 307.477 1157.68 341.765 1157.68 381.001V414.087C1157.68 468.703 1165.7 512.985 1181.4 547.231C1197.05 581.393 1220.42 606.846 1251.55 623.835C1282.81 640.162 1321.84 648.491 1368.92 648.491C1408.03 648.491 1442.17 642.699 1471.47 631.271C1501.49 619.115 1524.41 602.092 1540.55 580.341L1540.62 580.242C1557.33 558.657 1565.83 532.07 1565.83 500.112V498.415H1339.74V360.64H1741.1V781.854H1621.94L1608.65 706.226C1588.53 724.502 1566.94 739.91 1543.88 752.433C1518.33 766.704 1489.85 777.184 1458.48 783.911C1427.08 791.382 1392.07 795.088 1353.48 795.088C1233.31 795.088 1139.7 763.171 1073.55 698.525L1073.5 698.477C1007.96 632.937 975.79 532.196 975.79 397.544C975.79 307.931 991.336 233.707 1022.83 175.218M0 89.6845C0 46.8352 34.582 12.0509 77.3003 12.0509H481.202C694.503 12.0509 867.369 185.766 867.369 399.995C867.369 614.225 694.503 787.94 481.202 787.94H253.684L51.9667 1013.98C33.6916 1034.46 0 1021.41 0 994.04V89.6845ZM77.3003 24.0977C41.2882 24.0977 12.0468 53.4354 12.0468 89.6845V994.04C12.0468 1010.47 32.1526 1018.1 42.9784 1005.96L248.288 775.893H481.202C687.797 775.893 855.322 607.625 855.322 399.995C855.322 192.366 687.797 24.0977 481.202 24.0977H77.3003ZM1875.37 13.2327H2275.12C2330.22 13.2327 2376.53 23.6501 2413.69 44.8695C2451.47 65.286 2479.91 94.4615 2498.84 132.299C2518.49 169.358 2528.18 213.362 2528.18 264.094C2528.18 314.894 2518.09 359.637 2497.71 398.144C2497.71 398.147 2497.71 398.151 2497.71 398.155L2492.38 395.337L2497.73 398.116C2497.72 398.125 2497.72 398.134 2497.71 398.144C2478.03 435.986 2448.86 465.505 2410.36 486.641C2371.76 507.831 2324.75 518.265 2269.6 518.265H2051.74V512.241H2045.72V518.265H2051.74V781.852H1875.37V13.2327ZM1887.41 25.2795V769.805H2039.69V506.218H2269.6C2323.27 506.218 2368.16 496.065 2404.56 476.081C2441.05 456.048 2468.49 428.227 2487.04 392.558L2487.06 392.518C2506.38 356.032 2516.14 313.284 2516.14 264.094C2516.14 214.862 2506.73 172.864 2488.16 137.881L2488.1 137.753C2470.28 102.117 2443.6 74.7103 2407.91 55.4366L2407.78 55.3679C2372.9 35.4384 2328.79 25.2795 2275.12 25.2795H1887.41ZM2562.65 13.2327H3226.5V163.139H2982.76V781.852H2805.29V163.139H2562.65V13.2327ZM2574.7 25.2795V151.092H2817.33V769.805H2970.72V151.092H3214.45V25.2795H2574.7ZM2039.69 147.784H2247.54C2272.46 147.784 2293.42 152.303 2310.03 161.781C2327.24 171.18 2340.24 184.565 2348.88 201.845C2357.5 219.093 2361.65 240.304 2361.65 265.197C2361.65 301.566 2351.78 330.785 2331.33 352.045C2311.52 373.422 2283.26 383.714 2247.54 383.714H2039.69V147.784ZM2051.74 159.83V371.667H2247.54C2280.92 371.667 2305.59 362.12 2322.53 343.821L2322.61 343.735C2340.37 325.296 2349.6 299.387 2349.6 265.197C2349.6 241.564 2345.66 222.337 2338.11 207.233C2330.58 192.179 2319.33 180.575 2304.21 172.329L2304.11 172.271C2289.85 164.124 2271.12 159.83 2247.54 159.83H2051.74ZM212.239 247.835C212.239 235.122 222.524 224.792 235.241 224.792H480.672C577.036 224.792 655.13 303.092 655.13 399.649C655.13 496.207 577.036 574.507 480.672 574.507H358.029L250.906 691.279L250.3 691.683C239.904 698.614 230.088 699.168 222.595 694.389C215.629 689.945 212.239 681.805 212.239 674.629V247.835ZM235.241 236.839C229.204 236.839 224.286 241.749 224.286 247.835V674.629C224.286 678.501 226.208 682.404 229.074 684.232C231.351 685.685 235.713 686.721 243.031 682.043L352.732 562.46H480.672C570.356 562.46 643.083 489.58 643.083 399.649C643.083 309.718 570.356 236.839 480.672 236.839H235.241Z" fill="url(#paint4_linear_3311_10229)" fill-opacity="0.6"/> 7 | <path fill-rule="evenodd" clip-rule="evenodd" d="M1374.44 12.0468C1292.77 12.0468 1223.14 26.2657 1165.32 54.4498L1165.27 54.4763C1107.63 81.8548 1063.73 123.944 1033.45 180.899L1033.44 180.928C1003.17 237.137 987.837 309.228 987.837 397.544C987.837 530.507 1019.62 627.541 1082 689.935C1145.25 751.736 1235.45 783.042 1353.48 783.042C1391.34 783.042 1425.42 779.401 1455.76 772.177L1455.89 772.145C1486.24 765.641 1513.61 755.546 1538.03 741.898L1538.1 741.862C1563.33 728.165 1586.79 710.848 1608.47 689.887L1616.63 682.003L1632.05 769.807H1729.05V372.687H1351.79V486.368H1577.88V500.112C1577.88 534.302 1568.74 563.575 1550.19 587.566C1532.51 611.369 1507.66 629.618 1475.96 642.452L1475.89 642.479C1444.9 654.57 1409.21 660.538 1368.92 660.538C1320.45 660.538 1279.36 651.965 1245.92 634.486L1245.82 634.437C1212.27 616.134 1187.13 588.657 1170.44 552.251C1153.79 515.913 1145.63 469.759 1145.63 414.087V381.001C1145.63 340.83 1150.47 305.269 1160.25 274.407C1170.03 243.559 1184.41 217.744 1203.48 197.14C1223.32 175.773 1248.09 160.176 1277.62 150.322C1307.07 139.759 1341.22 134.551 1379.95 134.551C1405.43 134.551 1429.83 137.548 1453.14 143.565C1476.52 149.597 1497.37 158.677 1515.64 170.854C1534.03 183.113 1548.31 198.51 1558.36 217.032C1568.29 234.088 1573.61 253.327 1574.45 274.616H1729C1728.22 230.974 1718.86 193.6 1701.16 162.287L1701.08 162.153C1683.18 128.504 1657.77 100.559 1624.73 78.2938L1624.68 78.2591C1592.25 55.9144 1554.68 39.2771 1511.92 28.4042C1469.07 17.5104 1423.25 12.0468 1374.44 12.0468ZM1160.07 43.6073C1219.9 14.4512 1291.42 0 1374.44 0C1424.15 0 1470.97 5.56508 1514.88 16.7288C1558.86 27.9096 1597.75 45.0862 1631.48 68.3154C1666.06 91.6183 1692.82 120.997 1711.68 156.424C1731.38 191.309 1741.1 232.793 1741.1 280.639V286.663H1562.52V280.639C1562.52 258.787 1557.6 239.638 1547.9 223.016L1547.85 222.934L1547.81 222.85C1538.74 206.116 1525.83 192.129 1508.96 180.878C1491.93 169.527 1472.34 160.961 1450.13 155.23C1427.86 149.482 1404.47 146.598 1379.95 146.598C1342.24 146.598 1309.5 151.676 1281.62 161.684L1281.5 161.73C1253.71 170.993 1230.7 185.537 1212.32 205.325C1194.64 224.425 1181.07 248.607 1171.74 278.048C1162.4 307.477 1157.68 341.765 1157.68 381.001V414.087C1157.68 468.703 1165.7 512.985 1181.4 547.231C1197.05 581.393 1220.42 606.846 1251.55 623.835C1282.81 640.162 1321.84 648.491 1368.92 648.491C1408.03 648.491 1442.17 642.699 1471.47 631.271C1501.49 619.115 1524.41 602.092 1540.55 580.341L1540.62 580.242C1557.33 558.657 1565.83 532.07 1565.83 500.112V498.415H1339.74V360.64H1741.1V781.854H1621.94L1608.65 706.226C1588.53 724.502 1566.94 739.91 1543.88 752.433C1518.33 766.704 1489.85 777.184 1458.48 783.911C1427.08 791.382 1392.07 795.088 1353.48 795.088C1233.31 795.088 1139.7 763.171 1073.55 698.525L1073.5 698.477C1007.96 632.937 975.79 532.196 975.79 397.544C975.79 307.931 991.336 233.707 1022.83 175.218M0 89.6845C0 46.8352 34.582 12.0509 77.3003 12.0509H481.202C694.503 12.0509 867.369 185.766 867.369 399.995C867.369 614.225 694.503 787.94 481.202 787.94H253.684L51.9667 1013.98C33.6916 1034.46 0 1021.41 0 994.04V89.6845ZM77.3003 24.0977C41.2882 24.0977 12.0468 53.4354 12.0468 89.6845V994.04C12.0468 1010.47 32.1526 1018.1 42.9784 1005.96L248.288 775.893H481.202C687.797 775.893 855.322 607.625 855.322 399.995C855.322 192.366 687.797 24.0977 481.202 24.0977H77.3003ZM1875.37 13.2327H2275.12C2330.22 13.2327 2376.53 23.6501 2413.69 44.8695C2451.47 65.286 2479.91 94.4615 2498.84 132.299C2518.49 169.358 2528.18 213.362 2528.18 264.094C2528.18 314.894 2518.09 359.637 2497.71 398.144C2497.71 398.147 2497.71 398.151 2497.71 398.155L2492.38 395.337L2497.73 398.116C2497.72 398.125 2497.72 398.134 2497.71 398.144C2478.03 435.986 2448.86 465.505 2410.36 486.641C2371.76 507.831 2324.75 518.265 2269.6 518.265H2051.74V512.241H2045.72V518.265H2051.74V781.852H1875.37V13.2327ZM1887.41 25.2795V769.805H2039.69V506.218H2269.6C2323.27 506.218 2368.16 496.065 2404.56 476.081C2441.05 456.048 2468.49 428.227 2487.04 392.558L2487.06 392.518C2506.38 356.032 2516.14 313.284 2516.14 264.094C2516.14 214.862 2506.73 172.864 2488.16 137.881L2488.1 137.753C2470.28 102.117 2443.6 74.7103 2407.91 55.4366L2407.78 55.3679C2372.9 35.4384 2328.79 25.2795 2275.12 25.2795H1887.41ZM2562.65 13.2327H3226.5V163.139H2982.76V781.852H2805.29V163.139H2562.65V13.2327ZM2574.7 25.2795V151.092H2817.33V769.805H2970.72V151.092H3214.45V25.2795H2574.7ZM2039.69 147.784H2247.54C2272.46 147.784 2293.42 152.303 2310.03 161.781C2327.24 171.18 2340.24 184.565 2348.88 201.845C2357.5 219.093 2361.65 240.304 2361.65 265.197C2361.65 301.566 2351.78 330.785 2331.33 352.045C2311.52 373.422 2283.26 383.714 2247.54 383.714H2039.69V147.784ZM2051.74 159.83V371.667H2247.54C2280.92 371.667 2305.59 362.12 2322.53 343.821L2322.61 343.735C2340.37 325.296 2349.6 299.387 2349.6 265.197C2349.6 241.564 2345.66 222.337 2338.11 207.233C2330.58 192.179 2319.33 180.575 2304.21 172.329L2304.11 172.271C2289.85 164.124 2271.12 159.83 2247.54 159.83H2051.74ZM212.239 247.835C212.239 235.122 222.524 224.792 235.241 224.792H480.672C577.036 224.792 655.13 303.092 655.13 399.649C655.13 496.207 577.036 574.507 480.672 574.507H358.029L250.906 691.279L250.3 691.683C239.904 698.614 230.088 699.168 222.595 694.389C215.629 689.945 212.239 681.805 212.239 674.629V247.835ZM235.241 236.839C229.204 236.839 224.286 241.749 224.286 247.835V674.629C224.286 678.501 226.208 682.404 229.074 684.232C231.351 685.685 235.713 686.721 243.031 682.043L352.732 562.46H480.672C570.356 562.46 643.083 489.58 643.083 399.649C643.083 309.718 570.356 236.839 480.672 236.839H235.241Z" fill="url(#paint5_linear_3311_10229)" fill-opacity="0.15"/> 8 | <defs> 9 | 10 | <linearGradient id="paint3_linear_3311_10229" x1="6.02342" y1="1017.95" x2="886.292" y2="40.5368" gradientUnits="userSpaceOnUse"> 11 | <stop stop-color="#3333FF"/> 12 | <stop offset="0.5" stop-color="#980194"/> 13 | <stop offset="1" stop-color="#FE0100"/> 14 | </linearGradient> 15 | 16 | </defs> 17 | </svg> 18 | ``` -------------------------------------------------------------------------------- /examples/dynamic_sources/rss_reader/Api.py: -------------------------------------------------------------------------------- ```python 1 | import json 2 | from pathlib import Path 3 | 4 | import requests 5 | import urllib3 6 | import base64 7 | 8 | from httpcore import NetworkError 9 | 10 | from .config import Config 11 | 12 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 13 | 14 | 15 | def initialize_session(proxy_user, proxy_password, access_header): 16 | """Set up the session with proxy authentication.""" 17 | session = requests.Session() 18 | session.verify = False 19 | headers = { 20 | 'Accept': 'application/json', 21 | 'Content-Type': 'application/json', 22 | } 23 | if access_header is not None: 24 | headers['X-Custom-Header'] = access_header 25 | elif proxy_user is not None and proxy_password is not None: 26 | auth = base64.b64encode(f"{proxy_user}:{proxy_password}".encode()).decode() 27 | headers['Authorization'] = f'Basic {auth}' 28 | session.headers.update(headers) 29 | return session 30 | 31 | 32 | class PrivateGPTAPI: 33 | def __init__(self, config, client_api_key=None): 34 | """Initialize the chat client with proxy authentication.""" 35 | self.token = None 36 | self.chat_id = None 37 | 38 | self.base_url = config.get("base_url") 39 | self.proxy_user = config.get("proxy_user", None) 40 | if self.proxy_user == "": 41 | self.proxy_user = None 42 | self.proxy_password = config.get("proxy_password", None) 43 | if self.proxy_password == "": 44 | self.proxy_password = None 45 | self.access_header = config.get("access_header", None) 46 | if self.access_header == "": 47 | self.access_header = None 48 | 49 | self.chosen_groups = config.get("groups", []) 50 | self.language = config.get("language", "en") 51 | self.use_public = config.get("use_public", True) 52 | self.whitelist_keys = config.get("whitelist_keys", []) 53 | self.logged_in = False 54 | 55 | if client_api_key is not None: 56 | self.email, self.password = decrypt_api_key(client_api_key) 57 | if len(self.whitelist_keys) > 0: 58 | if client_api_key not in self.whitelist_keys: 59 | print("not authorized") 60 | else: 61 | self.email = config.get("email", None) 62 | self.password = config.get("password", None) 63 | 64 | self.session = initialize_session(self.proxy_user, self.proxy_password, self.access_header) 65 | if self.login(): 66 | self.logged_in = True 67 | 68 | def login(self): 69 | """Authenticate the user and retrieve the token.""" 70 | url = f"{self.base_url}/login" 71 | payload = {"email": self.email, "password": self.password} 72 | try: 73 | response = self.session.post(url, json=payload) 74 | print(response.content) 75 | response.raise_for_status() 76 | data = response.json() 77 | self.token = data['data']['token'] 78 | 79 | # Prüfen, ob der Header bereits existiert 80 | if 'Authorization' in self.session.headers: 81 | self.session.headers['Authorization'] += f', Bearer {self.token}' 82 | else: 83 | self.session.headers['Authorization'] = f'Bearer {self.token}' 84 | self.chat_id = None 85 | print("✅ Login successful.") 86 | return True 87 | except requests.exceptions.RequestException as e: 88 | print(f"❌ Login failed: {e}") 89 | return False 90 | 91 | def create_chat(self, user_input): 92 | """Start a new chat session. 93 | 94 | This method sends a POST request to the '/chats' endpoint with the provided parameters. 95 | It initializes a new chat session and stores the chat ID for future use. 96 | """ 97 | url = f"{self.base_url}/chats" 98 | payload = { 99 | "language": self.language, 100 | "question": user_input, # Initial question to start the chat 101 | "usePublic": self.use_public, 102 | "groups": self.chosen_groups 103 | } 104 | try: 105 | response = self.session.post(url, json=payload) 106 | response.raise_for_status() # Raise an exception if the response was not successful 107 | data = response.json() 108 | self.chat_id = data['data']['chatId'] # Store the chat ID for future use 109 | print("✅ Chat initialized.") 110 | resp = response.json() 111 | try: 112 | answer = resp.get('data', None).get('answer', "error") 113 | except: 114 | print(response.json()) 115 | resp = {"data": 116 | {"answer": "error"} 117 | } 118 | answer = "error" 119 | 120 | if answer.startswith("{\"role\":"): 121 | answerj = json.loads(answer) 122 | resp["data"]["answer"] = answerj["content"] 123 | resp["data"]["chatId"] = "0" 124 | 125 | print(f"💡 Response: {answer}") 126 | return resp 127 | except requests.exceptions.RequestException as e: 128 | # It seems we get disconnections from time to time.. 129 | # print(f"⚠️ Failed to get response on first try, trying again..: {e}") 130 | try: 131 | response = self.session.patch(url, json=payload) 132 | response.raise_for_status() 133 | data = response.json() 134 | answer = data.get('data', {}).get('answer', "No answer provided.") 135 | print(f"💡 Response: {answer}") 136 | return data 137 | except: 138 | print(f"❌ Failed to get response: {e}") 139 | return {"error": f"❌ Failed to get response: {e}"} 140 | 141 | def list_personal_groups(self): 142 | url = f"{self.base_url}/groups" 143 | try: 144 | resp = self.session.get(url) 145 | j = json.loads(resp.content) 146 | data_block = j["data"] 147 | if not data_block: 148 | return [] 149 | 150 | personal = data_block.get("personalGroups", []) 151 | return personal 152 | 153 | except NetworkError as e: 154 | return [] 155 | 156 | def get_document_info(self, id): 157 | url = f"{self.base_url}/sources/{id }" 158 | try: 159 | resp = self.session.get(url) 160 | j = json.loads(resp.content) 161 | data_block = j["data"] 162 | if not data_block: 163 | return [] 164 | 165 | return data_block 166 | 167 | except NetworkError as e: 168 | return [] 169 | 170 | def query_private_gpt(self, user_input) -> json: 171 | """Send a question to the chat and retrieve the response.""" 172 | if not self.chat_id: 173 | print("❌ Chat session not initialized.") 174 | return False 175 | url = f"{self.base_url}/chats/{self.chat_id}" 176 | payload = {"question": user_input} 177 | try: 178 | response = self.session.patch(url, json=payload) 179 | # response.raise_for_status() 180 | resp = response.json() 181 | try: 182 | answer = resp.get('data', None).get('answer', "error") 183 | except: 184 | print(response.json()) 185 | resp = {"data": 186 | {"answer": "error"} 187 | } 188 | answer = "error" 189 | 190 | if answer.startswith("{\"role\":"): 191 | answerj = json.loads(answer) 192 | resp["data"]["answer"] = answerj["content"] 193 | resp["data"]["chatId"] = "0" 194 | 195 | print(f"💡 Response: {answer}") 196 | return resp 197 | except requests.exceptions.RequestException as e: 198 | # It seems we get disconnections from time to time.. 199 | # print(f"⚠️ Failed to get response on first try, trying again..: {e}") 200 | try: 201 | response = self.session.patch(url, json=payload) 202 | response.raise_for_status() 203 | data = response.json() 204 | answer = data.get('data', {}).get('answer', "No answer provided.") 205 | print(f"💡 Response: {answer}") 206 | return data 207 | except: 208 | print(f"❌ Failed to get response: {e}") 209 | return {"error": f"❌ Failed to get response: {e}"} 210 | 211 | 212 | def add_source(self, markdown, groups, name): 213 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 214 | url = f"{self.base_url}/sources" 215 | try: 216 | 217 | payload = { 218 | "name": name, 219 | "groups": groups, 220 | "content": markdown 221 | } 222 | 223 | resp = self.session.post(url, json=payload) 224 | j = json.loads(resp.content) 225 | data_block = j["data"] 226 | if not data_block: 227 | return [] 228 | 229 | return data_block 230 | 231 | except requests.exceptions.RequestException as e: 232 | print(f"❌ Failed to get response: {e}") 233 | return {"error": f"❌ Failed to get response: {e}"} 234 | 235 | def update_source(self, source_id, markdown=None, groups=None, name=None): 236 | """Edit an existing Source""" 237 | url = f"{self.base_url}/sources/{source_id}" 238 | 239 | try: 240 | payload = {} 241 | if groups is None: 242 | existing_groups = self.get_document_info(source_id)["groups"] 243 | payload["groups"] = existing_groups 244 | else: 245 | payload["groups"] = groups 246 | 247 | if markdown is not None: 248 | payload["content"] = markdown 249 | if name is not None: 250 | payload["name"] = name 251 | 252 | resp = self.session.patch(url, json=payload) 253 | 254 | j = json.loads(resp.content) 255 | data_block = j["data"] 256 | if not data_block: 257 | return [] 258 | 259 | return data_block 260 | 261 | except requests.exceptions.RequestException as e: 262 | print(f"❌ Failed to get response: {e}") 263 | return {"error": f"❌ Failed to get response: {e}"} 264 | 265 | def delete_source(self, source_id): 266 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 267 | url = f"{self.base_url}/sources/{source_id}" 268 | try: 269 | 270 | resp = self.session.delete(url) 271 | j = json.loads(resp.content) 272 | message = j["message"] 273 | if not message: 274 | return "failed" 275 | 276 | return message 277 | 278 | 279 | except requests.exceptions.RequestException as e: 280 | print(f"❌ Failed to get response: {e}") 281 | return {"error": f"❌ Failed to get response: {e}"} 282 | 283 | 284 | def get_sources_from_group(self, group): 285 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 286 | url = f"{self.base_url}/sources/groups" 287 | try: 288 | 289 | payload = { 290 | "groupName": group 291 | } 292 | 293 | resp = self.session.post(url, json=payload) 294 | j = json.loads(resp.content) 295 | data_block = j["data"] 296 | if not data_block: 297 | return [] 298 | 299 | sources = [] 300 | for source in data_block["sources"]: 301 | doc = self.get_document_info(source) 302 | sources.append(doc) 303 | 304 | 305 | return sources 306 | 307 | 308 | except requests.exceptions.RequestException as e: 309 | print(f"❌ Failed to get response: {e}") 310 | return {"error": f"❌ Failed to get response: {e}"} 311 | 312 | def respond_with_context(self, messages, response_format=None, request_tools=None): 313 | last_user_message = next((p for p in reversed(messages) if p["role"] == "user"), None) 314 | user_input = "" 315 | 316 | for message in messages: 317 | if message["role"] == "system": 318 | user_input = str(message) + "\n" 319 | 320 | if last_user_message is not None: 321 | user_input += last_user_message["content"] 322 | 323 | last_assistant_message = next((p for p in reversed(messages) if p["role"] == "assistant"), None) 324 | last_tool_message = next((p for p in reversed(messages) if p["role"] == "tool"), None) 325 | 326 | hastoolresult = False 327 | if last_tool_message is not None and last_assistant_message is not None and last_assistant_message.tool_calls is not None and len( 328 | last_assistant_message.tool_calls) > 0: 329 | user_input += "\nYou called the tool: " + str( 330 | last_assistant_message.tool_calls[0]) + ". The result was: " + last_tool_message.content 331 | hastoolresult = True 332 | 333 | print(f"💁 Request: " + user_input) 334 | 335 | # PGPT manages history and context itself so we don't need to forward the history. 336 | add_context = False 337 | if add_context: 338 | messages.pop() 339 | user_input += "\nHere is some context about the previous conversation:\n" 340 | for message in messages: 341 | user_input += f"{message.role}: {message.content}\n" 342 | 343 | if response_format is not None: 344 | print("Response format: " + str(response_format)) 345 | user_input += add_response_format(response_format) 346 | 347 | if request_tools is not None and not hastoolresult: 348 | user_input += add_tools(request_tools, last_tool_message) 349 | 350 | if not self.logged_in: 351 | self.login() 352 | else: 353 | if self.chat_id is None: 354 | result = self.create_chat(user_input) 355 | else: 356 | result = self.query_private_gpt(user_input) 357 | 358 | if 'data' in result: 359 | response_data = result.get("data") 360 | if request_tools is not None and not hastoolresult and is_json( 361 | clean_response(response_data.get("answer"))): 362 | response_data["tool_call"] = clean_response(response_data.get("answer", "")) 363 | return response_data 364 | elif 'error' in result: 365 | # Try to login again and send the query once more on error. 366 | if self.login(): 367 | if self.chat_id is None: 368 | result = self.create_chat(user_input) 369 | else: 370 | result = self.query_private_gpt(user_input) 371 | 372 | if 'data' in result: 373 | return result['data'] 374 | else: 375 | return result 376 | 377 | else: 378 | return result 379 | 380 | 381 | def is_json(myjson): 382 | try: 383 | json.loads(myjson) 384 | except ValueError as e: 385 | return False 386 | return True 387 | 388 | 389 | def add_response_format(response_format): 390 | # prompt = "\nPlease fill in the following template with realistic and appropriate information. Be creative. The field 'type' defines the output format. In your reply, only return the generated json\n" 391 | prompt = "\nPlease fill in the following json template with realistic and appropriate information. In your reply, only return the generated json. If you can't answer return an empty json.\n" 392 | prompt += json.dumps(response_format) 393 | return prompt 394 | 395 | 396 | def add_tools(response_tools, last_tool_message): 397 | prompt = "\nPlease select the fitting provided tool to create your answer. Only return the generated result of the tool. Do not describe what you are doing, just return the json.\n" 398 | index = 1 399 | for tool in response_tools: 400 | prompt += "\n" + json.dumps(tool) + "\n" 401 | index += 1 402 | 403 | return prompt 404 | 405 | 406 | def clean_response(response): 407 | # Remove artefacts from reply here 408 | response = response.replace("[TOOL_CALLS]", "") 409 | return response 410 | 411 | 412 | def decrypt_api_key(api_key): 413 | """ 414 | This is PoC code and methods should be replaced with a more secure way to deal with credentials (e.g. in a db) 415 | """ 416 | try: 417 | base64_bytes = api_key.encode("ascii") 418 | decoded_string_bytes = base64.b64decode(base64_bytes) 419 | decoded_key = decoded_string_bytes.decode("ascii") 420 | except Exception as e: 421 | print(e) 422 | decoded_key = "invalid:invalid" 423 | 424 | return decoded_key.split(":")[0], decoded_key.split(":")[1] 425 | 426 | 427 | def main(): 428 | """Main function to run the chat application.""" 429 | config_file = Path.absolute(Path(__file__).parent.parent / "pgpt_openai_api_proxy.json") 430 | config = Config(config_file=config_file, required_fields=["base_url"]) 431 | chat = PrivateGPTAPI(config) 432 | 433 | print("Type your questions below. Type 'quit' to exit.") 434 | while True: 435 | try: 436 | question = input("❓ Question: ").strip() 437 | if question.lower() == 'quit': 438 | break 439 | if question: 440 | chat.query_private_gpt(question) 441 | except KeyboardInterrupt: 442 | print("\nExiting chat...") 443 | break 444 | except Exception as e: 445 | print(f"❌ Error: {str(e)}") 446 | break 447 | 448 | 449 | if __name__ == "__main__": 450 | main() ``` -------------------------------------------------------------------------------- /clients/Gradio/mcp_servers/pgpt/Api.py: -------------------------------------------------------------------------------- ```python 1 | import json 2 | from pathlib import Path 3 | 4 | import requests 5 | import urllib3 6 | import base64 7 | 8 | from httpcore import NetworkError 9 | 10 | from config import Config 11 | 12 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 13 | 14 | 15 | def initialize_session(proxy_user, proxy_password, access_header): 16 | """Set up the session with proxy authentication.""" 17 | session = requests.Session() 18 | session.verify = False 19 | headers = { 20 | 'Accept': 'application/json', 21 | 'Content-Type': 'application/json', 22 | } 23 | if access_header is not None: 24 | headers['X-Custom-Header'] = access_header 25 | elif proxy_user is not None and proxy_password is not None: 26 | auth = base64.b64encode(f"{proxy_user}:{proxy_password}".encode()).decode() 27 | headers['Authorization'] = f'Basic {auth}' 28 | session.headers.update(headers) 29 | return session 30 | 31 | 32 | class PrivateGPTAPI: 33 | def __init__(self, config, client_api_key=None): 34 | """Initialize the chat client with proxy authentication.""" 35 | self.token = None 36 | self.chat_id = None 37 | 38 | self.base_url = config.get("base_url") 39 | self.proxy_user = config.get("proxy_user", None) 40 | if self.proxy_user == "": 41 | self.proxy_user = None 42 | self.proxy_password = config.get("proxy_password", None) 43 | if self.proxy_password == "": 44 | self.proxy_password = None 45 | self.access_header = config.get("access_header", None) 46 | if self.access_header == "": 47 | self.access_header = None 48 | 49 | self.chosen_groups = config.get("groups", []) 50 | self.language = config.get("language", "en") 51 | self.use_public = config.get("use_public", True) 52 | self.whitelist_keys = config.get("whitelist_keys", []) 53 | self.logged_in = False 54 | 55 | if client_api_key is not None: 56 | self.email, self.password = decrypt_api_key(client_api_key) 57 | if len(self.whitelist_keys) > 0: 58 | if client_api_key not in self.whitelist_keys: 59 | print("not authorized") 60 | else: 61 | self.email = config.get("email", None) 62 | self.password = config.get("password", None) 63 | 64 | self.session = initialize_session(self.proxy_user, self.proxy_password, self.access_header) 65 | if self.login(): 66 | self.logged_in = True 67 | 68 | def login(self): 69 | """Authenticate the user and retrieve the token.""" 70 | url = f"{self.base_url}/login" 71 | payload = {"email": self.email, "password": self.password} 72 | try: 73 | response = self.session.post(url, json=payload) 74 | print(response.content) 75 | response.raise_for_status() 76 | data = response.json() 77 | self.token = data['data']['token'] 78 | 79 | # Prüfen, ob der Header bereits existiert 80 | if 'Authorization' in self.session.headers: 81 | self.session.headers['Authorization'] += f', Bearer {self.token}' 82 | else: 83 | self.session.headers['Authorization'] = f'Bearer {self.token}' 84 | self.chat_id = None 85 | print("✅ Login successful.") 86 | return True 87 | except requests.exceptions.RequestException as e: 88 | print(f"❌ Login failed: {e}") 89 | return False 90 | 91 | def create_chat(self, user_input): 92 | """Start a new chat session. 93 | 94 | This method sends a POST request to the '/chats' endpoint with the provided parameters. 95 | It initializes a new chat session and stores the chat ID for future use. 96 | """ 97 | url = f"{self.base_url}/chats" 98 | payload = { 99 | "language": self.language, 100 | "question": user_input, # Initial question to start the chat 101 | "usePublic": self.use_public, 102 | "groups": self.chosen_groups 103 | } 104 | try: 105 | response = self.session.post(url, json=payload) 106 | response.raise_for_status() # Raise an exception if the response was not successful 107 | data = response.json() 108 | self.chat_id = data['data']['chatId'] # Store the chat ID for future use 109 | print("✅ Chat initialized.") 110 | resp = response.json() 111 | try: 112 | answer = resp.get('data', None).get('answer', "error") 113 | except: 114 | print(response.json()) 115 | resp = {"data": 116 | {"answer": "error"} 117 | } 118 | answer = "error" 119 | 120 | if answer.startswith("{\"role\":"): 121 | answerj = json.loads(answer) 122 | resp["data"]["answer"] = answerj["content"] 123 | resp["data"]["chatId"] = "0" 124 | 125 | print(f"💡 Response: {answer}") 126 | return resp 127 | except requests.exceptions.RequestException as e: 128 | # It seems we get disconnections from time to time.. 129 | # print(f"⚠️ Failed to get response on first try, trying again..: {e}") 130 | try: 131 | response = self.session.patch(url, json=payload) 132 | response.raise_for_status() 133 | data = response.json() 134 | answer = data.get('data', {}).get('answer', "No answer provided.") 135 | print(f"💡 Response: {answer}") 136 | return data 137 | except: 138 | print(f"❌ Failed to get response: {e}") 139 | return {"error": f"❌ Failed to get response: {e}"} 140 | 141 | def list_personal_groups(self): 142 | url = f"{self.base_url}/groups" 143 | try: 144 | resp = self.session.get(url) 145 | try: 146 | j = json.loads(resp.content) 147 | data_block = j["data"] 148 | if not data_block: 149 | return [] 150 | 151 | personal = data_block.get("personalGroups", []) 152 | return personal 153 | except: 154 | return [] 155 | 156 | except NetworkError as e: 157 | return [] 158 | 159 | def get_document_info(self, id): 160 | url = f"{self.base_url}/sources/{id }" 161 | try: 162 | resp = self.session.get(url) 163 | j = json.loads(resp.content) 164 | data_block = j["data"] 165 | if not data_block: 166 | return [] 167 | 168 | return data_block 169 | 170 | except NetworkError as e: 171 | return [] 172 | 173 | def query_private_gpt(self, user_input) -> json: 174 | """Send a question to the chat and retrieve the response.""" 175 | if not self.chat_id: 176 | print("❌ Chat session not initialized.") 177 | return False 178 | url = f"{self.base_url}/chats/{self.chat_id}" 179 | payload = {"question": user_input} 180 | try: 181 | response = self.session.patch(url, json=payload) 182 | # response.raise_for_status() 183 | resp = response.json() 184 | try: 185 | answer = resp.get('data', None).get('answer', "error") 186 | except: 187 | print(response.json()) 188 | resp = {"data": 189 | {"answer": "error"} 190 | } 191 | answer = "error" 192 | 193 | if answer.startswith("{\"role\":"): 194 | answerj = json.loads(answer) 195 | resp["data"]["answer"] = answerj["content"] 196 | resp["data"]["chatId"] = "0" 197 | 198 | print(f"💡 Response: {answer}") 199 | return resp 200 | except requests.exceptions.RequestException as e: 201 | # It seems we get disconnections from time to time.. 202 | # print(f"⚠️ Failed to get response on first try, trying again..: {e}") 203 | try: 204 | response = self.session.patch(url, json=payload) 205 | response.raise_for_status() 206 | data = response.json() 207 | answer = data.get('data', {}).get('answer', "No answer provided.") 208 | print(f"💡 Response: {answer}") 209 | return data 210 | except: 211 | print(f"❌ Failed to get response: {e}") 212 | return {"error": f"❌ Failed to get response: {e}"} 213 | 214 | def add_user(self, userName, userEmail, userPassword, userGroups): 215 | """Add a user""" 216 | url = f"{self.base_url}/users" 217 | try: 218 | 219 | payload = { # necessary name, email, password, usePublic 220 | "name": userName, 221 | "email": userEmail, 222 | "password": userPassword, 223 | "usePublic": False, 224 | "language": "en", # optional - defaults to "en" 225 | # "timezone": "UTC", # optional - defaults to "Europe/Berlin" 226 | "groups": userGroups, 227 | "roles": ["documents"] 228 | # "activateFtp": true, 229 | # "ftpPassword": "myFTP-Password1337" 230 | } 231 | 232 | resp = self.session.post(url, json=payload) 233 | j = json.loads(resp.content) 234 | data_block = j["message"] 235 | if not data_block: 236 | return "failed" 237 | 238 | return data_block 239 | 240 | 241 | except requests.exceptions.RequestException as e: 242 | print(f"❌ Failed to get response: {e}") 243 | return {"error": f"❌ Failed to get response: {e}"} 244 | 245 | def add_source(self, markdown, groups, name): 246 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 247 | url = f"{self.base_url}/sources" 248 | try: 249 | 250 | payload = { 251 | "name": name, 252 | "groups": groups, 253 | "content": markdown 254 | } 255 | 256 | resp = self.session.post(url, json=payload) 257 | j = json.loads(resp.content) 258 | data_block = j["data"] 259 | if not data_block: 260 | return [] 261 | 262 | return data_block 263 | 264 | 265 | except requests.exceptions.RequestException as e: 266 | print(f"❌ Failed to get response: {e}") 267 | return {"error": f"❌ Failed to get response: {e}"} 268 | 269 | def delete_source(self, source_id): 270 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 271 | url = f"{self.base_url}/sources/{source_id}" 272 | try: 273 | 274 | resp = self.session.delete(url) 275 | j = json.loads(resp.content) 276 | message = j["message"] 277 | if not message: 278 | return "failed" 279 | 280 | return message 281 | 282 | 283 | except requests.exceptions.RequestException as e: 284 | print(f"❌ Failed to get response: {e}") 285 | return {"error": f"❌ Failed to get response: {e}"} 286 | 287 | 288 | def get_sources_from_group(self, group): 289 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 290 | url = f"{self.base_url}/sources/groups" 291 | try: 292 | 293 | payload = { 294 | "groupName": group 295 | } 296 | 297 | resp = self.session.post(url, json=payload) 298 | j = json.loads(resp.content) 299 | data_block = j["data"] 300 | if not data_block: 301 | return [] 302 | 303 | sources = [] 304 | for source in data_block["sources"]: 305 | doc = self.get_document_info(source) 306 | sources.append(doc) 307 | 308 | 309 | return sources 310 | 311 | 312 | except requests.exceptions.RequestException as e: 313 | print(f"❌ Failed to get response: {e}") 314 | return [] 315 | 316 | def respond_with_context(self, messages, response_format=None, request_tools=None): 317 | last_user_message = next((p for p in reversed(messages) if p["role"] == "user"), None) 318 | user_input = "" 319 | 320 | for message in messages: 321 | if message["role"] == "system": 322 | user_input = str(message) + "\n" 323 | 324 | if last_user_message is not None: 325 | user_input += last_user_message["content"] 326 | 327 | last_assistant_message = next((p for p in reversed(messages) if p["role"] == "assistant"), None) 328 | last_tool_message = next((p for p in reversed(messages) if p["role"] == "tool"), None) 329 | 330 | hastoolresult = False 331 | if last_tool_message is not None and last_assistant_message is not None and last_assistant_message.tool_calls is not None and len( 332 | last_assistant_message.tool_calls) > 0: 333 | user_input += "\nYou called the tool: " + str( 334 | last_assistant_message.tool_calls[0]) + ". The result was: " + last_tool_message.content 335 | hastoolresult = True 336 | 337 | print(f"💁 Request: " + user_input) 338 | 339 | # PGPT manages history and context itself so we don't need to forward the history. 340 | add_context = False 341 | if add_context: 342 | messages.pop() 343 | user_input += "\nHere is some context about the previous conversation:\n" 344 | for message in messages: 345 | user_input += f"{message.role}: {message.content}\n" 346 | 347 | if response_format is not None: 348 | print("Response format: " + str(response_format)) 349 | user_input += add_response_format(response_format) 350 | 351 | if request_tools is not None and not hastoolresult: 352 | user_input += add_tools(request_tools, last_tool_message) 353 | 354 | if not self.logged_in: 355 | self.login() 356 | else: 357 | if self.chat_id is None: 358 | result = self.create_chat(user_input) 359 | else: 360 | result = self.query_private_gpt(user_input) 361 | 362 | if 'data' in result: 363 | response_data = result.get("data") 364 | if request_tools is not None and not hastoolresult and is_json( 365 | clean_response(response_data.get("answer"))): 366 | response_data["tool_call"] = clean_response(response_data.get("answer", "")) 367 | return response_data 368 | elif 'error' in result: 369 | # Try to login again and send the query once more on error. 370 | if self.login(): 371 | if self.chat_id is None: 372 | result = self.create_chat(user_input) 373 | else: 374 | result = self.query_private_gpt(user_input) 375 | 376 | if 'data' in result: 377 | return result['data'] 378 | else: 379 | return result 380 | 381 | else: 382 | return result 383 | 384 | 385 | def is_json(myjson): 386 | try: 387 | json.loads(myjson) 388 | except ValueError as e: 389 | return False 390 | return True 391 | 392 | 393 | def add_response_format(response_format): 394 | # prompt = "\nPlease fill in the following template with realistic and appropriate information. Be creative. The field 'type' defines the output format. In your reply, only return the generated json\n" 395 | prompt = "\nPlease fill in the following json template with realistic and appropriate information. In your reply, only return the generated json. If you can't answer return an empty json.\n" 396 | prompt += json.dumps(response_format) 397 | return prompt 398 | 399 | 400 | def add_tools(response_tools, last_tool_message): 401 | prompt = "\nPlease select the fitting provided tool to create your answer. Only return the generated result of the tool. Do not describe what you are doing, just return the json.\n" 402 | index = 1 403 | for tool in response_tools: 404 | prompt += "\n" + json.dumps(tool) + "\n" 405 | index += 1 406 | 407 | return prompt 408 | 409 | 410 | def clean_response(response): 411 | # Remove artefacts from reply here 412 | response = response.replace("[TOOL_CALLS]", "") 413 | return response 414 | 415 | 416 | def decrypt_api_key(api_key): 417 | """ 418 | This is PoC code and methods should be replaced with a more secure way to deal with credentials (e.g. in a db) 419 | """ 420 | try: 421 | base64_bytes = api_key.encode("ascii") 422 | decoded_string_bytes = base64.b64decode(base64_bytes) 423 | decoded_key = decoded_string_bytes.decode("ascii") 424 | except Exception as e: 425 | print(e) 426 | decoded_key = "invalid:invalid" 427 | 428 | return decoded_key.split(":")[0], decoded_key.split(":")[1] 429 | 430 | 431 | def main(): 432 | """Main function to run the chat application.""" 433 | config_file = Path.absolute(Path(__file__).parent.parent / "pgpt_openai_api_proxy.json") 434 | config = Config(config_file=config_file, required_fields=["base_url"]) 435 | chat = PrivateGPTAPI(config) 436 | 437 | print("Type your questions below. Type 'quit' to exit.") 438 | while True: 439 | try: 440 | question = input("❓ Question: ").strip() 441 | if question.lower() == 'quit': 442 | break 443 | if question: 444 | chat.query_private_gpt(question) 445 | except KeyboardInterrupt: 446 | print("\nExiting chat...") 447 | break 448 | except Exception as e: 449 | print(f"❌ Error: {str(e)}") 450 | break 451 | 452 | 453 | if __name__ == "__main__": 454 | main() ``` -------------------------------------------------------------------------------- /examples/sftp_upload_with_id/Api.py: -------------------------------------------------------------------------------- ```python 1 | import json 2 | import os 3 | import posixpath 4 | from pathlib import Path 5 | from time import sleep 6 | 7 | import paramiko 8 | import requests 9 | import urllib3 10 | import base64 11 | 12 | from httpcore import NetworkError 13 | 14 | from .config import Config 15 | 16 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 17 | 18 | 19 | def initialize_session(proxy_user, proxy_password, access_header): 20 | """Set up the session with proxy authentication.""" 21 | session = requests.Session() 22 | session.verify = False 23 | headers = { 24 | 'Accept': 'application/json', 25 | 'Content-Type': 'application/json', 26 | } 27 | if access_header is not None: 28 | headers['X-Custom-Header'] = access_header 29 | elif proxy_user is not None and proxy_password is not None: 30 | auth = base64.b64encode(f"{proxy_user}:{proxy_password}".encode()).decode() 31 | headers['Authorization'] = f'Basic {auth}' 32 | session.headers.update(headers) 33 | return session 34 | 35 | 36 | class PrivateGPTAPI: 37 | def __init__(self, config, client_api_key=None): 38 | """Initialize the chat client with proxy authentication.""" 39 | self.token = None 40 | self.chat_id = None 41 | 42 | self.base_url = config.get("base_url") 43 | self.proxy_user = config.get("proxy_user", None) 44 | if self.proxy_user == "": 45 | self.proxy_user = None 46 | self.proxy_password = config.get("proxy_password", None) 47 | if self.proxy_password == "": 48 | self.proxy_password = None 49 | self.access_header = config.get("access_header", None) 50 | if self.access_header == "": 51 | self.access_header = None 52 | 53 | self.chosen_groups = config.get("groups", []) 54 | self.language = config.get("language", "en") 55 | self.use_public = config.get("use_public", True) 56 | self.whitelist_keys = config.get("whitelist_keys", []) 57 | self.logged_in = False 58 | 59 | if client_api_key is not None: 60 | self.email, self.password = decrypt_api_key(client_api_key) 61 | if len(self.whitelist_keys) > 0: 62 | if client_api_key not in self.whitelist_keys: 63 | print("not authorized") 64 | else: 65 | self.email = config.get("email", None) 66 | self.password = config.get("password", None) 67 | self.ftp_password = config.get("ftp_password", None) 68 | 69 | 70 | self.session = initialize_session(self.proxy_user, self.proxy_password, self.access_header) 71 | if self.login(): 72 | self.logged_in = True 73 | 74 | if self.ftp_password is not None: 75 | self.ftp_host = config.get("ftp_host", None) 76 | self.ftp_port = config.get("ftp_port", None) 77 | self.ftp_folder = config.get("ftp_folder", "/") 78 | self.ftp_subfolder = config.get("ftp_subfolder", "temp") 79 | 80 | def login(self): 81 | """Authenticate the user and retrieve the token.""" 82 | url = f"{self.base_url}/login" 83 | payload = {"email": self.email, "password": self.password} 84 | try: 85 | response = self.session.post(url, json=payload) 86 | print(response.content) 87 | response.raise_for_status() 88 | data = response.json() 89 | self.token = data['data']['token'] 90 | 91 | # Prüfen, ob der Header bereits existiert 92 | if 'Authorization' in self.session.headers: 93 | self.session.headers['Authorization'] += f', Bearer {self.token}' 94 | else: 95 | self.session.headers['Authorization'] = f'Bearer {self.token}' 96 | self.chat_id = None 97 | print("✅ Login successful.") 98 | return True 99 | except requests.exceptions.RequestException as e: 100 | print(f"❌ Login failed: {e}") 101 | return False 102 | 103 | def create_chat(self, user_input): 104 | """Start a new chat session. 105 | 106 | This method sends a POST request to the '/chats' endpoint with the provided parameters. 107 | It initializes a new chat session and stores the chat ID for future use. 108 | """ 109 | url = f"{self.base_url}/chats" 110 | payload = { 111 | "language": self.language, 112 | "question": user_input, # Initial question to start the chat 113 | "usePublic": self.use_public, 114 | "groups": self.chosen_groups 115 | } 116 | try: 117 | response = self.session.post(url, json=payload) 118 | response.raise_for_status() # Raise an exception if the response was not successful 119 | data = response.json() 120 | self.chat_id = data['data']['chatId'] # Store the chat ID for future use 121 | print("✅ Chat initialized.") 122 | resp = response.json() 123 | try: 124 | answer = resp.get('data', None).get('answer', "error") 125 | except: 126 | print(response.json()) 127 | resp = {"data": 128 | {"answer": "error"} 129 | } 130 | answer = "error" 131 | 132 | if answer.startswith("{\"role\":"): 133 | answerj = json.loads(answer) 134 | resp["data"]["answer"] = answerj["content"] 135 | resp["data"]["chatId"] = "0" 136 | 137 | print(f"💡 Response: {answer}") 138 | return resp 139 | except requests.exceptions.RequestException as e: 140 | # It seems we get disconnections from time to time.. 141 | # print(f"⚠️ Failed to get response on first try, trying again..: {e}") 142 | try: 143 | response = self.session.patch(url, json=payload) 144 | response.raise_for_status() 145 | data = response.json() 146 | answer = data.get('data', {}).get('answer', "No answer provided.") 147 | print(f"💡 Response: {answer}") 148 | return data 149 | except: 150 | print(f"❌ Failed to get response: {e}") 151 | return {"error": f"❌ Failed to get response: {e}"} 152 | 153 | def list_personal_groups(self): 154 | url = f"{self.base_url}/groups" 155 | try: 156 | resp = self.session.get(url) 157 | try: 158 | j = json.loads(resp.content) 159 | data_block = j["data"] 160 | if not data_block: 161 | return [] 162 | 163 | personal = data_block.get("personalGroups", []) 164 | return personal 165 | except: 166 | return [] 167 | 168 | except NetworkError as e: 169 | return [] 170 | 171 | def get_document_info(self, id): 172 | url = f"{self.base_url}/sources/{id }" 173 | try: 174 | resp = self.session.get(url) 175 | j = json.loads(resp.content) 176 | data_block = j["data"] 177 | if not data_block: 178 | return [] 179 | 180 | return data_block 181 | 182 | except NetworkError as e: 183 | return [] 184 | 185 | def query_private_gpt(self, user_input) -> json: 186 | """Send a question to the chat and retrieve the response.""" 187 | if not self.chat_id: 188 | print("❌ Chat session not initialized.") 189 | return False 190 | url = f"{self.base_url}/chats/{self.chat_id}" 191 | payload = {"question": user_input} 192 | try: 193 | response = self.session.patch(url, json=payload) 194 | # response.raise_for_status() 195 | resp = response.json() 196 | try: 197 | answer = resp.get('data', None).get('answer', "error") 198 | except: 199 | print(response.json()) 200 | resp = {"data": 201 | {"answer": "error"} 202 | } 203 | answer = "error" 204 | 205 | if answer.startswith("{\"role\":"): 206 | answerj = json.loads(answer) 207 | resp["data"]["answer"] = answerj["content"] 208 | resp["data"]["chatId"] = "0" 209 | 210 | print(f"💡 Response: {answer}") 211 | return resp 212 | except requests.exceptions.RequestException as e: 213 | # It seems we get disconnections from time to time.. 214 | # print(f"⚠️ Failed to get response on first try, trying again..: {e}") 215 | try: 216 | response = self.session.patch(url, json=payload) 217 | response.raise_for_status() 218 | data = response.json() 219 | answer = data.get('data', {}).get('answer', "No answer provided.") 220 | print(f"💡 Response: {answer}") 221 | return data 222 | except: 223 | print(f"❌ Failed to get response: {e}") 224 | return {"error": f"❌ Failed to get response: {e}"} 225 | 226 | 227 | def add_source(self, markdown, groups, name): 228 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 229 | url = f"{self.base_url}/sources" 230 | try: 231 | 232 | payload = { 233 | "name": name, 234 | "groups": groups, 235 | "content": markdown 236 | } 237 | 238 | resp = self.session.post(url, json=payload) 239 | j = json.loads(resp.content) 240 | data_block = j["data"] 241 | if not data_block: 242 | return [] 243 | 244 | return data_block 245 | 246 | 247 | except requests.exceptions.RequestException as e: 248 | print(f"❌ Failed to get response: {e}") 249 | return {"error": f"❌ Failed to get response: {e}"} 250 | 251 | 252 | def update_source(self, source_id, markdown=None, groups=None, name=None): 253 | """Edit an existing Source""" 254 | url = f"{self.base_url}/sources/{source_id}" 255 | 256 | try: 257 | payload = {} 258 | if groups is None: 259 | existing_groups = self.get_document_info(source_id)["groups"] 260 | payload["groups"] = existing_groups 261 | else: 262 | payload["groups"] = groups 263 | 264 | if markdown is not None: 265 | payload["content"] = markdown 266 | if name is not None: 267 | payload["name"] = name 268 | 269 | resp = self.session.patch(url, json=payload) 270 | 271 | j = json.loads(resp.content) 272 | data_block = j["data"] 273 | if not data_block: 274 | return [] 275 | 276 | return data_block 277 | 278 | except requests.exceptions.RequestException as e: 279 | print(f"❌ Failed to get response: {e}") 280 | return {"error": f"❌ Failed to get response: {e}"} 281 | 282 | def delete_source(self, source_id): 283 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 284 | url = f"{self.base_url}/sources/{source_id}" 285 | try: 286 | 287 | resp = self.session.delete(url) 288 | j = json.loads(resp.content) 289 | message = j["message"] 290 | if not message: 291 | return "failed" 292 | 293 | return message 294 | 295 | 296 | except requests.exceptions.RequestException as e: 297 | print(f"❌ Failed to get response: {e}") 298 | return {"error": f"❌ Failed to get response: {e}"} 299 | 300 | 301 | 302 | def upload_sftp(self, file_path): 303 | # Connect to SFTP to determine existing suffixes 304 | transport = paramiko.Transport((self.ftp_host, self.ftp_port)) 305 | transport.connect(username=self.email, password=self.ftp_password) 306 | sftp = paramiko.SFTPClient.from_transport(transport) 307 | remote_base_dir = posixpath.join(self.ftp_folder, self.ftp_subfolder) 308 | 309 | # Ensure the remote directory exists 310 | try: 311 | sftp.chdir(remote_base_dir) 312 | except IOError: 313 | # Create remote dirs if missing 314 | parts = remote_base_dir.strip("/").split("/") 315 | path = "" 316 | for part in parts: 317 | path = posixpath.join(path, part) 318 | try: 319 | sftp.chdir(path) 320 | except IOError: 321 | sftp.mkdir(path) 322 | sftp.chdir(path) 323 | 324 | # Determine remote file name 325 | remote_filename = os.path.basename(file_path) 326 | remote_path = posixpath.join(remote_base_dir, remote_filename) 327 | 328 | # Upload the file 329 | try: 330 | sftp.put(file_path, remote_path) 331 | print(f"Uploaded {file_path} to {remote_path} successfully.") 332 | except Exception as e: 333 | print(e) 334 | 335 | finally: 336 | sftp.close() 337 | transport.close() 338 | print(f"Connection closed") 339 | sources = [] 340 | 341 | while len(sources) == 0: 342 | print(f"Checking file status") 343 | sleep(2) 344 | sources = self.get_sources_from_group("temp") 345 | 346 | return sources 347 | 348 | 349 | 350 | def get_sources_from_group(self, group): 351 | """Send a source id to retrieve details. Working with version 1.3.3 and newer""" 352 | url = f"{self.base_url}/sources/groups" 353 | try: 354 | 355 | payload = { 356 | "groupName": group 357 | } 358 | 359 | resp = self.session.post(url, json=payload) 360 | j = json.loads(resp.content) 361 | data_block = j["data"] 362 | if not data_block: 363 | return [] 364 | 365 | sources = [] 366 | for source in data_block["sources"]: 367 | doc = self.get_document_info(source) 368 | sources.append(doc) 369 | 370 | 371 | return sources 372 | 373 | 374 | except requests.exceptions.RequestException as e: 375 | print(f"❌ Failed to get response: {e}") 376 | return [] 377 | 378 | def respond_with_context(self, messages, response_format=None, request_tools=None): 379 | last_user_message = next((p for p in reversed(messages) if p["role"] == "user"), None) 380 | user_input = "" 381 | 382 | for message in messages: 383 | if message["role"] == "system": 384 | user_input = str(message) + "\n" 385 | 386 | if last_user_message is not None: 387 | user_input += last_user_message["content"] 388 | 389 | last_assistant_message = next((p for p in reversed(messages) if p["role"] == "assistant"), None) 390 | last_tool_message = next((p for p in reversed(messages) if p["role"] == "tool"), None) 391 | 392 | hastoolresult = False 393 | if last_tool_message is not None and last_assistant_message is not None and last_assistant_message.tool_calls is not None and len( 394 | last_assistant_message.tool_calls) > 0: 395 | user_input += "\nYou called the tool: " + str( 396 | last_assistant_message.tool_calls[0]) + ". The result was: " + last_tool_message.content 397 | hastoolresult = True 398 | 399 | print(f"💁 Request: " + user_input) 400 | 401 | # PGPT manages history and context itself so we don't need to forward the history. 402 | add_context = False 403 | if add_context: 404 | messages.pop() 405 | user_input += "\nHere is some context about the previous conversation:\n" 406 | for message in messages: 407 | user_input += f"{message.role}: {message.content}\n" 408 | 409 | if response_format is not None: 410 | print("Response format: " + str(response_format)) 411 | user_input += add_response_format(response_format) 412 | 413 | if request_tools is not None and not hastoolresult: 414 | user_input += add_tools(request_tools, last_tool_message) 415 | 416 | if not self.logged_in: 417 | self.login() 418 | else: 419 | if self.chat_id is None: 420 | result = self.create_chat(user_input) 421 | else: 422 | result = self.query_private_gpt(user_input) 423 | 424 | if 'data' in result: 425 | response_data = result.get("data") 426 | if request_tools is not None and not hastoolresult and is_json( 427 | clean_response(response_data.get("answer"))): 428 | response_data["tool_call"] = clean_response(response_data.get("answer", "")) 429 | return response_data 430 | elif 'error' in result: 431 | # Try to login again and send the query once more on error. 432 | if self.login(): 433 | if self.chat_id is None: 434 | result = self.create_chat(user_input) 435 | else: 436 | result = self.query_private_gpt(user_input) 437 | 438 | if 'data' in result: 439 | return result['data'] 440 | else: 441 | return result 442 | 443 | else: 444 | return result 445 | 446 | 447 | def is_json(myjson): 448 | try: 449 | json.loads(myjson) 450 | except ValueError as e: 451 | return False 452 | return True 453 | 454 | 455 | def add_response_format(response_format): 456 | # prompt = "\nPlease fill in the following template with realistic and appropriate information. Be creative. The field 'type' defines the output format. In your reply, only return the generated json\n" 457 | prompt = "\nPlease fill in the following json template with realistic and appropriate information. In your reply, only return the generated json. If you can't answer return an empty json.\n" 458 | prompt += json.dumps(response_format) 459 | return prompt 460 | 461 | 462 | def add_tools(response_tools, last_tool_message): 463 | prompt = "\nPlease select the fitting provided tool to create your answer. Only return the generated result of the tool. Do not describe what you are doing, just return the json.\n" 464 | index = 1 465 | for tool in response_tools: 466 | prompt += "\n" + json.dumps(tool) + "\n" 467 | index += 1 468 | 469 | return prompt 470 | 471 | 472 | def clean_response(response): 473 | # Remove artefacts from reply here 474 | response = response.replace("[TOOL_CALLS]", "") 475 | return response 476 | 477 | 478 | def decrypt_api_key(api_key): 479 | """ 480 | This is PoC code and methods should be replaced with a more secure way to deal with credentials (e.g. in a db) 481 | """ 482 | try: 483 | base64_bytes = api_key.encode("ascii") 484 | decoded_string_bytes = base64.b64decode(base64_bytes) 485 | decoded_key = decoded_string_bytes.decode("ascii") 486 | except Exception as e: 487 | print(e) 488 | decoded_key = "invalid:invalid" 489 | 490 | return decoded_key.split(":")[0], decoded_key.split(":")[1] 491 | 492 | 493 | def main(): 494 | """Main function to run the chat application.""" 495 | config_file = Path.absolute(Path(__file__).parent.parent / "pgpt_openai_api_proxy.json") 496 | config = Config(config_file=config_file, required_fields=["base_url"]) 497 | chat = PrivateGPTAPI(config) 498 | 499 | print("Type your questions below. Type 'quit' to exit.") 500 | while True: 501 | try: 502 | question = input("❓ Question: ").strip() 503 | if question.lower() == 'quit': 504 | break 505 | if question: 506 | chat.query_private_gpt(question) 507 | except KeyboardInterrupt: 508 | print("\nExiting chat...") 509 | break 510 | except Exception as e: 511 | print(f"❌ Error: {str(e)}") 512 | break 513 | 514 | 515 | if __name__ == "__main__": 516 | main() ```