khoj 1.30.11.dev13__py3-none-any.whl → 1.30.11.dev56__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. khoj/app/settings.py +21 -0
  2. khoj/configure.py +3 -3
  3. khoj/database/adapters/__init__.py +15 -15
  4. khoj/database/admin.py +50 -40
  5. khoj/database/migrations/0075_migrate_generated_assets_and_validate.py +85 -0
  6. khoj/database/migrations/0076_rename_openaiprocessorconversationconfig_aimodelapi_and_more.py +26 -0
  7. khoj/database/models/__init__.py +171 -42
  8. khoj/interface/compiled/404/index.html +1 -1
  9. khoj/interface/compiled/_next/static/chunks/1603-e40aadd1e56ab030.js +1 -0
  10. khoj/interface/compiled/_next/static/chunks/5538-0ea2d3944ca051e1.js +1 -0
  11. khoj/interface/compiled/_next/static/chunks/app/agents/layout-1878cc328ea380bd.js +1 -0
  12. khoj/interface/compiled/_next/static/chunks/app/agents/{page-8eead7920b0ff92a.js → page-f5c0801b27a8e95e.js} +1 -1
  13. khoj/interface/compiled/_next/static/chunks/app/automations/layout-7f1b79a2c67af0b4.js +1 -0
  14. khoj/interface/compiled/_next/static/chunks/app/automations/{page-b5800b5286306140.js → page-8691f6c09a0acd44.js} +1 -1
  15. khoj/interface/compiled/_next/static/chunks/app/chat/layout-9219a85f3477e722.js +1 -0
  16. khoj/interface/compiled/_next/static/chunks/app/chat/{page-d7d2ab93e519f0b2.js → page-135d56dd4263e40d.js} +1 -1
  17. khoj/interface/compiled/_next/static/chunks/app/layout-6310c57b674dd6f5.js +1 -0
  18. khoj/interface/compiled/_next/static/chunks/app/{page-3c32ad5472f75965.js → page-e79ace822d51557b.js} +1 -1
  19. khoj/interface/compiled/_next/static/chunks/app/search/{page-faa998c71eb7ca8e.js → page-e8b578d155550386.js} +1 -1
  20. khoj/interface/compiled/_next/static/chunks/app/settings/layout-f285795bc3154b8c.js +1 -0
  21. khoj/interface/compiled/_next/static/chunks/app/settings/{page-cbe7f56b1f87d77a.js → page-b6c835050c970be7.js} +1 -1
  22. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-6f4879fbbf8b90f7.js +1 -0
  23. khoj/interface/compiled/_next/static/chunks/app/share/chat/{page-cd5757199539bbf2.js → page-635635e4fb39fe29.js} +1 -1
  24. khoj/interface/compiled/_next/static/chunks/{webpack-3a2dfd74acf6e193.js → webpack-5203c3872078c10c.js} +1 -1
  25. khoj/interface/compiled/_next/static/css/{bedf49fbfc598358.css → 089de1d8526b96e9.css} +1 -1
  26. khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +1 -0
  27. khoj/interface/compiled/_next/static/css/edd3abaf11580924.css +1 -0
  28. khoj/interface/compiled/_next/static/media/1d8a05b60287ae6c-s.p.woff2 +0 -0
  29. khoj/interface/compiled/_next/static/media/6f22fce21a7c433c-s.woff2 +0 -0
  30. khoj/interface/compiled/_next/static/media/77c207b095007c34-s.p.woff2 +0 -0
  31. khoj/interface/compiled/_next/static/media/82ef96de0e8f4d8c-s.p.woff2 +0 -0
  32. khoj/interface/compiled/_next/static/media/a6ecd16fa044d500-s.p.woff2 +0 -0
  33. khoj/interface/compiled/_next/static/media/bd82c78e5b7b3fe9-s.p.woff2 +0 -0
  34. khoj/interface/compiled/_next/static/media/c32c8052c071fc42-s.woff2 +0 -0
  35. khoj/interface/compiled/_next/static/media/c4250770ab8708b6-s.p.woff2 +0 -0
  36. khoj/interface/compiled/agents/index.html +1 -1
  37. khoj/interface/compiled/agents/index.txt +2 -2
  38. khoj/interface/compiled/assets/icons/khoj_lantern.svg +100 -0
  39. khoj/interface/compiled/assets/icons/khoj_lantern_128x128_dark.png +0 -0
  40. khoj/interface/compiled/automations/index.html +1 -1
  41. khoj/interface/compiled/automations/index.txt +3 -3
  42. khoj/interface/compiled/chat/index.html +1 -1
  43. khoj/interface/compiled/chat/index.txt +2 -2
  44. khoj/interface/compiled/index.html +1 -1
  45. khoj/interface/compiled/index.txt +2 -2
  46. khoj/interface/compiled/search/index.html +1 -1
  47. khoj/interface/compiled/search/index.txt +2 -2
  48. khoj/interface/compiled/settings/index.html +1 -1
  49. khoj/interface/compiled/settings/index.txt +5 -4
  50. khoj/interface/compiled/share/chat/index.html +1 -1
  51. khoj/interface/compiled/share/chat/index.txt +2 -2
  52. khoj/migrations/migrate_server_pg.py +3 -9
  53. khoj/processor/conversation/anthropic/anthropic_chat.py +11 -3
  54. khoj/processor/conversation/google/gemini_chat.py +11 -3
  55. khoj/processor/conversation/offline/chat_model.py +6 -2
  56. khoj/processor/conversation/openai/gpt.py +10 -2
  57. khoj/processor/conversation/openai/utils.py +1 -6
  58. khoj/processor/conversation/prompts.py +18 -0
  59. khoj/processor/conversation/utils.py +82 -26
  60. khoj/processor/image/generate.py +12 -15
  61. khoj/routers/api.py +5 -5
  62. khoj/routers/api_chat.py +49 -98
  63. khoj/routers/helpers.py +52 -12
  64. khoj/utils/initialization.py +10 -12
  65. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/METADATA +2 -1
  66. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/RECORD +71 -67
  67. khoj/interface/compiled/_next/static/chunks/1603-c68d44bc4ae6039a.js +0 -1
  68. khoj/interface/compiled/_next/static/chunks/5538-e5f3c9f4d67a64b9.js +0 -1
  69. khoj/interface/compiled/_next/static/chunks/app/agents/layout-f2ea2b26fc0e78b1.js +0 -1
  70. khoj/interface/compiled/_next/static/chunks/app/automations/layout-f1050c1f20a3af67.js +0 -1
  71. khoj/interface/compiled/_next/static/chunks/app/chat/layout-1072c3b0ab136e74.js +0 -1
  72. khoj/interface/compiled/_next/static/chunks/app/layout-72ec1be8afd0b1ab.js +0 -1
  73. khoj/interface/compiled/_next/static/chunks/app/settings/layout-fe8a2f65ccafd142.js +0 -1
  74. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-dc97434f0354a74e.js +0 -1
  75. khoj/interface/compiled/_next/static/css/2d097a35da6bfe8d.css +0 -1
  76. khoj/interface/compiled/_next/static/css/80bd6301fc657983.css +0 -1
  77. khoj/interface/compiled/_next/static/media/5455839c73f146e7-s.p.woff2 +0 -0
  78. khoj/interface/compiled/_next/static/media/5984b96ba4822821-s.p.woff2 +0 -0
  79. khoj/interface/compiled/_next/static/media/684adc3dde1b03f1-s.p.woff2 +0 -0
  80. khoj/interface/compiled/_next/static/media/82e3b9a1bdaf0c26-s.p.woff2 +0 -0
  81. khoj/interface/compiled/_next/static/media/8d1ea331386a0db8-s.p.woff2 +0 -0
  82. khoj/interface/compiled/_next/static/media/91475f6526542a4f-s.woff2 +0 -0
  83. khoj/interface/compiled/_next/static/media/b98b13dbc1c3b59c-s.p.woff2 +0 -0
  84. khoj/interface/compiled/_next/static/media/c824d7a20139e39d-s.woff2 +0 -0
  85. /khoj/interface/compiled/_next/static/{K_WyVARSz0loPVvwOW1gg → J7Vqh1vjCleYuVLeTaJL6}/_buildManifest.js +0 -0
  86. /khoj/interface/compiled/_next/static/{K_WyVARSz0loPVvwOW1gg → J7Vqh1vjCleYuVLeTaJL6}/_ssgManifest.js +0 -0
  87. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/WHEEL +0 -0
  88. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/entry_points.txt +0 -0
  89. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,7 @@
