Pew404 commited on
Commit
318db6e
·
verified ·
1 Parent(s): 13fbd2e

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +4 -0
  2. .gitignore +2 -0
  3. None/testing_chat_store.json +1 -0
  4. README.md +1 -1
  5. api.py +27 -0
  6. data/config.yaml +26 -0
  7. data/csv/t_sur_media_sync_es.csv +3 -0
  8. data/csv/t_sur_models_info.csv +3 -0
  9. data/pdf/alice.pdf +3 -0
  10. data/txt/blog/11 Steps To Make A Woman Orgasm (The Basics & Beyond).txt +4 -0
  11. data/txt/blog/Blowjobs_ What Are They and How to Give One.txt +20 -0
  12. data/txt/blog/Female Orgasm_ Types, Feeling, and How to Have One.txt +40 -0
  13. data/txt/blog/Female orgasm_ Everything you need to know.txt +74 -0
  14. data/txt/blog/Female orgasms_ Different types & how to climax.txt +54 -0
  15. data/txt/blog/Orgasm & Female Orgasm_ How many types of orgasm are there_.txt +104 -0
  16. environment.yml +350 -0
  17. fetishTest/Q&A.json +62 -0
  18. fetishTest/api.py +66 -0
  19. fetishTest/character.py +26 -0
  20. fetishTest/fetish_test.py +170 -0
  21. fetishTest/standard_character.json +0 -0
  22. fetishTest/test.py +30 -0
  23. milvusDB/prepare_milvus.py +215 -0
  24. milvusDB/retriever.py +115 -0
  25. milvusDB/update_milvus.py +275 -0
  26. pipeline/__init__.py +0 -0
  27. pipeline/chat_pipeline.py +97 -0
  28. pipeline/kb_pipeline.py +0 -0
  29. pipeline/modules.py +112 -0
  30. pipeline/search_pipeline.py +35 -0
  31. pipeline/sql_pipeline.py +224 -0
  32. pipeline/table_infos.py +30 -0
  33. pipeline/text2sql_dag.html +0 -0
  34. prompts/README.md +11 -0
  35. prompts/__init__.py +0 -0
  36. prompts/agent_prompts.py +132 -0
  37. prompts/default_prompts.py +469 -0
  38. requirements.txt +347 -0
  39. response_body.txt +642 -0
  40. routers/__init__.py +0 -0
  41. routers/sql_chat.py +204 -0
  42. routers/update_kb.py +27 -0
  43. tests/README.md +6 -0
  44. tests/__init__.py +0 -0
  45. tests/agent_workflow.py +198 -0
  46. tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/data_level0.bin +3 -0
  47. tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/header.bin +3 -0
  48. tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/length.bin +3 -0
  49. tests/chroma_db/72aecf5e-825b-406a-8b86-2cd424f8ff72/link_lists.bin +0 -0
  50. 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