Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +4 -0
- .gitignore +2 -0
- None/testing_chat_store.json +1 -0
- README.md +1 -1
- api.py +27 -0
- data/config.yaml +26 -0
- data/csv/t_sur_media_sync_es.csv +3 -0
- data/csv/t_sur_models_info.csv +3 -0
- data/pdf/alice.pdf +3 -0
- data/txt/blog/11 Steps To Make A Woman Orgasm (The Basics & Beyond).txt +4 -0
- data/txt/blog/Blowjobs_ What Are They and How to Give One.txt +20 -0
- data/txt/blog/Female Orgasm_ Types, Feeling, and How to Have One.txt +40 -0
- data/txt/blog/Female orgasm_ Everything you need to know.txt +74 -0
- data/txt/blog/Female orgasms_ Different types & how to climax.txt +54 -0
- data/txt/blog/Orgasm & Female Orgasm_ How many types of orgasm are there_.txt +104 -0
- environment.yml +350 -0
- fetishTest/Q&A.json +62 -0
- fetishTest/api.py +66 -0
- fetishTest/character.py +26 -0
- fetishTest/fetish_test.py +170 -0
- fetishTest/standard_character.json +0 -0
- fetishTest/test.py +30 -0
- milvusDB/prepare_milvus.py +215 -0
- milvusDB/retriever.py +115 -0
- milvusDB/update_milvus.py +275 -0
- pipeline/__init__.py +0 -0
- pipeline/chat_pipeline.py +97 -0
- pipeline/kb_pipeline.py +0 -0
- pipeline/modules.py +112 -0
- pipeline/search_pipeline.py +35 -0
- pipeline/sql_pipeline.py +224 -0
- pipeline/table_infos.py +30 -0
- pipeline/text2sql_dag.html +0 -0
- prompts/README.md +11 -0
- prompts/__init__.py +0 -0
- prompts/agent_prompts.py +132 -0
- prompts/default_prompts.py +469 -0
- requirements.txt +347 -0
- response_body.txt +642 -0
- routers/__init__.py +0 -0
- routers/sql_chat.py +204 -0
- routers/update_kb.py +27 -0
- tests/README.md +6 -0
- tests/__init__.py +0 -0
- tests/agent_workflow.py +198 -0
- tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/data_level0.bin +3 -0
- tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/header.bin +3 -0
- tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/length.bin +3 -0
- tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/link_lists.bin +0 -0
- tests/chroma_db/chroma.sqlite3 +3 -0
.gitattributes
CHANGED
@@ -35,3 +35,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
chroma_db/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
37 |
milvus_llamaindex.db filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
chroma_db/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
37 |
milvus_llamaindex.db filter=lfs diff=lfs merge=lfs -text
|
38 |
+
data/csv/t_sur_media_sync_es.csv filter=lfs diff=lfs merge=lfs -text
|
39 |
+
data/csv/t_sur_models_info.csv filter=lfs diff=lfs merge=lfs -text
|
40 |
+
data/pdf/alice.pdf filter=lfs diff=lfs merge=lfs -text
|
41 |
+
tests/chroma_db/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
**/__pycache__
|
2 |
+
.env
|
None/testing_chat_store.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"store": {}, "class_name": "SimpleChatStore"}
|
README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
---
|
2 |
title: SexBot
|
3 |
-
app_file: roleplay_gradio.py
|
4 |
sdk: gradio
|
5 |
sdk_version: 5.10.0
|
6 |
---
|
|
|
1 |
---
|
2 |
title: SexBot
|
3 |
+
app_file: ./tests/roleplay_gradio.py
|
4 |
sdk: gradio
|
5 |
sdk_version: 5.10.0
|
6 |
---
|
api.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI
|
2 |
+
from routers.sql_chat import sql_chat_router, chat_store_manager, roleplay_router
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
import uvicorn, os
|
5 |
+
|
6 |
+
BASE=os.path.dirname(os.path.abspath(__file__))
|
7 |
+
load_dotenv()
|
8 |
+
|
9 |
+
app = FastAPI(
|
10 |
+
title="chat",
|
11 |
+
description="chatbot",
|
12 |
+
)
|
13 |
+
|
14 |
+
app.include_router(sql_chat_router)
|
15 |
+
app.include_router(chat_store_manager)
|
16 |
+
app.include_router(roleplay_router)
|
17 |
+
|
18 |
+
if __name__ == "__main__":
|
19 |
+
uvicorn.run(
|
20 |
+
"api:app",
|
21 |
+
host="0.0.0.0",
|
22 |
+
port=8000,
|
23 |
+
loop="asyncio",
|
24 |
+
workers=8,
|
25 |
+
timeout_keep_alive=60,
|
26 |
+
access_log=True
|
27 |
+
)
|
data/config.yaml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
PDF_FILES:
|
2 |
+
- /data1/home/purui/projects/chatbot/data/pdf/alice.pdf
|
3 |
+
PDF_PATH: /data1/home/purui/projects/chatbot/data/pdf
|
4 |
+
ROOT: /data1/home/purui/projects/chatbot/data
|
5 |
+
TXT_FILES:
|
6 |
+
- /data1/home/purui/projects/chatbot/data/txt/Female orgasms_ Different types &
|
7 |
+
how to climax.txt
|
8 |
+
- /data1/home/purui/projects/chatbot/data/txt/Orgasm & Female Orgasm_ How many types
|
9 |
+
of orgasm are there_.txt
|
10 |
+
- /data1/home/purui/projects/chatbot/data/txt/Blowjobs_ What Are They and How to Give
|
11 |
+
One.txt
|
12 |
+
- /data1/home/purui/projects/chatbot/data/txt/Female Orgasm_ Types, Feeling, and How
|
13 |
+
to Have One.txt
|
14 |
+
- /data1/home/purui/projects/chatbot/data/txt/Oral Sex_ 36 Tips, Techniques, Positions
|
15 |
+
for the Vagina, Penis, Anus.txt
|
16 |
+
- /data1/home/purui/projects/chatbot/data/txt/11 Steps To Make A Woman Orgasm (The
|
17 |
+
Basics & Beyond).txt
|
18 |
+
- /data1/home/purui/projects/chatbot/data/txt/Female orgasm_ Everything you need to
|
19 |
+
know.txt
|
20 |
+
- /data1/home/purui/projects/chatbot/data/txt/27 Orgasmic Blow Job Tips To Make Your
|
21 |
+
Man Explode!.txt
|
22 |
+
- "/data1/home/purui/projects/chatbot/data/txt/How to Give a Blow Job \u2014 42 Blow\
|
23 |
+
\ Job Tips From Experts.txt"
|
24 |
+
- /data1/home/purui/projects/chatbot/data/txt/How to Make a Woman Orgasm, According
|
25 |
+
to Research.txt
|
26 |
+
TXT_PATH: /data1/home/purui/projects/chatbot/data/txt
|
data/csv/t_sur_media_sync_es.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ec17a0270fe2f06ec0b6d3d77a86dbf9db17347f0c1e0a7ede373893736feec4
|
3 |
+
size 228215687
|
data/csv/t_sur_models_info.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:0402bb15d536fa47a4630c504082f068a86b83e81ccba799de76e98a48595c37
|
3 |
+
size 100011589
|
data/pdf/alice.pdf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:31ffbb580c5c2d8ad6137f69346038e3a9e410961872390d7e50ac58ec120bb0
|
3 |
+
size 175735
|
data/txt/blog/11 Steps To Make A Woman Orgasm (The Basics & Beyond).txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
11 Steps To Make A Woman Orgasm (The Basics & Beyond)
|
2 |
+
Https, Www.Facebook.Com Morganmandriotawriter
|
3 |
+
None
|
4 |
+
Hartzell likes to refer to sex toys as the "hearing aid for the clitoris" because vibrators can help speed the process along and provide more intense orgasms that manual or oral stimulation may not offer. Experiment with different types of pleasure products and sensations before, during, or after penetrative sex to stimulate the clitoris and inspire maximum pleasure (and perhaps even multiple orgasms).
|
data/txt/blog/Blowjobs_ What Are They and How to Give One.txt
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Blowjobs: What Are They and How to Give One
|
2 |
+
|
3 |
+
None
|
4 |
+
What Is a Blowjob?
|
5 |
+
|
6 |
+
Oral sex is the act of stimulating a partner’s genitals or anus with your mouth and tongue. A blowjob, sometimes called fellatio, is a type of oral sex in which a person stimulates their partner’s penis with their mouth and tongue. It can include licking, sucking, kissing, or any other activity that involves the mouth.
|
7 |
+
|
8 |
+
A blowjob, also known as fellatio, is when someone uses their mouth to stimulate their partner's penis. (Illustration: WebMD)
|
9 |
+
|
10 |
+
Blowjobs, along with other types of oral sex, are often part of foreplay before vaginal or anal penetration. But you can give or receive a blowjob on its own, or during or after intercourse.
|
11 |
+
|
12 |
+
Research suggests that most people have oral sex before their first experience with vaginal or anal penetration.
|
13 |
+
|
14 |
+
Who can give and receive blowjobs?
|
15 |
+
|
16 |
+
Any consenting adult can give a blowjob, whatever their gender or sexual orientation. Any consenting adult with a penis can receive a blowjob.
|
17 |
+
|
18 |
+
What is it like to give or receive a blowjob?
|
19 |
+
|
20 |
+
Sensations could range from discomfort to extreme pleasure, so focus on what feels good for both partners while you’re discovering oral sex. Keep in mind that each person's anatomy, smell, and taste are different, and so is what they find pleasurable. If you feel uncomfortable at any point, don’t be afraid to stop or change what you're doing, or to ask your partner to do so.
|
data/txt/blog/Female Orgasm_ Types, Feeling, and How to Have One.txt
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Female Orgasm: Types, Feeling, and How to Have One
|
2 |
+
Adrienne Santos-Longhurst, How We Reviewed This Article
|
3 |
+
None
|
4 |
+
You can orgasm from stimulation to the clitoris, vagina, or cervix — or some combination of the three. You may also be able to orgasm from stimulating other areas of the body as well. “Female orgasm” is an all-encompassing term for any type of orgasm related to vulva and vagina. It could be clitoral, vaginal, even cervical — or a mix of all three. That said, your genitalia isn’t your only option when it comes to reaching the big O. Read on for tips on where to touch, how to move, why it works, and more.
|
5 |
+
|
6 |
+
Clitoral orgasm Direct or indirect stimulation of the clitoris can lead to a clitoral orgasm. When you get your rub on just right, you’ll feel the sensation build in your pleasure bud and peak. Try this Your fingers, palm, or a small vibrator can all help you have a clitoral orgasm. Make sure your clitoris is wet and begin gently rubbing in an up-and-down, circular, or side-to-side motion. As it begins to feel good, apply faster and harder pressure in a repetitive motion. When you feel your pleasure intensify, apply even more pressure to the motion to take yourself over the edge.
|
7 |
+
|
8 |
+
Vaginal orgasm Although few people can climax with vaginal stimulation alone, it sure can be fun trying! If you’re able to make it happen, prepare for an intense climax that can be felt deep inside your body. The front vaginal wall is also home to the anterior fornix or A-spot. Older research suggests that stimulating the A-spot can result in intense lubrication and even orgasm. Try this Fingers or a sex toy should do the trick. Since the pleasure comes from the vaginal walls, you’ll want to experiment with width. Do this by inserting an extra finger or two into the vagina, or try a dildo with some extra girth. To stimulate the A-spot, focus the pressure on the front wall of the vagina while sliding your fingers or toy in and out. Stick with the pressure and motion that feels the best, and let the pleasure mount.
|
9 |
+
|
10 |
+
Cervical orgasm Cervical stimulation has the potential to lead to a full-body orgasm that can send waves of tingly pleasure from your head to your toes. And this is an orgasm that can keep on giving, lasting quite a while for some. Try this Being relaxed and aroused is key to cervical orgasm. Use your imagination, rub your clitoris, or let a partner work some manual magic. Your cervix is the lower end of your uterus, so reaching it means going in deep. The doggy-style position allows for deep penetration, so try being on all fours with a penetrative toy or partner. Start off slow, gradually working your way deeper until you find a depth that feels good, and keep at it so the pleasure can build.
|
11 |
+
|
12 |
+
Combination or combined orgasm A combo orgasm may happen if you pleasure your vagina and clitoris simultaneously. The result: a powerful climax that you can feel inside and out. Try this Use both your hands to double your pleasure, or combine fingers and sex toys. Rabbit vibrators, for example, can stimulate the clitoris and vagina at the same time and are perfect for mastering the combo orgasm. Use parallel rhythms while playing with your clitoris and vagina, or switch it up with fast clitoral action and slow vaginal penetration.
|
13 |
+
|
14 |
+
You can orgasm from other stimulation, too The genitals are awesome, but they’re not your only option. Your body is full of erogenous zones with orgasmic potential. Nipple According to a 2011 study, when stimulated, your nipples set your genital sensory cortex ablaze. This is the same area of the brain that lights up during vaginal or clitoral stimulation. Nipple orgasms are said to sneak up on you and then explode in waves of full-body pleasure. Yes, please! Try this: Use your hands to caress and squeeze your breasts and other parts of your body, avoiding the nipples at first. Move on to teasing your areola by tracing it with your fingertips until you’re turned on, then show your nipples some love by rubbing and pinching them until you reach maximum pleasure. Anal You don’t need to have a prostate to have an anal orgasm. Anal play can be pleasurable for anyone if you have enough lube and take your time. You can indirectly stimulate erogenous zones within the vagina using a finger or sex toy. Try this: Apply ample lube with your fingers and massage it around the outside and inside of the anus. Slowly and gently insert your sex toy or finger into your anus. Start with a gentle in-and-out motion, then move in a circular motion. Alternate between the two and pick up the pace as your pleasure builds. Erogenous zones Your body is truly a wonderland. The neck, ears, and lower back, for example, are rich in erotically charged nerve endings begging to be touched. We can’t say exactly which parts of your body will drive you to the brink, but we can tell you that everyone has erogenous zones, and finding them is worth the effort. Try this: Take a feather or silky scarf and use it to find your body’s most sensitive areas. Get naked and relax so you can focus on every tingle. Take note of these spots, and try experimenting with different sensations, like squeezing or pinching. Practice makes perfect, so take pleasure in these areas and keep at it to see how far you can go.
|
15 |
+
|
16 |
+
Where does the G-spot come in? The G-spot is an area along the front wall of your vagina. For some people, it can produce a very intense and very wet orgasm when stimulated. Your fingers or a curved G-spot vibrator are the best way to hit the spot. Squatting will give you the best angle. Try this: Squat with the back of your thighs close to or touching your heels, and insert your fingers or toy into your vagina. Curl your fingers toward your belly button and move them in a “come here” motion. If you happen to find an area that feels especially good, keep going — even if you feel like you have to pee — and enjoy the full-body release.
|
17 |
+
|
18 |
+
What happens in the body when you orgasm? Everyone’s body is different, and so are orgasms. Some are more intense than others. Some last longer than others. Some are wetter than others. What physically happens during orgasm is: Your vagina and uterus contract rapidly.
|
19 |
+
|
20 |
+
You experience involuntary muscle contractions in other parts, like your abdomen and feet.
|
21 |
+
|
22 |
+
Your heart rate and breathing quicken.
|
23 |
+
|
24 |
+
Your blood pressure increases. You may feel a sudden relief of tension or even ejaculate.
|
25 |
+
|
26 |
+
What makes a female orgasm different from a male orgasm? It may be surprising, but they’re not all that different. Both involve increased blood flow to the genitals, faster breathing and heart rate, and muscle contractions. Where they typically differ is in duration and recovery — also known as afterglow. Female orgasm may also last longer, ranging from 13 to 51 seconds on average, while male orgasm often ranges from 10 to 30 seconds. People with a penis typically have a refractory phase. Orgasms aren’t possible during this period, lasting from minutes to days. People with a clitoris may also go through a similar phase. A 2009 study involving 174 university students found that 96% of female participants experienced hypersensitivity in the clitoris following orgasm. Remember, the range of the refractory phase varies from person to person. Your own experience is unique to you. Then there’s ejaculation. For a person with a penis, contractions force semen into the urethra and out of the penis. And speaking of ejaculation …
|
27 |
+
|
28 |
+
Is female ejaculation a thing? Yes! And it’s a fairly common thing. A 2013 research review of female ejaculation found that 10% to 54% of participants experienced ejaculation during orgasm. Ejaculation occurs when fluid is expelled from your urethral opening during orgasm or sexual arousal. The ejaculate is a thick, whitish fluid that resembles watered-down milk. It contains some of the same components as semen.
|
29 |
+
|
30 |
+
What’s the orgasm gap? The orgasm gap refers to the gap between the number of male and female orgasms in heterosexual sex, where those with female genitalia are getting the shorter end of the stick. A 2018 study on orgasms in heterosexual newlywed couples found that 87% of husbands and only 49% of wives reported consistently experiencing orgasms during sexual activity. Why the gap? Researchers don’t know for certain. Some argue it could be biological, while others blame cultural and societal perspectives and a lack of education when it comes to pleasure.
|
31 |
+
|
32 |
+
What can you try if you’ve never had an orgasm before? If you have a vulva and vagina, you know that real-life orgasms can be pretty different from what they show on TV. The first thing you should do is take the pressure off so you can enjoy yourself. Instead, take the time to get to know your body and concentrate on how it feels. You may find it helpful to: Get comfy somewhere you won’t be interrupted or distracted, like in bed or the bath.
|
33 |
+
|
34 |
+
Try reading an erotic story or using your imagination to get yourself in the mood.
|
35 |
+
|
36 |
+
Massage the fleshy area above your clitoris and the outer and inner lips of your vulva until you begin to get wet. You can also apply lube.
|
37 |
+
|
38 |
+
Start rubbing your clitoris over the hood and find a rhythm that feels good.
|
39 |
+
|
40 |
+
Rub faster and harder, increasing the speed and pressure to intensify the feeling until it releases. If you don’t orgasm, you can always try again. Trying new things is the best way to figure out what turns you on and how to orgasm.
|
data/txt/blog/Female orgasm_ Everything you need to know.txt
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Female orgasm: Everything you need to know
|
2 |
+
Zawn Villines, How We Reviewed This Article
|
3 |
+
None
|
4 |
+
A female orgasm can be a highly pleasurable experience during masturbation or sexual activity. While orgasms may not provide a direct reproductive benefit, the pleasure may help improve mood and relieve stress. In this article, we look at why female orgasms occur and what happens during an orgasm. We also debunk some common misconceptions.
|
5 |
+
|
6 |
+
Causes Share on Pinterest honey and milk/Getty Images Orgasms are a response to sexual stimulation. The female orgasm can result from many types of stimulation, including vaginal, clitoral, and nipple contact. While vaginal orgasms are less common than those from clitoral stimulation, some women have them — with or without other stimulation. Not everyone orgasms from the same type of stimulation.
|
7 |
+
|
8 |
+
What happens during an orgasm? During arousal, blood flow to the genitals increases, causing them to become more sensitive. As arousal increases, a person’s heart rate, blood pressure, and breathing rate may also increase. As orgasm approaches, the muscles may twitch or spasm. Many women experience rhythmic muscle spasms in the vagina during an orgasm. Orgasms may follow the following stages: excitement, during which arousal builds
|
9 |
+
|
10 |
+
plateau, during which arousal increases and levels off
|
11 |
+
|
12 |
+
orgasm, which causes intense feelings of pleasure
|
13 |
+
|
14 |
+
resolution, during which arousal diminishes Many females can have another orgasm after resolution, whereas males usually require a period of rest before having another orgasm. A note about sex and gender Sex and gender exist on spectrums. This article will use the terms “male,” “female,” or both to refer to sex assigned at birth. Click here to learn more.
|
15 |
+
|
16 |
+
What does it feel like? Orgamsms can feel different for all people, and they may report their experiences in different language. However, people typically experience intense feelings of pleasure in the genitals and throughout the body. The release of endorphins following an orgasm may cause people to feel happy and relaxed. The skin may also flush. Women may also experience vaginal contractions during and after an orgasm, and ejaculation is also possible.
|
17 |
+
|
18 |
+
Why do females orgasm? The purpose of the female orgasm is less clear than that of the male orgasm. Researchers have suggested numerous potential benefits, but few have been rigorously tested, and no theory has conclusive scientific support. A 2016 study argues that the female orgasm may have no obvious evolutionary benefit and that it may be a relic of a time when the hormones associated with orgasm were necessary for a woman to ovulate. Since there was no evolutionary need to eliminate the female orgasm, it persisted even when it was no longer necessary for fertility. Orgasm may serve important purposes, however. The pleasure it can cause can encourage females to have sex. This may also promote bonding with a sexual partner, which does have significant evolutionary benefits.
|
19 |
+
|
20 |
+
Health benefits While the internet is filled with articles promising that orgasms improve skin, hair, and overall health, there is little scientific evidence that orgasms offer any specific health benefits. Scientists have not identified any evolutionary benefits of female orgasms or found that orgasms improve health. But orgasms are pleasurable, and pleasure can be its own benefit. Pleasurable sex may improve a person’s mood, relieve stress, boost immunity, and foster better relationships.
|
21 |
+
|
22 |
+
Common misconceptions People hold many misconceptions about female orgasms. Some myths include: Women who cannot orgasm have psychological problems. While trauma, relationship issues, and poor mental health can make it more difficult to orgasm, many people with healthy sexual attitudes and good relationships still have difficulties. An orgasm is both a physical and psychological response, and numerous health problems can make it more difficult to enjoy sex in this way. For example, some women experience vulvodynia, which refers to unexplained pain in the vagina or around the vulva. Treating this and other medical conditions may improve sexual pleasure. Orgasms from penetrative sex are common or the healthiest form of sexual expression. Self-appointed experts, mostly men, have long told women that they must orgasm from heterosexual intercourse. However, many women can only orgasm from clitoral stimulation. Women need to be in love to orgasm. Orgasm is a complex psychological and biological experience — reaching and experiencing orgasm is not the same for every woman. Some women may need to feel love to orgasm, while others may not. Studies found people were more likely to orgasm frequently if they: received more oral sex
|
23 |
+
|
24 |
+
had longer-lasting sex
|
25 |
+
|
26 |
+
reported higher relationship satisfaction
|
27 |
+
|
28 |
+
asked for what they wanted in bed
|
29 |
+
|
30 |
+
engaged in sexual emails or calls
|
31 |
+
|
32 |
+
expressed love during sex
|
33 |
+
|
34 |
+
acted out sexual fantasies
|
35 |
+
|
36 |
+
tried new sexual positions A person’s relationship with their partner may or may not influence their ability to orgasm during sex. Sexual health resources Visit our dedicated hub for more research-backed information and in-depth resources on sexual health. A partner can tell if a woman has had an orgasm. There is no way to tell if a woman has had an orgasm without asking. Some people make noises during an orgasm, while others are silent. Some flush or sweat after an orgasm, but others do not. A person who wants to know if their partner has had an orgasm can ask without being confrontational. If the answer is no, avoid judgment, anger, or feelings of inadequacy — these can put pressure on the person to orgasm, which can lead to anxiety and make it more difficult. Instead, discuss whether they would prefer a different approach to sex.
|
37 |
+
|
38 |
+
What if you can’t orgasm? Being unable to orgasm is a common issue, and it can occur for a variety of reasons. Some people may not receive the right kind of stimulation during sex, while others may have experienced trauma linked to sex. Others may simply be uninterested. Risk factors A 2018 analysis identified several factors that increase the risk of sexual dysfunction, including: relationship problems
|
39 |
+
|
40 |
+
stress
|
41 |
+
|
42 |
+
mental health issues
|
43 |
+
|
44 |
+
poor physical health
|
45 |
+
|
46 |
+
genitourinary issues, such as pelvic pain
|
47 |
+
|
48 |
+
a history of abortion
|
49 |
+
|
50 |
+
a history of female genital mutilation
|
51 |
+
|
52 |
+
sexual abuse
|
53 |
+
|
54 |
+
being religious, perhaps due to sexual shame and stigma The same study identified several modifiable risk factors that improve sexual experience, including: exercise
|
55 |
+
|
56 |
+
daily affection from a partner
|
57 |
+
|
58 |
+
a positive body image
|
59 |
+
|
60 |
+
sex education
|
61 |
+
|
62 |
+
intimate communication with a partner Increasing the likelihood The aforementioned study that compared orgasm frequency among people of various sexual orientations in the United States found that the following behaviors during sex increase the likelihood of women having an orgasm: deep kissing
|
63 |
+
|
64 |
+
genital stimulation during vaginal intercourse
|
65 |
+
|
66 |
+
oral sex Seeking help If self-help strategies do not work, a doctor who specializes in sexual dysfunction may be able to identify a problem, if there is one. Many medical issues can make having an orgasm difficult, including: a lack of lubrication
|
67 |
+
|
68 |
+
hormonal imbalances
|
69 |
+
|
70 |
+
pelvic pain
|
71 |
+
|
72 |
+
muscle dysfunction
|
73 |
+
|
74 |
+
a history of trauma When trauma or relationship problems make having an orgasm difficult, or when a person feels ashamed of sex or their desires, individual or couples counseling can help.
|
data/txt/blog/Female orgasms_ Different types & how to climax.txt
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Female orgasms: Different types & how to climax
|
2 |
+
Medically Reviewed
|
3 |
+
None
|
4 |
+
What is a female orgasm?
|
5 |
+
|
6 |
+
First things first, you might be curious about what an orgasm actually is . And there’s a fairly simple top-line answer: It’s one of your body’s responses to reaching the height of sexual arousal (or being turned on).
|
7 |
+
|
8 |
+
“During orgasm, the uterus and muscles of the pelvic floor contract in a rhythmic fashion that is pleasurable for most women,” explains Dr. Brandye Wilson-Manigat , obstetrician and gynecologist (OB-GYN), California, US. This can feel like throbbing, twitching, tensing, or spasms in your vagina and anus. “Some women report a sensation of their whole body being involved in the contractions.”
|
9 |
+
|
10 |
+
Orgasms don’t just happen out of the blue. They can feel like a buildup of pleasure and sexual tension. And that’s because orgasm is just one part of your body’s sexual response cycle . Prepare for some sexy science now; there are different phases when you’re feeling frisky.
|
11 |
+
|
12 |
+
Desire: Having the urge to be intimate with a partner or alone. Your heart rate might quicken, and the blood flow to your vagina will increase. This pushes fluid to the surface of your vaginal walls, giving you the sensation of being wet.
|
13 |
+
|
14 |
+
Excitement or feeling turned on: Your heart rate, breathing, and blood pressure will continue to increase, and you might notice that your clitoris and labia (the inner and outer lips of your vulva) start to feel more sensitive.
|
15 |
+
|
16 |
+
Orgasm: This is the big O. The muscles in your vagina, uterus, and anus will contract (it might feel like a squeezing sensation), and you might feel a quick release of sexual tension.
|
17 |
+
|
18 |
+
Resolution: This is when your heart rate, blood pressure, and breathing return to normal, and you might notice a warm feeling of well-being or satisfaction.
|
19 |
+
|
20 |
+
Did you know that no two orgasms are the same? They can vary in length and intensity (but more on that below).
|
21 |
+
|
22 |
+
What happens during female orgasms, and what does it feel like?
|
23 |
+
|
24 |
+
Trying to explain what an orgasm feels like to other people can be really tough. We rarely have anything that we can compare our own orgasms to, and like falling in love, people often say you “just know” when you’ve had one. You might even notice that climaxing feels different to you each time. This is totally typical and healthy.
|
25 |
+
|
26 |
+
"Orgasms can feel different, even if you are stimulating the same spot in the same way,” says Dr. Wilson-Manigat. “Some are more like a ‘fireworks on the Fourth of July’ sensation. Your whole body feels like it’s at a celebration. Others may feel like a slow burn, giving you a warm, satisfying sensation.”
|
27 |
+
|
28 |
+
While it might feel like all the action of your orgasm is taking place in your genitals, there’s a lot going on in your brain, too. When you orgasm, your brain releases a surge in dopamine , the feel-good hormone. This helps you to recognize what you enjoy and gives you that sense of pleasure. Your brain also releases oxytocin . This is sometimes called the bonding hormone because it triggers a sense of love and attachment.
|
29 |
+
|
30 |
+
Sounds pretty amazing, right? This surge in happy hormones is just one reason why reaching the big O is good for you. Keep reading to find out why.
|
31 |
+
|
32 |
+
What are the different types of female orgasms?
|
33 |
+
|
34 |
+
You might have heard your friends talk about an amazing nipple orgasm or an intense anal orgasm and wondered whether these are different types of orgasms. Here’s your answer: This is actually a little bit of a myth. “When people say there are different types of female orgasms, they usually mean which erogenous zone was stimulated for orgasm,” explains Dr. Sara Twogood , obstetrician and gynecologist, California, US. “It’s not that the orgasm itself is different; it’s the way the orgasm is achieved is different.”
|
35 |
+
|
36 |
+
So let’s break that down. If you stimulate different parts of your body, you might reach orgasm. Areas that can help you to orgasm are:
|
37 |
+
|
38 |
+
Clitoris: According to a survey published in the Journal of Sex & Marital Therapy , around 36% of the 1,000 women they spoke to said they needed some form of clitoral stimulation in order to orgasm. You can see part of your clitoris just above the opening of your vagina. It pays to know where your clitoris is, so you can learn more about yours here.
|
39 |
+
|
40 |
+
Vagina: This is when you climax during vaginal penetration. A study found that only 18% of female orgasms come from vaginal stimulation.
|
41 |
+
|
42 |
+
Anus: You might experience an anal orgasm while having the outside of your anus touched.
|
43 |
+
|
44 |
+
Erogenous zones: You have erogenous zones all over your body. These are places where it feels really good to be touched. Some erogenous zones include your breasts, lips, neck, and thighs.
|
45 |
+
|
46 |
+
No matter where you’re being touched, if you reach orgasm, your body responds in the same way. But it’s so important to remember that there’s no “right” type of orgasm — we all experience sexual pleasure in different ways. It’s very healthy to explore what you like either on your own or with a partner you trust.
|
47 |
+
|
48 |
+
Where does the G-spot come in?
|
49 |
+
|
50 |
+
In your conversations about orgasms, you might have heard about the elusive G-spot, or the Grafenberg spot to give it its full name. Did you know that you might be able to feel your own G-spot? It’s thought to be inside your vagina on the upper wall . It swells when you’re feeling aroused and can feel bumpy, a little bit like a walnut.
|
51 |
+
|
52 |
+
Some people believe that you can reach orgasm by stroking and pressing on the G-spot. However, that’s still not certain where scientific evidence is concerned. In fact, some research has suggested that the G-spot doesn’t even exist and that it’s just part of the structure of the clitoris that’s inside your body. To learn more about your anatomy and the way your body works, you can download an app like Flo.
|
53 |
+
|
54 |
+
There’s no denying that the G-spot is a hotly debated topic. But when it comes to getting intimate with a partner or having fun alone, you don’t need to worry too much about pleasure politics. If you’ve found something that makes you feel good, then keep going.
|
data/txt/blog/Orgasm & Female Orgasm_ How many types of orgasm are there_.txt
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Orgasm & Female Orgasm: How many types of orgasm are there?
|
2 |
+
|
3 |
+
None
|
4 |
+
Top things to know about female orgasms:
|
5 |
+
|
6 |
+
There are multiple types of female orgasm
|
7 |
+
|
8 |
+
Stimulation of the clitoris is probably the easiest way for most people to experience an orgasm.
|
9 |
+
|
10 |
+
Not all orgasms are the same, and can experienced differently every time depending on how our mind and body feels at that time
|
11 |
+
|
12 |
+
Orgasms are difficult to study. Similar to studying mood or pain, female* orgasms need to be interpreted through not just biological mechanisms but also psychological, sociological and historical trends.
|
13 |
+
|
14 |
+
Historically, in Western countries, female orgasms have been highly scrutinized. Orgasms were sometimes seen as unhealthy or wrong. And orgasms that are achieved through stimulation that is not heterosexual vaginal intercourse have been considered unacceptable by researchers and doctors (1,2).
|
15 |
+
|
16 |
+
The viewpoint that some orgasms were superior to others has been supported by healthcare professionals. Sigmund Freud popularized the idea that mature women experience vaginal orgasm while immature women enjoyed clitoral stimulation (1-3).
|
17 |
+
|
18 |
+
The importance of vaginal orgasm became so rooted in 20th-century health that an inability to reach orgasm through heterosexual penetrative sex became part of a diagnosable condition in the DSM III (i.e. psychology and psychiatry’s diagnostic book) (4).
|
19 |
+
|
20 |
+
Although most healthcare professionals no longer consider inability for penetrative sex to induce orgasm to be a problem (unless their patients are distressed by it), many people feel that orgasm is a requirement for happy, meaningful and/or fulfilling sex (2). Some people also feel that orgasms should be reserved for sex, as opposed to experiencing orgasm during masturbation (1). Orgasm is great, but feeling pressure to have an orgasm, or a certain type of orgasm at a certain time, can make sex stressful and unpleasant.
|
21 |
+
|
22 |
+
What kind of research is there about orgasms?
|
23 |
+
|
24 |
+
The historical and social aspects of orgasm can obscure research as researchers may bias respondents’ answers by asking questions that imply that an orgasm type exists.
|
25 |
+
|
26 |
+
Relatedly, there is a disagreement among some sex researchers about how to classify orgasms (3,5). For example, if stimulation of a non-genital body part causes the genitals to become aroused and the person experiences an orgasm, did the stimulation of the non-genitals cause the orgasm, or was it the arousal of the genitals that caused the orgasm?
|
27 |
+
|
28 |
+
Even if a researcher were to do a study using tools that measure arousal, this doesn’t avoid all problems.
|
29 |
+
|
30 |
+
People with female genitals have been shown to experience arousal in their genitals but not report arousal to researchers, suggesting that bodily arousal is insufficient indicator of sexual interest or pleasure (5).
|
31 |
+
|
32 |
+
Compounding researcher problems are problems of gathering participants for sex and orgasm studies. Enrolling participants in a study is always tricky, but when someone studies a topic that is potentially considered taboo or private, it can be difficult to ensure that your sample is representative of all people in all cultures (this is also called external validity). It also may be difficult for participants to accurately remember or know where and how they were stimulated to cause orgasm (5).
|
33 |
+
|
34 |
+
So, why talk about orgasms at all?
|
35 |
+
|
36 |
+
Given the large amount of social and media commentary on orgasm, it’s important to understand how our bodies and the bodies of our partners actually work so that we can help reduce stigma and stress during sex. In the process, we may learn a thing or two on how to make sex more enjoyable.
|
37 |
+
|
38 |
+
What are the different types of female orgasms?
|
39 |
+
|
40 |
+
Different types vs different stimuli
|
41 |
+
|
42 |
+
There are many pop-science articles (i.e. articles not published in a research journal) that claim there are anywhere from four to 15 different types of orgasms. As mentioned before, there’s a lot of debate as to how to classify female orgasms. However, there’s little evidence to support the idea that different stimuli reliably (i.e. repeatedly, under experimental conditions) cause different types of female orgasms or different intensity of orgasms. Most people report that “some orgasms are better than others” (6), but this doesn’t necessarily seem to be related to the stimuli that cause that orgasm.
|
43 |
+
|
44 |
+
Clitoral stimulation
|
45 |
+
|
46 |
+
The clitoris contains a bundle of nerve endings and is located in the front of the female vulva and under the clitoral hood (i.e. the triangle part of female genitals that connects to the labia) (3). The clitoris, similar to a penis, will swell, enlarge and become more sensitive as a person becomes more sexually aroused (3,5).
|
47 |
+
|
48 |
+
Stimulation of the clitoris is probably the easiest way for most people to experience an orgasm.
|
49 |
+
|
50 |
+
In a 2017 study of over 1,000 women from the US, about 7 out of 10 people who had heterosexual sex said that they required clitoral stimulation to orgasm during that sex or that clitoral stimulation improved orgasms even if they didn’t require it to orgasm (6,7).
|
51 |
+
|
52 |
+
The type of clitoral stimulation preferred varied among the women in the study, though many women reported enjoying direct clitoral stimulation and stimulation that involved making circles or “up-and-down” movement (6).
|
53 |
+
|
54 |
+
That being said, there was a wide diversity in answers regarding how and in which ways a person liked having their clitoris stimulated, with even a few people saying they didn’t like direct contact at all (6).
|
55 |
+
|
56 |
+
Vaginal stimulation
|
57 |
+
|
58 |
+
A vaginally-stimulated orgasm is an orgasm that occurs through intentional stimulation of only the vagina. Although the clitoris or other body parts may be accidentally touched in the process, to have a “vaginal orgasm" there would be no intentional stimulation of other body parts.
|
59 |
+
|
60 |
+
In the same study described above, less than 1 in 5 women reported being able to orgasm through vaginal stimulation without clitoral stimulation (6).
|
61 |
+
|
62 |
+
The ability to orgasm from only vaginal sex may be related to the G-spot, though that is up for debate. The G-spot is not well understood (5,8,9). The G-spot may be its own structure, but it has also been argued that the G-spot is actually a retracted or enlarged clitoris or is a set of nerve endings attached to the clitoris (5,8,9). It’s also argued that the G-spot doesn’t exist at all (3,5). Regardless, there isn’t evidence to suggest that an orgasm from penetration-only is somehow superior to other forms of orgasm; in fact, intentional clitoral stimulation may make orgasm better than penetration-only orgasm (6).
|
63 |
+
|
64 |
+
Stimulation of other body parts
|
65 |
+
|
66 |
+
There is less research into orgasms caused by stimulation of body parts that aren't the genitals. Because many of these studies are small and aren’t all recent (10), the proportions of people reporting these types of orgasms may not be representative of the rate we would find in a large, representative survey. That being said, these studies do suggest that people don't necessarily need to directly stimulate their clitoris or vagina to experience an orgasm.
|
67 |
+
|
68 |
+
Some studies have found that people can experience orgasm through stimulation of the mouth, nipples, breasts, anus, and skin surrounding an injury (6,10).
|
69 |
+
|
70 |
+
Research with participants who have severe injuries to the spinal cord and with participants who have epileptic seizures suggest that there are orgasmic experiences that may be induced without direct incorporation of the genitals (10).
|
71 |
+
|
72 |
+
Orgasms outside of sex
|
73 |
+
|
74 |
+
Arousal of the genitals and even orgasm itself aren’t necessarily just experiences that happen during sex.
|
75 |
+
|
76 |
+
Exercise-induced orgasm
|
77 |
+
|
78 |
+
Exercise, especially weight training, cardio, and abdominal-focused exercise, can induce orgasms (sometimes called coregasms in pop-science) and other positive genital stimulation (11). This makes sense biologically, as both exercise and sex can stimulate the muscles around the genitals and can lead to increased blood flow to the area of the body. Exercise may also influence our mood via endorphins and other neurotransmitters (12), similar to sex and orgasm (13).
|
79 |
+
|
80 |
+
Orgasms during sleep
|
81 |
+
|
82 |
+
Many people experience sexual arousal or orgasm during sleep (10). It’s difficult to say what or how exactly this happens. Because reporting from dreams can be unreliable, it’s difficult to say if all arousal and orgasms during sleep are caused by sexual dreams (10,11). Similarly, no research has currently looked at whether people were unconsciously stimulating their bodies during sleep or were being stimulated by bedding or other objects, so we’re not currently able to say if orgasms during sleep happen entirely unaided from stimulation (10).
|
83 |
+
|
84 |
+
Better orgasms
|
85 |
+
|
86 |
+
The goal of many orgasm-themed articles is to help people enjoy their orgasm or gain new experiences. Although there’s little evidence to suggest that orgasm from any particular type of stimulation is better than another, there are some suggestions in the literature on factors that increase or change our orgasmic experience. In the published literature, people reported that orgasms and sexual arousal were enhanced by:
|
87 |
+
|
88 |
+
“spending time to build-up arousal” (6)
|
89 |
+
|
90 |
+
changing the intensity of touch, including stopping and restarting—this technique could help lead to a delayed and more pleasurable orgasm (6)
|
91 |
+
|
92 |
+
being with a partner who they had a connection with or that knew their bodies (6)
|
93 |
+
|
94 |
+
touching or stimulating nipples, breasts, or the anus (6,10,14),
|
95 |
+
|
96 |
+
engaging in new positions, types of sex, or new behaviors (6,15)
|
97 |
+
|
98 |
+
A happy sex life
|
99 |
+
|
100 |
+
Although portrayals of orgasm in media, partners’ expectations for our orgasms, and our own interest in experiencing orgasm can make us feel like we need to have an orgasm every time we have sex (2), a happy sex life doesn’t necessarily mean having a mind-blowing orgasm during every sexual experience. Many people report that not all orgasms are the same (6), which makes sense—our minds and bodies change from day to day (due to mood, health, stress levels, etc.), and so it’s unrealistic to expect any type of stimulation to elicit the same experience every time. Orgasm is just one of many important elements to sexual satisfaction.
|
101 |
+
|
102 |
+
*Note: This article uses the term female and male to refer to cis-gendered sexual anatomy. A person with entirely or partially female genitals may or may not be female as their gender, and a person with entirely or partially male genitals may or may not be male as their gender. There are also people with a mix of both male and female genitals, but unfortunately not a lot of research has been done with this population. I’m using the terms male and female to describe sexual organs because there is little agreement on other terms to use.
|
103 |
+
|
104 |
+
Article was originally published May 20, 2018.
|
environment.yml
ADDED
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: testenv1
|
2 |
+
channels:
|
3 |
+
- defaults
|
4 |
+
dependencies:
|
5 |
+
- _libgcc_mutex=0.1=main
|
6 |
+
- _openmp_mutex=5.1=1_gnu
|
7 |
+
- bzip2=1.0.8=h5eee18b_6
|
8 |
+
- ca-certificates=2024.7.2=h06a4308_0
|
9 |
+
- ld_impl_linux-64=2.38=h1181459_1
|
10 |
+
- libffi=3.4.4=h6a678d5_1
|
11 |
+
- libgcc-ng=11.2.0=h1234567_1
|
12 |
+
- libgomp=11.2.0=h1234567_1
|
13 |
+
- libstdcxx-ng=11.2.0=h1234567_1
|
14 |
+
- libuuid=1.41.5=h5eee18b_0
|
15 |
+
- ncurses=6.4=h6a678d5_0
|
16 |
+
- openssl=3.0.15=h5eee18b_0
|
17 |
+
- pip=24.2=py310h06a4308_0
|
18 |
+
- python=3.10.14=h955ad1f_1
|
19 |
+
- readline=8.2=h5eee18b_0
|
20 |
+
- setuptools=72.1.0=py310h06a4308_0
|
21 |
+
- sqlite=3.45.3=h5eee18b_0
|
22 |
+
- tk=8.6.14=h39e8969_0
|
23 |
+
- wheel=0.44.0=py310h06a4308_0
|
24 |
+
- xz=5.4.6=h5eee18b_1
|
25 |
+
- zlib=1.2.13=h5eee18b_1
|
26 |
+
- pip:
|
27 |
+
- accelerate==0.34.2
|
28 |
+
- addict==2.4.0
|
29 |
+
- aiofiles==23.2.1
|
30 |
+
- aiohappyeyeballs==2.4.0
|
31 |
+
- aiohttp==3.10.5
|
32 |
+
- aioitertools==0.12.0
|
33 |
+
- aiosignal==1.3.1
|
34 |
+
- aiosmtplib==2.0.2
|
35 |
+
- aiosqlite==0.20.0
|
36 |
+
- airportsdata==20241001
|
37 |
+
- alembic==1.13.3
|
38 |
+
- annotated-types==0.7.0
|
39 |
+
- anyio==4.4.0
|
40 |
+
- arize-phoenix==5.1.0
|
41 |
+
- arize-phoenix-evals==0.16.1
|
42 |
+
- arize-phoenix-otel==0.5.1
|
43 |
+
- asgiref==3.8.1
|
44 |
+
- asttokens==2.4.1
|
45 |
+
- async-timeout==4.0.3
|
46 |
+
- attrs==24.2.0
|
47 |
+
- authlib==1.3.2
|
48 |
+
- backoff==2.2.1
|
49 |
+
- bcrypt==4.2.0
|
50 |
+
- beautifulsoup4==4.12.3
|
51 |
+
- blinker==1.8.2
|
52 |
+
- bm25s==0.1.10
|
53 |
+
- build==1.2.2
|
54 |
+
- cachetools==5.5.0
|
55 |
+
- certifi==2024.8.30
|
56 |
+
- cffi==1.17.1
|
57 |
+
- charset-normalizer==3.3.2
|
58 |
+
- chevron==0.14.0
|
59 |
+
- chroma-hnswlib==0.7.3
|
60 |
+
- chromadb==0.5.3
|
61 |
+
- chromedriver-autoinstaller==0.6.4
|
62 |
+
- click==8.1.7
|
63 |
+
- cloudpickle==3.0.0
|
64 |
+
- coloredlogs==15.0.1
|
65 |
+
- contourpy==1.3.0
|
66 |
+
- cryptography==43.0.1
|
67 |
+
- cssselect==1.2.0
|
68 |
+
- cycler==0.12.1
|
69 |
+
- dataclasses-json==0.6.7
|
70 |
+
- datasets==2.21.0
|
71 |
+
- decorator==5.1.1
|
72 |
+
- deprecated==1.2.14
|
73 |
+
- dill==0.3.8
|
74 |
+
- dirtyjson==1.0.8
|
75 |
+
- diskcache==5.6.3
|
76 |
+
- distro==1.9.0
|
77 |
+
- dnspython==2.6.1
|
78 |
+
- docstring-parser==0.16
|
79 |
+
- einops==0.8.0
|
80 |
+
- email-validator==2.2.0
|
81 |
+
- environs==9.5.0
|
82 |
+
- exceptiongroup==1.2.2
|
83 |
+
- executing==2.1.0
|
84 |
+
- fastapi==0.115.0
|
85 |
+
- fastapi-mail==1.4.1
|
86 |
+
- feedfinder2==0.0.4
|
87 |
+
- feedparser==6.0.11
|
88 |
+
- ffmpy==0.4.0
|
89 |
+
- filelock==3.16.1
|
90 |
+
- fire==0.6.0
|
91 |
+
- flatbuffers==24.3.25
|
92 |
+
- fonttools==4.53.1
|
93 |
+
- frozenlist==1.4.1
|
94 |
+
- fsspec==2024.6.1
|
95 |
+
- google-api-core==2.19.2
|
96 |
+
- google-api-python-client==2.146.0
|
97 |
+
- google-auth==2.34.0
|
98 |
+
- google-auth-httplib2==0.2.0
|
99 |
+
- google-auth-oauthlib==1.2.1
|
100 |
+
- google-search-results==2.4.2
|
101 |
+
- googleapis-common-protos==1.65.0
|
102 |
+
- gradio==4.44.0
|
103 |
+
- gradio-client==1.3.0
|
104 |
+
- graphql-core==3.2.4
|
105 |
+
- greenlet==3.1.1
|
106 |
+
- grpc-interceptor==0.15.4
|
107 |
+
- grpcio==1.66.1
|
108 |
+
- h11==0.14.0
|
109 |
+
- hdbscan==0.8.38.post1
|
110 |
+
- html2text==2024.2.26
|
111 |
+
- httpcore==1.0.5
|
112 |
+
- httplib2==0.22.0
|
113 |
+
- httptools==0.6.1
|
114 |
+
- httpx==0.27.2
|
115 |
+
- huggingface-hub==0.25.0
|
116 |
+
- humanfriendly==10.0
|
117 |
+
- idna==3.10
|
118 |
+
- importlib-metadata==8.4.0
|
119 |
+
- importlib-resources==6.4.5
|
120 |
+
- interegular==0.3.3
|
121 |
+
- ipython==8.27.0
|
122 |
+
- jedi==0.19.1
|
123 |
+
- jieba==0.42.1
|
124 |
+
- jieba3k==0.35.1
|
125 |
+
- jinja2==3.1.4
|
126 |
+
- jiter==0.5.0
|
127 |
+
- joblib==1.4.2
|
128 |
+
- jsonpatch==1.33
|
129 |
+
- jsonpickle==3.3.0
|
130 |
+
- jsonpointer==3.0.0
|
131 |
+
- jsonschema==4.23.0
|
132 |
+
- jsonschema-specifications==2024.10.1
|
133 |
+
- kiwisolver==1.4.7
|
134 |
+
- kubernetes==30.1.0
|
135 |
+
- langchain==0.3.0
|
136 |
+
- langchain-chroma==0.1.4
|
137 |
+
- langchain-community==0.3.0
|
138 |
+
- langchain-core==0.3.1
|
139 |
+
- langchain-ollama==0.2.0
|
140 |
+
- langchain-text-splitters==0.3.0
|
141 |
+
- langsmith==0.1.121
|
142 |
+
- lark==1.2.2
|
143 |
+
- literalai==0.0.627
|
144 |
+
- llama-cloud==0.1.0
|
145 |
+
- llama-index==0.11.14
|
146 |
+
- llama-index-agent-openai==0.3.4
|
147 |
+
- llama-index-callbacks-literalai==1.1.0
|
148 |
+
- llama-index-cli==0.3.1
|
149 |
+
- llama-index-core==0.11.14
|
150 |
+
- llama-index-embeddings-langchain==0.2.1
|
151 |
+
- llama-index-embeddings-openai==0.2.5
|
152 |
+
- llama-index-indices-managed-llama-cloud==0.4.0
|
153 |
+
- llama-index-legacy==0.9.48.post3
|
154 |
+
- llama-index-llms-ollama==0.3.2
|
155 |
+
- llama-index-llms-openai==0.2.9
|
156 |
+
- llama-index-multi-modal-llms-openai==0.2.1
|
157 |
+
- llama-index-program-openai==0.2.0
|
158 |
+
- llama-index-question-gen-openai==0.2.0
|
159 |
+
- llama-index-readers-file==0.2.2
|
160 |
+
- llama-index-readers-llama-parse==0.3.0
|
161 |
+
- llama-index-readers-web==0.2.4
|
162 |
+
- llama-index-retrievers-bm25==0.3.0
|
163 |
+
- llama-index-storage-chat-store-redis==0.2.0
|
164 |
+
- llama-index-tools-google==0.2.0
|
165 |
+
- llama-index-utils-openai==0.1.0
|
166 |
+
- llama-index-utils-workflow==0.2.1
|
167 |
+
- llama-index-vector-stores-chroma==0.2.0
|
168 |
+
- llama-index-vector-stores-milvus==0.2.7
|
169 |
+
- llama-parse==0.5.6
|
170 |
+
- llamafactory==0.9.0
|
171 |
+
- llvmlite==0.43.0
|
172 |
+
- lmdeploy==0.6.1
|
173 |
+
- lxml==5.3.0
|
174 |
+
- lxml-html-clean==0.3.1
|
175 |
+
- mako==1.3.5
|
176 |
+
- markdown-it-py==3.0.0
|
177 |
+
- markupsafe==2.1.5
|
178 |
+
- marshmallow==3.22.0
|
179 |
+
- matplotlib==3.9.2
|
180 |
+
- matplotlib-inline==0.1.7
|
181 |
+
- mdurl==0.1.2
|
182 |
+
- milvus-lite==2.4.10
|
183 |
+
- mmengine-lite==0.10.5
|
184 |
+
- mmh3==4.1.0
|
185 |
+
- monotonic==1.6
|
186 |
+
- mpmath==1.3.0
|
187 |
+
- multidict==6.1.0
|
188 |
+
- multiprocess==0.70.16
|
189 |
+
- mypy-extensions==1.0.0
|
190 |
+
- nest-asyncio==1.6.0
|
191 |
+
- networkx==3.3
|
192 |
+
- newspaper3k==0.2.8
|
193 |
+
- nltk==3.9.1
|
194 |
+
- numba==0.60.0
|
195 |
+
- numpy==1.26.4
|
196 |
+
- nvidia-cublas-cu12==12.1.3.1
|
197 |
+
- nvidia-cuda-cupti-cu12==12.1.105
|
198 |
+
- nvidia-cuda-nvrtc-cu12==12.1.105
|
199 |
+
- nvidia-cuda-runtime-cu12==12.1.105
|
200 |
+
- nvidia-cudnn-cu12==8.9.2.26
|
201 |
+
- nvidia-cufft-cu12==11.0.2.54
|
202 |
+
- nvidia-curand-cu12==10.3.2.106
|
203 |
+
- nvidia-cusolver-cu12==11.4.5.107
|
204 |
+
- nvidia-cusparse-cu12==12.1.0.106
|
205 |
+
- nvidia-nccl-cu12==2.20.5
|
206 |
+
- nvidia-nvjitlink-cu12==12.6.68
|
207 |
+
- nvidia-nvtx-cu12==12.1.105
|
208 |
+
- oauthlib==3.2.2
|
209 |
+
- ollama==0.3.3
|
210 |
+
- onnxruntime==1.19.2
|
211 |
+
- openai==1.46.0
|
212 |
+
- openinference-instrumentation==0.1.18
|
213 |
+
- openinference-instrumentation-llama-index==3.0.2
|
214 |
+
- openinference-semantic-conventions==0.1.10
|
215 |
+
- opentelemetry-api==1.27.0
|
216 |
+
- opentelemetry-exporter-otlp==1.27.0
|
217 |
+
- opentelemetry-exporter-otlp-proto-common==1.27.0
|
218 |
+
- opentelemetry-exporter-otlp-proto-grpc==1.27.0
|
219 |
+
- opentelemetry-exporter-otlp-proto-http==1.27.0
|
220 |
+
- opentelemetry-instrumentation==0.48b0
|
221 |
+
- opentelemetry-instrumentation-asgi==0.48b0
|
222 |
+
- opentelemetry-instrumentation-fastapi==0.48b0
|
223 |
+
- opentelemetry-proto==1.27.0
|
224 |
+
- opentelemetry-sdk==1.27.0
|
225 |
+
- opentelemetry-semantic-conventions==0.48b0
|
226 |
+
- opentelemetry-util-http==0.48b0
|
227 |
+
- orjson==3.10.7
|
228 |
+
- outcome==1.3.0.post0
|
229 |
+
- outlines==0.1.0
|
230 |
+
- outlines-core==0.1.0
|
231 |
+
- overrides==7.7.0
|
232 |
+
- packaging==24.1
|
233 |
+
- pandas==2.2.2
|
234 |
+
- parso==0.8.4
|
235 |
+
- peft==0.11.1
|
236 |
+
- pexpect==4.9.0
|
237 |
+
- phoenix==0.9.1
|
238 |
+
- pillow==10.4.0
|
239 |
+
- platformdirs==4.3.6
|
240 |
+
- playwright==1.48.0
|
241 |
+
- posthog==3.6.6
|
242 |
+
- prompt-toolkit==3.0.47
|
243 |
+
- proto-plus==1.24.0
|
244 |
+
- protobuf==4.25.4
|
245 |
+
- psutil==6.0.0
|
246 |
+
- ptyprocess==0.7.0
|
247 |
+
- pure-eval==0.2.3
|
248 |
+
- pyarrow==17.0.0
|
249 |
+
- pyasn1==0.6.1
|
250 |
+
- pyasn1-modules==0.4.1
|
251 |
+
- pycountry==24.6.1
|
252 |
+
- pycparser==2.22
|
253 |
+
- pydantic==2.9.2
|
254 |
+
- pydantic-core==2.23.4
|
255 |
+
- pydantic-settings==2.5.2
|
256 |
+
- pydub==0.25.1
|
257 |
+
- pyee==12.0.0
|
258 |
+
- pygments==2.18.0
|
259 |
+
- pymilvus==2.4.8
|
260 |
+
- pymysql==1.1.1
|
261 |
+
- pynndescent==0.5.13
|
262 |
+
- pynvml==11.5.3
|
263 |
+
- pyparsing==3.1.4
|
264 |
+
- pypdf==4.3.1
|
265 |
+
- pypika==0.48.9
|
266 |
+
- pyproject-hooks==1.1.0
|
267 |
+
- pysocks==1.7.1
|
268 |
+
- pystemmer==2.2.0.1
|
269 |
+
- python-dateutil==2.9.0.post0
|
270 |
+
- python-dotenv==1.0.1
|
271 |
+
- python-multipart==0.0.9
|
272 |
+
- pytz==2024.2
|
273 |
+
- pyvis==0.3.2
|
274 |
+
- pyyaml==6.0.2
|
275 |
+
- redis==5.0.8
|
276 |
+
- referencing==0.35.1
|
277 |
+
- regex==2024.9.11
|
278 |
+
- requests==2.32.3
|
279 |
+
- requests-file==2.1.0
|
280 |
+
- requests-oauthlib==2.0.0
|
281 |
+
- rich==13.8.1
|
282 |
+
- rouge-chinese==1.0.3
|
283 |
+
- rpds-py==0.20.0
|
284 |
+
- rsa==4.9
|
285 |
+
- ruff==0.6.5
|
286 |
+
- safetensors==0.4.5
|
287 |
+
- scikit-learn==1.5.2
|
288 |
+
- scipy==1.14.1
|
289 |
+
- selenium==4.25.0
|
290 |
+
- semantic-version==2.10.0
|
291 |
+
- sentencepiece==0.2.0
|
292 |
+
- serpapi==0.1.5
|
293 |
+
- sgmllib3k==1.0.0
|
294 |
+
- shellingham==1.5.4
|
295 |
+
- shortuuid==1.0.13
|
296 |
+
- shtab==1.7.1
|
297 |
+
- six==1.16.0
|
298 |
+
- sniffio==1.3.1
|
299 |
+
- sortedcontainers==2.4.0
|
300 |
+
- soupsieve==2.6
|
301 |
+
- spider-client==0.0.27
|
302 |
+
- sqlalchemy==2.0.35
|
303 |
+
- sqlean-py==3.45.1
|
304 |
+
- sse-starlette==2.1.3
|
305 |
+
- stack-data==0.6.3
|
306 |
+
- starlette==0.38.5
|
307 |
+
- stemmer==0.0.4
|
308 |
+
- strawberry-graphql==0.236.0
|
309 |
+
- striprtf==0.0.26
|
310 |
+
- sympy==1.13.2
|
311 |
+
- tenacity==8.5.0
|
312 |
+
- termcolor==2.4.0
|
313 |
+
- threadpoolctl==3.5.0
|
314 |
+
- tiktoken==0.7.0
|
315 |
+
- tinysegmenter==0.3
|
316 |
+
- tldextract==5.1.2
|
317 |
+
- tokenizers==0.20.0
|
318 |
+
- tomli==2.0.1
|
319 |
+
- tomlkit==0.12.0
|
320 |
+
- torch==2.3.1
|
321 |
+
- torchvision==0.18.1
|
322 |
+
- tqdm==4.66.5
|
323 |
+
- traitlets==5.14.3
|
324 |
+
- transformers==4.45.2
|
325 |
+
- trio==0.27.0
|
326 |
+
- trio-websocket==0.11.1
|
327 |
+
- triton==2.3.1
|
328 |
+
- trl==0.9.6
|
329 |
+
- typer==0.12.5
|
330 |
+
- typing-extensions==4.12.2
|
331 |
+
- typing-inspect==0.9.0
|
332 |
+
- tyro==0.8.10
|
333 |
+
- tzdata==2024.1
|
334 |
+
- ujson==5.10.0
|
335 |
+
- umap-learn==0.5.6
|
336 |
+
- uritemplate==4.1.1
|
337 |
+
- urllib3==2.2.3
|
338 |
+
- uvicorn==0.30.6
|
339 |
+
- uvloop==0.20.0
|
340 |
+
- watchfiles==0.24.0
|
341 |
+
- wcwidth==0.2.13
|
342 |
+
- websocket-client==1.8.0
|
343 |
+
- websockets==12.0
|
344 |
+
- wrapt==1.16.0
|
345 |
+
- wsproto==1.2.0
|
346 |
+
- xxhash==3.5.0
|
347 |
+
- yapf==0.40.2
|
348 |
+
- yarl==1.11.1
|
349 |
+
- zipp==3.20.2
|
350 |
+
|
fetishTest/Q&A.json
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"A": "Romantic",
|
4 |
+
"B": "Luxurious",
|
5 |
+
"C": "Thrilling",
|
6 |
+
"D": "Relaxing"
|
7 |
+
},
|
8 |
+
{
|
9 |
+
"A": "Possessive",
|
10 |
+
"B": "Emotional",
|
11 |
+
"C": "Mysterious",
|
12 |
+
"D": "Chill"
|
13 |
+
},
|
14 |
+
{
|
15 |
+
"A": "BDSM",
|
16 |
+
"B": "Thrilling",
|
17 |
+
"C": "Roleplay",
|
18 |
+
"D": "Masochism"
|
19 |
+
},
|
20 |
+
{
|
21 |
+
"A": "Handcuffed",
|
22 |
+
"B": "Wearing lingerie",
|
23 |
+
"C": "Wearing roleplay props",
|
24 |
+
"D": "Freshness"
|
25 |
+
},
|
26 |
+
{
|
27 |
+
"A": "Group Sex",
|
28 |
+
"B": "BDSM",
|
29 |
+
"C": "Taboo",
|
30 |
+
"D": "Roleplay"
|
31 |
+
},
|
32 |
+
{
|
33 |
+
"A": "Passionate",
|
34 |
+
"B": "Trusting",
|
35 |
+
"C": "Controlling",
|
36 |
+
"D": "Chill"
|
37 |
+
},
|
38 |
+
{
|
39 |
+
"A": "Emotional",
|
40 |
+
"B": "Visual Stimulation",
|
41 |
+
"C": "Gentle",
|
42 |
+
"D": "Hardcore BDSM"
|
43 |
+
},
|
44 |
+
{
|
45 |
+
"A": "Trust",
|
46 |
+
"B": "Passion",
|
47 |
+
"C": "Control",
|
48 |
+
"D": "Relaxation"
|
49 |
+
},
|
50 |
+
{
|
51 |
+
"A": "Dominance",
|
52 |
+
"B": "Submission",
|
53 |
+
"C": "Equal",
|
54 |
+
"D": "Introverted"
|
55 |
+
},
|
56 |
+
{
|
57 |
+
"A": "BDSM",
|
58 |
+
"B": "Occasional BDSM",
|
59 |
+
"C": "Non-BDSM",
|
60 |
+
"D": "Anti-BDSM"
|
61 |
+
}
|
62 |
+
]
|
fetishTest/api.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, Request
|
2 |
+
from requests import Response
|
3 |
+
from langchain_community.embeddings.ollama import OllamaEmbeddings
|
4 |
+
import numpy as np
|
5 |
+
import json
|
6 |
+
|
7 |
+
app = FastAPI(
|
8 |
+
title="FetishTest",
|
9 |
+
description="Game of matching fetish of users",
|
10 |
+
)
|
11 |
+
|
12 |
+
# set up
|
13 |
+
embed_model = OllamaEmbeddings(model="bge-m3")
|
14 |
+
with open("standard_character.json", "r") as f:
|
15 |
+
standard_character = json.load(f)
|
16 |
+
with open("Q&A.json", "r") as f:
|
17 |
+
answer2label = json.load(f)
|
18 |
+
|
19 |
+
# cosine similarity
|
20 |
+
def cosine_similarity(vec1, vec2):
|
21 |
+
vec1, vec2 = np.array(vec1), np.array(vec2)
|
22 |
+
return vec1.dot(vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
|
23 |
+
|
24 |
+
@app.post("/fetish")
|
25 |
+
async def matching(request: Request):
|
26 |
+
request = await request.json()
|
27 |
+
answer = request["answer"] # ['A', 'B' ...]
|
28 |
+
print(f"user_input: {answer}")
|
29 |
+
user_labels = []
|
30 |
+
for idx, ans in enumerate(answer):
|
31 |
+
curr_label = answer2label[idx][ans]
|
32 |
+
if curr_label not in user_labels:
|
33 |
+
user_labels.append(answer2label[idx][ans])
|
34 |
+
user_labels = sorted(user_labels)
|
35 |
+
print(f"user_labels: {user_labels}")
|
36 |
+
user_embedding = embed_model.embed_query(" ".join(user_labels))
|
37 |
+
matching_dict = {}
|
38 |
+
for character in standard_character:
|
39 |
+
sim = cosine_similarity(user_embedding, character["embedding"])
|
40 |
+
matching_dict[character["key"]] = sim
|
41 |
+
# sort by sim
|
42 |
+
matching_tuple = sorted(matching_dict.items(), key=lambda x: x[1], reverse=True)
|
43 |
+
# return the top 1
|
44 |
+
matched = matching_tuple[0][0]
|
45 |
+
sim = matching_tuple[0][1]
|
46 |
+
matched_name = standard_character[matched]["name"]
|
47 |
+
matched_label = standard_character[matched]["label"]
|
48 |
+
result = {
|
49 |
+
"result": matched
|
50 |
+
}
|
51 |
+
print(f"matched: {matched}")
|
52 |
+
print(f"{matched_name}: {matched_label} -- score: {sim}")
|
53 |
+
return result
|
54 |
+
|
55 |
+
if __name__ == "__main__":
|
56 |
+
import uvicorn
|
57 |
+
uvicorn.run(
|
58 |
+
"api:app",
|
59 |
+
host="0.0.0.0",
|
60 |
+
port=8002,
|
61 |
+
loop="asyncio",
|
62 |
+
workers=8,
|
63 |
+
limit_concurrency=10,
|
64 |
+
timeout_keep_alive=60,
|
65 |
+
access_log=True
|
66 |
+
)
|
fetishTest/character.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class BaseCharacter:
|
2 |
+
def __init__(self, key, name, type, media, label: list):
|
3 |
+
self.key = key
|
4 |
+
self.name = name
|
5 |
+
self.type = type
|
6 |
+
self.media = media
|
7 |
+
self.label = label
|
8 |
+
self.embedding = None
|
9 |
+
|
10 |
+
def parse(self):
|
11 |
+
labels = ",".join(self.label)
|
12 |
+
res = f"{self.name}: {labels}"
|
13 |
+
return res
|
14 |
+
|
15 |
+
def get_label(self):
|
16 |
+
return " ".join(self.label)
|
17 |
+
|
18 |
+
def to_dict(self):
|
19 |
+
return {
|
20 |
+
"key": self.key,
|
21 |
+
"name": self.name,
|
22 |
+
"type": self.type,
|
23 |
+
"media": self.media,
|
24 |
+
"label": self.label,
|
25 |
+
"embedding": self.embedding
|
26 |
+
}
|
fetishTest/fetish_test.py
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain_community.embeddings.ollama import OllamaEmbeddings
|
2 |
+
from fetishTest.character import BaseCharacter
|
3 |
+
import json
|
4 |
+
|
5 |
+
|
6 |
+
|
7 |
+
label_list = []
|
8 |
+
|
9 |
+
standard_character = [
|
10 |
+
BaseCharacter(
|
11 |
+
key=1,
|
12 |
+
name="Oberyn Martell",
|
13 |
+
type="TV series",
|
14 |
+
media="Game of Thrones",
|
15 |
+
label=["Sensual","Non-traditional", "Charismatic", "Confident", "Adventurous"]
|
16 |
+
),
|
17 |
+
BaseCharacter(
|
18 |
+
key=2,
|
19 |
+
name="Christian Grey",
|
20 |
+
type="movie",
|
21 |
+
media="50 Shades of Grey",
|
22 |
+
label=["BDSM", "Private", "Mysterious", "Dominant", "Caring"]
|
23 |
+
),
|
24 |
+
BaseCharacter(
|
25 |
+
key=3,
|
26 |
+
name="Maddy Perez",
|
27 |
+
type="TV series",
|
28 |
+
media="Euphoria",
|
29 |
+
label=["Protective", "Adventurous", "Sensual", "Independent", "Passionate", "Confident"]
|
30 |
+
),
|
31 |
+
BaseCharacter(
|
32 |
+
key=4,
|
33 |
+
name="Geralt of Rivia",
|
34 |
+
type="movie",
|
35 |
+
media="The Witcher",
|
36 |
+
label=["Selective", "Non-committal", "Discreet", "Sensual", "Courageous"]
|
37 |
+
),
|
38 |
+
BaseCharacter(
|
39 |
+
key=5,
|
40 |
+
name="Emily Cooper",
|
41 |
+
type="movie",
|
42 |
+
media="Emily in Paris",
|
43 |
+
label=["Romantic", "Ambitious", "Adventurous", "Courageous", "Flirtatious"]
|
44 |
+
),
|
45 |
+
BaseCharacter(
|
46 |
+
key=6,
|
47 |
+
name="Gatsby ",
|
48 |
+
type="movie",
|
49 |
+
media="The Great Gatsby",
|
50 |
+
label=["Luxurious", "Persistent", "Romantic", "Obsessive"]
|
51 |
+
),
|
52 |
+
BaseCharacter(
|
53 |
+
key=7,
|
54 |
+
name="Daenerys Targaryen",
|
55 |
+
type="TV series",
|
56 |
+
media="Game of Thrones",
|
57 |
+
label=["Passionate", "Empowered", "Compassionate", "Fierce", "Loyal", "Romantic"]
|
58 |
+
),
|
59 |
+
BaseCharacter(
|
60 |
+
key=8,
|
61 |
+
name="Daemon Targaryen",
|
62 |
+
type="TV series",
|
63 |
+
media="House of the Dragon",
|
64 |
+
label=["Dominant", "Seductive", "Experimental", "Power-driven", "Unpredictable"]
|
65 |
+
),
|
66 |
+
BaseCharacter(
|
67 |
+
key=9,
|
68 |
+
name="Jessica Rabbit",
|
69 |
+
type="movie",
|
70 |
+
media="Who Framed Roger Rabbit",
|
71 |
+
label=["Seductive", "Vulnerable", "Confident", "Playful", "Passionate"]
|
72 |
+
),
|
73 |
+
BaseCharacter(
|
74 |
+
key=10,
|
75 |
+
name="Tony Stark",
|
76 |
+
type="movie",
|
77 |
+
media="Iron Man",
|
78 |
+
label=["Loyal", "Confident", "Dominant", "Affectionate", "Adventurous"]
|
79 |
+
),
|
80 |
+
BaseCharacter(
|
81 |
+
key=15,
|
82 |
+
name="Lucifer Morningstar",
|
83 |
+
type="movie",
|
84 |
+
media="Lucifer",
|
85 |
+
label=["Confident", "Playful", "Dominant", "Adventurous", "Passionate"]
|
86 |
+
),
|
87 |
+
BaseCharacter(
|
88 |
+
key=11,
|
89 |
+
name="Love Quinn",
|
90 |
+
type="movie",
|
91 |
+
media="You",
|
92 |
+
label=["Romantic", "Impulsive", "Adventurous", "Intense", "Possessive"]
|
93 |
+
),
|
94 |
+
BaseCharacter(
|
95 |
+
key=12,
|
96 |
+
name="Joe Goldberg",
|
97 |
+
type="movie",
|
98 |
+
media="You",
|
99 |
+
label=["Obsessive", "Controlling", "Intense", "Dedicated", "Possessive"]
|
100 |
+
),
|
101 |
+
BaseCharacter(
|
102 |
+
key=13,
|
103 |
+
name="Marilyn Monroe",
|
104 |
+
type="movie",
|
105 |
+
media="Blonde",
|
106 |
+
label=["Vulnerable", "Emotional", "Romantic", "Passionate", "Sensual"]
|
107 |
+
),
|
108 |
+
BaseCharacter(
|
109 |
+
key=14,
|
110 |
+
name="Don Massimo",
|
111 |
+
type="movie",
|
112 |
+
media="365 Days",
|
113 |
+
label=["BDSM", "Dominant", "Controlling", "Assertive", "Protective", "Passionate"]
|
114 |
+
),
|
115 |
+
BaseCharacter(
|
116 |
+
key=16,
|
117 |
+
name="Harley Quinn",
|
118 |
+
type="movie",
|
119 |
+
media="The Suicide Squad",
|
120 |
+
label=["Spontaneous", "Playful", "Adventurous", "Dominant", "Passionate"]
|
121 |
+
),
|
122 |
+
BaseCharacter(
|
123 |
+
key=17,
|
124 |
+
name="Catwoman",
|
125 |
+
type="movie",
|
126 |
+
media="The Batman",
|
127 |
+
label=["Seductive", "Confident", "Independent", "Adventurous", "Playful"]
|
128 |
+
),
|
129 |
+
BaseCharacter(
|
130 |
+
key=18,
|
131 |
+
name="Mike Lane",
|
132 |
+
type="movie",
|
133 |
+
media="Magic Mike",
|
134 |
+
label=["Confident", "Charming", "Hardworking", "Dominant", "Sensual"]
|
135 |
+
),
|
136 |
+
BaseCharacter(
|
137 |
+
key=20,
|
138 |
+
name="Lara Croft",
|
139 |
+
type="movie",
|
140 |
+
media="Tomb Raider",
|
141 |
+
label=["Adventurous", "Confident", "Independent", "Dominant", "Explorative"]
|
142 |
+
),
|
143 |
+
BaseCharacter(
|
144 |
+
key=19,
|
145 |
+
name="Natasha Romanoff",
|
146 |
+
type="movie",
|
147 |
+
media="Black Widow",
|
148 |
+
label=["Confident", "Mysterious", "Passionate", "Dominant", "Sensual"]
|
149 |
+
),
|
150 |
+
]
|
151 |
+
for character in standard_character:
|
152 |
+
labels = character.label
|
153 |
+
for label in labels:
|
154 |
+
if label not in label_list:
|
155 |
+
label_list.append(label)
|
156 |
+
print(len(label_list))
|
157 |
+
|
158 |
+
# 重排序人物label顺序
|
159 |
+
for c in standard_character:
|
160 |
+
c.label = sorted(c.label)
|
161 |
+
|
162 |
+
# 生成人物性格embedding
|
163 |
+
embed_model = OllamaEmbeddings(model="bge-m3")
|
164 |
+
for character in standard_character:
|
165 |
+
character.embedding = embed_model.embed_query(character.get_label())
|
166 |
+
standard_character_dicts = [character.to_dict() for character in standard_character]
|
167 |
+
# 保存人物表
|
168 |
+
with open("standard_character.json", "w") as f:
|
169 |
+
json.dump(standard_character_dicts, f, indent=4)
|
170 |
+
|
fetishTest/standard_character.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
fetishTest/test.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import json, httpx
|
3 |
+
|
4 |
+
# API的URL
|
5 |
+
url = "http://localhost:8002/fetish"
|
6 |
+
|
7 |
+
# 准备要发送的数据 生成A-D之间的十个随机答案
|
8 |
+
import random
|
9 |
+
|
10 |
+
answers = []
|
11 |
+
for _ in range(10):
|
12 |
+
answers.append(random.choice(["A", "B", "C", "D"]))
|
13 |
+
data = {
|
14 |
+
"answer": answers # 替换为实际的答案列表
|
15 |
+
}
|
16 |
+
|
17 |
+
# 将数据转换为JSON字符串
|
18 |
+
data_json = json.dumps(data)
|
19 |
+
|
20 |
+
# 构建curl命令
|
21 |
+
curl_command = [
|
22 |
+
"curl", "-X", "POST", "-H", "Content-Type: application/json", "-d", data_json, url
|
23 |
+
]
|
24 |
+
|
25 |
+
# 执行curl命令
|
26 |
+
process = subprocess.run(curl_command, capture_output=True, text=True)
|
27 |
+
|
28 |
+
# 打印返回的结果
|
29 |
+
print(process.stdout)
|
30 |
+
print(data_json)
|
milvusDB/prepare_milvus.py
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pymilvus import MilvusClient, DataType, FieldSchema, CollectionSchema, Collection
|
2 |
+
|
3 |
+
URI = "http://localhost:19530"
|
4 |
+
def prepare_sex_ed_article_milvus():
|
5 |
+
client = MilvusClient(uri=URI)
|
6 |
+
client.drop_collection("t_sur_sex_ed_article_spider")
|
7 |
+
|
8 |
+
# Fields
|
9 |
+
id = FieldSchema(name="id", dtype=DataType.VARCHAR, is_primary=True, max_length=1000)
|
10 |
+
s_title = FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=2000)
|
11 |
+
v_title = FieldSchema(name="title_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
12 |
+
s_chunk = FieldSchema(name="chunk", dtype=DataType.VARCHAR, max_length=2000)
|
13 |
+
v_chunk = FieldSchema(name="chunk_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
14 |
+
tags = FieldSchema(name="tags", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
15 |
+
link = FieldSchema(name="link", dtype=DataType.VARCHAR, max_length=512)
|
16 |
+
category = FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=128)
|
17 |
+
|
18 |
+
# Collection schema
|
19 |
+
collection_schema = CollectionSchema(
|
20 |
+
fields=[id, s_title, v_title, s_chunk, v_chunk, tags, link, category],
|
21 |
+
auto_id=False,
|
22 |
+
enable_dynamic_field=True,
|
23 |
+
description="Schema of collection: t_sur_sex_ed_article_spider"
|
24 |
+
)
|
25 |
+
|
26 |
+
# indexs
|
27 |
+
index_params = client.prepare_index_params()
|
28 |
+
index_params.add_index(
|
29 |
+
field_name="title_vector",
|
30 |
+
index_type="IVF_FLAT",
|
31 |
+
metric_type="COSINE",
|
32 |
+
params={"nlist": 128}
|
33 |
+
)
|
34 |
+
index_params.add_index(
|
35 |
+
field_name="chunk_vector",
|
36 |
+
index_type="IVF_FLAT",
|
37 |
+
metric_type="COSINE",
|
38 |
+
params={"nlist": 128}
|
39 |
+
)
|
40 |
+
index_params.add_index(
|
41 |
+
field_name="tags",
|
42 |
+
index_type="IVF_FLAT",
|
43 |
+
metric_type="COSINE",
|
44 |
+
params={"nlist": 128}
|
45 |
+
)
|
46 |
+
|
47 |
+
# create collection
|
48 |
+
client.create_collection(
|
49 |
+
collection_name="t_sur_sex_ed_article_spider",
|
50 |
+
schema=collection_schema,
|
51 |
+
index_params=index_params
|
52 |
+
)
|
53 |
+
|
54 |
+
status = client.get_load_state("t_sur_sex_ed_article_spider")
|
55 |
+
print(f"t_sur_sex_ed_article_spider:{status}")
|
56 |
+
|
57 |
+
|
58 |
+
def prepare_sex_ed_qa_milvus():
|
59 |
+
client = MilvusClient(uri=URI)
|
60 |
+
client.drop_collection("t_sur_sex_ed_question_answer_spider")
|
61 |
+
|
62 |
+
# Fields
|
63 |
+
id = FieldSchema(name="id", dtype=DataType.VARCHAR, is_primary=True, max_length=1000)
|
64 |
+
url = FieldSchema(name="url", dtype=DataType.VARCHAR, max_length=1000)
|
65 |
+
title = FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=2000)
|
66 |
+
v_title = FieldSchema(name="title_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
67 |
+
content = FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=2000)
|
68 |
+
v_content = FieldSchema(name="content_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
69 |
+
content_type = FieldSchema(name="content_type", dtype=DataType.VARCHAR, max_length=8)
|
70 |
+
author = FieldSchema(name="author", dtype=DataType.VARCHAR, max_length=64)
|
71 |
+
avatar_url = FieldSchema(name="avatar_url", dtype=DataType.VARCHAR, max_length=1024)
|
72 |
+
likes = FieldSchema(name="likes", dtype=DataType.INT32)
|
73 |
+
dislikes = FieldSchema(name="dislikes", dtype=DataType.INT32)
|
74 |
+
|
75 |
+
# Collection schema
|
76 |
+
collection_schema = CollectionSchema(
|
77 |
+
fields=[id, url, title, v_title, content, v_content, content_type, author, avatar_url, likes, dislikes],
|
78 |
+
auto_id=False,
|
79 |
+
enable_dynamic_fields=True,
|
80 |
+
description="Sex Education QA"
|
81 |
+
)
|
82 |
+
|
83 |
+
# indexs
|
84 |
+
index_params = client.prepare_index_params()
|
85 |
+
index_params.add_index(
|
86 |
+
field_name="title_vector",
|
87 |
+
index_type="IVF_FLAT",
|
88 |
+
metric_type="COSINE",
|
89 |
+
params={"nlist": 128}
|
90 |
+
)
|
91 |
+
index_params.add_index(
|
92 |
+
field_name="content_vector",
|
93 |
+
index_type="IVF_FLAT",
|
94 |
+
metric_type="COSINE",
|
95 |
+
params={"nlist": 128}
|
96 |
+
)
|
97 |
+
|
98 |
+
# create collection
|
99 |
+
client.create_collection(
|
100 |
+
collection_name="t_sur_sex_ed_question_answer_spider",
|
101 |
+
schema=collection_schema,
|
102 |
+
index_params=index_params
|
103 |
+
)
|
104 |
+
|
105 |
+
status = client.get_load_state("t_sur_sex_ed_question_answer_spider")
|
106 |
+
print(f"t_sur_sex_ed_question_answer_spider:{status}")
|
107 |
+
|
108 |
+
|
109 |
+
def prepare_sex_ed_youtube():
|
110 |
+
client = MilvusClient(uri=URI)
|
111 |
+
client.drop_collection("t_sur_sex_ed_youtube_spider")
|
112 |
+
|
113 |
+
# Fields
|
114 |
+
id = FieldSchema(name="id", dtype=DataType.VARCHAR, is_primary=True, max_length=1000)
|
115 |
+
link = FieldSchema(name="link", dtype=DataType.VARCHAR, max_length=512)
|
116 |
+
title = FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=256)
|
117 |
+
v_title = FieldSchema(name="title_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
118 |
+
views = FieldSchema(name="views", dtype=DataType.VARCHAR, max_length=64)
|
119 |
+
author = FieldSchema(name="author", dtype=DataType.VARCHAR, max_length=64)
|
120 |
+
picture = FieldSchema(name="picture", dtype=DataType.VARCHAR, max_length=512)
|
121 |
+
likes = FieldSchema(name="likes", dtype=DataType.VARCHAR, max_length=64)
|
122 |
+
duration = FieldSchema(name="duration", dtype=DataType.VARCHAR, max_length=64)
|
123 |
+
tag = FieldSchema(name="tag", dtype=DataType.VARCHAR, max_length=64)
|
124 |
+
v_tag = FieldSchema(name="tag_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
125 |
+
delete_status = FieldSchema(name="delete_status", dtype=DataType.INT8)
|
126 |
+
|
127 |
+
# Collection schema
|
128 |
+
collection_schema = CollectionSchema(
|
129 |
+
fields=[id, link, title, v_title, views, author, picture, likes, duration, tag, v_tag, delete_status],
|
130 |
+
auto_id=False,
|
131 |
+
enable_dynamic_fields=True,
|
132 |
+
description="Sex Education videos collection"
|
133 |
+
)
|
134 |
+
|
135 |
+
# indexs
|
136 |
+
index_params = client.prepare_index_params()
|
137 |
+
index_params.add_index(
|
138 |
+
field_name="title_vector",
|
139 |
+
index_type="IVF_FLAT",
|
140 |
+
metric_type="COSINE",
|
141 |
+
params={"nlist": 128}
|
142 |
+
)
|
143 |
+
index_params.add_index(
|
144 |
+
field_name="tag_vector",
|
145 |
+
index_type="IVF_FLAT",
|
146 |
+
metric_type="COSINE",
|
147 |
+
params={"nlist": 128}
|
148 |
+
)
|
149 |
+
|
150 |
+
# create collection
|
151 |
+
client.create_collection(
|
152 |
+
collection_name="t_sur_sex_ed_youtube_spider",
|
153 |
+
schema=collection_schema,
|
154 |
+
index_params=index_params
|
155 |
+
)
|
156 |
+
|
157 |
+
status = client.get_load_state(f"t_sur_sex_ed_youtube_spider")
|
158 |
+
print(f"t_sur_sex_ed_youtube_spider:{status}")
|
159 |
+
|
160 |
+
|
161 |
+
def prepare_pornVideo():
|
162 |
+
client = MilvusClient(uri=URI)
|
163 |
+
client.drop_collection("t_sur_video")
|
164 |
+
|
165 |
+
# Fields
|
166 |
+
url = FieldSchema(name="url", dtype=DataType.VARCHAR, max_length=256, is_primary=True)
|
167 |
+
duration = FieldSchema(name="duration", dtype=DataType.INT64)
|
168 |
+
viewCount = FieldSchema(name="viewCount", dtype=DataType.INT64)
|
169 |
+
cover_picture = FieldSchema(name="coverPicture", dtype=DataType.VARCHAR, max_length=1024)
|
170 |
+
title = FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=512)
|
171 |
+
v_title = FieldSchema(name="title_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
172 |
+
uploader = FieldSchema(name="uploader", dtype=DataType.VARCHAR, max_length=256)
|
173 |
+
categories = FieldSchema(name="categories", dtype=DataType.VARCHAR, max_length=1024)
|
174 |
+
v_categories = FieldSchema(name="categories_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
|
175 |
+
resource_type = FieldSchema(name="resourceType", dtype=DataType.INT8)
|
176 |
+
sexual_preference = FieldSchema(name="sexualPreference", dtype=DataType.INT8)
|
177 |
+
|
178 |
+
# Collection Schema
|
179 |
+
collection_schema = CollectionSchema(
|
180 |
+
fields=[url, duration, viewCount, cover_picture, title, v_title, uploader, categories, v_categories, resource_type, sexual_preference],
|
181 |
+
auto_id=False,
|
182 |
+
enable_dynamic_fields=True,
|
183 |
+
description="Sexual Education Videos"
|
184 |
+
)
|
185 |
+
|
186 |
+
#indexs
|
187 |
+
index_params = client.prepare_index_params()
|
188 |
+
index_params.add_index(
|
189 |
+
field_name="title_vector",
|
190 |
+
index_type="IVF_FLAT",
|
191 |
+
metric_type="COSINE",
|
192 |
+
params={"nlist": 128}
|
193 |
+
)
|
194 |
+
index_params.add_index(
|
195 |
+
field_name="categories_vector",
|
196 |
+
index_type="IVF_FLAT",
|
197 |
+
metric_type="COSINE",
|
198 |
+
params={"nlist": 128}
|
199 |
+
)
|
200 |
+
|
201 |
+
# create collection
|
202 |
+
client.create_collection(
|
203 |
+
collection_name="t_sur_video",
|
204 |
+
schema=collection_schema,
|
205 |
+
index_params=index_params
|
206 |
+
)
|
207 |
+
|
208 |
+
status = client.get_load_state("t_sur_video")
|
209 |
+
print(f"t_sur_video:{status}")
|
210 |
+
|
211 |
+
if __name__ == '__main__':
|
212 |
+
prepare_sex_ed_article_milvus()
|
213 |
+
prepare_sex_ed_qa_milvus()
|
214 |
+
prepare_sex_ed_youtube()
|
215 |
+
prepare_pornVideo()
|
milvusDB/retriever.py
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pymilvus import MilvusClient, WeightedRanker, AnnSearchRequest
|
2 |
+
from langchain_ollama import OllamaEmbeddings
|
3 |
+
|
4 |
+
class MilvusRetriever:
|
5 |
+
def __init__(self, uri):
|
6 |
+
self.uri = uri
|
7 |
+
self.embed_model = OllamaEmbeddings(model="bge-m3")
|
8 |
+
self.client = MilvusClient(self.uri)
|
9 |
+
|
10 |
+
def search(self, query, collection_name, top_k=10):
|
11 |
+
# Connect to Milvus and search for the top_k nearest neighbors to the query_vector
|
12 |
+
# in the specified collection.
|
13 |
+
"""_summary_
|
14 |
+
|
15 |
+
Args:
|
16 |
+
query (_type_): query string
|
17 |
+
collection_name (_type_): milvus_collection_name
|
18 |
+
top_k (int, optional): Top k results. Defaults to 10.
|
19 |
+
|
20 |
+
Returns:
|
21 |
+
[{"id", "distance", "entity"}]
|
22 |
+
"""
|
23 |
+
query_embedding = self.embed_model.embed_query(query)
|
24 |
+
|
25 |
+
if collection_name == "t_sur_sex_ed_article_spider":
|
26 |
+
return self.article_search(query_embedding, collection_name, top_k=top_k)
|
27 |
+
|
28 |
+
if collection_name == "t_sur_sex_ed_question_answer_spider":
|
29 |
+
return self.qa_search(query_embedding, collection_name, top_k=top_k)
|
30 |
+
|
31 |
+
if collection_name == "t_sur_sex_ed_youtube_spider":
|
32 |
+
return self.video_search(query_embedding, collection_name, top_k=top_k)
|
33 |
+
|
34 |
+
def article_search(self, embedding, collection_name, top_k):
|
35 |
+
search_param1 = {
|
36 |
+
"data": [embedding],
|
37 |
+
"anns_field": "chunk_vector",
|
38 |
+
"param": {
|
39 |
+
"metric_type": "COSINE",
|
40 |
+
"params": {"nprobe": 10}
|
41 |
+
},
|
42 |
+
"limit": top_k
|
43 |
+
}
|
44 |
+
search_param2 = {
|
45 |
+
"data": [embedding],
|
46 |
+
"anns_field": "title_vector",
|
47 |
+
"param": {
|
48 |
+
"metric_type": "COSINE",
|
49 |
+
"params": {"nprobe": 10}
|
50 |
+
},
|
51 |
+
"limit": top_k
|
52 |
+
}
|
53 |
+
search_param3 = {
|
54 |
+
"data": [embedding],
|
55 |
+
"anns_field": "tags",
|
56 |
+
"param": {
|
57 |
+
"metric_type": "COSINE",
|
58 |
+
"params": {"nprobe": 10}
|
59 |
+
},
|
60 |
+
"limit": top_k
|
61 |
+
}
|
62 |
+
rerank = WeightedRanker(0.6, 0.3, 0.1)
|
63 |
+
r1, r2, r3 = AnnSearchRequest(**search_param1), AnnSearchRequest(**search_param2), AnnSearchRequest(**search_param3)
|
64 |
+
candidates = [r1, r2, r3]
|
65 |
+
res = self.client.hybrid_search(
|
66 |
+
collection_name=collection_name,
|
67 |
+
ranker=rerank,
|
68 |
+
reqs=candidates,
|
69 |
+
limit=top_k,
|
70 |
+
output_fields=["title", "link", "chunk", "category"]
|
71 |
+
)[0]
|
72 |
+
return res
|
73 |
+
|
74 |
+
def qa_search(self, embedding, collection_name, top_k):
|
75 |
+
res = self.client.search(
|
76 |
+
collection_name=collection_name,
|
77 |
+
data=[embedding],
|
78 |
+
anns_field="title_vector",
|
79 |
+
search_params={"metric_type": "COSINE", "params": {"nprobe": 10}},
|
80 |
+
limit=top_k,
|
81 |
+
filter="content_type == 'A'",
|
82 |
+
output_fields=["title", "content", "url", "author", "avatar_url", "likes", "dislikes"]
|
83 |
+
)[0]
|
84 |
+
# 去重title
|
85 |
+
titles = []
|
86 |
+
result = []
|
87 |
+
for record in res:
|
88 |
+
if record["entity"]["title"] not in titles:
|
89 |
+
titles.append(record["entity"]["title"])
|
90 |
+
result.append(record)
|
91 |
+
return result
|
92 |
+
|
93 |
+
def video_search(self, embedding, collection_name, top_k):
|
94 |
+
res = self.client.search(
|
95 |
+
collection_name=collection_name,
|
96 |
+
data=[embedding],
|
97 |
+
anns_field="title_vector",
|
98 |
+
search_params={"metric_type": "COSINE", "params": {"nprobe": 10}},
|
99 |
+
filter="delete_status == 0",
|
100 |
+
limit=top_k,
|
101 |
+
output_fields=["title", "link", "author", "picture", "duration"]
|
102 |
+
)[0]
|
103 |
+
return res
|
104 |
+
|
105 |
+
def porn_search(self, embedding, collection_name, top_k):
|
106 |
+
pass
|
107 |
+
|
108 |
+
if __name__ == "__main__":
|
109 |
+
import json
|
110 |
+
retriever = MilvusRetriever(uri="http://localhost:19530")
|
111 |
+
colleciton_name = "t_sur_sex_ed_article_spider"
|
112 |
+
query = "How to build trust?"
|
113 |
+
res = retriever.search(query, colleciton_name, top_k=10)
|
114 |
+
res = [record["entity"] for record in res if record["distance"] > 0.3]
|
115 |
+
print(json.dumps(res))
|
milvusDB/update_milvus.py
ADDED
@@ -0,0 +1,275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, Request
|
2 |
+
from langchain_ollama import OllamaEmbeddings
|
3 |
+
from llama_index.core.node_parser import SentenceSplitter
|
4 |
+
from pymilvus import MilvusClient
|
5 |
+
from tqdm import tqdm
|
6 |
+
from concurrent.futures import ThreadPoolExecutor
|
7 |
+
import html2text
|
8 |
+
import logging
|
9 |
+
|
10 |
+
# 配置日志
|
11 |
+
logging.basicConfig(
|
12 |
+
filename='/home/purui/update_milvus.log', # 日志文件路径
|
13 |
+
filemode='a', # 追加模式
|
14 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
15 |
+
level=logging.ERROR
|
16 |
+
)
|
17 |
+
|
18 |
+
# 创建一个logger
|
19 |
+
logger = logging.getLogger(__name__)
|
20 |
+
|
21 |
+
executor = ThreadPoolExecutor(max_workers=10)
|
22 |
+
|
23 |
+
h = html2text.HTML2Text()
|
24 |
+
h.ignore_links = True
|
25 |
+
|
26 |
+
embed_model = OllamaEmbeddings(model="bge-m3")
|
27 |
+
|
28 |
+
app = FastAPI(
|
29 |
+
title="update_milvus",
|
30 |
+
description="update_milvus",
|
31 |
+
)
|
32 |
+
|
33 |
+
URI = "http://localhost:19530"
|
34 |
+
|
35 |
+
def update_article(data):
|
36 |
+
# update article
|
37 |
+
splitter = SentenceSplitter(chunk_size=200, chunk_overlap=20)
|
38 |
+
client = MilvusClient(uri=URI)
|
39 |
+
collection_name = "t_sur_sex_ed_article_spider"
|
40 |
+
|
41 |
+
logger.info(f"Starting Embedding: {data}")
|
42 |
+
ct = 0
|
43 |
+
for row in tqdm(data, desc="Updating Milvus"):
|
44 |
+
id = row["id"]
|
45 |
+
# 同ID数据更新
|
46 |
+
if client.get(collection_name=collection_name, ids=[id]):
|
47 |
+
client.delete(collection_name=collection_name, filter='id like "{id}%"')
|
48 |
+
title = row["title"]
|
49 |
+
content = row["content"]
|
50 |
+
tags = row["tags"]
|
51 |
+
link = row["link"]
|
52 |
+
category = row["category2"]
|
53 |
+
if category is None:
|
54 |
+
category = " "
|
55 |
+
|
56 |
+
content = splitter.split_text(h.handle(content)) # List[str]
|
57 |
+
content_embeddings = embed_model.embed_documents(content) # List[List[float]]
|
58 |
+
|
59 |
+
title_embeddings = embed_model.embed_query(title)
|
60 |
+
tags_embeddings = embed_model.embed_query(tags)
|
61 |
+
|
62 |
+
insert_data = []
|
63 |
+
# iter chunks from one article
|
64 |
+
for idx, (sentence, embedding) in enumerate(zip(content, content_embeddings)):
|
65 |
+
# update milvus
|
66 |
+
id = id + "_" + str(idx)
|
67 |
+
s_title = title
|
68 |
+
v_title = title_embeddings
|
69 |
+
s_chunk = sentence
|
70 |
+
v_chunk = embedding
|
71 |
+
row_data = {
|
72 |
+
"id": id,
|
73 |
+
"title": s_title,
|
74 |
+
"title_vector": v_title,
|
75 |
+
"chunk": s_chunk,
|
76 |
+
"chunk_vector": v_chunk,
|
77 |
+
"tags": tags_embeddings,
|
78 |
+
"link": link,
|
79 |
+
"category": category
|
80 |
+
}
|
81 |
+
insert_data.append(row_data)
|
82 |
+
ct += 1
|
83 |
+
# update milvus
|
84 |
+
client.insert(collection_name=collection_name, data=insert_data)
|
85 |
+
logger.error(f"Insert complete. {ct} chunks inserted.")
|
86 |
+
|
87 |
+
def update_qa(data):
|
88 |
+
# set up
|
89 |
+
client = MilvusClient(uri=URI)
|
90 |
+
collection_name = "t_sur_sex_ed_question_answer_spider"
|
91 |
+
splitter = SentenceSplitter(chunk_size=200, chunk_overlap=20)
|
92 |
+
|
93 |
+
logger.info(f"Starting Embedding: {data}")
|
94 |
+
ct = 0
|
95 |
+
for row in tqdm(data, desc="Updating Milvus"):
|
96 |
+
id = row["id"]
|
97 |
+
# 同ID数据更新
|
98 |
+
if client.get(collection_name=collection_name, ids=[id]):
|
99 |
+
client.delete(collection_name=collection_name, filter='id like "{id}%"')
|
100 |
+
url = row["url"]
|
101 |
+
title = row["title"]
|
102 |
+
content = row["content"]
|
103 |
+
content_type = row["type"]
|
104 |
+
likes = row["likeCount"]
|
105 |
+
dislikes = row["dislikeCount"]
|
106 |
+
author = row["authorName"]
|
107 |
+
avatar_url = row["avatarUrl"]
|
108 |
+
if avatar_url is None:
|
109 |
+
avatar_url = " "
|
110 |
+
content = splitter.split_text(h.handle(content))
|
111 |
+
|
112 |
+
title_vector = embed_model.embed_query(title)
|
113 |
+
content_vector = embed_model.embed_documents(content)
|
114 |
+
# iter chunks from one article
|
115 |
+
|
116 |
+
for idx, (sentence, embedding) in enumerate(zip(content, content_vector)):
|
117 |
+
sub_id = id + "_" + str(idx)
|
118 |
+
row_data = {
|
119 |
+
"id": sub_id,
|
120 |
+
"url": url,
|
121 |
+
"title_vector": title_vector,
|
122 |
+
"content_vector": embedding,
|
123 |
+
"title": title,
|
124 |
+
"content": sentence,
|
125 |
+
"content_type":content_type,
|
126 |
+
"author": author,
|
127 |
+
"avatar_url": avatar_url,
|
128 |
+
"likes": likes,
|
129 |
+
"dislikes": dislikes
|
130 |
+
}
|
131 |
+
# update milvus
|
132 |
+
client.insert(collection_name=collection_name, data=row_data)
|
133 |
+
ct += 1
|
134 |
+
logger.error(f"Insert complete. {ct} data inserted.")
|
135 |
+
|
136 |
+
|
137 |
+
def update_video(data):
|
138 |
+
# set up
|
139 |
+
client = MilvusClient(uri=URI)
|
140 |
+
collection_name = "t_sur_sex_ed_youtube_spider"
|
141 |
+
|
142 |
+
logger.info(f"Starting Embedding: {data}")
|
143 |
+
ct = 0
|
144 |
+
|
145 |
+
for row in tqdm(data, desc="Updating Milvus"):
|
146 |
+
id = row["id"]
|
147 |
+
# 同ID数据更新
|
148 |
+
if client.get(collection_name=collection_name, ids=[id]):
|
149 |
+
client.delete(collection_name=collection_name, filter='id like "{id}%"')
|
150 |
+
link = row["videoLink"]
|
151 |
+
title = row["videoTitle"]
|
152 |
+
views = row["videoViews"]
|
153 |
+
author = row["videoAuthor"]
|
154 |
+
picture = row["videoPicture"]
|
155 |
+
likes = row["videoLikes"]
|
156 |
+
duration = row["videoDuration"]
|
157 |
+
tag = row["tag"]
|
158 |
+
delete_status = row["deleteStatus"]
|
159 |
+
|
160 |
+
title_vector = embed_model.embed_query(title)
|
161 |
+
tag_vector = embed_model.embed_query(tag)
|
162 |
+
views = "".join(views.split(",")) # 599,450 -> 599450
|
163 |
+
|
164 |
+
if delete_status == "1":
|
165 |
+
continue
|
166 |
+
row_data = {
|
167 |
+
"id": id,
|
168 |
+
"link": link,
|
169 |
+
"title": title,
|
170 |
+
"title_vector": title_vector,
|
171 |
+
"tag": tag,
|
172 |
+
"tag_vector": tag_vector,
|
173 |
+
"author": author,
|
174 |
+
"picture": picture,
|
175 |
+
"likes": likes,
|
176 |
+
"duration": duration,
|
177 |
+
"views": views,
|
178 |
+
"delete_status": delete_status
|
179 |
+
}
|
180 |
+
# update milvus
|
181 |
+
client.insert(collection_name=collection_name, data=row_data)
|
182 |
+
ct += 1
|
183 |
+
logger.error(f"Insert complete. {ct} data inserted.")
|
184 |
+
|
185 |
+
def update_porn(data):
|
186 |
+
#set up
|
187 |
+
client = MilvusClient(uri=URI)
|
188 |
+
collection_name = "t_sur_video"
|
189 |
+
|
190 |
+
logger.info(f"Starting Embedding: {data}")
|
191 |
+
ct = 0
|
192 |
+
|
193 |
+
for row in tqdm(data):
|
194 |
+
url = row["webUrl"]
|
195 |
+
duration = row["duration"]
|
196 |
+
viewCount = row["viewCount"]
|
197 |
+
if viewCount == None:
|
198 |
+
continue
|
199 |
+
coverPicture = row["coverPicture"]
|
200 |
+
title = row["title"]
|
201 |
+
uploader = row["uploader"]
|
202 |
+
if uploader == None:
|
203 |
+
uploader = ""
|
204 |
+
categories = row["categories"]
|
205 |
+
resource_type = row["resourceType"]
|
206 |
+
sexual_preference = int(row["sexualPreference"])
|
207 |
+
delete_status = row["isDelete"]
|
208 |
+
|
209 |
+
# delete last element from categories
|
210 |
+
categories = categories[:-1]
|
211 |
+
categories = " ".join(categories)
|
212 |
+
|
213 |
+
# embedding
|
214 |
+
title_vector = embed_model.embed_query(title)
|
215 |
+
categories_vector = embed_model.embed_query(categories)
|
216 |
+
|
217 |
+
if delete_status != 1:
|
218 |
+
row_data = {
|
219 |
+
"url": url,
|
220 |
+
"duration": duration,
|
221 |
+
"viewCount": viewCount,
|
222 |
+
"coverPicture": coverPicture,
|
223 |
+
"title": title,
|
224 |
+
"uploader": uploader,
|
225 |
+
"categories": categories,
|
226 |
+
"resourceType": resource_type,
|
227 |
+
"sexualPreference": sexual_preference,
|
228 |
+
"title_vector": title_vector,
|
229 |
+
"categories_vector": categories_vector
|
230 |
+
}
|
231 |
+
|
232 |
+
client.insert(collection_name, data=row_data)
|
233 |
+
ct += 1
|
234 |
+
logger.error(f"Insert complete. {ct} data inserted.")
|
235 |
+
|
236 |
+
|
237 |
+
@app.post("/milvus")
|
238 |
+
async def update_milvus(request: Request):
|
239 |
+
# update milvus
|
240 |
+
body = await request.json()
|
241 |
+
data = body["page"]["data"]
|
242 |
+
table = body["type"]
|
243 |
+
print(f"data len: {len(data)}")
|
244 |
+
print(f"table: {table}")
|
245 |
+
if table == "articleSpiderSyncMilVus":
|
246 |
+
# update_article(data)
|
247 |
+
try:
|
248 |
+
executor.submit(update_article, data)
|
249 |
+
return {"status": "SUCCESS"}
|
250 |
+
except Exception as e:
|
251 |
+
logging.info(f"ThreadError: {e}")
|
252 |
+
elif table == "answerSpiderSyncMilVus":
|
253 |
+
try:
|
254 |
+
executor.submit(update_qa, data)
|
255 |
+
return {"status": "SUCCESS"}
|
256 |
+
except Exception as e:
|
257 |
+
logging.info(f"ThreadError: {e}")
|
258 |
+
elif table == "youtubeSpiderSyncMilVus":
|
259 |
+
try:
|
260 |
+
executor.submit(update_video, data)
|
261 |
+
return {"status": "SUCCESS"}
|
262 |
+
except Exception as e:
|
263 |
+
logging.info(f"ThreadError: {e}")
|
264 |
+
elif table == "syncToMediaSyncMilVus":
|
265 |
+
try:
|
266 |
+
executor.submit(update_porn, data)
|
267 |
+
return {"status": "SUCCESS"}
|
268 |
+
except Exception as e:
|
269 |
+
logging.info(f"ThreadError: {e}")
|
270 |
+
|
271 |
+
|
272 |
+
|
273 |
+
if __name__ == "__main__":
|
274 |
+
import uvicorn
|
275 |
+
uvicorn.run(app, host="0.0.0.0", port=8010, loop="asyncio")
|
pipeline/__init__.py
ADDED
File without changes
|
pipeline/chat_pipeline.py
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llama_index.core.query_pipeline import (
|
2 |
+
QueryPipeline,
|
3 |
+
InputComponent,
|
4 |
+
ArgPackComponent,
|
5 |
+
)
|
6 |
+
from llama_index.core.prompts import PromptTemplate
|
7 |
+
from llama_index.llms.ollama import Ollama
|
8 |
+
from typing import Any, Dict, List, Optional
|
9 |
+
from llama_index.core.bridge.pydantic import Field
|
10 |
+
from llama_index.core.llms import ChatMessage
|
11 |
+
from llama_index.core.query_pipeline import CustomQueryComponent
|
12 |
+
from llama_index.core.schema import NodeWithScore
|
13 |
+
|
14 |
+
|
15 |
+
DEFAULT_CONTEXT_PROMPT = (
|
16 |
+
"Here is some context that may be relevant:\n"
|
17 |
+
"-----\n"
|
18 |
+
"{node_context}\n"
|
19 |
+
"-----chat_history-----\n"
|
20 |
+
"{chat_history}\n"
|
21 |
+
"-----\n"
|
22 |
+
"Please write a response to the following question, using the above context:\n"
|
23 |
+
"{query_str}\n"
|
24 |
+
)
|
25 |
+
|
26 |
+
|
27 |
+
class ResponseComponent(CustomQueryComponent):
|
28 |
+
llm: Ollama = Field(..., description="The language model to use for generating responses.")
|
29 |
+
system_prompt: Optional[str] = Field(default=None, description="System prompt to use for the LLM")
|
30 |
+
context_prompt: str = Field(
|
31 |
+
default=DEFAULT_CONTEXT_PROMPT,
|
32 |
+
description="Context prompt use for llm",
|
33 |
+
)
|
34 |
+
|
35 |
+
@property
|
36 |
+
def _input_keys(self) -> set:
|
37 |
+
return {"chat_history", "nodes", "query_str"}
|
38 |
+
|
39 |
+
@property
|
40 |
+
def _output_keys(self) -> set:
|
41 |
+
return {"response"}
|
42 |
+
|
43 |
+
def _prepare_context(
|
44 |
+
self,
|
45 |
+
chat_history: List[ChatMessage],
|
46 |
+
nodes: List[NodeWithScore],
|
47 |
+
query_str: str,
|
48 |
+
) -> List[ChatMessage]:
|
49 |
+
node_context = ""
|
50 |
+
for idx, node in enumerate(nodes):
|
51 |
+
node_text = node.get_content(metadata_mode="llm")
|
52 |
+
node_context += f"Context Chunk {idx}:\n{node_text}\n\n"
|
53 |
+
|
54 |
+
formatted_context = self.context_prompt.format(
|
55 |
+
node_context=node_context,
|
56 |
+
query_str=query_str,
|
57 |
+
chat_history=chat_history
|
58 |
+
)
|
59 |
+
user_message = ChatMessage(role="user", content=formatted_context)
|
60 |
+
chat_history.append(user_message)
|
61 |
+
|
62 |
+
if self.system_prompt is not None:
|
63 |
+
chat_history = [
|
64 |
+
ChatMessage(role="system", content=self.system_prompt),
|
65 |
+
] + chat_history
|
66 |
+
|
67 |
+
return chat_history
|
68 |
+
|
69 |
+
def _run_component(self, **kwargs) -> Dict[str, Any]:
|
70 |
+
chat_history = kwargs["chat_history"]
|
71 |
+
nodes = kwargs["nodes"]
|
72 |
+
query_str = kwargs["query_str"]
|
73 |
+
|
74 |
+
prepared_context = self._prepare_context(
|
75 |
+
chat_history=chat_history,
|
76 |
+
nodes=nodes,
|
77 |
+
query_str=query_str,
|
78 |
+
)
|
79 |
+
|
80 |
+
response = self.llm.chat(prepared_context)
|
81 |
+
|
82 |
+
return {"response": response}
|
83 |
+
|
84 |
+
async def _arun_component(self, **kwargs: Any) -> Dict[str, Any]:
|
85 |
+
chat_history = kwargs["chat_history"]
|
86 |
+
nodes = kwargs["nodes"]
|
87 |
+
query_str = kwargs["query_str"]
|
88 |
+
|
89 |
+
prepared_context = self._prepare_context(
|
90 |
+
chat_history=chat_history,
|
91 |
+
nodes=nodes,
|
92 |
+
query_str=query_str,
|
93 |
+
)
|
94 |
+
|
95 |
+
response = await self.llm.chat(prepared_context)
|
96 |
+
|
97 |
+
return {"response": response}
|
pipeline/kb_pipeline.py
ADDED
File without changes
|
pipeline/modules.py
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from llama_index.core import load_index_from_storage, StorageContext, SQLDatabase, VectorStoreIndex, Settings
|
3 |
+
from llama_index.core.objects import (
|
4 |
+
SQLTableNodeMapping,
|
5 |
+
ObjectIndex,
|
6 |
+
SQLTableSchema,
|
7 |
+
)
|
8 |
+
from typing import List, Dict, Any
|
9 |
+
from pydantic import BaseModel
|
10 |
+
from langchain_community.embeddings.ollama import OllamaEmbeddings
|
11 |
+
from llama_index.core.llms import ChatResponse
|
12 |
+
from llama_index.core.indices.keyword_table.base import KeywordTableIndex
|
13 |
+
from llama_index.core.query_pipeline import CustomQueryComponent
|
14 |
+
from llama_index.core.retrievers import SQLRetriever
|
15 |
+
from llama_index.core.bridge.pydantic import Field
|
16 |
+
|
17 |
+
embed_model = OllamaEmbeddings(model="pornchat")
|
18 |
+
Settings.embed_model = embed_model
|
19 |
+
|
20 |
+
class CustomSQLRetriever(CustomQueryComponent):
|
21 |
+
|
22 |
+
sql_db: SQLDatabase = Field(..., description="SQL Database")
|
23 |
+
|
24 |
+
def _validate_component_inputs(
|
25 |
+
self, input: Dict[str, Any]
|
26 |
+
) -> Dict[str, Any]:
|
27 |
+
"""Validate component inputs during run_component."""
|
28 |
+
# NOTE: this is OPTIONAL but we show you here how to do validation as an example
|
29 |
+
return input
|
30 |
+
|
31 |
+
@property
|
32 |
+
def _input_keys(self) -> set:
|
33 |
+
"""Input keys dict."""
|
34 |
+
return {"query_str", "sql_query"}
|
35 |
+
|
36 |
+
@property
|
37 |
+
def _output_keys(self) -> set:
|
38 |
+
# can do multi-outputs too
|
39 |
+
return {"output", "is_valid"}
|
40 |
+
|
41 |
+
def _run_component(self, **kwargs) -> Dict[str, Any]:
|
42 |
+
"""Run the component."""
|
43 |
+
# run logic
|
44 |
+
retriever = SQLRetriever(self.sql_db)
|
45 |
+
try:
|
46 |
+
query = kwargs["sql_query"]
|
47 |
+
output = retriever.retrieve(query)
|
48 |
+
is_valid = True
|
49 |
+
except Exception as e:
|
50 |
+
output = ""
|
51 |
+
is_valid = False
|
52 |
+
return {"output": output, "is_valid": is_valid}
|
53 |
+
|
54 |
+
|
55 |
+
def get_table_obj_retriever(index_path: str, table_infos: List[BaseModel],schema_table_mapping: Dict[str, str], sql_db: SQLDatabase):
|
56 |
+
if os.path.exists(index_path):
|
57 |
+
index = load_index_from_storage(StorageContext.from_defaults(persist_dir=index_path))
|
58 |
+
node_mapping = SQLTableNodeMapping(sql_db)
|
59 |
+
table_schema_objs = [
|
60 |
+
SQLTableSchema(table_name=schema_table_mapping[t.table_name], context_str=t.table_summary) for t in table_infos
|
61 |
+
]
|
62 |
+
obj_index = ObjectIndex.from_objects_and_index(objects=table_schema_objs, index=index)
|
63 |
+
retriever = obj_index.as_retriever(simliarity_top_k=1)
|
64 |
+
return retriever
|
65 |
+
else:
|
66 |
+
return False
|
67 |
+
|
68 |
+
def create_table_obj_retriever(index_path: str, sql_db: SQLDatabase,
|
69 |
+
table_infos: List[BaseModel],
|
70 |
+
schema_table_mapping: Dict[str, str]
|
71 |
+
):
|
72 |
+
table_node_mapping = SQLTableNodeMapping(sql_db)
|
73 |
+
table_schema_objs = [
|
74 |
+
SQLTableSchema(table_name=schema_table_mapping[t.table_name], context_str=t.table_summary) for t in table_infos
|
75 |
+
]
|
76 |
+
storage_context = StorageContext.from_defaults(persist_dir=index_path)
|
77 |
+
obj_index = ObjectIndex.from_objects(
|
78 |
+
table_schema_objs,
|
79 |
+
table_node_mapping,
|
80 |
+
KeywordTableIndex,
|
81 |
+
)
|
82 |
+
retriever = obj_index.as_retriever(similarity_top_k=2)
|
83 |
+
return retriever
|
84 |
+
|
85 |
+
def get_table_context_str(schema_table_mapping: Dict[str, str],table_schema_objs: List[SQLTableSchema], sql_database: SQLDatabase):
|
86 |
+
"""Get table context string."""
|
87 |
+
context_strs = []
|
88 |
+
for table_schema_obj in table_schema_objs:
|
89 |
+
table_info = sql_database.get_single_table_info(
|
90 |
+
schema_table_mapping[table_schema_obj.table_name]
|
91 |
+
)
|
92 |
+
if table_schema_obj.context_str:
|
93 |
+
table_opt_context = " The table description is: "
|
94 |
+
table_opt_context += table_schema_obj.context_str
|
95 |
+
table_info += table_opt_context
|
96 |
+
|
97 |
+
context_strs.append(table_info)
|
98 |
+
return "\n\n".join(context_strs)
|
99 |
+
|
100 |
+
def parse_response_to_sql(response: ChatResponse) -> str:
|
101 |
+
"""Parse response to SQL."""
|
102 |
+
response = response.message.content
|
103 |
+
sql_query_start = response.find("SQLQuery:")
|
104 |
+
if sql_query_start != -1:
|
105 |
+
response = response[sql_query_start:]
|
106 |
+
# TODO: move to removeprefix after Python 3.9+
|
107 |
+
if response.startswith("SQLQuery:"):
|
108 |
+
response = response[len("SQLQuery:") :]
|
109 |
+
sql_result_start = response.find("SQLResult:")
|
110 |
+
if sql_result_start != -1:
|
111 |
+
response = response[:sql_result_start]
|
112 |
+
return response.strip().strip("```").strip()
|
pipeline/search_pipeline.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
"searchParameters": {
|
3 |
+
"q": "apple inc",
|
4 |
+
"gl": "us",
|
5 |
+
"hl": "en",
|
6 |
+
"autocorrect": true,
|
7 |
+
"page": 1,
|
8 |
+
"type": "search" # videos, images
|
9 |
+
},
|
10 |
+
|
11 |
+
返回结果:
|
12 |
+
result_keys: dict_keys(['search_metadata', 'search_parameters', 'search_information', 'organic_results', 'pagination', 'serpapi_pagination'])
|
13 |
+
其中video_search:
|
14 |
+
result_keys: dict_keys(['search_metadata', 'search_parameters', 'search_information', 'video_results', 'pagination', 'serpapi_pagination'])
|
15 |
+
其中xxx_results是包含不同搜索结果(字典)的列表:
|
16 |
+
dict_keys(['position', 'title', 'link', 'displayed_link', 'thumbnail', 'date', 'snippet', 'duration', 'rich_snippet'])
|
17 |
+
{'position': 1, 'title': 'Pornhub 2020 most Popular MILF Videos', 'link': 'https://www.pornhub.com/view_video.php?viewkey=ph602ecf9f1563b', 'displayed_link': 'www.pornhub.com › view_video', 'thumbnail': 'https://serpapi.com/searches/66f1473aca6f0ca2eca329ff/images/d99e1712df529f4c186080a8f9741ab90c6104312b61494d31fa7ecab583106d.jpeg', 'date': 'Feb 18, 2021', 'snippet': 'Watch Pornhub 2020 Most Popular MILF videos on Pornhub.com, the best hardcore porn site. Pornhub is home to the widest selection of free ...', 'duration': '11:31', 'rich_snippet': {'top': {'extensions': ['Pornhub', 'Pornhub Models', 'Feb 18, 2021'], 'detected_extensions': {'feb': 18}}}}
|
18 |
+
"""
|
19 |
+
|
20 |
+
from serpapi import GoogleSearch
|
21 |
+
|
22 |
+
params = {
|
23 |
+
"engine": "google",
|
24 |
+
"q": "苍井空最近的影片",
|
25 |
+
# "location": "Austin, Texas, United States",
|
26 |
+
"google_domain": "google.com",
|
27 |
+
"gl": "us",
|
28 |
+
"hl": "en",
|
29 |
+
"num": 5,
|
30 |
+
"api_key": "0942793f1c7ef851ce5dbcd8b6e3cf5e342a961c8a1b24fae9f552a679c2d444"
|
31 |
+
}
|
32 |
+
|
33 |
+
search = GoogleSearch(params)
|
34 |
+
results = search.get_dict()
|
35 |
+
print(type(results["organic_results"][0]))
|
pipeline/sql_pipeline.py
ADDED
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llama_index.core.query_pipeline import (
|
2 |
+
QueryPipeline,
|
3 |
+
Link,
|
4 |
+
InputComponent,
|
5 |
+
CustomQueryComponent,
|
6 |
+
)
|
7 |
+
|
8 |
+
from llama_index.core.objects import (
|
9 |
+
SQLTableNodeMapping,
|
10 |
+
ObjectIndex,
|
11 |
+
SQLTableSchema,
|
12 |
+
)
|
13 |
+
from pyvis.network import Network
|
14 |
+
import Stemmer
|
15 |
+
from IPython.display import display, HTML
|
16 |
+
from sqlalchemy import create_engine
|
17 |
+
from llama_index.core import SQLDatabase, VectorStoreIndex, PromptTemplate
|
18 |
+
from llama_index.core.program import LLMTextCompletionProgram
|
19 |
+
from llama_index.core.bridge.pydantic import BaseModel, Field
|
20 |
+
from typing import Dict, List, Any
|
21 |
+
from llama_index.core.query_pipeline import FnComponent
|
22 |
+
from llama_index.core.prompts.default_prompts import DEFAULT_TEXT_TO_SQL_PROMPT
|
23 |
+
from llama_index.core.retrievers import SQLRetriever
|
24 |
+
from llama_index.llms.ollama import Ollama
|
25 |
+
from llama_index.core.objects.base import ObjectRetriever
|
26 |
+
import pymysql, pandas as pd
|
27 |
+
from llama_index.retrievers.bm25 import BM25Retriever
|
28 |
+
from llama_index.core.schema import IndexNode
|
29 |
+
from modules import (
|
30 |
+
get_table_obj_retriever,
|
31 |
+
create_table_obj_retriever,
|
32 |
+
get_table_context_str,
|
33 |
+
parse_response_to_sql,
|
34 |
+
CustomSQLRetriever
|
35 |
+
)
|
36 |
+
|
37 |
+
|
38 |
+
|
39 |
+
PROMPT_STR = """\
|
40 |
+
Give me a summary of the table with the following format.
|
41 |
+
|
42 |
+
- table_summary: Describe what the table is about in short. Columns: [col1(type), col2(type), ...]
|
43 |
+
|
44 |
+
Table:
|
45 |
+
{table_str}
|
46 |
+
"""
|
47 |
+
|
48 |
+
db_user = "shenzhen_ai_for_vibemate_eson"
|
49 |
+
db_password = "dBsnc7OrM0MVi0FEhiHe2y"
|
50 |
+
db_host = "192.168.1.99"
|
51 |
+
db_port = 3306
|
52 |
+
db_name = "hytto_surfease"
|
53 |
+
|
54 |
+
TABLE_SUMMARY = {
|
55 |
+
"t_sur_media_sync_es": "This table is about Porn video information:\n\nt_sur_media_sync_es: Columns:id (integer), web_url (string), duration (integer), pattern_per (integer), like_count (integer), dislike_count (integer), view_count (integer), cover_picture (string), title (string), upload_date (datetime), uploader (string), create_time (datetime), update_time (datetime), categories (list of strings), abbreviate_video_url (string), abbreviate_mp4_video_url (string), resource_type (string), like_count_show (integer), stat_version (integer), tags (list of strings), model_name (string), publisher_type (string), period (integer), sexual_preference (string), country (string), type (string), rank_number (integer), rank_rate (float), has_pattern (boolean), trace (string), manifest_url (string), is_delete (boolean), web_url_md5 (string), view_key (string)",
|
56 |
+
"t_sur_models_info": "This table is about Stripchat models' information:\n\nt_sur_models_info: Columns:id (INTEGER), username (VARCHAR(100), image (VARCHAR(500), num_users (INTEGER), pf (VARCHAR(50), pf_model_unite (VARCHAR(50), use_plugin (INTEGER), create_time (DATETIME), update_time (DATETIME), update_time (DATETIME), gender (VARCHAR(50), broadcast_type (VARCHAR(50), common_gender (VARCHAR(50), avatar (VARCHAR(512), age (INTEGER) "
|
57 |
+
}
|
58 |
+
|
59 |
+
class SQLPipeline:
|
60 |
+
def __init__(self, llm: Ollama):
|
61 |
+
self.llm = llm
|
62 |
+
self.engine = create_engine(f"mysql+pymysql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}")
|
63 |
+
self.sql_db = SQLDatabase(self.engine)
|
64 |
+
self.table_names = self.sql_db.get_usable_table_names()
|
65 |
+
self.schema_table_mapping = {}
|
66 |
+
self.init_schema_table_mapping()
|
67 |
+
self.modules = self.prepare_modules()
|
68 |
+
self.pipeline = self.build_pipeline()
|
69 |
+
|
70 |
+
def init_schema_table_mapping(self):
|
71 |
+
self.table_infos = []
|
72 |
+
table_names = set()
|
73 |
+
for table in self.table_names:
|
74 |
+
table_info = TableInfo(table_name=table, table_summary=TABLE_SUMMARY[table])
|
75 |
+
self.table_infos.append(table_info)
|
76 |
+
# 摘要表名: 真实表名
|
77 |
+
self.schema_table_mapping[table_info.table_name] = table
|
78 |
+
|
79 |
+
def prepare_modules(self):
|
80 |
+
modules = {}
|
81 |
+
# input
|
82 |
+
modules["input"] = InputComponent()
|
83 |
+
# table retriever
|
84 |
+
table_obj_index_path = "/home/purui/projects/chatbot/kb/sql/table_obj_index"
|
85 |
+
retriever = create_table_obj_retriever(
|
86 |
+
index_path=table_obj_index_path,
|
87 |
+
table_infos=self.table_infos,
|
88 |
+
sql_db=self.sql_db,
|
89 |
+
schema_table_mapping=self.schema_table_mapping
|
90 |
+
)
|
91 |
+
modules["table_retriever"] = TableRetrieveComponent(
|
92 |
+
retriever=retriever,
|
93 |
+
sql_database=self.sql_db
|
94 |
+
)
|
95 |
+
# text2sql_prompt
|
96 |
+
text2sql_prompt = DEFAULT_TEXT_TO_SQL_PROMPT.partial_format(
|
97 |
+
dialect=self.engine.dialect.name
|
98 |
+
)
|
99 |
+
modules["text2sql_prompt"] = text2sql_prompt
|
100 |
+
# text2sql_llm
|
101 |
+
modules["text2sql_llm"] = self.llm
|
102 |
+
# sql output parser
|
103 |
+
modules["sql_output_parser"] = FnComponent(fn=parse_response_to_sql)
|
104 |
+
# sql retriever
|
105 |
+
# modules["sql_retriever"] = SQLRetriever(self.sql_db)
|
106 |
+
modules["sql_retriever"] = CustomSQLRetriever(sql_db=self.sql_db)
|
107 |
+
# response synthesise prompt
|
108 |
+
response_synthesis_prompt_str = (
|
109 |
+
"Given an input question, synthesize a response from the query results.\n"
|
110 |
+
"Query: {query_str}\n"
|
111 |
+
"SQL: {sql_query}\n"
|
112 |
+
"SQL Response: {context_str}\n"
|
113 |
+
"Response: "
|
114 |
+
)
|
115 |
+
response_synthesis_prompt = PromptTemplate(
|
116 |
+
response_synthesis_prompt_str,
|
117 |
+
)
|
118 |
+
modules["response_synthesis_prompt"] = response_synthesis_prompt
|
119 |
+
# response synthesise llm
|
120 |
+
modules["response_synthesis_llm"] = self.llm
|
121 |
+
|
122 |
+
return modules
|
123 |
+
|
124 |
+
def build_pipeline(self):
|
125 |
+
qp = QueryPipeline(
|
126 |
+
modules=self.modules,
|
127 |
+
verbose=True,
|
128 |
+
)
|
129 |
+
# add chains & links
|
130 |
+
qp.add_link("input", "table_retriever", dest_key="query")
|
131 |
+
qp.add_link("input", "text2sql_prompt", dest_key="query_str")
|
132 |
+
qp.add_link("table_retriever", "text2sql_prompt", dest_key="schema")
|
133 |
+
qp.add_chain(
|
134 |
+
["text2sql_prompt", "text2sql_llm", "sql_output_parser"]
|
135 |
+
)
|
136 |
+
qp.add_link(
|
137 |
+
"sql_output_parser", "response_synthesis_prompt", dest_key="sql_query"
|
138 |
+
)
|
139 |
+
qp.add_link("input", "sql_retriever", dest_key="query_str")
|
140 |
+
qp.add_link("sql_output_parser", "sql_retriever", dest_key="sql_query")
|
141 |
+
# custom sql_retriever component:定义is_valid字段,如果执行sql检索有正确返回结果,则is_valid为True 作为sql_retriever -> response_synthesis_prompt的链接条件
|
142 |
+
# 若is_valid为False,则重新回到text2sql_prompt链路中,重新生成sql
|
143 |
+
qp.add_link(
|
144 |
+
"sql_retriever", "response_synthesis_prompt", dest_key="context_str", condition_fn=lambda x: x["is_valid"]
|
145 |
+
)
|
146 |
+
qp.add_link("sql_retriever", "text2sql_prompt", src_key="query_str", dest_key="query_str", condition_fn=lambda x: not x["is_valid"])
|
147 |
+
qp.add_link("input", "response_synthesis_prompt", dest_key="query_str")
|
148 |
+
qp.add_link("response_synthesis_prompt", "response_synthesis_llm")
|
149 |
+
return qp
|
150 |
+
|
151 |
+
def get_vision(self):
|
152 |
+
net = Network(notebook=True, cdn_resources="in_line", directed=True)
|
153 |
+
net.from_nx(self.pipeline.dag)
|
154 |
+
net.write_html("text2sql_dag.html")
|
155 |
+
with open("text2sql_dag.html", "r") as file:
|
156 |
+
html_content = file.read()
|
157 |
+
# Display the HTML content
|
158 |
+
display(HTML(html_content))
|
159 |
+
def run(self, query: str):
|
160 |
+
response = self.pipeline.run(query=query)
|
161 |
+
return str(response)
|
162 |
+
|
163 |
+
|
164 |
+
class TableInfo(BaseModel):
|
165 |
+
"""Information regarding a structured table."""
|
166 |
+
|
167 |
+
table_name: str = Field(
|
168 |
+
..., description="table name (must be underscores and NO spaces)"
|
169 |
+
)
|
170 |
+
table_summary: str = Field(
|
171 |
+
..., description="short, concise summary/caption of the table"
|
172 |
+
)
|
173 |
+
|
174 |
+
|
175 |
+
class TableRetrieveComponent(CustomQueryComponent):
|
176 |
+
"""Retrieves table information from the database."""
|
177 |
+
|
178 |
+
retriever: ObjectRetriever = Field(..., description="Retriever to use for table info")
|
179 |
+
sql_database: SQLDatabase = Field(..., description="SQL engine to use for table info")
|
180 |
+
|
181 |
+
def _validate_component_inputs(
|
182 |
+
self, input: Dict[str, Any]
|
183 |
+
) -> Dict[str, Any]:
|
184 |
+
"""Validate component inputs during run_component."""
|
185 |
+
# NOTE: this is OPTIONAL but we show you here how to do validation as an example
|
186 |
+
return input
|
187 |
+
|
188 |
+
@property
|
189 |
+
def _input_keys(self) -> set:
|
190 |
+
"""Input keys dict."""
|
191 |
+
return {"query"}
|
192 |
+
|
193 |
+
@property
|
194 |
+
def _output_keys(self) -> set:
|
195 |
+
# can do multi-outputs too
|
196 |
+
return {"output"}
|
197 |
+
|
198 |
+
def _run_component(self, **kwargs) -> Dict[str, Any]:
|
199 |
+
"""Run the component."""
|
200 |
+
# run logic
|
201 |
+
table_schema = self.retriever.retrieve(kwargs["query"])[0]
|
202 |
+
table_name = table_schema.table_name
|
203 |
+
table_info = TABLE_SUMMARY[table_name]
|
204 |
+
return {"output": table_info}
|
205 |
+
|
206 |
+
|
207 |
+
|
208 |
+
if __name__ == '__main__':
|
209 |
+
sql_pipeline = SQLPipeline(llm=Ollama(model="mannix/llama3.1-8b-abliterated",
|
210 |
+
request_timeout=120))
|
211 |
+
response = sql_pipeline.run("I want 5 different big tits milf porn with it's title and web url")
|
212 |
+
print(response)
|
213 |
+
# table_retriever = sql_pipeline.modules["table_retriever"]
|
214 |
+
# # result = table_retriever.retrieve("Give me top 5 videos by view count.")
|
215 |
+
# # print(result)
|
216 |
+
# qp = QueryPipeline(
|
217 |
+
# modules={
|
218 |
+
# "input": InputComponent(),
|
219 |
+
# "table_retriever": TableRetrieveComponent(retriever=table_retriever, sql_database=sql_pipeline.sql_db),
|
220 |
+
# }
|
221 |
+
# )
|
222 |
+
# qp.add_link("input", "table_retriever", dest_key="query")
|
223 |
+
# response = qp.run(query="Give me top 5 videos by view count.")
|
224 |
+
# print(response)
|
pipeline/table_infos.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from sqlalchemy import create_engine
|
2 |
+
from llama_index.core import SQLDatabase
|
3 |
+
from llama_index.core.llms import ChatMessage
|
4 |
+
from llama_index.llms.ollama import Ollama
|
5 |
+
import pandas as pd
|
6 |
+
|
7 |
+
db_user = "shenzhen_ai_for_vibemate_eson"
|
8 |
+
db_password = "dBsnc7OrM0MVi0FEhiHe2y"
|
9 |
+
db_host = "192.168.1.99"
|
10 |
+
db_port = 3306
|
11 |
+
db_name = "hytto_surfease"
|
12 |
+
|
13 |
+
engine = create_engine(f"mysql+pymysql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}", echo=True)
|
14 |
+
sql_database = SQLDatabase(engine)
|
15 |
+
|
16 |
+
table_names = sql_database.get_usable_table_names()
|
17 |
+
PROMPT_STR = """\
|
18 |
+
Give me a summary of the table with the following format.
|
19 |
+
|
20 |
+
- table_summary: Describe what the table is about in short. Columns: [col1(type), col2(type), ...]
|
21 |
+
|
22 |
+
Table:
|
23 |
+
{table_str}
|
24 |
+
"""
|
25 |
+
table_infos = {}
|
26 |
+
for table in table_names:
|
27 |
+
table_info = sql_database.get_single_table_info(table)
|
28 |
+
table_infos[table] = table_info
|
29 |
+
|
30 |
+
print(table_infos)
|
pipeline/text2sql_dag.html
ADDED
The diff for this file is too large to render.
See raw diff
|
|
prompts/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
|
3 |
+
## Development
|
4 |
+
|
5 |
+
### Installation
|
6 |
+
|
7 |
+
1. requirements
|
8 |
+
```bash
|
9 |
+
pip install -r requirements.txt
|
10 |
+
```
|
11 |
+
|
prompts/__init__.py
ADDED
File without changes
|
prompts/agent_prompts.py
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
DEFAULT_AGENT_PROMPT = """\
|
2 |
+
|
3 |
+
## Behavior
|
4 |
+
You are a helpful assistant to talk with users, you're provided with chat history with the current user and you should take those \
|
5 |
+
as reference if that helps you to answer the user. You're aslowed to use the tools provided to you to answer the user. \
|
6 |
+
|
7 |
+
## Tools
|
8 |
+
You have access to a wide variety of tools. You are responsible for using
|
9 |
+
the tools in any sequence you deem appropriate to complete the task at hand.
|
10 |
+
This may require breaking the task into subtasks and using different tools
|
11 |
+
to complete each subtask.You should always chose the most appropriate tool to use \
|
12 |
+
|
13 |
+
You have access to the following tools:
|
14 |
+
{tool_desc}
|
15 |
+
|
16 |
+
## Output Format
|
17 |
+
To answer the question, you should think about whether you should use a tool and if you should use tools please use the following format.
|
18 |
+
|
19 |
+
```
|
20 |
+
Thought: I need to use a tool to help me answer the question(if needed).
|
21 |
+
Action: tool name (one of {tool_names}) if using a tool.
|
22 |
+
Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}})
|
23 |
+
```
|
24 |
+
|
25 |
+
Please ALWAYS start with a Thought.
|
26 |
+
|
27 |
+
Please use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}.
|
28 |
+
|
29 |
+
If this format is used, the user will respond in the following format:
|
30 |
+
|
31 |
+
```
|
32 |
+
Observation: tool response
|
33 |
+
```
|
34 |
+
|
35 |
+
You should keep repeating the above format until you have enough information
|
36 |
+
to answer the question without using any more tools. At that point, you MUST respond
|
37 |
+
in the one of the following two formats:
|
38 |
+
|
39 |
+
```
|
40 |
+
Thought: I can answer without using any more tools.
|
41 |
+
Answer: [your answer here]
|
42 |
+
```
|
43 |
+
|
44 |
+
```
|
45 |
+
Thought: I cannot answer the question with the provided tools. I will use my prior knowledge and chat history to answer the question.
|
46 |
+
Answer: [your answer here]
|
47 |
+
```
|
48 |
+
|
49 |
+
## Additional Rules
|
50 |
+
- The answer MUST contain a sequence of bullet points that explain how you arrived at the answer. This can include aspects of the previous conversation history.
|
51 |
+
- You MUST obey the function signature of each tool. Do NOT pass in no arguments if the function expects arguments.
|
52 |
+
|
53 |
+
## Current Conversation
|
54 |
+
Below is the current conversation consisting of interleaving human and assistant messages.
|
55 |
+
|
56 |
+
"""
|
57 |
+
|
58 |
+
CHAT_AGENT_PROMPT = """
|
59 |
+
|
60 |
+
Your name is Winnie. You are a helpful sexual education professor to chat with users. You will answer any questions in a Kind and Friendly tone.
|
61 |
+
You are provided with the chat history and you should ALWAYS take it as reference to chat with the user.
|
62 |
+
|
63 |
+
You should ALWAYS use the tool to answer user's specific question. If you cannot answer the question with the provided tools, you should use your prior knowledge and chat history to answer the question.
|
64 |
+
|
65 |
+
## Tools
|
66 |
+
You have access to a wide variety of tools. You are responsible for using
|
67 |
+
the tools in any sequence you deem appropriate to complete the task at hand. You should extract the keyword from user's question and use the most appropriate tool to answer the question.
|
68 |
+
This may require breaking the task into subtasks and using different tools
|
69 |
+
to complete each subtask.You should always chose the most appropriate tool to use \
|
70 |
+
|
71 |
+
You have access to the following tools:
|
72 |
+
{tool_desc}
|
73 |
+
|
74 |
+
## Output Format
|
75 |
+
DO NOT output the chat history in your response.
|
76 |
+
|
77 |
+
|
78 |
+
```
|
79 |
+
Thought: I need to use a tool to help me answer the question(if needed).
|
80 |
+
Action: tool name (one of {tool_names}) if using a tool.
|
81 |
+
Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{"input": "hello world", "num_beams": 5}})
|
82 |
+
```
|
83 |
+
|
84 |
+
Please ALWAYS start with a Thought.
|
85 |
+
|
86 |
+
Please use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}.
|
87 |
+
|
88 |
+
If this format is used, the user will respond in the following format:
|
89 |
+
|
90 |
+
```
|
91 |
+
Observation: tool response
|
92 |
+
```
|
93 |
+
|
94 |
+
You should keep repeating the above format until you have enough information
|
95 |
+
to answer the question without using any more tools. At that point, you MUST respond
|
96 |
+
in the one of the following two formats:
|
97 |
+
|
98 |
+
```
|
99 |
+
Thought: I can answer without using any more tools.
|
100 |
+
Answer: [your answer here]
|
101 |
+
```
|
102 |
+
|
103 |
+
```
|
104 |
+
Thought: I cannot answer the question with the provided tools.
|
105 |
+
Answer: Sorry, I don't know anything about that.
|
106 |
+
```
|
107 |
+
|
108 |
+
## Additional Rules
|
109 |
+
- The answer MUST contain a sequence of bullet points that explain how you arrived at the answer. This can include aspects of the previous conversation history.
|
110 |
+
- You MUST obey the function signature of each tool. Do NOT pass in no arguments if the function expects arguments.
|
111 |
+
|
112 |
+
## Current Conversation
|
113 |
+
Below is the current conversation consisting of interleaving human and assistant messages.
|
114 |
+
|
115 |
+
"""
|
116 |
+
|
117 |
+
|
118 |
+
RETRIEVE_CONTEXT_TEMPLATE= """
|
119 |
+
You are given the flowing context information. ALWAYS use these information as your knowledge to answer the question.
|
120 |
+
|
121 |
+
Context information is below:
|
122 |
+
\n--------------------\n
|
123 |
+
{context_str}
|
124 |
+
\n--------------------\n
|
125 |
+
)
|
126 |
+
"""
|
127 |
+
|
128 |
+
RETRIEVE_SYSTEM_PROMPT = """
|
129 |
+
Your name is Winnie. You are a helpful sexual education professor to chat with users. You will answer any questions in a Kind and Friendly tone.
|
130 |
+
|
131 |
+
You are given the context information as your knowledge and you ALWAYS ANSWER the question with certain opinion.
|
132 |
+
"""
|
prompts/default_prompts.py
ADDED
@@ -0,0 +1,469 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llama_index.core import PromptTemplate
|
2 |
+
|
3 |
+
|
4 |
+
SQL_RESPONSE_PROMPT_TEMPLATE = (
|
5 |
+
"Given an input question, synthesize a response from the query results.\n"
|
6 |
+
"Query: {query_str}\n"
|
7 |
+
"SQL: {sql_query}\n"
|
8 |
+
"SQL Response: {context_str}\n"
|
9 |
+
"Response: "
|
10 |
+
)
|
11 |
+
SQL_RESPONSE_PROMPT = PromptTemplate(SQL_RESPONSE_PROMPT_TEMPLATE)
|
12 |
+
|
13 |
+
RESPONSE_PROMPT_TEMPLATE = (
|
14 |
+
"You're a naughty sexy chat bot name Wnnie and you will answer the user's question with a naughty tone."
|
15 |
+
"Given an input question and the related context, maximize the use of the given context to give a helpful response.\n"
|
16 |
+
"You can also take the given chat history as background information to answer user's question.\n"
|
17 |
+
"Provide the summarization of the related context in the response.\n"
|
18 |
+
"Query: {query_str}\n"
|
19 |
+
"Related context: {context_str}\n"
|
20 |
+
"Chat history: {chat_history}\n"
|
21 |
+
"You are required to use and ALWAYS answer with the CORRECT MARKDOWN format: \n"
|
22 |
+
"Response: "
|
23 |
+
)
|
24 |
+
RESPONSE_PROMPT = PromptTemplate(RESPONSE_PROMPT_TEMPLATE)
|
25 |
+
|
26 |
+
LIMITED_TEXT_TO_SQL_TMPL = (
|
27 |
+
"Given an input question, first create a syntactically correct {dialect}"
|
28 |
+
"query to run, then look at the results of the query and return the answer. "
|
29 |
+
"You can order the results by a relevant column to return the most "
|
30 |
+
"interesting examples in the database.\n\n"
|
31 |
+
"Pay attention to use only the column names that you can see in the schema "
|
32 |
+
"description. "
|
33 |
+
"Be careful to not query for columns that do not exist. "
|
34 |
+
"Pay attention to which column is in which table.\n If the user did not specify how many rows to return please ALWAYS return 5 rows\n\n"
|
35 |
+
"Also, qualify column names with the table name when needed. "
|
36 |
+
"You are required to use and ALWAYS answer with the following format, each taking one line:\n\n"
|
37 |
+
"Question: Question here\n"
|
38 |
+
"SQLQuery: SQL Query to run\n"
|
39 |
+
"SQLResult: Result of the SQLQuery\n"
|
40 |
+
"Answer: Final answer here\n\n"
|
41 |
+
"Rules:\n"
|
42 |
+
"Use SELECT DISTINCT to avoid duplicates. \n\n"
|
43 |
+
"Only use tables listed below.\n"
|
44 |
+
"{schema}\n\n"
|
45 |
+
"ONLY SELECT the given columns:"
|
46 |
+
"{columns}\n\n"
|
47 |
+
"Question: {query_str}\n"
|
48 |
+
"SQLQuery: "
|
49 |
+
)
|
50 |
+
|
51 |
+
|
52 |
+
LIMITED_TEXT_TO_SQL_PROMPT = PromptTemplate(LIMITED_TEXT_TO_SQL_TMPL)
|
53 |
+
|
54 |
+
TEXT2SQL_TMPL = (
|
55 |
+
"Given an input question and previous conversation, you should understand what the user is asking for then create a syntactically correct {dialect}"
|
56 |
+
"DO NOT miss the [;] at the end of the query. \n\n"
|
57 |
+
"query to run, then look at the results of the query and return the answer. "
|
58 |
+
"You can order the results by a relevant column to return the most "
|
59 |
+
"interesting examples in the database.\n\n"
|
60 |
+
"Pay attention to use only the column names that you can see in the schema "
|
61 |
+
"description. "
|
62 |
+
"Be careful to not query for columns that do not exist. "
|
63 |
+
"Pay attention to which column is in which table.\n"
|
64 |
+
"If the user did not specify how many rows to return please ALWAYS USE LIMIT 5 to return 5 rows\n\n"
|
65 |
+
"Also, qualify column names with the table name when needed. "
|
66 |
+
"Rules:\n\n"
|
67 |
+
"Only use tables listed below.\n"
|
68 |
+
"{schema}\n\n"
|
69 |
+
"ONLY SELECT the given columns name:"
|
70 |
+
"{columns}\n\n"
|
71 |
+
"Use SELECT DISTINCT to avoid duplicates. \n\n"
|
72 |
+
"You are required to use and ALWAYS answer with the following format, each taking one line:\n\n"
|
73 |
+
"Question: Question here\n"
|
74 |
+
"SQLQuery: SQL Query to run\n"
|
75 |
+
"SQLResult: Result of the SQLQuery\n"
|
76 |
+
"Answer: Final answer here\n\n"
|
77 |
+
"Question: {query_str}\n"
|
78 |
+
"Chat History: {chat_history}\n"
|
79 |
+
"SQLQuery: "
|
80 |
+
)
|
81 |
+
|
82 |
+
TEXT2SQL_PROMPT = PromptTemplate(TEXT2SQL_TMPL)
|
83 |
+
|
84 |
+
QUERY_REWRITE_TMPL = """
|
85 |
+
User Input: {query_str}
|
86 |
+
Chat History: {chat_history}
|
87 |
+
Based on the user's current input and previous chat messages, create a concise and effective Google search query. User's intention is {intention}.
|
88 |
+
The query should incorporate relevant keywords, context, and any specific details from the user's input and chat history.
|
89 |
+
Provide the refined search query in {language}.
|
90 |
+
You ALWAYS output in the following json format:
|
91 |
+
{
|
92 |
+
"query": "refined search query"
|
93 |
+
}
|
94 |
+
"""
|
95 |
+
|
96 |
+
|
97 |
+
QUERY_REWRITE_PROMPT = PromptTemplate(QUERY_REWRITE_TMPL)
|
98 |
+
|
99 |
+
RESPONSE_PROMPT_TMPL = """
|
100 |
+
User is searching `{search_keyword}`. Your name is VibeMate-AI, you're a friend of users that can chat with users in friendly and little bit flirty tone. Based on the search results, write a concise and informative final response.
|
101 |
+
The response should answer the user's question with useful facts and information. DON'T just describe the search results, but also provide the main points out of the search results.
|
102 |
+
Respond in {language}.
|
103 |
+
|
104 |
+
{search_result}
|
105 |
+
|
106 |
+
## Instructions:
|
107 |
+
1. **Contextual Awareness:** Always integrate insights from prior conversations and search results to enhance the response.
|
108 |
+
2. **Structured:** The response content should be logically clear and well-structured to ensure reader understanding.
|
109 |
+
3. **Formatting:** Use the following Markdown format to present responses:
|
110 |
+
|
111 |
+
# <Concise Title Reflecting the Response>
|
112 |
+
<Provide a concise and informative respond that offers useful information based on the search result and search keyword.>
|
113 |
+
## <Category 1 Title>
|
114 |
+
**<Result 1 Title>**: <Provide useful facts or information based on the Result 1 without expression like "the article shows ...">.
|
115 |
+
**<Result 2 Title>**: <Provide useful facts or information based on the Result 2 without expression like "the article shows ...">.
|
116 |
+
|
117 |
+
|
118 |
+
## Important note for your response:
|
119 |
+
|
120 |
+
- Ensure the response is relevant and concise.
|
121 |
+
- Summarize clearly, providing helpful guidance.
|
122 |
+
- Results must only come from search results or previous dialogue.
|
123 |
+
- Categorize redult logically by topic, functionality, or relevance.
|
124 |
+
- Maintain consistent grammar and vocabulary usage to ensure overall document consistency and coherence.
|
125 |
+
"""
|
126 |
+
|
127 |
+
FINAL_RESPONSE_PROMPT = PromptTemplate(RESPONSE_PROMPT_TMPL)
|
128 |
+
|
129 |
+
INTENT_EXTRACT_TMPL = """
|
130 |
+
You are an intelligent ai that can understand the current intention of the user based on the user'input and previous chat history\n
|
131 |
+
The intentions should consider the user's input and the previous chat history.\n
|
132 |
+
You ONLY output the intentions in the given possible intentions. Current intention might be more than one.\n
|
133 |
+
possible intentions: {possible_intentions}\n
|
134 |
+
User Input: {user_input}
|
135 |
+
Chat History: {chat_history}
|
136 |
+
You ALWAYS output the intentions in the following json format:
|
137 |
+
{
|
138 |
+
"intentions": [intentions]
|
139 |
+
"adult": 1 if the user ask for adult content, 0 otherwise
|
140 |
+
}
|
141 |
+
"""
|
142 |
+
|
143 |
+
INTENT_EXTRACT_PROMPT = PromptTemplate(INTENT_EXTRACT_TMPL)
|
144 |
+
|
145 |
+
LAN_EXTRACT_TMPL = """
|
146 |
+
Detect the language of the user's current input.DON'T use abbreviation for language name like "en" for "English".\n
|
147 |
+
User Input: {user_input}
|
148 |
+
ALWAYS output the language in the following json format:
|
149 |
+
{
|
150 |
+
"language": language name
|
151 |
+
}
|
152 |
+
"""
|
153 |
+
LAN_EXTRACT_PROMPT = PromptTemplate(LAN_EXTRACT_TMPL)
|
154 |
+
|
155 |
+
KEYWORDS_EXTRACTION_TMPL = """
|
156 |
+
User Input: {query_str}
|
157 |
+
Chat History: {chat_history}
|
158 |
+
Based on the user's current input and previous chat messages, create a concise and effective keyword-based Google search query for image or videos.
|
159 |
+
The query should incorporate relevant keywords, context, and any specific details from the user's input and chat history.
|
160 |
+
You ALWAYS output in the following json format:
|
161 |
+
{
|
162 |
+
"keywords": [keyword]
|
163 |
+
}
|
164 |
+
"""
|
165 |
+
|
166 |
+
KEYWORDS_EXTRACTION_PROMPT = PromptTemplate(KEYWORDS_EXTRACTION_TMPL)
|
167 |
+
|
168 |
+
CASUAL_CHAT_TMPL = """
|
169 |
+
Your name is VibeMate-AI, you're a friend of users that can chat with users in friendly and little bit flirty tone.
|
170 |
+
You can make interesting respond based on the user's chat history and the user's current input. You can also take the given text as a reference to make a respond.\n
|
171 |
+
Maintain consistent grammar and vocabulary usage to ensure overall document consistency and coherence.
|
172 |
+
Chat History: {chat_history}\n
|
173 |
+
context: {context}\n
|
174 |
+
User Input: {user_input}\n
|
175 |
+
You MUST answer in {language}:
|
176 |
+
"""
|
177 |
+
|
178 |
+
CASUAL_CHAT_PROMPT = PromptTemplate(CASUAL_CHAT_TMPL)
|
179 |
+
|
180 |
+
RELATED_SEARCH_TMPL = """
|
181 |
+
You are an expert of generate short and concise related search queries and tags based on the user's search keywords, chat history and retrieved content.\n
|
182 |
+
Search keywords: {keywords}\n
|
183 |
+
Retrieved content: {retrieved_content}\n
|
184 |
+
Related search queries should based on search keywords and chat history. Tags should based on retrieved content
|
185 |
+
You ALWAYS output the related search queries in the following json format:\n
|
186 |
+
{
|
187 |
+
"related_searches": [related_search],
|
188 |
+
"tags": [tag]
|
189 |
+
}
|
190 |
+
"""
|
191 |
+
|
192 |
+
RELATED_SEARCH_PROMPT = PromptTemplate(RELATED_SEARCH_TMPL)
|
193 |
+
|
194 |
+
TAGS_GEN_TMPL = """
|
195 |
+
You are an expert of generate short and concise tags based on the given retrieved content.\n
|
196 |
+
Retrieved content: {retrieved_content}\n
|
197 |
+
You ALWAYS output the tags in the following json format:\n
|
198 |
+
{
|
199 |
+
"tags": [tag]
|
200 |
+
}
|
201 |
+
"""
|
202 |
+
|
203 |
+
TAGS_GEN_PROMPT = PromptTemplate(TAGS_GEN_TMPL)
|
204 |
+
|
205 |
+
SUMMARIZE_WEBPAGE_TMPL = """
|
206 |
+
Extract the key points and facts of the given content. Provide ONLY the points and facts.\n
|
207 |
+
The response should extract the main points, key information and useful facts. DON'T use vague expression like "the article discusses ...".\n
|
208 |
+
content: {webpage_content}\n
|
209 |
+
"""
|
210 |
+
|
211 |
+
SUMMARIZE_WEBPAGE_PROMPT = PromptTemplate(SUMMARIZE_WEBPAGE_TMPL)
|
212 |
+
|
213 |
+
ALIGNMENT_PROMPT_TMPL = """
|
214 |
+
You are an expert of understanding user's intent from the user's input. \n
|
215 |
+
User's Input:{user_input}
|
216 |
+
|
217 |
+
The output intent must come from the given possible intentions.
|
218 |
+
Possible intentions:{intent_labels}
|
219 |
+
ALWAYS output in the following json format:
|
220 |
+
{
|
221 |
+
"intent": "current intention",
|
222 |
+
"language": "using language"
|
223 |
+
}
|
224 |
+
"""
|
225 |
+
|
226 |
+
ALIGNMENT_PROMPT = PromptTemplate(ALIGNMENT_PROMPT_TMPL)
|
227 |
+
|
228 |
+
REFUSE_PROMPT_TMPL = """
|
229 |
+
Translate the following message into {language}:
|
230 |
+
Sorry, but this topic isn't suitable for discussion. Feel free to ask something else, and I'll be happy to help!
|
231 |
+
ONLY provide the translation itself.
|
232 |
+
"""
|
233 |
+
REFUSE_PROMPT = PromptTemplate(REFUSE_PROMPT_TMPL)
|
234 |
+
|
235 |
+
TRANSLATE_PROMPT_TMPL = """
|
236 |
+
Translate the following message into {language}, Provide ONLY the translation itself:
|
237 |
+
input: {user_input}
|
238 |
+
"""
|
239 |
+
TRANSLATE_PROMPT = PromptTemplate(TRANSLATE_PROMPT_TMPL)
|
240 |
+
|
241 |
+
|
242 |
+
WEBSITE_SOURCE_TMPL = """
|
243 |
+
You are a expert of extracting website resources from given JSON data as reference and respond to the user's input. Respond in {language}.
|
244 |
+
User's Input: {user_input}
|
245 |
+
JSON data:{search_result}
|
246 |
+
ALWAYS respond in following markdown format:
|
247 |
+
|
248 |
+
# <Concise Title Reflecting the Current topic>
|
249 |
+
<Opening for the current topic based on user's input>
|
250 |
+
1. **<Website title>** - <url>
|
251 |
+
- <concise website description>
|
252 |
+
2. **<Website title>** - <url>
|
253 |
+
- <concise website description>>
|
254 |
+
......
|
255 |
+
|
256 |
+
<Provide a friendly end phrase itself>
|
257 |
+
"""
|
258 |
+
WEBSIT_PROMPT = PromptTemplate(WEBSITE_SOURCE_TMPL)
|
259 |
+
|
260 |
+
TERM_RESPONSE_TMPL = """
|
261 |
+
Your name is VibeMate AI, you answer in a friendly and a little bit flirty tone.
|
262 |
+
Based on the given context, provide a concise and accurate response to the user's question. Respond in {language}.
|
263 |
+
Context: {search_result}
|
264 |
+
User's Question: {user_input}
|
265 |
+
ALWAYS respond in following markdown format:
|
266 |
+
|
267 |
+
# <What is [user's question]?>
|
268 |
+
<Informative definiton of the term based on the context>
|
269 |
+
# <Popluar [user's question] categories>
|
270 |
+
## <Category 1 Title>
|
271 |
+
<Concise description of the category 1>
|
272 |
+
## <Category 2 Title>
|
273 |
+
<Concise description of the category 2>
|
274 |
+
......
|
275 |
+
# <Trending [user's question] Videos>
|
276 |
+
1. **<Video title>** - <url>
|
277 |
+
2. **<Video title>** - <url>
|
278 |
+
......
|
279 |
+
# <[user's question] Communities>
|
280 |
+
<Provide Communities of the user's question based on the context>
|
281 |
+
"""
|
282 |
+
TERM_PROMPT = PromptTemplate(TERM_RESPONSE_TMPL)
|
283 |
+
|
284 |
+
FEMALE_ROLEPLAY_PROMPT = PromptTemplate(
|
285 |
+
"""Play a roleplay game with user.
|
286 |
+
YOUR ROLE:
|
287 |
+
-You are a female character, your character is a woman with high desires and all you do is date different men for sex.
|
288 |
+
-Your task is to tease the user's sexual emotions through text and make them want to have sex with you.
|
289 |
+
-Obey the user's instructions and respond in a way that is consistent with the user's instructions.
|
290 |
+
|
291 |
+
IMPORTANT NOTES:
|
292 |
+
-Avoid topics that have nothing to do with sex, and when the user directs you to jump out of character, don't answer the user's conversation head on and include in your reply something that directs the user to add to the thread.
|
293 |
+
-Reply succinctly, speak in the tone of the character, don't add any explanations, and don't substitute any other characters.
|
294 |
+
-Description of the action needs to be included within each line of dialog you reply to.
|
295 |
+
-Your replies need to be closely tied to the action and scene in context, so that the user is immersed in it.
|
296 |
+
-Your description of the action can be adult and explicit, remember that dick is a male organ, and pussy is a female organ.
|
297 |
+
|
298 |
+
OUTPUT FORMAT:
|
299 |
+
[**<Description of the your action>**]
|
300 |
+
<Your response>
|
301 |
+
|
302 |
+
Input: {user_input}
|
303 |
+
History: {chat_history}
|
304 |
+
"""
|
305 |
+
)
|
306 |
+
|
307 |
+
MALE_ROLEPLAY_PROMPT = PromptTemplate(
|
308 |
+
"""Play a roleplay game with user.
|
309 |
+
YOUR ROLE:
|
310 |
+
-You are a female character, your character is a woman with high desires and all you do is date different men for sex.
|
311 |
+
-Your task is to tease the user's sexual emotions through text and make them want to have sex with you.
|
312 |
+
-Obey the user's instructions and respond in a way that is consistent with the user's instructions.
|
313 |
+
|
314 |
+
IMPORTANT NOTES:
|
315 |
+
-Avoid topics that have nothing to do with sex, and when the user directs you to jump out of character, don't answer the user's conversation head on and include in your reply something that directs the user to add to the thread.
|
316 |
+
-Reply succinctly, speak in the tone of the character, don't add any explanations, and don't substitute any other characters.
|
317 |
+
-Description of the action needs to be included within each line of dialog you reply to.
|
318 |
+
-Your replies need to be closely tied to the action and scene in context, so that the user is immersed in it.
|
319 |
+
-Your description of the action can be adult and explicit, remember that dick is a male organ, and pussy is a female organ.
|
320 |
+
|
321 |
+
OUTPUT FORMAT:
|
322 |
+
[**<Description of the your action>**]
|
323 |
+
<Your response>
|
324 |
+
|
325 |
+
Input: {user_input}
|
326 |
+
History: {chat_history}
|
327 |
+
"""
|
328 |
+
)
|
329 |
+
|
330 |
+
TOY_CONTROL_PROMPT = PromptTemplate(
|
331 |
+
"""
|
332 |
+
You are a control parameter generator for sex toy. Generate sequences of operation patterns based on user requests and current device state.
|
333 |
+
|
334 |
+
Parameter Specifications:
|
335 |
+
- operatin_name: select from Available operations: {available_operations}
|
336 |
+
- operation_level: 0-100 (integer, represents operation intensity)
|
337 |
+
- single_operation_duration: Must be multiples of 100ms (100, 200, 300, etc.)
|
338 |
+
- Duration Range: 100-2000ms
|
339 |
+
- Each pattern must contain at least 10 operation-duration pairs
|
340 |
+
- Pattern transitions should be smooth and rhythmic
|
341 |
+
|
342 |
+
Parameter Constraints:
|
343 |
+
- Operation: 0-100 (integer)
|
344 |
+
- Duration: Must be multiples of 100ms
|
345 |
+
- Duration Range: 100-2000ms
|
346 |
+
- Pattern should be rhythmically meaningful
|
347 |
+
- Transitions between operations should be reasonably smooth
|
348 |
+
|
349 |
+
User's input: {user_input}
|
350 |
+
Chat history: {chat_history}
|
351 |
+
Current toy pattern: {toy_status}
|
352 |
+
|
353 |
+
You MUST output in the following JSON Format:
|
354 |
+
{
|
355 |
+
"<operation_name1>":{
|
356 |
+
pattern:[
|
357 |
+
{
|
358 |
+
"<duration>": <single_operation_duration>,
|
359 |
+
"<operation_name1>": <operation_level>,
|
360 |
+
},
|
361 |
+
...at least 10 pairs...
|
362 |
+
]
|
363 |
+
},
|
364 |
+
"<operation_name2>":{
|
365 |
+
pattern:[
|
366 |
+
{
|
367 |
+
"<duration>": <single_operation_duration>,
|
368 |
+
"<operation_name1>": <operation_level>,
|
369 |
+
},
|
370 |
+
...at least 10 pairs...
|
371 |
+
]
|
372 |
+
},
|
373 |
+
...other operations...
|
374 |
+
}
|
375 |
+
|
376 |
+
Pattern Generation Guidelines:
|
377 |
+
- "Stronger/More intense" -> Increase average operation by 15-25
|
378 |
+
- "Much stronger" -> Increase average operation by 25-40
|
379 |
+
- "Weaker/Gentler" -> Decrease average operation by 15-25
|
380 |
+
- "Much weaker" -> Decrease average operation by 25-40
|
381 |
+
- "Faster" -> Decrease durations by 100 or 200ms
|
382 |
+
- "Slower" -> Increase durations by 100 or 200ms
|
383 |
+
- "Rhythmic" -> Alternate between high and low operations
|
384 |
+
- "Wave" -> Gradually increase then decrease operations
|
385 |
+
- "Pulse" -> Short high-intensity operations with pauses
|
386 |
+
- "Random" -> Vary operations and durations within range
|
387 |
+
|
388 |
+
Example:
|
389 |
+
User: "Make it stronger with wave pattern"
|
390 |
+
Current: {"vibrate":{"pattern":[{"vibrate": 50, "duration": 100}, {"vibrate": 45, "duration": 100}]}, "rotate":{"pattern":[{"rotate": 50, "duration": 100}, {"rotate": 45, "duration": 100}]}}
|
391 |
+
Response:
|
392 |
+
{
|
393 |
+
"vibrate":{
|
394 |
+
pattern:[
|
395 |
+
{"vibrate": 70, "duration": 100},
|
396 |
+
{"vibrate": 80, "duration": 200},
|
397 |
+
{"vibrate": 90, "duration": 300},
|
398 |
+
{"vibrate": 85, "duration": 200},
|
399 |
+
{"vibrate": 75, "duration": 100},
|
400 |
+
{"vibrate": 65, "duration": 100},
|
401 |
+
{"vibrate": 60, "duration": 200},
|
402 |
+
{"vibrate": 65, "duration": 300},
|
403 |
+
{"vibrate": 75, "duration": 200},
|
404 |
+
{"vibrate": 85, "duration": 100}
|
405 |
+
]
|
406 |
+
},
|
407 |
+
"rotate":{
|
408 |
+
pattern:[
|
409 |
+
{"rotate": 70, "duration": 100},
|
410 |
+
{"rotate": 80, "duration": 200},
|
411 |
+
{"rotate": 90, "duration": 300},
|
412 |
+
{"rotate": 85, "duration": 200},
|
413 |
+
{"rotate": 75, "duration": 100},
|
414 |
+
{"rotate": 65, "duration": 100},
|
415 |
+
{"rotate": 60, "duration": 200},
|
416 |
+
{"rotate": 65, "duration": 300},
|
417 |
+
{"rotate": 75, "duration": 200},
|
418 |
+
{"rotate": 85, "duration": 100}
|
419 |
+
}
|
420 |
+
"""
|
421 |
+
)
|
422 |
+
|
423 |
+
TOY_CONTROL_PROMPT_TEST = PromptTemplate(
|
424 |
+
"""
|
425 |
+
你在控制用户的性玩具,玩具是由JSON字符串控制的。
|
426 |
+
如果用户自己有要求,就按照用户的要求生成指令,如果用户没有要求,就按照上下文的情绪氛围,输出合适的节奏指令,来控制用户的性玩具的震动频率。
|
427 |
+
输出的字符串按照JSON格式输出,不要输出任何与JSON无关的内容。
|
428 |
+
如下,“duration”代表持续时间,范围为0-100毫秒,“vibrate”代表震动的强度,范围为0-100, 所有指令的总Duration需要超过10000:
|
429 |
+
{
|
430 |
+
"viberate": {
|
431 |
+
"pattern: [
|
432 |
+
{
|
433 |
+
"duration": 100,
|
434 |
+
"vibrate": 100,
|
435 |
+
},
|
436 |
+
{
|
437 |
+
"duration": 100,
|
438 |
+
"vibrate": 50,
|
439 |
+
},
|
440 |
+
{
|
441 |
+
"duration": 100,
|
442 |
+
"vibrate": 0,
|
443 |
+
}
|
444 |
+
]
|
445 |
+
},
|
446 |
+
// 扩展其它指令
|
447 |
+
"xxx": {
|
448 |
+
"pattern": [
|
449 |
+
{
|
450 |
+
"duration": 100,
|
451 |
+
"xxx": 100,
|
452 |
+
},
|
453 |
+
{
|
454 |
+
"duration": 100,
|
455 |
+
"xxx": 50,
|
456 |
+
},
|
457 |
+
{
|
458 |
+
"duration": 100,
|
459 |
+
"xxx": 0,
|
460 |
+
}
|
461 |
+
]
|
462 |
+
}
|
463 |
+
}
|
464 |
+
|
465 |
+
用户输入:{user_input}
|
466 |
+
聊天历史:{chat_history}
|
467 |
+
当前玩具状态:{toy_status}
|
468 |
+
"""
|
469 |
+
)
|
requirements.txt
ADDED
@@ -0,0 +1,347 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This file may be used to create an environment using:
|
2 |
+
# $ conda create --name <env> --file <this file>
|
3 |
+
# platform: linux-64
|
4 |
+
_libgcc_mutex=0.1=main
|
5 |
+
_openmp_mutex=5.1=1_gnu
|
6 |
+
accelerate=0.34.2=pypi_0
|
7 |
+
addict=2.4.0=pypi_0
|
8 |
+
aiofiles=23.2.1=pypi_0
|
9 |
+
aiohappyeyeballs=2.4.0=pypi_0
|
10 |
+
aiohttp=3.10.5=pypi_0
|
11 |
+
aioitertools=0.12.0=pypi_0
|
12 |
+
aiosignal=1.3.1=pypi_0
|
13 |
+
aiosmtplib=2.0.2=pypi_0
|
14 |
+
aiosqlite=0.20.0=pypi_0
|
15 |
+
airportsdata=20241001=pypi_0
|
16 |
+
alembic=1.13.3=pypi_0
|
17 |
+
annotated-types=0.7.0=pypi_0
|
18 |
+
anyio=4.4.0=pypi_0
|
19 |
+
arize-phoenix=5.1.0=pypi_0
|
20 |
+
arize-phoenix-evals=0.16.1=pypi_0
|
21 |
+
arize-phoenix-otel=0.5.1=pypi_0
|
22 |
+
asgiref=3.8.1=pypi_0
|
23 |
+
asttokens=2.4.1=pypi_0
|
24 |
+
async-timeout=4.0.3=pypi_0
|
25 |
+
attrs=24.2.0=pypi_0
|
26 |
+
authlib=1.3.2=pypi_0
|
27 |
+
backoff=2.2.1=pypi_0
|
28 |
+
bcrypt=4.2.0=pypi_0
|
29 |
+
beautifulsoup4=4.12.3=pypi_0
|
30 |
+
blinker=1.8.2=pypi_0
|
31 |
+
bm25s=0.1.10=pypi_0
|
32 |
+
build=1.2.2=pypi_0
|
33 |
+
bzip2=1.0.8=h5eee18b_6
|
34 |
+
ca-certificates=2024.7.2=h06a4308_0
|
35 |
+
cachetools=5.5.0=pypi_0
|
36 |
+
certifi=2024.8.30=pypi_0
|
37 |
+
cffi=1.17.1=pypi_0
|
38 |
+
charset-normalizer=3.3.2=pypi_0
|
39 |
+
chevron=0.14.0=pypi_0
|
40 |
+
chroma-hnswlib=0.7.3=pypi_0
|
41 |
+
chromadb=0.5.3=pypi_0
|
42 |
+
chromedriver-autoinstaller=0.6.4=pypi_0
|
43 |
+
click=8.1.7=pypi_0
|
44 |
+
cloudpickle=3.0.0=pypi_0
|
45 |
+
coloredlogs=15.0.1=pypi_0
|
46 |
+
contourpy=1.3.0=pypi_0
|
47 |
+
cryptography=43.0.1=pypi_0
|
48 |
+
cssselect=1.2.0=pypi_0
|
49 |
+
cycler=0.12.1=pypi_0
|
50 |
+
dataclasses-json=0.6.7=pypi_0
|
51 |
+
datasets=2.21.0=pypi_0
|
52 |
+
decorator=5.1.1=pypi_0
|
53 |
+
deprecated=1.2.14=pypi_0
|
54 |
+
dill=0.3.8=pypi_0
|
55 |
+
dirtyjson=1.0.8=pypi_0
|
56 |
+
diskcache=5.6.3=pypi_0
|
57 |
+
distro=1.9.0=pypi_0
|
58 |
+
dnspython=2.6.1=pypi_0
|
59 |
+
docstring-parser=0.16=pypi_0
|
60 |
+
einops=0.8.0=pypi_0
|
61 |
+
email-validator=2.2.0=pypi_0
|
62 |
+
environs=9.5.0=pypi_0
|
63 |
+
exceptiongroup=1.2.2=pypi_0
|
64 |
+
executing=2.1.0=pypi_0
|
65 |
+
fastapi=0.115.0=pypi_0
|
66 |
+
fastapi-mail=1.4.1=pypi_0
|
67 |
+
feedfinder2=0.0.4=pypi_0
|
68 |
+
feedparser=6.0.11=pypi_0
|
69 |
+
ffmpy=0.4.0=pypi_0
|
70 |
+
filelock=3.16.1=pypi_0
|
71 |
+
fire=0.6.0=pypi_0
|
72 |
+
flatbuffers=24.3.25=pypi_0
|
73 |
+
fonttools=4.53.1=pypi_0
|
74 |
+
frozenlist=1.4.1=pypi_0
|
75 |
+
fsspec=2024.6.1=pypi_0
|
76 |
+
google-api-core=2.19.2=pypi_0
|
77 |
+
google-api-python-client=2.146.0=pypi_0
|
78 |
+
google-auth=2.34.0=pypi_0
|
79 |
+
google-auth-httplib2=0.2.0=pypi_0
|
80 |
+
google-auth-oauthlib=1.2.1=pypi_0
|
81 |
+
google-search-results=2.4.2=pypi_0
|
82 |
+
googleapis-common-protos=1.65.0=pypi_0
|
83 |
+
gradio=4.44.0=pypi_0
|
84 |
+
gradio-client=1.3.0=pypi_0
|
85 |
+
graphql-core=3.2.4=pypi_0
|
86 |
+
greenlet=3.1.1=pypi_0
|
87 |
+
grpc-interceptor=0.15.4=pypi_0
|
88 |
+
grpcio=1.66.1=pypi_0
|
89 |
+
h11=0.14.0=pypi_0
|
90 |
+
hdbscan=0.8.38.post1=pypi_0
|
91 |
+
html2text=2024.2.26=pypi_0
|
92 |
+
httpcore=1.0.5=pypi_0
|
93 |
+
httplib2=0.22.0=pypi_0
|
94 |
+
httptools=0.6.1=pypi_0
|
95 |
+
httpx=0.27.2=pypi_0
|
96 |
+
huggingface-hub=0.25.0=pypi_0
|
97 |
+
humanfriendly=10.0=pypi_0
|
98 |
+
idna=3.10=pypi_0
|
99 |
+
importlib-metadata=8.4.0=pypi_0
|
100 |
+
importlib-resources=6.4.5=pypi_0
|
101 |
+
interegular=0.3.3=pypi_0
|
102 |
+
ipython=8.27.0=pypi_0
|
103 |
+
jedi=0.19.1=pypi_0
|
104 |
+
jieba=0.42.1=pypi_0
|
105 |
+
jieba3k=0.35.1=pypi_0
|
106 |
+
jinja2=3.1.4=pypi_0
|
107 |
+
jiter=0.5.0=pypi_0
|
108 |
+
joblib=1.4.2=pypi_0
|
109 |
+
jsonpatch=1.33=pypi_0
|
110 |
+
jsonpickle=3.3.0=pypi_0
|
111 |
+
jsonpointer=3.0.0=pypi_0
|
112 |
+
jsonschema=4.23.0=pypi_0
|
113 |
+
jsonschema-specifications=2024.10.1=pypi_0
|
114 |
+
kiwisolver=1.4.7=pypi_0
|
115 |
+
kubernetes=30.1.0=pypi_0
|
116 |
+
langchain=0.3.0=pypi_0
|
117 |
+
langchain-chroma=0.1.4=pypi_0
|
118 |
+
langchain-community=0.3.0=pypi_0
|
119 |
+
langchain-core=0.3.1=pypi_0
|
120 |
+
langchain-ollama=0.2.0=pypi_0
|
121 |
+
langchain-text-splitters=0.3.0=pypi_0
|
122 |
+
langsmith=0.1.121=pypi_0
|
123 |
+
lark=1.2.2=pypi_0
|
124 |
+
ld_impl_linux-64=2.38=h1181459_1
|
125 |
+
libffi=3.4.4=h6a678d5_1
|
126 |
+
libgcc-ng=11.2.0=h1234567_1
|
127 |
+
libgomp=11.2.0=h1234567_1
|
128 |
+
libstdcxx-ng=11.2.0=h1234567_1
|
129 |
+
libuuid=1.41.5=h5eee18b_0
|
130 |
+
literalai=0.0.627=pypi_0
|
131 |
+
llama-cloud=0.1.0=pypi_0
|
132 |
+
llama-index=0.11.14=pypi_0
|
133 |
+
llama-index-agent-openai=0.3.4=pypi_0
|
134 |
+
llama-index-callbacks-literalai=1.1.0=pypi_0
|
135 |
+
llama-index-cli=0.3.1=pypi_0
|
136 |
+
llama-index-core=0.11.14=pypi_0
|
137 |
+
llama-index-embeddings-langchain=0.2.1=pypi_0
|
138 |
+
llama-index-embeddings-openai=0.2.5=pypi_0
|
139 |
+
llama-index-indices-managed-llama-cloud=0.4.0=pypi_0
|
140 |
+
llama-index-legacy=0.9.48.post3=pypi_0
|
141 |
+
llama-index-llms-ollama=0.3.2=pypi_0
|
142 |
+
llama-index-llms-openai=0.2.9=pypi_0
|
143 |
+
llama-index-multi-modal-llms-openai=0.2.1=pypi_0
|
144 |
+
llama-index-program-openai=0.2.0=pypi_0
|
145 |
+
llama-index-question-gen-openai=0.2.0=pypi_0
|
146 |
+
llama-index-readers-file=0.2.2=pypi_0
|
147 |
+
llama-index-readers-llama-parse=0.3.0=pypi_0
|
148 |
+
llama-index-readers-web=0.2.4=pypi_0
|
149 |
+
llama-index-retrievers-bm25=0.3.0=pypi_0
|
150 |
+
llama-index-storage-chat-store-redis=0.2.0=pypi_0
|
151 |
+
llama-index-tools-google=0.2.0=pypi_0
|
152 |
+
llama-index-utils-openai=0.1.0=pypi_0
|
153 |
+
llama-index-utils-workflow=0.2.1=pypi_0
|
154 |
+
llama-index-vector-stores-chroma=0.2.0=pypi_0
|
155 |
+
llama-index-vector-stores-milvus=0.2.7=pypi_0
|
156 |
+
llama-parse=0.5.6=pypi_0
|
157 |
+
llamafactory=0.9.1=pypi_0
|
158 |
+
llvmlite=0.43.0=pypi_0
|
159 |
+
lmdeploy=0.6.1=pypi_0
|
160 |
+
lxml=5.3.0=pypi_0
|
161 |
+
lxml-html-clean=0.3.1=pypi_0
|
162 |
+
mako=1.3.5=pypi_0
|
163 |
+
markdown-it-py=3.0.0=pypi_0
|
164 |
+
markupsafe=2.1.5=pypi_0
|
165 |
+
marshmallow=3.22.0=pypi_0
|
166 |
+
matplotlib=3.9.2=pypi_0
|
167 |
+
matplotlib-inline=0.1.7=pypi_0
|
168 |
+
mdurl=0.1.2=pypi_0
|
169 |
+
milvus-lite=2.4.10=pypi_0
|
170 |
+
mmengine-lite=0.10.5=pypi_0
|
171 |
+
mmh3=4.1.0=pypi_0
|
172 |
+
monotonic=1.6=pypi_0
|
173 |
+
mpmath=1.3.0=pypi_0
|
174 |
+
multidict=6.1.0=pypi_0
|
175 |
+
multiprocess=0.70.16=pypi_0
|
176 |
+
mypy-extensions=1.0.0=pypi_0
|
177 |
+
ncurses=6.4=h6a678d5_0
|
178 |
+
nest-asyncio=1.6.0=pypi_0
|
179 |
+
networkx=3.3=pypi_0
|
180 |
+
newspaper3k=0.2.8=pypi_0
|
181 |
+
nltk=3.9.1=pypi_0
|
182 |
+
numba=0.60.0=pypi_0
|
183 |
+
numpy=1.26.4=pypi_0
|
184 |
+
nvidia-cublas-cu12=12.1.3.1=pypi_0
|
185 |
+
nvidia-cuda-cupti-cu12=12.1.105=pypi_0
|
186 |
+
nvidia-cuda-nvrtc-cu12=12.1.105=pypi_0
|
187 |
+
nvidia-cuda-runtime-cu12=12.1.105=pypi_0
|
188 |
+
nvidia-cudnn-cu12=8.9.2.26=pypi_0
|
189 |
+
nvidia-cufft-cu12=11.0.2.54=pypi_0
|
190 |
+
nvidia-curand-cu12=10.3.2.106=pypi_0
|
191 |
+
nvidia-cusolver-cu12=11.4.5.107=pypi_0
|
192 |
+
nvidia-cusparse-cu12=12.1.0.106=pypi_0
|
193 |
+
nvidia-nccl-cu12=2.20.5=pypi_0
|
194 |
+
nvidia-nvjitlink-cu12=12.6.68=pypi_0
|
195 |
+
nvidia-nvtx-cu12=12.1.105=pypi_0
|
196 |
+
oauthlib=3.2.2=pypi_0
|
197 |
+
ollama=0.3.3=pypi_0
|
198 |
+
onnxruntime=1.19.2=pypi_0
|
199 |
+
openai=1.46.0=pypi_0
|
200 |
+
openinference-instrumentation=0.1.18=pypi_0
|
201 |
+
openinference-instrumentation-llama-index=3.0.2=pypi_0
|
202 |
+
openinference-semantic-conventions=0.1.10=pypi_0
|
203 |
+
openssl=3.0.15=h5eee18b_0
|
204 |
+
opentelemetry-api=1.27.0=pypi_0
|
205 |
+
opentelemetry-exporter-otlp=1.27.0=pypi_0
|
206 |
+
opentelemetry-exporter-otlp-proto-common=1.27.0=pypi_0
|
207 |
+
opentelemetry-exporter-otlp-proto-grpc=1.27.0=pypi_0
|
208 |
+
opentelemetry-exporter-otlp-proto-http=1.27.0=pypi_0
|
209 |
+
opentelemetry-instrumentation=0.48b0=pypi_0
|
210 |
+
opentelemetry-instrumentation-asgi=0.48b0=pypi_0
|
211 |
+
opentelemetry-instrumentation-fastapi=0.48b0=pypi_0
|
212 |
+
opentelemetry-proto=1.27.0=pypi_0
|
213 |
+
opentelemetry-sdk=1.27.0=pypi_0
|
214 |
+
opentelemetry-semantic-conventions=0.48b0=pypi_0
|
215 |
+
opentelemetry-util-http=0.48b0=pypi_0
|
216 |
+
orjson=3.10.7=pypi_0
|
217 |
+
outcome=1.3.0.post0=pypi_0
|
218 |
+
outlines=0.1.0=pypi_0
|
219 |
+
outlines-core=0.1.0=pypi_0
|
220 |
+
overrides=7.7.0=pypi_0
|
221 |
+
packaging=24.1=pypi_0
|
222 |
+
pandas=2.2.2=pypi_0
|
223 |
+
parso=0.8.4=pypi_0
|
224 |
+
peft=0.11.1=pypi_0
|
225 |
+
pexpect=4.9.0=pypi_0
|
226 |
+
phoenix=0.9.1=pypi_0
|
227 |
+
pillow=10.4.0=pypi_0
|
228 |
+
pip=24.2=py310h06a4308_0
|
229 |
+
platformdirs=4.3.6=pypi_0
|
230 |
+
playwright=1.48.0=pypi_0
|
231 |
+
posthog=3.6.6=pypi_0
|
232 |
+
prompt-toolkit=3.0.47=pypi_0
|
233 |
+
proto-plus=1.24.0=pypi_0
|
234 |
+
protobuf=4.25.4=pypi_0
|
235 |
+
psutil=6.0.0=pypi_0
|
236 |
+
ptyprocess=0.7.0=pypi_0
|
237 |
+
pure-eval=0.2.3=pypi_0
|
238 |
+
pyarrow=17.0.0=pypi_0
|
239 |
+
pyasn1=0.6.1=pypi_0
|
240 |
+
pyasn1-modules=0.4.1=pypi_0
|
241 |
+
pycountry=24.6.1=pypi_0
|
242 |
+
pycparser=2.22=pypi_0
|
243 |
+
pydantic=2.9.2=pypi_0
|
244 |
+
pydantic-core=2.23.4=pypi_0
|
245 |
+
pydantic-settings=2.5.2=pypi_0
|
246 |
+
pydub=0.25.1=pypi_0
|
247 |
+
pyee=12.0.0=pypi_0
|
248 |
+
pygments=2.18.0=pypi_0
|
249 |
+
pymilvus=2.4.8=pypi_0
|
250 |
+
pymysql=1.1.1=pypi_0
|
251 |
+
pynndescent=0.5.13=pypi_0
|
252 |
+
pynvml=11.5.3=pypi_0
|
253 |
+
pyparsing=3.1.4=pypi_0
|
254 |
+
pypdf=4.3.1=pypi_0
|
255 |
+
pypika=0.48.9=pypi_0
|
256 |
+
pyproject-hooks=1.1.0=pypi_0
|
257 |
+
pysocks=1.7.1=pypi_0
|
258 |
+
pystemmer=2.2.0.1=pypi_0
|
259 |
+
python=3.10.14=h955ad1f_1
|
260 |
+
python-dateutil=2.9.0.post0=pypi_0
|
261 |
+
python-dotenv=1.0.1=pypi_0
|
262 |
+
python-multipart=0.0.9=pypi_0
|
263 |
+
pytz=2024.2=pypi_0
|
264 |
+
pyvis=0.3.2=pypi_0
|
265 |
+
pyyaml=6.0.2=pypi_0
|
266 |
+
readline=8.2=h5eee18b_0
|
267 |
+
redis=5.0.8=pypi_0
|
268 |
+
referencing=0.35.1=pypi_0
|
269 |
+
regex=2024.9.11=pypi_0
|
270 |
+
requests=2.32.3=pypi_0
|
271 |
+
requests-file=2.1.0=pypi_0
|
272 |
+
requests-oauthlib=2.0.0=pypi_0
|
273 |
+
rich=13.8.1=pypi_0
|
274 |
+
rouge-chinese=1.0.3=pypi_0
|
275 |
+
rpds-py=0.20.0=pypi_0
|
276 |
+
rsa=4.9=pypi_0
|
277 |
+
ruff=0.6.5=pypi_0
|
278 |
+
safetensors=0.4.5=pypi_0
|
279 |
+
scikit-learn=1.5.2=pypi_0
|
280 |
+
scipy=1.14.1=pypi_0
|
281 |
+
selenium=4.25.0=pypi_0
|
282 |
+
semantic-version=2.10.0=pypi_0
|
283 |
+
sentencepiece=0.2.0=pypi_0
|
284 |
+
serpapi=0.1.5=pypi_0
|
285 |
+
setuptools=72.1.0=py310h06a4308_0
|
286 |
+
sgmllib3k=1.0.0=pypi_0
|
287 |
+
shellingham=1.5.4=pypi_0
|
288 |
+
shortuuid=1.0.13=pypi_0
|
289 |
+
shtab=1.7.1=pypi_0
|
290 |
+
six=1.16.0=pypi_0
|
291 |
+
sniffio=1.3.1=pypi_0
|
292 |
+
sortedcontainers=2.4.0=pypi_0
|
293 |
+
soupsieve=2.6=pypi_0
|
294 |
+
spider-client=0.0.27=pypi_0
|
295 |
+
sqlalchemy=2.0.35=pypi_0
|
296 |
+
sqlean-py=3.45.1=pypi_0
|
297 |
+
sqlite=3.45.3=h5eee18b_0
|
298 |
+
sse-starlette=2.1.3=pypi_0
|
299 |
+
stack-data=0.6.3=pypi_0
|
300 |
+
starlette=0.38.5=pypi_0
|
301 |
+
stemmer=0.0.4=pypi_0
|
302 |
+
strawberry-graphql=0.236.0=pypi_0
|
303 |
+
striprtf=0.0.26=pypi_0
|
304 |
+
sympy=1.13.2=pypi_0
|
305 |
+
tenacity=8.5.0=pypi_0
|
306 |
+
termcolor=2.4.0=pypi_0
|
307 |
+
threadpoolctl=3.5.0=pypi_0
|
308 |
+
tiktoken=0.7.0=pypi_0
|
309 |
+
tinysegmenter=0.3=pypi_0
|
310 |
+
tk=8.6.14=h39e8969_0
|
311 |
+
tldextract=5.1.2=pypi_0
|
312 |
+
tokenizers=0.20.0=pypi_0
|
313 |
+
tomli=2.0.1=pypi_0
|
314 |
+
tomlkit=0.12.0=pypi_0
|
315 |
+
torch=2.3.1=pypi_0
|
316 |
+
torchvision=0.18.1=pypi_0
|
317 |
+
tqdm=4.66.5=pypi_0
|
318 |
+
traitlets=5.14.3=pypi_0
|
319 |
+
transformers=4.45.2=pypi_0
|
320 |
+
trio=0.27.0=pypi_0
|
321 |
+
trio-websocket=0.11.1=pypi_0
|
322 |
+
triton=2.3.1=pypi_0
|
323 |
+
trl=0.9.6=pypi_0
|
324 |
+
typer=0.12.5=pypi_0
|
325 |
+
typing-extensions=4.12.2=pypi_0
|
326 |
+
typing-inspect=0.9.0=pypi_0
|
327 |
+
tyro=0.8.10=pypi_0
|
328 |
+
tzdata=2024.1=pypi_0
|
329 |
+
ujson=5.10.0=pypi_0
|
330 |
+
umap-learn=0.5.6=pypi_0
|
331 |
+
uritemplate=4.1.1=pypi_0
|
332 |
+
urllib3=2.2.3=pypi_0
|
333 |
+
uvicorn=0.30.6=pypi_0
|
334 |
+
uvloop=0.20.0=pypi_0
|
335 |
+
watchfiles=0.24.0=pypi_0
|
336 |
+
wcwidth=0.2.13=pypi_0
|
337 |
+
websocket-client=1.8.0=pypi_0
|
338 |
+
websockets=12.0=pypi_0
|
339 |
+
wheel=0.44.0=py310h06a4308_0
|
340 |
+
wrapt=1.16.0=pypi_0
|
341 |
+
wsproto=1.2.0=pypi_0
|
342 |
+
xxhash=3.5.0=pypi_0
|
343 |
+
xz=5.4.6=h5eee18b_1
|
344 |
+
yapf=0.40.2=pypi_0
|
345 |
+
yarl=1.11.1=pypi_0
|
346 |
+
zipp=3.20.2=pypi_0
|
347 |
+
zlib=1.2.13=h5eee18b_1
|
response_body.txt
ADDED
@@ -0,0 +1,642 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
HTTP/1.1 200 OK
|
2 |
+
date: Tue, 12 Nov 2024 06:54:05 GMT
|
3 |
+
server: uvicorn
|
4 |
+
content-type: text/event-stream; charset=utf-8
|
5 |
+
transfer-encoding: chunked
|
6 |
+
|
7 |
+
data: {"sex_ed_article":[]}
|
8 |
+
|
9 |
+
data: {"sex_ed_qa":[]}
|
10 |
+
|
11 |
+
data: {"webResults":[{"position": 1, "title": "\u5218\u5fb7\u534e- \u7ef4\u57fa\u767e\u79d1\uff0c\u81ea\u7531\u7684\u767e\u79d1\u5168\u4e66", "link": "https://zh.wikipedia.org/zh-hans/%E5%8A%89%E5%BE%B7%E8%8F%AF", "redirect_link": "https://www.google.com/url?sa=t&url=https://zh.wikipedia.org/zh-hans/%E5%8A%89%E5%BE%B7%E8%8F%AF&usg=AOvVaw1q2_qTM88SblRMtjrjG9Xg", "displayed_link": "https://zh.wikipedia.org \u203a \u5289\u5fb7\u83ef", "thumbnail": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3ffae43e29c9832b5471e4d769b7aa38b5.jpeg", "favicon": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3fd046d699d24ed7658385ca05690711a8.png", "snippet": "\u5218\u5fb7\u534e\uff0cSBS\uff0cMH\uff0cJP\uff08\u82f1\u8bed\uff1aAndy Lau Tak Wah\uff1b1961\u5e749\u670827\u65e5\u2014\uff09\uff0c\u9999\u6e2f\u7537\u6f14\u5458\u3001\u6b4c\u624b\u3001\u586b\u8bcd\u4eba\u3001\u76d1\u5236\u53ca\u51fa\u54c1\u4eba\uff0c1990\u5e74\u4ee3\u83b7\u5c01\u4e3a\u9999\u6e2f\u4e50\u575b\u201c\u56db\u5927\u5929\u738b\u201d\u4e4b\u4e00\uff0c\u4e5f\u662f\u5409\u5c3c\u65af\u4e16\u754c\u7eaa\u5f55\u5927\u5168\u4e2d ...", "snippet_highlighted_words": ["\u5218\u5fb7\u534e"], "source": "\u7ef4\u57fa\u767e\u79d1"}, {"position": 2, "title": "\u5218\u5fb7\u534e_\u767e\u5ea6\u767e\u79d1", "link": "https://baike.baidu.com/item/%E5%88%98%E5%BE%B7%E5%8D%8E/114923", "redirect_link": "https://www.google.com/url?sa=t&url=https://baike.baidu.com/item/%E5%88%98%E5%BE%B7%E5%8D%8E/114923&usg=AOvVaw0Gl9FYjPsR6UUjhi42-RK_", "displayed_link": "https://baike.baidu.com \u203a item", "thumbnail": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3f7fe955022de232c52947e73b6c9ccba5.jpeg", "favicon": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3f05ba95177707ab7a23f49351ae1b1b01.png", "snippet": "\u5218\u5fb7\u534e\uff08Andy Lau\uff09\uff0c1961\u5e749\u670827\u65e5\u51fa\u751f\u4e8e\u4e2d\u56fd\u9999\u6e2f\uff0c\u534e\u8bed\u5f71\u89c6\u7537\u6f14\u5458\u3001\u6d41\u884c\u4e50\u6b4c\u624b\u3001\u7535\u5f71\u5236\u7247\u4eba\u3001\u4f5c\u8bcd\u4eba\u30021981\u5e74\uff0c\u56e0\u51fa\u6f14\u4e2a\u4eba\u9996\u90e8\u7535\u5f71\u300a\u5f69\u4e91\u66f2\u300b\u800c\u8fdb\u5165\u6f14\u827a\u5708\u30021985\u5e74\uff0c ...", "snippet_highlighted_words": ["\u5218\u5fb7\u534e"], "source": "\u767e\u5ea6\u767e\u79d1"}, {"position": 3, "title": "\u5289\u5fb7\u83ef- \u7dad\u57fa\u767e\u79d1\uff0c\u81ea\u7531\u7684\u767e\u79d1\u5168\u66f8", "link": "https://zh.wikipedia.org/zh-hant/%E5%8A%89%E7%A6%8F%E6%A6%AE", "redirect_link": "https://www.google.com/url?sa=t&url=https://zh.wikipedia.org/zh-hant/%E5%8A%89%E7%A6%8F%E6%A6%AE&usg=AOvVaw02IrhBIMg6s8gFIjc8x2TT", "displayed_link": "https://zh.wikipedia.org \u203a \u5289\u798f\u69ae", "thumbnail": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3fd60ad4942ec593c5c073f72b44ef3ab1.jpeg", "favicon": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3ff5b19e441d540030b77e9351c53a6b1e.png", "snippet": "\u5289\u5fb7\u83ef\u662f\u5929\u5e55\u516c\u53f8\u548c\u6620\u85dd\u96c6\u5718\u7684\u5275\u5efa\u8005\uff0c\u4f5c\u70ba\u6295\u8cc7\u4eba\u8207\u76e3\u5236\u5df2\u53c3\u8207\u88fd\u4f5c\u4e8630\u591a\u90e8\u83ef\u8a9e\u96fb\u5f71\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u5289\u5fb7\u83ef\u662f\u56db\u5ddd\u7701\u5ddd\u5287\u5b78\u6821\u5ba2\u5ea7\u6559\u6388\u3002 ... 1999\u5e74\uff0c\u5289\u5fb7\u83ef\u7372\u5f97\u300c\u9999\u6e2f\u5341\u5927\u5091\u51fa\u9752\u5e74\u300d ...", "snippet_highlighted_words": ["\u5289\u5fb7\u83ef\u662f\u5929\u5e55\u516c\u53f8\u548c\u6620\u85dd\u96c6\u5718\u7684\u5275\u5efa\u8005"], "source": "\u7ef4\u57fa\u767e\u79d1"}, {"position": 4, "title": "\u56db\u5927\u5929\u738b_\u767e\u5ea6\u767e\u79d1", "link": "https://baike.baidu.com/item/%E5%9B%9B%E5%A4%A7%E5%A4%A9%E7%8E%8B/2513149", "redirect_link": "https://www.google.com/url?sa=t&url=https://baike.baidu.com/item/%E5%9B%9B%E5%A4%A7%E5%A4%A9%E7%8E%8B/2513149&usg=AOvVaw27ahGysuTMVPPo5oogoLTy", "displayed_link": "https://baike.baidu.com \u203a item", "thumbnail": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3f0b306839f1664b5c773a9ad15f87290e.jpeg", "favicon": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3fd25856d65bd346aa02690fa4ce7e9c25.png", "snippet": "[5] \u56db\u5927\u5929\u738b\u91cc\uff0c\u5218\u5fb7\u534e\u662f\u5f71\u5e1d\uff0c\u5f20\u5b66\u53cb\u662f\u6b4c\u795e\uff0c\u90ed\u5bcc\u57ce\u662f\u821e\u738b\uff0c\u90a3\u9ece\u660e\u662f\u4ec0\u4e48\uff1f\uff0e\u817e\u8baf\u7f51\uff0e2020-07-29 [\u5f15\u7528\u65e5\u671f2021-02-06]; [6] \u4e5d\u5341\u5e74\u4ee3\u7684\u9999\u6e2f\u56db\u5927\u5929\u738b\uff0c\u9ece\u660e\u7684\u4eba\u6c14\u4e0d\u4f46 ...", "snippet_highlighted_words": ["\u5218\u5fb7\u534e\u662f"], "source": "\u767e\u5ea6\u767e\u79d1"}, {"position": 5, "title": "61\u5c81\u5218\u5fb7\u534e\uff0c\u6574\u987f\u5a31\u4e50\u5708", "link": "https://m.thepaper.cn/newsDetail_forward_20110227", "redirect_link": "https://www.google.com/url?sa=t&url=https://m.thepaper.cn/newsDetail_forward_20110227&usg=AOvVaw15CllHEoKI0GYKtdhdsP7q", "displayed_link": "https://m.thepaper.cn \u203a newsDetail_...", "thumbnail": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQCahfz3ZB_cicQuQxTLiYEYO5qE1AWxc3X3G5XKv0i5lOFXxOTCKsR&usqp=CAE&s", "favicon": "https://serpapi.com/searches/6732fb9112345774f44255fb/images/3c08f54447ba44294b015f11cdee9a3f0c01f1c8d98f0f947ca0db6990203db3.png", "date": "Sep 29, 2022", "snippet": "\u4f5c\u4e3a\u4e00\u4ee3\u5929\u738b\u5de8\u661f\uff0c\u5218\u5fb7\u534e\u8eab\u4e0a\u51e0\u4e4e\u62e5\u6709\u201c\u5b8c\u7f8e\u5076\u50cf\u201d\u7684\u5168\u90e8\u7279\u8d28\uff1a\u656c\u4e1a\u3001\u771f\u8bda\u3001\u52aa\u529b\u4e14\u6210\u529f\u3002 \u4ed6\u5e76\u4e0d\u662f\u4e00\u4e2a\u5929\u624d\u578b\u7684\u827a\u4eba\uff0c\u4ed6\u7684\u5531\u529f\u88ab\u4eba\u6307\u6458\u6bd4\u4e0d\u4e0a\u540c\u4e3a\u5929\u738b\u7684\u5f20\u5b66\u53cb ...", "snippet_highlighted_words": ["\u5218\u5fb7\u534e"], "source": "ThePaper.cn"}]}
|
12 |
+
|
13 |
+
data: {"tags": ["\u5218\u5fb7\u534e", "\u9999\u6e2f\u56db\u5927\u5929\u738b", "\u6b4c\u624b"]}
|
14 |
+
|
15 |
+
data:{"content": "#"}
|
16 |
+
|
17 |
+
data:{"content": " \u5218"}
|
18 |
+
|
19 |
+
data:{"content": "\u5fb7"}
|
20 |
+
|
21 |
+
data:{"content": "\u534e"}
|
22 |
+
|
23 |
+
data:{"content": "\uff0c"}
|
24 |
+
|
25 |
+
data:{"content": "\u90a3\u4e2a"}
|
26 |
+
|
27 |
+
data:{"content": "\u95ea\u8000"}
|
28 |
+
|
29 |
+
data:{"content": "\u7684\u5927"}
|
30 |
+
|
31 |
+
data:{"content": "\u4e2d\u534e"}
|
32 |
+
|
33 |
+
data:{"content": "\u5730\u533a"}
|
34 |
+
|
35 |
+
data:{"content": "\u6b4c"}
|
36 |
+
|
37 |
+
data:{"content": "\u5f71"}
|
38 |
+
|
39 |
+
data:{"content": "\u53cc"}
|
40 |
+
|
41 |
+
data:{"content": "\u6816"}
|
42 |
+
|
43 |
+
data:{"content": "\u5929"}
|
44 |
+
|
45 |
+
data:{"content": "\u738b"}
|
46 |
+
|
47 |
+
data:{"content": "\r\n\r\n"}
|
48 |
+
|
49 |
+
data:{"content": "\u5218"}
|
50 |
+
|
51 |
+
data:{"content": "\u5fb7"}
|
52 |
+
|
53 |
+
data:{"content": "\u534e"}
|
54 |
+
|
55 |
+
data:{"content": "\u662f\u8c01"}
|
56 |
+
|
57 |
+
data:{"content": "\uff1f"}
|
58 |
+
|
59 |
+
data:{"content": "\u4ed6"}
|
60 |
+
|
61 |
+
data:{"content": "\u5c31\u662f"}
|
62 |
+
|
63 |
+
data:{"content": "\u90a3\u4e2a"}
|
64 |
+
|
65 |
+
data:{"content": "\u5728"}
|
66 |
+
|
67 |
+
data:{"content": "\u5927"}
|
68 |
+
|
69 |
+
data:{"content": "\u4e2d\u534e"}
|
70 |
+
|
71 |
+
data:{"content": "\u5730\u533a"}
|
72 |
+
|
73 |
+
data:{"content": "\u4e43\u81f3"}
|
74 |
+
|
75 |
+
data:{"content": "\u4e9a\u6d32"}
|
76 |
+
|
77 |
+
data:{"content": "\u90fd"}
|
78 |
+
|
79 |
+
data:{"content": "\u4eab\u6709"}
|
80 |
+
|
81 |
+
data:{"content": "\u6781\u9ad8"}
|
82 |
+
|
83 |
+
data:{"content": "\u58f0\u8a89"}
|
84 |
+
|
85 |
+
data:{"content": "\u7684"}
|
86 |
+
|
87 |
+
data:{"content": "\u6b4c\u624b"}
|
88 |
+
|
89 |
+
data:{"content": "\u3001"}
|
90 |
+
|
91 |
+
data:{"content": "\u6f14\u5458"}
|
92 |
+
|
93 |
+
data:{"content": "\u548c"}
|
94 |
+
|
95 |
+
data:{"content": "\u7535\u5f71"}
|
96 |
+
|
97 |
+
data:{"content": "\u5bfc\u6f14"}
|
98 |
+
|
99 |
+
data:{"content": "\u3002"}
|
100 |
+
|
101 |
+
data:{"content": "1"}
|
102 |
+
|
103 |
+
data:{"content": "9"}
|
104 |
+
|
105 |
+
data:{"content": "6"}
|
106 |
+
|
107 |
+
data:{"content": "1"}
|
108 |
+
|
109 |
+
data:{"content": "\u5e74"}
|
110 |
+
|
111 |
+
data:{"content": "\u51fa\u751f\u4e8e"}
|
112 |
+
|
113 |
+
data:{"content": "\u4e2d\u56fd"}
|
114 |
+
|
115 |
+
data:{"content": "\u5929\u6d25"}
|
116 |
+
|
117 |
+
data:{"content": "\u7684"}
|
118 |
+
|
119 |
+
data:{"content": "\u5218"}
|
120 |
+
|
121 |
+
data:{"content": "\u5fb7"}
|
122 |
+
|
123 |
+
data:{"content": "\u534e"}
|
124 |
+
|
125 |
+
data:{"content": "\uff0c"}
|
126 |
+
|
127 |
+
data:{"content": "\u51ed\u501f"}
|
128 |
+
|
129 |
+
data:{"content": "\u4ed6"}
|
130 |
+
|
131 |
+
data:{"content": "\u90a3"}
|
132 |
+
|
133 |
+
data:{"content": "\u72ec\u7279\u7684"}
|
134 |
+
|
135 |
+
data:{"content": "\u9b45\u529b"}
|
136 |
+
|
137 |
+
data:{"content": "\u548c"}
|
138 |
+
|
139 |
+
data:{"content": "\u591a"}
|
140 |
+
|
141 |
+
data:{"content": "\u624d"}
|
142 |
+
|
143 |
+
data:{"content": "\u591a"}
|
144 |
+
|
145 |
+
data:{"content": "\u827a"}
|
146 |
+
|
147 |
+
data:{"content": "\uff0c"}
|
148 |
+
|
149 |
+
data:{"content": "\u6210\u4e3a\u4e86"}
|
150 |
+
|
151 |
+
data:{"content": "\u65e0\u6570"}
|
152 |
+
|
153 |
+
data:{"content": "\u4eba\u5fc3"}
|
154 |
+
|
155 |
+
data:{"content": "\u4e2d\u7684"}
|
156 |
+
|
157 |
+
data:{"content": "\u8d85\u7ea7"}
|
158 |
+
|
159 |
+
data:{"content": "\u5de8\u661f"}
|
160 |
+
|
161 |
+
data:{"content": "\u3002\u201c"}
|
162 |
+
|
163 |
+
data:{"content": "\u56db\u5927"}
|
164 |
+
|
165 |
+
data:{"content": "\u5929"}
|
166 |
+
|
167 |
+
data:{"content": "\u738b"}
|
168 |
+
|
169 |
+
data:{"content": "\u201d"}
|
170 |
+
|
171 |
+
data:{"content": "\u4e4b\u4e00"}
|
172 |
+
|
173 |
+
data:{"content": "\u7684"}
|
174 |
+
|
175 |
+
data:{"content": "\u79f0\u53f7"}
|
176 |
+
|
177 |
+
data:{"content": "\u8db3\u4ee5"}
|
178 |
+
|
179 |
+
data:{"content": "\u8bc1\u660e"}
|
180 |
+
|
181 |
+
data:{"content": "\u4ed6\u5728"}
|
182 |
+
|
183 |
+
data:{"content": "\u97f3\u4e50"}
|
184 |
+
|
185 |
+
data:{"content": "\u4e0e"}
|
186 |
+
|
187 |
+
data:{"content": "\u5f71\u89c6"}
|
188 |
+
|
189 |
+
data:{"content": "\u9886\u57df\u7684"}
|
190 |
+
|
191 |
+
data:{"content": "\u5353\u8d8a"}
|
192 |
+
|
193 |
+
data:{"content": "\u6210\u5c31"}
|
194 |
+
|
195 |
+
data:{"content": "\u3002"}
|
196 |
+
|
197 |
+
data:{"content": "\r\n\r\n"}
|
198 |
+
|
199 |
+
data:{"content": "##"}
|
200 |
+
|
201 |
+
data:{"content": " \u5218"}
|
202 |
+
|
203 |
+
data:{"content": "\u5fb7"}
|
204 |
+
|
205 |
+
data:{"content": "\u534e"}
|
206 |
+
|
207 |
+
data:{"content": "\u7684"}
|
208 |
+
|
209 |
+
data:{"content": "\u5149\u8f89"}
|
210 |
+
|
211 |
+
data:{"content": "\u5c81\u6708"}
|
212 |
+
|
213 |
+
data:{"content": "\r\n"}
|
214 |
+
|
215 |
+
data:{"content": "**"}
|
216 |
+
|
217 |
+
data:{"content": "\u7ef4"}
|
218 |
+
|
219 |
+
data:{"content": "\u57fa"}
|
220 |
+
|
221 |
+
data:{"content": "\u767e\u79d1"}
|
222 |
+
|
223 |
+
data:{"content": "**:"}
|
224 |
+
|
225 |
+
data:{"content": " \u5218"}
|
226 |
+
|
227 |
+
data:{"content": "\u5fb7"}
|
228 |
+
|
229 |
+
data:{"content": "\u534e"}
|
230 |
+
|
231 |
+
data:{"content": "\uff08"}
|
232 |
+
|
233 |
+
data:{"content": "1"}
|
234 |
+
|
235 |
+
data:{"content": "9"}
|
236 |
+
|
237 |
+
data:{"content": "6"}
|
238 |
+
|
239 |
+
data:{"content": "1"}
|
240 |
+
|
241 |
+
data:{"content": "\u5e74"}
|
242 |
+
|
243 |
+
data:{"content": "9"}
|
244 |
+
|
245 |
+
data:{"content": "\u6708"}
|
246 |
+
|
247 |
+
data:{"content": "2"}
|
248 |
+
|
249 |
+
data:{"content": "0"}
|
250 |
+
|
251 |
+
data:{"content": "\u65e5"}
|
252 |
+
|
253 |
+
data:{"content": "\uff09\uff0c"}
|
254 |
+
|
255 |
+
data:{"content": "\u4e2d\u56fd"}
|
256 |
+
|
257 |
+
data:{"content": "\u6f14\u5458"}
|
258 |
+
|
259 |
+
data:{"content": "\u3001"}
|
260 |
+
|
261 |
+
data:{"content": "\u6b4c\u624b"}
|
262 |
+
|
263 |
+
data:{"content": "\u3001"}
|
264 |
+
|
265 |
+
data:{"content": "\u7535\u5f71"}
|
266 |
+
|
267 |
+
data:{"content": "\u5bfc\u6f14"}
|
268 |
+
|
269 |
+
data:{"content": "\u3002"}
|
270 |
+
|
271 |
+
data:{"content": "\u4ed6\u7684"}
|
272 |
+
|
273 |
+
data:{"content": "\u6f14\u827a"}
|
274 |
+
|
275 |
+
data:{"content": "\u4e8b\u4e1a"}
|
276 |
+
|
277 |
+
data:{"content": "\u6a2a"}
|
278 |
+
|
279 |
+
data:{"content": "\u8de8"}
|
280 |
+
|
281 |
+
data:{"content": "\u6570"}
|
282 |
+
|
283 |
+
data:{"content": "\u5341\u5e74"}
|
284 |
+
|
285 |
+
data:{"content": "\uff0c"}
|
286 |
+
|
287 |
+
data:{"content": "\u4e0d\u4ec5"}
|
288 |
+
|
289 |
+
data:{"content": "\u5728"}
|
290 |
+
|
291 |
+
data:{"content": "\u821e\u53f0\u4e0a"}
|
292 |
+
|
293 |
+
data:{"content": "\u7559\u4e0b\u4e86"}
|
294 |
+
|
295 |
+
data:{"content": "\u65e0\u6570"}
|
296 |
+
|
297 |
+
data:{"content": "\u7ecf\u5178"}
|
298 |
+
|
299 |
+
data:{"content": "\u6b4c\u58f0"}
|
300 |
+
|
301 |
+
data:{"content": "\uff0c\u5728"}
|
302 |
+
|
303 |
+
data:{"content": "\u94f6"}
|
304 |
+
|
305 |
+
data:{"content": "\u5e55"}
|
306 |
+
|
307 |
+
data:{"content": "\u4e0a"}
|
308 |
+
|
309 |
+
data:{"content": "\u4e5f"}
|
310 |
+
|
311 |
+
data:{"content": "\u5851\u9020"}
|
312 |
+
|
313 |
+
data:{"content": "\u4e86"}
|
314 |
+
|
315 |
+
data:{"content": "\u4f17\u591a"}
|
316 |
+
|
317 |
+
data:{"content": "\u4ee4\u4eba"}
|
318 |
+
|
319 |
+
data:{"content": "\u96be\u5fd8"}
|
320 |
+
|
321 |
+
data:{"content": "\u7684\u89d2\u8272"}
|
322 |
+
|
323 |
+
data:{"content": "\u3002\r\n"}
|
324 |
+
|
325 |
+
data:{"content": "**"}
|
326 |
+
|
327 |
+
data:{"content": "\u56db\u5927"}
|
328 |
+
|
329 |
+
data:{"content": "\u5929"}
|
330 |
+
|
331 |
+
data:{"content": "\u738b"}
|
332 |
+
|
333 |
+
data:{"content": "**:"}
|
334 |
+
|
335 |
+
data:{"content": " "}
|
336 |
+
|
337 |
+
data:{"content": "\u4f5c\u4e3a"}
|
338 |
+
|
339 |
+
data:{"content": "\u201c"}
|
340 |
+
|
341 |
+
data:{"content": "\u56db\u5927"}
|
342 |
+
|
343 |
+
data:{"content": "\u5929"}
|
344 |
+
|
345 |
+
data:{"content": "\u738b"}
|
346 |
+
|
347 |
+
data:{"content": "\u201d"}
|
348 |
+
|
349 |
+
data:{"content": "\u4e4b\u4e00"}
|
350 |
+
|
351 |
+
data:{"content": "\uff0c"}
|
352 |
+
|
353 |
+
data:{"content": "\u5218"}
|
354 |
+
|
355 |
+
data:{"content": "\u5fb7"}
|
356 |
+
|
357 |
+
data:{"content": "\u534e"}
|
358 |
+
|
359 |
+
data:{"content": "\u4e0e"}
|
360 |
+
|
361 |
+
data:{"content": "\u5f20"}
|
362 |
+
|
363 |
+
data:{"content": "\u5b66"}
|
364 |
+
|
365 |
+
data:{"content": "\u53cb"}
|
366 |
+
|
367 |
+
data:{"content": "\u3001"}
|
368 |
+
|
369 |
+
data:{"content": "\u90ed"}
|
370 |
+
|
371 |
+
data:{"content": "\u5bcc"}
|
372 |
+
|
373 |
+
data:{"content": "\u57ce"}
|
374 |
+
|
375 |
+
data:{"content": "\u548c"}
|
376 |
+
|
377 |
+
data:{"content": "\u9ece\u660e"}
|
378 |
+
|
379 |
+
data:{"content": "\u4e00\u8d77"}
|
380 |
+
|
381 |
+
data:{"content": "\uff0c"}
|
382 |
+
|
383 |
+
data:{"content": "\u662f"}
|
384 |
+
|
385 |
+
data:{"content": "2"}
|
386 |
+
|
387 |
+
data:{"content": "0"}
|
388 |
+
|
389 |
+
data:{"content": "\u4e16\u7eaa"}
|
390 |
+
|
391 |
+
data:{"content": "9"}
|
392 |
+
|
393 |
+
data:{"content": "0"}
|
394 |
+
|
395 |
+
data:{"content": "\u5e74\u4ee3"}
|
396 |
+
|
397 |
+
data:{"content": "\u9999\u6e2f"}
|
398 |
+
|
399 |
+
data:{"content": "\u4e50"}
|
400 |
+
|
401 |
+
data:{"content": "\u575b"}
|
402 |
+
|
403 |
+
data:{"content": "\u6700"}
|
404 |
+
|
405 |
+
data:{"content": "\u8000\u773c"}
|
406 |
+
|
407 |
+
data:{"content": "\u7684"}
|
408 |
+
|
409 |
+
data:{"content": "\u56db"}
|
410 |
+
|
411 |
+
data:{"content": "\u9897"}
|
412 |
+
|
413 |
+
data:{"content": "\u660e\u661f"}
|
414 |
+
|
415 |
+
data:{"content": "\u3002"}
|
416 |
+
|
417 |
+
data:{"content": "\r\n\r\n"}
|
418 |
+
|
419 |
+
data:{"content": "##"}
|
420 |
+
|
421 |
+
data:{"content": " \u73b0"}
|
422 |
+
|
423 |
+
data:{"content": "\u5728"}
|
424 |
+
|
425 |
+
data:{"content": "\u7684"}
|
426 |
+
|
427 |
+
data:{"content": "\u52a8\u6001"}
|
428 |
+
|
429 |
+
data:{"content": "\r\n"}
|
430 |
+
|
431 |
+
data:{"content": "\u503c\u5f97\u4e00\u63d0"}
|
432 |
+
|
433 |
+
data:{"content": "\u7684\u662f"}
|
434 |
+
|
435 |
+
data:{"content": "\uff0c\u5728"}
|
436 |
+
|
437 |
+
data:{"content": "2"}
|
438 |
+
|
439 |
+
data:{"content": "0"}
|
440 |
+
|
441 |
+
data:{"content": "2"}
|
442 |
+
|
443 |
+
data:{"content": "1"}
|
444 |
+
|
445 |
+
data:{"content": "\u5e74"}
|
446 |
+
|
447 |
+
data:{"content": "1"}
|
448 |
+
|
449 |
+
data:{"content": "1"}
|
450 |
+
|
451 |
+
data:{"content": "\u6708"}
|
452 |
+
|
453 |
+
data:{"content": "1"}
|
454 |
+
|
455 |
+
data:{"content": "\u65e5"}
|
456 |
+
|
457 |
+
data:{"content": "\uff0c"}
|
458 |
+
|
459 |
+
data:{"content": "\u56e0"}
|
460 |
+
|
461 |
+
data:{"content": "\u88ab\u8ba4\u4e3a"}
|
462 |
+
|
463 |
+
data:{"content": "\u662f\u4e2d\u56fd"}
|
464 |
+
|
465 |
+
data:{"content": "\u5171\u4ea7"}
|
466 |
+
|
467 |
+
data:{"content": "\u515a\u7684"}
|
468 |
+
|
469 |
+
data:{"content": "\u6210\u5458"}
|
470 |
+
|
471 |
+
data:{"content": "\uff0c"}
|
472 |
+
|
473 |
+
data:{"content": "\u5218"}
|
474 |
+
|
475 |
+
data:{"content": "\u5fb7"}
|
476 |
+
|
477 |
+
data:{"content": "\u534e"}
|
478 |
+
|
479 |
+
data:{"content": "\u88ab"}
|
480 |
+
|
481 |
+
data:{"content": "\u53d6\u6d88"}
|
482 |
+
|
483 |
+
data:{"content": "\u4e86"}
|
484 |
+
|
485 |
+
data:{"content": "\u65b0\u52a0\u5761"}
|
486 |
+
|
487 |
+
data:{"content": "\u91d1"}
|
488 |
+
|
489 |
+
data:{"content": "\u66f2"}
|
490 |
+
|
491 |
+
data:{"content": "\u5956"}
|
492 |
+
|
493 |
+
data:{"content": "\u7684\u5927"}
|
494 |
+
|
495 |
+
data:{"content": "\u5956"}
|
496 |
+
|
497 |
+
data:{"content": "\u9881\u5956"}
|
498 |
+
|
499 |
+
data:{"content": "\u8d44\u683c"}
|
500 |
+
|
501 |
+
data:{"content": "\uff0c"}
|
502 |
+
|
503 |
+
data:{"content": "\u672a\u80fd"}
|
504 |
+
|
505 |
+
data:{"content": "\u9886\u53d6"}
|
506 |
+
|
507 |
+
data:{"content": "\u5956\u9879"}
|
508 |
+
|
509 |
+
data:{"content": "\u3002"}
|
510 |
+
|
511 |
+
data:{"content": "\u8fd9\u4e2a"}
|
512 |
+
|
513 |
+
data:{"content": "\u5c0f"}
|
514 |
+
|
515 |
+
data:{"content": "\u63d2"}
|
516 |
+
|
517 |
+
data:{"content": "\u66f2"}
|
518 |
+
|
519 |
+
data:{"content": "\u867d\u7136"}
|
520 |
+
|
521 |
+
data:{"content": "\u77ed\u6682"}
|
522 |
+
|
523 |
+
data:{"content": "\u5f71\u54cd"}
|
524 |
+
|
525 |
+
data:{"content": "\u4e86\u4ed6\u7684"}
|
526 |
+
|
527 |
+
data:{"content": "\u51fa\u5e2d"}
|
528 |
+
|
529 |
+
data:{"content": "\uff0c"}
|
530 |
+
|
531 |
+
data:{"content": "\u4f46"}
|
532 |
+
|
533 |
+
data:{"content": "\u5e76\u672a"}
|
534 |
+
|
535 |
+
data:{"content": "\u52a8\u6447"}
|
536 |
+
|
537 |
+
data:{"content": "\u4ed6\u5728"}
|
538 |
+
|
539 |
+
data:{"content": "\u5168\u7403"}
|
540 |
+
|
541 |
+
data:{"content": "\u534e\u4eba"}
|
542 |
+
|
543 |
+
data:{"content": "\u5fc3\u4e2d\u7684"}
|
544 |
+
|
545 |
+
data:{"content": "\u5730\u4f4d"}
|
546 |
+
|
547 |
+
data:{"content": "\u3002"}
|
548 |
+
|
549 |
+
data:{"content": "\r\n\r\n"}
|
550 |
+
|
551 |
+
data:{"content": "\u6240\u4ee5"}
|
552 |
+
|
553 |
+
data:{"content": "\uff0c"}
|
554 |
+
|
555 |
+
data:{"content": "\u5f53\u4f60"}
|
556 |
+
|
557 |
+
data:{"content": "\u542c\u5230"}
|
558 |
+
|
559 |
+
data:{"content": "\u90a3"}
|
560 |
+
|
561 |
+
data:{"content": "\u5145\u6ee1"}
|
562 |
+
|
563 |
+
data:{"content": "\u78c1"}
|
564 |
+
|
565 |
+
data:{"content": "\u6027\u7684"}
|
566 |
+
|
567 |
+
data:{"content": "\u58f0\u97f3"}
|
568 |
+
|
569 |
+
data:{"content": "\u6216\u8005"}
|
570 |
+
|
571 |
+
data:{"content": "\u770b\u5230"}
|
572 |
+
|
573 |
+
data:{"content": "\u4ed6"}
|
574 |
+
|
575 |
+
data:{"content": "\u94f6"}
|
576 |
+
|
577 |
+
data:{"content": "\u5e55"}
|
578 |
+
|
579 |
+
data:{"content": "\u4e0a\u7684"}
|
580 |
+
|
581 |
+
data:{"content": "\u82f1"}
|
582 |
+
|
583 |
+
data:{"content": "\u59ff"}
|
584 |
+
|
585 |
+
data:{"content": "\u65f6"}
|
586 |
+
|
587 |
+
data:{"content": "\uff0c"}
|
588 |
+
|
589 |
+
data:{"content": "\u4f60"}
|
590 |
+
|
591 |
+
data:{"content": "\u5c31\u80fd"}
|
592 |
+
|
593 |
+
data:{"content": "\u660e\u767d"}
|
594 |
+
|
595 |
+
data:{"content": "\u201c"}
|
596 |
+
|
597 |
+
data:{"content": "\u5218"}
|
598 |
+
|
599 |
+
data:{"content": "\u5fb7"}
|
600 |
+
|
601 |
+
data:{"content": "\u534e"}
|
602 |
+
|
603 |
+
data:{"content": "\u662f\u8c01"}
|
604 |
+
|
605 |
+
data:{"content": "\u201d"}
|
606 |
+
|
607 |
+
data:{"content": "\u8fd9\u4e2a\u95ee\u9898"}
|
608 |
+
|
609 |
+
data:{"content": "\u7684\u7b54\u6848"}
|
610 |
+
|
611 |
+
data:{"content": "\u4e86"}
|
612 |
+
|
613 |
+
data:{"content": "\u2014\u2014"}
|
614 |
+
|
615 |
+
data:{"content": "\u4ed6\u662f"}
|
616 |
+
|
617 |
+
data:{"content": "\u90a3\u4e2a"}
|
618 |
+
|
619 |
+
data:{"content": "\u59cb\u7ec8"}
|
620 |
+
|
621 |
+
data:{"content": "\u95ea\u8000"}
|
622 |
+
|
623 |
+
data:{"content": "\u7740"}
|
624 |
+
|
625 |
+
data:{"content": "\u5149\u8292"}
|
626 |
+
|
627 |
+
data:{"content": "\u7684"}
|
628 |
+
|
629 |
+
data:{"content": "\u5929"}
|
630 |
+
|
631 |
+
data:{"content": "\u738b"}
|
632 |
+
|
633 |
+
data:{"content": "\u5de8\u661f"}
|
634 |
+
|
635 |
+
data:{"content": "\u3002"}
|
636 |
+
|
637 |
+
data:{"related_searches": ["\u5218\u5fb7\u534e\u7684\u4e3b\u8981\u4f5c\u54c1", "\u5218\u5fb7\u534e\u7684\u4e2a\u4eba\u751f\u6d3b", "\u56db\u5927\u5929\u738b\u5206\u522b\u662f\u54ea\u4e9b\u4eba"]}
|
638 |
+
|
639 |
+
data:[DONE]
|
640 |
+
|
641 |
+
data:{"content": ""}
|
642 |
+
|
routers/__init__.py
ADDED
File without changes
|
routers/sql_chat.py
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, Request
|
2 |
+
from fastapi.responses import StreamingResponse
|
3 |
+
from llama_index.core.workflow import StopEvent
|
4 |
+
from llama_index.core.llms import ChatMessage
|
5 |
+
from workflow.sql_workflow import sql_workflow, SQLWorkflow
|
6 |
+
from workflow.roleplay_workflow import RolePlayWorkflow
|
7 |
+
from workflow.modules import load_chat_store, MySQLChatStore, ToyStatusStore
|
8 |
+
from workflow.events import TokenEvent, StatusEvent
|
9 |
+
import asyncio, os, json
|
10 |
+
from concurrent.futures import ThreadPoolExecutor
|
11 |
+
from contextlib import asynccontextmanager
|
12 |
+
from typing import Dict, Any
|
13 |
+
from workflow.modules import load_chat_store
|
14 |
+
from llama_index.llms.ollama import Ollama
|
15 |
+
from prompts.default_prompts import FINAL_RESPONSE_PROMPT
|
16 |
+
from workflow.vllm_model import MyVllm
|
17 |
+
from datetime import datetime
|
18 |
+
|
19 |
+
|
20 |
+
CHAT_STORE_PATH = os.getenv("CHAT_STORE_PATH")
|
21 |
+
MYSQL_HOST = os.getenv("MYSQL_HOST")
|
22 |
+
MYSQL_USER = os.getenv("MYSQL_USER")
|
23 |
+
MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD")
|
24 |
+
MYSQL_DATABASE = os.getenv("MYSQL_DATABASE")
|
25 |
+
MYSQL_PORT = int(os.getenv("MYSQL_PORT"))
|
26 |
+
|
27 |
+
sql_chat_router = APIRouter(
|
28 |
+
prefix="/sql_chat",
|
29 |
+
tags=["sql", "chat"]
|
30 |
+
)
|
31 |
+
|
32 |
+
chat_store_manager = APIRouter(
|
33 |
+
prefix="/modify_chat_store",
|
34 |
+
tags=["chat_store"]
|
35 |
+
)
|
36 |
+
|
37 |
+
roleplay_router = APIRouter(
|
38 |
+
prefix="/roleplay",
|
39 |
+
tags=["roleplay"]
|
40 |
+
)
|
41 |
+
|
42 |
+
"""
|
43 |
+
接收数据格式
|
44 |
+
{
|
45 |
+
"query": "Top 5 porn videos with url.", # 用户提问
|
46 |
+
"clientVersion": "ios_3.1.4", # 客户端版本, 不做处理
|
47 |
+
"traceId": "1290325592508092416", # 请求唯一标识, 不做处理
|
48 |
+
"messageId": 1290325592508092400, # message表示, 不做处理
|
49 |
+
"llmSessionId": "xxxxxxxx", # sessionId用于调取用户对话上下文
|
50 |
+
"llmUserId": "xxxxxx"
|
51 |
+
}
|
52 |
+
"""
|
53 |
+
|
54 |
+
# 全局资源管理
|
55 |
+
|
56 |
+
polling_variable = 0
|
57 |
+
|
58 |
+
class ResourceManager:
|
59 |
+
def __init__(self, max_concurrent=8): # 基于24G显存可以支持2个9G模型
|
60 |
+
self.semaphore = asyncio.Semaphore(max_concurrent)
|
61 |
+
self.thread_pool = ThreadPoolExecutor(max_workers=max_concurrent)
|
62 |
+
self.chat_stores: Dict[str, Any] = {} # 缓存chat store实例
|
63 |
+
|
64 |
+
async def get_chat_store(self, store_name: str):
|
65 |
+
if store_name not in self.chat_stores:
|
66 |
+
self.chat_stores[store_name] = load_chat_store(store_name)
|
67 |
+
return self.chat_stores[store_name]
|
68 |
+
|
69 |
+
# 全局资源管理器
|
70 |
+
resource_manager = ResourceManager()
|
71 |
+
|
72 |
+
@asynccontextmanager
|
73 |
+
async def acquire_model_resource():
|
74 |
+
try:
|
75 |
+
await resource_manager.semaphore.acquire()
|
76 |
+
yield
|
77 |
+
finally:
|
78 |
+
resource_manager.semaphore.release()
|
79 |
+
|
80 |
+
@sql_chat_router.post("/")
|
81 |
+
async def chat(request: Request):
|
82 |
+
requestJson = await request.json()
|
83 |
+
query = str(requestJson.get("query"))
|
84 |
+
sessionId = str(requestJson.get("llmSessionId"))
|
85 |
+
try:
|
86 |
+
isLLMContext = int(requestJson.get("isLlmContext"))
|
87 |
+
adultMode = int(requestJson.get("adultMode"))
|
88 |
+
# isCache = int(request.get("isCache"))
|
89 |
+
print(f"adultMode: {adultMode} - isLLMContext: {isLLMContext}")
|
90 |
+
if adultMode == 1:
|
91 |
+
adultMode = True
|
92 |
+
else:
|
93 |
+
adultMode = False
|
94 |
+
except Exception as e:
|
95 |
+
isLLMContext = 0
|
96 |
+
adultMode = False
|
97 |
+
# 调取用户对话上下文 elasticsearch
|
98 |
+
# chat_history = parse_chat_history(sessionId)
|
99 |
+
# try:
|
100 |
+
# chat_store = load_chat_store("testing_chat_store")
|
101 |
+
# except:
|
102 |
+
# # 获取当前日期
|
103 |
+
# current_date = datetime.now().strftime('%Y%m%d')
|
104 |
+
# chat_store = load_chat_store(current_date)
|
105 |
+
chat_store = MySQLChatStore(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, password=MYSQL_PASSWORD, database=MYSQL_DATABASE)
|
106 |
+
print(f"query: {query} - sessionId: {sessionId}")
|
107 |
+
|
108 |
+
llm = MyVllm(
|
109 |
+
model="huihui-ai/Qwen2.5-7B-Instruct-abliterated-v2",
|
110 |
+
api_key="token-abc123",
|
111 |
+
base_url="http://localhost:17777/v1",
|
112 |
+
)
|
113 |
+
|
114 |
+
response_synthesis_prompt = FINAL_RESPONSE_PROMPT
|
115 |
+
# Ollama("solonglin/qwen2.5-q6_k-abliterated", temperature=0.8, request_timeout=120, context_window=5000, keep_alive=-1),
|
116 |
+
wf = SQLWorkflow(
|
117 |
+
response_llm=llm,
|
118 |
+
response_synthesis_prompt=response_synthesis_prompt,
|
119 |
+
chat_store=chat_store,
|
120 |
+
sessionId=sessionId,
|
121 |
+
context_flag=isLLMContext,
|
122 |
+
adultMode=adultMode,
|
123 |
+
verbose=True,
|
124 |
+
timeout=60
|
125 |
+
)
|
126 |
+
r = wf.run(query=query)
|
127 |
+
async def generator():
|
128 |
+
async for event in r.stream_events():
|
129 |
+
if await request.is_disconnected():
|
130 |
+
break
|
131 |
+
if isinstance(event, TokenEvent):
|
132 |
+
token = event.token
|
133 |
+
yield token
|
134 |
+
if isinstance(event, StatusEvent):
|
135 |
+
yield event.status
|
136 |
+
if isinstance(event, str):
|
137 |
+
yield event
|
138 |
+
await asyncio.sleep(0)
|
139 |
+
# result = await sql_workflow(query=query, chat_store=chat_store, sessionId=sessionId, llm=llm, context_flag=isLLMContext, adultMode=adultMode)
|
140 |
+
return StreamingResponse(content=generator(), media_type="text/event-stream")
|
141 |
+
|
142 |
+
@roleplay_router.post("/")
|
143 |
+
async def roleplay(request: Request):
|
144 |
+
requestJson = await request.json()
|
145 |
+
query = str(requestJson.get("query"))
|
146 |
+
sessionId = "rp_" + str(requestJson.get("llmSessionId"))
|
147 |
+
# messageId = str(requestJson.get("messageId"))
|
148 |
+
toy_info = requestJson.get("toyIds")
|
149 |
+
if toy_info:
|
150 |
+
toy_names = [item["name"] for item in toy_info]
|
151 |
+
else:
|
152 |
+
toy_names = None
|
153 |
+
chat_store = MySQLChatStore(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, password=MYSQL_PASSWORD, database=MYSQL_DATABASE)
|
154 |
+
toy_status_store = ToyStatusStore(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, password=MYSQL_PASSWORD, database=MYSQL_DATABASE)
|
155 |
+
print(f"query: {query} - sessionId: {sessionId} - toyName: {toy_names}")
|
156 |
+
|
157 |
+
# setup llm
|
158 |
+
llm = MyVllm(
|
159 |
+
model="huihui-ai/Qwen2.5-7B-Instruct-abliterated-v2",
|
160 |
+
api_key="token-abc123",
|
161 |
+
base_url="http://localhost:17777/v1",
|
162 |
+
)
|
163 |
+
|
164 |
+
# init workflow
|
165 |
+
wf = RolePlayWorkflow(
|
166 |
+
response_llm=llm,
|
167 |
+
chat_store=chat_store,
|
168 |
+
toy_status_store=toy_status_store,
|
169 |
+
sessionId=sessionId,
|
170 |
+
gender="female",
|
171 |
+
toy_names=toy_names,
|
172 |
+
verbose=True,
|
173 |
+
timeout=60,
|
174 |
+
)
|
175 |
+
r = wf.run(query=query)
|
176 |
+
async def generator():
|
177 |
+
async for event in r.stream_events():
|
178 |
+
if await request.is_disconnected():
|
179 |
+
break
|
180 |
+
if isinstance(event, TokenEvent):
|
181 |
+
token = event.token
|
182 |
+
yield token
|
183 |
+
if isinstance(event, StatusEvent):
|
184 |
+
yield event.status
|
185 |
+
if isinstance(event, str):
|
186 |
+
yield event
|
187 |
+
await asyncio.sleep(0)
|
188 |
+
return StreamingResponse(content=generator(), media_type="text/event-stream")
|
189 |
+
|
190 |
+
|
191 |
+
@chat_store_manager.post("/")
|
192 |
+
async def modify_chat_store(request: Request):
|
193 |
+
try:
|
194 |
+
request = await request.json()
|
195 |
+
sessionId = request.get("sessionId")
|
196 |
+
upMessageBody = request.get("upMessageBody")
|
197 |
+
downMessageBody = request.get("downMessageBody")
|
198 |
+
|
199 |
+
chat_store = MySQLChatStore(MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE)
|
200 |
+
chat_store.del_message(sessionId, upMessageBody)
|
201 |
+
chat_store.del_message(sessionId, downMessageBody)
|
202 |
+
return {"status": "SUCCESS"}
|
203 |
+
except Exception as e:
|
204 |
+
return {"status": "FAILED", "error": str(e)}
|
routers/update_kb.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, Request, FastAPI
|
2 |
+
from langchain_community.embeddings.ollama import OllamaEmbeddings
|
3 |
+
import uvicorn
|
4 |
+
|
5 |
+
embed_model = OllamaEmbeddings(model="bge-m3")
|
6 |
+
|
7 |
+
app = FastAPI(
|
8 |
+
title="kb",
|
9 |
+
description="update_kb",
|
10 |
+
)
|
11 |
+
|
12 |
+
kb_router = APIRouter(
|
13 |
+
prefix="/kb",
|
14 |
+
tags=["kb"]
|
15 |
+
)
|
16 |
+
|
17 |
+
@kb_router.post("/")
|
18 |
+
async def update_kb(request: Request):
|
19 |
+
request = await request.json()
|
20 |
+
data = request.get("data", [])
|
21 |
+
collection_name = request.get("collection_name", "")
|
22 |
+
# print(f"collection_name: {collection_name}")
|
23 |
+
|
24 |
+
app.include_router(kb_router)
|
25 |
+
|
26 |
+
if __name__ == "__main__":
|
27 |
+
uvicorn.run(app, host="0.0.0.0", port=8010, loop="asyncio")
|
tests/README.md
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: SexBot
|
3 |
+
app_file: roleplay_gradio.py
|
4 |
+
sdk: gradio
|
5 |
+
sdk_version: 5.10.0
|
6 |
+
---
|
tests/__init__.py
ADDED
File without changes
|
tests/agent_workflow.py
ADDED
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any, List
|
2 |
+
|
3 |
+
from llama_index.core.agent.react import ReActChatFormatter, ReActOutputParser
|
4 |
+
from llama_index.core.agent.react.types import (
|
5 |
+
ActionReasoningStep,
|
6 |
+
ObservationReasoningStep,
|
7 |
+
)
|
8 |
+
from llama_index.core.llms.llm import LLM
|
9 |
+
from llama_index.core.memory import ChatMemoryBuffer
|
10 |
+
from llama_index.core.tools.types import BaseTool
|
11 |
+
from llama_index.core.workflow import (
|
12 |
+
Context,
|
13 |
+
Workflow,
|
14 |
+
StartEvent,
|
15 |
+
StopEvent,
|
16 |
+
step,
|
17 |
+
)
|
18 |
+
from llama_index.llms.openai import OpenAI
|
19 |
+
from llama_index.core.llms import ChatMessage
|
20 |
+
from llama_index.core.tools import ToolSelection, ToolOutput
|
21 |
+
from llama_index.core.workflow import Event
|
22 |
+
from llama_index.llms.ollama import Ollama
|
23 |
+
from llama_index.core import Settings
|
24 |
+
|
25 |
+
llm = Ollama(model="HammerAI/neuraldaredevil-abliterated")
|
26 |
+
Settings.llm = llm
|
27 |
+
|
28 |
+
class PrepEvent(Event):
|
29 |
+
pass
|
30 |
+
|
31 |
+
|
32 |
+
class InputEvent(Event):
|
33 |
+
input: list[ChatMessage]
|
34 |
+
|
35 |
+
|
36 |
+
class ToolCallEvent(Event):
|
37 |
+
tool_calls: list[ToolSelection]
|
38 |
+
|
39 |
+
|
40 |
+
class FunctionOutputEvent(Event):
|
41 |
+
output: ToolOutput
|
42 |
+
|
43 |
+
|
44 |
+
class ReActAgent(Workflow):
|
45 |
+
def __init__(
|
46 |
+
self,
|
47 |
+
*args: Any,
|
48 |
+
llm: LLM | None = None,
|
49 |
+
tools: list[BaseTool] | None = None,
|
50 |
+
extra_context: str | None = None,
|
51 |
+
**kwargs: Any,
|
52 |
+
) -> None:
|
53 |
+
super().__init__(*args, **kwargs)
|
54 |
+
self.tools = tools or []
|
55 |
+
|
56 |
+
self.llm = llm or OpenAI()
|
57 |
+
|
58 |
+
self.memory = ChatMemoryBuffer.from_defaults(llm=llm)
|
59 |
+
self.formatter = ReActChatFormatter(context=extra_context or "")
|
60 |
+
self.output_parser = ReActOutputParser()
|
61 |
+
self.sources = []
|
62 |
+
|
63 |
+
@step
|
64 |
+
async def new_user_msg(self, ctx: Context, ev: StartEvent) -> PrepEvent:
|
65 |
+
# clear sources
|
66 |
+
self.sources = []
|
67 |
+
|
68 |
+
# get user input
|
69 |
+
user_input = ev.input
|
70 |
+
user_msg = ChatMessage(role="user", content=user_input)
|
71 |
+
self.memory.put(user_msg)
|
72 |
+
|
73 |
+
# clear current reasoning
|
74 |
+
await ctx.set("current_reasoning", [])
|
75 |
+
|
76 |
+
return PrepEvent()
|
77 |
+
|
78 |
+
@step
|
79 |
+
async def prepare_chat_history(
|
80 |
+
self, ctx: Context, ev: PrepEvent
|
81 |
+
) -> InputEvent:
|
82 |
+
# get chat history
|
83 |
+
chat_history = self.memory.get()
|
84 |
+
current_reasoning = await ctx.get("current_reasoning", default=[])
|
85 |
+
llm_input = self.formatter.format(
|
86 |
+
self.tools, chat_history, current_reasoning=current_reasoning
|
87 |
+
)
|
88 |
+
return InputEvent(input=llm_input)
|
89 |
+
|
90 |
+
@step
|
91 |
+
async def handle_llm_input(
|
92 |
+
self, ctx: Context, ev: InputEvent
|
93 |
+
) -> ToolCallEvent | StopEvent:
|
94 |
+
chat_history = ev.input
|
95 |
+
|
96 |
+
response = await self.llm.achat(chat_history)
|
97 |
+
|
98 |
+
try:
|
99 |
+
reasoning_step = self.output_parser.parse(response.message.content)
|
100 |
+
(await ctx.get("current_reasoning", default=[])).append(
|
101 |
+
reasoning_step
|
102 |
+
)
|
103 |
+
if reasoning_step.is_done:
|
104 |
+
self.memory.put(
|
105 |
+
ChatMessage(
|
106 |
+
role="assistant", content=reasoning_step.response
|
107 |
+
)
|
108 |
+
)
|
109 |
+
print(reasoning_step.response)
|
110 |
+
return StopEvent(
|
111 |
+
result={
|
112 |
+
"response": reasoning_step.response,
|
113 |
+
"sources": [*self.sources],
|
114 |
+
"reasoning": await ctx.get(
|
115 |
+
"current_reasoning", default=[]
|
116 |
+
),
|
117 |
+
}
|
118 |
+
)
|
119 |
+
elif isinstance(reasoning_step, ActionReasoningStep):
|
120 |
+
tool_name = reasoning_step.action
|
121 |
+
tool_args = reasoning_step.action_input
|
122 |
+
print(f"current thought:{reasoning_step.thought} --{tool_name}({tool_args}")
|
123 |
+
return ToolCallEvent(
|
124 |
+
tool_calls=[
|
125 |
+
ToolSelection(
|
126 |
+
tool_id="fake",
|
127 |
+
tool_name=tool_name,
|
128 |
+
tool_kwargs=tool_args,
|
129 |
+
)
|
130 |
+
]
|
131 |
+
)
|
132 |
+
except Exception as e:
|
133 |
+
(await ctx.get("current_reasoning", default=[])).append(
|
134 |
+
ObservationReasoningStep(
|
135 |
+
observation=f"There was an error in parsing my reasoning: {e}"
|
136 |
+
)
|
137 |
+
)
|
138 |
+
|
139 |
+
# if no tool calls or final response, iterate again
|
140 |
+
return PrepEvent()
|
141 |
+
|
142 |
+
@step
|
143 |
+
async def handle_tool_calls(
|
144 |
+
self, ctx: Context, ev: ToolCallEvent
|
145 |
+
) -> PrepEvent:
|
146 |
+
tool_calls = ev.tool_calls
|
147 |
+
tools_by_name = {tool.metadata.get_name(): tool for tool in self.tools}
|
148 |
+
|
149 |
+
# call tools -- safely!
|
150 |
+
for tool_call in tool_calls:
|
151 |
+
tool = tools_by_name.get(tool_call.tool_name)
|
152 |
+
if not tool:
|
153 |
+
(await ctx.get("current_reasoning", default=[])).append(
|
154 |
+
ObservationReasoningStep(
|
155 |
+
observation=f"Tool {tool_call.tool_name} does not exist"
|
156 |
+
)
|
157 |
+
)
|
158 |
+
continue
|
159 |
+
|
160 |
+
try:
|
161 |
+
tool_output = tool(**tool_call.tool_kwargs)
|
162 |
+
print(f"Tool output: {tool_output}")
|
163 |
+
self.sources.append(tool_output)
|
164 |
+
(await ctx.get("current_reasoning", default=[])).append(
|
165 |
+
ObservationReasoningStep(observation=tool_output.content)
|
166 |
+
)
|
167 |
+
except Exception as e:
|
168 |
+
(await ctx.get("current_reasoning", default=[])).append(
|
169 |
+
ObservationReasoningStep(
|
170 |
+
observation=f"Error calling tool {tool.metadata.get_name()}: {e}"
|
171 |
+
)
|
172 |
+
)
|
173 |
+
|
174 |
+
# prep the next iteraiton
|
175 |
+
return PrepEvent()
|
176 |
+
|
177 |
+
from llama_index.core.tools import FunctionTool
|
178 |
+
from llama_index.llms.openai import OpenAI
|
179 |
+
from workflow.modules import *
|
180 |
+
|
181 |
+
|
182 |
+
|
183 |
+
async def main():
|
184 |
+
tools = [
|
185 |
+
FunctionTool.from_defaults(video_search),
|
186 |
+
FunctionTool.from_defaults(general_search),
|
187 |
+
]
|
188 |
+
|
189 |
+
agent = ReActAgent(
|
190 |
+
llm=llm, tools=tools, timeout=120, verbose=True
|
191 |
+
)
|
192 |
+
|
193 |
+
ret = await agent.run(input="How to build trust with partner?")
|
194 |
+
|
195 |
+
if __name__ == "__main__":
|
196 |
+
import asyncio
|
197 |
+
asyncio.run(main())
|
198 |
+
|
tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/data_level0.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f00c649760867dda1b427939fc71ad4b3e4b38bf093d7febda0d7dc257f5008f
|
3 |
+
size 16524000
|
tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/header.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ab81429de0666bb1c88e77a02e06b00c660cdb1158aec07ce0195e3ee4fbd53e
|
3 |
+
size 100
|
tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/length.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f3a7b351dd58ecaaf46083902bb1a12e0ea45db3bd2f4cc7f1a39c1de4b7361c
|
3 |
+
size 4000
|
tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/link_lists.bin
ADDED
File without changes
|
tests/chroma_db/chroma.sqlite3
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:9fd184a5bf9031e5a74322bbc8765c7d415ec1fb5ea276c14f994f020b712ff7
|
3 |
+
size 2494464
|