1
1
  2:I[66513,[],"ClientPageRoot"]
2
- 3:I[5506,["3954","static/chunks/d3ac728e-a9e3522eef9b6b28.js","3072","static/chunks/3072-be830e4f8412b9d2.js","4752","static/chunks/4752-554a3db270186ce3.js","7592","static/chunks/7592-a09c39a38e60634b.js","3690","static/chunks/3690-51312931ba1eae30.js","3463","static/chunks/3463-081c031e873b7966.js","1603","static/chunks/1603-c68d44bc4ae6039a.js","8423","static/chunks/8423-1dda16bc56236523.js","5538","static/chunks/5538-e5f3c9f4d67a64b9.js","3111","static/chunks/app/share/chat/page-cd5757199539bbf2.js"],"default",1]
2
+ 3:I[5506,["3954","static/chunks/d3ac728e-a9e3522eef9b6b28.js","3072","static/chunks/3072-be830e4f8412b9d2.js","4752","static/chunks/4752-554a3db270186ce3.js","7592","static/chunks/7592-a09c39a38e60634b.js","3690","static/chunks/3690-51312931ba1eae30.js","3463","static/chunks/3463-081c031e873b7966.js","1603","static/chunks/1603-e40aadd1e56ab030.js","8423","static/chunks/8423-1dda16bc56236523.js","5538","static/chunks/5538-0ea2d3944ca051e1.js","3111","static/chunks/app/share/chat/page-635635e4fb39fe29.js"],"default",1]
3
3
  4:I[39275,[],""]
4
4
  5:I[61343,[],""]
