mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
Compare commits
7 Commits
1dfaa3a6df
...
924c5275e6
Author | SHA1 | Date | |
---|---|---|---|
|
924c5275e6 | ||
|
51db59622c | ||
|
1c1dcc0e18 | ||
|
db1d2aaff5 | ||
|
4322fdc910 | ||
|
2a5c5a4e15 | ||
|
ed07ce1098 |
|
@ -19,6 +19,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="join Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="join Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="join Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat en Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="join Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="seguir en X(Twitter)"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat sur Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="join Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="suivre sur X(Twitter)"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="Discordでチャット"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="X(Twitter)でフォロー"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="Follow Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="Follow Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="Follow Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
|
|
180
README_SI.md
Normal file
180
README_SI.md
Normal file
|
@ -0,0 +1,180 @@
|
|||
![cover-v5-optimized](https://github.com/langgenius/dify/assets/13230914/f9e19af5-61ba-4119-b926-d10c4c06ebab)
|
||||
|
||||
<p align="center">
|
||||
📌 <a href="https://dify.ai/blog/introducing-dify-workflow-file-upload-a-demo-on-ai-podcast">Predstavljamo nalaganje datotek Dify Workflow: znova ustvarite Google NotebookLM Podcast</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://cloud.dify.ai">Dify Cloud</a> ·
|
||||
<a href="https://docs.dify.ai/getting-started/install-self-hosted">Samostojno gostovanje</a> ·
|
||||
<a href="https://docs.dify.ai">Dokumentacija</a> ·
|
||||
<a href="https://udify.app/chat/22L1zSxg6yW1cWQg">Povpraševanje za podjetja</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://dify.ai" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Product-F04438"></a>
|
||||
<a href="https://dify.ai/pricing" target="_blank">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/free-pricing?logo=free&color=%20%23155EEF&label=pricing&labelColor=%20%23528bff"></a>
|
||||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat on Discord"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="follow on X(Twitter)"></a>
|
||||
<a href="https://hub.docker.com/u/langgenius" target="_blank">
|
||||
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/langgenius/dify-web?labelColor=%20%23FDB062&color=%20%23f79009"></a>
|
||||
<a href="https://github.com/langgenius/dify/graphs/commit-activity" target="_blank">
|
||||
<img alt="Commits last month" src="https://img.shields.io/github/commit-activity/m/langgenius/dify?labelColor=%20%2332b583&color=%20%2312b76a"></a>
|
||||
<a href="https://github.com/langgenius/dify/" target="_blank">
|
||||
<img alt="Issues closed" src="https://img.shields.io/github/issues-search?query=repo%3Alanggenius%2Fdify%20is%3Aclosed&label=issues%20closed&labelColor=%20%237d89b0&color=%20%235d6b98"></a>
|
||||
<a href="https://github.com/langgenius/dify/discussions/" target="_blank">
|
||||
<img alt="Discussion posts" src="https://img.shields.io/github/discussions/langgenius/dify?labelColor=%20%239b8afb&color=%20%237a5af8"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="./README.md"><img alt="README in English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||
<a href="./README_CN.md"><img alt="简体中文版自述文件" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||
<a href="./README_JA.md"><img alt="日本語のREADME" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||
<a href="./README_ES.md"><img alt="README en Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||
<a href="./README_FR.md"><img alt="README en Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||
<a href="./README_KL.md"><img alt="README tlhIngan Hol" src="https://img.shields.io/badge/Klingon-d9d9d9"></a>
|
||||
<a href="./README_KR.md"><img alt="README in Korean" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||
<a href="./README_AR.md"><img alt="README بالعربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||
<a href="./README_TR.md"><img alt="Türkçe README" src="https://img.shields.io/badge/Türkçe-d9d9d9"></a>
|
||||
<a href="./README_VI.md"><img alt="README Tiếng Việt" src="https://img.shields.io/badge/Ti%E1%BA%BFng%20Vi%E1%BB%87t-d9d9d9"></a>
|
||||
<a href="./README_SI.md"><img alt="README Slovenščina" src="https://img.shields.io/badge/Sloven%C5%A1%C4%8Dina-d9d9d9"></a>
|
||||
</p>
|
||||
|
||||
|
||||
Dify je odprtokodna platforma za razvoj aplikacij LLM. Njegov intuitivni vmesnik združuje agentski potek dela z umetno inteligenco, cevovod RAG, zmogljivosti agentov, upravljanje modelov, funkcije opazovanja in več, kar vam omogoča hiter prehod od prototipa do proizvodnje.
|
||||
|
||||
## Hitri začetek
|
||||
> Preden namestite Dify, se prepričajte, da vaša naprava izpolnjuje naslednje minimalne sistemske zahteve:
|
||||
>
|
||||
>- CPU >= 2 Core
|
||||
>- RAM >= 4 GiB
|
||||
|
||||
</br>
|
||||
|
||||
Najlažji način za zagon strežnika Dify je prek docker compose . Preden zaženete Dify z naslednjimi ukazi, se prepričajte, da sta Docker in Docker Compose nameščena na vašem računalniku:
|
||||
|
||||
```bash
|
||||
cd dify
|
||||
cd docker
|
||||
cp .env.example .env
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Po zagonu lahko dostopate do nadzorne plošče Dify v brskalniku na [http://localhost/install](http://localhost/install) in začnete postopek inicializacije.
|
||||
|
||||
#### Iskanje pomoči
|
||||
Prosimo, glejte naša pogosta vprašanja [FAQ](https://docs.dify.ai/getting-started/install-self-hosted/faqs) če naletite na težave pri nastavitvi Dify. Če imate še vedno težave, se obrnite na [skupnost ali nas](#community--contact).
|
||||
|
||||
> Če želite prispevati k Difyju ali narediti dodaten razvoj, glejte naš vodnik za [uvajanje iz izvorne kode](https://docs.dify.ai/getting-started/install-self-hosted/local-source-code)
|
||||
|
||||
## Ključne značilnosti
|
||||
**1. Potek dela**:
|
||||
Zgradite in preizkusite zmogljive poteke dela AI na vizualnem platnu, pri čemer izkoristite vse naslednje funkcije in več.
|
||||
|
||||
|
||||
https://github.com/langgenius/dify/assets/13230914/356df23e-1604-483d-80a6-9517ece318aa
|
||||
|
||||
|
||||
|
||||
**2. Celovita podpora za modele**:
|
||||
Brezhibna integracija s stotinami lastniških/odprtokodnih LLM-jev ducatov ponudnikov sklepanja in samostojnih rešitev, ki pokrivajo GPT, Mistral, Llama3 in vse modele, združljive z API-jem OpenAI. Celoten seznam podprtih ponudnikov modelov najdete [tukaj](https://docs.dify.ai/getting-started/readme/model-providers).
|
||||
|
||||
![providers-v5](https://github.com/langgenius/dify/assets/13230914/5a17bdbe-097a-4100-8363-40255b70f6e3)
|
||||
|
||||
|
||||
**3. Prompt IDE**:
|
||||
intuitivni vmesnik za ustvarjanje pozivov, primerjavo zmogljivosti modela in dodajanje dodatnih funkcij, kot je pretvorba besedila v govor, aplikaciji, ki temelji na klepetu.
|
||||
|
||||
**4. RAG Pipeline**:
|
||||
E Obsežne zmogljivosti RAG, ki pokrivajo vse od vnosa dokumenta do priklica, s podporo za ekstrakcijo besedila iz datotek PDF, PPT in drugih običajnih formatov dokumentov.
|
||||
|
||||
**5. Agent capabilities**:
|
||||
definirate lahko agente, ki temeljijo na klicanju funkcij LLM ali ReAct, in dodate vnaprej izdelana orodja ali orodja po meri za agenta. Dify ponuja več kot 50 vgrajenih orodij za agente AI, kot so Google Search, DALL·E, Stable Diffusion in WolframAlpha.
|
||||
|
||||
**6. LLMOps**:
|
||||
Spremljajte in analizirajte dnevnike aplikacij in učinkovitost skozi čas. Pozive, nabore podatkov in modele lahko nenehno izboljšujete na podlagi proizvodnih podatkov in opomb.
|
||||
|
||||
**7. Backend-as-a-Service**:
|
||||
AVse ponudbe Difyja so opremljene z ustreznimi API-ji, tako da lahko Dify brez težav integrirate v svojo poslovno logiko.
|
||||
|
||||
|
||||
## Uporaba Dify
|
||||
|
||||
- **Cloud </br>**
|
||||
Gostimo storitev Dify Cloud za vsakogar, ki jo lahko preizkusite brez nastavitev. Zagotavlja vse zmožnosti različice za samostojno namestitev in vključuje 200 brezplačnih klicev GPT-4 v načrtu peskovnika.
|
||||
|
||||
- **Self-hosting Dify Community Edition</br>**
|
||||
Hitro zaženite Dify v svojem okolju s tem [začetnim vodnikom](#quick-start) . Za dodatne reference in podrobnejša navodila uporabite našo [dokumentacijo](https://docs.dify.ai) .
|
||||
|
||||
|
||||
- **Dify za podjetja/organizacije</br>**
|
||||
Ponujamo dodatne funkcije, osredotočene na podjetja. Zabeležite svoja vprašanja prek tega klepetalnega robota ali nam pošljite e-pošto, da se pogovorimo o potrebah podjetja. </br>
|
||||
> Za novoustanovljena podjetja in mala podjetja, ki uporabljajo AWS, si oglejte Dify Premium na AWS Marketplace in ga z enim klikom uvedite v svoj AWS VPC. To je cenovno ugodna ponudba AMI z možnostjo ustvarjanja aplikacij z logotipom in blagovno znamko po meri.
|
||||
|
||||
|
||||
## Staying ahead
|
||||
|
||||
Star Dify on GitHub and be instantly notified of new releases.
|
||||
|
||||
![star-us](https://github.com/langgenius/dify/assets/13230914/b823edc1-6388-4e25-ad45-2f6b187adbb4)
|
||||
|
||||
|
||||
## Napredne nastavitve
|
||||
|
||||
Če morate prilagoditi konfiguracijo, si oglejte komentarje v naši datoteki .env.example in posodobite ustrezne vrednosti v svoji .env datoteki. Poleg tega boste morda morali prilagoditi docker-compose.yamlsamo datoteko, na primer spremeniti različice slike, preslikave vrat ali namestitve nosilca, glede na vaše specifično okolje in zahteve za uvajanje. Po kakršnih koli spremembah ponovno zaženite docker-compose up -d. Celoten seznam razpoložljivih spremenljivk okolja najdete tukaj .
|
||||
|
||||
Če želite konfigurirati visoko razpoložljivo nastavitev, so na voljo Helm Charts in datoteke YAML, ki jih prispeva skupnost, ki omogočajo uvedbo Difyja v Kubernetes.
|
||||
|
||||
- [Helm Chart by @LeoQuote](https://github.com/douban/charts/tree/master/charts/dify)
|
||||
- [Helm Chart by @BorisPolonsky](https://github.com/BorisPolonsky/dify-helm)
|
||||
- [YAML file by @Winson-030](https://github.com/Winson-030/dify-kubernetes)
|
||||
|
||||
#### Uporaba Terraform za uvajanje
|
||||
|
||||
namestite Dify v Cloud Platform z enim klikom z uporabo [terraform](https://www.terraform.io/)
|
||||
|
||||
##### Azure Global
|
||||
- [Azure Terraform by @nikawang](https://github.com/nikawang/dify-azure-terraform)
|
||||
|
||||
##### Google Cloud
|
||||
- [Google Cloud Terraform by @sotazum](https://github.com/DeNA/dify-google-cloud-terraform)
|
||||
|
||||
## Prispevam
|
||||
|
||||
Za tiste, ki bi radi prispevali kodo, si oglejte naš vodnik za prispevke . Hkrati vas prosimo, da podprete Dify tako, da ga delite na družbenih medijih ter na dogodkih in konferencah.
|
||||
|
||||
|
||||
|
||||
> Iščemo sodelavce za pomoč pri prevajanju Difyja v jezike, ki niso mandarinščina ali angleščina. Če želite pomagati, si oglejte i18n README za več informacij in nam pustite komentar v global-userskanalu našega strežnika skupnosti Discord .
|
||||
|
||||
## Skupnost in stik
|
||||
|
||||
* [Github Discussion](https://github.com/langgenius/dify/discussions). Najboljše za: izmenjavo povratnih informacij in postavljanje vprašanj.
|
||||
* [GitHub Issues](https://github.com/langgenius/dify/issues). Najboljše za: hrošče, na katere naletite pri uporabi Dify.AI, in predloge funkcij. Oglejte si naš [vodnik za prispevke](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md).
|
||||
* [Discord](https://discord.gg/FngNHpbcY7). Najboljše za: deljenje vaših aplikacij in druženje s skupnostjo.
|
||||
* [X(Twitter)](https://twitter.com/dify_ai). Najboljše za: deljenje vaših aplikacij in druženje s skupnostjo.
|
||||
|
||||
**Contributors**
|
||||
|
||||
<a href="https://github.com/langgenius/dify/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=langgenius/dify" />
|
||||
</a>
|
||||
|
||||
## Star history
|
||||
|
||||
[![Star History Chart](https://api.star-history.com/svg?repos=langgenius/dify&type=Date)](https://star-history.com/#langgenius/dify&Date)
|
||||
|
||||
|
||||
## Varnostno razkritje
|
||||
|
||||
Zaradi zaščite vaše zasebnosti se izogibajte objavljanju varnostnih vprašanj na GitHub. Namesto tega pošljite vprašanja na security@dify.ai in zagotovili vam bomo podrobnejši odgovor.
|
||||
|
||||
## Licenca
|
||||
|
||||
To skladišče je na voljo pod [odprtokodno licenco Dify](LICENSE) , ki je v bistvu Apache 2.0 z nekaj dodatnimi omejitvami.
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="Discord'da sohbet et"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="Follow Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="X(Twitter)'da takip et"></a>
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
<a href="https://discord.gg/FngNHpbcY7" target="_blank">
|
||||
<img src="https://img.shields.io/discord/1082486657678311454?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb"
|
||||
alt="chat trên Discord"></a>
|
||||
<a href="https://reddit.com/r/difyai" target="_blank">
|
||||
<img src="https://img.shields.io/reddit/subreddit-subscribers/difyai?style=plastic&logo=reddit&label=r%2Fdifyai&labelColor=white"
|
||||
alt="Follow Reddit"></a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=dify_ai" target="_blank">
|
||||
<img src="https://img.shields.io/twitter/follow/dify_ai?logo=X&color=%20%23f5f5f5"
|
||||
alt="theo dõi trên X(Twitter)"></a>
|
||||
|
|
|
@ -589,7 +589,7 @@ def upgrade_db():
|
|||
click.echo(click.style("Database migration successful!", fg="green"))
|
||||
|
||||
except Exception as e:
|
||||
logging.exception(f"Database migration failed: {e}")
|
||||
logging.exception("Failed to execute database migration")
|
||||
finally:
|
||||
lock.release()
|
||||
else:
|
||||
|
@ -633,7 +633,7 @@ where sites.id is null limit 1000"""
|
|||
except Exception as e:
|
||||
failed_app_ids.append(app_id)
|
||||
click.echo(click.style("Failed to fix missing site for app {}".format(app_id), fg="red"))
|
||||
logging.exception(f"Fix app related site missing issue failed, error: {e}")
|
||||
logging.exception(f"Failed to fix app related site missing issue, app_id: {app_id}")
|
||||
continue
|
||||
|
||||
if not processed_count:
|
||||
|
|
|
@ -17,6 +17,7 @@ language_timezone_mapping = {
|
|||
"hi-IN": "Asia/Kolkata",
|
||||
"tr-TR": "Europe/Istanbul",
|
||||
"fa-IR": "Asia/Tehran",
|
||||
"sl-SI": "Europe/Ljubljana",
|
||||
}
|
||||
|
||||
languages = list(language_timezone_mapping.keys())
|
||||
|
|
|
@ -70,7 +70,7 @@ class ChatMessageAudioApi(Resource):
|
|||
except ValueError as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logging.exception(f"internal server error, {str(e)}.")
|
||||
logging.exception("Failed to handle post request to ChatMessageAudioApi")
|
||||
raise InternalServerError()
|
||||
|
||||
|
||||
|
@ -128,7 +128,7 @@ class ChatMessageTextApi(Resource):
|
|||
except ValueError as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logging.exception(f"internal server error, {str(e)}.")
|
||||
logging.exception("Failed to handle post request to ChatMessageTextApi")
|
||||
raise InternalServerError()
|
||||
|
||||
|
||||
|
@ -170,7 +170,7 @@ class TextModesApi(Resource):
|
|||
except ValueError as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logging.exception(f"internal server error, {str(e)}.")
|
||||
logging.exception("Failed to handle get request to TextModesApi")
|
||||
raise InternalServerError()
|
||||
|
||||
|
||||
|
|
|
@ -948,7 +948,7 @@ class DocumentRetryApi(DocumentResource):
|
|||
raise DocumentAlreadyFinishedError()
|
||||
retry_documents.append(document)
|
||||
except Exception as e:
|
||||
logging.exception(f"Document {document_id} retry failed: {str(e)}")
|
||||
logging.exception(f"Failed to retry document, document id: {document_id}")
|
||||
continue
|
||||
# retry document
|
||||
DocumentService.retry_document(dataset_id, retry_documents)
|
||||
|
|
|
@ -72,7 +72,10 @@ class DefaultModelApi(Resource):
|
|||
model=model_setting["model"],
|
||||
)
|
||||
except Exception as ex:
|
||||
logging.exception(f"{model_setting['model_type']} save error: {ex}")
|
||||
logging.exception(
|
||||
f"Failed to update default model, model type: {model_setting['model_type']},"
|
||||
f" model:{model_setting.get('model')}"
|
||||
)
|
||||
raise ex
|
||||
|
||||
return {"result": "success"}
|
||||
|
@ -156,7 +159,10 @@ class ModelProviderModelApi(Resource):
|
|||
credentials=args["credentials"],
|
||||
)
|
||||
except CredentialsValidateFailedError as ex:
|
||||
logging.exception(f"save model credentials error: {ex}")
|
||||
logging.exception(
|
||||
f"Failed to save model credentials, tenant_id: {tenant_id},"
|
||||
f" model: {args.get('model')}, model_type: {args.get('model_type')}"
|
||||
)
|
||||
raise ValueError(str(ex))
|
||||
|
||||
return {"result": "success"}, 200
|
||||
|
|
|
@ -59,7 +59,7 @@ class AudioApi(WebApiResource):
|
|||
except ValueError as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logging.exception(f"internal server error: {str(e)}")
|
||||
logging.exception("Failed to handle post request to AudioApi")
|
||||
raise InternalServerError()
|
||||
|
||||
|
||||
|
@ -117,7 +117,7 @@ class TextApi(WebApiResource):
|
|||
except ValueError as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logging.exception(f"internal server error: {str(e)}")
|
||||
logging.exception("Failed to handle post request to TextApi")
|
||||
raise InternalServerError()
|
||||
|
||||
|
||||
|
|
|
@ -362,5 +362,5 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
|
|||
if e.args[0] == "I/O operation on closed file.": # ignore this error
|
||||
raise GenerateTaskStoppedError()
|
||||
else:
|
||||
logger.exception(e)
|
||||
logger.exception(f"Failed to process generate task pipeline, conversation_id: {conversation.id}")
|
||||
raise e
|
||||
|
|
|
@ -242,7 +242,7 @@ class AdvancedChatAppGenerateTaskPipeline(BasedGenerateTaskPipeline, WorkflowCyc
|
|||
start_listener_time = time.time()
|
||||
yield MessageAudioStreamResponse(audio=audio_trunk.audio, task_id=task_id)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.exception(f"Failed to listen audio message, task_id: {task_id}")
|
||||
break
|
||||
if tts_publisher:
|
||||
yield MessageAudioEndStreamResponse(audio="", task_id=task_id)
|
||||
|
|
|
@ -80,7 +80,7 @@ class MessageBasedAppGenerator(BaseAppGenerator):
|
|||
if e.args[0] == "I/O operation on closed file.": # ignore this error
|
||||
raise GenerateTaskStoppedError()
|
||||
else:
|
||||
logger.exception(e)
|
||||
logger.exception(f"Failed to handle response, conversation_id: {conversation.id}")
|
||||
raise e
|
||||
|
||||
def _get_conversation_by_user(
|
||||
|
|
|
@ -298,5 +298,7 @@ class WorkflowAppGenerator(BaseAppGenerator):
|
|||
if e.args[0] == "I/O operation on closed file.": # ignore this error
|
||||
raise GenerateTaskStoppedError()
|
||||
else:
|
||||
logger.exception(e)
|
||||
logger.exception(
|
||||
f"Fails to process generate task pipeline, task_id: {application_generate_entity.task_id}"
|
||||
)
|
||||
raise e
|
||||
|
|
|
@ -216,7 +216,7 @@ class WorkflowAppGenerateTaskPipeline(BasedGenerateTaskPipeline, WorkflowCycleMa
|
|||
else:
|
||||
yield MessageAudioStreamResponse(audio=audio_trunk.audio, task_id=task_id)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.exception(f"Fails to get audio trunk, task_id: {task_id}")
|
||||
break
|
||||
if tts_publisher:
|
||||
yield MessageAudioEndStreamResponse(audio="", task_id=task_id)
|
||||
|
|
|
@ -86,7 +86,7 @@ class MessageCycleManage:
|
|||
conversation.name = name
|
||||
except Exception as e:
|
||||
if dify_config.DEBUG:
|
||||
logging.exception(f"generate conversation name failed: {e}")
|
||||
logging.exception(f"generate conversation name failed, conversation_id: {conversation_id}")
|
||||
pass
|
||||
|
||||
db.session.merge(conversation)
|
||||
|
|
|
@ -41,7 +41,7 @@ def check_moderation(model_config: ModelConfigWithCredentialsEntity, text: str)
|
|||
if moderation_result is True:
|
||||
return True
|
||||
except Exception as ex:
|
||||
logger.exception(ex)
|
||||
logger.exception(f"Fails to check moderation, provider_name: {provider_name}")
|
||||
raise InvokeBadRequestError("Rate limit exceeded, please try again later.")
|
||||
|
||||
return False
|
||||
|
|
|
@ -29,7 +29,7 @@ def import_module_from_source(*, module_name: str, py_file_path: AnyStr, use_laz
|
|||
spec.loader.exec_module(module)
|
||||
return module
|
||||
except Exception as e:
|
||||
logging.exception(f"Failed to load module {module_name} from {py_file_path}: {str(e)}")
|
||||
logging.exception(f"Failed to load module {module_name} from script file '{py_file_path}'")
|
||||
raise e
|
||||
|
||||
|
||||
|
|
|
@ -554,7 +554,7 @@ class IndexingRunner:
|
|||
qa_documents.append(qa_document)
|
||||
format_documents.extend(qa_documents)
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
logging.exception("Failed to format qa document")
|
||||
|
||||
all_qa_documents.extend(format_documents)
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ class LLMGenerator:
|
|||
except InvokeError:
|
||||
questions = []
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
logging.exception("Failed to generate suggested questions after answer")
|
||||
questions = []
|
||||
|
||||
return questions
|
||||
|
@ -148,7 +148,7 @@ class LLMGenerator:
|
|||
error = str(e)
|
||||
error_step = "generate rule config"
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
logging.exception(f"Failed to generate rule config, model: {model_config.get('name')}")
|
||||
rule_config["error"] = str(e)
|
||||
|
||||
rule_config["error"] = f"Failed to {error_step}. Error: {error}" if error else ""
|
||||
|
@ -234,7 +234,7 @@ class LLMGenerator:
|
|||
error_step = "generate conversation opener"
|
||||
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
logging.exception(f"Failed to generate rule config, model: {model_config.get('name')}")
|
||||
rule_config["error"] = str(e)
|
||||
|
||||
rule_config["error"] = f"Failed to {error_step}. Error: {error}" if error else ""
|
||||
|
@ -286,7 +286,9 @@ class LLMGenerator:
|
|||
error = str(e)
|
||||
return {"code": "", "language": code_language, "error": f"Failed to generate code. Error: {error}"}
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
logging.exception(
|
||||
f"Failed to invoke LLM model, model: {model_config.get('name')}, language: {code_language}"
|
||||
)
|
||||
return {"code": "", "language": code_language, "error": f"An unexpected error occurred: {str(e)}"}
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -103,7 +103,7 @@ class AzureRerankModel(RerankModel):
|
|||
return RerankResult(model=model, docs=rerank_documents)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception in Azure rerank: {e}")
|
||||
logger.exception(f"Failed to invoke rerank model, model: {model}")
|
||||
raise
|
||||
|
||||
def validate_credentials(self, model: str, credentials: dict) -> None:
|
||||
|
|
|
@ -113,7 +113,7 @@ class SageMakerRerankModel(RerankModel):
|
|||
return RerankResult(model=model, docs=rerank_documents)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception {e}, line : {line}")
|
||||
logger.exception(f"Failed to invoke rerank model, model: {model}")
|
||||
|
||||
def validate_credentials(self, model: str, credentials: dict) -> None:
|
||||
"""
|
||||
|
|
|
@ -78,7 +78,7 @@ class SageMakerSpeech2TextModel(Speech2TextModel):
|
|||
json_obj = json.loads(json_str)
|
||||
asr_text = json_obj["text"]
|
||||
except Exception as e:
|
||||
logger.exception(f"failed to invoke speech2text model, {e}")
|
||||
logger.exception(f"failed to invoke speech2text model, model: {model}")
|
||||
raise CredentialsValidateFailedError(str(e))
|
||||
|
||||
return asr_text
|
||||
|
|
|
@ -117,7 +117,7 @@ class SageMakerEmbeddingModel(TextEmbeddingModel):
|
|||
return TextEmbeddingResult(embeddings=all_embeddings, usage=usage, model=model)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception {e}, line : {line}")
|
||||
logger.exception(f"Failed to invoke text embedding model, model: {model}, line: {line}")
|
||||
|
||||
def get_num_tokens(self, model: str, credentials: dict, texts: list[str]) -> int:
|
||||
"""
|
||||
|
|
|
@ -126,6 +126,6 @@ class OutputModeration(BaseModel):
|
|||
result: ModerationOutputsResult = moderation_factory.moderation_for_outputs(moderation_buffer)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.exception("Moderation Output error: %s", e)
|
||||
logger.exception(f"Moderation Output error, app_id: {app_id}")
|
||||
|
||||
return None
|
||||
|
|
|
@ -711,7 +711,7 @@ class TraceQueueManager:
|
|||
trace_task.app_id = self.app_id
|
||||
trace_manager_queue.put(trace_task)
|
||||
except Exception as e:
|
||||
logging.exception(f"Error adding trace task: {e}")
|
||||
logging.exception(f"Error adding trace task, trace_type {trace_task.trace_type}")
|
||||
finally:
|
||||
self.start_timer()
|
||||
|
||||
|
@ -730,7 +730,7 @@ class TraceQueueManager:
|
|||
if tasks:
|
||||
self.send_to_celery(tasks)
|
||||
except Exception as e:
|
||||
logging.exception(f"Error processing trace tasks: {e}")
|
||||
logging.exception("Error processing trace tasks")
|
||||
|
||||
def start_timer(self):
|
||||
global trace_manager_timer
|
||||
|
|
|
@ -242,7 +242,7 @@ class CouchbaseVector(BaseVector):
|
|||
try:
|
||||
self._cluster.query(query, named_parameters={"doc_ids": ids}).execute()
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.exception(f"Failed to delete documents, ids: {ids}")
|
||||
|
||||
def delete_by_document_id(self, document_id: str):
|
||||
query = f"""
|
||||
|
|
|
@ -79,7 +79,7 @@ class LindormVectorStore(BaseVector):
|
|||
existing_docs = self._client.mget(index=self._collection_name, body={"ids": batch_ids}, _source=False)
|
||||
return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]}
|
||||
except Exception as e:
|
||||
logger.exception(f"Error fetching batch {batch_ids}: {e}")
|
||||
logger.exception(f"Error fetching batch {batch_ids}")
|
||||
return set()
|
||||
|
||||
@retry(stop=stop_after_attempt(3), wait=wait_fixed(60))
|
||||
|
@ -96,7 +96,7 @@ class LindormVectorStore(BaseVector):
|
|||
)
|
||||
return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]}
|
||||
except Exception as e:
|
||||
logger.exception(f"Error fetching batch {batch_ids}: {e}")
|
||||
logger.exception(f"Error fetching batch ids: {batch_ids}")
|
||||
return set()
|
||||
|
||||
if ids is None:
|
||||
|
@ -177,7 +177,7 @@ class LindormVectorStore(BaseVector):
|
|||
else:
|
||||
logger.warning(f"Index '{self._collection_name}' does not exist. No deletion performed.")
|
||||
except Exception as e:
|
||||
logger.exception(f"Error occurred while deleting the index: {e}")
|
||||
logger.exception(f"Error occurred while deleting the index: {self._collection_name}")
|
||||
raise e
|
||||
|
||||
def text_exists(self, id: str) -> bool:
|
||||
|
@ -201,7 +201,7 @@ class LindormVectorStore(BaseVector):
|
|||
try:
|
||||
response = self._client.search(index=self._collection_name, body=query)
|
||||
except Exception as e:
|
||||
logger.exception(f"Error executing search: {e}")
|
||||
logger.exception(f"Error executing vector search, query: {query}")
|
||||
raise
|
||||
|
||||
docs_and_scores = []
|
||||
|
|
|
@ -142,7 +142,7 @@ class MyScaleVector(BaseVector):
|
|||
for r in self._client.query(sql).named_results()
|
||||
]
|
||||
except Exception as e:
|
||||
logging.exception(f"\033[91m\033[1m{type(e)}\033[0m \033[95m{str(e)}\033[0m")
|
||||
logging.exception(f"\033[91m\033[1m{type(e)}\033[0m \033[95m{str(e)}\033[0m") # noqa:TRY401
|
||||
return []
|
||||
|
||||
def delete(self) -> None:
|
||||
|
|
|
@ -158,7 +158,7 @@ class OpenSearchVector(BaseVector):
|
|||
try:
|
||||
response = self._client.search(index=self._collection_name.lower(), body=query)
|
||||
except Exception as e:
|
||||
logger.exception(f"Error executing search: {e}")
|
||||
logger.exception(f"Error executing vector search, query: {query}")
|
||||
raise
|
||||
|
||||
docs = []
|
||||
|
|
|
@ -69,7 +69,7 @@ class CacheEmbedding(Embeddings):
|
|||
except IntegrityError:
|
||||
db.session.rollback()
|
||||
except Exception as e:
|
||||
logging.exception("Failed transform embedding: %s", e)
|
||||
logging.exception("Failed transform embedding")
|
||||
cache_embeddings = []
|
||||
try:
|
||||
for i, embedding in zip(embedding_queue_indices, embedding_queue_embeddings):
|
||||
|
@ -89,7 +89,7 @@ class CacheEmbedding(Embeddings):
|
|||
db.session.rollback()
|
||||
except Exception as ex:
|
||||
db.session.rollback()
|
||||
logger.exception("Failed to embed documents: %s", ex)
|
||||
logger.exception("Failed to embed documents: %s")
|
||||
raise ex
|
||||
|
||||
return text_embeddings
|
||||
|
@ -112,7 +112,7 @@ class CacheEmbedding(Embeddings):
|
|||
embedding_results = (embedding_results / np.linalg.norm(embedding_results)).tolist()
|
||||
except Exception as ex:
|
||||
if dify_config.DEBUG:
|
||||
logging.exception(f"Failed to embed query text: {ex}")
|
||||
logging.exception(f"Failed to embed query text '{text[:10]}...({len(text)} chars)'")
|
||||
raise ex
|
||||
|
||||
try:
|
||||
|
@ -126,7 +126,7 @@ class CacheEmbedding(Embeddings):
|
|||
redis_client.setex(embedding_cache_key, 600, encoded_str)
|
||||
except Exception as ex:
|
||||
if dify_config.DEBUG:
|
||||
logging.exception("Failed to add embedding to redis %s", ex)
|
||||
logging.exception(f"Failed to add embedding to redis for the text '{text[:10]}...({len(text)} chars)'")
|
||||
raise ex
|
||||
|
||||
return embedding_results
|
||||
|
|
|
@ -229,7 +229,7 @@ class WordExtractor(BaseExtractor):
|
|||
for i in url_pattern.findall(x.text):
|
||||
hyperlinks_url = str(i)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.exception("Failed to parse HYPERLINK xml")
|
||||
|
||||
def parse_paragraph(paragraph):
|
||||
paragraph_content = []
|
||||
|
|
|
@ -159,7 +159,7 @@ class QAIndexProcessor(BaseIndexProcessor):
|
|||
qa_documents.append(qa_document)
|
||||
format_documents.extend(qa_documents)
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
logging.exception("Failed to format qa document")
|
||||
|
||||
all_qa_documents.extend(format_documents)
|
||||
|
||||
|
|
|
@ -57,13 +57,12 @@ class ASRTool(BuiltinTool):
|
|||
name="model",
|
||||
label=I18nObject(en_US="Model", zh_Hans="Model"),
|
||||
human_description=I18nObject(
|
||||
en_US="All available ASR models",
|
||||
zh_Hans="所有可用的 ASR 模型",
|
||||
en_US="All available ASR models. You can config model in the Model Provider of Settings.",
|
||||
zh_Hans="所有可用的 ASR 模型。你可以在设置中的模型供应商里配置。",
|
||||
),
|
||||
type=ToolParameter.ToolParameterType.SELECT,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
required=True,
|
||||
default=options[0].value,
|
||||
options=options,
|
||||
)
|
||||
)
|
||||
|
|
|
@ -77,13 +77,12 @@ class TTSTool(BuiltinTool):
|
|||
name="model",
|
||||
label=I18nObject(en_US="Model", zh_Hans="Model"),
|
||||
human_description=I18nObject(
|
||||
en_US="All available TTS models",
|
||||
zh_Hans="所有可用的 TTS 模型",
|
||||
en_US="All available TTS models. You can config model in the Model Provider of Settings.",
|
||||
zh_Hans="所有可用的 TTS 模型。你可以在设置中的模型供应商里配置。",
|
||||
),
|
||||
type=ToolParameter.ToolParameterType.SELECT,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
required=True,
|
||||
default=options[0].value,
|
||||
options=options,
|
||||
),
|
||||
)
|
||||
|
|
|
@ -38,7 +38,7 @@ def send_mail(parmas: SendEmailToolParameters):
|
|||
server.sendmail(parmas.email_account, parmas.sender_to, msg.as_string())
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.exception("send email failed: %s", e)
|
||||
logging.exception("send email failed")
|
||||
return False
|
||||
else: # NONE or TLS
|
||||
try:
|
||||
|
@ -49,5 +49,5 @@ def send_mail(parmas: SendEmailToolParameters):
|
|||
server.sendmail(parmas.email_account, parmas.sender_to, msg.as_string())
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.exception("send email failed: %s", e)
|
||||
logging.exception("send email failed")
|
||||
return False
|
||||
|
|
|
@ -175,7 +175,7 @@ class WorkflowTool(Tool):
|
|||
|
||||
files.append(file_dict)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.exception(f"Failed to transform file {file}")
|
||||
else:
|
||||
parameters_result[parameter.name] = tool_parameters.get(parameter.name)
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ class ToolFileManager:
|
|||
response.raise_for_status()
|
||||
blob = response.content
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to download file from {file_url}: {e}")
|
||||
logger.exception(f"Failed to download file from {file_url}")
|
||||
raise
|
||||
|
||||
mimetype = guess_type(file_url)[0] or "octet/stream"
|
||||
|
|
|
@ -388,7 +388,7 @@ class ToolManager:
|
|||
yield provider
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"load builtin provider {provider} error: {e}")
|
||||
logger.exception(f"load builtin provider {provider}")
|
||||
continue
|
||||
# set builtin providers loaded
|
||||
cls._builtin_providers_loaded = True
|
||||
|
|
|
@ -40,7 +40,7 @@ class ToolFileMessageTransformer:
|
|||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.exception(f"Failed to download image from {url}")
|
||||
result.append(
|
||||
ToolInvokeMessage(
|
||||
type=ToolInvokeMessage.MessageType.TEXT,
|
||||
|
|
|
@ -172,7 +172,7 @@ class GraphEngine:
|
|||
"answer"
|
||||
].strip()
|
||||
except Exception as e:
|
||||
logger.exception(f"Graph run failed: {str(e)}")
|
||||
logger.exception("Graph run failed")
|
||||
yield GraphRunFailedEvent(error=str(e))
|
||||
return
|
||||
|
||||
|
@ -692,7 +692,7 @@ class GraphEngine:
|
|||
)
|
||||
return
|
||||
except Exception as e:
|
||||
logger.exception(f"Node {node_instance.node_data.title} run failed: {str(e)}")
|
||||
logger.exception(f"Node {node_instance.node_data.title} run failed")
|
||||
raise e
|
||||
finally:
|
||||
db.session.close()
|
||||
|
|
|
@ -69,7 +69,7 @@ class BaseNode(Generic[GenericNodeData]):
|
|||
try:
|
||||
result = self._run()
|
||||
except Exception as e:
|
||||
logger.exception(f"Node {self.node_id} failed to run: {e}")
|
||||
logger.exception(f"Node {self.node_id} failed to run")
|
||||
result = NodeRunResult(
|
||||
status=WorkflowNodeExecutionStatus.FAILED,
|
||||
error=str(e),
|
||||
|
|
|
@ -70,7 +70,7 @@ class Storage:
|
|||
try:
|
||||
self.storage_runner.save(filename, data)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to save file: %s", e)
|
||||
logging.exception(f"Failed to save file {filename}")
|
||||
raise e
|
||||
|
||||
def load(self, filename: str, /, *, stream: bool = False) -> Union[bytes, Generator]:
|
||||
|
@ -80,42 +80,42 @@ class Storage:
|
|||
else:
|
||||
return self.load_once(filename)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to load file: %s", e)
|
||||
logging.exception(f"Failed to load file {filename}")
|
||||
raise e
|
||||
|
||||
def load_once(self, filename: str) -> bytes:
|
||||
try:
|
||||
return self.storage_runner.load_once(filename)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to load_once file: %s", e)
|
||||
logging.exception(f"Failed to load_once file {filename}")
|
||||
raise e
|
||||
|
||||
def load_stream(self, filename: str) -> Generator:
|
||||
try:
|
||||
return self.storage_runner.load_stream(filename)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to load_stream file: %s", e)
|
||||
logging.exception(f"Failed to load_stream file {filename}")
|
||||
raise e
|
||||
|
||||
def download(self, filename, target_filepath):
|
||||
try:
|
||||
self.storage_runner.download(filename, target_filepath)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to download file: %s", e)
|
||||
logging.exception(f"Failed to download file {filename}")
|
||||
raise e
|
||||
|
||||
def exists(self, filename):
|
||||
try:
|
||||
return self.storage_runner.exists(filename)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to check file exists: %s", e)
|
||||
logging.exception(f"Failed to check file exists {filename}")
|
||||
raise e
|
||||
|
||||
def delete(self, filename):
|
||||
try:
|
||||
return self.storage_runner.delete(filename)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to delete file: %s", e)
|
||||
logging.exception(f"Failed to delete file {filename}")
|
||||
raise e
|
||||
|
||||
|
||||
|
|
|
@ -39,13 +39,13 @@ class SMTPClient:
|
|||
|
||||
smtp.sendmail(self._from, mail["to"], msg.as_string())
|
||||
except smtplib.SMTPException as e:
|
||||
logging.exception(f"SMTP error occurred: {str(e)}")
|
||||
logging.exception("SMTP error occurred")
|
||||
raise
|
||||
except TimeoutError as e:
|
||||
logging.exception(f"Timeout occurred while sending email: {str(e)}")
|
||||
logging.exception("Timeout occurred while sending email")
|
||||
raise
|
||||
except Exception as e:
|
||||
logging.exception(f"Unexpected error occurred while sending email: {str(e)}")
|
||||
logging.exception(f"Unexpected error occurred while sending email to {mail['to']}")
|
||||
raise
|
||||
finally:
|
||||
if smtp:
|
||||
|
|
|
@ -679,7 +679,7 @@ class DatasetKeywordTable(db.Model):
|
|||
return json.loads(keyword_table_text.decode("utf-8"), cls=SetDecoder)
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.exception(str(e))
|
||||
logging.exception(f"Failed to load keyword table from file: {file_key}")
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ select = [
|
|||
"S506", # unsafe-yaml-load
|
||||
"SIM", # flake8-simplify rules
|
||||
"TRY400", # error-instead-of-exception
|
||||
"TRY401", # verbose-log-message
|
||||
"UP", # pyupgrade rules
|
||||
"W191", # tab-indentation
|
||||
"W605", # invalid-escape-sequence
|
||||
|
|
|
@ -779,7 +779,7 @@ class RegisterService:
|
|||
db.session.query(Tenant).delete()
|
||||
db.session.commit()
|
||||
|
||||
logging.exception(f"Setup failed: {e}")
|
||||
logging.exception(f"Setup account failed, email: {email}, name: {name}")
|
||||
raise ValueError(f"Setup failed: {e}")
|
||||
|
||||
@classmethod
|
||||
|
@ -821,7 +821,7 @@ class RegisterService:
|
|||
db.session.rollback()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
logging.exception(f"Register failed: {e}")
|
||||
logging.exception("Register failed")
|
||||
raise AccountRegisterError(f"Registration failed: {e}") from e
|
||||
|
||||
return account
|
||||
|
|
|
@ -88,7 +88,7 @@ class AppService:
|
|||
except (ProviderTokenNotInitError, LLMBadRequestError):
|
||||
model_instance = None
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
logging.exception(f"Get default model instance failed, tenant_id: {tenant_id}")
|
||||
model_instance = None
|
||||
|
||||
if model_instance:
|
||||
|
|
|
@ -195,7 +195,7 @@ class ApiToolManageService:
|
|||
# try to parse schema, avoid SSRF attack
|
||||
ApiToolManageService.parser_api_schema(schema)
|
||||
except Exception as e:
|
||||
logger.exception(f"parse api schema error: {str(e)}")
|
||||
logger.exception("parse api schema error")
|
||||
raise ValueError("invalid schema, please check the url you provided")
|
||||
|
||||
return {"schema": schema}
|
||||
|
|
|
@ -183,7 +183,7 @@ class ToolTransformService:
|
|||
try:
|
||||
username = db_provider.user.name
|
||||
except Exception as e:
|
||||
logger.exception(f"failed to get user name for api provider {db_provider.id}: {str(e)}")
|
||||
logger.exception(f"failed to get user name for api provider {db_provider.id}")
|
||||
# add provider into providers
|
||||
credentials = db_provider.credentials
|
||||
result = UserToolProvider(
|
||||
|
|
|
@ -38,4 +38,4 @@ def delete_annotation_index_task(annotation_id: str, app_id: str, tenant_id: str
|
|||
click.style("App annotations index deleted : {} latency: {}".format(app_id, end_at - start_at), fg="green")
|
||||
)
|
||||
except Exception as e:
|
||||
logging.exception("Annotation deleted index failed:{}".format(str(e)))
|
||||
logging.exception("Annotation deleted index failed")
|
||||
|
|
|
@ -60,7 +60,7 @@ def disable_annotation_reply_task(job_id: str, app_id: str, tenant_id: str):
|
|||
click.style("App annotations index deleted : {} latency: {}".format(app_id, end_at - start_at), fg="green")
|
||||
)
|
||||
except Exception as e:
|
||||
logging.exception("Annotation batch deleted index failed:{}".format(str(e)))
|
||||
logging.exception("Annotation batch deleted index failed")
|
||||
redis_client.setex(disable_app_annotation_job_key, 600, "error")
|
||||
disable_app_annotation_error_key = "disable_app_annotation_error_{}".format(str(job_id))
|
||||
redis_client.setex(disable_app_annotation_error_key, 600, str(e))
|
||||
|
|
|
@ -93,7 +93,7 @@ def enable_annotation_reply_task(
|
|||
click.style("App annotations added to index: {} latency: {}".format(app_id, end_at - start_at), fg="green")
|
||||
)
|
||||
except Exception as e:
|
||||
logging.exception("Annotation batch created index failed:{}".format(str(e)))
|
||||
logging.exception("Annotation batch created index failed")
|
||||
redis_client.setex(enable_app_annotation_job_key, 600, "error")
|
||||
enable_app_annotation_error_key = "enable_app_annotation_error_{}".format(str(job_id))
|
||||
redis_client.setex(enable_app_annotation_error_key, 600, str(e))
|
||||
|
|
|
@ -103,5 +103,5 @@ def batch_create_segment_to_index_task(
|
|||
click.style("Segment batch created job: {} latency: {}".format(job_id, end_at - start_at), fg="green")
|
||||
)
|
||||
except Exception as e:
|
||||
logging.exception("Segments batch created index failed:{}".format(str(e)))
|
||||
logging.exception("Segments batch created index failed")
|
||||
redis_client.setex(indexing_cache_key, 600, "error")
|
||||
|
|
|
@ -1 +1 @@
|
|||
recursive-include dify_client *.py
|
||||
recursive-include dify_oapi *.py
|
|
@ -1,185 +1,96 @@
|
|||
# dify-client
|
||||
# dify-oapi
|
||||
|
||||
A Dify App Service-API Client, using for build a webapp by request Service-API
|
||||
|
||||
## Usage
|
||||
|
||||
First, install `dify-client` python sdk package:
|
||||
First, install `dify-oapi` python sdk package:
|
||||
|
||||
```
|
||||
pip install dify-client
|
||||
pip install dify-oapi
|
||||
```
|
||||
|
||||
Write your code with sdk:
|
||||
|
||||
- completion generate with `blocking` response_mode
|
||||
- chat generate with `blocking` response_mode
|
||||
|
||||
```python
|
||||
from dify_client import CompletionClient
|
||||
from dify_oapi.api.chat.v1.model.chat_request import ChatRequest
|
||||
from dify_oapi.api.chat.v1.model.chat_request_body import ChatRequestBody
|
||||
from dify_oapi.api.chat.v1.model.chat_request_file import ChatRequestFile
|
||||
from dify_oapi.client import Client
|
||||
from dify_oapi.core.model.request_option import RequestOption
|
||||
|
||||
api_key = "your_api_key"
|
||||
def main():
|
||||
client = Client.builder().domain("https://api.dify.ai").build()
|
||||
req_file = (
|
||||
ChatRequestFile.builder()
|
||||
.type("image")
|
||||
.transfer_method("remote_url")
|
||||
.url("https://cloud.dify.ai/logo/logo-site.png")
|
||||
.build()
|
||||
)
|
||||
req_body = (
|
||||
ChatRequestBody.builder()
|
||||
.inputs({})
|
||||
.query("What are the specs of the iPhone 13 Pro Max?")
|
||||
.response_mode("blocking")
|
||||
.conversation_id("")
|
||||
.user("abc-123")
|
||||
.files([req_file])
|
||||
.build()
|
||||
)
|
||||
req = ChatRequest.builder().request_body(req_body).build()
|
||||
req_option = RequestOption.builder().api_key("<your-api-key>").build()
|
||||
response = client.chat.v1.chat.chat(req, req_option, False)
|
||||
# response = await client.chat.v1.chat.achat(req, req_option, False)
|
||||
print(response.success)
|
||||
print(response.code)
|
||||
print(response.msg)
|
||||
print(response.answer)
|
||||
|
||||
# Initialize CompletionClient
|
||||
completion_client = CompletionClient(api_key)
|
||||
|
||||
# Create Completion Message using CompletionClient
|
||||
completion_response = completion_client.create_completion_message(inputs={"query": "What's the weather like today?"},
|
||||
response_mode="blocking", user="user_id")
|
||||
completion_response.raise_for_status()
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
result = completion_response.json()
|
||||
|
||||
print(result.get('answer'))
|
||||
```
|
||||
|
||||
- completion using vision model, like gpt-4-vision
|
||||
|
||||
```python
|
||||
from dify_client import CompletionClient
|
||||
|
||||
api_key = "your_api_key"
|
||||
|
||||
# Initialize CompletionClient
|
||||
completion_client = CompletionClient(api_key)
|
||||
|
||||
files = [{
|
||||
"type": "image",
|
||||
"transfer_method": "remote_url",
|
||||
"url": "your_image_url"
|
||||
}]
|
||||
|
||||
# files = [{
|
||||
# "type": "image",
|
||||
# "transfer_method": "local_file",
|
||||
# "upload_file_id": "your_file_id"
|
||||
# }]
|
||||
|
||||
# Create Completion Message using CompletionClient
|
||||
completion_response = completion_client.create_completion_message(inputs={"query": "Describe the picture."},
|
||||
response_mode="blocking", user="user_id", files=files)
|
||||
completion_response.raise_for_status()
|
||||
|
||||
result = completion_response.json()
|
||||
|
||||
print(result.get('answer'))
|
||||
```
|
||||
|
||||
- chat generate with `streaming` response_mode
|
||||
|
||||
```python
|
||||
import json
|
||||
from dify_client import ChatClient
|
||||
from dify_oapi.api.chat.v1.model.chat_request import ChatRequest
|
||||
from dify_oapi.api.chat.v1.model.chat_request_body import ChatRequestBody
|
||||
from dify_oapi.api.chat.v1.model.chat_request_file import ChatRequestFile
|
||||
from dify_oapi.client import Client
|
||||
from dify_oapi.core.model.request_option import RequestOption
|
||||
|
||||
api_key = "your_api_key"
|
||||
def main():
|
||||
client = Client.builder().domain("https://api.dify.ai").build()
|
||||
req_file = (
|
||||
ChatRequestFile.builder()
|
||||
.type("image")
|
||||
.transfer_method("remote_url")
|
||||
.url("https://cloud.dify.ai/logo/logo-site.png")
|
||||
.build()
|
||||
)
|
||||
req_body = (
|
||||
ChatRequestBody.builder()
|
||||
.inputs({})
|
||||
.query("What are the specs of the iPhone 13 Pro Max?")
|
||||
.response_mode("streaming")
|
||||
.conversation_id("")
|
||||
.user("abc-123")
|
||||
.files([req_file])
|
||||
.build()
|
||||
)
|
||||
req = ChatRequest.builder().request_body(req_body).build()
|
||||
req_option = RequestOption.builder().api_key("<your-api-key>").build()
|
||||
response = client.chat.v1.chat.chat(req, req_option, True)
|
||||
# response = await client.chat.v1.chat.achat(req, req_option, True)
|
||||
for chunk in response:
|
||||
print(chunk)
|
||||
|
||||
# Initialize ChatClient
|
||||
chat_client = ChatClient(api_key)
|
||||
|
||||
# Create Chat Message using ChatClient
|
||||
chat_response = chat_client.create_chat_message(inputs={}, query="Hello", user="user_id", response_mode="streaming")
|
||||
chat_response.raise_for_status()
|
||||
|
||||
for line in chat_response.iter_lines(decode_unicode=True):
|
||||
line = line.split('data:', 1)[-1]
|
||||
if line.strip():
|
||||
line = json.loads(line.strip())
|
||||
print(line.get('answer'))
|
||||
```
|
||||
|
||||
- chat using vision model, like gpt-4-vision
|
||||
|
||||
```python
|
||||
from dify_client import ChatClient
|
||||
|
||||
api_key = "your_api_key"
|
||||
|
||||
# Initialize ChatClient
|
||||
chat_client = ChatClient(api_key)
|
||||
|
||||
files = [{
|
||||
"type": "image",
|
||||
"transfer_method": "remote_url",
|
||||
"url": "your_image_url"
|
||||
}]
|
||||
|
||||
# files = [{
|
||||
# "type": "image",
|
||||
# "transfer_method": "local_file",
|
||||
# "upload_file_id": "your_file_id"
|
||||
# }]
|
||||
|
||||
# Create Chat Message using ChatClient
|
||||
chat_response = chat_client.create_chat_message(inputs={}, query="Describe the picture.", user="user_id",
|
||||
response_mode="blocking", files=files)
|
||||
chat_response.raise_for_status()
|
||||
|
||||
result = chat_response.json()
|
||||
|
||||
print(result.get("answer"))
|
||||
```
|
||||
|
||||
- upload file when using vision model
|
||||
|
||||
```python
|
||||
from dify_client import DifyClient
|
||||
|
||||
api_key = "your_api_key"
|
||||
|
||||
# Initialize Client
|
||||
dify_client = DifyClient(api_key)
|
||||
|
||||
file_path = "your_image_file_path"
|
||||
file_name = "panda.jpeg"
|
||||
mime_type = "image/jpeg"
|
||||
|
||||
with open(file_path, "rb") as file:
|
||||
files = {
|
||||
"file": (file_name, file, mime_type)
|
||||
}
|
||||
response = dify_client.file_upload("user_id", files)
|
||||
|
||||
result = response.json()
|
||||
print(f'upload_file_id: {result.get("id")}')
|
||||
```
|
||||
|
||||
|
||||
|
||||
- Others
|
||||
|
||||
```python
|
||||
from dify_client import ChatClient
|
||||
|
||||
api_key = "your_api_key"
|
||||
|
||||
# Initialize Client
|
||||
client = ChatClient(api_key)
|
||||
|
||||
# Get App parameters
|
||||
parameters = client.get_application_parameters(user="user_id")
|
||||
parameters.raise_for_status()
|
||||
|
||||
print('[parameters]')
|
||||
print(parameters.json())
|
||||
|
||||
# Get Conversation List (only for chat)
|
||||
conversations = client.get_conversations(user="user_id")
|
||||
conversations.raise_for_status()
|
||||
|
||||
print('[conversations]')
|
||||
print(conversations.json())
|
||||
|
||||
# Get Message List (only for chat)
|
||||
messages = client.get_conversation_messages(user="user_id", conversation_id="conversation_id")
|
||||
messages.raise_for_status()
|
||||
|
||||
print('[messages]')
|
||||
print(messages.json())
|
||||
|
||||
# Rename Conversation (only for chat)
|
||||
rename_conversation_response = client.rename_conversation(conversation_id="conversation_id",
|
||||
name="new_name", user="user_id")
|
||||
rename_conversation_response.raise_for_status()
|
||||
|
||||
print('[rename result]')
|
||||
print(rename_conversation_response.json())
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
from dify_client.client import ChatClient, CompletionClient, DifyClient
|
|
@ -1,446 +0,0 @@
|
|||
import json
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
class DifyClient:
|
||||
def __init__(self, api_key, base_url: str = "https://api.dify.ai/v1"):
|
||||
self.api_key = api_key
|
||||
self.base_url = base_url
|
||||
|
||||
def _send_request(self, method, endpoint, json=None, params=None, stream=False):
|
||||
headers = {
|
||||
"Authorization": f"Bearer {self.api_key}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
response = requests.request(
|
||||
method, url, json=json, params=params, headers=headers, stream=stream
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def _send_request_with_files(self, method, endpoint, data, files):
|
||||
headers = {"Authorization": f"Bearer {self.api_key}"}
|
||||
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
response = requests.request(
|
||||
method, url, data=data, headers=headers, files=files
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def message_feedback(self, message_id, rating, user):
|
||||
data = {"rating": rating, "user": user}
|
||||
return self._send_request("POST", f"/messages/{message_id}/feedbacks", data)
|
||||
|
||||
def get_application_parameters(self, user):
|
||||
params = {"user": user}
|
||||
return self._send_request("GET", "/parameters", params=params)
|
||||
|
||||
def file_upload(self, user, files):
|
||||
data = {"user": user}
|
||||
return self._send_request_with_files(
|
||||
"POST", "/files/upload", data=data, files=files
|
||||
)
|
||||
|
||||
def text_to_audio(self, text: str, user: str, streaming: bool = False):
|
||||
data = {"text": text, "user": user, "streaming": streaming}
|
||||
return self._send_request("POST", "/text-to-audio", data=data)
|
||||
|
||||
def get_meta(self, user):
|
||||
params = {"user": user}
|
||||
return self._send_request("GET", "/meta", params=params)
|
||||
|
||||
|
||||
class CompletionClient(DifyClient):
|
||||
def create_completion_message(self, inputs, response_mode, user, files=None):
|
||||
data = {
|
||||
"inputs": inputs,
|
||||
"response_mode": response_mode,
|
||||
"user": user,
|
||||
"files": files,
|
||||
}
|
||||
return self._send_request(
|
||||
"POST",
|
||||
"/completion-messages",
|
||||
data,
|
||||
stream=True if response_mode == "streaming" else False,
|
||||
)
|
||||
|
||||
|
||||
class ChatClient(DifyClient):
|
||||
def create_chat_message(
|
||||
self,
|
||||
inputs,
|
||||
query,
|
||||
user,
|
||||
response_mode="blocking",
|
||||
conversation_id=None,
|
||||
files=None,
|
||||
):
|
||||
data = {
|
||||
"inputs": inputs,
|
||||
"query": query,
|
||||
"user": user,
|
||||
"response_mode": response_mode,
|
||||
"files": files,
|
||||
}
|
||||
if conversation_id:
|
||||
data["conversation_id"] = conversation_id
|
||||
|
||||
return self._send_request(
|
||||
"POST",
|
||||
"/chat-messages",
|
||||
data,
|
||||
stream=True if response_mode == "streaming" else False,
|
||||
)
|
||||
|
||||
def get_suggested(self, message_id, user: str):
|
||||
params = {"user": user}
|
||||
return self._send_request(
|
||||
"GET", f"/messages/{message_id}/suggested", params=params
|
||||
)
|
||||
|
||||
def stop_message(self, task_id, user):
|
||||
data = {"user": user}
|
||||
return self._send_request("POST", f"/chat-messages/{task_id}/stop", data)
|
||||
|
||||
def get_conversations(self, user, last_id=None, limit=None, pinned=None):
|
||||
params = {"user": user, "last_id": last_id, "limit": limit, "pinned": pinned}
|
||||
return self._send_request("GET", "/conversations", params=params)
|
||||
|
||||
def get_conversation_messages(
|
||||
self, user, conversation_id=None, first_id=None, limit=None
|
||||
):
|
||||
params = {"user": user}
|
||||
|
||||
if conversation_id:
|
||||
params["conversation_id"] = conversation_id
|
||||
if first_id:
|
||||
params["first_id"] = first_id
|
||||
if limit:
|
||||
params["limit"] = limit
|
||||
|
||||
return self._send_request("GET", "/messages", params=params)
|
||||
|
||||
def rename_conversation(
|
||||
self, conversation_id, name, auto_generate: bool, user: str
|
||||
):
|
||||
data = {"name": name, "auto_generate": auto_generate, "user": user}
|
||||
return self._send_request(
|
||||
"POST", f"/conversations/{conversation_id}/name", data
|
||||
)
|
||||
|
||||
def delete_conversation(self, conversation_id, user):
|
||||
data = {"user": user}
|
||||
return self._send_request("DELETE", f"/conversations/{conversation_id}", data)
|
||||
|
||||
def audio_to_text(self, audio_file, user):
|
||||
data = {"user": user}
|
||||
files = {"audio_file": audio_file}
|
||||
return self._send_request_with_files("POST", "/audio-to-text", data, files)
|
||||
|
||||
|
||||
class WorkflowClient(DifyClient):
|
||||
def run(
|
||||
self, inputs: dict, response_mode: str = "streaming", user: str = "abc-123"
|
||||
):
|
||||
data = {"inputs": inputs, "response_mode": response_mode, "user": user}
|
||||
return self._send_request("POST", "/workflows/run", data)
|
||||
|
||||
def stop(self, task_id, user):
|
||||
data = {"user": user}
|
||||
return self._send_request("POST", f"/workflows/tasks/{task_id}/stop", data)
|
||||
|
||||
def get_result(self, workflow_run_id):
|
||||
return self._send_request("GET", f"/workflows/run/{workflow_run_id}")
|
||||
|
||||
|
||||
class KnowledgeBaseClient(DifyClient):
|
||||
def __init__(
|
||||
self, api_key, base_url: str = "https://api.dify.ai/v1", dataset_id: str = None
|
||||
):
|
||||
"""
|
||||
Construct a KnowledgeBaseClient object.
|
||||
|
||||
Args:
|
||||
api_key (str): API key of Dify.
|
||||
base_url (str, optional): Base URL of Dify API. Defaults to 'https://api.dify.ai/v1'.
|
||||
dataset_id (str, optional): ID of the dataset. Defaults to None. You don't need this if you just want to
|
||||
create a new dataset. or list datasets. otherwise you need to set this.
|
||||
"""
|
||||
super().__init__(api_key=api_key, base_url=base_url)
|
||||
self.dataset_id = dataset_id
|
||||
|
||||
def _get_dataset_id(self):
|
||||
if self.dataset_id is None:
|
||||
raise ValueError("dataset_id is not set")
|
||||
return self.dataset_id
|
||||
|
||||
def create_dataset(self, name: str, **kwargs):
|
||||
return self._send_request("POST", "/datasets", {"name": name}, **kwargs)
|
||||
|
||||
def list_datasets(self, page: int = 1, page_size: int = 20, **kwargs):
|
||||
return self._send_request(
|
||||
"GET", f"/datasets?page={page}&limit={page_size}", **kwargs
|
||||
)
|
||||
|
||||
def create_document_by_text(self, name, text, extra_params: dict = None, **kwargs):
|
||||
"""
|
||||
Create a document by text.
|
||||
|
||||
:param name: Name of the document
|
||||
:param text: Text content of the document
|
||||
:param extra_params: extra parameters pass to the API, such as indexing_technique, process_rule. (optional)
|
||||
e.g.
|
||||
{
|
||||
'indexing_technique': 'high_quality',
|
||||
'process_rule': {
|
||||
'rules': {
|
||||
'pre_processing_rules': [
|
||||
{'id': 'remove_extra_spaces', 'enabled': True},
|
||||
{'id': 'remove_urls_emails', 'enabled': True}
|
||||
],
|
||||
'segmentation': {
|
||||
'separator': '\n',
|
||||
'max_tokens': 500
|
||||
}
|
||||
},
|
||||
'mode': 'custom'
|
||||
}
|
||||
}
|
||||
:return: Response from the API
|
||||
"""
|
||||
data = {
|
||||
"indexing_technique": "high_quality",
|
||||
"process_rule": {"mode": "automatic"},
|
||||
"name": name,
|
||||
"text": text,
|
||||
}
|
||||
if extra_params is not None and isinstance(extra_params, dict):
|
||||
data.update(extra_params)
|
||||
url = f"/datasets/{self._get_dataset_id()}/document/create_by_text"
|
||||
return self._send_request("POST", url, json=data, **kwargs)
|
||||
|
||||
def update_document_by_text(
|
||||
self, document_id, name, text, extra_params: dict = None, **kwargs
|
||||
):
|
||||
"""
|
||||
Update a document by text.
|
||||
|
||||
:param document_id: ID of the document
|
||||
:param name: Name of the document
|
||||
:param text: Text content of the document
|
||||
:param extra_params: extra parameters pass to the API, such as indexing_technique, process_rule. (optional)
|
||||
e.g.
|
||||
{
|
||||
'indexing_technique': 'high_quality',
|
||||
'process_rule': {
|
||||
'rules': {
|
||||
'pre_processing_rules': [
|
||||
{'id': 'remove_extra_spaces', 'enabled': True},
|
||||
{'id': 'remove_urls_emails', 'enabled': True}
|
||||
],
|
||||
'segmentation': {
|
||||
'separator': '\n',
|
||||
'max_tokens': 500
|
||||
}
|
||||
},
|
||||
'mode': 'custom'
|
||||
}
|
||||
}
|
||||
:return: Response from the API
|
||||
"""
|
||||
data = {"name": name, "text": text}
|
||||
if extra_params is not None and isinstance(extra_params, dict):
|
||||
data.update(extra_params)
|
||||
url = (
|
||||
f"/datasets/{self._get_dataset_id()}/documents/{document_id}/update_by_text"
|
||||
)
|
||||
return self._send_request("POST", url, json=data, **kwargs)
|
||||
|
||||
def create_document_by_file(
|
||||
self, file_path, original_document_id=None, extra_params: dict = None
|
||||
):
|
||||
"""
|
||||
Create a document by file.
|
||||
|
||||
:param file_path: Path to the file
|
||||
:param original_document_id: pass this ID if you want to replace the original document (optional)
|
||||
:param extra_params: extra parameters pass to the API, such as indexing_technique, process_rule. (optional)
|
||||
e.g.
|
||||
{
|
||||
'indexing_technique': 'high_quality',
|
||||
'process_rule': {
|
||||
'rules': {
|
||||
'pre_processing_rules': [
|
||||
{'id': 'remove_extra_spaces', 'enabled': True},
|
||||
{'id': 'remove_urls_emails', 'enabled': True}
|
||||
],
|
||||
'segmentation': {
|
||||
'separator': '\n',
|
||||
'max_tokens': 500
|
||||
}
|
||||
},
|
||||
'mode': 'custom'
|
||||
}
|
||||
}
|
||||
:return: Response from the API
|
||||
"""
|
||||
files = {"file": open(file_path, "rb")}
|
||||
data = {
|
||||
"process_rule": {"mode": "automatic"},
|
||||
"indexing_technique": "high_quality",
|
||||
}
|
||||
if extra_params is not None and isinstance(extra_params, dict):
|
||||
data.update(extra_params)
|
||||
if original_document_id is not None:
|
||||
data["original_document_id"] = original_document_id
|
||||
url = f"/datasets/{self._get_dataset_id()}/document/create_by_file"
|
||||
return self._send_request_with_files(
|
||||
"POST", url, {"data": json.dumps(data)}, files
|
||||
)
|
||||
|
||||
def update_document_by_file(
|
||||
self, document_id, file_path, extra_params: dict = None
|
||||
):
|
||||
"""
|
||||
Update a document by file.
|
||||
|
||||
:param document_id: ID of the document
|
||||
:param file_path: Path to the file
|
||||
:param extra_params: extra parameters pass to the API, such as indexing_technique, process_rule. (optional)
|
||||
e.g.
|
||||
{
|
||||
'indexing_technique': 'high_quality',
|
||||
'process_rule': {
|
||||
'rules': {
|
||||
'pre_processing_rules': [
|
||||
{'id': 'remove_extra_spaces', 'enabled': True},
|
||||
{'id': 'remove_urls_emails', 'enabled': True}
|
||||
],
|
||||
'segmentation': {
|
||||
'separator': '\n',
|
||||
'max_tokens': 500
|
||||
}
|
||||
},
|
||||
'mode': 'custom'
|
||||
}
|
||||
}
|
||||
:return:
|
||||
"""
|
||||
files = {"file": open(file_path, "rb")}
|
||||
data = {}
|
||||
if extra_params is not None and isinstance(extra_params, dict):
|
||||
data.update(extra_params)
|
||||
url = (
|
||||
f"/datasets/{self._get_dataset_id()}/documents/{document_id}/update_by_file"
|
||||
)
|
||||
return self._send_request_with_files(
|
||||
"POST", url, {"data": json.dumps(data)}, files
|
||||
)
|
||||
|
||||
def batch_indexing_status(self, batch_id: str, **kwargs):
|
||||
"""
|
||||
Get the status of the batch indexing.
|
||||
|
||||
:param batch_id: ID of the batch uploading
|
||||
:return: Response from the API
|
||||
"""
|
||||
url = f"/datasets/{self._get_dataset_id()}/documents/{batch_id}/indexing-status"
|
||||
return self._send_request("GET", url, **kwargs)
|
||||
|
||||
def delete_dataset(self):
|
||||
"""
|
||||
Delete this dataset.
|
||||
|
||||
:return: Response from the API
|
||||
"""
|
||||
url = f"/datasets/{self._get_dataset_id()}"
|
||||
return self._send_request("DELETE", url)
|
||||
|
||||
def delete_document(self, document_id):
|
||||
"""
|
||||
Delete a document.
|
||||
|
||||
:param document_id: ID of the document
|
||||
:return: Response from the API
|
||||
"""
|
||||
url = f"/datasets/{self._get_dataset_id()}/documents/{document_id}"
|
||||
return self._send_request("DELETE", url)
|
||||
|
||||
def list_documents(
|
||||
self, page: int = None, page_size: int = None, keyword: str = None, **kwargs
|
||||
):
|
||||
"""
|
||||
Get a list of documents in this dataset.
|
||||
|
||||
:return: Response from the API
|
||||
"""
|
||||
params = {}
|
||||
if page is not None:
|
||||
params["page"] = page
|
||||
if page_size is not None:
|
||||
params["limit"] = page_size
|
||||
if keyword is not None:
|
||||
params["keyword"] = keyword
|
||||
url = f"/datasets/{self._get_dataset_id()}/documents"
|
||||
return self._send_request("GET", url, params=params, **kwargs)
|
||||
|
||||
def add_segments(self, document_id, segments, **kwargs):
|
||||
"""
|
||||
Add segments to a document.
|
||||
|
||||
:param document_id: ID of the document
|
||||
:param segments: List of segments to add, example: [{"content": "1", "answer": "1", "keyword": ["a"]}]
|
||||
:return: Response from the API
|
||||
"""
|
||||
data = {"segments": segments}
|
||||
url = f"/datasets/{self._get_dataset_id()}/documents/{document_id}/segments"
|
||||
return self._send_request("POST", url, json=data, **kwargs)
|
||||
|
||||
def query_segments(
|
||||
self, document_id, keyword: str = None, status: str = None, **kwargs
|
||||
):
|
||||
"""
|
||||
Query segments in this document.
|
||||
|
||||
:param document_id: ID of the document
|
||||
:param keyword: query keyword, optional
|
||||
:param status: status of the segment, optional, e.g. completed
|
||||
"""
|
||||
url = f"/datasets/{self._get_dataset_id()}/documents/{document_id}/segments"
|
||||
params = {}
|
||||
if keyword is not None:
|
||||
params["keyword"] = keyword
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if "params" in kwargs:
|
||||
params.update(kwargs["params"])
|
||||
return self._send_request("GET", url, params=params, **kwargs)
|
||||
|
||||
def delete_document_segment(self, document_id, segment_id):
|
||||
"""
|
||||
Delete a segment from a document.
|
||||
|
||||
:param document_id: ID of the document
|
||||
:param segment_id: ID of the segment
|
||||
:return: Response from the API
|
||||
"""
|
||||
url = f"/datasets/{self._get_dataset_id()}/documents/{document_id}/segments/{segment_id}"
|
||||
return self._send_request("DELETE", url)
|
||||
|
||||
def update_document_segment(self, document_id, segment_id, segment_data, **kwargs):
|
||||
"""
|
||||
Update a segment in a document.
|
||||
|
||||
:param document_id: ID of the document
|
||||
:param segment_id: ID of the segment
|
||||
:param segment_data: Data of the segment, example: {"content": "1", "answer": "1", "keyword": ["a"], "enabled": True}
|
||||
:return: Response from the API
|
||||
"""
|
||||
data = {"segment": segment_data}
|
||||
url = f"/datasets/{self._get_dataset_id()}/documents/{document_id}/segments/{segment_id}"
|
||||
return self._send_request("POST", url, json=data, **kwargs)
|
0
sdks/python-client/dify_oapi/__init__.py
Executable file
0
sdks/python-client/dify_oapi/__init__.py
Executable file
0
sdks/python-client/dify_oapi/api/__init__.py
Executable file
0
sdks/python-client/dify_oapi/api/__init__.py
Executable file
0
sdks/python-client/dify_oapi/api/chat/__init__.py
Executable file
0
sdks/python-client/dify_oapi/api/chat/__init__.py
Executable file
8
sdks/python-client/dify_oapi/api/chat/service.py
Executable file
8
sdks/python-client/dify_oapi/api/chat/service.py
Executable file
|
@ -0,0 +1,8 @@
|
|||
from dify_oapi.core.model.config import Config
|
||||
|
||||
from .v1.version import V1
|
||||
|
||||
|
||||
class ChatService:
|
||||
def __init__(self, config: Config) -> None:
|
||||
self.v1: V1 = V1(config)
|
0
sdks/python-client/dify_oapi/api/chat/v1/__init__.py
Executable file
0
sdks/python-client/dify_oapi/api/chat/v1/__init__.py
Executable file
0
sdks/python-client/dify_oapi/api/chat/v1/model/__init__.py
Executable file
0
sdks/python-client/dify_oapi/api/chat/v1/model/__init__.py
Executable file
|
@ -0,0 +1,41 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
from .audio_to_text_request_body import AudioToTextRequestBody
|
||||
|
||||
|
||||
class AudioToTextRequest(BaseRequest):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.file: BytesIO | None = None
|
||||
self.request_body: AudioToTextRequestBody | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> AudioToTextRequestBuilder:
|
||||
return AudioToTextRequestBuilder()
|
||||
|
||||
|
||||
class AudioToTextRequestBuilder(object):
|
||||
def __init__(self):
|
||||
audio_to_text_request = AudioToTextRequest()
|
||||
audio_to_text_request.http_method = HttpMethod.POST
|
||||
audio_to_text_request.uri = "/v1/audio-to-text"
|
||||
self._audio_to_text_request = audio_to_text_request
|
||||
|
||||
def build(self) -> AudioToTextRequest:
|
||||
return self._audio_to_text_request
|
||||
|
||||
def request_body(
|
||||
self, request_body: AudioToTextRequestBody
|
||||
) -> AudioToTextRequestBuilder:
|
||||
self._audio_to_text_request.request_body = request_body
|
||||
self._audio_to_text_request.body = request_body.model_dump(exclude_none=True)
|
||||
return self
|
||||
|
||||
def file(self, file: BytesIO, file_name: str) -> AudioToTextRequestBuilder:
|
||||
self._audio_to_text_request.file = file
|
||||
self._audio_to_text_request.files = {"file": (file_name, file)}
|
||||
return self
|
|
@ -0,0 +1,23 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class AudioToTextRequestBody(BaseModel):
|
||||
user: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> AudioToTextRequestBodyBuilder:
|
||||
return AudioToTextRequestBodyBuilder()
|
||||
|
||||
|
||||
class AudioToTextRequestBodyBuilder(object):
|
||||
def __init__(self):
|
||||
self._audio_to_text_request_body = AudioToTextRequestBody()
|
||||
|
||||
def build(self) -> AudioToTextRequestBody:
|
||||
return self._audio_to_text_request_body
|
||||
|
||||
def user(self, user: str) -> AudioToTextRequestBodyBuilder:
|
||||
self._audio_to_text_request_body.user = user
|
||||
return self
|
|
@ -0,0 +1,5 @@
|
|||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class AudioToTextResponse(BaseResponse):
|
||||
text: str | None = None
|
32
sdks/python-client/dify_oapi/api/chat/v1/model/chat_request.py
Executable file
32
sdks/python-client/dify_oapi/api/chat/v1/model/chat_request.py
Executable file
|
@ -0,0 +1,32 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
|
||||
from .chat_request_body import ChatRequestBody
|
||||
|
||||
|
||||
class ChatRequest(BaseRequest):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.request_body: ChatRequestBody | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> ChatRequestBuilder:
|
||||
return ChatRequestBuilder()
|
||||
|
||||
|
||||
class ChatRequestBuilder:
|
||||
def __init__(self) -> None:
|
||||
chat_request = ChatRequest()
|
||||
chat_request.http_method = HttpMethod.POST
|
||||
chat_request.uri = "/v1/chat-messages"
|
||||
self._chat_request: ChatRequest = chat_request
|
||||
|
||||
def request_body(self, request_body: ChatRequestBody) -> ChatRequestBuilder:
|
||||
self._chat_request.request_body = request_body
|
||||
self._chat_request.body = request_body.model_dump(exclude_none=True)
|
||||
return self
|
||||
|
||||
def build(self) -> ChatRequest:
|
||||
return self._chat_request
|
57
sdks/python-client/dify_oapi/api/chat/v1/model/chat_request_body.py
Executable file
57
sdks/python-client/dify_oapi/api/chat/v1/model/chat_request_body.py
Executable file
|
@ -0,0 +1,57 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .chat_request_file import ChatRequestFile
|
||||
|
||||
|
||||
class ChatRequestBody(BaseModel):
|
||||
query: str | None = None
|
||||
inputs: dict | None = None
|
||||
response_mode: str | None = None
|
||||
user: str | None = None
|
||||
conversation_id: str | None = None
|
||||
files: list[ChatRequestFile] | None = None
|
||||
auto_generate_name: bool | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> ChatRequestBodyBuilder:
|
||||
return ChatRequestBodyBuilder()
|
||||
|
||||
|
||||
class ChatRequestBodyBuilder:
|
||||
def __init__(self):
|
||||
self._chat_request_body = ChatRequestBody()
|
||||
|
||||
def query(self, query: str) -> ChatRequestBodyBuilder:
|
||||
self._chat_request_body.query = query
|
||||
return self
|
||||
|
||||
def inputs(self, inputs: dict) -> ChatRequestBodyBuilder:
|
||||
self._chat_request_body.inputs = inputs
|
||||
return self
|
||||
|
||||
def response_mode(self, response_mode: str) -> ChatRequestBodyBuilder:
|
||||
if response_mode not in ["streaming", "blocking"]:
|
||||
raise ValueError('response_mode must be either "streaming" or "blocking"')
|
||||
self._chat_request_body.response_mode = response_mode
|
||||
return self
|
||||
|
||||
def user(self, user: str) -> ChatRequestBodyBuilder:
|
||||
self._chat_request_body.user = user
|
||||
return self
|
||||
|
||||
def conversation_id(self, conversation_id: str) -> ChatRequestBodyBuilder:
|
||||
self._chat_request_body.conversation_id = conversation_id
|
||||
return self
|
||||
|
||||
def files(self, files: list[ChatRequestFile]) -> ChatRequestBodyBuilder:
|
||||
self._chat_request_body.files = files
|
||||
return self
|
||||
|
||||
def auto_generate_name(self, auto_generate_name: bool) -> ChatRequestBodyBuilder:
|
||||
self._chat_request_body.auto_generate_name = auto_generate_name
|
||||
return self
|
||||
|
||||
def build(self):
|
||||
return self._chat_request_body
|
56
sdks/python-client/dify_oapi/api/chat/v1/model/chat_request_file.py
Executable file
56
sdks/python-client/dify_oapi/api/chat/v1/model/chat_request_file.py
Executable file
|
@ -0,0 +1,56 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
|
||||
|
||||
class ChatRequestFile(BaseModel):
|
||||
type: str | None = None
|
||||
transfer_method: str | None = None
|
||||
url: HttpUrl | None = None
|
||||
upload_file_id: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> ChatRequestFileBuilder:
|
||||
return ChatRequestFileBuilder()
|
||||
|
||||
|
||||
class ChatRequestFileBuilder:
|
||||
def __init__(self):
|
||||
self._chat_request_file = ChatRequestFile()
|
||||
|
||||
def type(self, type_: str):
|
||||
if type_ != "image":
|
||||
raise ValueError("Only 'image' is supported")
|
||||
self._chat_request_file.type = type_
|
||||
return self
|
||||
|
||||
def transfer_method(self, transfer_method: str):
|
||||
if transfer_method not in ("remote_url", "local_file"):
|
||||
raise ValueError("Only 'remote_url' and 'local_file' are supported")
|
||||
self._chat_request_file.transfer_method = transfer_method
|
||||
return self
|
||||
|
||||
def url(self, url: str):
|
||||
self._chat_request_file.url = HttpUrl(url=url)
|
||||
return self
|
||||
|
||||
def upload_file_id(self, upload_file_id: str):
|
||||
self._chat_request_file.upload_file_id = upload_file_id
|
||||
return self
|
||||
|
||||
def build(self) -> ChatRequestFile:
|
||||
if (
|
||||
self._chat_request_file.transfer_method == "remote_url"
|
||||
and self._chat_request_file.url is None
|
||||
):
|
||||
raise ValueError(
|
||||
"Url needs to be set when transfer_method is set as remote_url"
|
||||
)
|
||||
if (
|
||||
self._chat_request_file.transfer_method == "local_file"
|
||||
and self._chat_request_file.upload_file_id is None
|
||||
):
|
||||
raise ValueError(
|
||||
"Upload file_id needs to be set when transfer_method is set as local_file"
|
||||
)
|
||||
return self._chat_request_file
|
19
sdks/python-client/dify_oapi/api/chat/v1/model/chat_response.py
Executable file
19
sdks/python-client/dify_oapi/api/chat/v1/model/chat_response.py
Executable file
|
@ -0,0 +1,19 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class ChatResponse(BaseResponse):
|
||||
message_id: str | None = None
|
||||
conversation_id: str | None = None
|
||||
mode: str | None = None
|
||||
answer: str | None = None
|
||||
metadata: ChatResponseMetadata | None = None
|
||||
created_at: int | None = None
|
||||
|
||||
|
||||
class ChatResponseMetadata(BaseModel):
|
||||
usage: dict | None = None
|
||||
retriever_resources: list[dict] | None = None
|
|
@ -0,0 +1,42 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
|
||||
from .delete_conversation_request_body import DeleteConversationRequestBody
|
||||
|
||||
|
||||
class DeleteConversationRequest(BaseRequest):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.conversation_id: str | None = None
|
||||
self.request_body: DeleteConversationRequestBody | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> DeleteConversationRequestBuilder:
|
||||
return DeleteConversationRequestBuilder()
|
||||
|
||||
|
||||
class DeleteConversationRequestBuilder:
|
||||
def __init__(self):
|
||||
delete_conversation_request = DeleteConversationRequest()
|
||||
delete_conversation_request.http_method = HttpMethod.DELETE
|
||||
delete_conversation_request.uri = "/v1/conversations/:conversation_id"
|
||||
self._delete_conversation_request = delete_conversation_request
|
||||
|
||||
def request_body(
|
||||
self, request_body: DeleteConversationRequestBody
|
||||
) -> DeleteConversationRequestBuilder:
|
||||
self._delete_conversation_request.request_body = request_body
|
||||
self._delete_conversation_request.body = request_body.model_dump(
|
||||
exclude_none=True
|
||||
)
|
||||
return self
|
||||
|
||||
def conversation_id(self, conversation_id: str) -> DeleteConversationRequestBuilder:
|
||||
self._delete_conversation_request.conversation_id = conversation_id
|
||||
self._delete_conversation_request.paths["conversation_id"] = conversation_id
|
||||
return self
|
||||
|
||||
def build(self) -> DeleteConversationRequest:
|
||||
return self._delete_conversation_request
|
|
@ -0,0 +1,23 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DeleteConversationRequestBody(BaseModel):
|
||||
user: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> DeleteConversationRequestBodyBuilder:
|
||||
return DeleteConversationRequestBodyBuilder()
|
||||
|
||||
|
||||
class DeleteConversationRequestBodyBuilder:
|
||||
def __init__(self):
|
||||
self._delete_conversation_request_body = DeleteConversationRequestBody()
|
||||
|
||||
def user(self, user: str):
|
||||
self._delete_conversation_request_body.user = user
|
||||
return self
|
||||
|
||||
def build(self) -> DeleteConversationRequestBody:
|
||||
return self._delete_conversation_request_body
|
|
@ -0,0 +1,5 @@
|
|||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class DeleteConversationResponse(BaseResponse):
|
||||
result: str | None = None
|
|
@ -0,0 +1,48 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
|
||||
|
||||
class GetConversationListRequest(BaseRequest):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.user: str | None = None
|
||||
self.last_id: str | None = None
|
||||
self.limit: int | None = None
|
||||
self.pinned: bool | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> GetConversationListRequestBuilder:
|
||||
return GetConversationListRequestBuilder()
|
||||
|
||||
|
||||
class GetConversationListRequestBuilder:
|
||||
def __init__(self):
|
||||
get_conversation_list_request = GetConversationListRequest()
|
||||
get_conversation_list_request.http_method = HttpMethod.GET
|
||||
get_conversation_list_request.uri = "/v1/conversations"
|
||||
self._get_conversation_list_request = get_conversation_list_request
|
||||
|
||||
def user(self, user: str) -> GetConversationListRequestBuilder:
|
||||
self._get_conversation_list_request.user = user
|
||||
self._get_conversation_list_request.add_query("user", user)
|
||||
return self
|
||||
|
||||
def last_id(self, last_id: str) -> GetConversationListRequestBuilder:
|
||||
self._get_conversation_list_request.last_id = last_id
|
||||
self._get_conversation_list_request.add_query("last_id", last_id)
|
||||
return self
|
||||
|
||||
def limit(self, limit: int) -> GetConversationListRequestBuilder:
|
||||
self._get_conversation_list_request.limit = limit
|
||||
self._get_conversation_list_request.add_query("limit", limit)
|
||||
return self
|
||||
|
||||
def pinned(self, pinned: bool) -> GetConversationListRequestBuilder:
|
||||
self._get_conversation_list_request.pinned = pinned
|
||||
self._get_conversation_list_request.add_query("pinned", str(pinned).lower())
|
||||
return self
|
||||
|
||||
def build(self) -> GetConversationListRequest:
|
||||
return self._get_conversation_list_request
|
|
@ -0,0 +1,21 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class GetConversationListResponse(BaseResponse):
|
||||
data: list[GetConversationListData] | None = None
|
||||
has_more: bool | None = None
|
||||
limit: int | None = None
|
||||
|
||||
|
||||
class GetConversationListData(BaseModel):
|
||||
id: str | None = None
|
||||
name: str | None = None
|
||||
inputs: dict | None = None
|
||||
status: str | None = None
|
||||
introduction: str | None = None
|
||||
created_at: int | None = None
|
||||
updated_at: int | None = None
|
48
sdks/python-client/dify_oapi/api/chat/v1/model/message_history_request.py
Executable file
48
sdks/python-client/dify_oapi/api/chat/v1/model/message_history_request.py
Executable file
|
@ -0,0 +1,48 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
|
||||
|
||||
class MessageHistoryRequest(BaseRequest):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.conversation_id: str | None = None
|
||||
self.user: str | None = None
|
||||
self.first_id: str | None = None
|
||||
self.limit: int | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> MessageHistoryRequestBuilder:
|
||||
return MessageHistoryRequestBuilder()
|
||||
|
||||
|
||||
class MessageHistoryRequestBuilder:
|
||||
def __init__(self):
|
||||
message_history_request = MessageHistoryRequest()
|
||||
message_history_request.http_method = HttpMethod.GET
|
||||
message_history_request.uri = "/v1/messages"
|
||||
self._message_history_request = message_history_request
|
||||
|
||||
def build(self) -> MessageHistoryRequest:
|
||||
return self._message_history_request
|
||||
|
||||
def conversation_id(self, conversation_id: str):
|
||||
self._message_history_request.conversation_id = conversation_id
|
||||
self._message_history_request.add_query("conversation_id", conversation_id)
|
||||
return self
|
||||
|
||||
def user(self, user: str):
|
||||
self._message_history_request.user = user
|
||||
self._message_history_request.add_query("user", user)
|
||||
return self
|
||||
|
||||
def first_id(self, first_id: str):
|
||||
self._message_history_request.first_id = first_id
|
||||
self._message_history_request.add_query("first_id", first_id)
|
||||
return self
|
||||
|
||||
def limit(self, limit: int):
|
||||
self._message_history_request.limit = limit
|
||||
self._message_history_request.add_query("limit", limit)
|
||||
return self
|
49
sdks/python-client/dify_oapi/api/chat/v1/model/message_history_response.py
Executable file
49
sdks/python-client/dify_oapi/api/chat/v1/model/message_history_response.py
Executable file
|
@ -0,0 +1,49 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class MessageHistoryResponse(BaseResponse):
|
||||
data: list[dict] | None = None
|
||||
id: str | None = None
|
||||
conversation_id: str | None = None
|
||||
inputs: list[dict] | None = None
|
||||
query: str | None = None
|
||||
message_files: list[MessageHistoryResponseFile] | None = None
|
||||
answer: str | None = None
|
||||
created_at: int | None = None
|
||||
feedback: MessageHistoryResponseFeedback | None = None
|
||||
retriever_resources: list[dict] | None = None
|
||||
has_more: bool | None = None
|
||||
limit: int | None = None
|
||||
|
||||
|
||||
class MessageHistoryResponseFeedback(BaseModel):
|
||||
rating: str | None = None
|
||||
|
||||
|
||||
class MessageHistoryResponseFile(BaseModel):
|
||||
id: str | None = None
|
||||
type: str | None = None
|
||||
url: str | None = None
|
||||
belongs_to: str | None = None
|
||||
agent_thoughts: list[MessageHistoryResponseFileAgentThought] | None = None
|
||||
|
||||
|
||||
class MessageHistoryResponseFileAgentThought(BaseResponse):
|
||||
id: str | None = None
|
||||
message_id: str | None = None
|
||||
position: int | None = None
|
||||
thought: str | None = None
|
||||
observation: str | None = None
|
||||
tool: str | None = None
|
||||
tool_input: str | None = None
|
||||
created_at: int | None = None
|
||||
message_files: list[MessageHistoryResponseFileAgentThoughtFile] | None = None
|
||||
conversation_id: str | None = None
|
||||
|
||||
|
||||
class MessageHistoryResponseFileAgentThoughtFile(BaseModel):
|
||||
file_id: str | None = None
|
36
sdks/python-client/dify_oapi/api/chat/v1/model/message_suggested_request.py
Executable file
36
sdks/python-client/dify_oapi/api/chat/v1/model/message_suggested_request.py
Executable file
|
@ -0,0 +1,36 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
|
||||
|
||||
class MessageSuggestedRequest(BaseRequest):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.message_id: str | None = None
|
||||
self.user: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> MessageSuggestedRequestBuilder:
|
||||
return MessageSuggestedRequestBuilder()
|
||||
|
||||
|
||||
class MessageSuggestedRequestBuilder:
|
||||
def __init__(self):
|
||||
message_suggested_request = MessageSuggestedRequest()
|
||||
message_suggested_request.http_method = HttpMethod.GET
|
||||
message_suggested_request.uri = "/v1/messages/:message_id/suggested"
|
||||
self._message_suggested_request = message_suggested_request
|
||||
|
||||
def build(self) -> MessageSuggestedRequest:
|
||||
return self._message_suggested_request
|
||||
|
||||
def message_id(self, message_id: str):
|
||||
self._message_suggested_request.message_id = message_id
|
||||
self._message_suggested_request.paths["message_id"] = message_id
|
||||
return self
|
||||
|
||||
def user(self, user: str):
|
||||
self._message_suggested_request.user = user
|
||||
self._message_suggested_request.add_query("user", user)
|
||||
return self
|
|
@ -0,0 +1,6 @@
|
|||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class MessageSuggestedResponse(BaseResponse):
|
||||
result: str | None = None
|
||||
data: list[str] | None = None
|
|
@ -0,0 +1,42 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
|
||||
from .rename_conversation_request_body import RenameConversationRequestBody
|
||||
|
||||
|
||||
class RenameConversationRequest(BaseRequest):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.conversation_id: str | None = None
|
||||
self.request_body: RenameConversationRequestBody | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> RenameConversationRequestBuilder:
|
||||
return RenameConversationRequestBuilder()
|
||||
|
||||
|
||||
class RenameConversationRequestBuilder:
|
||||
def __init__(self):
|
||||
rename_conversation_request = RenameConversationRequest()
|
||||
rename_conversation_request.http_method = HttpMethod.POST
|
||||
rename_conversation_request.uri = "/v1/conversations/:conversation_id/name"
|
||||
self._rename_conversation_request = rename_conversation_request
|
||||
|
||||
def build(self) -> RenameConversationRequest:
|
||||
return self._rename_conversation_request
|
||||
|
||||
def request_body(
|
||||
self, request_body: RenameConversationRequestBody
|
||||
) -> RenameConversationRequestBuilder:
|
||||
self._rename_conversation_request.request_body = request_body
|
||||
self._rename_conversation_request.body = request_body.model_dump(
|
||||
exclude_none=True
|
||||
)
|
||||
return self
|
||||
|
||||
def conversation_id(self, conversation_id: str) -> RenameConversationRequestBuilder:
|
||||
self._rename_conversation_request.conversation_id = conversation_id
|
||||
self._rename_conversation_request.paths["conversation_id"] = conversation_id
|
||||
return self
|
|
@ -0,0 +1,35 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class RenameConversationRequestBody(BaseModel):
|
||||
name: str | None = None
|
||||
auto_generate: bool | None = None
|
||||
user: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> RenameConversationRequestBodyBuilder:
|
||||
return RenameConversationRequestBodyBuilder()
|
||||
|
||||
|
||||
class RenameConversationRequestBodyBuilder:
|
||||
def __init__(self):
|
||||
self._rename_conversation_request_body = RenameConversationRequestBody()
|
||||
|
||||
def builder(self) -> RenameConversationRequestBody:
|
||||
return self._rename_conversation_request_body
|
||||
|
||||
def name(self, name: str) -> RenameConversationRequestBodyBuilder:
|
||||
self._rename_conversation_request_body.name = name
|
||||
return self
|
||||
|
||||
def auto_generate(
|
||||
self, auto_generate: bool
|
||||
) -> RenameConversationRequestBodyBuilder:
|
||||
self._rename_conversation_request_body.auto_generate = auto_generate
|
||||
return self
|
||||
|
||||
def user(self, user: str) -> RenameConversationRequestBodyBuilder:
|
||||
self._rename_conversation_request_body.user = user
|
||||
return self
|
|
@ -0,0 +1,11 @@
|
|||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class RenameConversationResponse(BaseResponse):
|
||||
id: str | None = None
|
||||
result: str | None = None
|
||||
inputs: dict | None = None
|
||||
status: str | None = None
|
||||
introduction: str | None = None
|
||||
created_at: int | None = None
|
||||
updated_at: int | None = None
|
38
sdks/python-client/dify_oapi/api/chat/v1/model/stop_chat_request.py
Executable file
38
sdks/python-client/dify_oapi/api/chat/v1/model/stop_chat_request.py
Executable file
|
@ -0,0 +1,38 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dify_oapi.core.enum import HttpMethod
|
||||
from dify_oapi.core.model.base_request import BaseRequest
|
||||
|
||||
from .stop_chat_request_body import StopChatRequestBody
|
||||
|
||||
|
||||
class StopChatRequest(BaseRequest):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.task_id: str | None = None
|
||||
self.request_body: StopChatRequestBody | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> StopChatRequestBuilder:
|
||||
return StopChatRequestBuilder()
|
||||
|
||||
|
||||
class StopChatRequestBuilder:
|
||||
def __init__(self) -> None:
|
||||
stop_chat_request = StopChatRequest()
|
||||
stop_chat_request.http_method = HttpMethod.POST
|
||||
stop_chat_request.uri = "/v1/chat-messages/:task_id/stop"
|
||||
self._stop_chat_request: StopChatRequest = stop_chat_request
|
||||
|
||||
def task_id(self, task_id: str) -> StopChatRequestBuilder:
|
||||
self._stop_chat_request.task_id = task_id
|
||||
self._stop_chat_request.paths["task_id"] = str(task_id)
|
||||
return self
|
||||
|
||||
def request_body(self, request_body: StopChatRequestBody) -> StopChatRequestBuilder:
|
||||
self._stop_chat_request.request_body = request_body
|
||||
self._stop_chat_request.body = request_body.model_dump(exclude_none=True)
|
||||
return self
|
||||
|
||||
def build(self) -> StopChatRequest:
|
||||
return self._stop_chat_request
|
23
sdks/python-client/dify_oapi/api/chat/v1/model/stop_chat_request_body.py
Executable file
23
sdks/python-client/dify_oapi/api/chat/v1/model/stop_chat_request_body.py
Executable file
|
@ -0,0 +1,23 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class StopChatRequestBody(BaseModel):
|
||||
user: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def builder() -> StopChatRequestBodyBuilder:
|
||||
return StopChatRequestBodyBuilder()
|
||||
|
||||
|
||||
class StopChatRequestBodyBuilder:
|
||||
def __init__(self):
|
||||
self._stop_chat_request_body = StopChatRequestBody()
|
||||
|
||||
def user(self, user: str) -> StopChatRequestBodyBuilder:
|
||||
self._stop_chat_request_body.user = user
|
||||
return self
|
||||
|
||||
def build(self) -> StopChatRequestBody:
|
||||
return self._stop_chat_request_body
|
5
sdks/python-client/dify_oapi/api/chat/v1/model/stop_chat_response.py
Executable file
5
sdks/python-client/dify_oapi/api/chat/v1/model/stop_chat_response.py
Executable file
|
@ -0,0 +1,5 @@
|
|||
from dify_oapi.core.model.base_response import BaseResponse
|
||||
|
||||
|
||||
class StopChatResponse(BaseResponse):
|
||||
result: str | None = None
|
4
sdks/python-client/dify_oapi/api/chat/v1/resource/__init__.py
Executable file
4
sdks/python-client/dify_oapi/api/chat/v1/resource/__init__.py
Executable file
|
@ -0,0 +1,4 @@
|
|||
from .chat import * # noqa F403
|
||||
from .conversation import * # noqa 403
|
||||
from .message import * # noqa 403
|
||||
from .audio import * # noqa 403
|
25
sdks/python-client/dify_oapi/api/chat/v1/resource/audio.py
Normal file
25
sdks/python-client/dify_oapi/api/chat/v1/resource/audio.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from dify_oapi.core.http.transport import ATransport, Transport
|
||||
from dify_oapi.core.model.config import Config
|
||||
from dify_oapi.core.model.request_option import RequestOption
|
||||
|
||||
from ..model.audio_to_text_request import AudioToTextRequest
|
||||
from ..model.audio_to_text_response import AudioToTextResponse
|
||||
|
||||
|
||||
class Audio:
|
||||
def __init__(self, config: Config) -> None:
|
||||
self.config: Config = config
|
||||
|
||||
def to_text(
|
||||
self, request: AudioToTextRequest, option: RequestOption | None = None
|
||||
) -> AudioToTextResponse:
|
||||
return Transport.execute(
|
||||
self.config, request, unmarshal_as=AudioToTextResponse, option=option
|
||||
)
|
||||
|
||||
async def ato_text(
|
||||
self, request: AudioToTextRequest, option: RequestOption | None = None
|
||||
) -> AudioToTextResponse:
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, unmarshal_as=AudioToTextResponse, option=option
|
||||
)
|
93
sdks/python-client/dify_oapi/api/chat/v1/resource/chat.py
Executable file
93
sdks/python-client/dify_oapi/api/chat/v1/resource/chat.py
Executable file
|
@ -0,0 +1,93 @@
|
|||
from collections.abc import AsyncGenerator, Generator
|
||||
from typing import Literal, overload
|
||||
|
||||
from dify_oapi.core.const import APPLICATION_JSON, CONTENT_TYPE
|
||||
from dify_oapi.core.http.transport import ATransport, Transport
|
||||
from dify_oapi.core.model.config import Config
|
||||
from dify_oapi.core.model.request_option import RequestOption
|
||||
|
||||
from ..model.chat_request import ChatRequest
|
||||
from ..model.chat_response import ChatResponse
|
||||
from ..model.stop_chat_request import StopChatRequest
|
||||
from ..model.stop_chat_response import StopChatResponse
|
||||
|
||||
|
||||
class Chat:
|
||||
def __init__(self, config: Config) -> None:
|
||||
self.config: Config = config
|
||||
|
||||
@overload
|
||||
def chat(
|
||||
self, request: ChatRequest, option: RequestOption | None, stream: Literal[True]
|
||||
) -> Generator[bytes, None, None]: ...
|
||||
|
||||
@overload
|
||||
def chat(
|
||||
self, request: ChatRequest, option: RequestOption | None, stream: Literal[False]
|
||||
) -> ChatResponse: ...
|
||||
|
||||
@overload
|
||||
def chat(
|
||||
self, request: ChatRequest, option: RequestOption | None
|
||||
) -> ChatResponse: ...
|
||||
|
||||
def chat(
|
||||
self,
|
||||
request: ChatRequest,
|
||||
option: RequestOption | None = None,
|
||||
stream: bool = False,
|
||||
):
|
||||
if request.body is not None:
|
||||
option.headers[CONTENT_TYPE] = f"{APPLICATION_JSON}; charset=utf-8"
|
||||
if stream:
|
||||
return Transport.execute(self.config, request, option=option, stream=True)
|
||||
else:
|
||||
return Transport.execute(
|
||||
self.config, request, unmarshal_as=ChatResponse, option=option
|
||||
)
|
||||
|
||||
@overload
|
||||
async def achat(
|
||||
self, request: ChatRequest, option: RequestOption | None, stream: Literal[True]
|
||||
) -> AsyncGenerator[bytes, None]: ...
|
||||
|
||||
@overload
|
||||
def achat(
|
||||
self, request: ChatRequest, option: RequestOption | None, stream: Literal[False]
|
||||
) -> ChatResponse: ...
|
||||
|
||||
@overload
|
||||
async def achat(
|
||||
self, request: ChatRequest, option: RequestOption | None
|
||||
) -> ChatResponse: ...
|
||||
|
||||
async def achat(
|
||||
self,
|
||||
request: ChatRequest,
|
||||
option: RequestOption | None = None,
|
||||
stream: bool = False,
|
||||
):
|
||||
if stream:
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, option=option, stream=True
|
||||
)
|
||||
else:
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, unmarshal_as=ChatResponse, option=option
|
||||
)
|
||||
|
||||
def stop(
|
||||
self, request: StopChatRequest, option: RequestOption | None = None
|
||||
) -> StopChatResponse:
|
||||
if request.body is not None:
|
||||
option.headers[CONTENT_TYPE] = f"{APPLICATION_JSON}; charset=utf-8"
|
||||
return Transport.execute(
|
||||
self.config, request, unmarshal_as=StopChatResponse, option=option
|
||||
)
|
||||
|
||||
async def astop(
|
||||
self, request: StopChatRequest, option: RequestOption | None = None
|
||||
) -> StopChatResponse:
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, unmarshal_as=StopChatResponse, option=option
|
||||
)
|
76
sdks/python-client/dify_oapi/api/chat/v1/resource/conversation.py
Executable file
76
sdks/python-client/dify_oapi/api/chat/v1/resource/conversation.py
Executable file
|
@ -0,0 +1,76 @@
|
|||
from dify_oapi.core.const import APPLICATION_JSON, CONTENT_TYPE
|
||||
from dify_oapi.core.http.transport import ATransport, Transport
|
||||
from dify_oapi.core.model.config import Config
|
||||
from dify_oapi.core.model.request_option import RequestOption
|
||||
|
||||
from ..model.delete_conversation_request import DeleteConversationRequest
|
||||
from ..model.delete_conversation_response import DeleteConversationResponse
|
||||
from ..model.get_conversation_list_request import GetConversationListRequest
|
||||
from ..model.get_conversation_list_response import GetConversationListResponse
|
||||
from ..model.rename_conversation_request import RenameConversationRequest
|
||||
from ..model.rename_conversation_response import RenameConversationResponse
|
||||
|
||||
|
||||
class Conversation:
|
||||
def __init__(self, config: Config) -> None:
|
||||
self.config: Config = config
|
||||
|
||||
def list(
|
||||
self, request: GetConversationListRequest, option: RequestOption | None = None
|
||||
) -> GetConversationListResponse:
|
||||
# 添加 content-type
|
||||
if request.body is not None:
|
||||
option.headers[CONTENT_TYPE] = f"{APPLICATION_JSON}; charset=utf-8"
|
||||
|
||||
# 发起请求
|
||||
return Transport.execute(
|
||||
self.config,
|
||||
request,
|
||||
unmarshal_as=GetConversationListResponse,
|
||||
option=option,
|
||||
)
|
||||
|
||||
async def alist(
|
||||
self, request: GetConversationListRequest, option: RequestOption | None = None
|
||||
) -> GetConversationListResponse:
|
||||
# 发起请求
|
||||
return await ATransport.aexecute(
|
||||
self.config,
|
||||
request,
|
||||
unmarshal_as=GetConversationListResponse,
|
||||
option=option,
|
||||
)
|
||||
|
||||
def delete(
|
||||
self, request: DeleteConversationRequest, option: RequestOption | None = None
|
||||
) -> DeleteConversationResponse:
|
||||
if request.body is not None:
|
||||
option.headers[CONTENT_TYPE] = f"{APPLICATION_JSON}; charset=utf-8"
|
||||
return Transport.execute(
|
||||
self.config, request, unmarshal_as=DeleteConversationResponse, option=option
|
||||
)
|
||||
|
||||
async def adelete(
|
||||
self, request: DeleteConversationRequest, option: RequestOption | None = None
|
||||
) -> DeleteConversationResponse:
|
||||
# 发起请求
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, unmarshal_as=DeleteConversationResponse, option=option
|
||||
)
|
||||
|
||||
def rename(
|
||||
self, request: RenameConversationRequest, option: RequestOption | None = None
|
||||
) -> RenameConversationResponse:
|
||||
if request.body is not None:
|
||||
option.headers[CONTENT_TYPE] = f"{APPLICATION_JSON}; charset=utf-8"
|
||||
return Transport.execute(
|
||||
self.config, request, unmarshal_as=RenameConversationResponse, option=option
|
||||
)
|
||||
|
||||
async def arename(
|
||||
self, request: RenameConversationRequest, option: RequestOption | None = None
|
||||
) -> RenameConversationResponse:
|
||||
# 发起请求
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, unmarshal_as=RenameConversationResponse, option=option
|
||||
)
|
54
sdks/python-client/dify_oapi/api/chat/v1/resource/message.py
Executable file
54
sdks/python-client/dify_oapi/api/chat/v1/resource/message.py
Executable file
|
@ -0,0 +1,54 @@
|
|||
from dify_oapi.core.const import APPLICATION_JSON, CONTENT_TYPE
|
||||
from dify_oapi.core.http.transport import ATransport, Transport
|
||||
from dify_oapi.core.model.config import Config
|
||||
from dify_oapi.core.model.request_option import RequestOption
|
||||
|
||||
from ..model.message_history_request import MessageHistoryRequest
|
||||
from ..model.message_history_response import MessageHistoryResponse
|
||||
from ..model.message_suggested_request import MessageSuggestedRequest
|
||||
from ..model.message_suggested_response import MessageSuggestedResponse
|
||||
|
||||
|
||||
class Message:
|
||||
def __init__(self, config: Config) -> None:
|
||||
self.config: Config = config
|
||||
|
||||
def suggested(
|
||||
self, request: MessageSuggestedRequest, option: RequestOption | None = None
|
||||
) -> MessageSuggestedResponse:
|
||||
# 添加 content-type
|
||||
if request.body is not None:
|
||||
option.headers[CONTENT_TYPE] = f"{APPLICATION_JSON}; charset=utf-8"
|
||||
|
||||
# 发起请求
|
||||
return Transport.execute(
|
||||
self.config, request, unmarshal_as=MessageSuggestedResponse, option=option
|
||||
)
|
||||
|
||||
async def asuggested(
|
||||
self, request: MessageSuggestedRequest, option: RequestOption | None = None
|
||||
) -> MessageSuggestedResponse:
|
||||
# 发起请求
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, unmarshal_as=MessageSuggestedResponse, option=option
|
||||
)
|
||||
|
||||
def history(
|
||||
self, request: MessageHistoryRequest, option: RequestOption | None = None
|
||||
) -> MessageHistoryResponse:
|
||||
# 添加 content-type
|
||||
if request.body is not None:
|
||||
option.headers[CONTENT_TYPE] = f"{APPLICATION_JSON}; charset=utf-8"
|
||||
|
||||
# 发起请求
|
||||
return Transport.execute(
|
||||
self.config, request, unmarshal_as=MessageHistoryResponse, option=option
|
||||
)
|
||||
|
||||
async def ahistory(
|
||||
self, request: MessageHistoryRequest, option: RequestOption | None = None
|
||||
) -> MessageHistoryResponse:
|
||||
# 发起请求
|
||||
return await ATransport.aexecute(
|
||||
self.config, request, unmarshal_as=MessageHistoryResponse, option=option
|
||||
)
|
11
sdks/python-client/dify_oapi/api/chat/v1/version.py
Executable file
11
sdks/python-client/dify_oapi/api/chat/v1/version.py
Executable file
|
@ -0,0 +1,11 @@
|
|||
from dify_oapi.core.model.config import Config
|
||||
|
||||
from .resource import Chat, Conversation, Message, Audio
|
||||
|
||||
|
||||
class V1:
|
||||
def __init__(self, config: Config):
|
||||
self.chat: Chat = Chat(config)
|
||||
self.conversation: Conversation = Conversation(config)
|
||||
self.message: Message = Message(config)
|
||||
self.audio: Audio = Audio(config)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user