5
- 0:["K_WyVARSz0loPVvwOW1gg",[[["",{"children":["share",{"children":["chat",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",{"children":["share",{"children":["chat",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/3cf13271869a4aeb.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/2d097a35da6bfe8d.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","2",{"rel":"stylesheet","href":"/_next/static/css/1f293605f2871853.css","precedence":"next","crossOrigin":"$undefined"}]]],null],null]},[[null,["$","html",null,{"lang":"en","className":"__variable_a693a0 __variable_702545","children":[["$","meta",null,{"httpEquiv":"Content-Security-Policy","content":"default-src 'self' https://assets.khoj.dev; script-src 'self' https://assets.khoj.dev 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'none'; object-src 'none';"}],["$","body",null,{"children":[["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","share","children","chat","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}],["$","script",null,{"dangerouslySetInnerHTML":{"__html":"window.EXCALIDRAW_ASSET_PATH = 'https://assets.khoj.dev/@excalidraw/excalidraw/dist/';"}}]]}]]}]],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","share","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/bedf49fbfc598358.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/3c34171b174cc381.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"__variable_a693a0 __variable_702545","children":[["$","meta",null,{"httpEquiv":"Content-Security-Policy","content":"default-src 'self' https://assets.khoj.dev; media-src * blob:; script-src 'self' https://assets.khoj.dev 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'none'; object-src 'none';"}],["$","body",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}]],null],null],["$L6",null]]]]
5
+ 0:["J7Vqh1vjCleYuVLeTaJL6",[[["",{"children":["share",{"children":["chat",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",{"children":["share",{"children":["chat",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/3cf13271869a4aeb.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/edd3abaf11580924.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","2",{"rel":"stylesheet","href":"/_next/static/css/1f293605f2871853.css","precedence":"next","crossOrigin":"$undefined"}]]],null],null]},[[null,["$","html",null,{"lang":"en","className":"__variable_f36179 __variable_702545","children":[["$","meta",null,{"httpEquiv":"Content-Security-Policy","content":"default-src 'self' https://assets.khoj.dev; media-src * blob:; script-src 'self' https://assets.khoj.dev https://app.chatwoot.com 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'self' https://app.chatwoot.com; object-src 'none';"}],["$","body",null,{"children":[["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","share","children","chat","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}],["$","script",null,{"dangerouslySetInnerHTML":{"__html":"window.EXCALIDRAW_ASSET_PATH = 'https://assets.khoj.dev/@excalidraw/excalidraw/dist/';"}}]]}]]}]],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","share","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/089de1d8526b96e9.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/3c34171b174cc381.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"__variable_f36179 __variable_702545","children":[["$","meta",null,{"httpEquiv":"Content-Security-Policy","content":"default-src 'self' https://assets.khoj.dev; media-src * blob:; script-src 'self' https://assets.khoj.dev https://app.chatwoot.com 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'self' https://app.chatwoot.com; object-src 'none';"}],["$","body",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}]],null],null],["$L6",null]]]]
6
6
  6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Khoj AI - Chat"}],["$","meta","3",{"name":"description","content":"Use this page to view a chat with Khoj AI."}],["$","link","4",{"rel":"manifest","href":"/static/khoj.webmanifest","crossOrigin":"use-credentials"}],["$","meta","5",{"property":"og:title","content":"Khoj AI"}],["$","meta","6",{"property":"og:description","content":"Your Second Brain."}],["$","meta","7",{"property":"og:url","content":"https://app.khoj.dev/"}],["$","meta","8",{"property":"og:site_name","content":"Khoj AI"}],["$","meta","9",{"property":"og:image","content":"https://assets.khoj.dev/khoj_lantern_256x256.png"}],["$","meta","10",{"property":"og:image:width","content":"256"}],["$","meta","11",{"property":"og:image:height","content":"256"}],["$","meta","12",{"property":"og:image","content":"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"}],["$","meta","13",{"property":"og:image:width","content":"1200"}],["$","meta","14",{"property":"og:image:height","content":"630"}],["$","meta","15",{"property":"og:type","content":"website"}],["$","meta","16",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","17",{"name":"twitter:title","content":"Khoj AI"}],["$","meta","18",{"name":"twitter:description","content":"Your Second Brain."}],["$","meta","19",{"name":"twitter:image","content":"https://assets.khoj.dev/khoj_lantern_256x256.png"}],["$","meta","20",{"name":"twitter:image:width","content":"256"}],["$","meta","21",{"name":"twitter:image:height","content":"256"}],["$","meta","22",{"name":"twitter:image","content":"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"}],["$","meta","23",{"name":"twitter:image:width","content":"1200"}],["$","meta","24",{"name":"twitter:image:height","content":"630"}],["$","link","25",{"rel":"icon","href":"/static/assets/icons/khoj_lantern.ico"}],["$","link","26",{"rel":"apple-touch-icon","href":"/static/assets/icons/khoj_lantern_256x256.png"}],["$","meta","27",{"name":"next-size-adjust"}]]
7
7
  1:null
@@ -60,11 +60,7 @@ import logging
60
60
 
61
61
  from packaging import version
62
62
 
63
- from khoj.database.models import (
64
- ChatModelOptions,
65
- OpenAIProcessorConversationConfig,
66
- SearchModelConfig,
67
- )
63
+ from khoj.database.models import AiModelApi, ChatModelOptions, SearchModelConfig
68
64
  from khoj.utils.yaml import load_config_from_file, save_config_to_file
69
65
 
70
66
  logger = logging.getLogger(__name__)
@@ -121,16 +117,14 @@ def migrate_server_pg(args):
121
117
  if openai.get("chat-model") is None:
122
118
  openai["chat-model"] = "gpt-3.5-turbo"
123
119
 
124
- openai_config = OpenAIProcessorConversationConfig.objects.create(
125
- api_key=openai.get("api-key"), name="default"
126
- )
120
+ openai_model_api = AiModelApi.objects.create(api_key=openai.get("api-key"), name="default")
127
121
 
128
122
  ChatModelOptions.objects.create(
129
123
  chat_model=openai.get("chat-model"),
130
124
  tokenizer=processor_conversation.get("tokenizer"),
131
125
  max_prompt_size=processor_conversation.get("max-prompt-size"),
132
126
  model_type=ChatModelOptions.ModelType.OPENAI,
133
- openai_config=openai_config,
127
+ ai_model_api=openai_model_api,
134
128
  )
135
129
 
136
130
  save_config_to_file(raw_config, args.config_file)
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from datetime import datetime, timedelta
3
- from typing import Dict, Optional
3
+ from typing import Dict, List, Optional
4
4
 
5
5
  import pyjson5
6
6
  from langchain.schema import ChatMessage
@@ -23,7 +23,7 @@ from khoj.utils.helpers import (
23
23
  is_none_or_empty,
24
24
  truncate_code_context,
25
25
  )
26
- from khoj.utils.rawconfig import LocationData
26
+ from khoj.utils.rawconfig import FileAttachment, LocationData
27
27
  from khoj.utils.yaml import yaml_dump
28
28
 
29
29
  logger = logging.getLogger(__name__)
@@ -55,7 +55,7 @@ def extract_questions_anthropic(
55
55
  [
56
56
  f'User: {chat["intent"]["query"]}\nAssistant: {{"queries": {chat["intent"].get("inferred-queries") or list([chat["intent"]["query"]])}}}\nA: {chat["message"]}\n\n'
57
57
  for chat in conversation_log.get("chat", [])[-4:]
58
- if chat["by"] == "khoj" and "text-to-image" not in chat["intent"].get("type")
58
+ if chat["by"] == "khoj"
59
59
  ]
60
60
  )
61
61
 
@@ -157,6 +157,10 @@ def converse_anthropic(
157
157
  query_images: Optional[list[str]] = None,
158
158
  vision_available: bool = False,
159
159
  query_files: str = None,
160
+ generated_images: Optional[list[str]] = None,
161
+ generated_files: List[FileAttachment] = None,
162
+ generated_excalidraw_diagram: Optional[str] = None,
163
+ program_execution_context: Optional[List[str]] = None,
160
164
  tracer: dict = {},
161
165
  ):
162
166
  """
@@ -217,6 +221,10 @@ def converse_anthropic(
217
221
  vision_enabled=vision_available,
218
222
  model_type=ChatModelOptions.ModelType.ANTHROPIC,
219
223
  query_files=query_files,
224
+ generated_excalidraw_diagram=generated_excalidraw_diagram,
225
+ generated_files=generated_files,
226
+ generated_images=generated_images,
227
+ program_execution_context=program_execution_context,
220
228
  )
221
229
 
222
230
  messages, system_prompt = format_messages_for_anthropic(messages, system_prompt)
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from datetime import datetime, timedelta
3
- from typing import Dict, Optional
3
+ from typing import Dict, List, Optional
4
4
 
5
5
  import pyjson5
6
6
  from langchain.schema import ChatMessage
@@ -23,7 +23,7 @@ from khoj.utils.helpers import (
23
23
  is_none_or_empty,
24
24
  truncate_code_context,
25
25
  )
26
- from khoj.utils.rawconfig import LocationData
26
+ from khoj.utils.rawconfig import FileAttachment, LocationData
27
27
  from khoj.utils.yaml import yaml_dump
28
28
 
29
29
  logger = logging.getLogger(__name__)
@@ -56,7 +56,7 @@ def extract_questions_gemini(
56
56
  [
57
57
  f'User: {chat["intent"]["query"]}\nAssistant: {{"queries": {chat["intent"].get("inferred-queries") or list([chat["intent"]["query"]])}}}\nA: {chat["message"]}\n\n'
58
58
  for chat in conversation_log.get("chat", [])[-4:]
59
- if chat["by"] == "khoj" and "text-to-image" not in chat["intent"].get("type")
59
+ if chat["by"] == "khoj"
60
60
  ]
61
61
  )
62
62
 
@@ -167,6 +167,10 @@ def converse_gemini(
167
167
  query_images: Optional[list[str]] = None,
168
168
  vision_available: bool = False,
169
169
  query_files: str = None,
170
+ generated_images: Optional[list[str]] = None,
171
+ generated_files: List[FileAttachment] = None,
172
+ generated_excalidraw_diagram: Optional[str] = None,
173
+ program_execution_context: List[str] = None,
170
174
  tracer={},
171
175
  ):
172
176
  """
@@ -228,6 +232,10 @@ def converse_gemini(
228
232
  vision_enabled=vision_available,
229
233
  model_type=ChatModelOptions.ModelType.GOOGLE,
230
234
  query_files=query_files,
235
+ generated_excalidraw_diagram=generated_excalidraw_diagram,
236
+ generated_files=generated_files,
237
+ generated_images=generated_images,
238
+ program_execution_context=program_execution_context,
231
239
  )
232
240
 
233
241
  messages, system_prompt = format_messages_for_gemini(messages, system_prompt)
@@ -28,7 +28,7 @@ from khoj.utils.helpers import (
28
28
  is_promptrace_enabled,
29
29
  truncate_code_context,
30
30
  )
31
- from khoj.utils.rawconfig import LocationData
31
+ from khoj.utils.rawconfig import FileAttachment, LocationData
32
32
  from khoj.utils.yaml import yaml_dump
33
33
 
34
34
  logger = logging.getLogger(__name__)
@@ -69,7 +69,7 @@ def extract_questions_offline(
69
69
 
70
70
  if use_history:
71
71
  for chat in conversation_log.get("chat", [])[-4:]:
72
- if chat["by"] == "khoj" and "text-to-image" not in chat["intent"].get("type"):
72
+ if chat["by"] == "khoj":
73
73
  chat_history += f"Q: {chat['intent']['query']}\n"
74
74
  chat_history += f"Khoj: {chat['message']}\n\n"
75
75
 
@@ -164,6 +164,8 @@ def converse_offline(
164
164
  user_name: str = None,
165
165
  agent: Agent = None,
166
166
  query_files: str = None,
167
+ generated_files: List[FileAttachment] = None,
168
+ additional_context: List[str] = None,
167
169
  tracer: dict = {},
168
170
  ) -> Union[ThreadedGenerator, Iterator[str]]:
169
171
  """
@@ -231,6 +233,8 @@ def converse_offline(
231
233
  tokenizer_name=tokenizer_name,
232
234
  model_type=ChatModelOptions.ModelType.OFFLINE,
233
235
  query_files=query_files,
236
+ generated_files=generated_files,
237
+ program_execution_context=additional_context,
234
238
  )
235
239
 
236
240
  logger.debug(f"Conversation Context for {model}: {messages_to_print(messages)}")
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from datetime import datetime, timedelta
3
- from typing import Dict, Optional
3
+ from typing import Dict, List, Optional
4
4
 
5
5
  import pyjson5
6
6
  from langchain.schema import ChatMessage
@@ -22,7 +22,7 @@ from khoj.utils.helpers import (
22
22
  is_none_or_empty,
23
23
  truncate_code_context,
24
24
  )
25
- from khoj.utils.rawconfig import LocationData
25
+ from khoj.utils.rawconfig import FileAttachment, LocationData
26
26
  from khoj.utils.yaml import yaml_dump
27
27
 
28
28
  logger = logging.getLogger(__name__)
@@ -157,6 +157,10 @@ def converse(
157
157
  query_images: Optional[list[str]] = None,
158
158
  vision_available: bool = False,
159
159
  query_files: str = None,
160
+ generated_images: Optional[list[str]] = None,
161
+ generated_files: List[FileAttachment] = None,
162
+ generated_excalidraw_diagram: Optional[str] = None,
163
+ program_execution_context: List[str] = None,
160
164
  tracer: dict = {},
161
165
  ):
162
166
  """
@@ -219,6 +223,10 @@ def converse(
219
223
  vision_enabled=vision_available,
220
224
  model_type=ChatModelOptions.ModelType.OPENAI,
221
225
  query_files=query_files,
226
+ generated_excalidraw_diagram=generated_excalidraw_diagram,
227
+ generated_files=generated_files,
228
+ generated_images=generated_images,
229
+ program_execution_context=program_execution_context,
222
230
  )
223
231
  logger.debug(f"Conversation Context for GPT: {messages_to_print(messages)}")
224
232
 
@@ -19,12 +19,7 @@ from khoj.processor.conversation.utils import (
19
19
  ThreadedGenerator,
20
20
  commit_conversation_trace,
21
21
  )
22
- from khoj.utils import state
23
- from khoj.utils.helpers import (
24
- get_chat_usage_metrics,
25
- in_debug_mode,
26
- is_promptrace_enabled,
27
- )
22
+ from khoj.utils.helpers import get_chat_usage_metrics, is_promptrace_enabled
28
23
 
29
24
  logger = logging.getLogger(__name__)
30
25
 
@@ -178,6 +178,18 @@ Improved Prompt:
178
178
  """.strip()
179
179
  )
180
180
 
181
+ generated_image_attachment = PromptTemplate.from_template(
182
+ f"""
183
+ Here is the image you generated based on my query. You can follow-up with a general response to my query. Limit to 1-2 sentences.
184
+ """.strip()
185
+ )
186
+
187
+ generated_diagram_attachment = PromptTemplate.from_template(
188
+ f"""
189
+ I've successfully created a diagram based on the user's query. The diagram will automatically be shared with the user. I can follow-up with a general response or summary. Limit to 1-2 sentences.
190
+ """.strip()
191
+ )
192
+
181
193
  ## Diagram Generation
182
194
  ## --
183
195
 
@@ -1029,6 +1041,12 @@ A:
1029
1041
  """.strip()
1030
1042
  )
1031
1043
 
1044
+ additional_program_context = PromptTemplate.from_template(
1045
+ """
1046
+ Here are some additional results from the query execution:
1047
+ {context}
1048
+ """.strip()
1049
+ )
1032
1050
 
1033
1051
  personality_prompt_safety_expert_lax = PromptTemplate.from_template(
1034
1052
  """
@@ -154,7 +154,7 @@ def construct_chat_history(conversation_history: dict, n: int = 4, agent_name="A
154
154
  chat_history += f'{agent_name}: {{"queries": {chat["intent"].get("inferred-queries")}}}\n'
155
155
 
156
156
  chat_history += f"{agent_name}: {chat['message']}\n\n"
157
- elif chat["by"] == "khoj" and ("text-to-image" in chat["intent"].get("type")):
157
+ elif chat["by"] == "khoj" and chat.get("images"):
158
158
  chat_history += f"User: {chat['intent']['query']}\n"
159
159
  chat_history += f"{agent_name}: [generated image redacted for space]\n"
160
160
  elif chat["by"] == "khoj" and ("excalidraw" in chat["intent"].get("type")):
@@ -213,6 +213,7 @@ class ChatEvent(Enum):
213
213
  END_LLM_RESPONSE = "end_llm_response"
214
214
  MESSAGE = "message"
215
215
  REFERENCES = "references"
216
+ GENERATED_ASSETS = "generated_assets"
216
217
  STATUS = "status"
217
218
  METADATA = "metadata"
218
219
  USAGE = "usage"
@@ -225,7 +226,6 @@ def message_to_log(
225
226
  user_message_metadata={},
226
227
  khoj_message_metadata={},
227
228
  conversation_log=[],
228
- train_of_thought=[],
229
229
  ):
230
230
  """Create json logs from messages, metadata for conversation log"""
231
231
  default_khoj_message_metadata = {
@@ -234,6 +234,10 @@ def message_to_log(
234
234
  }
235
235
  khoj_response_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
236
236
 
237
+ # Filter out any fields that are set to None
238
+ user_message_metadata = {k: v for k, v in user_message_metadata.items() if v is not None}
239
+ khoj_message_metadata = {k: v for k, v in khoj_message_metadata.items() if v is not None}
240
+
237
241
  # Create json log from Human's message
238
242
  human_log = merge_dicts({"message": user_message, "by": "you"}, user_message_metadata)
239
243
 
@@ -261,31 +265,41 @@ def save_to_conversation_log(
261
265
  automation_id: str = None,
262
266
  query_images: List[str] = None,
263
267
  raw_query_files: List[FileAttachment] = [],
268
+ generated_images: List[str] = [],
269
+ raw_generated_files: List[FileAttachment] = [],
270
+ generated_excalidraw_diagram: str = None,
264
271
  train_of_thought: List[Any] = [],
265
272
  tracer: Dict[str, Any] = {},
266
273
  ):
267
274
  user_message_time = user_message_time or datetime.now().strftime("%Y-%m-%d %H:%M:%S")
268
275
  turn_id = tracer.get("mid") or str(uuid.uuid4())
276
+
277
+ user_message_metadata = {"created": user_message_time, "images": query_images, "turnId": turn_id}
278
+
279
+ if raw_query_files and len(raw_query_files) > 0:
280
+ user_message_metadata["queryFiles"] = [file.model_dump(mode="json") for file in raw_query_files]
281
+
282
+ khoj_message_metadata = {
283
+ "context": compiled_references,
284
+ "intent": {"inferred-queries": inferred_queries, "type": intent_type},
285
+ "onlineContext": online_results,
286
+ "codeContext": code_results,
287
+ "automationId": automation_id,
288
+ "trainOfThought": train_of_thought,
289
+ "turnId": turn_id,
290
+ "images": generated_images,
291
+ "queryFiles": [file.model_dump(mode="json") for file in raw_generated_files],
292
+ }
293
+
294
+ if generated_excalidraw_diagram:
295
+ khoj_message_metadata["excalidrawDiagram"] = generated_excalidraw_diagram
296
+
269
297
  updated_conversation = message_to_log(
270
298
  user_message=q,
271
299
  chat_response=chat_response,
272
- user_message_metadata={
273
- "created": user_message_time,
274
- "images": query_images,
275
- "turnId": turn_id,
276
- "queryFiles": [file.model_dump(mode="json") for file in raw_query_files],
277
- },
278
- khoj_message_metadata={
279
- "context": compiled_references,
280
- "intent": {"inferred-queries": inferred_queries, "type": intent_type},
281
- "onlineContext": online_results,
282
- "codeContext": code_results,
283
- "automationId": automation_id,
284
- "trainOfThought": train_of_thought,
285
- "turnId": turn_id,
286
- },
300
+ user_message_metadata=user_message_metadata,
301
+ khoj_message_metadata=khoj_message_metadata,
287
302
  conversation_log=meta_log.get("chat", []),
288
- train_of_thought=train_of_thought,
289
303
  )
290
304
  ConversationAdapters.save_conversation(
291
305
  user,
@@ -303,13 +317,13 @@ def save_to_conversation_log(
303
317
  Saved Conversation Turn
304
318
  You ({user.username}): "{q}"
305
319
 
306
- Khoj: "{inferred_queries if ("text-to-image" in intent_type) else chat_response}"
320
+ Khoj: "{chat_response}"
307
321
  """.strip()
308
322
  )
309
323
 
310
324
 
311
325
  def construct_structured_message(
312
- message: str, images: list[str], model_type: str, vision_enabled: bool, attached_file_context: str
326
+ message: str, images: list[str], model_type: str, vision_enabled: bool, attached_file_context: str = None
313
327
  ):
314
328
  """
315
329
  Format messages into appropriate multimedia format for supported chat model types
@@ -327,7 +341,8 @@ def construct_structured_message(
327
341
  constructed_messages.append({"type": "text", "text": attached_file_context})
328
342
  if vision_enabled and images:
329
343
  for image in images:
330
- constructed_messages.append({"type": "image_url", "image_url": {"url": image}})
344
+ if image.startswith("https://"):
345
+ constructed_messages.append({"type": "image_url", "image_url": {"url": image}})
331
346
  return constructed_messages
332
347
 
333
348
  if not is_none_or_empty(attached_file_context):
@@ -365,6 +380,10 @@ def generate_chatml_messages_with_context(
365
380
  model_type="",
366
381
  context_message="",
367
382
  query_files: str = None,
383
+ generated_images: Optional[list[str]] = None,
384
+ generated_files: List[FileAttachment] = None,
385
+ generated_excalidraw_diagram: str = None,
386
+ program_execution_context: List[str] = [],
368
387
  ):
369
388
  """Generate chat messages with appropriate context from previous conversation to send to the chat model"""
370
389
  # Set max prompt size from user config or based on pre-configured for model and machine specs
@@ -384,6 +403,7 @@ def generate_chatml_messages_with_context(
384
403
  message_attached_files = ""
385
404
 
386
405
  chat_message = chat.get("message")
406
+ role = "user" if chat["by"] == "you" else "assistant"
387
407
 
388
408
  if chat["by"] == "khoj" and "excalidraw" in chat["intent"].get("type", ""):
389
409
  chat_message = chat["intent"].get("inferred-queries")[0]
@@ -404,7 +424,7 @@ def generate_chatml_messages_with_context(
404
424
  query_files_dict[file["name"]] = file["content"]
405
425
 
406
426
  message_attached_files = gather_raw_query_files(query_files_dict)
407
- chatml_messages.append(ChatMessage(content=message_attached_files, role="user"))
427
+ chatml_messages.append(ChatMessage(content=message_attached_files, role=role))
408
428
 
409
429
  if not is_none_or_empty(chat.get("onlineContext")):
410
430
  message_context += f"{prompts.online_search_conversation.format(online_results=chat.get('onlineContext'))}"
@@ -413,10 +433,20 @@ def generate_chatml_messages_with_context(
413
433
  reconstructed_context_message = ChatMessage(content=message_context, role="user")
414
434
  chatml_messages.insert(0, reconstructed_context_message)
415
435
 
416
- role = "user" if chat["by"] == "you" else "assistant"
417
- message_content = construct_structured_message(
418
- chat_message, chat.get("images"), model_type, vision_enabled, attached_file_context=query_files
419
- )
436
+ if chat.get("images"):
437
+ if role == "assistant":
438
+ # Issue: the assistant role cannot accept an image as a message content, so send it in a separate user message.
439
+ file_attachment_message = construct_structured_message(
440
+ message=prompts.generated_image_attachment.format(),
441
+ images=chat.get("images"),
442
+ model_type=model_type,
443
+ vision_enabled=vision_enabled,
444
+ )
445
+ chatml_messages.append(ChatMessage(content=file_attachment_message, role="user"))
446
+ else:
447
+ message_content = construct_structured_message(
448
+ chat_message, chat.get("images"), model_type, vision_enabled
449
+ )
420
450
 
421
451
  reconstructed_message = ChatMessage(content=message_content, role=role)
422
452
  chatml_messages.insert(0, reconstructed_message)
@@ -425,6 +455,7 @@ def generate_chatml_messages_with_context(
425
455
  break
426
456
 
427
457
  messages = []
458
+
428
459
  if not is_none_or_empty(user_message):
429
460
  messages.append(
430
461
  ChatMessage(
@@ -437,6 +468,31 @@ def generate_chatml_messages_with_context(
437
468
  if not is_none_or_empty(context_message):
438
469
  messages.append(ChatMessage(content=context_message, role="user"))
439
470
 
471
+ if generated_images:
472
+ messages.append(
473
+ ChatMessage(
474
+ content=construct_structured_message(
475
+ prompts.generated_image_attachment.format(), generated_images, model_type, vision_enabled
476
+ ),
477
+ role="user",
478
+ )
479
+ )
480
+
481
+ if generated_files:
482
+ message_attached_files = gather_raw_query_files({file.name: file.content for file in generated_files})
483
+ messages.append(ChatMessage(content=message_attached_files, role="assistant"))
484
+
485
+ if generated_excalidraw_diagram:
486
+ messages.append(ChatMessage(content=prompts.generated_diagram_attachment.format(), role="assistant"))
487
+
488
+ if program_execution_context:
489
+ messages.append(
490
+ ChatMessage(
491
+ content=prompts.additional_program_context.format(context="\n".join(program_execution_context)),
492
+ role="assistant",
493
+ )
494
+ )
495
+
440
496
  if len(chatml_messages) > 0:
441
497
  messages += chatml_messages
442
498
 
@@ -12,7 +12,7 @@ from khoj.database.models import Agent, KhojUser, TextToImageModelConfig
12
12
  from khoj.routers.helpers import ChatEvent, generate_better_image_prompt
13
13
  from khoj.routers.storage import upload_image
14
14
  from khoj.utils import state
15
- from khoj.utils.helpers import ImageIntentType, convert_image_to_webp, timer
15
+ from khoj.utils.helpers import convert_image_to_webp, timer
16
16
  from khoj.utils.rawconfig import LocationData
17
17
 
18
18
  logger = logging.getLogger(__name__)
@@ -34,14 +34,13 @@ async def text_to_image(
34
34
  status_code = 200
35
35
  image = None
36
36
  image_url = None
37
- intent_type = ImageIntentType.TEXT_TO_IMAGE_V3
38
37
 
39
38
  text_to_image_config = await ConversationAdapters.aget_user_text_to_image_model(user)
40
39
  if not text_to_image_config:
41
40
  # If the user has not configured a text to image model, return an unsupported on server error
42
41
  status_code = 501
43
42
  message = "Failed to generate image. Setup image generation on the server."
44
- yield image_url or image, status_code, message, intent_type.value
43
+ yield image_url or image, status_code, message
45
44
  return
46
45
 
47
46
  text2image_model = text_to_image_config.model_name
@@ -50,8 +49,8 @@ async def text_to_image(
50
49
  if chat["by"] == "khoj" and chat["intent"].get("type") in ["remember", "reminder"]:
51
50
  chat_history += f"Q: {chat['intent']['query']}\n"
52
51
  chat_history += f"A: {chat['message']}\n"
53
- elif chat["by"] == "khoj" and "text-to-image" in chat["intent"].get("type"):
54
- chat_history += f"Q: Prompt: {chat['intent']['query']}\n"
52
+ elif chat["by"] == "khoj" and chat.get("images"):
53
+ chat_history += f"Q: {chat['intent']['query']}\n"
55
54
  chat_history += f"A: Improved Prompt: {chat['intent']['inferred-queries'][0]}\n"
56
55
 
57
56
  if send_status_func:
@@ -92,31 +91,29 @@ async def text_to_image(
92
91
  logger.error(f"Image Generation blocked by OpenAI: {e}")
93
92
  status_code = e.status_code # type: ignore
94
93
  message = f"Image generation blocked by OpenAI due to policy violation" # type: ignore
95
- yield image_url or image, status_code, message, intent_type.value
94
+ yield image_url or image, status_code, message
96
95
  return
97
96
  else:
98
97
  logger.error(f"Image Generation failed with {e}", exc_info=True)
99
98
  message = f"Image generation failed using OpenAI" # type: ignore
100
99
  status_code = e.status_code # type: ignore
101
- yield image_url or image, status_code, message, intent_type.value
100
+ yield image_url or image, status_code, message
102
101
  return
103
102
  except requests.RequestException as e:
104
103
  logger.error(f"Image Generation failed with {e}", exc_info=True)
105
104
  message = f"Image generation using {text2image_model} via {text_to_image_config.model_type} failed due to a network error."
106
105
  status_code = 502
107
- yield image_url or image, status_code, message, intent_type.value
106
+ yield image_url or image, status_code, message
108
107
  return
109
108
 
110
109
  # Decide how to store the generated image
111
110
  with timer("Upload image to S3", logger):
112
111
  image_url = upload_image(webp_image_bytes, user.uuid)
113
- if image_url:
114
- intent_type = ImageIntentType.TEXT_TO_IMAGE2
115
- else:
116
- intent_type = ImageIntentType.TEXT_TO_IMAGE_V3
112
+
113
+ if not image_url:
117
114
  image = base64.b64encode(webp_image_bytes).decode("utf-8")
118
115
 
119
- yield image_url or image, status_code, image_prompt, intent_type.value
116
+ yield image_url or image, status_code, image_prompt
120
117
 
121
118
 
122
119
  def generate_image_with_openai(
@@ -127,8 +124,8 @@ def generate_image_with_openai(
127
124
  # Get the API key from the user's configuration
128
125
  if text_to_image_config.api_key:
129
126
  api_key = text_to_image_config.api_key
130
- elif text_to_image_config.openai_config:
131
- api_key = text_to_image_config.openai_config.api_key
127
+ elif text_to_image_config.ai_model_api:
128
+ api_key = text_to_image_config.ai_model_api.api_key
132
129
  elif state.openai_client:
133
130
  api_key = state.openai_client.api_key
134
131
  auth_header = {"Authorization": f"Bearer {api_key}"} if api_key else {}
khoj/routers/api.py CHANGED
@@ -430,9 +430,8 @@ async def extract_references_and_questions(
430
430
  tracer=tracer,
431
431
  )
432
432
  elif conversation_config.model_type == ChatModelOptions.ModelType.OPENAI:
433
- openai_chat_config = conversation_config.openai_config
434
- api_key = openai_chat_config.api_key
435
- base_url = openai_chat_config.api_base_url
433
+ api_key = conversation_config.ai_model_api.api_key
434
+ base_url = conversation_config.ai_model_api.api_base_url
436
435
  chat_model = conversation_config.chat_model
437
436
  inferred_queries = extract_questions(
438
437
  defiltered_query,
@@ -449,7 +448,7 @@ async def extract_references_and_questions(
449
448
  tracer=tracer,
450
449
  )
451
450
  elif conversation_config.model_type == ChatModelOptions.ModelType.ANTHROPIC:
452
- api_key = conversation_config.openai_config.api_key
451
+ api_key = conversation_config.ai_model_api.api_key
453
452
  chat_model = conversation_config.chat_model
454
453
  inferred_queries = extract_questions_anthropic(
455
454
  defiltered_query,
@@ -465,7 +464,7 @@ async def extract_references_and_questions(
465
464
  tracer=tracer,
466
465
  )
467
466
  elif conversation_config.model_type == ChatModelOptions.ModelType.GOOGLE:
468
- api_key = conversation_config.openai_config.api_key
467
+ api_key = conversation_config.ai_model_api.api_key
469
468
  chat_model = conversation_config.chat_model
470
469
  inferred_queries = extract_questions_gemini(
471
470
  defiltered_query,
@@ -537,6 +536,7 @@ def user_info(request: Request) -> Response:
537
536
  "photo": user_picture,
538
537
  "is_active": is_active,
539
538
  "has_documents": has_documents,
539
+ "khoj_version": state.khoj_version,
540
540
  }
541
541
 
542
542
  # Return user information as a JSON response